From 165b5fff9dde5536d9cb1f850b36c17bf5654f0f Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:43:22 -0700 Subject: [PATCH 0001/1342] bgpd: Add new configuration cli for eBGP and iBGP multipath. There is support to configure this for each (AFI,SAFI), but currently this configuration is only present for IPv4 unicast: maximum-paths [ibgp] <1-255> no maximum-paths [ibgp] [<1-255>] * bgpd/Makefile.am * Add bgp_mpath.h and bgp_mpath.c to build * bgpd/bgp_mpath.h * New file for bgp multipath declarations * define BGP_DEFAULT_MAXPATHS * bgpd/bgp_mpath.c * bgp_maximum_paths_set(): Configure maximum paths for the given afi, safi and bgp instance * bgp_maximum_paths_unset(): Return maximum paths configuration to the default setting for the given afi, safi and bgp instance * bgpd/bgp_vty.c * Define command strings for above CLI * bgp_config_write_maxpaths(): Outputs configuration for the given afi, safi and bgp instance * Install command elements for IPv4 unicast * bgpd/bgp_zebra.h * bgp_config_write_maxpaths(): External declaration * bgpd/bgpd.c * bgp_create(): Initialize bgp instance to default maximum paths setting * bgp_config_write_family(): Output maximum paths configuration for the given address family * bgp_config_write(): Output maximum paths configuration for IPv4 unicast address family * bgpd/bgpd.h * struct bgp: Add storage for maximum paths configuration for each afi, safi --- bgpd/Makefile.am | 4 +- bgpd/bgp_mpath.c | 83 +++++++++++++++++++++++++ bgpd/bgp_mpath.h | 34 ++++++++++ bgpd/bgp_vty.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_zebra.h | 2 + bgpd/bgpd.c | 9 +++ bgpd/bgpd.h | 6 ++ 7 files changed, 294 insertions(+), 2 deletions(-) create mode 100644 bgpd/bgp_mpath.c create mode 100644 bgpd/bgp_mpath.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 1b17d3863..3051555b9 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -15,14 +15,14 @@ libbgp_a_SOURCES = \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ - bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c + bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ - bgp_advertise.h bgp_snmp.h bgp_vty.h + bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c new file mode 100644 index 000000000..56c703f6d --- /dev/null +++ b/bgpd/bgp_mpath.c @@ -0,0 +1,83 @@ +/* $QuaggaId: Format:%an, %ai, %h$ $ + * + * BGP Multipath + * Copyright (C) 2010 Google Inc. + * + * 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 + +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_mpath.h" + +/* + * bgp_maximum_paths_set + * + * Record maximum-paths configuration for BGP instance + */ +int +bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi, + int peertype, u_int16_t maxpaths) +{ + if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX)) + return -1; + + switch (peertype) + { + case BGP_PEER_IBGP: + bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths; + break; + case BGP_PEER_EBGP: + bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths; + break; + default: + return -1; + } + + return 0; +} + +/* + * bgp_maximum_paths_unset + * + * Remove maximum-paths configuration from BGP instance + */ +int +bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi, + int peertype) +{ + if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX)) + return -1; + + switch (peertype) + { + case BGP_PEER_IBGP: + bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; + break; + case BGP_PEER_EBGP: + bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; + break; + default: + return -1; + } + + return 0; +} diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h new file mode 100644 index 000000000..f0ac83679 --- /dev/null +++ b/bgpd/bgp_mpath.h @@ -0,0 +1,34 @@ +/* $QuaggaId: Format:%an, %ai, %h$ $ + * + * BGP Multipath + * Copyright (C) 2010 Google Inc. + * + * 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 _QUAGGA_BGP_MPATH_H +#define _QUAGGA_BGP_MPATH_H + +/* BGP default maximum-paths */ +#define BGP_DEFAULT_MAXPATHS 1 + +/* Functions to support maximum-paths configuration */ +extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t); +extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); + +#endif /* _QUAGGA_BGP_MPATH_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e7e7dba10..2c44efc22 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -48,6 +48,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_mpath.h" extern struct in_addr router_id_zebra; @@ -650,6 +651,149 @@ DEFUN (no_bgp_confederation_peers, return CMD_SUCCESS; } +/* Maximum-paths configuration */ +DEFUN (bgp_maxpaths, + bgp_maxpaths_cmd, + "maximum-paths <1-255>", + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + struct bgp *bgp; + u_int16_t maxpaths; + int ret; + + bgp = vty->index; + + VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255); + + ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty), + BGP_PEER_EBGP, maxpaths); + if (ret < 0) + { + vty_out (vty, + "%% Failed to set maximum-paths %u for afi %u, safi %u%s", + maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (bgp_maxpaths_ibgp, + bgp_maxpaths_ibgp_cmd, + "maximum-paths ibgp <1-255>", + "Forward packets over multiple paths\n" + "iBGP-multipath\n" + "Number of paths\n") +{ + struct bgp *bgp; + u_int16_t maxpaths; + int ret; + + bgp = vty->index; + + VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255); + + ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty), + BGP_PEER_IBGP, maxpaths); + if (ret < 0) + { + vty_out (vty, + "%% Failed to set maximum-paths ibgp %u for afi %u, safi %u%s", + maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_maxpaths, + no_bgp_maxpaths_cmd, + "no maximum-paths", + NO_STR + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + struct bgp *bgp; + int ret; + + bgp = vty->index; + + ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty), + BGP_PEER_EBGP); + if (ret < 0) + { + vty_out (vty, + "%% Failed to unset maximum-paths for afi %u, safi %u%s", + bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_maxpaths, + no_bgp_maxpaths_arg_cmd, + "no maximum-paths <1-255>", + NO_STR + "Forward packets over multiple paths\n" + "Number of paths\n") + +DEFUN (no_bgp_maxpaths_ibgp, + no_bgp_maxpaths_ibgp_cmd, + "no maximum-paths ibgp", + NO_STR + "Forward packets over multiple paths\n" + "iBGP-multipath\n" + "Number of paths\n") +{ + struct bgp *bgp; + int ret; + + bgp = vty->index; + + ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty), + BGP_PEER_IBGP); + if (ret < 0) + { + vty_out (vty, + "%% Failed to unset maximum-paths ibgp for afi %u, safi %u%s", + bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_maxpaths_ibgp, + no_bgp_maxpaths_ibgp_arg_cmd, + "no maximum-paths ibgp <1-255>", + NO_STR + "Forward packets over multiple paths\n" + "iBGP-multipath\n" + "Number of paths\n") + +int +bgp_config_write_maxpaths (struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi, int *write) +{ + if (bgp->maxpaths[afi][safi].maxpaths_ebgp != BGP_DEFAULT_MAXPATHS) + { + bgp_config_write_family_header (vty, afi, safi, write); + vty_out (vty, " maximum-paths %d%s", + bgp->maxpaths[afi][safi].maxpaths_ebgp, VTY_NEWLINE); + } + + if (bgp->maxpaths[afi][safi].maxpaths_ibgp != BGP_DEFAULT_MAXPATHS) + { + bgp_config_write_family_header (vty, afi, safi, write); + vty_out (vty, " maximum-paths ibgp %d%s", + bgp->maxpaths[afi][safi].maxpaths_ibgp, VTY_NEWLINE); + } + + return 0; +} + /* BGP timers. */ DEFUN (bgp_timers, @@ -9062,6 +9206,20 @@ bgp_vty_init (void) install_element (BGP_NODE, &bgp_confederation_peers_cmd); install_element (BGP_NODE, &no_bgp_confederation_peers_cmd); + /* "maximum-paths" commands. */ + install_element (BGP_NODE, &bgp_maxpaths_cmd); + install_element (BGP_NODE, &no_bgp_maxpaths_cmd); + install_element (BGP_NODE, &no_bgp_maxpaths_arg_cmd); + install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd); + install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd); + install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); + install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); + /* "timers bgp" commands. */ install_element (BGP_NODE, &bgp_timers_cmd); install_element (BGP_NODE, &no_bgp_timers_cmd); diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index bd9538642..5172cb8a5 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -23,6 +23,8 @@ Boston, MA 02111-1307, USA. */ extern void bgp_zebra_init (void); extern int bgp_if_update_all (void); +extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, + safi_t, int *); extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, int *); extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ee0cc5da6..e86fca342 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -57,6 +57,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_mpath.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ @@ -1947,6 +1948,8 @@ bgp_create (as_t *as, const char *name) bgp->route[afi][safi] = bgp_table_init (afi, safi); bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); bgp->rib[afi][safi] = bgp_table_init (afi, safi); + bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; + bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; } bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; @@ -5117,6 +5120,9 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi, } } } + + bgp_config_write_maxpaths (vty, bgp, afi, safi, &write); + if (write) vty_out (vty, " exit-address-family%s", VTY_NEWLINE); @@ -5290,6 +5296,9 @@ bgp_config_write (struct vty *vty) bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST); } + /* maximum-paths */ + bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write); + /* Distance configuration. */ bgp_config_write_distance (vty, bgp); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 4da19e714..bd03f653e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -162,6 +162,12 @@ struct bgp /* BGP graceful restart */ u_int32_t restart_time; u_int32_t stalepath_time; + + /* Maximum-paths configuration */ + struct bgp_maxpaths_cfg { + u_int16_t maxpaths_ebgp; + u_int16_t maxpaths_ibgp; + } maxpaths[AFI_MAX][SAFI_MAX]; }; /* BGP peer-group support. */ From 42ea68512fc4d04b500def45e8f899321f4081e7 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:44:23 -0700 Subject: [PATCH 0002/1342] bgpd: add bgp_mpath_test.c * tests/bgp_mpath_test.c * New file with test framework for testing BGP multipath * Add test for CLI support functions * tests/Makefile.am * Add new testbgpmpath target --- tests/Makefile.am | 4 +- tests/bgp_mpath_test.c | 309 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 tests/bgp_mpath_test.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 4ab507bbe..2e98ff793 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,7 +6,7 @@ AM_LDFLAGS = $(PILDFLAGS) noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ aspathtest testprivs teststream testbgpcap ecommtest \ - testbgpmpattr testchecksum + testbgpmpattr testchecksum testbgpmpath testsig_SOURCES = test-sig.c testbuffer_SOURCES = test-buffer.c @@ -21,6 +21,7 @@ testbgpcap_SOURCES = bgp_capability_test.c ecommtest_SOURCES = ecommunity_test.c testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c +testbgpmpath_SOURCES = bgp_mpath_test.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ @@ -35,3 +36,4 @@ testbgpcap_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a ecommtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a testbgpmpattr_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ +testbgpmpath_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c new file mode 100644 index 000000000..37e977369 --- /dev/null +++ b/tests/bgp_mpath_test.c @@ -0,0 +1,309 @@ +/* $QuaggaId: Format:%an, %ai, %h$ $ + * + * BGP Multipath Unit Test + * Copyright (C) 2010 Google Inc. + * + * 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 + +#include "vty.h" +#include "stream.h" +#include "privs.h" +#include "linklist.h" +#include "memory.h" +#include "zclient.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" + +#define VT100_RESET "\x1b[0m" +#define VT100_RED "\x1b[31m" +#define VT100_GREEN "\x1b[32m" +#define VT100_YELLOW "\x1b[33m" +#define OK VT100_GREEN "OK" VT100_RESET +#define FAILED VT100_RED "failed" VT100_RESET + +#define TEST_PASSED 0 +#define TEST_FAILED -1 + +#define EXPECT_TRUE(expr, res) \ + if (!(expr)) \ + { \ + printf ("Test failure in %s line %u: %s\n", \ + __FUNCTION__, __LINE__, #expr); \ + (res) = TEST_FAILED; \ + } + +typedef struct testcase_t__ testcase_t; + +typedef int (*test_setup_func)(testcase_t *); +typedef int (*test_run_func)(testcase_t *); +typedef int (*test_cleanup_func)(testcase_t *); + +struct testcase_t__ { + const char *desc; + void *test_data; + void *verify_data; + void *tmp_data; + test_setup_func setup; + test_run_func run; + test_cleanup_func cleanup; +}; + +/* need these to link in libbgp */ +struct thread_master *master = NULL; +struct zclient *zclient; +struct zebra_privs_t bgpd_privs = +{ + .user = NULL, + .group = NULL, + .vty_group = NULL, +}; + +static int tty = 0; + +/* Create fake bgp instance */ +static struct bgp * +bgp_create_fake (as_t *as, const char *name) +{ + struct bgp *bgp; + afi_t afi; + safi_t safi; + + if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL) + return NULL; + + bgp_lock (bgp); + //bgp->peer_self = peer_new (bgp); + //bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement"); + + bgp->peer = list_new (); + //bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; + + bgp->group = list_new (); + //bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; + + bgp->rsclient = list_new (); + //bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + bgp->route[afi][safi] = bgp_table_init (afi, safi); + bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); + bgp->rib[afi][safi] = bgp_table_init (afi, safi); + bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; + bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; + } + + bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; + bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; + bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + + bgp->as = *as; + + if (name) + bgp->name = strdup (name); + + return bgp; +} + +/*========================================================= + * Testcase for maximum-paths configuration + */ +static int +setup_bgp_cfg_maximum_paths (testcase_t *t) +{ + as_t asn = 1; + t->tmp_data = bgp_create_fake (&asn, NULL); + if (!t->tmp_data) + return -1; + return 0; +} + +static int +run_bgp_cfg_maximum_paths (testcase_t *t) +{ + afi_t afi; + safi_t safi; + struct bgp *bgp; + int api_result; + int test_result = TEST_PASSED; + + bgp = t->tmp_data; + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + /* test bgp_maximum_paths_set */ + api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, 10); + EXPECT_TRUE (api_result == 0, test_result); + api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, 10); + EXPECT_TRUE (api_result == 0, test_result); + EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ebgp == 10, test_result); + EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ibgp == 10, test_result); + + /* test bgp_maximum_paths_unset */ + api_result = bgp_maximum_paths_unset (bgp, afi, safi, BGP_PEER_EBGP); + EXPECT_TRUE (api_result == 0, test_result); + api_result = bgp_maximum_paths_unset (bgp, afi, safi, BGP_PEER_IBGP); + EXPECT_TRUE (api_result == 0, test_result); + EXPECT_TRUE ((bgp->maxpaths[afi][safi].maxpaths_ebgp == + BGP_DEFAULT_MAXPATHS), test_result); + EXPECT_TRUE ((bgp->maxpaths[afi][safi].maxpaths_ibgp == + BGP_DEFAULT_MAXPATHS), test_result); + } + + return test_result; +} + +static int +cleanup_bgp_cfg_maximum_paths (testcase_t *t) +{ + return bgp_delete ((struct bgp *)t->tmp_data); +} + +testcase_t test_bgp_cfg_maximum_paths = { + .desc = "Test bgp maximum-paths config", + .setup = setup_bgp_cfg_maximum_paths, + .run = run_bgp_cfg_maximum_paths, + .cleanup = cleanup_bgp_cfg_maximum_paths, +}; + +/*========================================================= + * Set up testcase vector + */ +testcase_t *all_tests[] = { + &test_bgp_cfg_maximum_paths, +}; + +int all_tests_count = (sizeof(all_tests)/sizeof(testcase_t *)); + +/*========================================================= + * Test Driver Functions + */ +static int +global_test_init (void) +{ + master = thread_master_create (); + zclient = zclient_new (); + bgp_master_init (); + + if (fileno (stdout) >= 0) + tty = isatty (fileno (stdout)); + return 0; +} + +static int +global_test_cleanup (void) +{ + zclient_free (zclient); + thread_master_free (master); + return 0; +} + +static void +display_result (testcase_t *test, int result) +{ + if (tty) + printf ("%s: %s\n", test->desc, result == TEST_PASSED ? OK : FAILED); + else + printf ("%s: %s\n", test->desc, result == TEST_PASSED ? "OK" : "FAILED"); +} + +static int +setup_test (testcase_t *t) +{ + int res = 0; + if (t->setup) + res = t->setup (t); + return res; +} + +static int +cleanup_test (testcase_t *t) +{ + int res = 0; + if (t->cleanup) + res = t->cleanup (t); + return res; +} + +static void +run_tests (testcase_t *tests[], int num_tests, int *pass_count, int *fail_count) +{ + int test_index, result; + testcase_t *cur_test; + + *pass_count = *fail_count = 0; + + for (test_index = 0; test_index < num_tests; test_index++) + { + cur_test = tests[test_index]; + if (!cur_test->desc) + { + printf ("error: test %d has no description!\n", test_index); + continue; + } + if (!cur_test->run) + { + printf ("error: test %s has no run function!\n", cur_test->desc); + continue; + } + if (setup_test (cur_test) != 0) + { + printf ("error: setup failed for test %s\n", cur_test->desc); + continue; + } + result = cur_test->run (cur_test); + if (result == TEST_PASSED) + *pass_count += 1; + else + *fail_count += 1; + display_result (cur_test, result); + if (cleanup_test (cur_test) != 0) + { + printf ("error: cleanup failed for test %s\n", cur_test->desc); + continue; + } + } +} + +int +main (void) +{ + int pass_count, fail_count; + time_t cur_time; + + time (&cur_time); + printf("BGP Multipath Tests Run at %s", ctime(&cur_time)); + if (global_test_init () != 0) + { + printf("Global init failed. Terminating.\n"); + exit(1); + } + run_tests (all_tests, all_tests_count, &pass_count, &fail_count); + global_test_cleanup (); + printf("Total pass/fail: %d/%d\n", pass_count, fail_count); + return fail_count; +} From 96450faf3385a6ed9f4dd5c2c58776c4a664a8da Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:45:12 -0700 Subject: [PATCH 0003/1342] bgpd: Adds equal-paths check to path comparison. Paths that are equal to the best path are accumulated onto an ordered list (mp_list) if maximum-paths is configured. A future commit will add the multipath markup to the BGP rib table based on the mp_list. Add unit test for the added mp_list functions. Deterministic MED is not supported in this commit, it will be added later. * bgpd/bgp_aspath.c * Make aspath_cmp() an external symbol so it can be used in equivalent paths check * bgpd/bgp_aspath.h * Add extern declaration of aspath_cmp() * bgpd/bgp_mpath.c * bgp_info_nexthop_cmp(): Compares nexthops of two paths * bgp_info_mpath_cmp(): Compare function to order multipaths by nexthop and then by peer address * bgp_mp_list_init(): Initialize a list with the multipath order function * bgp_mp_list_clear(): Clear out the mp_list * bgp_mp_list_add(): Add a multipath to mp_list * bgpd/bgp_mpath.h * External declarations for above added functions in bgp_mpath.c * bgpd/bgp_route.c * bgp_info_cmp(): Add equivalent paths result (paths_eq). If eBGP paths are equal down to IGP metric check, flag as equal if peer AS matches. Similarly for iBGP paths but compare full AS_PATH. * bgp_best_selection(): If multipath is enabled, accumulate equivalent paths in mp_list. Add debug bgp event output to see result (will be filtered later to display only when change occurs) * bgp_process_rsclient(): Pass multipath config to bgp_best_selection() * bgp_process_main(): Pass multipath config to bgp_best_selection() * tests/bgp_mpath_test.c * Add unit test case for bgp_mp_list functions --- bgpd/bgp_aspath.c | 2 +- bgpd/bgp_aspath.h | 1 + bgpd/bgp_mpath.c | 119 +++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_mpath.h | 7 +++ bgpd/bgp_route.c | 113 ++++++++++++++++++++++++++++++-------- tests/bgp_mpath_test.c | 90 ++++++++++++++++++++++++++++++- 6 files changed, 309 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index cf9304270..de0d6876c 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1821,7 +1821,7 @@ aspath_key_make (void *p) } /* If two aspath have same value then return 1 else return 0 */ -static int +int aspath_cmp (const void *arg1, const void *arg2) { const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index d63b914c1..b881b6544 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -72,6 +72,7 @@ extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); extern struct aspath *aspath_add_seq (struct aspath *, as_t); extern struct aspath *aspath_add_confed_seq (struct aspath *, as_t); +extern int aspath_cmp (const void *, const void *); extern int aspath_cmp_left (const struct aspath *, const struct aspath *); extern int aspath_cmp_left_confed (const struct aspath *, const struct aspath *); extern struct aspath *aspath_delete_confed_seq (struct aspath *); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 56c703f6d..09b469516 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -24,8 +24,14 @@ #include #include "command.h" +#include "prefix.h" +#include "linklist.h" +#include "sockunion.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" #include "bgpd/bgp_mpath.h" /* @@ -81,3 +87,116 @@ bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi, return 0; } + +/* + * bgp_info_nexthop_cmp + * + * Compare the nexthops of two paths. Return value is less than, equal to, + * or greater than zero if bi1 is respectively less than, equal to, + * or greater than bi2. + */ +static int +bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) +{ + struct attr_extra *ae1, *ae2; + int compare; + + ae1 = bgp_attr_extra_get (bi1->attr); + ae2 = bgp_attr_extra_get (bi2->attr); + + compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); + + if (!compare && ae1 && ae2 && (ae1->mp_nexthop_len == ae2->mp_nexthop_len)) + { + switch (ae1->mp_nexthop_len) + { + case 4: + case 12: + compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, + &ae2->mp_nexthop_global_in); + break; +#ifdef HAVE_IPV6 + case 16: + compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, + &ae2->mp_nexthop_global); + break; + case 32: + compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, + &ae2->mp_nexthop_global); + if (!compare) + compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, + &ae2->mp_nexthop_local); + break; +#endif /* HAVE_IPV6 */ + } + } + + return compare; +} + +/* + * bgp_info_mpath_cmp + * + * This function determines our multipath list ordering. By ordering + * the list we can deterministically select which paths are included + * in the multipath set. The ordering also helps in detecting changes + * in the multipath selection so we can detect whether to send an + * update to zebra. + * + * The order of paths is determined first by received nexthop, and then + * by peer address if the nexthops are the same. + */ +static int +bgp_info_mpath_cmp (void *val1, void *val2) +{ + struct bgp_info *bi1, *bi2; + int compare; + + bi1 = val1; + bi2 = val2; + + compare = bgp_info_nexthop_cmp (bi1, bi2); + + if (!compare) + compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote); + + return compare; +} + +/* + * bgp_mp_list_init + * + * Initialize the mp_list, which holds the list of multipaths + * selected by bgp_best_selection + */ +void +bgp_mp_list_init (struct list *mp_list) +{ + assert (mp_list); + memset (mp_list, 0, sizeof (struct list)); + mp_list->cmp = bgp_info_mpath_cmp; +} + +/* + * bgp_mp_list_clear + * + * Clears all entries out of the mp_list + */ +void +bgp_mp_list_clear (struct list *mp_list) +{ + assert (mp_list); + list_delete_all_node (mp_list); +} + +/* + * bgp_mp_list_add + * + * Adds a multipath entry to the mp_list + */ +void +bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo) +{ + assert (mp_list && mpinfo); + listnode_add_sort (mp_list, mpinfo); +} diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index f0ac83679..de6461fda 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -31,4 +31,11 @@ extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t); extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); +/* Functions used by bgp_best_selection to record current + * multipath selections + */ +extern void bgp_mp_list_init (struct list *); +extern void bgp_mp_list_clear (struct list *); +extern void bgp_mp_list_add (struct list *, struct bgp_info *); + #endif /* _QUAGGA_BGP_MPATH_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5c516f024..718e25fff 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -54,6 +54,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_mpath.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -316,7 +317,8 @@ bgp_med_value (struct attr *attr, struct bgp *bgp) /* Compare two bgp route entity. br is preferable then return 1. */ static int -bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist) +bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, + int *paths_eq) { u_int32_t new_pref; u_int32_t exist_pref; @@ -331,6 +333,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist) int internal_as_route = 0; int confed_as_route = 0; int ret; + uint32_t newm, existm; + + *paths_eq = 0; /* 0. Null check. */ if (new == NULL) @@ -454,18 +459,32 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist) return 0; /* 8. IGP metric check. */ - if (new->extra || exist->extra) - { - uint32_t newm = (new->extra ? new->extra->igpmetric : 0); - uint32_t existm = (exist->extra ? exist->extra->igpmetric : 0); - - if (newm < existm) - return 1; - if (newm > existm) - return 0; - } + newm = (new->extra ? new->extra->igpmetric : 0); + existm = (exist->extra ? exist->extra->igpmetric : 0); + if (newm < existm) + ret = 1; + if (newm > existm) + ret = 0; /* 9. Maximum path check. */ + if (newm == existm) + { + if ((peer_sort (new->peer) == BGP_PEER_IBGP)) + { + if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) + *paths_eq = 1; + } + else if (new->peer->as == exist->peer->as) + *paths_eq = 1; + } + else + { + /* + * TODO: If unequal cost ibgp multipath is enabled we can + * mark the paths as equal here instead of returning + */ + return ret; + } /* 10. If both paths are external, prefer the path that was received first (the oldest one). This step minimizes route-flap, since a @@ -1267,7 +1286,9 @@ struct bgp_info_pair }; static void -bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *result) +bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, + struct bgp_maxpaths_cfg *mpath_cfg, + struct bgp_info_pair *result) { struct bgp_info *new_select; struct bgp_info *old_select; @@ -1275,7 +1296,13 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair * struct bgp_info *ri1; struct bgp_info *ri2; struct bgp_info *nextri = NULL; - + int paths_eq, do_mpath; + struct list mp_list; + + bgp_mp_list_init (&mp_list); + do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS || + mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS); + /* bgp deterministic-med */ new_select = NULL; if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) @@ -1299,7 +1326,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair * || aspath_cmp_left_confed (ri1->attr->aspath, ri2->attr->aspath)) { - if (bgp_info_cmp (bgp, ri2, new_select)) + if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq)) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; @@ -1341,14 +1368,58 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair * bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED); - if (bgp_info_cmp (bgp, ri, new_select)) - new_select = ri; + if (bgp_info_cmp (bgp, ri, new_select, &paths_eq)) + { + new_select = ri; + + if (do_mpath && !paths_eq) + { + bgp_mp_list_clear (&mp_list); + bgp_mp_list_add (&mp_list, ri); + } + } + + if (do_mpath && paths_eq) + bgp_mp_list_add (&mp_list, ri); } - result->old = old_select; - result->new = new_select; - return; + /* + * TODO: Will add some additional filtering later to only + * output debugs when multipath state for the route changes + */ + if (BGP_DEBUG (events, EVENTS) && do_mpath) + { + struct listnode *mp_node; + struct bgp_info *mp_info; + char buf[2][INET_ADDRSTRLEN]; + + prefix2str (&rn->p, buf[0], sizeof (buf[0])); + zlog_debug ("%s bestpath nexthop %s, %d mpath candidates", + buf[0], + (new_select ? + inet_ntop(AF_INET, &new_select->attr->nexthop, + buf[1], sizeof (buf[1])) : + "None"), + listcount (&mp_list)); + for (mp_node = listhead (&mp_list); mp_node; + mp_node = listnextnode (mp_node)) + { + mp_info = listgetdata (mp_node); + if (mp_info == new_select) + continue; + zlog_debug (" candidate mpath nexthop %s", + inet_ntop(AF_INET, &mp_info->attr->nexthop, buf[0], + sizeof (buf[0]))); + } + } + + bgp_mp_list_clear (&mp_list); + + result->old = old_select; + result->new = new_select; + + return; } static int @@ -1422,7 +1493,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data) struct peer *rsclient = rn->table->owner; /* Best path selection. */ - bgp_best_selection (bgp, rn, &old_and_new); + bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); new_select = old_and_new.new; old_select = old_and_new.old; @@ -1483,7 +1554,7 @@ bgp_process_main (struct work_queue *wq, void *data) struct peer *peer; /* Best path selection. */ - bgp_best_selection (bgp, rn, &old_and_new); + bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); old_select = old_and_new.old; new_select = old_and_new.new; diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index 37e977369..4d51ddb88 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -31,9 +31,10 @@ #include "zclient.h" #include "bgpd/bgpd.h" -#include "bgpd/bgp_mpath.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mpath.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" @@ -190,11 +191,98 @@ testcase_t test_bgp_cfg_maximum_paths = { .cleanup = cleanup_bgp_cfg_maximum_paths, }; +/*========================================================= + * Testcase for bgp_mp_list + */ +struct peer test_mp_list_peer[5]; +int test_mp_list_peer_count = sizeof (test_mp_list_peer)/ sizeof (struct peer); +struct attr test_mp_list_attr[4]; +struct bgp_info test_mp_list_info[] = { + { .peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0] }, + { .peer = &test_mp_list_peer[1], .attr = &test_mp_list_attr[1] }, + { .peer = &test_mp_list_peer[2], .attr = &test_mp_list_attr[1] }, + { .peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2] }, + { .peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3] }, +}; +int test_mp_list_info_count = + sizeof (test_mp_list_info)/sizeof (struct bgp_info); + +static int +setup_bgp_mp_list (testcase_t *t) +{ + test_mp_list_attr[0].nexthop.s_addr = 0x01010101; + test_mp_list_attr[1].nexthop.s_addr = 0x02020202; + test_mp_list_attr[2].nexthop.s_addr = 0x03030303; + test_mp_list_attr[3].nexthop.s_addr = 0x04040404; + + if ((test_mp_list_peer[0].su_remote = sockunion_str2su ("1.1.1.1")) == NULL) + return -1; + if ((test_mp_list_peer[1].su_remote = sockunion_str2su ("2.2.2.2")) == NULL) + return -1; + if ((test_mp_list_peer[2].su_remote = sockunion_str2su ("3.3.3.3")) == NULL) + return -1; + if ((test_mp_list_peer[3].su_remote = sockunion_str2su ("4.4.4.4")) == NULL) + return -1; + if ((test_mp_list_peer[4].su_remote = sockunion_str2su ("5.5.5.5")) == NULL) + return -1; + + return 0; +} + +static int +run_bgp_mp_list (testcase_t *t) +{ + struct list mp_list; + struct listnode *mp_node; + struct bgp_info *info; + int i; + int test_result = TEST_PASSED; + bgp_mp_list_init (&mp_list); + EXPECT_TRUE (listcount(&mp_list) == 0, test_result); + + bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[2]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); + + for (i = 0, mp_node = listhead(&mp_list); i < test_mp_list_info_count; + i++, mp_node = listnextnode(mp_node)) + { + info = listgetdata(mp_node); + EXPECT_TRUE (info == &test_mp_list_info[i], test_result); + } + + bgp_mp_list_clear (&mp_list); + EXPECT_TRUE (listcount(&mp_list) == 0, test_result); + + return test_result; +} + +static int +cleanup_bgp_mp_list (testcase_t *t) +{ + int i; + + for (i = 0; i < test_mp_list_peer_count; i++) + sockunion_free (test_mp_list_peer[i].su_remote); + + return 0; +} + +testcase_t test_bgp_mp_list = { + .desc = "Test bgp_mp_list", + .setup = setup_bgp_mp_list, + .run = run_bgp_mp_list, + .cleanup = cleanup_bgp_mp_list, +}; + /*========================================================= * Set up testcase vector */ testcase_t *all_tests[] = { &test_bgp_cfg_maximum_paths, + &test_bgp_mp_list, }; int all_tests_count = (sizeof(all_tests)/sizeof(testcase_t *)); From de8d5dff1523bb9fe47d54f31c9e5322bd805b44 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:46:01 -0700 Subject: [PATCH 0004/1342] bgpd: Adds support to mark up the BGP rib table entry with multipath information based on the multipath list (mp_list) generated during the best path calculation. Display "multipath" for paths that are multipath and also on bestpath if the route is multipath. Flag a best path with the BGP_INFO_MULTIPATH_CHG if the multipath set has changed since the last update. This can be used to trigger updates to zebra and peers. The multipath markup is a lazily allocated bgp_info_mpath structure that is added to the best path and any multipaths. The mpath structures are linked together with the best path element at the head and the other elements ordered by nexthop and then by peer address. This markup scheme is updated by calling bgp_info_mpath_update() and passing in a new mp_list the the current multipath set. There are additional API's for walking the multipath set, querying the count of multipaths, and for cleaning up the multipath markup information when freeing path information. * bgpd/bgp_mpath.c * bgp_info_mpath_new(): Allocation of new mpath element * bgp_info_mpath_free(): Release memory for mpath element * bgp_info_mpath_get(): Access mpath element of path. Allocate memory on-demand * bgp_info_mpath_enqueue(): Enqueue a path onto the multipath list * bgp_info_mpath_dequeue(): Remove a path from the multipath list * bgp_info_mpath_first(): Return first path on the multipath list * bgp_info_mpath_next(): Return next path on the multipath list * bgp_info_mpath_count(): Return the number of paths on the multipath list * bgp_info_mpath_count_set(): Set the number of paths on the multipath list * bgp_info_mpath_update(): Update multipath markup on bgp route table entry and flag any changes. Emit 'debug bgp event' output on any multipath change. * bgpd/bgp_mpath.h * struct bgp_info_mpath: Information added to a bgp_info path to record multipath information * External declarations for new functions in bgp_mpath.c * bgpd/bgp_route.c * bgp_info_free(): Free mpath memory when freeing path information * bgp_info_reap(): Dequeue path from multipath queue before deleting it * bgp_best_selection(): Calls bgp_info_mpath_update() with latest mp_list to mark-up rib table entry * bgp_vty_out_detail(): Add display of multipath flag for a path. Also display 'multipath' for bestpath if it is a multipath route * bgpd/bgp_route.h * struct bgp_info: Add pointer to bgp_info_mpath information * Add flags to mark a path as multipath (BGP_INFO_MULTIPATH) and to mark bestpath if multipath information has changed (BGP_INFO_MULTIPATH_CHG) * lib/memtypes.c * Add MTYPE_BGP_MPATH_INFO for allocating memory for bgp_info_mpath * tests/bgp_mpath_test.c * Add test case for bgp_info_mpath_update() and supporting functions --- bgpd/bgp_mpath.c | 313 +++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_mpath.h | 32 +++++ bgpd/bgp_route.c | 37 ++--- bgpd/bgp_route.h | 6 + lib/memtypes.c | 1 + tests/bgp_mpath_test.c | 84 ++++++++++- 6 files changed, 443 insertions(+), 30 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 09b469516..af1c342c6 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -27,11 +27,13 @@ #include "prefix.h" #include "linklist.h" #include "sockunion.h" +#include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" #include "bgpd/bgp_mpath.h" /* @@ -200,3 +202,314 @@ bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo) assert (mp_list && mpinfo); listnode_add_sort (mp_list, mpinfo); } + +/* + * bgp_info_mpath_new + * + * Allocate and zero memory for a new bgp_info_mpath element + */ +static struct bgp_info_mpath * +bgp_info_mpath_new (void) +{ + struct bgp_info_mpath *new_mpath; + new_mpath = XCALLOC (MTYPE_BGP_MPATH_INFO, sizeof (struct bgp_info_mpath)); + return new_mpath; +} + +/* + * bgp_info_mpath_free + * + * Release resources for a bgp_info_mpath element and zero out pointer + */ +void +bgp_info_mpath_free (struct bgp_info_mpath **mpath) +{ + if (mpath && *mpath) + { + XFREE (MTYPE_BGP_MPATH_INFO, *mpath); + *mpath = NULL; + } +} + +/* + * bgp_info_mpath_get + * + * Fetch the mpath element for the given bgp_info. Used for + * doing lazy allocation. + */ +static struct bgp_info_mpath * +bgp_info_mpath_get (struct bgp_info *binfo) +{ + struct bgp_info_mpath *mpath; + if (!binfo->mpath) + { + mpath = bgp_info_mpath_new(); + if (!mpath) + return NULL; + binfo->mpath = mpath; + mpath->mp_info = binfo; + } + return binfo->mpath; +} + +/* + * bgp_info_mpath_enqueue + * + * Enqueue a path onto the multipath list given the previous multipath + * list entry + */ +static void +bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo) +{ + struct bgp_info_mpath *prev, *mpath; + + prev = bgp_info_mpath_get (prev_info); + mpath = bgp_info_mpath_get (binfo); + if (!prev || !mpath) + return; + + mpath->mp_next = prev->mp_next; + mpath->mp_prev = prev; + if (prev->mp_next) + prev->mp_next->mp_prev = mpath; + prev->mp_next = mpath; + + SET_FLAG (binfo->flags, BGP_INFO_MULTIPATH); +} + +/* + * bgp_info_mpath_dequeue + * + * Remove a path from the multipath list + */ +void +bgp_info_mpath_dequeue (struct bgp_info *binfo) +{ + struct bgp_info_mpath *mpath = binfo->mpath; + if (!mpath) + return; + if (mpath->mp_prev) + mpath->mp_prev->mp_next = mpath->mp_next; + if (mpath->mp_next) + mpath->mp_next->mp_prev = mpath->mp_prev; + mpath->mp_next = mpath->mp_prev = NULL; + UNSET_FLAG (binfo->flags, BGP_INFO_MULTIPATH); +} + +/* + * bgp_info_mpath_next + * + * Given a bgp_info, return the next multipath entry + */ +struct bgp_info * +bgp_info_mpath_next (struct bgp_info *binfo) +{ + if (!binfo->mpath || !binfo->mpath->mp_next) + return NULL; + return binfo->mpath->mp_next->mp_info; +} + +/* + * bgp_info_mpath_first + * + * Given bestpath bgp_info, return the first multipath entry. + */ +struct bgp_info * +bgp_info_mpath_first (struct bgp_info *binfo) +{ + return bgp_info_mpath_next (binfo); +} + +/* + * bgp_info_mpath_count + * + * Given the bestpath bgp_info, return the number of multipath entries + */ +u_int32_t +bgp_info_mpath_count (struct bgp_info *binfo) +{ + if (!binfo->mpath) + return 0; + return binfo->mpath->mp_count; +} + +/* + * bgp_info_mpath_count_set + * + * Sets the count of multipaths into bestpath's mpath element + */ +static void +bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count) +{ + struct bgp_info_mpath *mpath; + if (!count && !binfo->mpath) + return; + mpath = bgp_info_mpath_get (binfo); + if (!mpath) + return; + mpath->mp_count = count; +} + +/* + * bgp_info_mpath_update + * + * Compare and sync up the multipath list with the mp_list generated by + * bgp_best_selection + */ +void +bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, + struct bgp_info *old_best, struct list *mp_list, + struct bgp_maxpaths_cfg *mpath_cfg) +{ + u_int16_t maxpaths, mpath_count, old_mpath_count; + struct listnode *mp_node, *mp_next_node; + struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; + int mpath_changed, debug; + char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN]; + + mpath_changed = 0; + maxpaths = BGP_DEFAULT_MAXPATHS; + mpath_count = 0; + cur_mpath = NULL; + old_mpath_count = 0; + prev_mpath = new_best; + mp_node = listhead (mp_list); + debug = BGP_DEBUG (events, EVENTS); + + if (debug) + prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf)); + + if (new_best) + { + mpath_count++; + if (new_best != old_best) + bgp_info_mpath_dequeue (new_best); + maxpaths = (peer_sort (new_best->peer) == BGP_PEER_IBGP) ? + mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp; + } + + if (old_best) + { + cur_mpath = bgp_info_mpath_first (old_best); + old_mpath_count = bgp_info_mpath_count (old_best); + bgp_info_mpath_count_set (old_best, 0); + bgp_info_mpath_dequeue (old_best); + } + + /* + * We perform an ordered walk through both lists in parallel. + * The reason for the ordered walk is that if there are paths + * that were previously multipaths and are still multipaths, the walk + * should encounter them in both lists at the same time. Otherwise + * there will be paths that are in one list or another, and we + * will deal with these separately. + * + * Note that new_best might be somewhere in the mp_list, so we need + * to skip over it + */ + while (mp_node || cur_mpath) + { + /* + * We can bail out of this loop if all existing paths on the + * multipath list have been visited (for cleanup purposes) and + * the maxpath requirement is fulfulled + */ + if (!cur_mpath && (mpath_count >= maxpaths)) + break; + + mp_next_node = mp_node ? listnextnode (mp_node) : NULL; + next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL; + + /* + * If equal, the path was a multipath and is still a multipath. + * Insert onto new multipath list if maxpaths allows. + */ + if (mp_node && (listgetdata (mp_node) == cur_mpath)) + { + list_delete_node (mp_list, mp_node); + bgp_info_mpath_dequeue (cur_mpath); + if ((mpath_count < maxpaths) && + bgp_info_nexthop_cmp (prev_mpath, cur_mpath)) + { + bgp_info_mpath_enqueue (prev_mpath, cur_mpath); + prev_mpath = cur_mpath; + mpath_count++; + } + else + { + mpath_changed = 1; + if (debug) + zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf, + inet_ntop (AF_INET, &cur_mpath->attr->nexthop, + nh_buf[0], sizeof (nh_buf[0])), + sockunion2str (cur_mpath->peer->su_remote, + nh_buf[1], sizeof (nh_buf[1]))); + } + mp_node = mp_next_node; + cur_mpath = next_mpath; + continue; + } + + if (cur_mpath && (!mp_node || + (bgp_info_mpath_cmp (cur_mpath, + listgetdata (mp_node)) < 0))) + { + /* + * If here, we have an old multipath and either the mp_list + * is finished or the next mp_node points to a later + * multipath, so we need to purge this path from the + * multipath list + */ + bgp_info_mpath_dequeue (cur_mpath); + mpath_changed = 1; + if (debug) + zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf, + inet_ntop (AF_INET, &cur_mpath->attr->nexthop, + nh_buf[0], sizeof (nh_buf[0])), + sockunion2str (cur_mpath->peer->su_remote, + nh_buf[1], sizeof (nh_buf[1]))); + cur_mpath = next_mpath; + } + else + { + /* + * If here, we have a path on the mp_list that was not previously + * a multipath (due to non-equivalance or maxpaths exceeded), + * or the matching multipath is sorted later in the multipath + * list. Before we enqueue the path on the new multipath list, + * make sure its not on the old_best multipath list or referenced + * via next_mpath: + * - If next_mpath points to this new path, update next_mpath to + * point to the multipath after this one + * - Dequeue the path from the multipath list just to make sure + */ + new_mpath = listgetdata (mp_node); + list_delete_node (mp_list, mp_node); + if (new_mpath == next_mpath) + next_mpath = bgp_info_mpath_next (new_mpath); + bgp_info_mpath_dequeue (new_mpath); + if ((mpath_count < maxpaths) && (new_mpath != new_best) && + bgp_info_nexthop_cmp (prev_mpath, new_mpath)) + { + bgp_info_mpath_enqueue (prev_mpath, new_mpath); + prev_mpath = new_mpath; + mpath_changed = 1; + mpath_count++; + if (debug) + zlog_debug ("%s add mpath nexthop %s peer %s", pfx_buf, + inet_ntop (AF_INET, &new_mpath->attr->nexthop, + nh_buf[0], sizeof (nh_buf[0])), + sockunion2str (new_mpath->peer->su_remote, + nh_buf[1], sizeof (nh_buf[1]))); + } + mp_node = mp_next_node; + } + } + + if (new_best) + { + bgp_info_mpath_count_set (new_best, mpath_count-1); + if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count)) + SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); + } +} diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index de6461fda..1dc2687e2 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -27,6 +27,24 @@ /* BGP default maximum-paths */ #define BGP_DEFAULT_MAXPATHS 1 +/* Supplemental information linked to bgp_info for keeping track of + * multipath selections, lazily allocated to save memory + */ +struct bgp_info_mpath +{ + /* Points to the first multipath (on bestpath) or the next multipath */ + struct bgp_info_mpath *mp_next; + + /* Points to the previous multipath or NULL on bestpath */ + struct bgp_info_mpath *mp_prev; + + /* Points to bgp_info associated with this multipath info */ + struct bgp_info *mp_info; + + /* When attached to best path, the number of selected multipaths */ + u_int32_t mp_count; +}; + /* Functions to support maximum-paths configuration */ extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t); extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); @@ -37,5 +55,19 @@ extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); extern void bgp_mp_list_init (struct list *); extern void bgp_mp_list_clear (struct list *); extern void bgp_mp_list_add (struct list *, struct bgp_info *); +extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *, + struct bgp_info *, struct list *, + struct bgp_maxpaths_cfg *); + +/* Unlink and free multipath information associated with a bgp_info */ +extern void bgp_info_mpath_dequeue (struct bgp_info *); +extern void bgp_info_mpath_free (struct bgp_info_mpath **); + +/* Walk list of multipaths associated with a best path */ +extern struct bgp_info *bgp_info_mpath_first (struct bgp_info *); +extern struct bgp_info *bgp_info_mpath_next (struct bgp_info *); + +/* Accessors for multipath information */ +extern u_int32_t bgp_info_mpath_count (struct bgp_info *); #endif /* _QUAGGA_BGP_MPATH_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 718e25fff..ec17dc612 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -141,6 +141,7 @@ bgp_info_free (struct bgp_info *binfo) bgp_attr_unintern (binfo->attr); bgp_info_extra_free (&binfo->extra); + bgp_info_mpath_free (&binfo->mpath); peer_unlock (binfo->peer); /* bgp_info peer reference */ @@ -211,6 +212,7 @@ bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri) else rn->info = ri->next; + bgp_info_mpath_dequeue (ri); bgp_info_unlock (ri); bgp_unlock_node (rn); } @@ -1384,35 +1386,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, } - /* - * TODO: Will add some additional filtering later to only - * output debugs when multipath state for the route changes - */ - if (BGP_DEBUG (events, EVENTS) && do_mpath) - { - struct listnode *mp_node; - struct bgp_info *mp_info; - char buf[2][INET_ADDRSTRLEN]; - - prefix2str (&rn->p, buf[0], sizeof (buf[0])); - zlog_debug ("%s bestpath nexthop %s, %d mpath candidates", - buf[0], - (new_select ? - inet_ntop(AF_INET, &new_select->attr->nexthop, - buf[1], sizeof (buf[1])) : - "None"), - listcount (&mp_list)); - for (mp_node = listhead (&mp_list); mp_node; - mp_node = listnextnode (mp_node)) - { - mp_info = listgetdata (mp_node); - if (mp_info == new_select) - continue; - zlog_debug (" candidate mpath nexthop %s", - inet_ntop(AF_INET, &mp_info->attr->nexthop, buf[0], - sizeof (buf[0]))); - } - } + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); bgp_mp_list_clear (&mp_list); @@ -5995,6 +5969,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) vty_out (vty, ", atomic-aggregate"); + if (CHECK_FLAG (binfo->flags, BGP_INFO_MULTIPATH) || + (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED) && + bgp_info_mpath_count (binfo))) + vty_out (vty, ", multipath"); + if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) vty_out (vty, ", best"); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3e5285965..45e8d2e80 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -57,6 +57,10 @@ struct bgp_info /* Extra information */ struct bgp_info_extra *extra; + + /* Multipath information */ + struct bgp_info_mpath *mpath; + /* Uptime. */ time_t uptime; @@ -76,6 +80,8 @@ struct bgp_info #define BGP_INFO_STALE (1 << 8) #define BGP_INFO_REMOVED (1 << 9) #define BGP_INFO_COUNTED (1 << 10) +#define BGP_INFO_MULTIPATH (1 << 11) +#define BGP_INFO_MULTIPATH_CHG (1 << 12) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ u_char type; diff --git a/lib/memtypes.c b/lib/memtypes.c index 590206718..dca32caa0 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -115,6 +115,7 @@ struct memory_list memory_list_bgp[] = { MTYPE_BGP_SYNCHRONISE, "BGP synchronise" }, { MTYPE_BGP_ADJ_IN, "BGP adj in" }, { MTYPE_BGP_ADJ_OUT, "BGP adj out" }, + { MTYPE_BGP_MPATH_INFO, "BGP multipath info" }, { 0, NULL }, { MTYPE_AS_LIST, "BGP AS list" }, { MTYPE_AS_FILTER, "BGP AS filter" }, diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index 4d51ddb88..15e450a20 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -194,7 +194,13 @@ testcase_t test_bgp_cfg_maximum_paths = { /*========================================================= * Testcase for bgp_mp_list */ -struct peer test_mp_list_peer[5]; +struct peer test_mp_list_peer[] = { + { .local_as = 1, .as = 2 }, + { .local_as = 1, .as = 2 }, + { .local_as = 1, .as = 2 }, + { .local_as = 1, .as = 2 }, + { .local_as = 1, .as = 2 }, +}; int test_mp_list_peer_count = sizeof (test_mp_list_peer)/ sizeof (struct peer); struct attr test_mp_list_attr[4]; struct bgp_info test_mp_list_info[] = { @@ -277,12 +283,88 @@ testcase_t test_bgp_mp_list = { .cleanup = cleanup_bgp_mp_list, }; +/*========================================================= + * Testcase for bgp_info_mpath_update + */ + +struct bgp_node test_rn; + +static int +setup_bgp_info_mpath_update (testcase_t *t) +{ + int i; + str2prefix ("42.1.1.0/24", &test_rn.p); + setup_bgp_mp_list (t); + for (i = 0; i < test_mp_list_info_count; i++) + bgp_info_add (&test_rn, &test_mp_list_info[i]); + return 0; +} + +static int +run_bgp_info_mpath_update (testcase_t *t) +{ + struct bgp_info *new_best, *old_best, *mpath; + struct list mp_list; + struct bgp_maxpaths_cfg mp_cfg = { 3, 3 }; + int test_result = TEST_PASSED; + bgp_mp_list_init (&mp_list); + bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); + new_best = &test_mp_list_info[3]; + old_best = NULL; + bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, &mp_cfg); + bgp_mp_list_clear (&mp_list); + EXPECT_TRUE (bgp_info_mpath_count (new_best) == 2, test_result); + mpath = bgp_info_mpath_first (new_best); + EXPECT_TRUE (mpath == &test_mp_list_info[0], test_result); + EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); + mpath = bgp_info_mpath_next (mpath); + EXPECT_TRUE (mpath == &test_mp_list_info[1], test_result); + EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); + + bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); + bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); + new_best = &test_mp_list_info[0]; + old_best = &test_mp_list_info[3]; + bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, &mp_cfg); + bgp_mp_list_clear (&mp_list); + EXPECT_TRUE (bgp_info_mpath_count (new_best) == 1, test_result); + mpath = bgp_info_mpath_first (new_best); + EXPECT_TRUE (mpath == &test_mp_list_info[1], test_result); + EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); + EXPECT_TRUE (!CHECK_FLAG (test_mp_list_info[0].flags, BGP_INFO_MULTIPATH), + test_result); + + return test_result; +} + +static int +cleanup_bgp_info_mpath_update (testcase_t *t) +{ + int i; + + for (i = 0; i < test_mp_list_peer_count; i++) + sockunion_free (test_mp_list_peer[i].su_remote); + + return 0; +} + +testcase_t test_bgp_info_mpath_update = { + .desc = "Test bgp_info_mpath_update", + .setup = setup_bgp_info_mpath_update, + .run = run_bgp_info_mpath_update, + .cleanup = cleanup_bgp_info_mpath_update, +}; + /*========================================================= * Set up testcase vector */ testcase_t *all_tests[] = { &test_bgp_cfg_maximum_paths, &test_bgp_mp_list, + &test_bgp_info_mpath_update, }; int all_tests_count = (sizeof(all_tests)/sizeof(testcase_t *)); From 8196f13d2ab7f3b09150c00328228f90391acb7c Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:47:07 -0700 Subject: [PATCH 0005/1342] bgpd: Modify the BGP to zebra route announcement to support multipath routes. Use a growable buffer (bgp_nexthop_buf) to collect nexthops that are included in the announcement. Use the BGP_INFO_MULTIPATH_CHG flag to trigger zebra announcement so zebra will be updated if the multipath set changes. Display all multipath nexthops in 'debug bgp zebra' output. * bgpd/bgp_main.c * bgp_exit(): Free bgp_nexthop_buf when exiting * bgpd/bgp_route.c * bgp_process_rsclient(): Clear BGP_INFO_MULTIPATH_CHG after processing * bgp_process_main(): Check BGP_INFO_MULTIPATH_CHG to trigger zebra announcement and clear aftr processing * bgpd/bgp_zebra.c * bgp_nexthop_buf: Growable buffer used to collect nexthops for zebra announcement * bgp_zebra_announce(): Grow bgp_nexthop_buf if needed. Include multipath count in zebra announcement and add all nexthops to bgp_nexthop_buf. Pass bgp_nexthop_buf data to zebra announcement. Added nexthops to debug output. * bgp_zebra_init(): Initialize bgp_nexthop_buf at startup * bgpd/bgp_zebra.h * BGP_NEXTHOP_BUF_SIZE: Default initial bgp_nexthop_buf size has room for 8 nexthops --- bgpd/bgp_main.c | 4 ++++ bgpd/bgp_route.c | 9 +++++++-- bgpd/bgp_zebra.c | 46 +++++++++++++++++++++++++++++++++++++++++----- bgpd/bgp_zebra.h | 4 ++++ 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1a460c6bb..e5fa79d60 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "routemap.h" #include "filter.h" #include "plist.h" +#include "stream.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -47,6 +48,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_clist.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_filter.h" +#include "bgpd/bgp_zebra.h" /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = @@ -293,6 +295,8 @@ bgp_exit (int status) zclient_free (zclient); if (zlookup) zclient_free (zlookup); + if (bgp_nexthop_buf) + stream_free (bgp_nexthop_buf); /* reverse bgp_master_init */ if (master) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ec17dc612..f3e46221c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1487,7 +1487,8 @@ bgp_process_rsclient (struct work_queue *wq, void *data) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); - } + UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); + } bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); @@ -1501,6 +1502,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); + UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); } @@ -1537,9 +1539,11 @@ bgp_process_main (struct work_queue *wq, void *data) { if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { - if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) + if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) || + CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG)) bgp_zebra_announce (p, old_select, bgp); + UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1551,6 +1555,7 @@ bgp_process_main (struct work_queue *wq, void *data) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); + UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index f3baeee0e..6c21230a0 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -37,11 +37,15 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_debug.h" +#include "bgpd/bgp_mpath.h" /* All information about zebra. */ struct zclient *zclient = NULL; struct in_addr router_id_zebra; +/* Growable buffer for nexthops sent to zebra */ +struct stream *bgp_nexthop_buf = NULL; + /* Router-id update message from zebra. */ static int bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length) @@ -645,6 +649,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) int flags; u_char distance; struct peer *peer; + struct bgp_info *mpinfo; + size_t oldsize, newsize; if (zclient->sock < 0) return; @@ -665,6 +671,21 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + /* resize nexthop buffer size if necessary */ + if ((oldsize = stream_get_size (bgp_nexthop_buf)) < + (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1))) + { + newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)); + newsize = stream_resize (bgp_nexthop_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize nexthop buffer"); + return; + } + } + + stream_reset (bgp_nexthop_buf); + if (p->family == AF_INET) { struct zapi_ipv4 api; @@ -672,12 +693,19 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) api.flags = flags; nexthop = &info->attr->nexthop; + stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); + for (mpinfo = bgp_info_mpath_first (info); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + nexthop = &mpinfo->attr->nexthop; + stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); + } api.type = ZEBRA_ROUTE_BGP; api.message = 0; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; + api.nexthop_num = 1 + bgp_info_mpath_count (info); + api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf); api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; @@ -692,12 +720,18 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) if (BGP_DEBUG(zebra, ZEBRA)) { + int i; char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u", + zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u" + " count %d", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, - inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])), - api.metric); + inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])), + api.metric, api.nexthop_num); + for (i = 1; i < api.nexthop_num; i++) + zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s", + i, inet_ntop(AF_INET, api.nexthop[i], buf[1], + sizeof(buf[1]))); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, @@ -1043,4 +1077,6 @@ bgp_zebra_init (void) /* Interface related init. */ if_init (); + + bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 5172cb8a5..461255e39 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -21,6 +21,10 @@ Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ZEBRA_H #define _QUAGGA_BGP_ZEBRA_H +#define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) + +extern struct stream *bgp_nexthop_buf; + extern void bgp_zebra_init (void); extern int bgp_if_update_all (void); extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, From 6918e74b97fd40f947ebd2eded9ab24b8569d3b8 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:48:20 -0700 Subject: [PATCH 0006/1342] bgpd: For deterministic MED build a multipath set for each peer AS as the first stage of the best path calculation. The second stage then selects a winner from each peer AS's best path. In the second stage we clear multipath set of the non-selected best paths via bgp_mp_dmed_deselect(). Since the multipath set is already marked up for the winning path, we don't call bgp_info_mpath_update() after the second stage calculation. * bgpd/bgp_mpath.c * bgp_mp_dmed_deselect(): New function to cleanup the multipath markup if a DMED selected path loses in stage 2 of the best path calculation * bgpd/bgp_mpath.h * Add external declaration of bgp_mp_dmed_deselect() * bgpd/bgp_route.c * bgp_best_selection(): If multipath is enabled, build up the mp_list for the current peer AS, and do the RIB markup the best path from that AS. In the second stage, clear the RIB markup for the DMED selected path if it is not selected as best. Only call bgp_info_mpath_update() in the second stage when not doing deterministic MED. --- bgpd/bgp_mpath.c | 25 +++++++++++++++++++++++++ bgpd/bgp_mpath.h | 1 + bgpd/bgp_route.c | 24 +++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index af1c342c6..7944c55fc 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -513,3 +513,28 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); } } + +/* + * bgp_mp_dmed_deselect + * + * Clean up multipath information for BGP_INFO_DMED_SELECTED path that + * is not selected as best path + */ +void +bgp_mp_dmed_deselect (struct bgp_info *dmed_best) +{ + struct bgp_info *mpinfo, *mpnext; + + if (!dmed_best) + return; + + for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext) + { + mpnext = bgp_info_mpath_next (mpinfo); + bgp_info_mpath_dequeue (mpinfo); + } + + bgp_info_mpath_count_set (dmed_best, 0); + UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG); + assert (bgp_info_mpath_first (dmed_best) == 0); +} diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index 1dc2687e2..3712493ed 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -55,6 +55,7 @@ extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); extern void bgp_mp_list_init (struct list *); extern void bgp_mp_list_clear (struct list *); extern void bgp_mp_list_add (struct list *, struct bgp_info *); +extern void bgp_mp_dmed_deselect (struct bgp_info *); extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *, struct bgp_info *, struct list *, struct bgp_maxpaths_cfg *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f3e46221c..5c4ab2666 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1316,6 +1316,9 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, continue; new_select = ri1; + if (do_mpath) + bgp_mp_list_add (&mp_list, ri1); + old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL; if (ri1->next) for (ri2 = ri1->next; ri2; ri2 = ri2->next) { @@ -1328,17 +1331,30 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, || aspath_cmp_left_confed (ri1->attr->aspath, ri2->attr->aspath)) { + if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED)) + old_select = ri2; if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq)) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; + if (do_mpath && !paths_eq) + { + bgp_mp_list_clear (&mp_list); + bgp_mp_list_add (&mp_list, ri2); + } } + if (do_mpath && paths_eq) + bgp_mp_list_add (&mp_list, ri2); + bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK); } } bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK); bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED); + + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); + bgp_mp_list_clear (&mp_list); } /* Check old selected route and new selected route. */ @@ -1372,6 +1388,9 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, if (bgp_info_cmp (bgp, ri, new_select, &paths_eq)) { + if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) + bgp_mp_dmed_deselect (new_select); + new_select = ri; if (do_mpath && !paths_eq) @@ -1380,13 +1399,16 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, bgp_mp_list_add (&mp_list, ri); } } + else if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) + bgp_mp_dmed_deselect (ri); if (do_mpath && paths_eq) bgp_mp_list_add (&mp_list, ri); } - bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); + if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); bgp_mp_list_clear (&mp_list); From 0b597ef00ec7c7eebd836e2b1d5a266efcd60005 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:49:11 -0700 Subject: [PATCH 0007/1342] bgpd: When advertising a multipath route, the attribute set to be advertised is based on the bestpath attribute set, but the following attributes are aggregated from the attribute sets of the multipath constituents: - AS_PATH - ORIGIN - COMMUNITIES - EXTENDED COMMUNITIES In addition the route is advertised with the NEXT_HOP set to the router's interface IP address, instead of the NEXT_HOP of the best path. This is to ensure that traffic will go to this router so it can be fanned out via the multipath route. * bgpd/ecommunity.c * ecommunity_uniq_sort(): Make this function externally accessible * bgpd/ecommunity.h * Add external declaration for ecommunity_uniq_sort() * bgpd/bgp_mpath.c * bgp_info_nexthop_cmp(): Replace calls to bgp_attr_extra_get() to avoid unwanted memory allocation * bgp_info_mpath_free(): Free aggregate attribute for multipath * bgp_info_mpath_attr(): Lookup aggregate attribute of a multipath route * bgp_info_mpath_attr_set(): Set aggregate attribute of a multipath route * bgp_info_mpath_aggregate_update(): Update the aggregate attribute of a multipath route * bgpd/bgp_mpath.h * bgp_info_mpath: Add pointer to hold aggregate attribute of a multipath * Add external declarations for new functions * bgpd/bgp_route.c * bgp_announce_check(): Use aggregate attribute when announcing multipath route * bgp_announce_check_rsclient(): Use aggregate attribute when announcing multipath route * bgp_best_selection(): After updating multipath set, update the multipath aggregate attribute --- bgpd/bgp_ecommunity.c | 2 +- bgpd/bgp_ecommunity.h | 1 + bgpd/bgp_mpath.c | 193 +++++++++++++++++++++++++++++++++++++++++- bgpd/bgp_mpath.h | 6 ++ bgpd/bgp_route.c | 33 +++++--- 5 files changed, 218 insertions(+), 17 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 8d5fa741a..244ffd160 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -98,7 +98,7 @@ ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval) /* This function takes pointer to Extended Communites strucutre then create a new Extended Communities structure by uniq and sort each Extended Communities value. */ -static struct ecommunity * +struct ecommunity * ecommunity_uniq_sort (struct ecommunity *ecom) { int i; diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 942fdc733..1a2252709 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -71,6 +71,7 @@ extern void ecommunity_free (struct ecommunity *); extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short); extern struct ecommunity *ecommunity_dup (struct ecommunity *); extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); +extern struct ecommunity *ecommunity_uniq_sort (struct ecommunity *); extern struct ecommunity *ecommunity_intern (struct ecommunity *); extern int ecommunity_cmp (const void *, const void *); extern void ecommunity_unintern (struct ecommunity *); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 7944c55fc..44823c4ba 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -34,6 +34,9 @@ #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_mpath.h" /* @@ -103,8 +106,8 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) struct attr_extra *ae1, *ae2; int compare; - ae1 = bgp_attr_extra_get (bi1->attr); - ae2 = bgp_attr_extra_get (bi2->attr); + ae1 = bi1->attr->extra; + ae2 = bi2->attr->extra; compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); @@ -226,6 +229,8 @@ bgp_info_mpath_free (struct bgp_info_mpath **mpath) { if (mpath && *mpath) { + if ((*mpath)->mp_attr) + bgp_attr_unintern ((*mpath)->mp_attr); XFREE (MTYPE_BGP_MPATH_INFO, *mpath); *mpath = NULL; } @@ -350,6 +355,37 @@ bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count) mpath->mp_count = count; } +/* + * bgp_info_mpath_attr + * + * Given bestpath bgp_info, return aggregated attribute set used + * for advertising the multipath route + */ +struct attr * +bgp_info_mpath_attr (struct bgp_info *binfo) +{ + if (!binfo->mpath) + return NULL; + return binfo->mpath->mp_attr; +} + +/* + * bgp_info_mpath_attr_set + * + * Sets the aggregated attribute into bestpath's mpath element + */ +static void +bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr) +{ + struct bgp_info_mpath *mpath; + if (!attr && !binfo->mpath) + return; + mpath = bgp_info_mpath_get (binfo); + if (!mpath) + return; + mpath->mp_attr = attr; +} + /* * bgp_info_mpath_update * @@ -538,3 +574,156 @@ bgp_mp_dmed_deselect (struct bgp_info *dmed_best) UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG); assert (bgp_info_mpath_first (dmed_best) == 0); } + +/* + * bgp_info_mpath_aggregate_update + * + * Set the multipath aggregate attribute. We need to see if the + * aggregate has changed and then set the ATTR_CHANGED flag on the + * bestpath info so that a peer update will be generated. The + * change is detected by generating the current attribute, + * interning it, and then comparing the interned pointer with the + * current value. We can skip this generate/compare step if there + * is no change in multipath selection and no attribute change in + * any multipath. + */ +void +bgp_info_mpath_aggregate_update (struct bgp_info *new_best, + struct bgp_info *old_best) +{ + struct bgp_info *mpinfo; + struct aspath *aspath; + struct aspath *asmerge; + struct attr *new_attr, *old_attr; + u_char origin, attr_chg; + struct community *community, *commerge; + struct ecommunity *ecomm, *ecommerge; + struct attr_extra *ae; + struct attr attr = { 0 }; + + if (old_best && (old_best != new_best) && + (old_attr = bgp_info_mpath_attr (old_best))) + { + bgp_attr_unintern (old_attr); + bgp_info_mpath_attr_set (old_best, NULL); + } + + if (!new_best) + return; + + if (!bgp_info_mpath_count (new_best)) + { + if ((new_attr = bgp_info_mpath_attr (new_best))) + { + bgp_attr_unintern (new_attr); + bgp_info_mpath_attr_set (new_best, NULL); + SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); + } + return; + } + + /* + * Bail out here if the following is true: + * - MULTIPATH_CHG bit is not set on new_best, and + * - ATTR_CHANGED bit is not set on new_best or any of the multipaths + */ + attr_chg = 0; + if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED)) + attr_chg = 1; + else + for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) + { + attr_chg = 1; + break; + } + } + if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) && !attr_chg) + { + assert (bgp_info_mpath_attr (new_best)); + return; + } + + bgp_attr_dup (&attr, new_best->attr); + + /* aggregate attribute from multipath constituents */ + aspath = aspath_dup (attr.aspath); + origin = attr.origin; + community = attr.community ? community_dup (attr.community) : NULL; + ae = attr.extra; + ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; + + for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + + if (origin < mpinfo->attr->origin) + origin = mpinfo->attr->origin; + + if (mpinfo->attr->community) + { + if (community) + { + commerge = community_merge (community, mpinfo->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (mpinfo->attr->community); + } + + ae = mpinfo->attr->extra; + if (ae && ae->ecommunity) + { + if (ecomm) + { + ecommerge = ecommunity_merge (ecomm, ae->ecommunity); + ecomm = ecommunity_uniq_sort (ecommerge); + ecommunity_free (ecommerge); + } + else + ecomm = ecommunity_dup (ae->ecommunity); + } + } + + attr.aspath = aspath; + attr.origin = origin; + if (community) + { + attr.community = community; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + if (ecomm) + { + ae = bgp_attr_extra_get (&attr); + ae->ecommunity = ecomm; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + } + + /* Zap multipath attr nexthop so we set nexthop to self */ + attr.nexthop.s_addr = 0; +#ifdef HAVE_IPV6 + if (attr.extra) + memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); +#endif /* HAVE_IPV6 */ + + /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */ + + new_attr = bgp_attr_intern (&attr); + bgp_attr_extra_free (&attr); + + if (new_attr != bgp_info_mpath_attr (new_best)) + { + if ((old_attr = bgp_info_mpath_attr (new_best))) + bgp_attr_unintern (old_attr); + bgp_info_mpath_attr_set (new_best, new_attr); + SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); + } + else + bgp_attr_unintern (new_attr); +} diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index 3712493ed..37b9ac8b7 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -43,6 +43,9 @@ struct bgp_info_mpath /* When attached to best path, the number of selected multipaths */ u_int32_t mp_count; + + /* Aggregated attribute for advertising multipath route */ + struct attr *mp_attr; }; /* Functions to support maximum-paths configuration */ @@ -59,6 +62,8 @@ extern void bgp_mp_dmed_deselect (struct bgp_info *); extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *, struct bgp_info *, struct list *, struct bgp_maxpaths_cfg *); +extern void bgp_info_mpath_aggregate_update (struct bgp_info *, + struct bgp_info *); /* Unlink and free multipath information associated with a bgp_info */ extern void bgp_info_mpath_dequeue (struct bgp_info *); @@ -70,5 +75,6 @@ extern struct bgp_info *bgp_info_mpath_next (struct bgp_info *); /* Accessors for multipath information */ extern u_int32_t bgp_info_mpath_count (struct bgp_info *); +extern struct attr *bgp_info_mpath_attr (struct bgp_info *); #endif /* _QUAGGA_BGP_MPATH_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5c4ab2666..a4923f57b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -785,10 +785,12 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, struct bgp *bgp; int transparent; int reflect; + struct attr *riattr; from = ri->peer; filter = &peer->filter[afi][safi]; bgp = peer->bgp; + riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) return 0; @@ -803,11 +805,11 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, /* If peer's id and route's nexthop are same. draft-ietf-idr-bgp4-23 5.1.3 */ if (p->family == AF_INET - && IPV4_ADDR_SAME(&peer->remote_id, &ri->attr->nexthop)) + && IPV4_ADDR_SAME(&peer->remote_id, &riattr->nexthop)) return 0; #ifdef HAVE_IPV6 if (p->family == AF_INET6 - && IPV6_ADDR_SAME(&peer->remote_id, &ri->attr->nexthop)) + && IPV6_ADDR_SAME(&peer->remote_id, &riattr->nexthop)) return 0; #endif @@ -835,14 +837,14 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, transparent = 0; /* If community is not disabled check the no-export and local. */ - if (! transparent && bgp_community_filter (peer, ri->attr)) + if (! transparent && bgp_community_filter (peer, riattr)) return 0; /* If the attribute has originator-id and it is same as remote peer's id. */ - if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) + if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { - if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->extra->originator_id)) + if (IPV4_ADDR_SAME (&peer->remote_id, &riattr->extra->originator_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, @@ -865,7 +867,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } /* Output filter check. */ - if (bgp_output_filter (peer, p, ri->attr, afi, safi) == FILTER_DENY) + if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, @@ -878,7 +880,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, #ifdef BGP_SEND_ASPATH_CHECK /* AS path loop check. */ - if (aspath_loop_check (ri->attr->aspath, peer->as)) + if (aspath_loop_check (riattr->aspath, peer->as)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, @@ -891,7 +893,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { - if (aspath_loop_check(ri->attr->aspath, bgp->confed_id)) + if (aspath_loop_check(riattr->aspath, bgp->confed_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, @@ -932,7 +934,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } /* For modify attribute, copy it to temporary structure. */ - bgp_attr_dup (attr, ri->attr); + bgp_attr_dup (attr, riattr); /* If local-preference is not set. */ if ((peer_sort (peer) == BGP_PEER_IBGP @@ -1091,10 +1093,12 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct bgp_info info; struct peer *from; struct bgp *bgp; + struct attr *riattr; from = ri->peer; filter = &rsclient->filter[afi][safi]; bgp = rsclient->bgp; + riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) return 0; @@ -1122,10 +1126,10 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, /* If the attribute has originator-id and it is same as remote peer's id. */ - if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) + if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { if (IPV4_ADDR_SAME (&rsclient->remote_id, - &ri->attr->extra->originator_id)) + &riattr->extra->originator_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, @@ -1148,7 +1152,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, } /* Output filter check. */ - if (bgp_output_filter (rsclient, p, ri->attr, afi, safi) == FILTER_DENY) + if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, @@ -1161,7 +1165,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, #ifdef BGP_SEND_ASPATH_CHECK /* AS path loop check. */ - if (aspath_loop_check (ri->attr->aspath, rsclient->as)) + if (aspath_loop_check (riattr->aspath, rsclient->as)) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, @@ -1172,7 +1176,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, #endif /* BGP_SEND_ASPATH_CHECK */ /* For modify attribute, copy it to temporary structure. */ - bgp_attr_dup (attr, ri->attr); + bgp_attr_dup (attr, riattr); /* next-hop-set */ if ((p->family == AF_INET && attr->nexthop.s_addr == 0) @@ -1410,6 +1414,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); + bgp_info_mpath_aggregate_update (new_select, old_select); bgp_mp_list_clear (&mp_list); result->old = old_select; From 78d92e1721538ec41feb2b1c34712675b830087b Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:51:07 -0700 Subject: [PATCH 0008/1342] bgpd: Fix a crash caused by mistakenly dequeueing the bestpath on the multipath list. This causes the multipath list to get truncated but the multipath count still reflects what it was before truncation. When we install the route to zebra we fail to fill the nexthop array with the number of nexthop pointers indicated by the multipath count and this leads to a NULL pointer crash in stream_put_in_addr(). Changes: * bgpd/bgp_mpath.c * bgp_info_mpath_update(): If new_mpath is the bestpath we should just move to the next mp_list node. Move dequeue of new_mpath and the code that updates next_mpath to inside the check that new_mpath is not the bestpath. --- bgpd/bgp_mpath.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 44823c4ba..1709c2448 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -521,12 +521,13 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, */ new_mpath = listgetdata (mp_node); list_delete_node (mp_list, mp_node); - if (new_mpath == next_mpath) - next_mpath = bgp_info_mpath_next (new_mpath); - bgp_info_mpath_dequeue (new_mpath); if ((mpath_count < maxpaths) && (new_mpath != new_best) && bgp_info_nexthop_cmp (prev_mpath, new_mpath)) { + if (new_mpath == next_mpath) + next_mpath = bgp_info_mpath_next (new_mpath); + bgp_info_mpath_dequeue (new_mpath); + bgp_info_mpath_enqueue (prev_mpath, new_mpath); prev_mpath = new_mpath; mpath_changed = 1; From 01d7ff0a2166a422c56bd26f04fc22832a9e690b Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 20 Jul 2011 20:52:06 -0700 Subject: [PATCH 0009/1342] bgpd: We try to skip out of updating the multipath aggregate if there are no changes in the multipath set or attributes, but failed to check for just a bestpath change. The result is there is no attribute on the new bestpath and we hit the assert. Added the bestpath check and rearranged the code to only check attributes when there is no bestpath or multipath change, so we only scan the for attribute changes when necessary. * bgpd/bgp_mpath.c * bgp_info_mpath_aggregate_update(): Added check for bestpath change before skipping the aggregate generation. Skip the attribute check if either the multipath set or bestpath has changed. --- bgpd/bgp_mpath.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 1709c2448..d07830d14 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -626,25 +626,32 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, /* * Bail out here if the following is true: * - MULTIPATH_CHG bit is not set on new_best, and + * - No change in bestpath, and * - ATTR_CHANGED bit is not set on new_best or any of the multipaths */ - attr_chg = 0; - if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED)) - attr_chg = 1; - else - for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; - mpinfo = bgp_info_mpath_next (mpinfo)) - { - if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) + if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) && + (old_best == new_best)) + { + attr_chg = 0; + + if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED)) + attr_chg = 1; + else + for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) { - attr_chg = 1; - break; + if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) + { + attr_chg = 1; + break; + } } - } - if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) && !attr_chg) - { - assert (bgp_info_mpath_attr (new_best)); - return; + + if (!attr_chg) + { + assert (bgp_info_mpath_attr (new_best)); + return; + } } bgp_attr_dup (&attr, new_best->attr); From 54dd61227352dd1dd4db4fe76dbf7d2e92522e74 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 21 Mar 2012 10:00:07 -0700 Subject: [PATCH 0010/1342] lib: Tweaks to linked list macros * lib/linklist.h - Change the listnextnode, listhead and listtail macros so that they allow the list pointer to be NULL. - Modify the ALL_LIST_ELEMENTS* macros such that they clear the data pointer at the beginning and end of the loop. From: Josh Bailey Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/linklist.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/linklist.h b/lib/linklist.h index cc6867cd4..f0ae36256 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -54,9 +54,9 @@ struct list void (*del) (void *val); }; -#define listnextnode(X) ((X)->next) -#define listhead(X) ((X)->head) -#define listtail(X) ((X)->tail) +#define listnextnode(X) ((X) ? ((X)->next) : NULL) +#define listhead(X) ((X) ? ((X)->head) : NULL) +#define listtail(X) ((X) ? ((X)->tail) : NULL) #define listcount(X) ((X)->count) #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) #define listgetdata(X) (assert((X)->data != NULL), (X)->data) @@ -88,10 +88,10 @@ extern void list_add_list (struct list *, struct list *); * It is safe to delete the listnode using this macro. */ #define ALL_LIST_ELEMENTS(list,node,nextnode,data) \ - (node) = listhead(list); \ + (node) = listhead(list), ((data) = NULL); \ (node) != NULL && \ ((data) = listgetdata(node),(nextnode) = listnextnode(node), 1); \ - (node) = (nextnode) + (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. * Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only @@ -100,9 +100,9 @@ extern void list_add_list (struct list *, struct list *); * of previous macro. */ #define ALL_LIST_ELEMENTS_RO(list,node,data) \ - (node) = listhead(list); \ + (node) = listhead(list), ((data) = NULL);\ (node) != NULL && ((data) = listgetdata(node), 1); \ - (node) = listnextnode(node) + (node) = listnextnode(node), ((data) = NULL) /* these *do not* cleanup list nodes and referenced data, as the functions * do - these macros simply {de,at}tach a listnode from/to a list. From bed930fd70742af5ae138e0a5ee629dda296ea36 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 21 Mar 2012 10:22:19 -0700 Subject: [PATCH 0011/1342] lib: add support for keyed-hashing with MD5 * lib/md5.[ch] Add implementation of HMAC-MD5 from RFC 2104. From: Josh Bailey Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/md5.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/md5.h | 4 +++ 2 files changed, 77 insertions(+) diff --git a/lib/md5.c b/lib/md5.c index 894de648b..2fc36e179 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -298,3 +298,76 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt) ctxt->md5_stc += C; ctxt->md5_std += D; } + +/* From RFC 2104 */ +void +hmac_md5(text, text_len, key, key_len, digest) +unsigned char* text; /* pointer to data stream */ +int text_len; /* length of data stream */ +unsigned char* key; /* pointer to authentication key */ +int key_len; /* length of authentication key */ +caddr_t digest; /* caller digest to be filled in */ + +{ + MD5_CTX context; + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + */ + unsigned char tk[16]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + bzero( k_ipad, sizeof k_ipad); + bzero( k_opad, sizeof k_opad); + bcopy( key, k_ipad, key_len); + bcopy( key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + MD5Init(&context); /* init context for 1st + * pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, text, text_len); /* then text of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd + * pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st + * hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ +} diff --git a/lib/md5.h b/lib/md5.h index 89b9a3209..a03bf22a2 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -82,4 +82,8 @@ do { \ md5_result((x), (y)); \ } while (0) +/* From RFC 2104 */ +void hmac_md5(unsigned char* text, int text_len, unsigned char* key, + int key_len, caddr_t digest); + #endif /* ! _LIBZEBRA_MD5_H_*/ From d531050b7bf0f93d4d29a7a2f7b745641778b483 Mon Sep 17 00:00:00 2001 From: Subbaiah Venkata Date: Sat, 24 Mar 2012 13:10:19 -0700 Subject: [PATCH 0012/1342] lib: add stream_set_endp() * lib/stream.[ch]: - Add stream_set_endp(). This can be used to trim data (for example, padding) at the end of a stream. - Fix swapped 'getp' and 'endp' parameters in STREAM_WARN_OFFSETS. From: Subbaiah Venkata Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/stream.c | 20 +++++++++++++++++--- lib/stream.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/stream.c b/lib/stream.c index 983330ffb..b226a25ea 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -52,7 +52,7 @@ * using stream_put..._at() functions. */ #define STREAM_WARN_OFFSETS(S) \ - zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \ + zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \ (S), \ (unsigned long) (S)->size, \ (unsigned long) (S)->getp, \ @@ -214,6 +214,20 @@ stream_set_getp (struct stream *s, size_t pos) s->getp = pos; } +void +stream_set_endp (struct stream *s, size_t pos) +{ + STREAM_VERIFY_SANE(s); + + if (!GETP_VALID (s, pos)) + { + STREAM_BOUND_WARN (s, "set endp"); + pos = s->endp; + } + + s->endp = pos; +} + /* Forward pointer. */ void stream_forward_getp (struct stream *s, size_t size) @@ -934,9 +948,9 @@ stream_fifo_pop (struct stream_fifo *fifo) if (fifo->head == NULL) fifo->tail = NULL; - } - fifo->count--; + fifo->count--; + } return s; } diff --git a/lib/stream.h b/lib/stream.h index 3e4ba7b41..f10aa6d41 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -146,6 +146,7 @@ extern size_t stream_get_size (struct stream *); extern u_char *stream_get_data (struct stream *); extern void stream_set_getp (struct stream *, size_t); +extern void stream_set_endp (struct stream *, size_t); extern void stream_forward_getp (struct stream *, size_t); extern void stream_forward_endp (struct stream *, size_t); From 26e2ae362baf207d82e4c1ac76bc1c2b2df6ccaa Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Thu, 22 Mar 2012 01:09:21 -0700 Subject: [PATCH 0013/1342] zebra: read multipath routes and hw addr from netlink * zebra/rt_netlink.c: - Pick up the hardware address of an interface when we receive a netlink link change message. Extract code for parsing the link-layer hardware address into a new function so we can reuse it. - netlink_routing_table(): Update to handle multipath routes. - netlink_route_change(): Update to handle multipath routes. Fix problem where the metric was not being read out. * zebra/zebra_rib.[ch]: Extern nexthop_ipv4_ifindex_add() -- it is now called from the netlink code. From: Josh Bailey Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- zebra/rib.h | 4 + zebra/rt_netlink.c | 188 ++++++++++++++++++++++++++++++++++++++------- zebra/zebra_rib.c | 2 +- 3 files changed, 165 insertions(+), 29 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 887ed3c2c..b5c9e0524 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -225,6 +225,10 @@ extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, struct in_addr *); +extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, + struct in_addr *, + struct in_addr *, + unsigned int); extern void rib_lookup_and_dump (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 *); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7652f80a9..2cde50a1d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -32,6 +32,7 @@ #include "prefix.h" #include "connected.h" #include "table.h" +#include "memory.h" #include "rib.h" #include "thread.h" #include "privs.h" @@ -426,6 +427,37 @@ netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, } } +/* Utility function to parse hardware link-layer address and update ifp */ +static void +netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) +{ + int i; + + if (tb[IFLA_ADDRESS]) + { + int hw_addr_len; + + hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]); + + if (hw_addr_len > INTERFACE_HWADDR_MAX) + zlog_warn ("Hardware address is too large: %d", hw_addr_len); + else + { + ifp->hw_addr_len = hw_addr_len; + memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len); + + for (i = 0; i < hw_addr_len; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == hw_addr_len) + ifp->hw_addr_len = 0; + else + ifp->hw_addr_len = hw_addr_len; + } + } +} + /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int @@ -436,7 +468,6 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; - int i; ifi = NLMSG_DATA (h); @@ -474,30 +505,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Hardware type and address. */ ifp->hw_type = ifi->ifi_type; - - if (tb[IFLA_ADDRESS]) - { - int hw_addr_len; - - hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]); - - if (hw_addr_len > INTERFACE_HWADDR_MAX) - zlog_warn ("Hardware address is too large: %d", hw_addr_len); - else - { - ifp->hw_addr_len = hw_addr_len; - memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len); - - for (i = 0; i < hw_addr_len; i++) - if (ifp->hw_addr[i] != 0) - break; - - if (i == hw_addr_len) - ifp->hw_addr_len = 0; - else - ifp->hw_addr_len = hw_addr_len; - } - } + netlink_interface_update_hw_addr (tb, ifp); if_add_update (ifp); @@ -709,7 +717,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); - /* Multipath treatment is needed. */ if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); @@ -723,7 +730,64 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); + if (!tb[RTA_MULTIPATH]) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, + table, metric, 0); + else + { + /* This is a multipath route */ + + struct rib *rib; + struct rtnexthop *rtnh = + (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); + + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + rib->type = ZEBRA_ROUTE_KERNEL; + rib->distance = 0; + rib->flags = flags; + rib->metric = metric; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + for (;;) + { + if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) + break; + + rib->nexthop_num++; + index = rtnh->rtnh_ifindex; + gate = 0; + if (rtnh->rtnh_len > sizeof (*rtnh)) + { + memset (tb, 0, sizeof (tb)); + netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh)); + if (tb[RTA_GATEWAY]) + gate = RTA_DATA (tb[RTA_GATEWAY]); + } + + if (gate) + { + if (index) + nexthop_ipv4_ifindex_add (rib, gate, src, index); + else + nexthop_ipv4_add (rib, gate, src); + } + else + nexthop_ifindex_add (rib, index); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + if (rib->nexthop_num == 0) + XFREE (MTYPE_RIB, rib); + else + rib_add_ipv4_multipath (&p, rib); + } } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) @@ -768,6 +832,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) int index; int table; + int metric; void *dest; void *gate; void *src; @@ -825,6 +890,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } index = 0; + metric = 0; dest = NULL; gate = NULL; src = NULL; @@ -843,6 +909,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); + if (tb[RTA_PRIORITY]) + metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; @@ -861,7 +930,66 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); + { + if (!tb[RTA_MULTIPATH]) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, + metric, 0); + else + { + /* This is a multipath route */ + + struct rib *rib; + struct rtnexthop *rtnh = + (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); + + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + rib->type = ZEBRA_ROUTE_KERNEL; + rib->distance = 0; + rib->flags = 0; + rib->metric = metric; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + for (;;) + { + if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) + break; + + rib->nexthop_num++; + index = rtnh->rtnh_ifindex; + gate = 0; + if (rtnh->rtnh_len > sizeof (*rtnh)) + { + memset (tb, 0, sizeof (tb)); + netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh)); + if (tb[RTA_GATEWAY]) + gate = RTA_DATA (tb[RTA_GATEWAY]); + } + + if (gate) + { + if (index) + nexthop_ipv4_ifindex_add (rib, gate, src, index); + else + nexthop_ipv4_add (rib, gate, src); + } + else + nexthop_ifindex_add (rib, index); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + if (rib->nexthop_num == 0) + XFREE (MTYPE_RIB, rib); + else + rib_add_ipv4_multipath (&p, rib); + } + } else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); } @@ -954,6 +1082,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; + netlink_interface_update_hw_addr (tb, ifp); + /* If new link is added. */ if_add_update (ifp); } @@ -964,6 +1094,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; + netlink_interface_update_hw_addr (tb, ifp); + if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 12f3fa5a5..580b75bb8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -225,7 +225,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) return nexthop; } -static struct nexthop * +struct nexthop * nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src, unsigned int ifindex) { From 6902c69aa30a73ecd70ef8941518b541ca02b878 Mon Sep 17 00:00:00 2001 From: Subbaiah Venkata Date: Tue, 27 Mar 2012 19:21:29 -0700 Subject: [PATCH 0014/1342] zebra: tweak deletion of routes without nexthop addr * zebra/zserv.c - zread_ipv4_delete(): Pass a null 'gate' parameter to rib_delete_ipv4() if the route being deleted does not specify a next hop IP address. We were previously passing a pointer to a cleared out IP address. - zread_ipv4_add(): Fix indentation. From: Subbaiah Venkata Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- zebra/zserv.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index dc3d432bd..9e6f6253c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -786,10 +786,10 @@ zread_ipv4_add (struct zserv *client, u_short length) case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; - case ZEBRA_NEXTHOP_BLACKHOLE: - nexthop_blackhole_add (rib); - break; - } + case ZEBRA_NEXTHOP_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } } } @@ -814,7 +814,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) int i; struct stream *s; struct zapi_ipv4 api; - struct in_addr nexthop; + struct in_addr nexthop, *nexthop_p; unsigned long ifindex; struct prefix_ipv4 p; u_char nexthop_num; @@ -824,6 +824,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) s = client->ibuf; ifindex = 0; nexthop.s_addr = 0; + nexthop_p = NULL; /* Type, flags, message. */ api.type = stream_getc (s); @@ -856,6 +857,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); + nexthop_p = &nexthop; break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); @@ -876,7 +878,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) else api.metric = 0; - rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, + rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, client->rtm_table); return 0; } From 3f045a08812525505e165deea99a79447b44506b Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Sat, 24 Mar 2012 08:35:20 -0700 Subject: [PATCH 0015/1342] isisd: add Google's changes to IS-IS --- isisd/dict.c | 29 +- isisd/dict.h | 21 - isisd/isis_adjacency.c | 313 ++--- isisd/isis_adjacency.h | 16 +- isisd/isis_bpf.c | 15 +- isisd/isis_circuit.c | 2575 +++++++++++++++++++++++++--------------- isisd/isis_circuit.h | 57 +- isisd/isis_common.h | 13 +- isisd/isis_constants.h | 78 +- isisd/isis_csm.c | 36 +- isisd/isis_dlpi.c | 18 +- isisd/isis_dr.c | 69 +- isisd/isis_dynhn.c | 35 +- isisd/isis_dynhn.h | 2 + isisd/isis_events.c | 150 ++- isisd/isis_events.h | 3 +- isisd/isis_flags.c | 8 +- isisd/isis_flags.h | 35 +- isisd/isis_lsp.c | 1517 +++++++++++++---------- isisd/isis_lsp.h | 46 +- isisd/isis_main.c | 29 +- isisd/isis_misc.c | 134 ++- isisd/isis_misc.h | 13 +- isisd/isis_pdu.c | 1486 +++++++++++++++-------- isisd/isis_pdu.h | 19 +- isisd/isis_pfpacket.c | 91 +- isisd/isis_route.c | 248 ++-- isisd/isis_route.h | 10 +- isisd/isis_routemap.c | 1 + isisd/isis_spf.c | 1073 ++++++++++------- isisd/isis_spf.h | 21 +- isisd/isis_tlv.c | 58 +- isisd/isis_tlv.h | 80 +- isisd/isis_zebra.c | 82 +- isisd/isisd.c | 1991 +++++++++++++++++++++++-------- isisd/isisd.h | 20 +- lib/memtypes.c | 2 + 37 files changed, 6649 insertions(+), 3745 deletions(-) diff --git a/isisd/dict.c b/isisd/dict.c index 6c3e1e7fd..35cb924ca 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -18,17 +18,11 @@ * $Name$ */ -#include -#include #include "zebra.h" #include "zassert.h" -#define DICT_IMPLEMENTATION +#include "memory.h" #include "dict.h" -#ifdef KAZLIB_RCSID -static const char rcsid[] = "Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz"; -#endif - /* * These macros provide short convenient names for structure members, * which are embellished with dict_ prefixes so that they are @@ -246,7 +240,7 @@ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) { - dict_t *new = malloc(sizeof *new); + dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t)); if (new) { new->compare = comp; @@ -287,7 +281,7 @@ void dict_set_allocator(dict_t *dict, dnode_alloc_t al, void dict_destroy(dict_t *dict) { assert (dict_isempty(dict)); - free(dict); + XFREE(MTYPE_ISIS_DICT, dict); } /* @@ -310,9 +304,6 @@ void dict_free_nodes(dict_t *dict) void dict_free(dict_t *dict) { -#ifdef KAZLIB_OBSOLESCENT_DEBUG - assert ("call to obsolescent function dict_free()" && 0); -#endif dict_free_nodes(dict); } @@ -813,7 +804,7 @@ dnode_t *dict_delete(dict_t *dict, dnode_t *delete) int dict_alloc_insert(dict_t *dict, const void *key, void *data) { - dnode_t *node = dict->allocnode(dict->context); + dnode_t *node = dict->allocnode (dict->context); if (node) { dnode_init(node, data); @@ -949,17 +940,17 @@ int dict_contains(dict_t *dict, dnode_t *node) static dnode_t *dnode_alloc(void *context) { - return malloc(sizeof *dnode_alloc(NULL)); + return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t)); } static void dnode_free(dnode_t *node, void *context) { - free(node); + XFREE(MTYPE_ISIS_DICT_NODE, node); } dnode_t *dnode_create(void *data) { - dnode_t *new = malloc(sizeof *new); + dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t)); if (new) { new->data = data; new->parent = NULL; @@ -981,7 +972,7 @@ dnode_t *dnode_init(dnode_t *dnode, void *data) void dnode_destroy(dnode_t *dnode) { assert (!dnode_is_in_a_dict(dnode)); - free(dnode); + XFREE(MTYPE_ISIS_DICT_NODE, dnode); } void *dnode_get(dnode_t *dnode) @@ -1235,7 +1226,7 @@ static int comparef(const void *key1, const void *key2) static char *dupstring(char *str) { int sz = strlen(str) + 1; - char *new = malloc(sz); + char *new = XCALLOC(MTYPE_ISIS_TMP, sz); if (new) memcpy(new, str, sz); return new; @@ -1350,7 +1341,7 @@ int main(void) "s switch to non-functioning allocator\n" "q quit"; - for (i = 0; i < sizeof darray / sizeof *darray; i++) + for (i = 0; i < 10; i++) dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); for (;;) { diff --git a/isisd/dict.h b/isisd/dict.h index 9395d1c08..93edb7d60 100644 --- a/isisd/dict.h +++ b/isisd/dict.h @@ -22,9 +22,6 @@ #define DICT_H #include -#ifdef KAZLIB_SIDEEFFECT_DEBUG -#include "sfx.h" -#endif /* * Blurb for inclusion into C++ translation units @@ -44,16 +41,12 @@ typedef unsigned long dictcount_t; typedef enum { dnode_red, dnode_black } dnode_color_t; typedef struct dnode_t { - #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) struct dnode_t *dict_left; struct dnode_t *dict_right; struct dnode_t *dict_parent; dnode_color_t dict_color; const void *dict_key; void *dict_data; - #else - int dict_dummy; - #endif } dnode_t; typedef int (*dict_comp_t)(const void *, const void *); @@ -61,7 +54,6 @@ typedef dnode_t *(*dnode_alloc_t)(void *); typedef void (*dnode_free_t)(dnode_t *, void *); typedef struct dict_t { - #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) dnode_t dict_nilnode; dictcount_t dict_nodecount; dictcount_t dict_maxcount; @@ -70,20 +62,13 @@ typedef struct dict_t { dnode_free_t dict_freenode; void *dict_context; int dict_dupes; - #else - int dict_dummmy; - #endif } dict_t; typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); typedef struct dict_load_t { - #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) dict_t *dict_dictptr; dnode_t dict_nilnode; - #else - int dict_dummmy; - #endif } dict_load_t; extern dict_t *dict_create(dictcount_t, dict_comp_t); @@ -124,18 +109,12 @@ extern void dict_load_next(dict_load_t *, dnode_t *, const void *); extern void dict_load_end(dict_load_t *); extern void dict_merge(dict_t *, dict_t *); -#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -#ifdef KAZLIB_SIDEEFFECT_DEBUG -#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) -#else #define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) -#endif #define dict_count(D) ((D)->dict_nodecount) #define dict_isempty(D) ((D)->dict_nodecount == 0) #define dnode_get(N) ((N)->dict_data) #define dnode_getkey(N) ((N)->dict_key) #define dnode_put(N, X) ((N)->dict_data = (X)) -#endif #ifdef __cplusplus } diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index aab8d1a3d..10bce3e8a 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -36,6 +36,7 @@ #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_adjacency.h" @@ -43,6 +44,10 @@ #include "isisd/isis_dr.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_pdu.h" +#include "isisd/isis_tlv.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_events.h" extern struct isis *isis; @@ -73,9 +78,9 @@ isis_new_adj (u_char * id, u_char * snpa, int level, } if (snpa) { - memcpy (adj->snpa, snpa, 6); + memcpy (adj->snpa, snpa, ETH_ALEN); } else { - memset (adj->snpa, ' ', 6); + memset (adj->snpa, ' ', ETH_ALEN); } adj->circuit = circuit; @@ -125,37 +130,60 @@ isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb) } void -isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb) +isis_delete_adj (void *arg) { + struct isis_adjacency *adj = arg; + if (!adj) return; - /* When we recieve a NULL list, we will know its p2p. */ - if (adjdb) - listnode_delete (adjdb, adj); - THREAD_OFF (adj->t_expire); + THREAD_TIMER_OFF (adj->t_expire); + + /* remove from SPF trees */ + spftree_area_adj_del (adj->circuit->area, adj); + if (adj->area_addrs) + list_delete (adj->area_addrs); if (adj->ipv4_addrs) list_delete (adj->ipv4_addrs); #ifdef HAVE_IPV6 if (adj->ipv6_addrs) list_delete (adj->ipv6_addrs); #endif - + XFREE (MTYPE_ISIS_ADJACENCY, adj); return; } +static const char * +adj_state2string (int state) +{ + + switch (state) + { + case ISIS_ADJ_INITIALIZING: + return "Initializing"; + case ISIS_ADJ_UP: + return "Up"; + case ISIS_ADJ_DOWN: + return "Down"; + default: + return "Unknown"; + } + + return NULL; /* not reached */ +} + void -isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, +isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state, const char *reason) { int old_state; - int level = adj->level; + int level; struct isis_circuit *circuit; old_state = adj->adj_state; - adj->adj_state = state; + adj->adj_state = new_state; circuit = adj->circuit; @@ -163,42 +191,103 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, { zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s", circuit->area->area_tag, - old_state, state, reason ? reason : "unspecified"); + old_state, new_state, reason ? reason : "unspecified"); } - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + if (circuit->area->log_adj_changes) { - if (state == ISIS_ADJ_UP) - circuit->upadjcount[level - 1]++; - if (state == ISIS_ADJ_DOWN) - { - isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]); - circuit->upadjcount[level - 1]--; - } + const char *adj_name; + struct isis_dynhn *dyn; - list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); - isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], - circuit->u.bc.lan_neighs[level - 1]); + dyn = dynhn_find_by_id (adj->sysid); + if (dyn) + adj_name = (const char *)dyn->name.name; + else + adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown"; + + zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", + adj_name, + adj->circuit ? adj->circuit->interface->name : "no circuit", + adj_state2string (old_state), + adj_state2string (new_state), + reason ? reason : "unspecified"); } - else if (state == ISIS_ADJ_UP) - { /* p2p interface */ - if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) - send_hello (circuit, 1); - - /* update counter & timers for debugging purposes */ - adj->last_flap = time (NULL); - adj->flaps++; - - /* 7.3.17 - going up on P2P -> send CSNP */ - /* FIXME: yup, I know its wrong... but i will do it! (for now) */ - send_csnp (circuit, 1); - send_csnp (circuit, 2); + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) + { + if ((adj->level & level) == 0) + continue; + if (new_state == ISIS_ADJ_UP) + { + circuit->upadjcount[level - 1]++; + isis_event_adjacency_state_change (adj, new_state); + /* update counter & timers for debugging purposes */ + adj->last_flap = time (NULL); + adj->flaps++; + } + else if (new_state == ISIS_ADJ_DOWN) + { + listnode_delete (circuit->u.bc.adjdb[level - 1], adj); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + { + /* Clean lsp_queue when no adj is up. */ + if (circuit->lsp_queue) + list_delete_all_node (circuit->lsp_queue); + } + isis_event_adjacency_state_change (adj, new_state); + isis_delete_adj (adj); + } + list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); + isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], + circuit->u.bc.lan_neighs[level - 1]); + + /* On adjacency state change send new pseudo LSP if we are the DR */ + if (circuit->u.bc.is_dr[level - 1]) + lsp_regenerate_schedule_pseudo (circuit, level); + } } - else if (state == ISIS_ADJ_DOWN) - { /* p2p interface */ - adj->circuit->u.p2p.neighbor = NULL; - isis_delete_adj (adj, NULL); + else if (circuit->circ_type == CIRCUIT_T_P2P) + { + for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) + { + if ((adj->level & level) == 0) + continue; + if (new_state == ISIS_ADJ_UP) + { + circuit->upadjcount[level - 1]++; + isis_event_adjacency_state_change (adj, new_state); + + if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) + send_hello (circuit, level); + + /* update counter & timers for debugging purposes */ + adj->last_flap = time (NULL); + adj->flaps++; + + /* 7.3.17 - going up on P2P -> send CSNP */ + /* FIXME: yup, I know its wrong... but i will do it! (for now) */ + send_csnp (circuit, level); + } + else if (new_state == ISIS_ADJ_DOWN) + { + if (adj->circuit->u.p2p.neighbor == adj) + adj->circuit->u.p2p.neighbor = NULL; + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + { + /* Clean lsp_queue when no adj is up. */ + if (circuit->lsp_queue) + list_delete_all_node (circuit->lsp_queue); + } + isis_event_adjacency_state_change (adj, new_state); + isis_delete_adj (adj); + } + } } + return; } @@ -225,7 +314,7 @@ isis_adj_print (struct isis_adjacency *adj) snpa_print (adj->snpa), adj->level, adj->hold_time); if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { - zlog_debug ("IPv4 Addresses:"); + zlog_debug ("IPv4 Address(es):"); for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr)) zlog_debug ("%s", inet_ntoa (*ipv4_addr)); @@ -234,7 +323,7 @@ isis_adj_print (struct isis_adjacency *adj) #ifdef HAVE_IPV6 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { - zlog_debug ("IPv6 Addresses:"); + zlog_debug ("IPv6 Address(es):"); for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN); @@ -251,14 +340,12 @@ int isis_adj_expire (struct thread *thread) { struct isis_adjacency *adj; - int level; /* * Get the adjacency */ adj = THREAD_ARG (thread); assert (adj); - level = adj->level; adj->t_expire = NULL; /* trigger the adj expire event */ @@ -267,32 +354,12 @@ isis_adj_expire (struct thread *thread) return 0; } -static const char * -adj_state2string (int state) -{ - - switch (state) - { - case ISIS_ADJ_INITIALIZING: - return "Initializing"; - case ISIS_ADJ_UP: - return "Up"; - case ISIS_ADJ_DOWN: - return "Down"; - default: - return "Unknown"; - } - - return NULL; /* not reached */ -} - /* - * show clns/isis neighbor (detail) + * show isis neighbor [detail] */ -static void -isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail) +void +isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail) { - #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; u_char ip6[INET6_ADDRSTRLEN]; @@ -335,10 +402,11 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail) if (detail == ISIS_UI_LEVEL_DETAIL) { level = adj->level; + vty_out (vty, "%s", VTY_NEWLINE); if (adj->circuit) - vty_out (vty, "%s Interface: %s", VTY_NEWLINE, adj->circuit->interface->name); /* interface name */ + vty_out (vty, " Interface: %s", adj->circuit->interface->name); else - vty_out (vty, "NULL circuit!%s", VTY_NEWLINE); + vty_out (vty, " Interface: NULL circuit"); vty_out (vty, ", Level: %u", adj->level); /* level */ vty_out (vty, ", State: %s", adj_state2string (adj->adj_state)); now = time (NULL); @@ -347,40 +415,54 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail) time2string (adj->last_upd + adj->hold_time - now)); else vty_out (vty, ", Expires in %s", time2string (adj->hold_time)); - vty_out (vty, "%s Adjacency flaps: %u", VTY_NEWLINE, adj->flaps); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Adjacency flaps: %u", adj->flaps); vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap)); - vty_out (vty, "%s Circuit type: %s", - VTY_NEWLINE, circuit_t2string (adj->circuit_t)); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t)); vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids)); - vty_out (vty, "%s SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa)); - dyn = dynhn_find_by_id (adj->lanid); - if (dyn) - vty_out (vty, ", LAN id: %s.%02x", - dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]); - else - vty_out (vty, ", LAN id: %s.%02x", - sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]); - - vty_out (vty, "%s Priority: %u", - VTY_NEWLINE, adj->prio[adj->level - 1]); - - vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s", - isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1]. - dis), adj->dischanges[level - 1], - time2string (now - - (adj->dis_record[ISIS_LEVELS + level - 1]. - last_dis_change)), VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " SNPA: %s", snpa_print (adj->snpa)); + if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST) + { + dyn = dynhn_find_by_id (adj->lanid); + if (dyn) + vty_out (vty, ", LAN id: %s.%02x", + dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]); + else + vty_out (vty, ", LAN id: %s.%02x", + sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]); + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]); + + vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago", + isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1]. + dis), adj->dischanges[level - 1], + time2string (now - + (adj->dis_record[ISIS_LEVELS + level - 1]. + last_dis_change))); + } + vty_out (vty, "%s", VTY_NEWLINE); + if (adj->area_addrs && listcount (adj->area_addrs) > 0) + { + struct area_addr *area_addr; + vty_out (vty, " Area Address(es):%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr)) + vty_out (vty, " %s%s", isonet_print (area_addr->area_addr, + area_addr->addr_len), VTY_NEWLINE); + } if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { - vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE); + vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr)) vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE); } #ifdef HAVE_IPV6 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { - vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE); + vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN); @@ -393,53 +475,6 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail) return; } -void -isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty) -{ - isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF); -} - -void -isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) -{ - isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL); -} - -void -isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) -{ - isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE); -} - -void -isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty) -{ - isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF); -} - -void -isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) -{ - isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL); -} - -void -isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) -{ - isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE); -} - -void -isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *, - void *), void *arg) -{ - struct listnode *node, *nnode; - struct isis_adjacency *adj; - - for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj)) - (*func) (adj, arg); -} - void isis_adj_build_neigh_list (struct list *adjdb, struct list *list) { diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 99a8bb228..04a925059 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -103,25 +103,13 @@ struct isis_adjacency *isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb); struct isis_adjacency *isis_new_adj (u_char * id, u_char * snpa, int level, struct isis_circuit *circuit); -void isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb); +void isis_delete_adj (void *adj); void isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, const char *reason); void isis_adj_print (struct isis_adjacency *adj); int isis_adj_expire (struct thread *thread); -void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty); -void isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty); -void isis_adj_print_vty_extensive (struct isis_adjacency *adj, - struct vty *vty); -void isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty); -void isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, - struct vty *vty); -void isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, - struct vty *vty); - +void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail); void isis_adj_build_neigh_list (struct list *adjdb, struct list *list); void isis_adj_build_up_list (struct list *adjdb, struct list *list); -void isis_adjdb_iterate (struct list *adjdb, - void (*func) (struct isis_adjacency *, - void *), void *arg); #endif /* ISIS_ADJACENCY_H */ diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 05f11386c..4d5b16513 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -301,7 +301,16 @@ int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { struct ether_header *eth; - int written; + int written, buflen; + + buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN; + if (buflen > sizeof (sock_buff)) + { + zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than " + "output pdu size %d on circuit %s", + sizeof (sock_buff), buflen, circuit->interface->name); + return ISIS_WARNING; + } stream_set_getp (circuit->snd_stream, 0); @@ -328,9 +337,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) stream_get_endp (circuit->snd_stream)); /* now we can send this */ - written = write (circuit->fd, sock_buff, - stream_get_endp (circuit->snd_stream) - + LLC_LEN + ETHER_HDR_LEN); + written = write (circuit->fd, sock_buff, buflen); return ISIS_OK; } diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index d2923b575..cb439e877 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -44,6 +44,7 @@ #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" @@ -53,18 +54,13 @@ #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" -#include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" -extern struct thread_master *master; -extern struct isis *isis; - /* * Prototypes. */ -void isis_circuit_down(struct isis_circuit *); int isis_interface_config_write(struct vty *); int isis_if_new_hook(struct interface *); int isis_if_delete_hook(struct interface *); @@ -76,55 +72,63 @@ isis_circuit_new () int i; circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit)); - if (circuit) - { - /* set default metrics for circuit */ - for (i = 0; i < 2; i++) - { - circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRICS; - circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; - circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; - circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; - circuit->te_metric[i] = DEFAULT_CIRCUIT_METRICS; - } - } - else + if (circuit == NULL) { zlog_err ("Can't malloc isis circuit"); return NULL; } + /* + * Default values + */ + circuit->is_type = IS_LEVEL_1_AND_2; + circuit->flags = 0; + circuit->pad_hellos = 1; + for (i = 0; i < 2; i++) + { + circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL; + circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER; + circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; + circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; + circuit->priority[i] = DEFAULT_PRIORITY; + circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC; + circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; + circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; + circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; + circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; + } + return circuit; } +void +isis_circuit_del (struct isis_circuit *circuit) +{ + if (!circuit) + return; + + isis_circuit_if_unbind (circuit, circuit->interface); + + /* and lastly the circuit itself */ + XFREE (MTYPE_ISIS_CIRCUIT, circuit); + + return; +} + void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area) { - int i; + assert (area); circuit->area = area; + /* * The level for the circuit is same as for the area, unless configured * otherwise. */ - circuit->circuit_is_type = area->is_type; - /* - * Default values - */ - for (i = 0; i < 2; i++) - { - circuit->hello_interval[i] = HELLO_INTERVAL; - circuit->hello_multiplier[i] = HELLO_MULTIPLIER; - circuit->csnp_interval[i] = CSNP_INTERVAL; - circuit->psnp_interval[i] = PSNP_INTERVAL; - circuit->u.bc.priority[i] = DEFAULT_PRIORITY; - } - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - circuit->u.bc.adjdb[0] = list_new (); - circuit->u.bc.adjdb[1] = list_new (); - circuit->u.bc.pad_hellos = 1; - } - circuit->lsp_interval = LSP_INTERVAL; + if (area->is_type != IS_LEVEL_1_AND_2 && area->is_type != circuit->is_type) + zlog_warn ("circut %s is_type %d mismatch with area %s is_type %d", + circuit->interface->name, circuit->is_type, + circuit->area->area_tag, area->is_type); /* * Add the circuit into area @@ -132,20 +136,20 @@ isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area) listnode_add (area->circuit_list, circuit); circuit->idx = flags_get_index (&area->flags); - circuit->lsp_queue = list_new (); return; } void -isis_circuit_deconfigure (struct isis_circuit *circuit, - struct isis_area *area) +isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area) { - - /* Remove circuit from area */ - listnode_delete (area->circuit_list, circuit); /* Free the index of SRM and SSN flags */ flags_free_index (&area->flags, circuit->idx); + circuit->idx = 0; + /* Remove circuit from area */ + assert (circuit->area == area); + listnode_delete (area->circuit_list, circuit); + circuit->area = NULL; return; } @@ -161,8 +165,11 @@ circuit_lookup_by_ifp (struct interface *ifp, struct list *list) for (ALL_LIST_ELEMENTS_RO (list, node, circuit)) if (circuit->interface == ifp) - return circuit; - + { + assert (ifp->info == circuit); + return circuit; + } + return NULL; } @@ -173,83 +180,77 @@ circuit_scan_by_ifp (struct interface *ifp) struct listnode *node; struct isis_circuit *circuit; - if (!isis->area_list) - return NULL; + if (ifp->info) + return (struct isis_circuit *)ifp->info; - for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) + if (isis->area_list) { - circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (circuit) - return circuit; + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) + { + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (circuit) + return circuit; + } } - return circuit_lookup_by_ifp (ifp, isis->init_circ_list); } -void -isis_circuit_del (struct isis_circuit *circuit) +static struct isis_circuit * +isis_circuit_lookup (struct vty *vty) { + struct interface *ifp; + struct isis_circuit *circuit; - if (!circuit) - return; - - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + ifp = (struct interface *) vty->index; + if (!ifp) { - /* destroy adjacency databases */ - if (circuit->u.bc.adjdb[0]) - list_delete (circuit->u.bc.adjdb[0]); - if (circuit->u.bc.adjdb[1]) - list_delete (circuit->u.bc.adjdb[1]); - /* destroy neighbour lists */ - if (circuit->u.bc.lan_neighs[0]) - list_delete (circuit->u.bc.lan_neighs[0]); - if (circuit->u.bc.lan_neighs[1]) - list_delete (circuit->u.bc.lan_neighs[1]); - /* destroy addresses */ + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return NULL; } - if (circuit->ip_addrs) - list_delete (circuit->ip_addrs); -#ifdef HAVE_IPV6 - if (circuit->ipv6_link) - list_delete (circuit->ipv6_link); - if (circuit->ipv6_non_link) - list_delete (circuit->ipv6_non_link); -#endif /* HAVE_IPV6 */ - /* and lastly the circuit itself */ - XFREE (MTYPE_ISIS_CIRCUIT, circuit); + circuit = circuit_scan_by_ifp (ifp); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return NULL; + } - return; + return circuit; } void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *connected) { + struct listnode *node; struct prefix_ipv4 *ipv4; u_char buf[BUFSIZ]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6; #endif /* HAVE_IPV6 */ - if (!circuit->ip_addrs) - circuit->ip_addrs = list_new (); -#ifdef HAVE_IPV6 - if (!circuit->ipv6_link) - circuit->ipv6_link = list_new (); - if (!circuit->ipv6_non_link) - circuit->ipv6_non_link = list_new (); -#endif /* HAVE_IPV6 */ - memset (&buf, 0, BUFSIZ); if (connected->address->family == AF_INET) { + u_int32_t addr = connected->address->u.prefix4.s_addr; + addr = ntohl (addr); + if (IPV4_NET0(addr) || + IPV4_NET127(addr) || + IN_CLASSD(addr) || + IPV4_LINKLOCAL(addr)) + return; + + for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4)) + if (prefix_same ((struct prefix *) ipv4, connected->address)) + return; + ipv4 = prefix_ipv4_new (); ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; listnode_add (circuit->ip_addrs, ipv4); if (circuit->area) - lsp_regenerate_schedule (circuit->area); + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #ifdef EXTREME_DEBUG prefix2str (connected->address, buf, BUFSIZ); @@ -260,6 +261,16 @@ isis_circuit_add_addr (struct isis_circuit *circuit, #ifdef HAVE_IPV6 if (connected->address->family == AF_INET6) { + if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6)) + return; + + for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6)) + if (prefix_same ((struct prefix *) ipv6, connected->address)) + return; + for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6)) + if (prefix_same ((struct prefix *) ipv6, connected->address)) + return; + ipv6 = prefix_ipv6_new (); ipv6->prefixlen = connected->address->prefixlen; ipv6->prefix = connected->address->u.prefix6; @@ -269,7 +280,7 @@ isis_circuit_add_addr (struct isis_circuit *circuit, else listnode_add (circuit->ipv6_non_link, ipv6); if (circuit->area) - lsp_regenerate_schedule (circuit->area); + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #ifdef EXTREME_DEBUG prefix2str (connected->address, buf, BUFSIZ); @@ -301,20 +312,20 @@ isis_circuit_del_addr (struct isis_circuit *circuit, ipv4->prefix = connected->address->u.prefix4; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip)) - if (prefix_same ((struct prefix *) ip, (struct prefix *) &ipv4)) + if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4)) break; if (ip) { listnode_delete (circuit->ip_addrs, ip); - if (circuit->area) - lsp_regenerate_schedule (circuit->area); + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); } else { prefix2str (connected->address, (char *)buf, BUFSIZ); - zlog_warn("Nonexitant ip address %s removal attempt from circuit \ - %d", buf, circuit->circuit_id); + zlog_warn ("Nonexitant ip address %s removal attempt from \ + circuit %d", buf, circuit->circuit_id); } } #ifdef HAVE_IPV6 @@ -354,72 +365,105 @@ isis_circuit_del_addr (struct isis_circuit *circuit, if (!found) { prefix2str (connected->address, (char *)buf, BUFSIZ); - zlog_warn("Nonexitant ip address %s removal attempt from \ - circuit %d", buf, circuit->circuit_id); + zlog_warn ("Nonexitant ip address %s removal attempt from \ + circuit %d", buf, circuit->circuit_id); } - else - if (circuit->area) - lsp_regenerate_schedule (circuit->area); + else if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); } #endif /* HAVE_IPV6 */ return; } +static u_char +isis_circuit_id_gen (struct interface *ifp) +{ + u_char id = 0; + char ifname[16]; + unsigned int i; + int start = -1, end = -1; + + /* + * Get a stable circuit id from ifname. This makes + * the ifindex from flapping when netdevs are created + * and deleted on the fly. Note that this circuit id + * is used in pseudo lsps so it is better to be stable. + * The following code works on any reasonanle ifname + * like: eth1 or trk-1.1 etc. + */ + for (i = 0; i < strlen (ifp->name); i++) + { + if (isdigit(ifp->name[i])) + { + if (start < 0) + { + start = i; + end = i + 1; + } + else + { + end = i + 1; + } + } + else if (start >= 0) + break; + } + + if ((start >= 0) && (end >= start) && (end - start) < 16) + { + memset (ifname, 0, 16); + strncpy (ifname, &ifp->name[start], end - start); + id = (u_char)atoi(ifname); + } + + /* Try to be unique. */ + if (!id) + id = (u_char)((ifp->ifindex & 0xff) | 0x80); + + return id; +} + void isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp) { struct listnode *node, *nnode; struct connected *conn; - circuit->interface = ifp; - ifp->info = circuit; - - circuit->circuit_id = ifp->ifindex % 255; /* FIXME: Why not ? */ + circuit->circuit_id = isis_circuit_id_gen (ifp); + isis_circuit_if_bind (circuit, ifp); /* isis_circuit_update_addrs (circuit, ifp); */ if (if_is_broadcast (ifp)) { - circuit->circ_type = CIRCUIT_T_BROADCAST; - /* - * Get the Hardware Address - */ -#ifdef HAVE_STRUCT_SOCKADDR_DL -#ifndef SUNOS_5 - if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) - zlog_warn ("unsupported link layer"); - else - memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), - ETH_ALEN); -#endif -#else - if (circuit->interface->hw_addr_len != ETH_ALEN) - { - zlog_warn ("unsupported link layer"); - } + if (circuit->circ_type_config == CIRCUIT_T_P2P) + circuit->circ_type = CIRCUIT_T_P2P; else - { - memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN); - } -#ifdef EXTREME_DEGUG - zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s", - circuit->interface->ifindex, ISO_MTU (circuit), - snpa_print (circuit->u.bc.snpa)); - -#endif /* EXTREME_DEBUG */ -#endif /* HAVE_STRUCT_SOCKADDR_DL */ + circuit->circ_type = CIRCUIT_T_BROADCAST; } else if (if_is_pointopoint (ifp)) { circuit->circ_type = CIRCUIT_T_P2P; } + else if (if_is_loopback (ifp)) + { + circuit->circ_type = CIRCUIT_T_LOOPBACK; + circuit->is_passive = 1; + } else { /* It's normal in case of loopback etc. */ if (isis->debugs & DEBUG_EVENTS) - zlog_debug ("isis_circuit_if_add: unsupported media"); + zlog_debug ("isis_circuit_if_add: unsupported media"); + circuit->circ_type = CIRCUIT_T_UNKNOWN; } + circuit->ip_addrs = list_new (); +#ifdef HAVE_IPV6 + circuit->ipv6_link = list_new (); + circuit->ipv6_non_link = list_new (); +#endif /* HAVE_IPV6 */ + for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) isis_circuit_add_addr (circuit, conn); @@ -427,88 +471,158 @@ isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp) } void -isis_circuit_update_params (struct isis_circuit *circuit, - struct interface *ifp) +isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp) { - assert (circuit); + struct listnode *node, *nnode; + struct connected *conn; - if (circuit->circuit_id != ifp->ifindex) - { - zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id, - ifp->ifindex); - circuit->circuit_id = ifp->ifindex % 255; - } + assert (circuit->interface == ifp); - /* FIXME: Why is this needed? shouldn't we compare to the area's mtu */ - /* Ofer, this was here in case someone changes the mtu (e.g. with ifconfig) - The areas MTU is the minimum of mtu's of circuits in the area - now we can't catch the change - if (circuit->mtu != ifp->mtu) { - zlog_warn ("changing circuit mtu %d->%d", circuit->mtu, - ifp->mtu); - circuit->mtu = ifp->mtu; - } - */ - /* - * Get the Hardware Address - */ -#ifdef HAVE_STRUCT_SOCKADDR_DL -#ifndef SUNOS_5 - if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) - zlog_warn ("unsupported link layer"); - else - memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), ETH_ALEN); -#endif -#else - if (circuit->interface->hw_addr_len != ETH_ALEN) - { - zlog_warn ("unsupported link layer"); - } - else - { - if (memcmp (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN)) - { - zlog_warn ("changing circuit snpa %s->%s", - snpa_print (circuit->u.bc.snpa), - snpa_print (circuit->interface->hw_addr)); - } - } -#endif + /* destroy addresses */ + for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) + isis_circuit_del_addr (circuit, conn); - if (if_is_broadcast (ifp)) + if (circuit->ip_addrs) { - circuit->circ_type = CIRCUIT_T_BROADCAST; + assert (listcount(circuit->ip_addrs) == 0); + list_delete (circuit->ip_addrs); + circuit->ip_addrs = NULL; } - else if (if_is_pointopoint (ifp)) + +#ifdef HAVE_IPV6 + if (circuit->ipv6_link) { - circuit->circ_type = CIRCUIT_T_P2P; + assert (listcount(circuit->ipv6_link) == 0); + list_delete (circuit->ipv6_link); + circuit->ipv6_link = NULL; } - else + + if (circuit->ipv6_non_link) { - zlog_warn ("isis_circuit_update_params: unsupported media"); + assert (listcount(circuit->ipv6_non_link) == 0); + list_delete (circuit->ipv6_non_link); + circuit->ipv6_non_link = NULL; } +#endif /* HAVE_IPV6 */ + + circuit->circ_type = CIRCUIT_T_UNKNOWN; + circuit->circuit_id = 0; return; } void -isis_circuit_if_del (struct isis_circuit *circuit) +isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp) +{ + assert (circuit != NULL); + assert (ifp != NULL); + if (circuit->interface) + assert (circuit->interface == ifp); + else + circuit->interface = ifp; + if (ifp->info) + assert (ifp->info == circuit); + else + ifp->info = circuit; +} + +void +isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp) { - circuit->interface->info = NULL; + assert (circuit != NULL); + assert (ifp != NULL); + assert (circuit->interface == ifp); + assert (ifp->info == circuit); circuit->interface = NULL; + ifp->info = NULL; +} - return; +static void +isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set) +{ + struct isis_area *area; + struct isis_lsp *lsp; + dnode_t *dnode, *dnode_next; + int level; + + assert (circuit); + area = circuit->area; + assert (area); + for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) + { + if (level & circuit->is_type) + { + if (area->lspdb[level - 1] && + dict_count (area->lspdb[level - 1]) > 0) + { + for (dnode = dict_first (area->lspdb[level - 1]); + dnode != NULL; dnode = dnode_next) + { + dnode_next = dict_next (area->lspdb[level - 1], dnode); + lsp = dnode_get (dnode); + if (is_set) + { + ISIS_SET_FLAG (lsp->SRMflags, circuit); + } + else + { + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + } + } + } + } + } } -void +int isis_circuit_up (struct isis_circuit *circuit) { + int retv; + + /* Set the flags for all the lsps of the circuit. */ + isis_circuit_update_all_srmflags (circuit, 1); + + if (circuit->state == C_STATE_UP) + return ISIS_OK; + + if (circuit->is_passive) + return ISIS_OK; if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + /* + * Get the Hardware Address + */ +#ifdef HAVE_STRUCT_SOCKADDR_DL +#ifndef SUNOS_5 + if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) + zlog_warn ("unsupported link layer"); + else + memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), + ETH_ALEN); +#endif +#else + if (circuit->interface->hw_addr_len != ETH_ALEN) + { + zlog_warn ("unsupported link layer"); + } + else + { + memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN); + } +#ifdef EXTREME_DEGUG + zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s", + circuit->interface->ifindex, ISO_MTU (circuit), + snpa_print (circuit->u.bc.snpa)); +#endif /* EXTREME_DEBUG */ +#endif /* HAVE_STRUCT_SOCKADDR_DL */ + + circuit->u.bc.adjdb[0] = list_new (); + circuit->u.bc.adjdb[1] = list_new (); + if (circuit->area->min_bcast_mtu == 0 || - ISO_MTU (circuit) < circuit->area->min_bcast_mtu) - circuit->area->min_bcast_mtu = ISO_MTU (circuit); + ISO_MTU (circuit) < circuit->area->min_bcast_mtu) + circuit->area->min_bcast_mtu = ISO_MTU (circuit); /* * ISO 10589 - 8.4.1 Enabling of broadcast circuits */ @@ -519,91 +633,183 @@ isis_circuit_up (struct isis_circuit *circuit) /* 8.4.1 a) commence sending of IIH PDUs */ - if (circuit->circuit_is_type & IS_LEVEL_1) - { - thread_add_event (master, send_lan_l1_hello, circuit, 0); - circuit->u.bc.lan_neighs[0] = list_new (); - } + if (circuit->is_type & IS_LEVEL_1) + { + thread_add_event (master, send_lan_l1_hello, circuit, 0); + circuit->u.bc.lan_neighs[0] = list_new (); + } - if (circuit->circuit_is_type & IS_LEVEL_2) - { - thread_add_event (master, send_lan_l2_hello, circuit, 0); - circuit->u.bc.lan_neighs[1] = list_new (); - } + if (circuit->is_type & IS_LEVEL_2) + { + thread_add_event (master, send_lan_l2_hello, circuit, 0); + circuit->u.bc.lan_neighs[1] = list_new (); + } /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */ /* 8.4.1 c) FIXME: listen for ESH PDUs */ /* 8.4.1 d) */ /* dr election will commence in... */ - if (circuit->circuit_is_type & IS_LEVEL_1) - THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, - circuit, 2 * circuit->hello_interval[0]); - if (circuit->circuit_is_type & IS_LEVEL_2) - THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, - circuit, 2 * circuit->hello_interval[1]); + if (circuit->is_type & IS_LEVEL_1) + THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, + circuit, 2 * circuit->hello_interval[0]); + if (circuit->is_type & IS_LEVEL_2) + THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, + circuit, 2 * circuit->hello_interval[1]); } else { /* initializing the hello send threads * for a ptp IF */ + circuit->u.p2p.neighbor = NULL; thread_add_event (master, send_p2p_hello, circuit, 0); - } /* initializing PSNP timers */ - if (circuit->circuit_is_type & IS_LEVEL_1) - { - THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, - isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); - } + if (circuit->is_type & IS_LEVEL_1) + THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, + isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); + + if (circuit->is_type & IS_LEVEL_2) + THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, + isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); - if (circuit->circuit_is_type & IS_LEVEL_2) + /* unified init for circuits; ignore warnings below this level */ + retv = isis_sock_init (circuit); + if (retv != ISIS_OK) { - THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, - isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); + isis_circuit_down (circuit); + return retv; } - /* initialize the circuit streams */ + /* initialize the circuit streams after opening connection */ if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); - /* unified init for circuits */ - isis_sock_init (circuit); - #ifdef GNU_LINUX THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, - circuit->fd); + circuit->fd); #else THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit, - circuit->fd); + circuit->fd); #endif - return; + + circuit->lsp_queue = list_new (); + circuit->lsp_queue_last_cleared = time (NULL); + + return ISIS_OK; } void isis_circuit_down (struct isis_circuit *circuit) { - /* Cancel all active threads -- FIXME: wrong place */ - /* HT: Read thread if GNU_LINUX, TIMER thread otherwise. */ - THREAD_OFF (circuit->t_read); + if (circuit->state != C_STATE_UP) + return; + + /* Clear the flags for all the lsps of the circuit. */ + isis_circuit_update_all_srmflags (circuit, 0); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + /* destroy neighbour lists */ + if (circuit->u.bc.lan_neighs[0]) + { + list_delete (circuit->u.bc.lan_neighs[0]); + circuit->u.bc.lan_neighs[0] = NULL; + } + if (circuit->u.bc.lan_neighs[1]) + { + list_delete (circuit->u.bc.lan_neighs[1]); + circuit->u.bc.lan_neighs[1] = NULL; + } + /* destroy adjacency databases */ + if (circuit->u.bc.adjdb[0]) + { + circuit->u.bc.adjdb[0]->del = isis_delete_adj; + list_delete (circuit->u.bc.adjdb[0]); + circuit->u.bc.adjdb[0] = NULL; + } + if (circuit->u.bc.adjdb[1]) + { + circuit->u.bc.adjdb[1]->del = isis_delete_adj; + list_delete (circuit->u.bc.adjdb[1]); + circuit->u.bc.adjdb[1] = NULL; + } + if (circuit->u.bc.is_dr[0]) + { + isis_dr_resign (circuit, 1); + circuit->u.bc.is_dr[0] = 0; + } + memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); + if (circuit->u.bc.is_dr[1]) + { + isis_dr_resign (circuit, 2); + circuit->u.bc.is_dr[1] = 0; + } + memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); + memset (circuit->u.bc.snpa, 0, ETH_ALEN); + THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]); THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); + THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]); + THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]); } else if (circuit->circ_type == CIRCUIT_T_P2P) { + isis_delete_adj (circuit->u.p2p.neighbor); + circuit->u.p2p.neighbor = NULL; THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello); } + + /* Cancel all active threads */ + THREAD_TIMER_OFF (circuit->t_send_csnp[0]); + THREAD_TIMER_OFF (circuit->t_send_csnp[1]); + THREAD_TIMER_OFF (circuit->t_send_psnp[0]); + THREAD_TIMER_OFF (circuit->t_send_psnp[1]); + THREAD_OFF (circuit->t_read); + + if (circuit->lsp_queue) + { + circuit->lsp_queue->del = NULL; + list_delete (circuit->lsp_queue); + circuit->lsp_queue = NULL; + } + + /* send one gratuitous hello to spead up convergence */ + if (circuit->is_type & IS_LEVEL_1) + send_hello (circuit, IS_LEVEL_1); + if (circuit->is_type & IS_LEVEL_2) + send_hello (circuit, IS_LEVEL_2); + + circuit->upadjcount[0] = 0; + circuit->upadjcount[1] = 0; + /* close the socket */ - close (circuit->fd); + if (circuit->fd) + { + close (circuit->fd); + circuit->fd = 0; + } + + if (circuit->rcv_stream != NULL) + { + stream_free (circuit->rcv_stream); + circuit->rcv_stream = NULL; + } + + if (circuit->snd_stream != NULL) + { + stream_free (circuit->snd_stream); + circuit->snd_stream = NULL; + } + + thread_cancel_event (master, circuit); return; } @@ -628,201 +834,346 @@ circuit_update_nlpids (struct isis_circuit *circuit) return; } +void +isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, + char detail) +{ + if (detail == ISIS_UI_LEVEL_BRIEF) + { + vty_out (vty, " %-12s", circuit->interface->name); + vty_out (vty, "0x%-7x", circuit->circuit_id); + vty_out (vty, "%-9s", circuit_state2string (circuit->state)); + vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type)); + vty_out (vty, "%-9s", circuit_t2string (circuit->is_type)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) + { + vty_out (vty, " Interface: %s", circuit->interface->name); + vty_out (vty, ", State: %s", circuit_state2string (circuit->state)); + if (circuit->is_passive) + vty_out (vty, ", Passive"); + else + vty_out (vty, ", Active"); + vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Type: %s", circuit_type2string (circuit->circ_type)); + vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa)); + vty_out (vty, "%s", VTY_NEWLINE); + if (circuit->is_type & IS_LEVEL_1) + { + vty_out (vty, " Level-1 Information:%s", VTY_NEWLINE); + if (circuit->area->newmetric) + vty_out (vty, " Metric: %d", circuit->te_metric[0]); + else + vty_out (vty, " Metric: %d", + circuit->metrics[0].metric_default); + if (!circuit->is_passive) + { + vty_out (vty, ", Active neighbors: %u%s", + circuit->upadjcount[0], VTY_NEWLINE); + vty_out (vty, " Hello interval: %u, " + "Holddown count: %u %s%s", + circuit->hello_interval[0], + circuit->hello_multiplier[0], + (circuit->pad_hellos ? "(pad)" : "(no-pad)"), + VTY_NEWLINE); + vty_out (vty, " CNSP interval: %u, " + "PSNP interval: %u%s", + circuit->csnp_interval[0], + circuit->psnp_interval[0], VTY_NEWLINE); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + vty_out (vty, " LAN Priority: %u, %s%s", + circuit->priority[0], + (circuit->u.bc.is_dr[0] ? \ + "is DIS" : "is not DIS"), VTY_NEWLINE); + } + else + { + vty_out (vty, "%s", VTY_NEWLINE); + } + } + if (circuit->is_type & IS_LEVEL_2) + { + vty_out (vty, " Level-2 Information:%s", VTY_NEWLINE); + if (circuit->area->newmetric) + vty_out (vty, " Metric: %d", circuit->te_metric[1]); + else + vty_out (vty, " Metric: %d", + circuit->metrics[1].metric_default); + if (!circuit->is_passive) + { + vty_out (vty, ", Active neighbors: %u%s", + circuit->upadjcount[1], VTY_NEWLINE); + vty_out (vty, " Hello interval: %u, " + "Holddown count: %u %s%s", + circuit->hello_interval[1], + circuit->hello_multiplier[1], + (circuit->pad_hellos ? "(pad)" : "(no-pad)"), + VTY_NEWLINE); + vty_out (vty, " CNSP interval: %u, " + "PSNP interval: %u%s", + circuit->csnp_interval[1], + circuit->psnp_interval[1], VTY_NEWLINE); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + vty_out (vty, " LAN Priority: %u, %s%s", + circuit->priority[1], + (circuit->u.bc.is_dr[1] ? \ + "is DIS" : "is not DIS"), VTY_NEWLINE); + } + else + { + vty_out (vty, "%s", VTY_NEWLINE); + } + } + if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0) + { + struct listnode *node; + struct prefix *ip_addr; + u_char buf[BUFSIZ]; + vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr)) + { + prefix2str (ip_addr, (char*)buf, BUFSIZ), + vty_out (vty, " %s%s", buf, VTY_NEWLINE); + } + } + vty_out (vty, "%s", VTY_NEWLINE); + } + return; +} + int isis_interface_config_write (struct vty *vty) { - int write = 0; struct listnode *node, *node2; struct interface *ifp; struct isis_area *area; - struct isis_circuit *c; + struct isis_circuit *circuit; int i; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) - { - /* IF name */ - vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); - write++; - /* IF desc */ - if (ifp->desc) - { - vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); - write++; - } - /* ISIS Circuit */ - for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area)) { - c = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (c) - { - if (c->ip_router) - { - vty_out (vty, " ip router isis %s%s", area->area_tag, - VTY_NEWLINE); - write++; - } + /* IF name */ + vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); + write++; + /* IF desc */ + if (ifp->desc) + { + vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); + write++; + } + /* ISIS Circuit */ + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area)) + { + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (circuit == NULL) + continue; + if (circuit->ip_router) + { + vty_out (vty, " ip router isis %s%s", area->area_tag, + VTY_NEWLINE); + write++; + } + if (circuit->is_passive) + { + vty_out (vty, " isis passive%s", VTY_NEWLINE); + write++; + } + if (circuit->circ_type_config == CIRCUIT_T_P2P) + { + vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE); + write++; + } #ifdef HAVE_IPV6 - if (c->ipv6_router) - { - vty_out (vty, " ipv6 router isis %s%s", area->area_tag, - VTY_NEWLINE); - write++; - } + if (circuit->ipv6_router) + { + vty_out (vty, " ipv6 router isis %s%s", area->area_tag, + VTY_NEWLINE); + write++; + } #endif /* HAVE_IPV6 */ - /* ISIS - circuit type */ - if (c->circuit_is_type == IS_LEVEL_1) - { - vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE); - write++; - } - else - { - if (c->circuit_is_type == IS_LEVEL_2) - { - vty_out (vty, " isis circuit-type level-2-only%s", - VTY_NEWLINE); - write++; - } - } - - /* ISIS - CSNP interval - FIXME: compare to cisco */ - if (c->csnp_interval[0] == c->csnp_interval[1]) - { - if (c->csnp_interval[0] != CSNP_INTERVAL) - { - vty_out (vty, " isis csnp-interval %d%s", - c->csnp_interval[0], VTY_NEWLINE); - write++; - } - } - else - { - for (i = 0; i < 2; i++) - { - if (c->csnp_interval[1] != CSNP_INTERVAL) - { - vty_out (vty, " isis csnp-interval %d level-%d%s", - c->csnp_interval[1], i + 1, VTY_NEWLINE); - write++; - } - } - } - - /* ISIS - Hello padding - Defaults to true so only display if false */ - if (c->circ_type == CIRCUIT_T_BROADCAST && !c->u.bc.pad_hellos) - { - vty_out (vty, " no isis hello padding%s", VTY_NEWLINE); - write++; - } - - /* ISIS - Hello interval - FIXME: compare to cisco */ - if (c->hello_interval[0] == c->hello_interval[1]) - { - if (c->hello_interval[0] != HELLO_INTERVAL) - { - vty_out (vty, " isis hello-interval %d%s", - c->hello_interval[0], VTY_NEWLINE); - write++; - } - } - else - { - for (i = 0; i < 2; i++) - { - if (c->hello_interval[i] != HELLO_INTERVAL) - { - if (c->hello_interval[i] == HELLO_MINIMAL) - { - vty_out (vty, - " isis hello-interval minimal level-%d%s", - i + 1, VTY_NEWLINE); - } - else - { - vty_out (vty, " isis hello-interval %d level-%d%s", - c->hello_interval[i], i + 1, VTY_NEWLINE); - } - write++; - } - } - } - - /* ISIS - Hello Multiplier */ - if (c->hello_multiplier[0] == c->hello_multiplier[1]) - { - if (c->hello_multiplier[0] != HELLO_MULTIPLIER) - { - vty_out (vty, " isis hello-multiplier %d%s", - c->hello_multiplier[0], VTY_NEWLINE); - write++; - } - } - else - { - for (i = 0; i < 2; i++) - { - if (c->hello_multiplier[i] != HELLO_MULTIPLIER) - { - vty_out (vty, " isis hello-multiplier %d level-%d%s", - c->hello_multiplier[i], i + 1, VTY_NEWLINE); - write++; - } - } - } - /* ISIS - Priority */ - if (c->circ_type == CIRCUIT_T_BROADCAST) - { - if (c->u.bc.priority[0] == c->u.bc.priority[1]) - { - if (c->u.bc.priority[0] != DEFAULT_PRIORITY) - { - vty_out (vty, " isis priority %d%s", - c->u.bc.priority[0], VTY_NEWLINE); - write++; - } - } - else - { - for (i = 0; i < 2; i++) - { - if (c->u.bc.priority[i] != DEFAULT_PRIORITY) - { - vty_out (vty, " isis priority %d level-%d%s", - c->u.bc.priority[i], i + 1, VTY_NEWLINE); - write++; - } - } - } - } - /* ISIS - Metric */ - if (c->te_metric[0] == c->te_metric[1]) - { - if (c->te_metric[0] != DEFAULT_CIRCUIT_METRICS) - { - vty_out (vty, " isis metric %d%s", c->te_metric[0], - VTY_NEWLINE); - write++; - } - } - else - { - for (i = 0; i < 2; i++) - { - if (c->te_metric[i] != DEFAULT_CIRCUIT_METRICS) - { - vty_out (vty, " isis metric %d level-%d%s", - c->te_metric[i], i + 1, VTY_NEWLINE); - write++; - } - } - } - - } + /* ISIS - circuit type */ + if (circuit->is_type == IS_LEVEL_1) + { + vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE); + write++; + } + else + { + if (circuit->is_type == IS_LEVEL_2) + { + vty_out (vty, " isis circuit-type level-2-only%s", + VTY_NEWLINE); + write++; + } + } + + /* ISIS - CSNP interval */ + if (circuit->csnp_interval[0] == circuit->csnp_interval[1]) + { + if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL) + { + vty_out (vty, " isis csnp-interval %d%s", + circuit->csnp_interval[0], VTY_NEWLINE); + write++; + } + } + else + { + for (i = 0; i < 2; i++) + { + if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL) + { + vty_out (vty, " isis csnp-interval %d level-%d%s", + circuit->csnp_interval[i], i + 1, VTY_NEWLINE); + write++; + } + } + } + + /* ISIS - PSNP interval */ + if (circuit->psnp_interval[0] == circuit->psnp_interval[1]) + { + if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL) + { + vty_out (vty, " isis psnp-interval %d%s", + circuit->psnp_interval[0], VTY_NEWLINE); + write++; + } + } + else + { + for (i = 0; i < 2; i++) + { + if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL) + { + vty_out (vty, " isis psnp-interval %d level-%d%s", + circuit->psnp_interval[i], i + 1, VTY_NEWLINE); + write++; + } + } + } + + /* ISIS - Hello padding - Defaults to true so only display if false */ + if (circuit->pad_hellos == 0) + { + vty_out (vty, " no isis hello padding%s", VTY_NEWLINE); + write++; + } + + /* ISIS - Hello interval */ + if (circuit->hello_interval[0] == circuit->hello_interval[1]) + { + if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL) + { + vty_out (vty, " isis hello-interval %d%s", + circuit->hello_interval[0], VTY_NEWLINE); + write++; + } + } + else + { + for (i = 0; i < 2; i++) + { + if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL) + { + vty_out (vty, " isis hello-interval %d level-%d%s", + circuit->hello_interval[i], i + 1, VTY_NEWLINE); + write++; + } + } + } + + /* ISIS - Hello Multiplier */ + if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1]) + { + if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER) + { + vty_out (vty, " isis hello-multiplier %d%s", + circuit->hello_multiplier[0], VTY_NEWLINE); + write++; + } + } + else + { + for (i = 0; i < 2; i++) + { + if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER) + { + vty_out (vty, " isis hello-multiplier %d level-%d%s", + circuit->hello_multiplier[i], i + 1, + VTY_NEWLINE); + write++; + } + } + } + + /* ISIS - Priority */ + if (circuit->priority[0] == circuit->priority[1]) + { + if (circuit->priority[0] != DEFAULT_PRIORITY) + { + vty_out (vty, " isis priority %d%s", + circuit->priority[0], VTY_NEWLINE); + write++; + } + } + else + { + for (i = 0; i < 2; i++) + { + if (circuit->priority[i] != DEFAULT_PRIORITY) + { + vty_out (vty, " isis priority %d level-%d%s", + circuit->priority[i], i + 1, VTY_NEWLINE); + write++; + } + } + } + + /* ISIS - Metric */ + if (circuit->te_metric[0] == circuit->te_metric[1]) + { + if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC) + { + vty_out (vty, " isis metric %d%s", circuit->te_metric[0], + VTY_NEWLINE); + write++; + } + } + else + { + for (i = 0; i < 2; i++) + { + if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC) + { + vty_out (vty, " isis metric %d level-%d%s", + circuit->te_metric[i], i + 1, VTY_NEWLINE); + write++; + } + } + } + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd, + VTY_NEWLINE); + write++; + } + else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) + { + vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd, + VTY_NEWLINE); + write++; + } + } + vty_out (vty, "!%s", VTY_NEWLINE); } - vty_out (vty, "!%s", VTY_NEWLINE); - } return write; } @@ -835,58 +1186,45 @@ DEFUN (ip_router_isis, "IS-IS Routing for IP\n" "Routing process tag\n") { - struct isis_circuit *c; + struct isis_circuit *circuit; struct interface *ifp; struct isis_area *area; ifp = (struct interface *) vty->index; assert (ifp); - area = isis_area_lookup (argv[0]); - - /* Prevent more than one circuit per interface */ - if (area) - c = circuit_lookup_by_ifp (ifp, area->circuit_list); - else - c = NULL; - if (c && (ifp->info != NULL)) - { -#ifdef HAVE_IPV6 - if (c->ipv6_router == 0) - { -#endif /* HAVE_IPV6 */ - /* FIXME: Find the way to warn only vty users. */ - /* vty_out (vty, "ISIS circuit is already defined%s", VTY_NEWLINE); */ - return CMD_WARNING; -#ifdef HAVE_IPV6 - } -#endif /* HAVE_IPV6 */ - } - - /* this is here for ciscopability */ - if (!area) + /* Prevent more than one area per circuit */ + circuit = circuit_scan_by_ifp (ifp); + if (circuit) { - /* FIXME: Find the way to warn only vty users. */ - /* vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); */ - return CMD_WARNING; + if (circuit->ip_router == 1) + { + if (strcmp (circuit->area->area_tag, argv[0])) + { + vty_out (vty, "ISIS circuit is already defined on %s%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + return CMD_SUCCESS; + } } - if (!c) + if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) { - c = circuit_lookup_by_ifp (ifp, isis->init_circ_list); - c = isis_csm_state_change (ISIS_ENABLE, c, area); - c->interface = ifp; /* this is automatic */ - ifp->info = c; /* hardly related to the FSM */ + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } + area = vty->index; - if (!c) - return CMD_WARNING; + circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); + isis_circuit_if_bind (circuit, ifp); - c->ip_router = 1; + circuit->ip_router = 1; area->ip_circuits++; - circuit_update_nlpids (c); + circuit_update_nlpids (circuit); vty->node = INTERFACE_NODE; + vty->index = ifp; return CMD_SUCCESS; } @@ -900,28 +1238,33 @@ DEFUN (no_ip_router_isis, "IS-IS Routing for IP\n" "Routing process tag\n") { - struct isis_circuit *circuit = NULL; struct interface *ifp; struct isis_area *area; - struct listnode *node; + struct isis_circuit *circuit; ifp = (struct interface *) vty->index; - assert (ifp); + if (!ifp) + { + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } area = isis_area_lookup (argv[0]); if (!area) { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Can't find ISIS instance %s%s", + argv[0], VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - if (circuit->interface == ifp) - break; + + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (!circuit) { - vty_out (vty, "Can't find ISIS interface %s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } + circuit->ip_router = 0; area->ip_circuits--; #ifdef HAVE_IPV6 @@ -932,107 +1275,288 @@ DEFUN (no_ip_router_isis, return CMD_SUCCESS; } -DEFUN (isis_circuit_type, - isis_circuit_type_cmd, - "isis circuit-type (level-1|level-1-2|level-2-only)", - "IS-IS commands\n" - "Configure circuit type for interface\n" - "Level-1 only adjacencies are formed\n" - "Level-1-2 adjacencies are formed\n" - "Level-2 only adjacencies are formed\n") +#ifdef HAVE_IPV6 +DEFUN (ipv6_router_isis, + ipv6_router_isis_cmd, + "ipv6 router isis WORD", + "IPv6 interface subcommands\n" + "IPv6 Router interface commands\n" + "IS-IS Routing for IPv6\n" + "Routing process tag\n") { struct isis_circuit *circuit; struct interface *ifp; - int circuit_t; - int is_type; + struct isis_area *area; - ifp = vty->index; - circuit = ifp->info; - /* UGLY - will remove l8r */ - if (circuit == NULL) + ifp = (struct interface *) vty->index; + assert (ifp); + + /* Prevent more than one area per circuit */ + circuit = circuit_scan_by_ifp (ifp); + if (circuit) { - return CMD_WARNING; + if (circuit->ipv6_router == 1) + { + if (strcmp (circuit->area->area_tag, argv[0])) + { + vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + return CMD_SUCCESS; + } } - /* XXX what to do when ip_router_isis is not executed */ - if (circuit->area == NULL) - return CMD_WARNING; + if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + area = vty->index; - assert (circuit); + circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); + isis_circuit_if_bind (circuit, ifp); + + circuit->ipv6_router = 1; + area->ipv6_circuits++; + circuit_update_nlpids (circuit); - circuit_t = string2circuit_t (argv[0]); + vty->node = INTERFACE_NODE; + vty->index = ifp; + + return CMD_SUCCESS; +} - if (!circuit_t) +DEFUN (no_ipv6_router_isis, + no_ipv6_router_isis_cmd, + "no ipv6 router isis WORD", + NO_STR + "IPv6 interface subcommands\n" + "IPv6 Router interface commands\n" + "IS-IS Routing for IPv6\n" + "Routing process tag\n") +{ + struct interface *ifp; + struct isis_area *area; + struct listnode *node; + struct isis_circuit *circuit; + + ifp = (struct interface *) vty->index; + if (!ifp) { - vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); - return CMD_SUCCESS; + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + area = isis_area_lookup (argv[0]); + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s%s", + argv[0], VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } - is_type = circuit->area->is_type; - if (is_type == IS_LEVEL_1_AND_2 || is_type == circuit_t) - isis_event_circuit_type_change (circuit, circuit_t); + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + circuit->ipv6_router = 0; + area->ipv6_circuits--; + if (circuit->ip_router == 0) + isis_csm_state_change (ISIS_DISABLE, circuit, area); + + return CMD_SUCCESS; +} +#endif /* HAVE_IPV6 */ + +DEFUN (isis_passive, + isis_passive_cmd, + "isis passive", + "IS-IS commands\n" + "Configure the passive mode for interface\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (circuit->is_passive == 1) + return CMD_SUCCESS; + + if (circuit->state != C_STATE_UP) + { + circuit->is_passive = 1; + } else { - vty_out (vty, "invalid circuit level for area %s.%s", - circuit->area->area_tag, VTY_NEWLINE); + struct isis_area *area = circuit->area; + isis_csm_state_change (ISIS_DISABLE, circuit, area); + circuit->is_passive = 1; + isis_csm_state_change (ISIS_ENABLE, circuit, area); } return CMD_SUCCESS; } -DEFUN (no_isis_circuit_type, - no_isis_circuit_type_cmd, - "no isis circuit-type (level-1|level-1-2|level-2-only)", +DEFUN (no_isis_passive, + no_isis_passive_cmd, + "no isis passive", NO_STR "IS-IS commands\n" + "Configure the passive mode for interface\n") +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *) vty->index; + if (!ifp) + { + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + /* FIXME: what is wrong with circuit = ifp->info ? */ + circuit = circuit_scan_by_ifp (ifp); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + if (if_is_loopback(ifp)) + { + vty_out (vty, "Can't set no passive for loopback interface%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + if (circuit->is_passive == 0) + return CMD_SUCCESS; + + if (circuit->state != C_STATE_UP) + { + circuit->is_passive = 0; + } + else + { + struct isis_area *area = circuit->area; + isis_csm_state_change (ISIS_DISABLE, circuit, area); + circuit->is_passive = 0; + isis_csm_state_change (ISIS_ENABLE, circuit, area); + } + + return CMD_SUCCESS; +} + +DEFUN (isis_circuit_type, + isis_circuit_type_cmd, + "isis circuit-type (level-1|level-1-2|level-2-only)", + "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { - struct isis_circuit *circuit; - struct interface *ifp; + int circuit_type; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + circuit_type = string2circuit_t (argv[0]); + if (!circuit_type) { - return CMD_WARNING; + vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); + if (circuit->state == C_STATE_UP && + circuit->area->is_type != IS_LEVEL_1_AND_2 && + circuit->area->is_type != circuit_type) + { + vty_out (vty, "Invalid circuit level for area %s.%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + isis_event_circuit_type_change (circuit, circuit_type); + + return CMD_SUCCESS; +} + +DEFUN (no_isis_circuit_type, + no_isis_circuit_type_cmd, + "no isis circuit-type (level-1|level-1-2|level-2-only)", + NO_STR + "IS-IS commands\n" + "Configure circuit type for interface\n" + "Level-1 only adjacencies are formed\n" + "Level-1-2 adjacencies are formed\n" + "Level-2 only adjacencies are formed\n") +{ + int circuit_type; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; /* - * Set the circuits level to its default value which is that of the area + * Set the circuits level to its default value */ - isis_event_circuit_type_change (circuit, circuit->area->is_type); + if (circuit->state == C_STATE_UP) + circuit_type = circuit->area->is_type; + else + circuit_type = IS_LEVEL_1_AND_2; + isis_event_circuit_type_change (circuit, circuit_type); return CMD_SUCCESS; } -DEFUN (isis_passwd, - isis_passwd_cmd, - "isis password WORD", +DEFUN (isis_passwd_md5, + isis_passwd_md5_cmd, + "isis password md5 WORD", "IS-IS commands\n" - "Configure the authentication password for interface\n" - "Password\n") + "Configure the authentication password for a circuit\n" + "Authentication type\n" + "Circuit password\n") { - struct isis_circuit *circuit; - struct interface *ifp; int len; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + len = strlen (argv[0]); + if (len > 254) { - return CMD_WARNING; + vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } + circuit->passwd.len = len; + circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; + strncpy ((char *)circuit->passwd.passwd, argv[0], 255); + + return CMD_SUCCESS; +} + +DEFUN (isis_passwd_clear, + isis_passwd_clear_cmd, + "isis password clear WORD", + "IS-IS commands\n" + "Configure the authentication password for a circuit\n" + "Authentication type\n" + "Circuit password\n") +{ + int len; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; @@ -1046,24 +1570,17 @@ DEFUN (no_isis_passwd, "no isis password", NO_STR "IS-IS commands\n" - "Configure the authentication password for interface\n") + "Configure the authentication password for a circuit\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; memset (&circuit->passwd, 0, sizeof (struct isis_passwd)); return CMD_SUCCESS; } - DEFUN (isis_priority, isis_priority_cmd, "isis priority <0-127>", @@ -1071,22 +1588,21 @@ DEFUN (isis_priority, "Set priority for Designated Router election\n" "Priority value\n") { - struct isis_circuit *circuit; - struct interface *ifp; int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { - return CMD_WARNING; + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - prio = atoi (argv[0]); - circuit->u.bc.priority[0] = prio; - circuit->u.bc.priority[1] = prio; + circuit->priority[0] = prio; + circuit->priority[1] = prio; return CMD_SUCCESS; } @@ -1098,19 +1614,12 @@ DEFUN (no_isis_priority, "IS-IS commands\n" "Set priority for Designated Router election\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->u.bc.priority[0] = DEFAULT_PRIORITY; - circuit->u.bc.priority[1] = DEFAULT_PRIORITY; + circuit->priority[0] = DEFAULT_PRIORITY; + circuit->priority[1] = DEFAULT_PRIORITY; return CMD_SUCCESS; } @@ -1131,21 +1640,20 @@ DEFUN (isis_priority_l1, "Priority value\n" "Specify priority for level-1 routing\n") { - struct isis_circuit *circuit; - struct interface *ifp; int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { - return CMD_WARNING; + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - prio = atoi (argv[0]); - circuit->u.bc.priority[0] = prio; + circuit->priority[0] = prio; return CMD_SUCCESS; } @@ -1158,18 +1666,11 @@ DEFUN (no_isis_priority_l1, "Set priority for Designated Router election\n" "Specify priority for level-1 routing\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->u.bc.priority[0] = DEFAULT_PRIORITY; + circuit->priority[0] = DEFAULT_PRIORITY; return CMD_SUCCESS; } @@ -1191,21 +1692,20 @@ DEFUN (isis_priority_l2, "Priority value\n" "Specify priority for level-2 routing\n") { - struct isis_circuit *circuit; - struct interface *ifp; int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { - return CMD_WARNING; + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - prio = atoi (argv[0]); - - circuit->u.bc.priority[1] = prio; + circuit->priority[1] = prio; return CMD_SUCCESS; } @@ -1218,18 +1718,11 @@ DEFUN (no_isis_priority_l2, "Set priority for Designated Router election\n" "Specify priority for level-2 routing\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->u.bc.priority[1] = DEFAULT_PRIORITY; + circuit->priority[1] = DEFAULT_PRIORITY; return CMD_SUCCESS; } @@ -1244,36 +1737,49 @@ ALIAS (no_isis_priority_l2, "Specify priority for level-2 routing\n") /* Metric command */ - DEFUN (isis_metric, +DEFUN (isis_metric, isis_metric_cmd, "isis metric <0-16777215>", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") { - struct isis_circuit *circuit; - struct interface *ifp; int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) { - return CMD_WARNING; + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - met = atoi (argv[0]); + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } circuit->te_metric[0] = met; circuit->te_metric[1] = met; - if (met > 63) - met = 63; - circuit->metrics[0].metric_default = met; circuit->metrics[1].metric_default = met; + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + return CMD_SUCCESS; } @@ -1284,21 +1790,17 @@ DEFUN (no_isis_metric, "IS-IS commands\n" "Set default metric for circuit\n") { - struct isis_circuit *circuit; - struct interface *ifp; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; + circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; + circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; + circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; - circuit->te_metric[0] = DEFAULT_CIRCUIT_METRICS; - circuit->te_metric[1] = DEFAULT_CIRCUIT_METRICS; - circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRICS; - circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRICS; + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); return CMD_SUCCESS; } @@ -1311,34 +1813,175 @@ ALIAS (no_isis_metric, "Set default metric for circuit\n" "Default metric value\n") +DEFUN (isis_metric_l1, + isis_metric_l1_cmd, + "isis metric <0-16777215> level-1", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-1 routing\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->te_metric[0] = met; + circuit->metrics[0].metric_default = met; + + if (circuit->area) + lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric_l1, + no_isis_metric_l1_cmd, + "no isis metric level-1", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Specify metric for level-1 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; + circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; + + if (circuit->area) + lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); + + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric_l1, + no_isis_metric_l1_arg_cmd, + "no isis metric <0-16777215> level-1", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-1 routing\n") + +DEFUN (isis_metric_l2, + isis_metric_l2_cmd, + "isis metric <0-16777215> level-2", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-2 routing\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->te_metric[1] = met; + circuit->metrics[1].metric_default = met; + + if (circuit->area) + lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric_l2, + no_isis_metric_l2_cmd, + "no isis metric level-2", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Specify metric for level-2 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; + circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; + + if (circuit->area) + lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); + + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric_l2, + no_isis_metric_l2_arg_cmd, + "no isis metric <0-16777215> level-2", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-2 routing\n") /* end of metrics */ + DEFUN (isis_hello_interval, isis_hello_interval_cmd, - "isis hello-interval (<1-65535>|minimal)", + "isis hello-interval <1-600>", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 seconds, interval depends on multiplier\n") { - struct isis_circuit *circuit; - struct interface *ifp; int interval; - char c; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { - return CMD_WARNING; + vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - c = *argv[0]; - if (isdigit ((int) c)) - { - interval = atoi (argv[0]); - } - else - interval = HELLO_MINIMAL; /* FIXME: should be calculated */ circuit->hello_interval[0] = (u_int16_t) interval; circuit->hello_interval[1] = (u_int16_t) interval; @@ -1353,27 +1996,19 @@ DEFUN (no_isis_hello_interval, "IS-IS commands\n" "Set Hello interval\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); - + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */ - circuit->hello_interval[1] = HELLO_INTERVAL; + circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; + circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval, no_isis_hello_interval_arg_cmd, - "no isis hello-interval (<1-65535>|minimal)", + "no isis hello-interval <1-600>", NO_STR "IS-IS commands\n" "Set Hello interval\n" @@ -1382,33 +2017,25 @@ ALIAS (no_isis_hello_interval, DEFUN (isis_hello_interval_l1, isis_hello_interval_l1_cmd, - "isis hello-interval (<1-65535>|minimal) level-1", + "isis hello-interval <1-600> level-1", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; long interval; - char c; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { - return CMD_WARNING; + vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - c = *argv[0]; - if (isdigit ((int) c)) - { - interval = atoi (argv[0]); - } - else - interval = HELLO_MINIMAL; circuit->hello_interval[0] = (u_int16_t) interval; @@ -1423,26 +2050,18 @@ DEFUN (no_isis_hello_interval_l1, "Set Hello interval\n" "Specify hello-interval for level-1 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); - + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */ + circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval_l1, no_isis_hello_interval_l1_arg_cmd, - "no isis hello-interval (<1-65535>|minimal) level-1", + "no isis hello-interval <1-600> level-1", NO_STR "IS-IS commands\n" "Set Hello interval\n" @@ -1452,33 +2071,25 @@ ALIAS (no_isis_hello_interval_l1, DEFUN (isis_hello_interval_l2, isis_hello_interval_l2_cmd, - "isis hello-interval (<1-65535>|minimal) level-2", + "isis hello-interval <1-600> level-2", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - long interval; - char c; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - c = *argv[0]; - if (isdigit ((int) c)) + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { - interval = atoi (argv[0]); + vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - else - interval = HELLO_MINIMAL; circuit->hello_interval[1] = (u_int16_t) interval; @@ -1493,26 +2104,18 @@ DEFUN (no_isis_hello_interval_l2, "Set Hello interval\n" "Specify hello-interval for level-2 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); - + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->hello_interval[1] = HELLO_INTERVAL; /* Default is 1 sec. */ + circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval_l2, no_isis_hello_interval_l2_arg_cmd, - "no isis hello-interval (<1-65535>|minimal) level-2", + "no isis hello-interval <1-600> level-2", NO_STR "IS-IS commands\n" "Set Hello interval\n" @@ -1522,24 +2125,23 @@ ALIAS (no_isis_hello_interval_l2, DEFUN (isis_hello_multiplier, isis_hello_multiplier_cmd, - "isis hello-multiplier <3-1000>", + "isis hello-multiplier <2-100>", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") { - struct isis_circuit *circuit; - struct interface *ifp; int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { - return CMD_WARNING; + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - mult = atoi (argv[0]); circuit->hello_multiplier[0] = (u_int16_t) mult; circuit->hello_multiplier[1] = (u_int16_t) mult; @@ -1554,26 +2156,19 @@ DEFUN (no_isis_hello_multiplier, "IS-IS commands\n" "Set multiplier for Hello holding time\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->hello_multiplier[0] = HELLO_MULTIPLIER; - circuit->hello_multiplier[1] = HELLO_MULTIPLIER; + circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; + circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier, no_isis_hello_multiplier_arg_cmd, - "no isis hello-multiplier <3-1000>", + "no isis hello-multiplier <2-100>", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" @@ -1581,25 +2176,24 @@ ALIAS (no_isis_hello_multiplier, DEFUN (isis_hello_multiplier_l1, isis_hello_multiplier_l1_cmd, - "isis hello-multiplier <3-1000> level-1", + "isis hello-multiplier <2-100> level-1", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { - return CMD_WARNING; + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - mult = atoi (argv[0]); circuit->hello_multiplier[0] = (u_int16_t) mult; @@ -1614,25 +2208,18 @@ DEFUN (no_isis_hello_multiplier_l1, "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-1 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->hello_multiplier[0] = HELLO_MULTIPLIER; + circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier_l1, no_isis_hello_multiplier_l1_arg_cmd, - "no isis hello-multiplier <3-1000> level-1", + "no isis hello-multiplier <2-100> level-1", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" @@ -1641,25 +2228,24 @@ ALIAS (no_isis_hello_multiplier_l1, DEFUN (isis_hello_multiplier_l2, isis_hello_multiplier_l2_cmd, - "isis hello-multiplier <3-1000> level-2", + "isis hello-multiplier <2-100> level-2", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { - return CMD_WARNING; + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - mult = atoi (argv[0]); circuit->hello_multiplier[1] = (u_int16_t) mult; @@ -1674,57 +2260,43 @@ DEFUN (no_isis_hello_multiplier_l2, "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-2 IIHs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->hello_multiplier[1] = HELLO_MULTIPLIER; + circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier_l2, no_isis_hello_multiplier_l2_arg_cmd, - "no isis hello-multiplier <3-1000> level-2", + "no isis hello-multiplier <2-100> level-2", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") -DEFUN (isis_hello, - isis_hello_cmd, +DEFUN (isis_hello_padding, + isis_hello_padding_cmd, "isis hello padding", "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") { - struct interface *ifp; - struct isis_circuit *circuit; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->u.bc.pad_hellos = 1; + circuit->pad_hellos = 1; return CMD_SUCCESS; } -DEFUN (no_isis_hello, - no_isis_hello_cmd, +DEFUN (no_isis_hello_padding, + no_isis_hello_padding_cmd, "no isis hello padding", NO_STR "IS-IS commands\n" @@ -1732,42 +2304,34 @@ DEFUN (no_isis_hello, "Pad hello packets\n" "\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->u.bc.pad_hellos = 0; + circuit->pad_hellos = 0; return CMD_SUCCESS; } DEFUN (csnp_interval, csnp_interval_cmd, - "isis csnp-interval <0-65535>", + "isis csnp-interval <1-600>", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") { - struct isis_circuit *circuit; - struct interface *ifp; unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { - return CMD_WARNING; + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - interval = atol (argv[0]); circuit->csnp_interval[0] = (u_int16_t) interval; circuit->csnp_interval[1] = (u_int16_t) interval; @@ -1782,26 +2346,19 @@ DEFUN (no_csnp_interval, "IS-IS commands\n" "Set CSNP interval in seconds\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->csnp_interval[0] = CSNP_INTERVAL; - circuit->csnp_interval[1] = CSNP_INTERVAL; + circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; + circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval, no_csnp_interval_arg_cmd, - "no isis csnp-interval <0-65535>", + "no isis csnp-interval <1-600>", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" @@ -1809,25 +2366,24 @@ ALIAS (no_csnp_interval, DEFUN (csnp_interval_l1, csnp_interval_l1_cmd, - "isis csnp-interval <0-65535> level-1", + "isis csnp-interval <1-600> level-1", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") { - struct isis_circuit *circuit; - struct interface *ifp; unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { - return CMD_WARNING; + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - interval = atol (argv[0]); circuit->csnp_interval[0] = (u_int16_t) interval; @@ -1842,25 +2398,18 @@ DEFUN (no_csnp_interval_l1, "Set CSNP interval in seconds\n" "Specify interval for level-1 CSNPs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->csnp_interval[0] = CSNP_INTERVAL; + circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval_l1, no_csnp_interval_l1_arg_cmd, - "no isis csnp-interval <0-65535> level-1", + "no isis csnp-interval <1-600> level-1", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" @@ -1869,25 +2418,24 @@ ALIAS (no_csnp_interval_l1, DEFUN (csnp_interval_l2, csnp_interval_l2_cmd, - "isis csnp-interval <0-65535> level-2", + "isis csnp-interval <1-600> level-2", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") { - struct isis_circuit *circuit; - struct interface *ifp; unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { - return CMD_WARNING; + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - - interval = atol (argv[0]); circuit->csnp_interval[1] = (u_int16_t) interval; @@ -1902,153 +2450,276 @@ DEFUN (no_csnp_interval_l2, "Set CSNP interval in seconds\n" "Specify interval for level-2 CSNPs\n") { - struct isis_circuit *circuit; - struct interface *ifp; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } - assert (circuit); + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - circuit->csnp_interval[1] = CSNP_INTERVAL; + circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval_l2, no_csnp_interval_l2_arg_cmd, - "no isis csnp-interval <0-65535> level-2", + "no isis csnp-interval <1-600> level-2", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") -#ifdef HAVE_IPV6 -DEFUN (ipv6_router_isis, - ipv6_router_isis_cmd, - "ipv6 router isis WORD", - "IPv6 interface subcommands\n" - "IPv6 Router interface commands\n" - "IS-IS Routing for IPv6\n" - "Routing process tag\n") +DEFUN (psnp_interval, + psnp_interval_cmd, + "isis psnp-interval <1-120>", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n") { - struct isis_circuit *c; - struct interface *ifp; - struct isis_area *area; + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - ifp = (struct interface *) vty->index; - assert (ifp); + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } - area = isis_area_lookup (argv[0]); + circuit->psnp_interval[0] = (u_int16_t) interval; + circuit->psnp_interval[1] = (u_int16_t) interval; - /* Prevent more than one circuit per interface */ - if (area) - c = circuit_lookup_by_ifp (ifp, area->circuit_list); - else - c = NULL; + return CMD_SUCCESS; +} - if (c && (ifp->info != NULL)) - { - if (c->ipv6_router == 1) - { - vty_out (vty, "ISIS circuit is already defined for IPv6%s", - VTY_NEWLINE); - return CMD_WARNING; - } - } +DEFUN (no_psnp_interval, + no_psnp_interval_cmd, + "no isis psnp-interval", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - /* this is here for ciscopability */ - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_WARNING; - } + circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; + circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval, + no_psnp_interval_arg_cmd, + "no isis psnp-interval <1-120>", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n") + +DEFUN (psnp_interval_l1, + psnp_interval_l1_cmd, + "isis psnp-interval <1-120> level-1", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-1 PSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - if (!c) + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { - c = circuit_lookup_by_ifp (ifp, isis->init_circ_list); - c = isis_csm_state_change (ISIS_ENABLE, c, area); - c->interface = ifp; - ifp->info = c; + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - if (!c) - return CMD_WARNING; + circuit->psnp_interval[0] = (u_int16_t) interval; - c->ipv6_router = 1; - area->ipv6_circuits++; - circuit_update_nlpids (c); + return CMD_SUCCESS; +} - vty->node = INTERFACE_NODE; +DEFUN (no_psnp_interval_l1, + no_psnp_interval_l1_cmd, + "no isis psnp-interval level-1", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "Specify interval for level-1 PSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } -DEFUN (no_ipv6_router_isis, - no_ipv6_router_isis_cmd, - "no ipv6 router isis WORD", +ALIAS (no_psnp_interval_l1, + no_psnp_interval_l1_arg_cmd, + "no isis psnp-interval <1-120> level-1", NO_STR - "IPv6 interface subcommands\n" - "IPv6 Router interface commands\n" - "IS-IS Routing for IPv6\n" - "Routing process tag\n") -{ - struct isis_circuit *c; - struct interface *ifp; - struct isis_area *area; + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-1 PSNPs\n") - ifp = (struct interface *) vty->index; - /* UGLY - will remove l8r - if (circuit == NULL) { - return CMD_WARNING; - } */ - assert (ifp); +DEFUN (psnp_interval_l2, + psnp_interval_l2_cmd, + "isis psnp-interval <1-120> level-2", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-2 PSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; - area = isis_area_lookup (argv[0]); - if (!area) + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - c = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (!c) - return CMD_WARNING; + circuit->psnp_interval[1] = (u_int16_t) interval; - c->ipv6_router = 0; - area->ipv6_circuits--; - if (c->ip_router == 0) - isis_csm_state_change (ISIS_DISABLE, c, area); + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval_l2, + no_psnp_interval_l2_cmd, + "no isis psnp-interval level-2", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "Specify interval for level-2 PSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } -#endif /* HAVE_IPV6 */ -static struct cmd_node interface_node = { +ALIAS (no_psnp_interval_l2, + no_psnp_interval_l2_arg_cmd, + "no isis psnp-interval <1-120> level-2", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-2 PSNPs\n") + +struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; +DEFUN (isis_network, + isis_network_cmd, + "isis network point-to-point", + "IS-IS commands\n" + "Set network type\n" + "point-to-point network type\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + /* RFC5309 section 4 */ + if (circuit->circ_type == CIRCUIT_T_P2P) + return CMD_SUCCESS; + + if (circuit->state != C_STATE_UP) + { + circuit->circ_type = CIRCUIT_T_P2P; + circuit->circ_type_config = CIRCUIT_T_P2P; + } + else + { + struct isis_area *area = circuit->area; + if (!if_is_broadcast (circuit->interface)) + { + vty_out (vty, "isis network point-to-point " + "is valid only on broadcast interfaces%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_csm_state_change (ISIS_DISABLE, circuit, area); + circuit->circ_type = CIRCUIT_T_P2P; + circuit->circ_type_config = CIRCUIT_T_P2P; + isis_csm_state_change (ISIS_ENABLE, circuit, area); + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_network, + no_isis_network_cmd, + "no isis network point-to-point", + NO_STR + "IS-IS commands\n" + "Set network type for circuit\n" + "point-to-point network type\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + /* RFC5309 section 4 */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + return CMD_SUCCESS; + + if (circuit->state != C_STATE_UP) + { + circuit->circ_type = CIRCUIT_T_BROADCAST; + circuit->circ_type_config = CIRCUIT_T_BROADCAST; + } + else + { + struct isis_area *area = circuit->area; + if (circuit->interface && + !if_is_broadcast (circuit->interface)) + { + vty_out (vty, "no isis network point-to-point " + "is valid only on broadcast interfaces%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_csm_state_change (ISIS_DISABLE, circuit, area); + circuit->circ_type = CIRCUIT_T_BROADCAST; + circuit->circ_type_config = CIRCUIT_T_BROADCAST; + isis_csm_state_change (ISIS_ENABLE, circuit, area); + } + + return CMD_SUCCESS; +} + int isis_if_new_hook (struct interface *ifp) { -/* FIXME: Discuss if the circuit should be created here - ifp->info = XMALLOC (MTYPE_ISIS_IF_INFO, sizeof (struct isis_if_info)); */ - ifp->info = NULL; return 0; } int isis_if_delete_hook (struct interface *ifp) { -/* FIXME: Discuss if the circuit should be created here - XFREE (MTYPE_ISIS_IF_INFO, ifp->info);*/ - ifp->info = NULL; return 0; } @@ -2071,10 +2742,14 @@ isis_circuit_init () install_element (INTERFACE_NODE, &ip_router_isis_cmd); install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); + install_element (INTERFACE_NODE, &isis_passive_cmd); + install_element (INTERFACE_NODE, &no_isis_passive_cmd); + install_element (INTERFACE_NODE, &isis_circuit_type_cmd); install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); - install_element (INTERFACE_NODE, &isis_passwd_cmd); + install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); + install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_cmd); install_element (INTERFACE_NODE, &isis_priority_cmd); @@ -2090,6 +2765,12 @@ isis_circuit_init () install_element (INTERFACE_NODE, &isis_metric_cmd); install_element (INTERFACE_NODE, &no_isis_metric_cmd); install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); + install_element (INTERFACE_NODE, &isis_metric_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_metric_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); @@ -2111,8 +2792,9 @@ isis_circuit_init () install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_cmd); + install_element (INTERFACE_NODE, &isis_hello_padding_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); + install_element (INTERFACE_NODE, &csnp_interval_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); @@ -2123,6 +2805,19 @@ isis_circuit_init () install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_network_cmd); + install_element (INTERFACE_NODE, &no_isis_network_cmd); + #ifdef HAVE_IPV6 install_element (INTERFACE_NODE, &ipv6_router_isis_cmd); install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index a7e719f60..7ed481dc2 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -52,8 +52,6 @@ struct isis_bcast_info u_char l1_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-1 DR */ u_char l2_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-2 DR */ struct thread *t_refresh_pseudo_lsp[2]; /* refresh pseudo-node LSPs */ - int pad_hellos; /* add padding to Hello PDUs ? */ - u_char priority[2]; /* l1/2 IS Priority */ }; struct isis_p2p_info @@ -78,31 +76,36 @@ struct isis_circuit struct thread *t_send_csnp[2]; struct thread *t_send_psnp[2]; struct list *lsp_queue; /* LSPs to be txed (both levels) */ + time_t lsp_queue_last_cleared;/* timestamp used to enforce transmit interval; + * for scalability, use one timestamp per + * circuit, instead of one per lsp per circuit + */ /* there is no real point in two streams, just for programming kicker */ int (*rx) (struct isis_circuit * circuit, u_char * ssnpa); struct stream *rcv_stream; /* Stream for receiving */ int (*tx) (struct isis_circuit * circuit, int level); struct stream *snd_stream; /* Stream for sending */ int idx; /* idx in S[RM|SN] flags */ -#define CIRCUIT_T_BROADCAST 0 -#define CIRCUIT_T_P2P 1 -#define CIRCUIT_T_STATIC_IN 2 -#define CIRCUIT_T_STATIC_OUT 3 -#define CIRCUIT_T_DA 4 +#define CIRCUIT_T_UNKNOWN 0 +#define CIRCUIT_T_BROADCAST 1 +#define CIRCUIT_T_P2P 2 +#define CIRCUIT_T_LOOPBACK 3 int circ_type; /* type of the physical interface */ + int circ_type_config; /* config type of the physical interface */ union { struct isis_bcast_info bc; struct isis_p2p_info p2p; } u; + u_char priority[2]; /* l1/2 IS configured priority */ + int pad_hellos; /* add padding to Hello PDUs ? */ char ext_domain; /* externalDomain (boolean) */ + int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables */ struct isis_passwd passwd; /* Circuit rx/tx password */ - long lsp_interval; - int manual_l2_only; /* manualL2OnlyMode (boolean) */ - int circuit_is_type; /* circuit is type == level of circuit + int is_type; /* circuit is type == level of circuit * diffrenciated from circuit type (media) */ u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */ u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */ @@ -110,24 +113,17 @@ struct isis_circuit u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */ struct metric metrics[2]; /* l1XxxMetric */ u_int32_t te_metric[2]; - struct password *c_rx_passwds; /* circuitReceivePasswords */ - struct password *c_tc_passwd; /* circuitTransmitPassword */ int ip_router; /* Route IP ? */ + int is_passive; /* Is Passive ? */ struct list *ip_addrs; /* our IP addresses */ #ifdef HAVE_IPV6 int ipv6_router; /* Route IPv6 ? */ struct list *ipv6_link; /* our link local IPv6 addresses */ struct list *ipv6_non_link; /* our non-link local IPv6 addresses */ #endif /* HAVE_IPV6 */ - /* - * RFC 2973 IS-IS Mesh Groups - */ -#define MESH_INACTIVE 0 -#define MESH_BLOCKED 1 -#define MESH_SET 2 - int mesh_enabled; /* meshGroupEnabled */ - u_int16_t mesh_group; /* meshGroup */ u_int16_t upadjcount[2]; +#define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01 + u_char flags; /* * Counters as in 10589--11.2.5.9 */ @@ -141,25 +137,30 @@ struct isis_circuit void isis_circuit_init (void); struct isis_circuit *isis_circuit_new (void); +void isis_circuit_del (struct isis_circuit *circuit); struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp, struct list *list); struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp); -void isis_circuit_del (struct isis_circuit *circuit); void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area); -void isis_circuit_up (struct isis_circuit *circuit); void isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area); - -int isis_circuit_destroy (struct isis_circuit *circuit); void isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp); -void isis_circuit_if_del (struct isis_circuit *circuit); -void circuit_update_nlpids (struct isis_circuit *circuit); -void isis_circuit_update_params (struct isis_circuit *circuit, - struct interface *ifp); +void isis_circuit_if_del (struct isis_circuit *circuit, + struct interface *ifp); +void isis_circuit_if_bind (struct isis_circuit *circuit, + struct interface *ifp); +void isis_circuit_if_unbind (struct isis_circuit *circuit, + struct interface *ifp); void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *conn); void isis_circuit_del_addr (struct isis_circuit *circuit, struct connected *conn); +int isis_circuit_up (struct isis_circuit *circuit); +void isis_circuit_down (struct isis_circuit *); +void circuit_update_nlpids (struct isis_circuit *circuit); +void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, + char detail); + #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_common.h b/isisd/isis_common.h index 263385560..d158961b9 100644 --- a/isisd/isis_common.h +++ b/isisd/isis_common.h @@ -21,6 +21,9 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef ISIS_COMMON_H +#define ISIS_COMMON_H + /* * Area Address */ @@ -35,6 +38,7 @@ struct isis_passwd u_char len; #define ISIS_PASSWD_TYPE_UNUSED 0 #define ISIS_PASSWD_TYPE_CLEARTXT 1 +#define ISIS_PASSWD_TYPE_HMAC_MD5 54 #define ISIS_PASSWD_TYPE_PRIVATE 255 u_char type; /* Authenticate SNPs? */ @@ -64,11 +68,4 @@ struct nlpids u_char nlpids[4]; /* FIXME: enough ? */ }; -/* - * Flags structure for SSN and SRM flags - */ -struct flags -{ - int maxindex; - struct list *free_idcs; -}; +#endif diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h index 1b75ba6b1..bb2c4b406 100644 --- a/isisd/isis_constants.h +++ b/isisd/isis_constants.h @@ -27,8 +27,10 @@ * Architectural constant values from p. 35 of ISO/IEC 10589 */ -#define MAX_LINK_METRIC 63 -#define MAX_PATH_METRIC 1023 +#define MAX_NARROW_LINK_METRIC 63 +#define MAX_NARROW_PATH_METRIC 1023 +#define MAX_WIDE_LINK_METRIC 0x00FFFFFF /* RFC4444 */ +#define MAX_WIDE_PATH_METRIC 0xFE000000 /* RFC3787 */ #define ISO_SAP 0xFE #define INTRADOMAIN_ROUTEING_SELECTOR 0 #define SEQUENCE_MODULUS 4294967296 @@ -38,7 +40,7 @@ * implementation specific jitter values */ -#define IIH_JITTER 25 /* % */ +#define IIH_JITTER 10 /* % */ #define MAX_AGE_JITTER 5 /* % */ #define MAX_LSP_GEN_JITTER 5 /* % */ #define CSNP_JITTER 10 /* % */ @@ -46,36 +48,59 @@ #define RANDOM_SPREAD 100000.0 +#define ISIS_LEVELS 2 +#define ISIS_LEVEL1 1 +#define ISIS_LEVEL2 2 + /* * Default values - * ISO - 10589 - * Section 7.3.21 - Parameters + * ISO - 10589 Section 7.3.21 - Parameters + * RFC 4444 */ #define MAX_AGE 1200 #define ZERO_AGE_LIFETIME 60 -#define MAX_LSP_GEN_INTERVAL 900 -#define MIN_LSP_GEN_INTERVAL 30 +#define MIN_LSP_LIFETIME 350 +#define MAX_LSP_LIFETIME 65535 +#define DEFAULT_LSP_LIFETIME 1200 + +#define MIN_MAX_LSP_GEN_INTERVAL 1 +#define MAX_MAX_LSP_GEN_INTERVAL 65235 +#define DEFAULT_MAX_LSP_GEN_INTERVAL 900 + +#define MIN_MIN_LSP_GEN_INTERVAL 1 +#define MAX_MIN_LSP_GEN_INTERVAL 120 /* RFC 4444 says 65535 */ +#define DEFAULT_MIN_LSP_GEN_INTERVAL 30 + #define MIN_LSP_TRANS_INTERVAL 5 -#define ISIS_MIN_LSP_LIFETIME 380 -#define CSNP_INTERVAL 10 -#define PSNP_INTERVAL 2 -#define ISIS_MAX_PATH_SPLITS 3 -#define ISIS_LEVELS 2 -#define ISIS_LEVEL1 1 -#define ISIS_LEVEL2 2 +#define MIN_CSNP_INTERVAL 1 +#define MAX_CSNP_INTERVAL 600 +#define DEFAULT_CSNP_INTERVAL 10 + +#define MIN_PSNP_INTERVAL 1 +#define MAX_PSNP_INTERVAL 120 +#define DEFAULT_PSNP_INTERVAL 2 + +#define MIN_HELLO_INTERVAL 1 +#define MAX_HELLO_INTERVAL 600 +#define DEFAULT_HELLO_INTERVAL 3 + +#define MIN_HELLO_MULTIPLIER 2 +#define MAX_HELLO_MULTIPLIER 100 +#define DEFAULT_HELLO_MULTIPLIER 10 -#define HELLO_INTERVAL 10 -#define HELLO_MINIMAL HELLO_INTERVAL -#define HELLO_MULTIPLIER 3 +#define MIN_PRIORITY 0 +#define MAX_PRIORITY 127 #define DEFAULT_PRIORITY 64 -/* different vendors implement different values 5-10 on average */ -#define LSP_GEN_INTERVAL_DEFAULT 10 -#define LSP_INTERVAL 33 /* msecs */ -#define DEFAULT_CIRCUIT_METRICS 10 -#define METRICS_UNSUPPORTED 0x80 -#define PERIODIC_SPF_INTERVAL 60 /* at the top of my head */ -#define MINIMUM_SPF_INTERVAL 5 /* .. same here */ + +/* min and max metric varies by new vs old metric types */ +#define DEFAULT_CIRCUIT_METRIC 10 + +#define METRICS_UNSUPPORTED 0x80 + +#define MINIMUM_SPF_INTERVAL 1 + +#define ISIS_MAX_PATH_SPLITS 64 /* * NLPID values @@ -104,6 +129,7 @@ #define SNPA_ADDRSTRLEN 18 #define ISIS_SYS_ID_LEN 6 +#define ISIS_NSEL_LEN 1 #define SYSID_STRLEN 24 /* @@ -136,8 +162,8 @@ * packets, using isomtu = mtu - LLC_LEN */ #define ISO_MTU(C) \ - (C->circ_type==CIRCUIT_T_BROADCAST) ? \ - (C->interface->mtu - LLC_LEN) : (C->interface->mtu) + ((if_is_broadcast ((C)->interface)) ? \ + (C->interface->mtu - LLC_LEN) : (C->interface->mtu)) #ifndef ETH_ALEN #define ETH_ALEN 6 diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index 80d0c9066..5d74a71be 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -36,6 +36,7 @@ #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" @@ -45,7 +46,6 @@ #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" -#include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" @@ -85,6 +85,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) case C_STATE_NA: if (circuit) zlog_warn ("Non-null circuit while state C_STATE_NA"); + assert (circuit == NULL); switch (event) { case ISIS_ENABLE: @@ -106,23 +107,29 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) } break; case C_STATE_INIT: + assert (circuit); switch (event) { case ISIS_ENABLE: isis_circuit_configure (circuit, (struct isis_area *) arg); - isis_circuit_up (circuit); + if (isis_circuit_up (circuit) != ISIS_OK) + { + isis_circuit_deconfigure (circuit, (struct isis_area *) arg); + break; + } circuit->state = C_STATE_UP; - isis_event_circuit_state_change (circuit, 1); + isis_event_circuit_state_change (circuit, circuit->area, 1); listnode_delete (isis->init_circ_list, circuit); break; case IF_UP_FROM_Z: + assert (circuit); zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); break; case IF_DOWN_FROM_Z: - isis_circuit_if_del (circuit); + isis_circuit_if_del (circuit, (struct interface *) arg); listnode_delete (isis->init_circ_list, circuit); isis_circuit_del (circuit); circuit = NULL; @@ -130,6 +137,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) } break; case C_STATE_CONF: + assert (circuit); switch (event) { case ISIS_ENABLE: @@ -137,9 +145,13 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) break; case IF_UP_FROM_Z: isis_circuit_if_add (circuit, (struct interface *) arg); - isis_circuit_up (circuit); + if (isis_circuit_up (circuit) != ISIS_OK) + { + isis_circuit_if_del (circuit, (struct interface *) arg); + break; + } circuit->state = C_STATE_UP; - isis_event_circuit_state_change (circuit, 1); + isis_event_circuit_state_change (circuit, circuit->area, 1); break; case ISIS_DISABLE: isis_circuit_deconfigure (circuit, (struct isis_area *) arg); @@ -152,6 +164,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) } break; case C_STATE_UP: + assert (circuit); switch (event) { case ISIS_ENABLE: @@ -161,15 +174,18 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: + isis_circuit_down (circuit); isis_circuit_deconfigure (circuit, (struct isis_area *) arg); - listnode_add (isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; - isis_event_circuit_state_change (circuit, 0); + isis_event_circuit_state_change (circuit, + (struct isis_area *)arg, 0); + listnode_add (isis->init_circ_list, circuit); break; case IF_DOWN_FROM_Z: - isis_circuit_if_del (circuit); + isis_circuit_down (circuit); + isis_circuit_if_del (circuit, (struct interface *) arg); circuit->state = C_STATE_CONF; - isis_event_circuit_state_change (circuit, 0); + isis_event_circuit_state_change (circuit, circuit->area, 0); break; } break; diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index fe872a952..73b6d3e7b 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -442,12 +442,12 @@ open_dlpi_dev (struct isis_circuit *circuit) * 8.4.2 - Broadcast subnetwork IIH PDUs */ retval = 0; - if (circuit->circuit_is_type & IS_LEVEL_1) + if (circuit->is_type & IS_LEVEL_1) { retval |= dlpimcast (fd, ALL_L1_ISS); retval |= dlpimcast (fd, ALL_ISS); } - if (circuit->circuit_is_type & IS_LEVEL_2) + if (circuit->is_type & IS_LEVEL_2) retval |= dlpimcast (fd, ALL_L2_ISS); if (retval != 0) @@ -589,6 +589,16 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl; char *dstaddr; u_short *dstsap; + int buflen; + + buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; + if (buflen > sizeof (sock_buff)) + { + zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than " + "output pdu size %d on circuit %s", + sizeof (sock_buff), buflen, circuit->interface->name); + return ISIS_WARNING; + } stream_set_getp (circuit->snd_stream, 0); @@ -612,7 +622,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) else memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL); /* Note: DLPI SAP values are in host byte order */ - *dstsap = stream_get_endp (circuit->snd_stream) + LLC_LEN; + *dstsap = buflen; sock_buff[0] = ISO_SAP; sock_buff[1] = ISO_SAP; @@ -620,7 +630,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, - sock_buff, stream_get_endp (circuit->snd_stream) + LLC_LEN, 0); + sock_buff, buflen, 0); return ISIS_OK; } diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c index 8d306c8f5..bc6ec1196 100644 --- a/isisd/isis_dr.c +++ b/isisd/isis_dr.c @@ -47,9 +47,6 @@ #include "isisd/isis_dr.h" #include "isisd/isis_events.h" -extern struct isis *isis; -extern struct thread_master *master; - const char * isis_disflag2string (int disflag) { @@ -137,15 +134,14 @@ isis_dr_elect (struct isis_circuit *circuit, int level) int biggest_prio = -1; int cmp_res, retval = ISIS_OK; - own_prio = circuit->u.bc.priority[level - 1]; + own_prio = circuit->priority[level - 1]; adjdb = circuit->u.bc.adjdb[level - 1]; if (!adjdb) { zlog_warn ("isis_dr_elect() adjdb == NULL"); - retval = ISIS_WARNING; list_delete (list); - goto out; + return ISIS_WARNING; } isis_adj_build_up_list (adjdb, list); @@ -189,42 +185,34 @@ isis_dr_elect (struct isis_circuit *circuit, int level) if (!adj_dr) { /* - * Could not find the DR - means we are alone and thus the DR + * Could not find the DR - means we are alone. Resign if we were DR. */ - if (!circuit->u.bc.is_dr[level - 1]) - { - list_delete (list); - list = NULL; - return isis_dr_commence (circuit, level); - } - goto out; + if (circuit->u.bc.is_dr[level - 1]) + retval = isis_dr_resign (circuit, level); + list_delete (list); + return retval; } /* * Now we have the DR adjacency, compare it to self */ - if (adj_dr->prio[level - 1] < own_prio - || (adj_dr->prio[level - 1] == own_prio - && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0)) + if (adj_dr->prio[level - 1] < own_prio || + (adj_dr->prio[level - 1] == own_prio && + memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0)) { - if (!circuit->u.bc.is_dr[level - 1]) - { - /* - * We are the DR - */ + adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS; + adj_dr->dis_record[level - 1].last_dis_change = time (NULL); - /* rotate the history log */ - for (ALL_LIST_ELEMENTS_RO (list, node, adj)) - isis_check_dr_change (adj, level); + /* rotate the history log */ + for (ALL_LIST_ELEMENTS_RO (list, node, adj)) + isis_check_dr_change (adj, level); - /* commence */ - list_delete (list); - return isis_dr_commence (circuit, level); - } + /* We are the DR, commence DR */ + if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0) + retval = isis_dr_commence (circuit, level); } else { - /* ok we have found the DIS - lets mark the adjacency */ /* set flag for show output */ adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS; @@ -240,16 +228,10 @@ isis_dr_elect (struct isis_circuit *circuit, int level) /* * We are not DR - if we were -> resign */ - if (circuit->u.bc.is_dr[level - 1]) - { - list_delete (list); - return isis_dr_resign (circuit, level); - } + retval = isis_dr_resign (circuit, level); } -out: - if (list) - list_delete (list); + list_delete (list); return retval; } @@ -264,11 +246,12 @@ isis_dr_resign (struct isis_circuit *circuit, int level) circuit->u.bc.run_dr_elect[level - 1] = 0; THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); + circuit->lsp_regenerate_pending[level - 1] = 0; memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; - lsp_purge_dr (id, circuit, level); + lsp_purge_pseudo (id, circuit, level); if (level == 1) { @@ -327,7 +310,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level) if (LSP_PSEUDO_ID (old_dr)) { /* there was a dr elected, purge its LSPs from the db */ - lsp_purge_dr (old_dr, circuit, level); + lsp_purge_pseudo (old_dr, circuit, level); } memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; @@ -335,7 +318,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level) assert (circuit->circuit_id); /* must be non-zero */ /* if (circuit->t_send_l1_psnp) thread_cancel (circuit->t_send_l1_psnp); */ - lsp_l1_pseudo_generate (circuit); + lsp_generate_pseudo (circuit, 1); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, @@ -353,7 +336,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level) if (LSP_PSEUDO_ID (old_dr)) { /* there was a dr elected, purge its LSPs from the db */ - lsp_purge_dr (old_dr, circuit, level); + lsp_purge_pseudo (old_dr, circuit, level); } memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; @@ -361,7 +344,7 @@ isis_dr_commence (struct isis_circuit *circuit, int level) assert (circuit->circuit_id); /* must be non-zero */ /* if (circuit->t_send_l1_psnp) thread_cancel (circuit->t_send_l1_psnp); */ - lsp_l2_pseudo_generate (circuit); + lsp_generate_pseudo (circuit, 2); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index 0b758c856..ffb0d503f 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -41,8 +41,6 @@ #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" -extern struct isis *isis; -extern struct thread_master *master; extern struct host host; struct list *dyn_cache = NULL; @@ -51,7 +49,8 @@ static int dyn_cache_cleanup (struct thread *); void dyn_cache_init (void) { - dyn_cache = list_new (); + if (dyn_cache == NULL) + dyn_cache = list_new (); THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120); return; } @@ -67,8 +66,8 @@ dyn_cache_cleanup (struct thread *thread) for (ALL_LIST_ELEMENTS (dyn_cache, node, nnode, dyn)) { - if ((now - dyn->refresh) < (MAX_AGE + 120)) - continue; + if ((now - dyn->refresh) < MAX_LSP_LIFETIME) + continue; list_delete_node (dyn_cache, node); XFREE (MTYPE_ISIS_DYNHN, dyn); @@ -91,6 +90,19 @@ dynhn_find_by_id (u_char * id) return NULL; } +struct isis_dynhn * +dynhn_find_by_name (const char *hostname) +{ + struct listnode *node = NULL; + struct isis_dynhn *dyn = NULL; + + for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) + if (strncmp ((char *)dyn->name.name, hostname, 255) == 0) + return dyn; + + return NULL; +} + void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level) { @@ -122,6 +134,19 @@ isis_dynhn_insert (u_char * id, struct hostname *hostname, int level) return; } +void +isis_dynhn_remove (u_char * id) +{ + struct isis_dynhn *dyn; + + dyn = dynhn_find_by_id (id); + if (!dyn) + return; + listnode_delete (dyn_cache, dyn); + XFREE (MTYPE_ISIS_DYNHN, dyn); + return; +} + /* * Level System ID Dynamic Hostname (notag) * 2 0000.0000.0001 foo-gw diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h index 37a7b03c0..379c454fc 100644 --- a/isisd/isis_dynhn.h +++ b/isisd/isis_dynhn.h @@ -33,7 +33,9 @@ struct isis_dynhn void dyn_cache_init (void); void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level); +void isis_dynhn_remove (u_char * id); struct isis_dynhn *dynhn_find_by_id (u_char * id); +struct isis_dynhn *dynhn_find_by_name (const char *hostname); void dynhn_print_all (struct vty *vty); #endif /* _ZEBRA_ISIS_DYNHN_H */ diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 438009224..750a4c384 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -30,11 +30,13 @@ #include "hash.h" #include "prefix.h" #include "stream.h" +#include "table.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" @@ -44,15 +46,11 @@ #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" -#include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_spf.h" -extern struct thread_master *master; -extern struct isis *isis; - /* debug isis-spf spf-events 4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4 4w4d: ISIS-Spf (tlt): L2, 0000.0000.0042.01-00 TLV contents changed, code 0x2 @@ -62,26 +60,59 @@ extern struct isis *isis; */ void -isis_event_circuit_state_change (struct isis_circuit *circuit, int up) +isis_event_circuit_state_change (struct isis_circuit *circuit, + struct isis_area *area, int up) { - struct isis_area *area; - - area = circuit->area; - assert (area); area->circuit_state_changes++; if (isis->debugs & DEBUG_EVENTS) - zlog_debug ("ISIS-Evt (%s) circuit %s", circuit->area->area_tag, - up ? "up" : "down"); + zlog_debug ("ISIS-Evt (%s) circuit %s", area->area_tag, + up ? "up" : "down"); /* * Regenerate LSPs this affects */ - lsp_regenerate_schedule (area); + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } +static void +area_resign_level (struct isis_area *area, int level) +{ + if (area->lspdb[level - 1]) + { + lsp_db_destroy (area->lspdb[level - 1]); + area->lspdb[level - 1] = NULL; + } + if (area->spftree[level - 1]) + { + isis_spftree_del (area->spftree[level - 1]); + area->spftree[level - 1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->spftree6[level - 1]) + { + isis_spftree_del (area->spftree6[level - 1]); + area->spftree6[level - 1] = NULL; + } +#endif + if (area->route_table[level - 1]) + { + route_table_finish (area->route_table[level - 1]); + area->route_table[level - 1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->route_table6[level - 1]) + { + route_table_finish (area->route_table6[level - 1]); + area->route_table6[level - 1] = NULL; + } +#endif /* HAVE_IPV6 */ + + THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); +} + void isis_event_system_type_change (struct isis_area *area, int newtype) { @@ -96,45 +127,71 @@ isis_event_system_type_change (struct isis_area *area, int newtype) return; /* No change */ switch (area->is_type) - { + { case IS_LEVEL_1: - if (area->lspdb[1] == NULL) - area->lspdb[1] = lsp_db_init (); - lsp_l2_generate (area); + if (newtype == IS_LEVEL_2) + { + area_resign_level (area, IS_LEVEL_1); + } + else + { + if (area->lspdb[1] == NULL) + area->lspdb[1] = lsp_db_init (); + if (area->route_table[1] == NULL) + area->route_table[1] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[1] == NULL) + area->route_table6[1] = route_table_init (); +#endif /* HAVE_IPV6 */ + } break; + case IS_LEVEL_1_AND_2: if (newtype == IS_LEVEL_1) - { - lsp_db_destroy (area->lspdb[1]); - } + area_resign_level (area, IS_LEVEL_2); else - { - lsp_db_destroy (area->lspdb[0]); - } + area_resign_level (area, IS_LEVEL_1); break; + case IS_LEVEL_2: - if (area->lspdb[0] == NULL) - area->lspdb[0] = lsp_db_init (); - lsp_l1_generate (area); + if (newtype == IS_LEVEL_1) + { + area_resign_level (area, IS_LEVEL_2); + } + else + { + if (area->lspdb[0] == NULL) + area->lspdb[0] = lsp_db_init (); + if (area->route_table[0] == NULL) + area->route_table[0] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[0] == NULL) + area->route_table6[0] = route_table_init (); +#endif /* HAVE_IPV6 */ + } break; default: break; - } + } area->is_type = newtype; - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - isis_event_circuit_type_change (circuit, newtype); - spftree_area_init (area); - lsp_regenerate_schedule (area); + /* override circuit's is_type */ + if (area->is_type != IS_LEVEL_1_AND_2) + { + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + isis_event_circuit_type_change (circuit, newtype); + } - return; -} + spftree_area_init (area); -void -isis_event_area_addr_change (struct isis_area *area) -{ + if (newtype & IS_LEVEL_1) + lsp_generate (area, IS_LEVEL_1); + if (newtype & IS_LEVEL_2) + lsp_generate (area, IS_LEVEL_2); + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + return; } static void @@ -148,7 +205,7 @@ circuit_commence_level (struct isis_circuit *circuit, int level) if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, - circuit, 2 * circuit->hello_interval[1]); + circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, @@ -194,6 +251,8 @@ circuit_resign_level (struct isis_circuit *circuit, int level) THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]); circuit->u.bc.run_dr_elect[idx] = 0; + list_delete (circuit->u.bc.lan_neighs[idx]); + circuit->u.bc.lan_neighs[idx] = NULL; } return; @@ -202,14 +261,19 @@ circuit_resign_level (struct isis_circuit *circuit, int level) void isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) { + if (circuit->state != C_STATE_UP) + { + circuit->is_type = newtype; + return; + } if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) circuit type change %s -> %s", circuit->area->area_tag, - circuit_t2string (circuit->circuit_is_type), + circuit_t2string (circuit->is_type), circuit_t2string (newtype)); - if (circuit->circuit_is_type == newtype) + if (circuit->is_type == newtype) return; /* No change */ if (!(newtype & circuit->area->is_type)) @@ -221,7 +285,7 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) return; } - switch (circuit->circuit_is_type) + switch (circuit->is_type) { case IS_LEVEL_1: if (newtype == IS_LEVEL_2) @@ -243,8 +307,8 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) break; } - circuit->circuit_is_type = newtype; - lsp_regenerate_schedule (circuit->area); + circuit->is_type = newtype; + lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } @@ -286,7 +350,7 @@ isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate) adj->circuit->area->area_tag); /* LSP generation again */ - lsp_regenerate_schedule (adj->circuit->area); + lsp_regenerate_schedule (adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } @@ -307,7 +371,7 @@ isis_event_dis_status_change (struct thread *thread) zlog_debug ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag); /* LSP generation again */ - lsp_regenerate_schedule (circuit->area); + lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return 0; } diff --git a/isisd/isis_events.h b/isisd/isis_events.h index 86bf051f3..c252f3def 100644 --- a/isisd/isis_events.h +++ b/isisd/isis_events.h @@ -26,13 +26,12 @@ * Events related to area */ void isis_event_system_type_change (struct isis_area *area, int newtype); -void isis_event_area_addr_change (struct isis_area *area); /* * Events related to circuit */ void isis_event_circuit_state_change (struct isis_circuit *circuit, - int state); + struct isis_area *area, int state); void isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype); /* diff --git a/isisd/isis_flags.c b/isisd/isis_flags.c index 03c91101f..ec0eaa4f8 100644 --- a/isisd/isis_flags.c +++ b/isisd/isis_flags.c @@ -36,11 +36,11 @@ flags_initialize (struct flags *flags) flags->free_idcs = NULL; } -int +long int flags_get_index (struct flags *flags) { struct listnode *node; - int index; + long int index; if (flags->free_idcs == NULL || flags->free_idcs->count == 0) { @@ -49,7 +49,7 @@ flags_get_index (struct flags *flags) else { node = listhead (flags->free_idcs); - index = (int) listgetdata (node); + index = (long int) listgetdata (node); listnode_delete (flags->free_idcs, (void *) index); index--; } @@ -58,7 +58,7 @@ flags_get_index (struct flags *flags) } void -flags_free_index (struct flags *flags, int index) +flags_free_index (struct flags *flags, long int index) { if (index + 1 == flags->maxindex) { diff --git a/isisd/isis_flags.h b/isisd/isis_flags.h index 13dd9e145..e2e42adcc 100644 --- a/isisd/isis_flags.h +++ b/isisd/isis_flags.h @@ -26,28 +26,43 @@ /* The grand plan is to support 1024 circuits so we have 32*32 bit flags * the support will be achived using the newest drafts */ -#define ISIS_MAX_CIRCUITS 32 /* = 1024 */ /*FIXME:defined in lsp.h as well */ +#define ISIS_MAX_CIRCUITS 32 /* = 1024 */ -void flags_initialize (struct flags *flags); -struct flags *new_flags (int size); -int flags_get_index (struct flags *flags); -void flags_free_index (struct flags *flags, int index); +/* + * Flags structure for SSN and SRM flags + */ +struct flags +{ + int maxindex; + struct list *free_idcs; +}; +void flags_initialize (struct flags *flags); +long int flags_get_index (struct flags *flags); +void flags_free_index (struct flags *flags, long int index); int flags_any_set (u_int32_t * flags); #define ISIS_SET_FLAG(F,C) \ - F[C->idx>>5] |= (1<<(C->idx & 0x1F)); + { \ + F[C->idx>>5] |= (1<<(C->idx & 0x1F)); \ + } #define ISIS_CLEAR_FLAG(F,C) \ - F[C->idx>>5] &= ~(1<<(C->idx & 0x1F)); + { \ + F[C->idx>>5] &= ~(1<<(C->idx & 0x1F)); \ + } -#define ISIS_CHECK_FLAG(F, C) F[(C)->idx>>5] & (1<<(C->idx & 0x1F)) +#define ISIS_CHECK_FLAG(F, C) (F[(C)->idx>>5] & (1<<(C->idx & 0x1F))) /* sets all u_32int_t flags to 1 */ #define ISIS_FLAGS_SET_ALL(FLAGS) \ - memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4); + { \ + memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4); \ + } #define ISIS_FLAGS_CLEAR_ALL(FLAGS) \ - memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4); + { \ + memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4); \ + } #endif /* _ZEBRA_ISIS_FLAGS_H */ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 50289db39..f71794323 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -34,10 +34,12 @@ #include "hash.h" #include "if.h" #include "checksum.h" +#include "md5.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_tlv.h" @@ -45,7 +47,6 @@ #include "isisd/isis_pdu.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" -#include "isisd/isis_flags.h" #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" @@ -54,15 +55,14 @@ #include "spgrid.h" #endif -#define LSP_MEMORY_PREASSIGN - -extern struct isis *isis; -extern struct thread_master *master; -extern struct in_addr router_id_zebra; - /* staticly assigned vars for printing purposes */ char lsp_bits_string[200]; /* FIXME: enough ? */ +static int lsp_l1_refresh (struct thread *thread); +static int lsp_l2_refresh (struct thread *thread); +static int lsp_l1_refresh_pseudo (struct thread *thread); +static int lsp_l2_refresh_pseudo (struct thread *thread); + int lsp_id_cmp (u_char * id1, u_char * id2) { @@ -90,7 +90,7 @@ lsp_search (u_char * id, dict_t * lspdb) zlog_debug ("searching db"); for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn)) { - zlog_debug ("%s\t%pX", rawlspid_print ((char *) dnode_getkey (dn)), + zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)), dnode_get (dn)); } #endif /* EXTREME DEBUG */ @@ -109,54 +109,56 @@ lsp_clear_data (struct isis_lsp *lsp) if (!lsp) return; + if (lsp->tlv_data.hostname) + isis_dynhn_remove (lsp->lsp_header->lsp_id); + if (lsp->own_lsp) { if (lsp->tlv_data.nlpids) - XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids); + XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids); if (lsp->tlv_data.hostname) - XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname); + XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname); + if (lsp->tlv_data.router_id) + XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id); } - if (lsp->tlv_data.is_neighs) - list_delete (lsp->tlv_data.is_neighs); - if (lsp->tlv_data.te_is_neighs) - list_delete (lsp->tlv_data.te_is_neighs); - if (lsp->tlv_data.area_addrs) - list_delete (lsp->tlv_data.area_addrs); - if (lsp->tlv_data.es_neighs) - list_delete (lsp->tlv_data.es_neighs); - if (lsp->tlv_data.ipv4_addrs) - list_delete (lsp->tlv_data.ipv4_addrs); - if (lsp->tlv_data.ipv4_int_reachs) - list_delete (lsp->tlv_data.ipv4_int_reachs); - if (lsp->tlv_data.ipv4_ext_reachs) - list_delete (lsp->tlv_data.ipv4_ext_reachs); - if (lsp->tlv_data.te_ipv4_reachs) - list_delete (lsp->tlv_data.te_ipv4_reachs); -#ifdef HAVE_IPV6 - if (lsp->tlv_data.ipv6_addrs) - list_delete (lsp->tlv_data.ipv6_addrs); - if (lsp->tlv_data.ipv6_reachs) - list_delete (lsp->tlv_data.ipv6_reachs); -#endif /* HAVE_IPV6 */ - memset (&lsp->tlv_data, 0, sizeof (struct tlvs)); - - return; + free_tlvs (&lsp->tlv_data); } static void lsp_destroy (struct isis_lsp *lsp) { + struct listnode *cnode, *lnode, *lnnode; + struct isis_lsp *lsp_in_list; + struct isis_circuit *circuit; + if (!lsp) return; + for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit)) + { + if (circuit->lsp_queue == NULL) + continue; + for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list)) + if (lsp_in_list == lsp) + list_delete_node(circuit->lsp_queue, lnode); + } + ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); + ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); + lsp_clear_data (lsp); if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) { list_delete (lsp->lspu.frags); + lsp->lspu.frags = NULL; } + isis_spf_schedule (lsp->area, lsp->level); +#ifdef HAVE_IPV6 + isis_spf_schedule6 (lsp->area, lsp->level); +#endif + if (lsp->pdu) stream_free (lsp->pdu); XFREE (MTYPE_ISIS_LSP, lsp); @@ -254,7 +256,7 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, { if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x," + zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," " lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), @@ -273,7 +275,7 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, { if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x," + zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," " lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), @@ -290,7 +292,7 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug - ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us", + ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x," @@ -303,6 +305,91 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, return LSP_OLDER; } +static void +lsp_auth_add (struct isis_lsp *lsp) +{ + struct isis_passwd *passwd; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + + /* + * Add the authentication info if its present + */ + (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) : + (passwd = &lsp->area->domain_passwd); + switch (passwd->type) + { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); + tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later + * overwrite the MD5 hash */ + lsp->auth_tlv_offset = stream_get_endp (lsp->pdu); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5; + lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE; + memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, + ISIS_AUTH_MD5_SIZE); + tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, + lsp->pdu); + break; + + default: + break; + } +} + +static void +lsp_auth_update (struct isis_lsp *lsp) +{ + struct isis_passwd *passwd; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + uint16_t checksum, rem_lifetime; + + /* For HMAC MD5 we need to recompute the md5 hash and store it */ + (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) : + (passwd = &lsp->area->domain_passwd); + if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5) + return; + + /* + * In transient conditions (when net is configured where authentication + * config and lsp regenerate schedule is not yet run), there could be + * an own_lsp with auth_tlv_offset set to 0. In such a case, simply + * return, when lsp_regenerate is run, lsp will have auth tlv. + */ + if (lsp->auth_tlv_offset == 0) + return; + + /* + * RFC 5304 set auth value, checksum and remaining lifetime to zero + * before computation and reset to old values after computation. + */ + checksum = lsp->lsp_header->checksum; + rem_lifetime = lsp->lsp_header->rem_lifetime; + lsp->lsp_header->checksum = 0; + lsp->lsp_header->rem_lifetime = 0; + /* Set the authentication value as well to zero */ + memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, + 0, ISIS_AUTH_MD5_SIZE); + /* Compute autentication value */ + hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu), + (unsigned char *) &passwd->passwd, passwd->len, + (caddr_t) &hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, + ISIS_AUTH_MD5_SIZE); + /* Copy back the checksum and remaining lifetime */ + lsp->lsp_header->checksum = checksum; + lsp->lsp_header->rem_lifetime = rem_lifetime; +} + void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num) { @@ -311,11 +398,25 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num) if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num) newseq = ntohl (lsp->lsp_header->seq_num) + 1; else - newseq = seq_num++; + newseq = seq_num + 1; lsp->lsp_header->seq_num = htonl (newseq); - fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, - ntohs (lsp->lsp_header->pdu_len) - 12, 12); + + /* Recompute authentication and checksum information */ + lsp_auth_update (lsp); + /* ISO 10589 - 7.3.11 Generation of the checksum + * The checksum shall be computed over all fields in the LSP which appear + * after the Remaining Lifetime field. This field (and those appearing + * before it) are excluded so that the LSP may be aged by systems without + * requiring recomputation. + */ + fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, + ntohs (lsp->lsp_header->pdu_len) - 12, 12); + + isis_spf_schedule (lsp->area, lsp->level); +#ifdef HAVE_IPV6 + isis_spf_schedule6 (lsp->area, lsp->level); +#endif return; } @@ -340,39 +441,27 @@ lsp_seqnum_update (struct isis_lsp *lsp0) return; } -int -isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area, - int pdulen, struct isis_passwd *passwd) -{ - uint32_t expected = 0, found; - struct tlvs tlvs; - int retval = 0; - - expected |= TLVFLAG_AUTH_INFO; - retval = parse_tlvs (area->area_tag, stream->data + - ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, - pdulen - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs); - if (retval || !(found & TLVFLAG_AUTH_INFO)) - return 1; /* Auth fail (parsing failed or no auth-tlv) */ - - return authentication_check (passwd, &tlvs.auth_info); -} - static void lsp_update_data (struct isis_lsp *lsp, struct stream *stream, - struct isis_area *area) + struct isis_area *area, int level) { uint32_t expected = 0, found; int retval; + /* free the old lsp data */ + lsp_clear_data (lsp); + /* copying only the relevant part of our stream */ + if (lsp->pdu != NULL) + stream_free (lsp->pdu); lsp->pdu = stream_dup (stream); - + /* setting pointers to the correct place */ lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); + lsp->area = area; + lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; lsp->installed = time (NULL); /* @@ -400,57 +489,59 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream, expected |= TLVFLAG_IPV6_REACHABILITY; #endif /* HAVE_IPV6 */ - retval = parse_tlvs (area->area_tag, lsp->pdu->data + - ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, - ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data); + retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) + + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, + ntohs (lsp->lsp_header->pdu_len) - + ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, + &expected, &found, &lsp->tlv_data, + NULL); + if (retval != ISIS_OK) + { + zlog_warn ("Could not parse LSP"); + return; + } - if (found & TLVFLAG_DYN_HOSTNAME) + if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) { - if (area->dynhostname) isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, (lsp->lsp_header->lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : (lsp->lsp_header->lsp_bits & LSPBIT_IST)); } + return; } void -lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr, - struct stream *stream, struct isis_area *area, int level) +lsp_update (struct isis_lsp *lsp, struct stream *stream, + struct isis_area *area, int level) { dnode_t *dnode = NULL; - /* Remove old LSP from LSP database. */ + /* Remove old LSP from database. This is required since the + * lsp_update_data will free the lsp->pdu (which has the key, lsp_id) + * and will update it with the new data in the stream. */ dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id); if (dnode) dnode_destroy (dict_delete (area->lspdb[level - 1], dnode)); - /* free the old lsp data */ - XFREE (MTYPE_STREAM_DATA, lsp->pdu); - lsp_clear_data (lsp); - /* rebuild the lsp data */ - lsp_update_data (lsp, stream, area); - - /* set the new values for lsp header */ - memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); + lsp_update_data (lsp, stream, area, level); - if (dnode) - lsp_insert (lsp, area->lspdb[level - 1]); + /* insert the lsp back into the database */ + lsp_insert (lsp, area->lspdb[level - 1]); } /* creation of LSP directly from what we received */ struct isis_lsp * lsp_new_from_stream_ptr (struct stream *stream, u_int16_t pdu_len, struct isis_lsp *lsp0, - struct isis_area *area) + struct isis_area *area, int level) { struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); - lsp_update_data (lsp, stream, area); + lsp_update_data (lsp, stream, area, level); if (lsp0 == NULL) { @@ -484,12 +575,8 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, zlog_warn ("lsp_new(): out of memory"); return NULL; } -#ifdef LSP_MEMORY_PREASSIGN - lsp->pdu = stream_new (1514); /*Should be minimal mtu? yup... */ -#else - /* We need to do realloc on TLVs additions */ - lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); -#endif /* LSP_MEMORY_PREASSIGN */ + /* FIXME: Should be minimal mtu? */ + lsp->pdu = stream_new (1500); if (LSP_FRAGMENT (lsp_id) == 0) lsp->lspu.frags = list_new (); lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); @@ -497,7 +584,7 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); /* at first we fill the FIXED HEADER */ - (level == 1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) : + (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) : fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE); /* now for the LSP HEADER */ @@ -514,9 +601,10 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); if (isis->debugs & DEBUG_EVENTS) - zlog_debug ("New LSP with ID %s-%02x-%02x seqnum %08x", + zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x", sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id), LSP_FRAGMENT (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num)); return lsp; @@ -526,6 +614,13 @@ void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb) { dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp); + if (lsp->lsp_header->seq_num != 0) + { + isis_spf_schedule (lsp->area, lsp->level); +#ifdef HAVE_IPV6 + isis_spf_schedule6 (lsp->area, lsp->level); +#endif + } } /* @@ -562,12 +657,13 @@ lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id, } /* - * Build a list of all LSPs bounded by start and stop ids + * Build a list of num_lsps LSPs bounded by start_id and stop_id. */ void -lsp_build_list (u_char * start_id, u_char * stop_id, +lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps, struct list *list, dict_t * lspdb) { + u_char count; dnode_t *first, *last, *curr; first = dict_lower_bound (lspdb, start_id); @@ -579,14 +675,18 @@ lsp_build_list (u_char * start_id, u_char * stop_id, curr = first; listnode_add (list, first->dict_data); + count = 1; while (curr) { curr = dict_next (lspdb, curr); if (curr) - listnode_add (list, curr->dict_data); - if (curr == last) - break; + { + listnode_add (list, curr->dict_data); + count++; + } + if (count == num_lsps || curr == last) + break; } return; @@ -596,11 +696,12 @@ lsp_build_list (u_char * start_id, u_char * stop_id, * Build a list of LSPs with SSN flag set for the given circuit */ void -lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list, - dict_t * lspdb) +lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, + struct list *list, dict_t * lspdb) { dnode_t *dnode, *next; struct isis_lsp *lsp; + u_char count = 0; dnode = dict_first (lspdb); while (dnode != NULL) @@ -608,7 +709,12 @@ lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list, next = dict_next (lspdb, dnode); lsp = dnode_get (dnode); if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit)) - listnode_add (list, lsp); + { + listnode_add (list, lsp); + ++count; + } + if (count == num_lsps) + break; dnode = next; } @@ -622,22 +728,11 @@ lsp_set_time (struct isis_lsp *lsp) if (lsp->lsp_header->rem_lifetime == 0) { - if (lsp->age_out != 0) - lsp->age_out--; + if (lsp->age_out > 0) + lsp->age_out--; return; } - /* If we are turning 0 */ - /* ISO 10589 - 7.3.16.4 first paragraph */ - - if (ntohs (lsp->lsp_header->rem_lifetime) == 1) - { - /* 7.3.16.4 a) set SRM flags on all */ - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - /* 7.3.16.4 b) retain only the header FIXME */ - /* 7.3.16.4 c) record the time to purge FIXME (other way to do it) */ - } - lsp->lsp_header->rem_lifetime = htons (ntohs (lsp->lsp_header->rem_lifetime) - 1); } @@ -654,13 +749,11 @@ lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag) dyn = NULL; if (dyn) - sprintf ((char *)id, "%.14s", dyn->name.name); - else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost) - sprintf ((char *)id, "%.14s", unix_hostname ()); + sprintf ((char *)id, "%.14s", dyn->name.name); + else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost) + sprintf ((char *)id, "%.14s", unix_hostname ()); else - { memcpy (id, sysid_print (lsp_id), 15); - } if (frag) sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id), LSP_FRAGMENT (lsp_id)); @@ -692,30 +785,32 @@ lsp_bits2string (u_char * lsp_bits) } /* this function prints the lsp on show isis database */ -static void -lsp_print (dnode_t * node, struct vty *vty, char dynhost) +void +lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost) { - struct isis_lsp *lsp = dnode_get (node); u_char LSPid[255]; + char age_out[8]; lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); - vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' '); - vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num)); - vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum)); - + vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' '); + vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len)); + vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num)); + vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum)); if (ntohs (lsp->lsp_header->rem_lifetime) == 0) - vty_out (vty, " (%2u)", lsp->age_out); + { + snprintf (age_out, 8, "(%u)", lsp->age_out); + age_out[7] = '\0'; + vty_out (vty, "%7s ", age_out); + } else - vty_out (vty, "%5u", ntohs (lsp->lsp_header->rem_lifetime)); - - vty_out (vty, " %s%s", - lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE); + vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime)); + vty_out (vty, "%s%s", + lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE); } -static void -lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) +void +lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) { - struct isis_lsp *lsp = dnode_get (node); struct area_addr *area_addr; int i; struct listnode *lnode; @@ -736,7 +831,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) u_char ipv4_address[20]; lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); - lsp_print (node, vty, dynhost); + lsp_print (lsp, vty, dynhost); /* for all area address */ if (lsp->tlv_data.area_addrs) @@ -756,11 +851,11 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) { case NLPID_IP: case NLPID_IPV6: - vty_out (vty, " NLPID: 0x%X%s", + vty_out (vty, " NLPID : 0x%X%s", lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE); break; default: - vty_out (vty, " NLPID: %s%s", "unknown", VTY_NEWLINE); + vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE); break; } } @@ -769,33 +864,42 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) /* for the hostname tlv */ if (lsp->tlv_data.hostname) { - memset (hostname, 0, sizeof (hostname)); + bzero (hostname, sizeof (hostname)); memcpy (hostname, lsp->tlv_data.hostname->name, lsp->tlv_data.hostname->namelen); - vty_out (vty, " Hostname: %s%s", hostname, VTY_NEWLINE); + vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE); } - if (lsp->tlv_data.ipv4_addrs) - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr)) - { - memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address)); - vty_out (vty, " IP: %s%s", ipv4_address, VTY_NEWLINE); - } + /* authentication tlv */ + if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) + { + if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5) + vty_out (vty, " Auth type : md5%s", VTY_NEWLINE); + else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT) + vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE); + } /* TE router id */ if (lsp->tlv_data.router_id) { memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id), sizeof (ipv4_address)); - vty_out (vty, " Router ID: %s%s", ipv4_address, VTY_NEWLINE); + vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE); } + if (lsp->tlv_data.ipv4_addrs) + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr)) + { + memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address)); + vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE); + } + /* for the IS neighbor tlv */ if (lsp->tlv_data.is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh)) { lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0); - vty_out (vty, " Metric: %-10d IS %s%s", + vty_out (vty, " Metric : %-8d IS : %s%s", is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE); } @@ -808,7 +912,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) sizeof (ipv4_reach_prefix)); memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask)); - vty_out (vty, " Metric: %-10d IP-Internal %s %s%s", + vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s", ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } @@ -822,7 +926,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) sizeof (ipv4_reach_prefix)); memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask)); - vty_out (vty, " Metric: %-10d IP-External %s %s%s", + vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s", ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } @@ -838,11 +942,11 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ); if ((ipv6_reach->control_info && CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) - vty_out (vty, " Metric: %-10d IPv6-Internal %s/%d%s", + vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s", ntohl (ipv6_reach->metric), buff, ipv6_reach->prefix_len, VTY_NEWLINE); else - vty_out (vty, " Metric: %-10d IPv6-External %s/%d%s", + vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s", ntohl (ipv6_reach->metric), buff, ipv6_reach->prefix_len, VTY_NEWLINE); } @@ -852,11 +956,9 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh)) { - uint32_t metric; - memcpy (&metric, te_is_neigh->te_metric, 3); lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); - vty_out (vty, " Metric: %-10d IS-Extended %s%s", - ntohl (metric << 8), LSPid, VTY_NEWLINE); + vty_out (vty, " Metric : %-8d IS-Extended : %s%s", + GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE); } /* TE IPv4 tlv */ @@ -865,12 +967,13 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost) te_ipv4_reach)) { /* FIXME: There should be better way to output this stuff. */ - vty_out (vty, " Metric: %-10d IP-Extended %s/%d%s", + vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s", ntohl (te_ipv4_reach->te_metric), inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start, te_ipv4_reach->control)), te_ipv4_reach->control & 0x3F, VTY_NEWLINE); } + vty_out (vty, "%s", VTY_NEWLINE); return; } @@ -883,10 +986,6 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) dnode_t *node = dict_first (lspdb), *next; int lsp_count = 0; - /* print the title, for both modes */ - vty_out (vty, "LSP ID LSP Seq Num LSP Checksum " - "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE); - if (detail == ISIS_UI_LEVEL_BRIEF) { while (node != NULL) @@ -894,7 +993,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) /* I think it is unnecessary, so I comment it out */ /* dict_contains (lspdb, node); */ next = dict_next (lspdb, node); - lsp_print (node, vty, dynhost); + lsp_print (dnode_get (node), vty, dynhost); node = next; lsp_count++; } @@ -904,7 +1003,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) while (node != NULL) { next = dict_next (lspdb, node); - lsp_print_detail (node, vty, dynhost); + lsp_print_detail (dnode_get (node), vty, dynhost); node = next; lsp_count++; } @@ -914,7 +1013,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) } #define FRAG_THOLD(S,T) \ -((STREAM_SIZE(S)*T)/100) + ((STREAM_SIZE(S)*T)/100) /* stream*, area->lsp_frag_threshold, increment */ #define FRAG_NEEDED(S,T,I) \ @@ -933,16 +1032,32 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2)) { tlv_build_func (*from, lsp->pdu); - *to = *from; - *from = NULL; + if (listcount (*to) != 0) + { + struct listnode *node, *nextnode; + void *elem; + + for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) + { + listnode_add (*to, elem); + list_delete_node (*from, node); + } + } + else + { + list_free (*to); + *to = *from; + *from = NULL; + } } else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2)) { /* fit all we can */ count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); - if (count) - count = count / tlvsize; + count = count / tlvsize; + if (count > (int)listcount (*from)) + count = listcount (*from); for (i = 0; i < count; i++) { listnode_add (*to, listgetdata (listhead (*from))); @@ -954,6 +1069,44 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, return; } +static u_int16_t +lsp_rem_lifetime (struct isis_area *area, int level) +{ + u_int16_t rem_lifetime; + + /* Add jitter to configured LSP lifetime */ + rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1], + MAX_AGE_JITTER); + + /* No jitter if the max refresh will be less than configure gen interval */ + if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300)) + rem_lifetime = area->max_lsp_lifetime[level - 1]; + + return rem_lifetime; +} + +static u_int16_t +lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime) +{ + struct isis_area *area = lsp->area; + int level = lsp->level; + u_int16_t refresh_time; + + /* Add jitter to LSP refresh time */ + refresh_time = isis_jitter (area->lsp_refresh[level - 1], + MAX_LSP_GEN_JITTER); + + /* RFC 4444 : make sure the refresh time is at least less than 300 + * of the remaining lifetime and more than gen interval */ + if (refresh_time <= area->lsp_gen_interval[level - 1] || + refresh_time > (rem_lifetime - 300)) + refresh_time = rem_lifetime - 300; + + assert (area->lsp_gen_interval[level - 1] < refresh_time); + + return refresh_time; +} + static struct isis_lsp * lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, int level) @@ -963,40 +1116,21 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (frag_id) = frag_num; + /* FIXME add authentication TLV for fragment LSPs */ lsp = lsp_search (frag_id, area->lspdb[level - 1]); if (lsp) { - /* - * Clear the TLVs, but inherit the authinfo - */ + /* Clear the TLVs */ lsp_clear_data (lsp); - if (lsp0->tlv_data.auth_info.type) - { - memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info, - sizeof (struct isis_passwd)); - tlv_add_authinfo (lsp->tlv_data.auth_info.type, - lsp->tlv_data.auth_info.len, - lsp->tlv_data.auth_info.passwd, lsp->pdu); - } return lsp; } - lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type, - 0, level); + lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, + area->is_type | area->overload_bit, 0, level); + lsp->area = area; lsp->own_lsp = 1; lsp_insert (lsp, area->lspdb[level - 1]); listnode_add (lsp0->lspu.frags, lsp); lsp->lspu.zero_lsp = lsp0; - /* - * Copy the authinfo from zero LSP - */ - if (lsp0->tlv_data.auth_info.type) - { - memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info, - sizeof (struct isis_passwd)); - tlv_add_authinfo (lsp->tlv_data.auth_info.type, - lsp->tlv_data.auth_info.len, - lsp->tlv_data.auth_info.passwd, lsp->pdu); - } return lsp; } @@ -1005,7 +1139,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, * area->lsp_frag_threshold is exceeded. */ static void -lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) +lsp_build (struct isis_lsp *lsp, struct isis_area *area) { struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; @@ -1022,8 +1156,27 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) #endif /* HAVE_IPV6 */ struct tlvs tlv_data; struct isis_lsp *lsp0 = lsp; - struct isis_passwd *passwd; struct in_addr *routerid; + uint32_t expected = 0, found = 0; + uint32_t metric; + u_char zero_id[ISIS_SYS_ID_LEN + 1]; + int retval = ISIS_OK; + + /* + * Building the zero lsp + */ + memset (zero_id, 0, ISIS_SYS_ID_LEN + 1); + + /* Reset stream endp. Stream is always there and on every LSP refresh only + * TLV part of it is overwritten. So we must seek past header we will not + * touch. */ + stream_reset (lsp->pdu); + stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + + /* + * Add the authentication info if its present + */ + lsp_auth_add (lsp); /* * First add the tlvs related to area @@ -1033,6 +1186,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) if (lsp->tlv_data.area_addrs == NULL) lsp->tlv_data.area_addrs = list_new (); list_add_list (lsp->tlv_data.area_addrs, area->area_addrs); + if (listcount (lsp->tlv_data.area_addrs) > 0) + tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu); + /* Protocols Supported */ if (area->ip_circuits > 0 #ifdef HAVE_IPV6 @@ -1055,7 +1211,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) NLPID_IPV6; } #endif /* HAVE_IPV6 */ + tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); } + /* Dynamic Hostname */ if (area->dynhostname) { @@ -1065,39 +1223,13 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) memcpy (lsp->tlv_data.hostname->name, unix_hostname (), strlen (unix_hostname ())); lsp->tlv_data.hostname->namelen = strlen (unix_hostname ()); + tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); } - /* - * Building the zero lsp - */ - - /* Reset stream endp. Stream is always there and on every LSP refresh only - * TLV part of it is overwritten. So we must seek past header we will not - * touch. */ - stream_reset (lsp->pdu); - stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - - /* - * Add the authentication info if its present - */ - (level == 1) ? (passwd = &area->area_passwd) : - (passwd = &area->domain_passwd); - if (passwd->type) - { - memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); - tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); - } - if (lsp->tlv_data.nlpids) - tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); - if (lsp->tlv_data.hostname) - tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); - if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0) - tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu); - /* IPv4 address and TE router ID TLVs. In case of the first one we don't * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into * LSP and this address is same as router id. */ - if (router_id_zebra.s_addr != 0) + if (isis->router_id != 0) { if (lsp->tlv_data.ipv4_addrs == NULL) { @@ -1106,7 +1238,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) } routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); - routerid->s_addr = router_id_zebra.s_addr; + routerid->s_addr = isis->router_id; listnode_add (lsp->tlv_data.ipv4_addrs, routerid); tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR); @@ -1116,8 +1248,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) { lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); - lsp->tlv_data.router_id->id.s_addr = router_id_zebra.s_addr; - tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID); + lsp->tlv_data.router_id->id.s_addr = isis->router_id; + tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, + TE_ROUTER_ID); } } @@ -1126,7 +1259,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) #ifdef TOPOLOGY_GENERATE /* If topology exists (and we create topology for level 1 only), create * (hardcoded) link to topology. */ - if (area->topology && level == 1) + if (area->topology && level == IS_LEVEL_1) { if (tlv_data.is_neighs == NULL) { @@ -1177,7 +1310,6 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) (ipv4->prefix.s_addr)); listnode_add (tlv_data.ipv4_int_reachs, ipreach); } - tlv_data.ipv4_int_reachs->del = free_tlv; } if (area->newmetric) { @@ -1205,6 +1337,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) } } } + #ifdef HAVE_IPV6 /* * Add IPv6 reachability of this circuit @@ -1243,7 +1376,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) switch (circuit->circ_type) { case CIRCUIT_T_BROADCAST: - if (level & circuit->circuit_is_type) + if (level & circuit->is_type) { if (area->oldmetric) { @@ -1253,20 +1386,21 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); - if (level == 1) + if (level == IS_LEVEL_1) memcpy (is_neigh->neigh_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); is_neigh->metrics = circuit->metrics[level - 1]; - listnode_add (tlv_data.is_neighs, is_neigh); - tlv_data.is_neighs->del = free_tlv; + if (!memcmp (is_neigh->neigh_id, zero_id, + ISIS_SYS_ID_LEN + 1)) + XFREE (MTYPE_ISIS_TLV, is_neigh); + else + listnode_add (tlv_data.is_neighs, is_neigh); } if (area->newmetric) { - uint32_t metric; - if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); @@ -1274,21 +1408,22 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); - if (level == 1) + if (level == IS_LEVEL_1) memcpy (te_is_neigh->neigh_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (te_is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); if (area->oldmetric) - metric = - ((htonl(circuit->metrics[level - 1].metric_default) >> 8) - & 0xffffff); + metric = circuit->metrics[level - 1].metric_default; else - metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff); - - memcpy (te_is_neigh->te_metric, &metric, 3); - listnode_add (tlv_data.te_is_neighs, te_is_neigh); + metric = circuit->te_metric[level - 1]; + SET_TE_METRIC(te_is_neigh, metric); + if (!memcmp (te_is_neigh->neigh_id, zero_id, + ISIS_SYS_ID_LEN + 1)) + XFREE (MTYPE_ISIS_TLV, te_is_neigh); + else + listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } break; @@ -1320,21 +1455,14 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); - metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff); - memcpy (te_is_neigh->te_metric, &metric, 3); + metric = circuit->te_metric[level - 1]; + SET_TE_METRIC(te_is_neigh, metric); listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } break; - case CIRCUIT_T_STATIC_IN: - zlog_warn ("lsp_area_create: unsupported circuit type"); - break; - case CIRCUIT_T_STATIC_OUT: - zlog_warn ("lsp_area_create: unsupported circuit type"); - break; - case CIRCUIT_T_DA: - zlog_warn ("lsp_area_create: unsupported circuit type"); - break; + case CIRCUIT_T_LOOPBACK: + break; default: zlog_warn ("lsp_area_create: unknown circuit type"); } @@ -1352,6 +1480,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } + /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit() * for now. lsp_tlv_fit() needs to be fixed to deal with variable length * TLVs (sub TLVs!). */ @@ -1361,7 +1490,8 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) lsp->tlv_data.te_ipv4_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs, - 9, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs); + TE_IPV4_REACH_LEN, area->lsp_frag_threshold, + tlv_add_te_ipv4_reachs); if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); @@ -1406,87 +1536,99 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); free_tlvs (&tlv_data); + + /* Validate the LSP */ + retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) + + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, + stream_get_endp (lsp->pdu) - + ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, + &expected, &found, &tlv_data, NULL); + assert (retval == ISIS_OK); + return; } /* - * 7.3.7 Generation on non-pseudonode LSPs + * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs */ -static int -lsp_generate_non_pseudo (struct isis_area *area, int level) +int +lsp_generate (struct isis_area *area, int level) { struct isis_lsp *oldlsp, *newlsp; u_int32_t seq_num = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; + u_int16_t rem_lifetime, refresh_time; + + if ((area == NULL) || (area->is_type & level) != level) + return ISIS_ERROR; memset (&lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN); /* only builds the lsp if the area shares the level */ - if ((area->is_type & level) == level) - { - oldlsp = lsp_search (lspid, area->lspdb[level - 1]); - if (oldlsp) - { - seq_num = ntohl (oldlsp->lsp_header->seq_num); - lsp_search_and_destroy (oldlsp->lsp_header->lsp_id, - area->lspdb[level - 1]); - /* FIXME: we should actually initiate a purge */ - } - newlsp = lsp_new (lspid, area->max_lsp_lifetime[level - 1], seq_num, - area->is_type, 0, level); - newlsp->own_lsp = 1; + oldlsp = lsp_search (lspid, area->lspdb[level - 1]); + if (oldlsp) + { + /* FIXME: we should actually initiate a purge */ + seq_num = ntohl (oldlsp->lsp_header->seq_num); + lsp_search_and_destroy (oldlsp->lsp_header->lsp_id, + area->lspdb[level - 1]); + } + rem_lifetime = lsp_rem_lifetime (area, level); + newlsp = lsp_new (lspid, rem_lifetime, seq_num, + area->is_type | area->overload_bit, 0, level); + newlsp->area = area; + newlsp->own_lsp = 1; + + lsp_insert (newlsp, area->lspdb[level - 1]); + /* build_lsp_data (newlsp, area); */ + lsp_build (newlsp, area); + /* time to calculate our checksum */ + lsp_seqnum_update (newlsp); + lsp_set_all_srmflags (newlsp); + + refresh_time = lsp_refresh_time (newlsp, rem_lifetime); + THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); + if (level == IS_LEVEL_1) + THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], + lsp_l1_refresh, area, refresh_time); + else if (level == IS_LEVEL_2) + THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], + lsp_l2_refresh, area, refresh_time); - lsp_insert (newlsp, area->lspdb[level - 1]); - /* build_lsp_data (newlsp, area); */ - lsp_build_nonpseudo (newlsp, area); - /* time to calculate our checksum */ - lsp_seqnum_update (newlsp); - } - - /* DEBUG_ADJ_PACKETS */ - if (isis->debugs & DEBUG_ADJ_PACKETS) + if (isis->debugs & DEBUG_UPDATE_PACKETS) { - /* FIXME: is this place right? fix missing info */ - zlog_debug ("ISIS-Upd (%s): Building L%d LSP", area->area_tag, level); + zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, " + "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", + area->area_tag, level, + rawlspid_print (newlsp->lsp_header->lsp_id), + ntohl (newlsp->lsp_header->pdu_len), + ntohl (newlsp->lsp_header->seq_num), + ntohs (newlsp->lsp_header->checksum), + ntohs (newlsp->lsp_header->rem_lifetime), + refresh_time); } return ISIS_OK; } /* - * 7.3.9 Generation of level 1 LSPs (non-pseudonode) - */ -int -lsp_l1_generate (struct isis_area *area) -{ - THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area, - MAX_LSP_GEN_INTERVAL); - - return lsp_generate_non_pseudo (area, 1); -} - -/* - * 7.3.9 Generation of level 2 LSPs (non-pseudonode) + * Search own LSPs, update holding time and set SRM */ -int -lsp_l2_generate (struct isis_area *area) -{ - THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area, - MAX_LSP_GEN_INTERVAL); - - return lsp_generate_non_pseudo (area, 2); -} - static int -lsp_non_pseudo_regenerate (struct isis_area *area, int level) +lsp_regenerate (struct isis_area *area, int level) { dict_t *lspdb = area->lspdb[level - 1]; struct isis_lsp *lsp, *frag; struct listnode *node; u_char lspid[ISIS_SYS_ID_LEN + 2]; + u_int16_t rem_lifetime, refresh_time; + + if ((area == NULL) || (area->is_type & level) != level) + return ISIS_ERROR; memset (lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); @@ -1495,180 +1637,147 @@ lsp_non_pseudo_regenerate (struct isis_area *area, int level) if (!lsp) { - zlog_err - ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!", - area->area_tag, level); - + zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!", + area->area_tag, level); return ISIS_ERROR; } lsp_clear_data (lsp); - lsp_build_nonpseudo (lsp, area); - lsp->lsp_header->rem_lifetime = htons (isis_jitter - (area->max_lsp_lifetime[level - 1], - MAX_AGE_JITTER)); + lsp_build (lsp, area); + lsp->lsp_header->lsp_bits = area->is_type | area->overload_bit; + rem_lifetime = lsp_rem_lifetime (area, level); + lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_seqnum_update (lsp); - if (isis->debugs & DEBUG_UPDATE_PACKETS) + lsp->last_generated = time (NULL); + lsp_set_all_srmflags (lsp); + for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag)) { - zlog_debug ("ISIS-Upd (%s): refreshing our L%d LSP %s, " - "seq 0x%08x, cksum 0x%04x lifetime %us", - area->area_tag, - level, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime)); + frag->lsp_header->lsp_bits = area->is_type | area->overload_bit; + /* Set the lifetime values of all the fragments to the same value, + * so that no fragment expires before the lsp is refreshed. + */ + frag->lsp_header->rem_lifetime = htons (rem_lifetime); + lsp_set_all_srmflags (frag); } - lsp->last_generated = time (NULL); - area->lsp_regenerate_pending[level - 1] = 0; - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag)) + refresh_time = lsp_refresh_time (lsp, rem_lifetime); + if (level == IS_LEVEL_1) + THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], + lsp_l1_refresh, area, refresh_time); + else if (level == IS_LEVEL_2) + THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], + lsp_l2_refresh, area, refresh_time); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { - frag->lsp_header->rem_lifetime = htons (isis_jitter - (area-> - max_lsp_lifetime[level - 1], - MAX_AGE_JITTER)); - ISIS_FLAGS_SET_ALL (frag->SRMflags); + zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, " + "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", + area->area_tag, level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->pdu_len), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + refresh_time); } - if (area->ip_circuits) - isis_spf_schedule (area, level); -#ifdef HAVE_IPV6 - if (area->ipv6_circuits) - isis_spf_schedule6 (area, level); -#endif return ISIS_OK; } /* - * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding - * time and set SRM + * Something has changed or periodic refresh -> regenerate LSP */ -int -lsp_refresh_l1 (struct thread *thread) +static int +lsp_l1_refresh (struct thread *thread) { struct isis_area *area; - unsigned long ref_time; area = THREAD_ARG (thread); assert (area); area->t_lsp_refresh[0] = NULL; - if (area->is_type & IS_LEVEL_1) - lsp_non_pseudo_regenerate (area, 1); - - ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0]; + area->lsp_regenerate_pending[0] = 0; - THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area, - isis_jitter (ref_time, MAX_AGE_JITTER)); + if ((area->is_type & IS_LEVEL_1) == 0) + return ISIS_ERROR; - return ISIS_OK; + return lsp_regenerate (area, IS_LEVEL_1); } -int -lsp_refresh_l2 (struct thread *thread) +static int +lsp_l2_refresh (struct thread *thread) { struct isis_area *area; - unsigned long ref_time; area = THREAD_ARG (thread); assert (area); area->t_lsp_refresh[1] = NULL; - if (area->is_type & IS_LEVEL_2) - lsp_non_pseudo_regenerate (area, 2); - - ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1]; - - THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area, - isis_jitter (ref_time, MAX_AGE_JITTER)); - - return ISIS_OK; -} - -/* - * Something has changed -> regenerate LSP - */ - -static int -lsp_l1_regenerate (struct thread *thread) -{ - struct isis_area *area; - - area = THREAD_ARG (thread); - area->lsp_regenerate_pending[0] = 0; - - return lsp_non_pseudo_regenerate (area, 1); -} - -static int -lsp_l2_regenerate (struct thread *thread) -{ - struct isis_area *area; - - area = THREAD_ARG (thread); area->lsp_regenerate_pending[1] = 0; - return lsp_non_pseudo_regenerate (area, 2); + if ((area->is_type & IS_LEVEL_2) == 0) + return ISIS_ERROR; + + return lsp_regenerate (area, IS_LEVEL_2); } int -lsp_regenerate_schedule (struct isis_area *area) +lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) { struct isis_lsp *lsp; u_char id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; + struct listnode *cnode; + struct isis_circuit *circuit; + int lvl; + + if (area == NULL) + return ISIS_ERROR; + memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0; now = time (NULL); - /* - * First level 1 - */ - if (area->is_type & IS_LEVEL_1) + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { - lsp = lsp_search (id, area->lspdb[0]); - if (!lsp || area->lsp_regenerate_pending[0]) - goto L2; + if (!((level & lvl) && (area->is_type & lvl))) + continue; + + if (area->lsp_regenerate_pending[lvl - 1]) + continue; + + lsp = lsp_search (id, area->lspdb[lvl - 1]); + if (!lsp) + continue; + /* * Throttle avoidance */ + THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]); diff = now - lsp->last_generated; - if (diff < MIN_LSP_GEN_INTERVAL) - { - area->lsp_regenerate_pending[0] = 1; - thread_add_timer (master, lsp_l1_regenerate, area, - MIN_LSP_GEN_INTERVAL - diff); - goto L2; - } + if (diff < area->lsp_gen_interval[lvl - 1]) + { + area->lsp_regenerate_pending[lvl - 1] = 1; + if (lvl == IS_LEVEL_1) + THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], + lsp_l1_refresh, area, + area->lsp_gen_interval[lvl - 1] - diff); + else if (lvl == IS_LEVEL_2) + THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], + lsp_l2_refresh, area, + area->lsp_gen_interval[lvl - 1] - diff); + } else - lsp_non_pseudo_regenerate (area, 1); + { + lsp_regenerate (area, lvl); + } } - /* - * then 2 - */ -L2: - if (area->is_type & IS_LEVEL_2) + + if (all_pseudo) { - lsp = lsp_search (id, area->lspdb[1]); - if (!lsp || area->lsp_regenerate_pending[1]) - return ISIS_OK; - /* - * Throttle avoidance - */ - diff = now - lsp->last_generated; - if (diff < MIN_LSP_GEN_INTERVAL) - { - area->lsp_regenerate_pending[1] = 1; - thread_add_timer (master, lsp_l2_regenerate, area, - MIN_LSP_GEN_INTERVAL - diff); - return ISIS_OK; - } - else - lsp_non_pseudo_regenerate (area, 2); + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) + lsp_regenerate_schedule_pseudo (circuit, level); } return ISIS_OK; @@ -1691,16 +1800,10 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, struct es_neigh *es_neigh; struct list *adj_list; struct listnode *node; - struct isis_passwd *passwd; - - assert (circuit); - assert (circuit->circ_type == CIRCUIT_T_BROADCAST); - - if (!circuit->u.bc.is_dr[level - 1]) - return; /* we are not DIS on this circuit */ lsp->level = level; - if (level == 1) + /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ + if (level == IS_LEVEL_1) lsp->lsp_header->lsp_bits |= IS_LEVEL_1; else lsp->lsp_header->lsp_bits |= IS_LEVEL_2; @@ -1738,12 +1841,12 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj)) { - if (adj->circuit_t & level) + if (adj->level & level) { - if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) || - (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS && + if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) || + (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS && adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || - (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) + (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) { /* an IS neighbour -> add it */ if (circuit->area->oldmetric) @@ -1761,7 +1864,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); } } - else if (level == 1 && adj->sys_type == ISIS_SYSTYPE_ES) + else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES) { /* an ES neigbour add it, if we are building level 1 LSP */ /* FIXME: the tlv-format is hard to use here */ @@ -1777,6 +1880,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, } } } + list_delete (adj_list); /* Reset endp of stream to overwrite only TLV part of it. */ stream_reset (lsp->pdu); @@ -1785,13 +1889,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, /* * Add the authentication info if it's present */ - (level == 1) ? (passwd = &circuit->area->area_passwd) : - (passwd = &circuit->area->domain_passwd); - if (passwd->type) - { - memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); - tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); - } + lsp_auth_add (lsp); if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0) tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu); @@ -1803,20 +1901,89 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu); lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); - fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, - ntohs (lsp->lsp_header->pdu_len) - 12, 12); - list_delete (adj_list); + /* Recompute authentication and checksum information */ + lsp_auth_update (lsp); + fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, + ntohs (lsp->lsp_header->pdu_len) - 12, 12); return; } +int +lsp_generate_pseudo (struct isis_circuit *circuit, int level) +{ + dict_t *lspdb = circuit->area->lspdb[level - 1]; + struct isis_lsp *lsp; + u_char lsp_id[ISIS_SYS_ID_LEN + 2]; + u_int16_t rem_lifetime, refresh_time; + + if ((circuit->is_type & level) != level || + (circuit->state != C_STATE_UP) || + (circuit->circ_type != CIRCUIT_T_BROADCAST) || + (circuit->u.bc.is_dr[level - 1] == 0)) + return ISIS_ERROR; + + memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_FRAGMENT (lsp_id) = 0; + LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; + + /* + * If for some reason have a pseudo LSP in the db already -> regenerate + */ + if (lsp_search (lsp_id, lspdb)) + return lsp_regenerate_schedule_pseudo (circuit, level); + + rem_lifetime = lsp_rem_lifetime (circuit->area, level); + /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ + lsp = lsp_new (lsp_id, rem_lifetime, 1, circuit->area->is_type, 0, level); + lsp->area = circuit->area; + + lsp_build_pseudo (lsp, circuit, level); + + lsp->own_lsp = 1; + lsp_insert (lsp, lspdb); + lsp_set_all_srmflags (lsp); + + refresh_time = lsp_refresh_time (lsp, rem_lifetime); + THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); + circuit->lsp_regenerate_pending[level - 1] = 0; + if (level == IS_LEVEL_1) + THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], + lsp_l1_refresh_pseudo, circuit, refresh_time); + else if (level == IS_LEVEL_2) + THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], + lsp_l2_refresh_pseudo, circuit, refresh_time); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) + { + zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, " + "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", + circuit->area->area_tag, level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->pdu_len), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + refresh_time); + } + + return ISIS_OK; +} + static int -lsp_pseudo_regenerate (struct isis_circuit *circuit, int level) +lsp_regenerate_pseudo (struct isis_circuit *circuit, int level) { dict_t *lspdb = circuit->area->lspdb[level - 1]; struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; + u_int16_t rem_lifetime, refresh_time; + + if ((circuit->is_type & level) != level || + (circuit->state != C_STATE_UP) || + (circuit->circ_type != CIRCUIT_T_BROADCAST) || + (circuit->u.bc.is_dr[level - 1] == 0)) + return ISIS_ERROR; memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; @@ -1826,151 +1993,154 @@ lsp_pseudo_regenerate (struct isis_circuit *circuit, int level) if (!lsp) { - zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level, - rawlspid_print (lsp_id)); + zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!", + level, rawlspid_print (lsp_id)); return ISIS_ERROR; } lsp_clear_data (lsp); lsp_build_pseudo (lsp, circuit, level); - lsp->lsp_header->rem_lifetime = - htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1], - MAX_AGE_JITTER)); - + /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ + lsp->lsp_header->lsp_bits = circuit->area->is_type; + rem_lifetime = lsp_rem_lifetime (circuit->area, level); + lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_inc_seqnum (lsp, 0); + lsp->last_generated = time (NULL); + lsp_set_all_srmflags (lsp); + + refresh_time = lsp_refresh_time (lsp, rem_lifetime); + if (level == IS_LEVEL_1) + THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], + lsp_l1_refresh_pseudo, circuit, refresh_time); + else if (level == IS_LEVEL_2) + THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], + lsp_l2_refresh_pseudo, circuit, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { - zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s", - circuit->area->area_tag, level, - rawlspid_print (lsp->lsp_header->lsp_id)); + zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, " + "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", + circuit->area->area_tag, level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->pdu_len), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + refresh_time); } - lsp->last_generated = time (NULL); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - return ISIS_OK; } -int +/* + * Something has changed or periodic refresh -> regenerate pseudo LSP + */ +static int lsp_l1_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; - int retval; - unsigned long ref_time; + u_char id[ISIS_SYS_ID_LEN + 2]; circuit = THREAD_ARG (thread); - if (!circuit->u.bc.is_dr[0]) - return ISIS_ERROR; /* FIXME: purge and such */ - circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL; + circuit->lsp_regenerate_pending[0] = 0; - retval = lsp_pseudo_regenerate (circuit, 1); - - ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0]; - - THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0], - lsp_l1_refresh_pseudo, circuit, - isis_jitter (ref_time, MAX_AGE_JITTER)); - - return retval; -} - -int -lsp_l1_pseudo_generate (struct isis_circuit *circuit) -{ - struct isis_lsp *lsp; - u_char id[ISIS_SYS_ID_LEN + 2]; - unsigned long ref_time; - - memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); - LSP_FRAGMENT (id) = 0; - LSP_PSEUDO_ID (id) = circuit->circuit_id; - - /* - * If for some reason have a pseudo LSP in the db already -> regenerate - */ - if (lsp_search (id, circuit->area->lspdb[0])) - return lsp_pseudo_regenerate (circuit, 1); - lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0], - 1, circuit->area->is_type, 0, 1); - - lsp_build_pseudo (lsp, circuit, 1); - - lsp->own_lsp = 1; - lsp_insert (lsp, circuit->area->lspdb[0]); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - - ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0]; - - THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0], - lsp_l1_refresh_pseudo, circuit, - isis_jitter (ref_time, MAX_AGE_JITTER)); + if ((circuit->u.bc.is_dr[0] == 0) || + (circuit->is_type & IS_LEVEL_1) == 0) + { + memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (id) = circuit->circuit_id; + LSP_FRAGMENT (id) = 0; + lsp_purge_pseudo (id, circuit, IS_LEVEL_1); + return ISIS_ERROR; + } - return lsp_regenerate_schedule (circuit->area); + return lsp_regenerate_pseudo (circuit, IS_LEVEL_1); } -int +static int lsp_l2_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; - int retval; - unsigned long ref_time; - circuit = THREAD_ARG (thread); + u_char id[ISIS_SYS_ID_LEN + 2]; - if (!circuit->u.bc.is_dr[1]) - return ISIS_ERROR; /* FIXME: purge and such */ + circuit = THREAD_ARG (thread); circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL; + circuit->lsp_regenerate_pending[1] = 0; - retval = lsp_pseudo_regenerate (circuit, 2); - - ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1]; - - THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1], - lsp_l2_refresh_pseudo, circuit, - isis_jitter (ref_time, MAX_AGE_JITTER)); + if ((circuit->u.bc.is_dr[1] == 0) || + (circuit->is_type & IS_LEVEL_2) == 0) + { + memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (id) = circuit->circuit_id; + LSP_FRAGMENT (id) = 0; + lsp_purge_pseudo (id, circuit, IS_LEVEL_2); + return ISIS_ERROR; + } - return retval; + return lsp_regenerate_pseudo (circuit, IS_LEVEL_2); } int -lsp_l2_pseudo_generate (struct isis_circuit *circuit) +lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; - u_char id[ISIS_SYS_ID_LEN + 2]; - unsigned long ref_time; - - memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); - LSP_FRAGMENT (id) = 0; - LSP_PSEUDO_ID (id) = circuit->circuit_id; - - if (lsp_search (id, circuit->area->lspdb[1])) - return lsp_pseudo_regenerate (circuit, 2); + u_char lsp_id[ISIS_SYS_ID_LEN + 2]; + time_t now, diff; + int lvl; - lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1], - 1, circuit->area->is_type, 0, 2); + if (circuit == NULL || + circuit->circ_type != CIRCUIT_T_BROADCAST || + circuit->state != C_STATE_UP) + return ISIS_OK; - lsp_build_pseudo (lsp, circuit, 2); + memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; + LSP_FRAGMENT (lsp_id) = 0; + now = time (NULL); - ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1]; + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + { + if (!((level & lvl) && (circuit->is_type & lvl))) + continue; + if (circuit->u.bc.is_dr[lvl - 1] == 0 || + circuit->lsp_regenerate_pending[lvl - 1]) + continue; - lsp->own_lsp = 1; - lsp_insert (lsp, circuit->area->lspdb[1]); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]); + if (!lsp) + continue; - THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1], - lsp_l2_refresh_pseudo, circuit, - isis_jitter (ref_time, MAX_AGE_JITTER)); + /* + * Throttle avoidance + */ + THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]); + diff = now - lsp->last_generated; + if (diff < circuit->area->lsp_gen_interval[lvl - 1]) + { + circuit->lsp_regenerate_pending[lvl - 1] = 1; + if (lvl == IS_LEVEL_1) + THREAD_TIMER_ON (master, + circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], + lsp_l1_refresh_pseudo, circuit, + circuit->area->lsp_gen_interval[lvl - 1] - diff); + else if (lvl == IS_LEVEL_2) + THREAD_TIMER_ON (master, + circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], + lsp_l2_refresh_pseudo, circuit, + circuit->area->lsp_gen_interval[lvl - 1] - diff); + } + else + { + lsp_regenerate_pseudo (circuit, lvl); + } + } - return lsp_regenerate_schedule (circuit->area); + return ISIS_OK; } /* @@ -1988,6 +2158,7 @@ lsp_tick (struct thread *thread) struct listnode *lspnode, *cnode; dnode_t *dnode, *dnode_next; int level; + u_int16_t rem_lifetime; lsp_list = list_new (); @@ -2003,54 +2174,87 @@ lsp_tick (struct thread *thread) for (level = 0; level < ISIS_LEVELS; level++) { if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) - { - dnode = dict_first (area->lspdb[level]); - while (dnode != NULL) - { - dnode_next = dict_next (area->lspdb[level], dnode); - lsp = dnode_get (dnode); - lsp_set_time (lsp); - if (lsp->age_out == 0) - { - - zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out", - area->area_tag, - lsp->level, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num)); + { + for (dnode = dict_first (area->lspdb[level]); + dnode != NULL; dnode = dnode_next) + { + dnode_next = dict_next (area->lspdb[level], dnode); + lsp = dnode_get (dnode); + + /* + * The lsp rem_lifetime is kept at 0 for MaxAge or + * ZeroAgeLifetime depending on explicit purge or + * natural age out. So schedule spf only once when + * the first time rem_lifetime becomes 0. + */ + rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime); + lsp_set_time (lsp); + + /* + * Schedule may run spf which should be done only after + * the lsp rem_lifetime becomes 0 for the first time. + * ISO 10589 - 7.3.16.4 first paragraph. + */ + if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0) + { + /* 7.3.16.4 a) set SRM flags on all */ + lsp_set_all_srmflags (lsp); + /* 7.3.16.4 b) retain only the header FIXME */ + /* 7.3.16.4 c) record the time to purge FIXME */ + /* run/schedule spf */ + /* isis_spf_schedule is called inside lsp_destroy() below; + * so it is not needed here. */ + /* isis_spf_schedule (lsp->area, lsp->level); */ + } + + if (lsp->age_out == 0) + { + zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out", + area->area_tag, + lsp->level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num)); #ifdef TOPOLOGY_GENERATE - if (lsp->from_topology) - THREAD_TIMER_OFF (lsp->t_lsp_top_ref); + if (lsp->from_topology) + THREAD_TIMER_OFF (lsp->t_lsp_top_ref); #endif /* TOPOLOGY_GENERATE */ - lsp_destroy (lsp); - dict_delete (area->lspdb[level], dnode); - } - else if (flags_any_set (lsp->SRMflags)) - listnode_add (lsp_list, lsp); - dnode = dnode_next; - } - - /* - * Send LSPs on circuits indicated by the SRMflags - */ - if (listcount (lsp_list) > 0) - { + lsp_destroy (lsp); + lsp = NULL; + dict_delete_free (area->lspdb[level], dnode); + } + else if (flags_any_set (lsp->SRMflags)) + listnode_add (lsp_list, lsp); + } + + /* + * Send LSPs on circuits indicated by the SRMflags + */ + if (listcount (lsp_list) > 0) + { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) - { + { + int diff = time (NULL) - circuit->lsp_queue_last_cleared; + if (circuit->lsp_queue == NULL || + diff < MIN_LSP_TRANS_INTERVAL) + continue; for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp)) - { - if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) - { - /* FIXME: if same or elder lsp is already in lsp - * queue */ - listnode_add (circuit->lsp_queue, lsp); - thread_add_event (master, send_lsp, circuit, 0); - } - } - } - } - list_delete_all_node (lsp_list); - } + { + if (circuit->upadjcount[lsp->level - 1] && + ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) + { + /* Add the lsp only if it is not already in lsp + * queue */ + if (! listnode_lookup (circuit->lsp_queue, lsp)) + { + listnode_add (circuit->lsp_queue, lsp); + thread_add_event (master, send_lsp, circuit, 0); + } + } + } + } + list_delete_all_node (lsp_list); + } + } } list_delete (lsp_list); @@ -2059,22 +2263,45 @@ lsp_tick (struct thread *thread) } void -lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level) +lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; + u_int16_t seq_num; + u_int8_t lsp_bits; lsp = lsp_search (id, circuit->area->lspdb[level - 1]); + if (!lsp) + return; - if (lsp && lsp->purged == 0) - { - lsp->lsp_header->rem_lifetime = htons (0); - lsp->lsp_header->pdu_len = - htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - lsp->purged = 0; - fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, - ntohs (lsp->lsp_header->pdu_len) - 12, 12); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - } + /* store old values */ + seq_num = lsp->lsp_header->seq_num; + lsp_bits = lsp->lsp_header->lsp_bits; + + /* reset stream */ + lsp_clear_data (lsp); + stream_reset (lsp->pdu); + + /* update header */ + lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2); + lsp->lsp_header->checksum = 0; + lsp->lsp_header->seq_num = seq_num; + lsp->lsp_header->rem_lifetime = 0; + lsp->lsp_header->lsp_bits = lsp_bits; + lsp->level = level; + lsp->age_out = lsp->area->max_lsp_lifetime[level-1]; + stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + + /* + * Add and update the authentication info if its present + */ + lsp_auth_add (lsp); + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); + lsp_auth_update (lsp); + fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, + ntohs (lsp->lsp_header->pdu_len) - 12, 12); + + lsp_set_all_srmflags (lsp); return; } @@ -2092,27 +2319,35 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, /* * We need to create the LSP to be purged */ - zlog_debug ("LSP PURGE NON EXIST"); lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); - /*FIXME: BUG BUG BUG! the lsp doesn't exist here! */ - /*did smt here, maybe good probably not */ + lsp->area = area; lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2; - lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + /* FIXME: Should be minimal mtu? */ + lsp->pdu = stream_new (1500); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); - fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE + fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); + stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - /* - * Retain only LSP header - */ - lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Set the remaining lifetime to 0 */ lsp->lsp_header->rem_lifetime = 0; + + /* + * Add and update the authentication info if its present + */ + lsp_auth_add (lsp); + lsp_auth_update (lsp); + + /* + * Update the PDU length to header plus any authentication TLV. + */ + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); + /* * Put the lsp into LSPdb */ @@ -2121,17 +2356,36 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, /* * Send in to whole area */ - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_set_all_srmflags (lsp); return; } +void lsp_set_all_srmflags (struct isis_lsp *lsp) +{ + struct listnode *node; + struct isis_circuit *circuit; + + assert (lsp); + + ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags); + + if (lsp->area) + { + struct list *circuit_list = lsp->area->circuit_list; + for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit)) + { + ISIS_SET_FLAG(lsp->SRMflags, circuit); + } + } +} + #ifdef TOPOLOGY_GENERATE static int top_lsp_refresh (struct thread *thread) { struct isis_lsp *lsp; - unsigned long ref_time; + u_int16_t rem_lifetime, refresh_time; lsp = THREAD_ARG (thread); assert (lsp); @@ -2140,7 +2394,7 @@ top_lsp_refresh (struct thread *thread) lsp_seqnum_update (lsp); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_set_all_srmflags (lsp); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s", @@ -2150,14 +2404,13 @@ top_lsp_refresh (struct thread *thread) isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, IS_LEVEL_1); - lsp->lsp_header->rem_lifetime = - htons (isis_jitter (lsp->area->max_lsp_lifetime[0], MAX_AGE_JITTER)); - - ref_time = lsp->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : lsp->area->lsp_refresh[0]; + lsp->lsp_header->lsp_bits = lsp->area->is_type | lsp->area->overload_bit; + rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); + lsp->lsp_header->rem_lifetime = htons (rem_lifetime); + refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, - isis_jitter (ref_time, MAX_LSP_GEN_JITTER)); + lsp->area->lsp_refresh[0]); return ISIS_OK; } @@ -2170,16 +2423,16 @@ generate_topology_lsps (struct isis_area *area) struct arc *arc; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; - unsigned long ref_time; + u_int16_t rem_lifetime, refresh_time; /* first we find the maximal node */ for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc)) - { - if (arc->from_node > max) - max = arc->from_node; - if (arc->to_node > max) - max = arc->to_node; - } + { + if (arc->from_node > max) + max = arc->from_node; + if (arc->to_node > max) + max = arc->to_node; + } for (i = 1; i < (max + 1); i++) { @@ -2189,12 +2442,13 @@ generate_topology_lsps (struct isis_area *area) lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF); lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF); - lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0], - MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1); + rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1); + lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit, + 0, 1); if (!lsp) return; - lsp->from_topology = 1; lsp->area = area; + lsp->from_topology = 1; /* Creating LSP data based on topology info. */ build_topology_lsp_data (lsp, area, i); @@ -2203,12 +2457,10 @@ generate_topology_lsps (struct isis_area *area) /* Take care of inserting dynamic hostname into cache. */ isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1); - ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? - MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0]; - + refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, - isis_jitter (ref_time, MAX_LSP_GEN_JITTER)); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + refresh_time); + lsp_set_all_srmflags (lsp); lsp_insert (lsp, area->lspdb[0]); } } @@ -2325,8 +2577,6 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area, if (area->newmetric) { - uint32_t metric; - if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); @@ -2337,8 +2587,7 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area, ISIS_SYS_ID_LEN); te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF); te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF); - metric = ((htonl(arc->distance) >> 8) & 0xffffff); - memcpy (te_is_neigh->te_metric, &metric, 3); + SET_TE_METRIC(te_is_neigh, arc->distance); listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index adbde78ef..6e7f745d2 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -24,10 +24,6 @@ #ifndef _ZEBRA_ISIS_LSP_H #define _ZEBRA_ISIS_LSP_H -/* The grand plan is to support 1024 circuits so we have 32*32 bit flags - * the support will be achived using the newest drafts */ -#define ISIS_MAX_CIRCUITS 32 /* = 1024 - FIXME:defined in flags.h as well */ - /* Structure for isis_lsp, this structure will only support the fixed * System ID (Currently 6) (atleast for now). In order to support more * We will have to split the header into two parts, and for readability @@ -42,15 +38,13 @@ struct isis_lsp struct list *frags; struct isis_lsp *zero_lsp; } lspu; + u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */ u_int32_t SRMflags[ISIS_MAX_CIRCUITS]; u_int32_t SSNflags[ISIS_MAX_CIRCUITS]; - u_int32_t rexmit_queue[ISIS_MAX_CIRCUITS]; int level; /* L1 or L2? */ - int purged; /* have purged this one */ int scheduled; /* scheduled for sending */ time_t installed; time_t last_generated; - time_t last_sent; int own_lsp; #ifdef TOPOLOGY_GENERATE int from_topology; @@ -58,8 +52,6 @@ struct isis_lsp #endif /* used for 60 second counting when rem_lifetime is zero */ int age_out; - struct isis_adjacency *adj; - /* FIXME: For now only topology LSP's use this. Is it helpful for others? */ struct isis_area *area; struct tlvs tlv_data; /* Simplifies TLV access */ }; @@ -68,37 +60,32 @@ dict_t *lsp_db_init (void); void lsp_db_destroy (dict_t * lspdb); int lsp_tick (struct thread *thread); -int lsp_l1_generate (struct isis_area *area); -int lsp_l2_generate (struct isis_area *area); -int lsp_refresh_l1 (struct thread *thread); -int lsp_refresh_l2 (struct thread *thread); -int lsp_regenerate_schedule (struct isis_area *area); +int lsp_generate (struct isis_area *area, int level); +int lsp_regenerate_schedule (struct isis_area *area, int level, + int all_pseudo); +int lsp_generate_pseudo (struct isis_circuit *circuit, int level); +int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level); -int lsp_l1_pseudo_generate (struct isis_circuit *circuit); -int lsp_l2_pseudo_generate (struct isis_circuit *circuit); -int lsp_l1_refresh_pseudo (struct thread *thread); -int lsp_l2_refresh_pseudo (struct thread *thread); -int isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area, - int pdulen, struct isis_passwd *passwd); struct isis_lsp *lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, u_int8_t lsp_bits, u_int16_t checksum, int level); struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream, u_int16_t pdu_len, struct isis_lsp *lsp0, - struct isis_area *area); + struct isis_area *area, + int level); void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb); struct isis_lsp *lsp_search (u_char * id, dict_t * lspdb); -void lsp_build_list (u_char * start_id, u_char * stop_id, +void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps, struct list *list, dict_t * lspdb); void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id, struct list *list, dict_t * lspdb); -void lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list, - dict_t * lspdb); +void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, + struct list *list, dict_t * lspdb); void lsp_search_and_destroy (u_char * id, dict_t * lspdb); -void lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level); +void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level); void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, struct isis_area *area); @@ -115,13 +102,18 @@ void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, int lsp_id_cmp (u_char * id1, u_char * id2); int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, u_int16_t checksum, u_int16_t rem_lifetime); -void lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr, - struct stream *stream, struct isis_area *area, int level); +void lsp_update (struct isis_lsp *lsp, struct stream *stream, + struct isis_area *area, int level); void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num); +void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost); +void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost); int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost); const char *lsp_bits2string (u_char *); +/* sets SRMflags for all active circuits of an lsp */ +void lsp_set_all_srmflags (struct isis_lsp *lsp); + #ifdef TOPOLOGY_GENERATE void generate_topology_lsps (struct isis_area *area); void remove_topology_lsps (struct isis_area *area); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index c5e824c19..7bb84d8fc 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -43,6 +43,9 @@ #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_route.h" +#include "isisd/isis_zebra.h" /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" @@ -66,7 +69,7 @@ struct zebra_privs_t isisd_privs = { .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = 2, + .cap_num_p = sizeof (_caps_p) / sizeof (*_caps_p), .cap_num_i = 0 }; @@ -151,7 +154,10 @@ reload () zlog_debug ("Reload"); /* FIXME: Clean up func call here */ vty_reset (); + (void) isisd_privs.change (ZPRIVS_RAISE); execve (_progpath, _argv, _envp); + zlog_err ("Reload failed: cannot exec %s: %s", _progpath, + safe_strerror (errno)); } static void @@ -319,28 +325,31 @@ main (int argc, char **argv, char **envp) memory_init (); access_list_init(); isis_init (); - dyn_cache_init (); + isis_circuit_init (); + isis_spf_cmds_init (); + + /* create the global 'isis' instance */ + isis_new (1); + + isis_zebra_init (); + sort_node (); /* parse config file */ /* this is needed three times! because we have interfaces before the areas */ vty_read_config (config_file, config_default); - vty_read_config (config_file, config_default); - vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); /* demonize */ - if (daemon_mode && daemon (0, 0) < 0) - { - zlog_err("ISISd daemon failed: %s", strerror(errno)); - exit (1); - } + if (daemon_mode) + daemon (0, 0); /* Process ID file creation. */ - pid_output (pid_file); + if (pid_file[0] != '\0') + pid_output (pid_file); /* Make isis vty socket. */ vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH); diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 6b565bcbe..968fa05fe 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -32,7 +32,9 @@ #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" +#include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_misc.h" @@ -40,6 +42,7 @@ #include "isisd/isis_lsp.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" +#include "isisd/isis_dynhn.h" /* staticly assigned vars for printing purposes */ struct in_addr new_prefix; @@ -99,10 +102,10 @@ isonet_print (u_char * from, int len) * extract dot from the dotted str, and insert all the number in a buff */ int -dotformat2buff (u_char * buff, const u_char * dotted) +dotformat2buff (u_char * buff, const char * dotted) { int dotlen, len = 0; - const u_char *pos = dotted; + const char *pos = dotted; u_char number[3]; int nextdotpos = 2; @@ -157,10 +160,10 @@ dotformat2buff (u_char * buff, const u_char * dotted) * conversion of XXXX.XXXX.XXXX to memory */ int -sysid2buff (u_char * buff, const u_char * dotted) +sysid2buff (u_char * buff, const char * dotted) { int len = 0; - const u_char *pos = dotted; + const char *pos = dotted; u_char number[3]; number[2] = '\0'; @@ -271,7 +274,7 @@ speaks (struct nlpids *nlpids, int family) * Returns 0 on error, IS-IS Circuit Type on ok */ int -string2circuit_t (const u_char * str) +string2circuit_t (const char * str) { if (!str) @@ -289,6 +292,42 @@ string2circuit_t (const u_char * str) return 0; } +const char * +circuit_state2string (int state) +{ + + switch (state) + { + case C_STATE_INIT: + return "Init"; + case C_STATE_CONF: + return "Config"; + case C_STATE_UP: + return "Up"; + default: + return "Unknown"; + } + return NULL; +} + +const char * +circuit_type2string (int type) +{ + + switch (type) + { + case CIRCUIT_T_P2P: + return "p2p"; + case CIRCUIT_T_BROADCAST: + return "lan"; + case CIRCUIT_T_LOOPBACK: + return "loopback"; + default: + return "Unknown"; + } + return NULL; +} + const char * circuit_t2string (int circuit_t) { @@ -498,7 +537,6 @@ unix_hostname (void) { static struct utsname names; const char *hostname; - extern struct host host; hostname = host.name; if (!hostname) @@ -509,3 +547,87 @@ unix_hostname (void) return hostname; } + +/* + * Returns the dynamic hostname associated with the passed system ID. + * If no dynamic hostname found then returns formatted system ID. + */ +const char * +print_sys_hostname (u_char *sysid) +{ + struct isis_dynhn *dyn; + + if (!sysid) + return "nullsysid"; + + /* For our system ID return our host name */ + if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0) + return unix_hostname(); + + dyn = dynhn_find_by_id (sysid); + if (dyn) + return (const char *)dyn->name.name; + + return sysid_print (sysid); +} + +/* + * This function is a generic utility that logs data of given length. + * Move this to a shared lib so that any protocol can use it. + */ +void +zlog_dump_data (void *data, int len) +{ + int i; + unsigned char *p; + unsigned char c; + char bytestr[4]; + char addrstr[10]; + char hexstr[ 16*3 + 5]; + char charstr[16*1 + 5]; + + p = data; + memset (bytestr, 0, sizeof(bytestr)); + memset (addrstr, 0, sizeof(addrstr)); + memset (hexstr, 0, sizeof(hexstr)); + memset (charstr, 0, sizeof(charstr)); + + for (i = 1; i <= len; i++) + { + c = *p; + if (isalnum (c) == 0) + c = '.'; + + /* store address for this line */ + if ((i % 16) == 1) + snprintf (addrstr, sizeof(addrstr), "%p", p); + + /* store hex str (for left side) */ + snprintf (bytestr, sizeof (bytestr), "%02X ", *p); + strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1); + + /* store char str (for right side) */ + snprintf (bytestr, sizeof (bytestr), "%c", c); + strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1); + + if ((i % 16) == 0) + { + /* line completed */ + zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); + hexstr[0] = 0; + charstr[0] = 0; + } + else if ((i % 8) == 0) + { + /* half line: add whitespaces */ + strncat (hexstr, " ", sizeof (hexstr) - strlen (hexstr) - 1); + strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1); + } + p++; /* next byte */ + } + + /* print rest of buffer if not empty */ + if (strlen (hexstr) > 0) + zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); + return; +} diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h index d5003a8e6..0cd65a66a 100644 --- a/isisd/isis_misc.h +++ b/isisd/isis_misc.h @@ -24,8 +24,10 @@ #ifndef _ZEBRA_ISIS_MISC_H #define _ZEBRA_ISIS_MISC_H -int string2circuit_t (const u_char *); +int string2circuit_t (const char *); const char *circuit_t2string (int); +const char *circuit_state2string (int state); +const char *circuit_type2string (int type); const char *syst2string (int); struct in_addr newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen); @@ -33,8 +35,8 @@ struct in_addr newprefix2inaddr (u_char * prefix_start, * Converting input to memory stored format * return value of 0 indicates wrong input */ -int dotformat2buff (u_char *, const u_char *); -int sysid2buff (u_char *, const u_char *); +int dotformat2buff (u_char *, const char *); +int sysid2buff (u_char *, const char *); /* * Printing functions @@ -46,6 +48,8 @@ const char *rawlspid_print (u_char *); const char *time2string (u_int32_t); /* typedef struct nlpids nlpids; */ char *nlpid2string (struct nlpids *); +const char *print_sys_hostname (u_char *sysid); +void zlog_dump_data (void *data, int len); /* * misc functions @@ -57,7 +61,8 @@ const char *unix_hostname (void); /* * macros */ -#define GETSYSID(A,L) (A->area_addr + (A->addr_len - (L + 1))) +#define GETSYSID(A) (A->area_addr + (A->addr_len - \ + (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN))) /* used for calculating nice string representation instead of plain seconds */ diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index a2ab0649d..fe943bbaa 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -29,21 +29,22 @@ #include "log.h" #include "stream.h" #include "vty.h" -#include "hash.c" +#include "hash.h" #include "prefix.h" #include "if.h" #include "checksum.h" +#include "md5.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" -#include "isisd/isis_flags.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" @@ -53,9 +54,6 @@ #include "isisd/isis_csm.h" #include "isisd/isis_events.h" -extern struct thread_master *master; -extern struct isis *isis; - #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ @@ -168,31 +166,151 @@ accept_level (int level, int circuit_t) return retval; } -int -authentication_check (struct isis_passwd *one, struct isis_passwd *theother) +/* + * Verify authentication information + * Support cleartext and HMAC MD5 authentication + */ +static int +authentication_check (struct isis_passwd *remote, struct isis_passwd *local, + struct stream *stream, uint32_t auth_tlv_offset) { - if (one->type != theother->type) + unsigned char digest[ISIS_AUTH_MD5_SIZE]; + + /* Auth fail () - passwd type mismatch */ + if (local->type != remote->type) + return ISIS_ERROR; + + switch (local->type) + { + /* No authentication required */ + case ISIS_PASSWD_TYPE_UNUSED: + break; + + /* Cleartext (ISO 10589) */ + case ISIS_PASSWD_TYPE_CLEARTXT: + /* Auth fail () - passwd len mismatch */ + if (remote->len != local->len) + return ISIS_ERROR; + return memcmp (local->passwd, remote->passwd, local->len); + + /* HMAC MD5 (RFC 3567) */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Auth fail () - passwd len mismatch */ + if (remote->len != ISIS_AUTH_MD5_SIZE) + return ISIS_ERROR; + /* Set the authentication value to 0 before the check */ + memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0, + ISIS_AUTH_MD5_SIZE); + /* Compute the digest */ + hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream), + (unsigned char *) &(local->passwd), local->len, + (caddr_t) &digest); + /* Copy back the authentication value after the check */ + memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3, + remote->passwd, ISIS_AUTH_MD5_SIZE); + return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); + + default: + zlog_err ("Unsupported authentication type"); + return ISIS_ERROR; + } + + /* Authentication pass when no authentication is configured */ + return ISIS_OK; +} + +static int +lsp_authentication_check (struct stream *stream, struct isis_area *area, + int level, struct isis_passwd *passwd) +{ + struct isis_link_state_hdr *hdr; + uint32_t expected = 0, found = 0, auth_tlv_offset = 0; + uint16_t checksum, rem_lifetime; + struct tlvs tlvs; + int retval = ISIS_OK; + + hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); + expected |= TLVFLAG_AUTH_INFO; + auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN; + retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN, + ntohs (hdr->pdu_len) - ISIS_FIXED_HDR_LEN - + ISIS_LSP_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); + + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " + "cksum 0x%04x, lifetime %us, len %u", + area->area_tag, level, rawlspid_print (hdr->lsp_id), + ntohl (hdr->seq_num), ntohs (hdr->checksum), + ntohs (hdr->rem_lifetime), ntohs (hdr->pdu_len)); + if ((isis->debugs & DEBUG_UPDATE_PACKETS) && + (isis->debugs & DEBUG_PACKET_DUMP)) + zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream)); + return retval; + } + + if (!(found & TLVFLAG_AUTH_INFO)) { - zlog_warn ("Unsupported authentication type %d", theother->type); - return 1; /* Auth fail (different authentication types) */ + zlog_err ("No authentication tlv in LSP"); + return ISIS_ERROR; } - switch (one->type) + + if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT && + tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) { - case ISIS_PASSWD_TYPE_CLEARTXT: - if (one->len != theother->len) - return 1; /* Auth fail () - passwd len mismatch */ - return memcmp (one->passwd, theother->passwd, one->len); - break; - default: - zlog_warn ("Unsupported authentication type"); - break; + zlog_err ("Unknown authentication type in LSP"); + return ISIS_ERROR; } - return 0; /* Auth pass */ + + /* + * RFC 5304 set checksum and remaining lifetime to zero before + * verification and reset to old values after verification. + */ + checksum = hdr->checksum; + rem_lifetime = hdr->rem_lifetime; + hdr->checksum = 0; + hdr->rem_lifetime = 0; + retval = authentication_check (&tlvs.auth_info, passwd, stream, + auth_tlv_offset); + hdr->checksum = checksum; + hdr->rem_lifetime = rem_lifetime; + + return retval; } /* * Processing helper functions */ +static void +del_addr (void *val) +{ + XFREE (MTYPE_ISIS_TMP, val); +} + +static void +tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) +{ + struct listnode *node; + struct area_addr *area_addr, *malloced; + + if (adj->area_addrs) + { + adj->area_addrs->del = del_addr; + list_delete (adj->area_addrs); + } + adj->area_addrs = list_new (); + if (tlvs->area_addrs) + { + for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr)) + { + malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr)); + memcpy (malloced, area_addr, sizeof (struct area_addr)); + listnode_add (adj->area_addrs, malloced); + } + } +} + static void tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) { @@ -213,12 +331,6 @@ tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) } } -static void -del_ip_addr (void *val) -{ - XFREE (MTYPE_ISIS_TMP, val); -} - static void tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { @@ -227,7 +339,7 @@ tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) if (adj->ipv4_addrs) { - adj->ipv4_addrs->del = del_ip_addr; + adj->ipv4_addrs->del = del_addr; list_delete (adj->ipv4_addrs); } adj->ipv4_addrs = list_new (); @@ -251,7 +363,7 @@ tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) if (adj->ipv6_addrs) { - adj->ipv6_addrs->del = del_ip_addr; + adj->ipv6_addrs->del = del_addr; list_delete (adj->ipv6_addrs); } adj->ipv6_addrs = list_new (); @@ -284,9 +396,25 @@ process_p2p_hello (struct isis_circuit *circuit) int retval = ISIS_OK; struct isis_p2p_hello_hdr *hdr; struct isis_adjacency *adj; - u_int32_t expected = 0, found; + u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; struct tlvs tlvs; + if (isis->debugs & DEBUG_ADJ_PACKETS) + { + zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", + circuit->area->area_tag, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + + if (circuit->circ_type != CIRCUIT_T_P2P) + { + zlog_warn ("p2p hello on non p2p circuit"); + return ISIS_WARNING; + } + if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN) { @@ -311,7 +439,7 @@ process_p2p_hello (struct isis_circuit *circuit) * Get the header */ hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN; + stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); /* hdr.circuit_t = stream_getc (stream); stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN); @@ -319,35 +447,15 @@ process_p2p_hello (struct isis_circuit *circuit) hdr.pdu_len = stream_getw (stream); hdr.local_id = stream_getc (stream); */ - /* - * My interpertation of the ISO, if no adj exists we will create one for - * the circuit - */ - - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," - " cir id %02d, length %d", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string (circuit->circuit_is_type), - circuit->circuit_id, ntohs (hdr->pdu_len)); - } - - adj = circuit->u.p2p.neighbor; - if (!adj) + if (ntohs (hdr->pdu_len) > ISO_MTU(circuit)) { - adj = isis_new_adj (hdr->source_id, NULL, 0, circuit); - if (adj == NULL) - return ISIS_ERROR; - circuit->u.p2p.neighbor = adj; - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - adj->sys_type = ISIS_SYSTYPE_UNKNOWN; + zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " + "invalid pdu length %d", + circuit->area->area_tag, circuit->interface->name, + ntohs (hdr->pdu_len)); + return ISIS_WARNING; } - /* 8.2.6 Monitoring point-to-point adjacencies */ - adj->hold_time = ntohs (hdr->hold_time); - adj->last_upd = time (NULL); - /* * Lets get the TLVS now */ @@ -357,37 +465,94 @@ process_p2p_hello (struct isis_circuit *circuit) expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; + auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN - - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs); + - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, + &auth_tlv_offset); if (retval > ISIS_WARNING) { + zlog_warn ("parse_tlvs() failed"); free_tlvs (&tlvs); return retval; }; + if (!(found & TLVFLAG_AREA_ADDRS)) + { + zlog_warn ("No Area addresses TLV in P2P IS to IS hello"); + free_tlvs (&tlvs); + return ISIS_WARNING; + } + /* 8.2.5.1 c) Authentication */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&circuit->passwd, &tlvs.auth_info)) - { - isis_event_auth_failure (circuit->area->area_tag, - "P2P hello authentication failure", - hdr->source_id); - return ISIS_OK; - } + authentication_check (&tlvs.auth_info, &circuit->passwd, + circuit->rcv_stream, auth_tlv_offset)) + { + isis_event_auth_failure (circuit->area->area_tag, + "P2P hello authentication failure", + hdr->source_id); + free_tlvs (&tlvs); + return ISIS_OK; + } } + /* + * check if it's own interface ip match iih ip addrs + */ + if ((found & TLVFLAG_IPV4_ADDR) == 0 || + ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) + { + zlog_warn ("ISIS-Adj: No usable IP interface addresses " + "in LAN IIH from %s\n", circuit->interface->name); + free_tlvs (&tlvs); + return ISIS_WARNING; + } + + /* + * My interpertation of the ISO, if no adj exists we will create one for + * the circuit + */ + adj = circuit->u.p2p.neighbor; + if (!adj || adj->level != hdr->circuit_t) + { + if (!adj) + { + adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit); + if (adj == NULL) + return ISIS_ERROR; + } + else + { + adj->level = hdr->circuit_t; + } + circuit->u.p2p.neighbor = adj; + isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); + adj->sys_type = ISIS_SYSTYPE_UNKNOWN; + } + + /* 8.2.6 Monitoring point-to-point adjacencies */ + adj->hold_time = ntohs (hdr->hold_time); + adj->last_upd = time (NULL); + /* we do this now because the adj may not survive till the end... */ + tlvs_to_adj_area_addrs (&tlvs, adj); + + /* which protocol are spoken ??? */ + if (found & TLVFLAG_NLPID) + tlvs_to_adj_nlpids (&tlvs, adj); /* we need to copy addresses to the adj */ - tlvs_to_adj_ipv4_addrs (&tlvs, adj); + if (found & TLVFLAG_IPV4_ADDR) + tlvs_to_adj_ipv4_addrs (&tlvs, adj); #ifdef HAVE_IPV6 - tlvs_to_adj_ipv6_addrs (&tlvs, adj); + if (found & TLVFLAG_IPV6_ADDR) + tlvs_to_adj_ipv6_addrs (&tlvs, adj); #endif /* HAVE_IPV6 */ /* lets take care of the expiry */ @@ -422,6 +587,7 @@ process_p2p_hello (struct isis_circuit *circuit) { /* (7) reject - wrong system type event */ zlog_warn ("wrongSystemType"); + free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) @@ -508,6 +674,7 @@ process_p2p_hello (struct isis_circuit *circuit) { /* (5) reject - wrong system type event */ zlog_warn ("wrongSystemType"); + free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || @@ -540,7 +707,7 @@ process_p2p_hello (struct isis_circuit *circuit) } } /* 8.2.5.2 b) if no match was detected */ - else + else if (listcount (circuit->area->area_addrs) > 0) { if (circuit->area->is_type == IS_LEVEL_1) { @@ -566,6 +733,7 @@ process_p2p_hello (struct isis_circuit *circuit) { /* (6) reject - Area Mismatch event */ zlog_warn ("AreaMismatch"); + free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) @@ -618,6 +786,11 @@ process_p2p_hello (struct isis_circuit *circuit) } } } + else + { + /* down - area mismatch */ + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); + } /* 8.2.5.2 c) if the action was up - comparing circuit IDs */ /* FIXME - Missing parts */ @@ -641,7 +814,15 @@ process_p2p_hello (struct isis_circuit *circuit) } adj->circuit_t = hdr->circuit_t; - adj->level = hdr->circuit_t; + + if (isis->debugs & DEBUG_ADJ_PACKETS) + { + zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," + " cir id %02d, length %d", + circuit->area->area_tag, circuit->interface->name, + circuit_t2string (circuit->is_type), + circuit->circuit_id, ntohs (hdr->pdu_len)); + } free_tlvs (&tlvs); @@ -657,11 +838,28 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) int retval = ISIS_OK; struct isis_lan_hello_hdr hdr; struct isis_adjacency *adj; - u_int32_t expected = 0, found; + u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; struct tlvs tlvs; u_char *snpa; struct listnode *node; + if (isis->debugs & DEBUG_ADJ_PACKETS) + { + zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " + "cirID %u", + circuit->area->area_tag, level, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + + if (circuit->circ_type != CIRCUIT_T_BROADCAST) + { + zlog_warn ("lan hello on non broadcast circuit"); + return ISIS_WARNING; + } + if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN) { @@ -676,7 +874,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) return ISIS_WARNING; } - if (!accept_level (level, circuit->circuit_is_type)) + if (!accept_level (level, circuit->is_type)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -708,13 +906,25 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) hdr.prio = stream_getc (circuit->rcv_stream); stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 && - hdr.circuit_t != IS_LEVEL_1_AND_2) + if (hdr.pdu_len > ISO_MTU(circuit)) { - zlog_warn ("Level %d LAN Hello with Circuit Type %d", level, - hdr.circuit_t); + zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " + "invalid pdu length %d", + circuit->area->area_tag, circuit->interface->name, + hdr.pdu_len); + hdr.pdu_len = stream_get_endp (circuit->rcv_stream); + } + + if (hdr.circuit_t != IS_LEVEL_1 && + hdr.circuit_t != IS_LEVEL_2 && + hdr.circuit_t != IS_LEVEL_1_AND_2 && + (level & hdr.circuit_t) == 0) + { + zlog_err ("Level %d LAN Hello with Circuit Type %d", level, + hdr.circuit_t); return ISIS_ERROR; } + /* * Then get the tlvs */ @@ -725,10 +935,12 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; + auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, - STREAM_PNT (circuit->rcv_stream), - hdr.pdu_len - ISIS_LANHELLO_HDRLEN - - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs); + STREAM_PNT (circuit->rcv_stream), + hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, + &expected, &found, &tlvs, + &auth_tlv_offset); if (retval > ISIS_WARNING) { @@ -744,24 +956,28 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) goto out; } + /* Verify authentication, either cleartext of HMAC MD5 */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&circuit->passwd, &tlvs.auth_info)) - { - isis_event_auth_failure (circuit->area->area_tag, - "LAN hello authentication failure", - hdr.source_id); - retval = ISIS_WARNING; - goto out; - } + authentication_check (&tlvs.auth_info, &circuit->passwd, + circuit->rcv_stream, auth_tlv_offset)) + { + isis_event_auth_failure (circuit->area->area_tag, + "LAN hello authentication failure", + hdr.source_id); + retval = ISIS_WARNING; + goto out; + } } /* * Accept the level 1 adjacency only if a match between local and * remote area addresses is found */ - if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs)) + if (listcount (circuit->area->area_addrs) == 0 || + (level == IS_LEVEL_1 && + area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -788,43 +1004,49 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) /* * check if it's own interface ip match iih ip addrs */ - if (!(found & TLVFLAG_IPV4_ADDR) - || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) + if ((found & TLVFLAG_IPV4_ADDR) == 0 || + ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) { - zlog_debug - ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n", - circuit->interface->name); + zlog_debug ("ISIS-Adj: No usable IP interface addresses " + "in LAN IIH from %s\n", circuit->interface->name); retval = ISIS_WARNING; goto out; } adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]); - if (!adj) + if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) || + (adj->level != level)) { - /* - * Do as in 8.4.2.5 - */ - adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit); - if (adj == NULL) - { - retval = ISIS_ERROR; - goto out; - } - - adj->level = level; + if (!adj) + { + /* + * Do as in 8.4.2.5 + */ + adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit); + if (adj == NULL) + { + retval = ISIS_ERROR; + goto out; + } + } + else + { + if (ssnpa) { + memcpy (adj->snpa, ssnpa, 6); + } else { + memset (adj->snpa, ' ', 6); + } + adj->level = level; + } isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - if (level == 1) - { - adj->sys_type = ISIS_SYSTYPE_L1_IS; - } + if (level == IS_LEVEL_1) + adj->sys_type = ISIS_SYSTYPE_L1_IS; else - { - adj->sys_type = ISIS_SYSTYPE_L2_IS; - } + adj->sys_type = ISIS_SYSTYPE_L2_IS; list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], - circuit->u.bc.lan_neighs[level - 1]); + circuit->u.bc.lan_neighs[level - 1]); } if(adj->dis_record[level-1].dis==ISIS_IS_DIS) @@ -833,7 +1055,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) case 1: if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) { - thread_add_event (master, isis_event_dis_status_change, circuit, 0); + thread_add_event (master, isis_event_dis_status_change, circuit, 0); memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); } @@ -841,7 +1063,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) case 2: if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) { - thread_add_event (master, isis_event_dis_status_change, circuit, 0); + thread_add_event (master, isis_event_dis_status_change, circuit, 0); memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); } @@ -854,6 +1076,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); + tlvs_to_adj_area_addrs (&tlvs, adj); + /* which protocol are spoken ??? */ if (found & TLVFLAG_NLPID) tlvs_to_adj_nlpids (&tlvs, adj); @@ -872,7 +1096,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, - (long) adj->hold_time); + (long) adj->hold_time); /* * If the snpa for this circuit is found from LAN Neighbours TLV @@ -880,31 +1104,48 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) */ if (found & TLVFLAG_LAN_NEIGHS) + { + if (adj->adj_state != ISIS_ADJ_UP) { - if (adj->adj_state != ISIS_ADJ_UP) - { - for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) - if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) - { - isis_adj_state_change (adj, ISIS_ADJ_UP, - "own SNPA found in LAN Neighbours TLV"); - } - } + for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) + { + if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) + { + isis_adj_state_change (adj, ISIS_ADJ_UP, + "own SNPA found in LAN Neighbours TLV"); + } + } + } + else + { + int found = 0; + for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) + if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) + { + found = 1; + break; + } + if (found == 0) + isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, + "own SNPA not found in LAN Neighbours TLV"); } + } + else if (adj->adj_state == ISIS_ADJ_UP) + { + isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, + "no LAN Neighbours TLV found"); + } out: - /* DEBUG_ADJ_PACKETS */ if (isis->debugs & DEBUG_ADJ_PACKETS) { - /* FIXME: is this place right? fix missing info */ zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " "cirID %u, length %ld", circuit->area->area_tag, level, snpa_print (ssnpa), circuit->interface->name, - circuit_t2string (circuit->circuit_is_type), + circuit_t2string (circuit->is_type), circuit->circuit_id, - /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) stream_get_endp (circuit->rcv_stream)); + stream_get_endp (circuit->rcv_stream)); } free_tlvs (&tlvs); @@ -927,7 +1168,16 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; - /* Sanity check - FIXME: move to correct place */ + if (isis->debugs & DEBUG_UPDATE_PACKETS) + { + zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN) { @@ -941,19 +1191,26 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " - "lifetime %us, len %lu, on %s", + "lifetime %us, len %u, on %s", circuit->area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), - /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) stream_get_endp (circuit->rcv_stream), + ntohs (hdr->pdu_len), circuit->interface->name); } - assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN); + if (ntohs (hdr->pdu_len) <= ISIS_LSP_HDR_LEN || + ntohs (hdr->pdu_len) > ISO_MTU(circuit)) + { + zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", + circuit->area->area_tag, + rawlspid_print (hdr->lsp_id), ntohs (hdr->pdu_len)); + + return ISIS_WARNING; + } /* Checksum sanity check - FIXME: move to correct place */ /* 12 = sysid+pdu+remtime */ @@ -979,13 +1236,13 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) } /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */ - if (!accept_level (level, circuit->circuit_is_type)) + if (!accept_level (level, circuit->is_type)) { zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of" " type %s", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), - level, circuit_t2string (circuit->circuit_is_type)); + level, circuit_t2string (circuit->is_type)); return ISIS_WARNING; } @@ -995,12 +1252,12 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */ /* 7.3.15.1 a) 7 - password check */ - (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) : - (passwd = &circuit->area->domain_passwd); + (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) : + (passwd = &circuit->area->domain_passwd); if (passwd->type) { - if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area, - ntohs (hdr->pdu_len), passwd)) + if (lsp_authentication_check (circuit->rcv_stream, circuit->area, + level, passwd)) { isis_event_auth_failure (circuit->area->area_tag, "LSP authentication failure", hdr->lsp_id); @@ -1021,7 +1278,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */ /* for broadcast circuits, snpa should be compared */ - /* FIXME : Point To Point */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { @@ -1038,7 +1294,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) return ISIS_WARNING; /* Silently discard */ } } - /* for non broadcast, we just need to find same level adj */ else { @@ -1049,13 +1304,15 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) } else { - if (((level == 1) && + if (((level == IS_LEVEL_1) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) || - ((level == 2) && + ((level == IS_LEVEL_2) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1))) return ISIS_WARNING; /* Silently discard */ + adj = circuit->u.p2p.neighbor; } } + dontcheckadj: /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */ @@ -1082,10 +1339,9 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* 7.3.16.4 b) 1) */ if (comp == LSP_NEWER) { - lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, - level); + lsp_update (lsp, circuit->rcv_stream, circuit->area, level); /* ii */ - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_set_all_srmflags (lsp); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* v */ @@ -1109,38 +1365,25 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } - else - { - /* our own LSP -> 7.3.16.4 c) */ - if (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) != - circuit->circuit_id - || (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) == - circuit->circuit_id - && circuit->u.bc.is_dr[level - 1] == 1)) - { - lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1); - if (isis->debugs & DEBUG_UPDATE_PACKETS) - zlog_debug ("LSP LEN: %d", - ntohs (lsp->lsp_header->pdu_len)); - fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, - ntohs (lsp->lsp_header->pdu_len) - 12, 12); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - if (isis->debugs & DEBUG_UPDATE_PACKETS) - zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new " - "seq 0x%08x", circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), - ntohl (lsp->lsp_header->seq_num)); - lsp->lsp_header->rem_lifetime = - htons (isis_jitter - (circuit->area->max_lsp_lifetime[level - 1], - MAX_AGE_JITTER)); - } - else - { - /* Got purge for own pseudo-lsp, and we are not DR */ - lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level); - } - } + else if (lsp->lsp_header->rem_lifetime != 0) + { + /* our own LSP -> 7.3.16.4 c) */ + if (comp == LSP_NEWER) + { + lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); + lsp_set_all_srmflags (lsp); + } + else + { + ISIS_SET_FLAG (lsp->SRMflags, circuit); + ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); + } + if (isis->debugs & DEBUG_UPDATE_PACKETS) + zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new " + "seq 0x%08x", circuit->area->area_tag, + rawlspid_print (hdr->lsp_id), + ntohl (lsp->lsp_header->seq_num)); + } } return retval; } @@ -1163,21 +1406,13 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { /* 7.3.16.1 */ - lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1); - - fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, - ntohs (lsp->lsp_header->pdu_len) - 12, 12); - - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); + lsp_set_all_srmflags (lsp); if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq " "0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); - lsp->lsp_header->rem_lifetime = - htons (isis_jitter - (circuit->area->max_lsp_lifetime[level - 1], - MAX_AGE_JITTER)); } } else @@ -1187,21 +1422,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ if ((!lsp || comp == LSP_NEWER)) { - /* i */ - if (lsp) - { -#ifdef EXTREME_DEBUG - zlog_debug ("level %d number is - %ld", level, - circuit->area->lspdb[level - 1]->dict_nodecount); -#endif /* EXTREME DEBUG */ - lsp_search_and_destroy (hdr->lsp_id, - circuit->area->lspdb[level - 1]); - /* exists, so we overwrite */ -#ifdef EXTREME_DEBUG - zlog_debug ("level %d number is - %ld", level, - circuit->area->lspdb[level - 1]->dict_nodecount); -#endif /* EXTREME DEBUG */ - } /* * If this lsp is a frag, need to see if we have zero lsp present */ @@ -1212,19 +1432,24 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]); if (!lsp0) { - zlog_debug ("Got lsp frag, while zero lsp not database"); + zlog_debug ("Got lsp frag, while zero lsp not in database"); return ISIS_OK; } } - lsp = - lsp_new_from_stream_ptr (circuit->rcv_stream, - ntohs (hdr->pdu_len), lsp0, - circuit->area); - lsp->level = level; - lsp->adj = adj; - lsp_insert (lsp, circuit->area->lspdb[level - 1]); + /* i */ + if (!lsp) + { + lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, + ntohs (hdr->pdu_len), lsp0, + circuit->area, level); + lsp_insert (lsp, circuit->area->lspdb[level - 1]); + } + else /* exists, so we overwrite */ + { + lsp_update (lsp, circuit->rcv_stream, circuit->area, level); + } /* ii */ - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_set_all_srmflags (lsp); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); @@ -1237,11 +1462,9 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) else if (comp == LSP_EQUAL) { ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, level); + lsp_update (lsp, circuit->rcv_stream, circuit->area, level); if (circuit->circ_type != CIRCUIT_T_BROADCAST) - { - ISIS_SET_FLAG (lsp->SSNflags, circuit); - } + ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.15.1 e) 3) LSP older than the one in db */ else @@ -1250,8 +1473,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } - if (lsp) - lsp->adj = adj; return retval; } @@ -1268,11 +1489,11 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, int retval = ISIS_OK; int cmp, own_lsp; char typechar = ' '; - int len; + unsigned int len; struct isis_adjacency *adj; struct isis_complete_seqnum_hdr *chdr = NULL; struct isis_partial_seqnum_hdr *phdr = NULL; - uint32_t found = 0, expected = 0; + uint32_t found = 0, expected = 0, auth_tlv_offset = 0; struct isis_lsp *lsp; struct lsp_entry *entry; struct listnode *node, *nnode; @@ -1289,9 +1510,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN; len = ntohs (chdr->pdu_len); - if (len < ISIS_CSNP_HDRLEN) + if (len < ISIS_CSNP_HDRLEN || len > ISO_MTU(circuit)) { - zlog_warn ("Received a CSNP with bogus length!"); + zlog_warn ("Received a CSNP with bogus length %d", len); return ISIS_OK; } } @@ -1302,9 +1523,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN; len = ntohs (phdr->pdu_len); - if (len < ISIS_PSNP_HDRLEN) + if (len < ISIS_PSNP_HDRLEN || len > ISO_MTU(circuit)) { - zlog_warn ("Received a CSNP with bogus length!"); + zlog_warn ("Received a CSNP with bogus length %d", len); return ISIS_OK; } } @@ -1322,7 +1543,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, } /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */ - if (!accept_level (level, circuit->circuit_is_type)) + if (!accept_level (level, circuit->is_type)) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " @@ -1331,26 +1552,23 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, level, typechar, circuit->interface->name, - circuit_t2string (circuit->circuit_is_type), level); + circuit_t2string (circuit->is_type), level); return ISIS_OK; } /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */ if ((snp_type == ISIS_SNP_PSNP_FLAG) && - (circuit->circ_type == CIRCUIT_T_BROADCAST)) + (circuit->circ_type == CIRCUIT_T_BROADCAST) && + (!circuit->u.bc.is_dr[level - 1])) { - if (!circuit->u.bc.is_dr[level - 1]) - { + zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " + "skipping: we are not the DIS", + circuit->area->area_tag, + level, + typechar, snpa_print (ssnpa), circuit->interface->name); - zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " - "skipping: we are not the DIS", - circuit->area->area_tag, - level, - typechar, snpa_print (ssnpa), circuit->interface->name); - - return ISIS_OK; - } + return ISIS_OK; } /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */ @@ -1380,7 +1598,10 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, else { if (!circuit->u.p2p.neighbor) - return ISIS_OK; /* Silently discard */ + { + zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name); + return ISIS_OK; /* Silently discard */ + } } /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */ @@ -1392,10 +1613,12 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, /* parse the SNP */ expected |= TLVFLAG_LSP_ENTRIES; expected |= TLVFLAG_AUTH_INFO; + + auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), len - circuit->rcv_stream->getp, - &expected, &found, &tlvs); + &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { @@ -1404,7 +1627,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, return retval; } - if (level == 1) + if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; @@ -1412,16 +1635,19 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) { if (passwd->type) - { - if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (passwd, &tlvs.auth_info)) - { - isis_event_auth_failure (circuit->area->area_tag, - "SNP authentication" " failure", - phdr ? phdr->source_id : chdr->source_id); - return ISIS_OK; - } - } + { + if (!(found & TLVFLAG_AUTH_INFO) || + authentication_check (&tlvs.auth_info, passwd, + circuit->rcv_stream, auth_tlv_offset)) + { + isis_event_auth_failure (circuit->area->area_tag, + "SNP authentication" " failure", + phdr ? phdr->source_id : + chdr->source_id); + free_tlvs (&tlvs); + return ISIS_OK; + } + } } /* debug isis snp-packets */ @@ -1461,19 +1687,18 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */ if (cmp == LSP_EQUAL) { - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */ + /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } + /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */ else if (cmp == LSP_OLDER) { ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); ISIS_SET_FLAG (lsp->SRMflags, circuit); } + /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */ else { - /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM - * on p2p */ if (own_lsp) { lsp_inc_seqnum (lsp, ntohl (entry->seq_num)); @@ -1482,8 +1707,8 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, else { ISIS_SET_FLAG (lsp->SSNflags, circuit); - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } } } @@ -1496,7 +1721,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, { lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime), 0, 0, entry->checksum, level); + lsp->area = circuit->area; lsp_insert (lsp, circuit->area->lspdb[level - 1]); + ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); ISIS_SET_FLAG (lsp->SSNflags, circuit); } } @@ -1507,7 +1734,8 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, if (snp_type == ISIS_SNP_CSNP_FLAG) { /* - * Build a list from our own LSP db bounded with start_ and stop_lsp_id + * Build a list from our own LSP db bounded with + * start_lsp_id and stop_lsp_id */ lsp_list = list_new (); lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id, @@ -1530,11 +1758,10 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, } /* on remaining LSPs we set SRM (neighbor knew not of) */ for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp)) - { ISIS_SET_FLAG (lsp->SRMflags, circuit); - } /* lets free it */ - list_free (lsp_list); + list_delete (lsp_list); + } free_tlvs (&tlvs); @@ -1544,6 +1771,16 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, static int process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa) { + if (isis->debugs & DEBUG_SNP_PACKETS) + { + zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + /* Sanity check - FIXME: move to correct place */ if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN) @@ -1558,10 +1795,20 @@ process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa) static int process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa) { + if (isis->debugs & DEBUG_SNP_PACKETS) + { + zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) { - zlog_warn ("Packet too short"); + zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN); return ISIS_WARNING; } @@ -1585,6 +1832,16 @@ process_is_hello (struct isis_circuit *circuit) u_char neigh_len; u_char *sysid; + if (isis->debugs & DEBUG_ADJ_PACKETS) + { + zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u", + circuit->area->area_tag, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + /* In this point in time we are not yet able to handle is_hellos * on lan - Sorry juniper... */ @@ -1649,7 +1906,6 @@ static int isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) { struct isis_fixed_hdr *hdr; - struct esis_fixed_hdr *esis_hdr; int retval = ISIS_OK; @@ -1660,7 +1916,7 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) { - zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); + zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); return ISIS_ERROR; } @@ -1669,28 +1925,11 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) */ if (hdr->idrp == ISO9542_ESIS) { - esis_hdr = (struct esis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream); - stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN); - /* FIXME: Need to do some acceptence tests */ - /* example length... */ - switch (esis_hdr->pdu_type) - { - case ESH_PDU: - /* FIXME */ - break; - case ISH_PDU: - zlog_debug ("AN ISH PDU!!"); - retval = process_is_hello (circuit); - break; - default: - return ISIS_ERROR; - } - return retval; - } - else - { - stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); + zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp); + return ISIS_ERROR; } + stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); + /* * and then process it */ @@ -1721,6 +1960,14 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) zlog_warn ("Unsupported ISIS version %u", hdr->version2); return ISIS_WARNING; } + + if (circuit->is_passive) + { + zlog_warn ("Received ISIS PDU on passive circuit %s", + circuit->interface->name); + return ISIS_WARNING; + } + /* either 3 or 0 */ if ((hdr->max_area_addrs != 0) && (hdr->max_area_addrs != isis->max_area_addrs)) @@ -1795,8 +2042,11 @@ isis_receive (struct thread *thread) /* * prepare for next packet. */ - THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, - circuit->fd); + if (!circuit->is_passive) + { + THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, + circuit->fd); + } return retval; } @@ -1830,10 +2080,13 @@ isis_receive (struct thread *thread) /* * prepare for next packet. */ - circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit, - listcount - (circuit->area->circuit_list) * - 100); + if (!circuit->is_passive) + { + circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit, + listcount + (circuit->area->circuit_list) * + 100); + } return retval; } @@ -1908,11 +2161,14 @@ send_hello (struct isis_circuit *circuit, int level) struct isis_fixed_hdr fixed_hdr; struct isis_lan_hello_hdr hello_hdr; struct isis_p2p_hello_hdr p2p_hello_hdr; - + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + unsigned long len_pointer, length, auth_tlv_offset = 0; u_int32_t interval; - unsigned long len_pointer, length; int retval; + if (circuit->is_passive) + return ISIS_OK; + if (circuit->interface->mtu == 0) { zlog_warn ("circuit has zero MTU"); @@ -1925,7 +2181,7 @@ send_hello (struct isis_circuit *circuit, int level) stream_reset (circuit->snd_stream); if (circuit->circ_type == CIRCUIT_T_BROADCAST) - if (level == 1) + if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO, circuit->snd_stream); else @@ -1942,7 +2198,7 @@ send_hello (struct isis_circuit *circuit, int level) circuit->hello_interval[level - 1]; if (interval > USHRT_MAX) interval = USHRT_MAX; - hello_hdr.circuit_t = circuit->circuit_is_type; + hello_hdr.circuit_t = circuit->is_type; memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); hello_hdr.hold_time = htons ((u_int16_t) interval); @@ -1959,13 +2215,13 @@ send_hello (struct isis_circuit *circuit, int level) } else { - hello_hdr.prio = circuit->u.bc.priority[level - 1]; - if (level == 1 && circuit->u.bc.l1_desig_is) + hello_hdr.prio = circuit->priority[level - 1]; + if (level == IS_LEVEL_1) { memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); } - else if (level == 2 && circuit->u.bc.l2_desig_is) + else if (level == IS_LEVEL_2) { memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); @@ -1974,27 +2230,49 @@ send_hello (struct isis_circuit *circuit, int level) } /* - * Then the variable length part + * Then the variable length part. */ + /* add circuit password */ - if (circuit->passwd.type) - if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, - circuit->passwd.passwd, circuit->snd_stream)) - return ISIS_WARNING; + switch (circuit->passwd.type) + { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, + circuit->passwd.passwd, circuit->snd_stream)) + return ISIS_WARNING; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later overwrite the MD5 hash */ + auth_tlv_offset = stream_get_endp (circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; + } + /* Area Addresses TLV */ - assert (circuit->area); - if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) - if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) - return ISIS_WARNING; + if (listcount (circuit->area->area_addrs) == 0) + return ISIS_WARNING; + if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) + return ISIS_WARNING; /* LAN Neighbors TLV */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0) + if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] && + listcount (circuit->u.bc.lan_neighs[0]) > 0) if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], circuit->snd_stream)) return ISIS_WARNING; - if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0) + if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] && + listcount (circuit->u.bc.lan_neighs[1]) > 0) if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], circuit->snd_stream)) return ISIS_WARNING; @@ -2005,19 +2283,20 @@ send_hello (struct isis_circuit *circuit, int level) if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) return ISIS_WARNING; /* IP interface Address TLV */ - if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) + if (circuit->ip_router && circuit->ip_addrs && + listcount (circuit->ip_addrs) > 0) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) return ISIS_WARNING; #ifdef HAVE_IPV6 /* IPv6 Interface Address TLV */ if (circuit->ipv6_router && circuit->ipv6_link && - circuit->ipv6_link->count > 0) + listcount (circuit->ipv6_link) > 0) if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream)) return ISIS_WARNING; #endif /* HAVE_IPV6 */ - if (circuit->u.bc.pad_hellos) + if (circuit->pad_hellos) if (tlv_add_padding (circuit->snd_stream)) return ISIS_WARNING; @@ -2025,11 +2304,18 @@ send_hello (struct isis_circuit *circuit, int level) /* Update PDU length */ stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); - retval = circuit->tx (circuit, level); - if (retval) - zlog_warn ("sending of LAN Level %d Hello failed", level); + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + hmac_md5 (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream), + (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, + (caddr_t) &hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + } - /* DEBUG_ADJ_PACKETS */ if (isis->debugs & DEBUG_ADJ_PACKETS) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) @@ -2037,24 +2323,26 @@ send_hello (struct isis_circuit *circuit, int level) zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld", circuit->area->area_tag, level, circuit->interface->name, /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) STREAM_SIZE (circuit->snd_stream)); + length); } else { zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld", circuit->area->area_tag, circuit->interface->name, /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) STREAM_SIZE (circuit->snd_stream)); + length); } + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream)); } - return retval; -} + retval = circuit->tx (circuit, level); + if (retval != ISIS_OK) + zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed", + circuit->area->area_tag, level, circuit->interface->name); -static int -send_lan_hello (struct isis_circuit *circuit, int level) -{ - return send_hello (circuit, level); + return retval; } int @@ -2070,7 +2358,7 @@ send_lan_l1_hello (struct thread *thread) if (circuit->u.bc.run_dr_elect[0]) retval = isis_dr_elect (circuit, 1); - retval = send_lan_hello (circuit, 1); + retval = send_hello (circuit, 1); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], @@ -2093,7 +2381,7 @@ send_lan_l2_hello (struct thread *thread) if (circuit->u.bc.run_dr_elect[1]) retval = isis_dr_elect (circuit, 2); - retval = send_lan_hello (circuit, 2); + retval = send_hello (circuit, 2); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], @@ -2128,11 +2416,18 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, { struct isis_fixed_hdr fixed_hdr; struct isis_passwd *passwd; - int retval = ISIS_OK; unsigned long lenp; u_int16_t length; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + unsigned long auth_tlv_offset = 0; + int retval = ISIS_OK; + + if (circuit->snd_stream == NULL) + circuit->snd_stream = stream_new (ISO_MTU (circuit)); + else + stream_reset (circuit->snd_stream); - if (level == 1) + if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM, circuit->snd_stream); else @@ -2156,28 +2451,142 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, /* * And TLVs */ - if (level == 1) + if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) - if (passwd->type) - retval = tlv_add_authinfo (passwd->type, passwd->len, - passwd->passwd, circuit->snd_stream); - - if (!retval && lsps) - { - retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); + { + switch (passwd->type) + { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, + passwd->passwd, circuit->snd_stream)) + return ISIS_WARNING; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later overwrite the MD5 hash */ + auth_tlv_offset = stream_get_endp (circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; } + } + + retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); + if (retval != ISIS_OK) + return retval; + length = (u_int16_t) stream_get_endp (circuit->snd_stream); - assert (length >= ISIS_CSNP_HDRLEN); /* Update PU length */ stream_putw_at (circuit->snd_stream, lenp, length); + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && + passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + hmac_md5 (STREAM_DATA (circuit->snd_stream), + stream_get_endp(circuit->snd_stream), + (unsigned char *) &passwd->passwd, passwd->len, + (caddr_t) &hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + } + return retval; } +/* + * Count the maximum number of lsps that can be accomodated by a given size. + */ +static uint16_t +get_max_lsp_count (uint16_t size) +{ + uint16_t tlv_count; + uint16_t lsp_count; + uint16_t remaining_size; + + /* First count the full size TLVs */ + tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE; + lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN); + + /* The last TLV, if any */ + remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE; + if (remaining_size - 2 >= LSP_ENTRIES_LEN) + lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN; + + return lsp_count; +} + +/* + * Calculate the length of Authentication Info. TLV. + */ +static uint16_t +auth_tlv_length (int level, struct isis_circuit *circuit) +{ + struct isis_passwd *passwd; + uint16_t length; + + if (level == IS_LEVEL_1) + passwd = &circuit->area->area_passwd; + else + passwd = &circuit->area->domain_passwd; + + /* Also include the length of TLV header */ + length = AUTH_INFO_HDRLEN; + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) + { + switch (passwd->type) + { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + length += passwd->len; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + length += ISIS_AUTH_MD5_SIZE; + break; + + default: + break; + } + } + + return length; +} + +/* + * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP. + */ +static uint16_t +max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit) +{ + int snp_hdr_len; + int auth_tlv_len; + uint16_t lsp_count; + + snp_hdr_len = ISIS_FIXED_HDR_LEN; + if (snp_type == ISIS_SNP_CSNP_FLAG) + snp_hdr_len += ISIS_CSNP_HDRLEN; + else + snp_hdr_len += ISIS_PSNP_HDRLEN; + + auth_tlv_len = auth_tlv_length (level, circuit); + lsp_count = get_max_lsp_count ( + stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len); +} + /* * FIXME: support multiple CSNPs */ @@ -2185,52 +2594,100 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, int send_csnp (struct isis_circuit *circuit, int level) { - int retval = ISIS_OK; u_char start[ISIS_SYS_ID_LEN + 2]; u_char stop[ISIS_SYS_ID_LEN + 2]; struct list *list = NULL; struct listnode *node; struct isis_lsp *lsp; + u_char num_lsps, loop = 1; + int i, retval = ISIS_OK; + + if (circuit->area->lspdb[level - 1] == NULL || + dict_count (circuit->area->lspdb[level - 1]) == 0) + return retval; memset (start, 0x00, ISIS_SYS_ID_LEN + 2); memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); - if (circuit->area->lspdb[level - 1] && - dict_count (circuit->area->lspdb[level - 1]) > 0) + num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit); + + while (loop) { list = list_new (); - lsp_build_list (start, stop, list, circuit->area->lspdb[level - 1]); - - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); + lsp_build_list (start, stop, num_lsps, list, + circuit->area->lspdb[level - 1]); + /* + * Update the stop lsp_id before encoding this CSNP. + */ + if (listcount (list) < num_lsps) + { + memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); + } else - stream_reset (circuit->snd_stream); + { + node = listtail (list); + lsp = listgetdata (node); + memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); + } retval = build_csnp (level, start, stop, list, circuit); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed", + circuit->area->area_tag, level, circuit->interface->name); + list_delete (list); + return retval; + } if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", - circuit->area->area_tag, level, circuit->interface->name, - /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) STREAM_SIZE (circuit->snd_stream)); - for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) - { - zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime)); - } - } + { + zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", + circuit->area->area_tag, level, circuit->interface->name, + stream_get_endp (circuit->snd_stream)); + for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) + { + zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us", + circuit->area->area_tag, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime)); + } + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream)); + } + + retval = circuit->tx (circuit, level); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete (list); + return retval; + } + /* + * Start lsp_id of the next CSNP should be one plus the + * stop lsp_id in this current CSNP. + */ + memcpy (start, stop, ISIS_SYS_ID_LEN + 2); + loop = 0; + for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) + { + if (start[i] < (u_char)0xff) + { + start[i] += 1; + loop = 1; + break; + } + } + memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); list_delete (list); - - if (retval == ISIS_OK) - retval = circuit->tx (circuit, level); } + return retval; } @@ -2284,12 +2741,19 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) struct isis_fixed_hdr fixed_hdr; unsigned long lenp; u_int16_t length; - int retval = 0; struct isis_lsp *lsp; struct isis_passwd *passwd; struct listnode *node; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + unsigned long auth_tlv_offset = 0; + int retval = ISIS_OK; - if (level == 1) + if (circuit->snd_stream == NULL) + circuit->snd_stream = stream_new (ISO_MTU (circuit)); + else + stream_reset (circuit->snd_stream); + + if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, circuit->snd_stream); else @@ -2308,20 +2772,40 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) * And TLVs */ - if (level == 1) + if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) - if (passwd->type) - retval = tlv_add_authinfo (passwd->type, passwd->len, - passwd->passwd, circuit->snd_stream); - - if (!retval && lsps) - { - retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); + { + switch (passwd->type) + { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, + passwd->passwd, circuit->snd_stream)) + return ISIS_WARNING; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later overwrite the MD5 hash */ + auth_tlv_offset = stream_get_endp (circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; } + } + + retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); + if (retval != ISIS_OK) + return retval; if (isis->debugs & DEBUG_SNP_PACKETS) { @@ -2338,10 +2822,22 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) } length = (u_int16_t) stream_get_endp (circuit->snd_stream); - assert (length >= ISIS_PSNP_HDRLEN); /* Update PDU length */ stream_putw_at (circuit->snd_stream, lenp, length); + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && + passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + hmac_md5 (STREAM_DATA (circuit->snd_stream), + stream_get_endp(circuit->snd_stream), + (unsigned char *) &passwd->passwd, passwd->len, + (caddr_t) &hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + } + return ISIS_OK; } @@ -2352,54 +2848,71 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) static int send_psnp (int level, struct isis_circuit *circuit) { - int retval = ISIS_OK; struct isis_lsp *lsp; struct list *list = NULL; struct listnode *node; + u_char num_lsps; + int retval = ISIS_OK; - if ((circuit->circ_type == CIRCUIT_T_BROADCAST && - !circuit->u.bc.is_dr[level - 1]) || - circuit->circ_type != CIRCUIT_T_BROADCAST) - { + if (circuit->circ_type == CIRCUIT_T_BROADCAST && + circuit->u.bc.is_dr[level - 1]) + return ISIS_OK; - if (circuit->area->lspdb[level - 1] && - dict_count (circuit->area->lspdb[level - 1]) > 0) - { - list = list_new (); - lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level - 1]); - - if (listcount (list) > 0) - { - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->snd_stream); + if (circuit->area->lspdb[level - 1] == NULL || + dict_count (circuit->area->lspdb[level - 1]) == 0) + return ISIS_OK; + num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); - if (isis->debugs & DEBUG_SNP_PACKETS) - zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld", - circuit->area->area_tag, level, - circuit->interface->name, - /* FIXME: use %z when we stop supporting old - * compilers. */ - (unsigned long) STREAM_SIZE (circuit->snd_stream)); + while (1) + { + list = list_new (); + lsp_build_list_ssn (circuit, num_lsps, list, + circuit->area->lspdb[level - 1]); + + if (listcount (list) == 0) + { + list_delete (list); + return ISIS_OK; + } + + retval = build_psnp (level, circuit, list); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed", + circuit->area->area_tag, level, circuit->interface->name); + list_delete (list); + return retval; + } - retval = build_psnp (level, circuit, list); - if (retval == ISIS_OK) - retval = circuit->tx (circuit, level); + if (isis->debugs & DEBUG_SNP_PACKETS) + { + zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld", + circuit->area->area_tag, level, + circuit->interface->name, + stream_get_endp (circuit->snd_stream)); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream)); + } + + retval = circuit->tx (circuit, level); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete (list); + return retval; + } - if (retval == ISIS_OK) - { - /* - * sending succeeded, we can clear SSN flags of this circuit - * for the LSPs in list - */ - for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) - ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); - } - } - list_delete (list); - } + /* + * sending succeeded, we can clear SSN flags of this circuit + * for the LSPs in list + */ + for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) + ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); + list_delete (list); } return retval; @@ -2458,90 +2971,80 @@ send_lsp (struct thread *thread) struct isis_circuit *circuit; struct isis_lsp *lsp; struct listnode *node; - int retval = 0; + int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); - if (circuit->state == C_STATE_UP) - { - lsp = listgetdata ((node = listhead (circuit->lsp_queue))); + if (circuit->state != C_STATE_UP || circuit->is_passive == 1) + { + return retval; + } - /* - * Do not send if levels do not match - */ - if (!(lsp->level & circuit->circuit_is_type)) - goto dontsend; + lsp = listgetdata ((node = listhead (circuit->lsp_queue))); - /* - * Do not send if we do not have adjacencies in state up on the circuit - */ - if (circuit->upadjcount[lsp->level - 1] == 0) - goto dontsend; - /* only send if it needs sending */ - if ((time (NULL) - lsp->last_sent) >= - circuit->area->lsp_gen_interval[lsp->level - 1]) - { + /* + * Do not send if levels do not match + */ + if (!(lsp->level & circuit->is_type)) + { + list_delete_node (circuit->lsp_queue, node); + return retval; + } - if (isis->debugs & DEBUG_UPDATE_PACKETS) - { - zlog_debug - ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," - " lifetime %us on %s", circuit->area->area_tag, lsp->level, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime), - circuit->interface->name); - } - /* copy our lsp to the send buffer */ - stream_copy (circuit->snd_stream, lsp->pdu); + /* + * Do not send if we do not have adjacencies in state up on the circuit + */ + if (circuit->upadjcount[lsp->level - 1] == 0) + { + list_delete_node (circuit->lsp_queue, node); + return retval; + } - retval = circuit->tx (circuit, lsp->level); + /* copy our lsp to the send buffer */ + stream_copy (circuit->snd_stream, lsp->pdu); - /* - * If the sending succeeded, we can del the lsp from circuits - * lsp_queue - */ - if (retval == ISIS_OK) - { - list_delete_node (circuit->lsp_queue, node); + if (isis->debugs & DEBUG_UPDATE_PACKETS) + { + zlog_debug + ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," + " lifetime %us on %s", circuit->area->area_tag, lsp->level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + circuit->interface->name); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream)); + } + + retval = circuit->tx (circuit, lsp->level); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed", + circuit->area->area_tag, lsp->level, + circuit->interface->name); + return retval; + } - /* - * On broadcast circuits also the SRMflag can be cleared - */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + /* + * If the sending succeeded, we can del the lsp from circuits + * lsp_queue + */ + list_delete_node (circuit->lsp_queue, node); - if (flags_any_set (lsp->SRMflags) == 0) - { - /* - * need to remember when we were last sent - */ - lsp->last_sent = time (NULL); - } - } - else - { - zlog_debug ("sending of level %d link state failed", lsp->level); - } - } - else - { - /* my belief is that if it wasn't his time, the lsp can be removed - * from the queue - */ - dontsend: - list_delete_node (circuit->lsp_queue, node); - } -#if 0 - /* - * If there are still LSPs send next one after lsp-interval (33 msecs) - */ - if (listcount (circuit->lsp_queue) > 0) - thread_add_timer (master, send_lsp, circuit, 1); -#endif - } + /* Set the last-cleared time if the queue is empty. */ + /* TODO: Is is possible that new lsps keep being added to the queue + * that the queue is never empty? */ + if (list_isempty (circuit->lsp_queue)) + circuit->lsp_queue_last_cleared = time (NULL); + + /* + * On broadcast circuits also the SRMflag can be cleared + */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); return retval; } @@ -2560,8 +3063,8 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, else stream_reset (circuit->snd_stream); -// fill_llc_hdr (stream); - if (level == 1) + // fill_llc_hdr (stream); + if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, circuit->snd_stream); else @@ -2586,7 +3089,10 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, stream_putw_at (circuit->snd_stream, lenp, length); retval = circuit->tx (circuit, level); + if (retval != ISIS_OK) + zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); return retval; } - diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h index 95c1ee4ff..9e215535e 100644 --- a/isisd/isis_pdu.h +++ b/isisd/isis_pdu.h @@ -95,7 +95,7 @@ struct isis_fixed_hdr u_char version2; u_char reserved; u_char max_area_addrs; -}; +} __attribute__ ((packed)); #define ISIS_FIXED_HDR_LEN 8 @@ -186,6 +186,17 @@ struct isis_link_state_hdr } __attribute__ ((packed)); #define ISIS_LSP_HDR_LEN 19 +/* + * Since the length field of LSP Entries TLV is one byte long, and each LSP + * entry is LSP_ENTRIES_LEN (16) bytes long, the maximum number of LSP entries + * can be accomodated in a TLV is + * 255 / 16 = 15. + * + * Therefore, the maximum length of the LSP Entries TLV is + * 16 * 15 + 2 (header) = 242 bytes. + */ +#define MAX_LSP_ENTRIES_TLV_SIZE 242 + #define L1_COMPLETE_SEQ_NUM 24 #define L2_COMPLETE_SEQ_NUM 25 /* @@ -241,6 +252,8 @@ int isis_receive (struct thread *thread); #define ISIS_SNP_PSNP_FLAG 0 #define ISIS_SNP_CSNP_FLAG 1 +#define ISIS_AUTH_MD5_SIZE 16U + /* * Sending functions */ @@ -258,8 +271,4 @@ int ack_lsp (struct isis_link_state_hdr *hdr, void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type); int send_hello (struct isis_circuit *circuit, int level); - -int authentication_check (struct isis_passwd *one, - struct isis_passwd *theother); - #endif /* _ZEBRA_ISIS_PDU_H */ diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 9e4165e35..42947b22c 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -134,7 +134,7 @@ open_packet_socket (struct isis_circuit *circuit) circuit->fd = fd; - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + if (if_is_broadcast (circuit->interface)) { /* * Join to multicast groups @@ -142,24 +142,22 @@ open_packet_socket (struct isis_circuit *circuit) * 8.4.2 - Broadcast subnetwork IIH PDUs * FIXME: is there a case only one will fail?? */ - if (circuit->circuit_is_type & IS_LEVEL_1) - { - /* joining ALL_L1_ISS */ - retval = isis_multicast_join (circuit->fd, 1, - circuit->interface->ifindex); - /* joining ALL_ISS */ - retval = isis_multicast_join (circuit->fd, 3, - circuit->interface->ifindex); - } - if (circuit->circuit_is_type & IS_LEVEL_2) - /* joining ALL_L2_ISS */ - retval = isis_multicast_join (circuit->fd, 2, - circuit->interface->ifindex); + if (circuit->is_type & IS_LEVEL_1) + /* joining ALL_L1_ISS */ + retval = isis_multicast_join (circuit->fd, 1, + circuit->interface->ifindex); + if (circuit->is_type & IS_LEVEL_2) + /* joining ALL_L2_ISS */ + retval = isis_multicast_join (circuit->fd, 2, + circuit->interface->ifindex); + /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */ + retval = isis_multicast_join (circuit->fd, 3, + circuit->interface->ifindex); } else { retval = - isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex); + isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex); } return retval; @@ -184,12 +182,13 @@ isis_sock_init (struct isis_circuit *circuit) goto end; } - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + /* Assign Rx and Tx callbacks are based on real if type */ + if (if_is_broadcast (circuit->interface)) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } - else if (circuit->circ_type == CIRCUIT_T_P2P) + else if (if_is_pointopoint (circuit->interface)) { circuit->tx = isis_send_pdu_p2p; circuit->rx = isis_recv_pdu_p2p; @@ -234,13 +233,14 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) if (bytesread < 0) { - zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s", - circuit->fd, safe_strerror (errno)); - zlog_warn ("circuit is %s", circuit->interface->name); - zlog_warn ("circuit fd %d", circuit->fd); - zlog_warn ("bytesread %d", bytesread); + zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, " + "recvfrom(): %s", + circuit->interface->name, circuit->fd, bytesread, + safe_strerror (errno)); /* get rid of the packet */ - bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff)); + bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), + MSG_DONTWAIT, (struct sockaddr *) &s_addr, + (socklen_t *) &addr_len); return ISIS_WARNING; } /* @@ -249,15 +249,22 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ - bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff)); + bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), + MSG_DONTWAIT, (struct sockaddr *) &s_addr, + (socklen_t *) &addr_len); if (bytesread < 0) - zlog_warn ("isis_recv_pdu_bcast(): read() failed"); + zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed"); return ISIS_WARNING; } /* on lan we have to read to the static buff first */ - bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0, + bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); + if (bytesread < 0) + { + zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed"); + return ISIS_WARNING; + } /* then we lose the LLC */ stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN); @@ -285,9 +292,11 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) if (s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ - bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff)); + bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), + MSG_DONTWAIT, (struct sockaddr *) &s_addr, + (socklen_t *) &addr_len); if (bytesread < 0) - zlog_warn ("isis_recv_pdu_p2p(): read() failed"); + zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed"); return ISIS_WARNING; } @@ -309,6 +318,9 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { + struct msghdr msg; + struct iovec iov[2]; + /* we need to do the LLC in here because of P2P circuits, which will * not need it */ @@ -321,7 +333,10 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; - if (level == 1) + /* RFC5309 section 4.1 recommends ALL_ISS */ + if (circuit->circ_type == CIRCUIT_T_P2P) + memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN); + else if (level == 1) memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN); else memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN); @@ -332,14 +347,17 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) sock_buff[1] = 0xFE; sock_buff[2] = 0x03; - /* then we copy the data */ - memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, - stream_get_endp (circuit->snd_stream)); + memset (&msg, 0, sizeof (msg)); + msg.msg_name = &sa; + msg.msg_namelen = sizeof (struct sockaddr_ll); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + iov[0].iov_base = sock_buff; + iov[0].iov_len = LLC_LEN; + iov[1].iov_base = circuit->snd_stream->data; + iov[1].iov_len = stream_get_endp (circuit->snd_stream); - /* now we can send this */ - written = sendto (circuit->fd, sock_buff, - stream_get_endp(circuit->snd_stream) + LLC_LEN, 0, - (struct sockaddr *) &sa, sizeof (struct sockaddr_ll)); + written = sendmsg (circuit->fd, &msg, 0); return ISIS_OK; } @@ -347,7 +365,6 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { - int written = 1; struct sockaddr_ll sa; diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 1286486ce..96d8df8fa 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -36,6 +36,7 @@ #include "isis_constants.h" #include "isis_common.h" +#include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" @@ -48,9 +49,6 @@ #include "isis_route.h" #include "isis_zebra.h" -extern struct isis *isis; -extern struct thread_master *master; - static struct isis_nexthop * isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) { @@ -294,14 +292,24 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, { rinfo->nexthops = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) - adjinfo2nexthop (rinfo->nexthops, adj); + { + /* check for force resync this route */ + if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) + SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + adjinfo2nexthop (rinfo->nexthops, adj); + } } #ifdef HAVE_IPV6 if (family == AF_INET6) { rinfo->nexthops6 = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) - adjinfo2nexthop6 (rinfo->nexthops6, adj); + { + /* check for force resync this route */ + if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) + SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + adjinfo2nexthop6 (rinfo->nexthops6, adj); + } } #endif /* HAVE_IPV6 */ @@ -353,18 +361,25 @@ isis_route_info_same (struct isis_route_info *new, #ifdef HAVE_IPV6 struct isis_nexthop6 *nexthop6; #endif /* HAVE_IPV6 */ + + if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return 0; + + if (CHECK_FLAG (new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) + return 0; + if (!isis_route_info_same_attrib (new, old)) return 0; if (family == AF_INET) { for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop)) - if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) + if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) == 0) return 0; for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop)) - if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) + if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) == 0) return 0; } @@ -386,65 +401,6 @@ isis_route_info_same (struct isis_route_info *new, return 1; } -static void -isis_nexthops_merge (struct list *new, struct list *old) -{ - struct listnode *node; - struct isis_nexthop *nexthop; - - for (ALL_LIST_ELEMENTS_RO (new, node, nexthop)) - { - if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex)) - continue; - listnode_add (old, nexthop); - nexthop->lock++; - } -} - -#ifdef HAVE_IPV6 -static void -isis_nexthops6_merge (struct list *new, struct list *old) -{ - struct listnode *node; - struct isis_nexthop6 *nexthop6; - - for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6)) - { - if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex)) - continue; - listnode_add (old, nexthop6); - nexthop6->lock++; - } -} -#endif /* HAVE_IPV6 */ - -static void -isis_route_info_merge (struct isis_route_info *new, - struct isis_route_info *old, u_char family) -{ - if (family == AF_INET) - isis_nexthops_merge (new->nexthops, old->nexthops); -#ifdef HAVE_IPV6 - else if (family == AF_INET6) - isis_nexthops6_merge (new->nexthops6, old->nexthops6); -#endif /* HAVE_IPV6 */ - - return; -} - -static int -isis_route_info_prefer_new (struct isis_route_info *new, - struct isis_route_info *old) -{ - if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE)) - return 1; - - if (new->cost < old->cost) - return 1; - - return 0; -} - struct isis_route_info * isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, struct list *adjacencies, struct isis_area *area, @@ -479,68 +435,32 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, if (!rinfo_old) { if (isis->debugs & DEBUG_RTE_EVENTS) - zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); - SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE); - route_node->info = rinfo_new; - return rinfo_new; - } - - if (isis->debugs & DEBUG_RTE_EVENTS) - zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag, - buff); - - if (isis_route_info_same (rinfo_new, rinfo_old, family)) - { - if (isis->debugs & DEBUG_RTE_EVENTS) - zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff); - isis_route_info_delete (rinfo_new); - route_info = rinfo_old; - } - else if (isis_route_info_same_attrib (rinfo_new, rinfo_old)) - { - /* merge the nexthop lists */ - if (isis->debugs & DEBUG_RTE_EVENTS) - zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s", - area->area_tag, buff); -#ifdef EXTREME_DEBUG - if (family == AF_INET) - { - zlog_debug ("Old nexthops"); - nexthops_print (rinfo_old->nexthops); - zlog_debug ("New nexthops"); - nexthops_print (rinfo_new->nexthops); - } - else if (family == AF_INET6) - { - zlog_debug ("Old nexthops"); - nexthops6_print (rinfo_old->nexthops6); - zlog_debug ("New nexthops"); - nexthops6_print (rinfo_new->nexthops6); - } -#endif /* EXTREME_DEBUG */ - isis_route_info_merge (rinfo_new, rinfo_old, family); - isis_route_info_delete (rinfo_new); - route_info = rinfo_old; - UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); + route_info = rinfo_new; + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } else { - if (isis_route_info_prefer_new (rinfo_new, rinfo_old)) - { - if (isis->debugs & DEBUG_RTE_EVENTS) - zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag, - buff); - isis_route_info_delete (rinfo_old); - route_info = rinfo_new; - } + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag, + buff); + if (isis_route_info_same (rinfo_new, rinfo_old, family)) + { + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, + buff); + isis_route_info_delete (rinfo_new); + route_info = rinfo_old; + } else - { - if (isis->debugs & DEBUG_RTE_EVENTS) - zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag, - buff); - isis_route_info_delete (rinfo_new); - route_info = rinfo_old; - } + { + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag, + buff); + isis_route_info_delete (rinfo_old); + route_info = rinfo_new; + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + } } SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE); @@ -570,7 +490,7 @@ isis_route_delete (struct prefix *prefix, struct route_table *table) return; } - if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) + if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) { UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) @@ -600,10 +520,12 @@ isis_route_validate_table (struct isis_area *area, struct route_table *table) if (isis->debugs & DEBUG_RTE_EVENTS) { prefix2str (&rnode->p, (char *) buff, BUFSIZ); - zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s", + zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s", area->area_tag, - (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ? - "sync'ed" : "nosync"), + (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ? + "synced" : "not-synced"), + (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ? + "resync" : "not-resync"), (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ? "active" : "inactive"), buff); } @@ -706,41 +628,55 @@ isis_route_validate_merge (struct isis_area *area, int family) /* Walk through route tables and propagate necessary changes into RIB. In case * of L1L2 area, level tables have to be merged at first. */ -int -isis_route_validate (struct thread *thread) +void +isis_route_validate (struct isis_area *area) { - struct isis_area *area; - - area = THREAD_ARG (thread); + struct listnode *node; + struct isis_circuit *circuit; if (area->is_type == IS_LEVEL_1) - { - isis_route_validate_table (area, area->route_table[0]); - goto validate_ipv6; - } - if (area->is_type == IS_LEVEL_2) - { - isis_route_validate_table (area, area->route_table[1]); - goto validate_ipv6; - } - - isis_route_validate_merge (area, AF_INET); + isis_route_validate_table (area, area->route_table[0]); + else if (area->is_type == IS_LEVEL_2) + isis_route_validate_table (area, area->route_table[1]); + else + isis_route_validate_merge (area, AF_INET); -validate_ipv6: #ifdef HAVE_IPV6 if (area->is_type == IS_LEVEL_1) + isis_route_validate_table (area, area->route_table6[0]); + else if (area->is_type == IS_LEVEL_2) + isis_route_validate_table (area, area->route_table6[1]); + else + isis_route_validate_merge (area, AF_INET6); +#endif + + /* walk all circuits and reset any spf specific flags */ + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); + + return; +} + +void +isis_route_invalidate_table (struct isis_area *area, struct route_table *table) +{ + struct route_node *rode; + struct isis_route_info *rinfo; + for (rode = route_top (table); rode; rode = route_next (rode)) { - isis_route_validate_table (area, area->route_table6[0]); - return ISIS_OK; - } - if (area->is_type == IS_LEVEL_2) - { - isis_route_validate_table (area, area->route_table6[1]); - return ISIS_OK; - } + if (rode->info == NULL) + continue; + rinfo = rode->info; - isis_route_validate_merge (area, AF_INET6); -#endif + UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); + } +} - return ISIS_OK; +void +isis_route_invalidate (struct isis_area *area) +{ + if (area->is_type & IS_LEVEL_1) + isis_route_invalidate_table (area, area->route_table[0]); + if (area->is_type & IS_LEVEL_2) + isis_route_invalidate_table (area, area->route_table[1]); } diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 4eac79b86..1312400c8 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -43,8 +43,9 @@ struct isis_nexthop struct isis_route_info { -#define ISIS_ROUTE_FLAG_ZEBRA_SYNC 0x01 -#define ISIS_ROUTE_FLAG_ACTIVE 0x02 +#define ISIS_ROUTE_FLAG_ACTIVE 0x01 /* active route for the prefix */ +#define ISIS_ROUTE_FLAG_ZEBRA_SYNCED 0x02 /* set when route synced to zebra */ +#define ISIS_ROUTE_FLAG_ZEBRA_RESYNC 0x04 /* set when route needs to sync */ u_char flag; u_int32_t cost; u_int32_t depth; @@ -59,6 +60,9 @@ struct isis_route_info *isis_route_create (struct prefix *prefix, struct list *adjacencies, struct isis_area *area, int level); -int isis_route_validate (struct thread *thread); +void isis_route_validate (struct isis_area *area); +void isis_route_invalidate_table (struct isis_area *area, + struct route_table *table); +void isis_route_invalidate (struct isis_area *area); #endif /* _ZEBRA_ISIS_ROUTE_H */ diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index cff0fa3ff..558d39102 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -35,6 +35,7 @@ #include "isis_constants.h" #include "isis_common.h" +#include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 5d7e9da42..a91742b62 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -36,6 +36,7 @@ #include "isis_constants.h" #include "isis_common.h" +#include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" @@ -49,10 +50,6 @@ #include "isis_route.h" #include "isis_csm.h" -extern struct isis *isis; -extern struct thread_master *master; -extern struct host host; - int isis_run_spf_l1 (struct thread *thread); int isis_run_spf_l2 (struct thread *thread); @@ -113,7 +110,6 @@ remove_excess_adjs (struct list *adjs) return; } -#ifdef EXTREME_DEBUG static const char * vtype2string (enum vertextype vtype) { @@ -164,12 +160,12 @@ vid2string (struct isis_vertex *vertex, u_char * buff) { case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: - return rawlspid_print (vertex->N.id); + return print_sys_hostname (vertex->N.id); break; case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: case VTYPE_ES: - return sysid_print (vertex->N.id); + return print_sys_hostname (vertex->N.id); break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: @@ -186,149 +182,260 @@ vid2string (struct isis_vertex *vertex, u_char * buff) return (char *) buff; } -#endif /* EXTREME_DEBUG */ -static struct isis_spftree * -isis_spftree_new () +static struct isis_vertex * +isis_vertex_new (void *id, enum vertextype vtype) { - struct isis_spftree *tree; + struct isis_vertex *vertex; - tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree)); - if (tree == NULL) + vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); + if (vertex == NULL) { - zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!"); + zlog_err ("isis_vertex_new Out of memory!"); return NULL; } - tree->tents = list_new (); - tree->paths = list_new (); - return tree; + vertex->type = vtype; + switch (vtype) + { + case VTYPE_ES: + case VTYPE_NONPSEUDO_IS: + case VTYPE_NONPSEUDO_TE_IS: + memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); + break; + case VTYPE_PSEUDO_IS: + case VTYPE_PSEUDO_TE_IS: + memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); + break; + case VTYPE_IPREACH_INTERNAL: + case VTYPE_IPREACH_EXTERNAL: + case VTYPE_IPREACH_TE: +#ifdef HAVE_IPV6 + case VTYPE_IP6REACH_INTERNAL: + case VTYPE_IP6REACH_EXTERNAL: +#endif /* HAVE_IPV6 */ + memcpy (&vertex->N.prefix, (struct prefix *) id, + sizeof (struct prefix)); + break; + default: + zlog_err ("WTF!"); + } + + vertex->Adj_N = list_new (); + vertex->parents = list_new (); + vertex->children = list_new (); + + return vertex; } static void isis_vertex_del (struct isis_vertex *vertex) { list_delete (vertex->Adj_N); + vertex->Adj_N = NULL; + list_delete (vertex->parents); + vertex->parents = NULL; + list_delete (vertex->children); + vertex->children = NULL; + memset(vertex, 0, sizeof(struct isis_vertex)); XFREE (MTYPE_ISIS_VERTEX, vertex); return; } -#if 0 /* HT: Not used yet. */ static void +isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj) +{ + struct listnode *node, *nextnode; + if (!vertex) + return; + for (node = listhead (vertex->Adj_N); node; node = nextnode) + { + nextnode = listnextnode(node); + if (listgetdata(node) == adj) + list_delete_node(vertex->Adj_N, node); + } + return; +} + +struct isis_spftree * +isis_spftree_new (struct isis_area *area) +{ + struct isis_spftree *tree; + + tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree)); + if (tree == NULL) + { + zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!"); + return NULL; + } + + tree->tents = list_new (); + tree->paths = list_new (); + tree->area = area; + tree->lastrun = 0; + tree->runcount = 0; + tree->pending = 0; + return tree; +} + +void isis_spftree_del (struct isis_spftree *spftree) { + THREAD_TIMER_OFF (spftree->t_spf); + spftree->tents->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->tents); + spftree->tents = NULL; spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->paths); + spftree->paths = NULL; XFREE (MTYPE_ISIS_SPFTREE, spftree); return; } -#endif + +void +isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj) +{ + struct listnode *node; + if (!adj) + return; + for (node = listhead (spftree->tents); node; node = listnextnode (node)) + isis_vertex_adj_del (listgetdata (node), adj); + for (node = listhead (spftree->paths); node; node = listnextnode (node)) + isis_vertex_adj_del (listgetdata (node), adj); + return; +} void spftree_area_init (struct isis_area *area) { - if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL) - { - area->spftree[0] = isis_spftree_new (); + if (area->is_type & IS_LEVEL_1) + { + if (area->spftree[0] == NULL) + area->spftree[0] = isis_spftree_new (area); #ifdef HAVE_IPV6 - area->spftree6[0] = isis_spftree_new (); + if (area->spftree6[0] == NULL) + area->spftree6[0] = isis_spftree_new (area); #endif + } - /* thread_add_timer (master, isis_run_spf_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */ - } - - if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL) - { - area->spftree[1] = isis_spftree_new (); + if (area->is_type & IS_LEVEL_2) + { + if (area->spftree[1] == NULL) + area->spftree[1] = isis_spftree_new (area); #ifdef HAVE_IPV6 - area->spftree6[1] = isis_spftree_new (); + if (area->spftree6[1] == NULL) + area->spftree6[1] = isis_spftree_new (area); #endif - /* thread_add_timer (master, isis_run_spf_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */ - } + } return; } -static struct isis_vertex * -isis_vertex_new (void *id, enum vertextype vtype) +void +spftree_area_del (struct isis_area *area) { - struct isis_vertex *vertex; - - vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); - if (vertex == NULL) + if (area->is_type & IS_LEVEL_1) + { + if (area->spftree[0] != NULL) { - zlog_err ("isis_vertex_new Out of memory!"); - return NULL; + isis_spftree_del (area->spftree[0]); + area->spftree[0] = NULL; + } +#ifdef HAVE_IPV6 + if (area->spftree6[0]) + { + isis_spftree_del (area->spftree6[0]); + area->spftree6[0] = NULL; } +#endif + } - vertex->type = vtype; - switch (vtype) + if (area->is_type & IS_LEVEL_2) + { + if (area->spftree[1] != NULL) { - case VTYPE_ES: - case VTYPE_NONPSEUDO_IS: - case VTYPE_NONPSEUDO_TE_IS: - memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); - break; - case VTYPE_PSEUDO_IS: - case VTYPE_PSEUDO_TE_IS: - memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); - break; - case VTYPE_IPREACH_INTERNAL: - case VTYPE_IPREACH_EXTERNAL: - case VTYPE_IPREACH_TE: + isis_spftree_del (area->spftree[1]); + area->spftree[1] = NULL; + } #ifdef HAVE_IPV6 - case VTYPE_IP6REACH_INTERNAL: - case VTYPE_IP6REACH_EXTERNAL: -#endif /* HAVE_IPV6 */ - memcpy (&vertex->N.prefix, (struct prefix *) id, - sizeof (struct prefix)); - break; - default: - zlog_err ("WTF!"); + if (area->spftree[1] != NULL) + { + isis_spftree_del (area->spftree6[1]); + area->spftree6[1] = NULL; } +#endif + } - vertex->Adj_N = list_new (); + return; +} - return vertex; +void +spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj) +{ + if (area->is_type & IS_LEVEL_1) + { + if (area->spftree[0] != NULL) + isis_spftree_adj_del (area->spftree[0], adj); +#ifdef HAVE_IPV6 + if (area->spftree6[0] != NULL) + isis_spftree_adj_del (area->spftree6[0], adj); +#endif + } + + if (area->is_type & IS_LEVEL_2) + { + if (area->spftree[1] != NULL) + isis_spftree_adj_del (area->spftree[1], adj); +#ifdef HAVE_IPV6 + if (area->spftree6[1] != NULL) + isis_spftree_adj_del (area->spftree6[1], adj); +#endif + } + + return; +} + +/* + * Find the system LSP: returns the LSP in our LSP database + * associated with the given system ID. + */ +static struct isis_lsp * +isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid) +{ + u_char lspid[ISIS_SYS_ID_LEN + 2]; + + memcpy (lspid, sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (lspid) = 0; + LSP_FRAGMENT (lspid) = 0; + return (lsp_search (lspid, area->lspdb[level - 1])); } /* * Add this IS to the root of SPT */ -static void -isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area, - int level) +static struct isis_vertex * +isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid) { struct isis_vertex *vertex; struct isis_lsp *lsp; - u_char lspid[ISIS_SYS_ID_LEN + 2]; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif /* EXTREME_DEBUG */ - memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID (lspid) = 0; - LSP_FRAGMENT (lspid) = 0; - - lsp = lsp_search (lspid, area->lspdb[level - 1]); + lsp = isis_root_system_lsp (spftree->area, level, sysid); if (lsp == NULL) zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level); - if (!area->oldmetric) - vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_TE_IS); + if (!spftree->area->oldmetric) + vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS); else - vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS); - - vertex->lsp = lsp; + vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS); listnode_add (spftree->paths, vertex); @@ -338,7 +445,7 @@ isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area, vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ - return; + return vertex; } static struct isis_vertex * @@ -390,34 +497,49 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype) */ static struct isis_vertex * isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, - void *id, struct isis_adjacency *adj, u_int32_t cost, - int depth, int family) + void *id, uint32_t cost, int depth, int family, + struct isis_adjacency *adj, struct isis_vertex *parent) { struct isis_vertex *vertex, *v; struct listnode *node; + struct isis_adjacency *parent_adj; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif + assert (isis_find_vertex (spftree->paths, id, vtype) == NULL); + assert (isis_find_vertex (spftree->tents, id, vtype) == NULL); vertex = isis_vertex_new (id, vtype); vertex->d_N = cost; vertex->depth = depth; - if (adj) + if (parent) { + listnode_add (vertex->parents, parent); + if (listnode_lookup (parent->children, vertex) == NULL) + listnode_add (parent->children, vertex); + } + + if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) { + for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj)) + listnode_add (vertex->Adj_N, parent_adj); + } else if (adj) { listnode_add (vertex->Adj_N, adj); + } + #ifdef EXTREME_DEBUG - zlog_debug ("ISIS-Spf: add to TENT %s %s depth %d dist %d", + zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d", + print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vid2string (vertex, buff), - vertex->depth, vertex->d_N); + vertex->depth, vertex->d_N, listcount(vertex->Adj_N)); #endif /* EXTREME_DEBUG */ - listnode_add (spftree->tents, vertex); + if (list_isempty (spftree->tents)) { listnode_add (spftree->tents, vertex); return vertex; } - - /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */ + + /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */ for (node = listhead (spftree->tents); node; node = listnextnode (node)) { v = listgetdata (node); @@ -426,35 +548,24 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, list_add_node_prev (spftree->tents, node, vertex); break; } - else if (v->d_N == vertex->d_N) + else if (v->d_N == vertex->d_N && v->type > vertex->type) { /* Tie break, add according to type */ - while (v && v->d_N == vertex->d_N && v->type > vertex->type) - { - if (v->type > vertex->type) - { - break; - } - /* XXX: this seems dubious, node is the loop iterator */ - node = listnextnode (node); - (node) ? (v = listgetdata (node)) : (v = NULL); - } - list_add_node_prev (spftree->tents, node, vertex); - break; - } - else if (node->next == NULL) - { - list_add_node_next (spftree->tents, node, vertex); + list_add_node_prev (spftree->tents, node, vertex); break; } } + + if (node == NULL) + listnode_add (spftree->tents, vertex); + return vertex; } -static struct isis_vertex * +static void isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, - void *id, struct isis_adjacency *adj, u_int32_t cost, - int family) + void *id, struct isis_adjacency *adj, uint32_t cost, + int family, struct isis_vertex *parent) { struct isis_vertex *vertex; @@ -470,40 +581,65 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, /* d) */ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs (vertex->Adj_N); + if (parent && (listnode_lookup (vertex->parents, parent) == NULL)) + listnode_add (vertex->parents, parent); + if (parent && (listnode_lookup (parent->children, vertex) == NULL)) + listnode_add (parent->children, vertex); + return; } - /* f) */ - else if (vertex->d_N > cost) + else if (vertex->d_N < cost) { - listnode_delete (spftree->tents, vertex); - goto add2tent; + /* e) do nothing */ + return; } - /* e) do nothing */ - return vertex; + else { /* vertex->d_N > cost */ + /* f) */ + struct listnode *pnode, *pnextnode; + struct isis_vertex *pvertex; + listnode_delete (spftree->tents, vertex); + assert (listcount (vertex->children) == 0); + for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex)) + listnode_delete(pvertex->children, vertex); + isis_vertex_del (vertex); + } } -add2tent: - return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family); + isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent); + return; } static void process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, - u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj, - int family) + uint32_t dist, uint16_t depth, int family, + struct isis_vertex *parent) { struct isis_vertex *vertex; #ifdef EXTREME_DEBUG u_char buff[255]; #endif + assert (spftree && parent); + + /* RFC3787 section 5.1 */ + if (spftree->area->newmetric == 1) + { + if (dist > MAX_WIDE_PATH_METRIC) + return; + } /* C.2.6 b) */ - if (dist > MAX_PATH_METRIC) - return; + else if (spftree->area->oldmetric == 1) + { + if (dist > MAX_NARROW_PATH_METRIC) + return; + } + /* c) */ vertex = isis_find_vertex (spftree->paths, id, vtype); if (vertex) { #ifdef EXTREME_DEBUG - zlog_debug ("ISIS-Spf: process_N %s %s dist %d already found from PATH", + zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH", + print_sys_hostname (vertex->N.id), vtype2string (vtype), vid2string (vertex, buff), dist); #endif /* EXTREME_DEBUG */ assert (dist >= vertex->d_N); @@ -516,16 +652,26 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, { /* 1) */ #ifdef EXTREME_DEBUG - zlog_debug ("ISIS-Spf: process_N %s %s dist %d", - vtype2string (vtype), vid2string (vertex, buff), dist); + zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d", + print_sys_hostname (vertex->N.id), + vtype2string (vtype), vid2string (vertex, buff), dist, + (parent ? print_sys_hostname (parent->N.id) : "null"), + (parent ? listcount (parent->Adj_N) : 0)); #endif /* EXTREME_DEBUG */ if (vertex->d_N == dist) { - if (adj) - listnode_add (vertex->Adj_N, adj); + struct listnode *node; + struct isis_adjacency *parent_adj; + for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj)) + if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL) + listnode_add (vertex->Adj_N, parent_adj); /* 2) */ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs (vertex->Adj_N); + if (listnode_lookup (vertex->parents, parent) == NULL) + listnode_add (vertex->parents, parent); + if (listnode_lookup (parent->children, vertex) == NULL) + listnode_add (parent->children, vertex); /* 3) */ return; } @@ -536,11 +682,23 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, } else { + struct listnode *pnode, *pnextnode; + struct isis_vertex *pvertex; listnode_delete (spftree->tents, vertex); + assert (listcount (vertex->children) == 0); + for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex)) + listnode_delete(pvertex->children, vertex); + isis_vertex_del (vertex); } } - isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family); +#ifdef EXTREME_DEBUG + zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s", + print_sys_hostname(id), vtype2string (vtype), dist, + (parent ? print_sys_hostname (parent->N.id) : "null")); +#endif /* EXTREME_DEBUG */ + + isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent); return; } @@ -549,10 +707,11 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, */ static int isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, - uint32_t cost, uint16_t depth, int family) + uint32_t cost, uint16_t depth, int family, + u_char *root_sysid, struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; - u_int16_t dist; + uint32_t dist; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipreach; @@ -562,117 +721,121 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, #ifdef HAVE_IPV6 struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ + static const u_char null_sysid[ISIS_SYS_ID_LEN]; - - if (!lsp->adj) - return ISIS_WARNING; - if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family)) + if (!speaks (lsp->tlv_data.nlpids, family)) return ISIS_OK; lspfragloop: if (lsp->lsp_header->seq_num == 0) { - zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num" - " - do not process"); + zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore"); return ISIS_WARNING; } +#ifdef EXTREME_DEBUG + zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); +#endif /* EXTREME_DEBUG */ + if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) + { + if (lsp->tlv_data.is_neighs) { - if (lsp->tlv_data.is_neighs) - { - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) - { - /* C.2.6 a) */ - /* Two way connectivity */ - if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) - continue; - dist = cost + is_neigh->metrics.metric_default; - vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS - : VTYPE_NONPSEUDO_IS; - process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, - depth + 1, lsp->adj, family); - } - } - if (lsp->tlv_data.te_is_neighs) - { - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, - te_is_neigh)) - { - uint32_t metric; - if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) - continue; - memcpy (&metric, te_is_neigh->te_metric, 3); - dist = cost + ntohl (metric << 8); - vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS; - process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, - depth + 1, lsp->adj, family); - } - } - if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, - node, ipreach)) - { - dist = cost + ipreach->metrics.metric_default; - vtype = VTYPE_IPREACH_INTERNAL; - prefix.u.prefix4 = ipreach->prefix; - prefix.prefixlen = ip_masklen (ipreach->mask); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); - } - } + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) + { + /* C.2.6 a) */ + /* Two way connectivity */ + if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) + continue; + if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) + continue; + dist = cost + is_neigh->metrics.metric_default; + vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS + : VTYPE_NONPSEUDO_IS; + process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, + depth + 1, family, parent); + } + } + if (lsp->tlv_data.te_is_neighs) + { + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, + te_is_neigh)) + { + if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) + continue; + if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) + continue; + dist = cost + GET_TE_METRIC(te_is_neigh); + vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS + : VTYPE_NONPSEUDO_TE_IS; + process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, + depth + 1, family, parent); + } + } + } - if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, - node, ipreach)) - { - dist = cost + ipreach->metrics.metric_default; - vtype = VTYPE_IPREACH_EXTERNAL; - prefix.u.prefix4 = ipreach->prefix; - prefix.prefixlen = ip_masklen (ipreach->mask); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); - } - } - if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, - node, te_ipv4_reach)) - { - dist = cost + ntohl (te_ipv4_reach->te_metric); - vtype = VTYPE_IPREACH_TE; - prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, - te_ipv4_reach->control); - prefix.prefixlen = (te_ipv4_reach->control & 0x3F); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); - } - } + if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) + { + prefix.family = AF_INET; + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach)) + { + dist = cost + ipreach->metrics.metric_default; + vtype = VTYPE_IPREACH_INTERNAL; + prefix.u.prefix4 = ipreach->prefix; + prefix.prefixlen = ip_masklen (ipreach->mask); + apply_mask (&prefix); + process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, + family, parent); + } + } + if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) + { + prefix.family = AF_INET; + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach)) + { + dist = cost + ipreach->metrics.metric_default; + vtype = VTYPE_IPREACH_EXTERNAL; + prefix.u.prefix4 = ipreach->prefix; + prefix.prefixlen = ip_masklen (ipreach->mask); + apply_mask (&prefix); + process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, + family, parent); + } + } + if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) + { + prefix.family = AF_INET; + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, + node, te_ipv4_reach)) + { + dist = cost + ntohl (te_ipv4_reach->te_metric); + vtype = VTYPE_IPREACH_TE; + prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, + te_ipv4_reach->control); + prefix.prefixlen = (te_ipv4_reach->control & 0x3F); + apply_mask (&prefix); + process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, + family, parent); + } + } #ifdef HAVE_IPV6 - if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) - { - prefix.family = AF_INET6; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, - node, ip6reach)) - { - dist = cost + ip6reach->metric; - vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? - VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; - prefix.prefixlen = ip6reach->prefix_len; - memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix, - PSIZE (ip6reach->prefix_len)); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); - } - } -#endif /* HAVE_IPV6 */ + if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) + { + prefix.family = AF_INET6; + for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach)) + { + dist = cost + ip6reach->metric; + vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? + VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; + prefix.prefixlen = ip6reach->prefix_len; + memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix, + PSIZE (ip6reach->prefix_len)); + apply_mask (&prefix); + process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, + family, parent); } + } +#endif /* HAVE_IPV6 */ if (fragnode == NULL) fragnode = listhead (lsp->lspu.frags); @@ -690,13 +853,16 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, static int isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, - struct isis_lsp *lsp, uint16_t cost, - uint16_t depth, int family) + struct isis_lsp *lsp, uint32_t cost, + uint16_t depth, int family, + u_char *root_sysid, + struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; enum vertextype vtype; + uint32_t dist; pseudofragloop: @@ -707,41 +873,36 @@ isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, return ISIS_WARNING; } +#ifdef EXTREME_DEBUG + zlog_debug ("ISIS-Spf: process_pseudo_lsp %s", + print_sys_hostname(lsp->lsp_header->lsp_id)); +#endif /* EXTREME_DEBUG */ + + /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ + if (lsp->tlv_data.is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { - vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS - : VTYPE_NONPSEUDO_IS; /* Two way connectivity */ - if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) + if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; - if (isis_find_vertex - (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL - && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id, - vtype) == NULL) - { - /* C.2.5 i) */ - isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj, - cost, depth, family); - } + dist = cost + is_neigh->metrics.metric_default; + vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS + : VTYPE_NONPSEUDO_IS; + process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, + depth + 1, family, parent); } if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { - vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS; /* Two way connectivity */ - if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) + if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; - if (isis_find_vertex - (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL - && isis_find_vertex (spftree->paths, (void *) te_is_neigh->neigh_id, - vtype) == NULL) - { - /* C.2.5 i) */ - isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, lsp->adj, - cost, depth, family); - } + dist = cost + GET_TE_METRIC(te_is_neigh); + vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS + : VTYPE_NONPSEUDO_TE_IS; + process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, + depth + 1, family, parent); } if (fragnode == NULL) @@ -759,10 +920,10 @@ isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, } static int -isis_spf_preload_tent (struct isis_spftree *spftree, - struct isis_area *area, int level, int family) +isis_spf_preload_tent (struct isis_spftree *spftree, int level, + int family, u_char *root_sysid, + struct isis_vertex *parent) { - struct isis_vertex *vertex; struct isis_circuit *circuit; struct listnode *cnode, *anode, *ipnode; struct isis_adjacency *adj; @@ -773,15 +934,16 @@ isis_spf_preload_tent (struct isis_spftree *spftree, struct prefix prefix; int retval = ISIS_OK; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; + static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6; #endif /* HAVE_IPV6 */ - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) + for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit)) { if (circuit->state != C_STATE_UP) continue; - if (!(circuit->circuit_is_type & level)) + if (!(circuit->is_type & level)) continue; if (family == AF_INET && !circuit->ip_router) continue; @@ -799,8 +961,9 @@ isis_spf_preload_tent (struct isis_spftree *spftree, { prefix.u.prefix4 = ipv4->prefix; prefix.prefixlen = ipv4->prefixlen; + apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, - NULL, 0, family); + NULL, 0, family, parent); } } #ifdef HAVE_IPV6 @@ -811,8 +974,9 @@ isis_spf_preload_tent (struct isis_spftree *spftree, { prefix.prefixlen = ipv6->prefixlen; prefix.u.prefix6 = ipv6->prefix; + apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL, - &prefix, NULL, 0, family); + &prefix, NULL, 0, family, parent); } } #endif /* HAVE_IPV6 */ @@ -832,43 +996,41 @@ isis_spf_preload_tent (struct isis_spftree *spftree, level, circuit->interface->name); continue; } - anode = listhead (adj_list); - while (anode) + for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj)) { - adj = listgetdata (anode); if (!speaks (&adj->nlpids, family)) - { - anode = listnextnode (anode); continue; - } switch (adj->sys_type) { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, - circuit->te_metric[level - 1], family); + circuit->te_metric[level - 1], + family, parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: - vertex = - isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, - adj->sysid, adj, - circuit->te_metric[level - 1], family); + isis_spf_add_local (spftree, + spftree->area->oldmetric ? + VTYPE_NONPSEUDO_IS : + VTYPE_NONPSEUDO_TE_IS, + adj->sysid, adj, + circuit->te_metric[level - 1], + family, parent); memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = 0; LSP_FRAGMENT (lsp_id) = 0; - lsp = lsp_search (lsp_id, area->lspdb[level - 1]); + lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); if (!lsp) - zlog_warn ("No lsp found for IS adjacency"); - /* else { - isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family); - } */ + zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency " + "L%d on %s (ID %u)", + rawlspid_print (lsp_id), level, + circuit->interface->name, circuit->circuit_id); break; case ISIS_SYSTYPE_UNKNOWN: default: zlog_warn ("isis_spf_preload_tent unknow adj type"); } - anode = listnextnode (anode); } list_delete (adj_list); /* @@ -878,23 +1040,36 @@ isis_spf_preload_tent (struct isis_spftree *spftree, memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); - lsp = lsp_search (lsp_id, area->lspdb[level - 1]); + /* can happen during DR reboot */ + if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0) + { + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)", + level, circuit->interface->name, circuit->circuit_id); + continue; + } adj = isis_adj_lookup (lsp_id, adjdb); /* if no adj, we are the dis or error */ if (!adj && !circuit->u.bc.is_dr[level - 1]) { - zlog_warn ("ISIS-Spf: No adjacency found for DR"); + zlog_warn ("ISIS-Spf: No adjacency found from root " + "to L%d DR %s on %s (ID %d)", + level, rawlspid_print (lsp_id), + circuit->interface->name, circuit->circuit_id); + continue; } + lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { - zlog_warn ("ISIS-Spf: No lsp found for DR"); - } - else - { - isis_spf_process_pseudo_lsp (spftree, lsp, - circuit->te_metric[level - 1], 0, family); - + zlog_warn ("ISIS-Spf: No lsp (%p) found from root " + "to L%d DR %s on %s (ID %d)", + lsp, level, rawlspid_print (lsp_id), + circuit->interface->name, circuit->circuit_id); + continue; } + isis_spf_process_pseudo_lsp (spftree, lsp, + circuit->te_metric[level - 1], 0, + family, root_sysid, parent); } else if (circuit->circ_type == CIRCUIT_T_P2P) { @@ -905,28 +1080,36 @@ isis_spf_preload_tent (struct isis_spftree *spftree, { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, - circuit->te_metric[level - 1], family); + circuit->te_metric[level - 1], family, + parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: if (speaks (&adj->nlpids, family)) - isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid, + isis_spf_add_local (spftree, + spftree->area->oldmetric ? + VTYPE_NONPSEUDO_IS : + VTYPE_NONPSEUDO_TE_IS, + adj->sysid, adj, circuit->te_metric[level - 1], - family); + family, parent); break; case ISIS_SYSTYPE_UNKNOWN: default: - zlog_warn ("isis_spf_preload_tent unknow adj type"); + zlog_warn ("isis_spf_preload_tent unknown adj type"); break; } } + else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) + { + continue; + } else { zlog_warn ("isis_spf_preload_tent unsupported media"); retval = ISIS_WARNING; } - } return retval; @@ -938,25 +1121,30 @@ isis_spf_preload_tent (struct isis_spftree *spftree, */ static void add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, - struct isis_area *area, int level) + int level) { -#ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; -#endif /* EXTREME_DEBUG */ + + if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) + return; listnode_add (spftree->paths, vertex); #ifdef EXTREME_DEBUG - zlog_debug ("ISIS-Spf: added %s %s depth %d dist %d to PATHS", + zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS", + print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ + if (vertex->type > VTYPE_ES) { if (listcount (vertex->Adj_N) > 0) isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N, - vertex->depth, vertex->Adj_N, area, level); + vertex->depth, vertex->Adj_N, spftree->area, level); else if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_debug ("ISIS-Spf: no adjacencies do not install route"); + zlog_debug ("ISIS-Spf: no adjacencies do not install route for " + "%s depth %d dist %d", vid2string (vertex, buff), + vertex->depth, vertex->d_N); } return; @@ -969,22 +1157,20 @@ init_spt (struct isis_spftree *spftree) list_delete_all_node (spftree->tents); list_delete_all_node (spftree->paths); spftree->tents->del = spftree->paths->del = NULL; - return; } static int -isis_run_spf (struct isis_area *area, int level, int family) +isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) { int retval = ISIS_OK; struct listnode *node; struct isis_vertex *vertex; + struct isis_vertex *root_vertex; struct isis_spftree *spftree = NULL; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; struct route_table *table = NULL; - struct route_node *rode; - struct isis_route_info *rinfo; if (family == AF_INET) spftree = area->spftree[level - 1]; @@ -992,8 +1178,8 @@ isis_run_spf (struct isis_area *area, int level, int family) else if (family == AF_INET6) spftree = area->spftree6[level - 1]; #endif - assert (spftree); + assert (sysid); /* Make all routes in current route table inactive. */ if (family == AF_INET) @@ -1003,30 +1189,28 @@ isis_run_spf (struct isis_area *area, int level, int family) table = area->route_table6[level - 1]; #endif - for (rode = route_top (table); rode; rode = route_next (rode)) - { - if (rode->info == NULL) - continue; - rinfo = rode->info; - - UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); - } + isis_route_invalidate_table (area, table); /* * C.2.5 Step 0 */ init_spt (spftree); /* a) */ - isis_spf_add_self (spftree, area, level); + root_vertex = isis_spf_add_root (spftree, level, sysid); /* b) */ - retval = isis_spf_preload_tent (spftree, area, level, family); + retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex); + if (retval != ISIS_OK) + { + zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid)); + goto out; + } /* * C.2.7 Step 2 */ if (listcount (spftree->tents) == 0) { - zlog_warn ("ISIS-Spf: TENT is empty"); + zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid)); goto out; } @@ -1034,14 +1218,22 @@ isis_run_spf (struct isis_area *area, int level, int family) { node = listhead (spftree->tents); vertex = listgetdata (node); - /* Remove from tent list */ + +#ifdef EXTREME_DEBUG + zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS", + print_sys_hostname (vertex->N.id), + vtype2string (vertex->type), vertex->depth, vertex->d_N); +#endif /* EXTREME_DEBUG */ + + /* Remove from tent list and add to paths list */ list_delete_node (spftree->tents, node); - if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) - continue; - add_to_paths (spftree, vertex, area, level); - if (vertex->type == VTYPE_PSEUDO_IS || - vertex->type == VTYPE_NONPSEUDO_IS) - { + add_to_paths (spftree, vertex, level); + switch (vertex->type) + { + case VTYPE_PSEUDO_IS: + case VTYPE_NONPSEUDO_IS: + case VTYPE_PSEUDO_TE_IS: + case VTYPE_NONPSEUDO_TE_IS: memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); @@ -1050,13 +1242,13 @@ isis_run_spf (struct isis_area *area, int level, int family) if (LSP_PSEUDO_ID (lsp_id)) { isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family); - + vertex->depth, family, sysid, + vertex); } else { isis_spf_process_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family); + vertex->depth, family, sysid, vertex); } } else @@ -1064,12 +1256,15 @@ isis_run_spf (struct isis_area *area, int level, int family) zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id)); } + break; + default:; } } out: - thread_add_event (master, isis_route_validate, area, 0); + isis_route_validate (area); spftree->lastrun = time (NULL); + spftree->runcount++; spftree->pending = 0; return retval; @@ -1085,6 +1280,7 @@ isis_run_spf_l1 (struct thread *thread) assert (area); area->spftree[0]->t_spf = NULL; + area->spftree[0]->pending = 0; if (!(area->is_type & IS_LEVEL_1)) { @@ -1098,10 +1294,7 @@ isis_run_spf_l1 (struct thread *thread) zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); if (area->ip_circuits) - retval = isis_run_spf (area, 1, AF_INET); - - THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); + retval = isis_run_spf (area, 1, AF_INET, isis->sysid); return retval; } @@ -1116,6 +1309,7 @@ isis_run_spf_l2 (struct thread *thread) assert (area); area->spftree[1]->t_spf = NULL; + area->spftree[1]->pending = 0; if (!(area->is_type & IS_LEVEL_2)) { @@ -1128,10 +1322,7 @@ isis_run_spf_l2 (struct thread *thread) zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag); if (area->ip_circuits) - retval = isis_run_spf (area, 2, AF_INET); - - THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); + retval = isis_run_spf (area, 2, AF_INET, isis->sysid); return retval; } @@ -1139,53 +1330,40 @@ isis_run_spf_l2 (struct thread *thread) int isis_spf_schedule (struct isis_area *area, int level) { - int retval = ISIS_OK; struct isis_spftree *spftree = area->spftree[level - 1]; - time_t diff, now = time (NULL); - - if (spftree->pending) - return retval; + time_t now = time (NULL); + int diff = now - spftree->lastrun; - diff = now - spftree->lastrun; + assert (diff >= 0); + assert (area->is_type & level); - /* FIXME: let's wait a minute before doing the SPF */ - if (now - isis->uptime < 60 || isis->uptime == 0) - { - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60); + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", + area->area_tag, level, diff); - spftree->pending = 1; - return retval; - } + if (spftree->pending) + return ISIS_OK; THREAD_TIMER_OFF (spftree->t_spf); - if (diff < MINIMUM_SPF_INTERVAL) - { - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, - MINIMUM_SPF_INTERVAL - diff); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, - MINIMUM_SPF_INTERVAL - diff); + /* wait MINIMUM_SPF_INTERVAL before doing the SPF */ + if (diff >= MINIMUM_SPF_INTERVAL) + return isis_run_spf (area, level, AF_INET, isis->sysid); - spftree->pending = 1; - } + if (level == 1) + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, + MINIMUM_SPF_INTERVAL - diff); else - { - spftree->pending = 0; - retval = isis_run_spf (area, level, AF_INET); - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - } + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, + MINIMUM_SPF_INTERVAL - diff); - return retval; + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", + area->area_tag, level, MINIMUM_SPF_INTERVAL - diff); + + spftree->pending = 1; + + return ISIS_OK; } #ifdef HAVE_IPV6 @@ -1199,11 +1377,12 @@ isis_run_spf6_l1 (struct thread *thread) assert (area); area->spftree6[0]->t_spf = NULL; + area->spftree6[0]->pending = 0; if (!(area->is_type & IS_LEVEL_1)) { if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); + zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } @@ -1211,10 +1390,7 @@ isis_run_spf6_l1 (struct thread *thread) zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); if (area->ipv6_circuits) - retval = isis_run_spf (area, 1, AF_INET6); - - THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); + retval = isis_run_spf (area, 1, AF_INET6, isis->sysid); return retval; } @@ -1229,6 +1405,7 @@ isis_run_spf6_l2 (struct thread *thread) assert (area); area->spftree6[1]->t_spf = NULL; + area->spftree6[1]->pending = 0; if (!(area->is_type & IS_LEVEL_2)) { @@ -1241,10 +1418,7 @@ isis_run_spf6_l2 (struct thread *thread) zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag); if (area->ipv6_circuits) - retval = isis_run_spf (area, 2, AF_INET6); - - THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); + retval = isis_run_spf (area, 2, AF_INET6, isis->sysid); return retval; } @@ -1259,22 +1433,14 @@ isis_spf_schedule6 (struct isis_area *area, int level) if (spftree->pending) return retval; - diff = now - spftree->lastrun; - - /* FIXME: let's wait a minute before doing the SPF */ - if (now - isis->uptime < 60 || isis->uptime == 0) - { - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, 60); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, 60); - - spftree->pending = 1; - return retval; - } - THREAD_TIMER_OFF (spftree->t_spf); + /* FIXME: let's wait MINIMUM_SPF_INTERVAL before doing the SPF */ + if (now - isis->uptime < MINIMUM_SPF_INTERVAL || isis->uptime == 0) + diff = 0; + else + diff = now - spftree->lastrun; + if (diff < MINIMUM_SPF_INTERVAL) { if (level == 1) @@ -1288,15 +1454,7 @@ isis_spf_schedule6 (struct isis_area *area, int level) } else { - spftree->pending = 0; - retval = isis_run_spf (area, level, AF_INET6); - - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); + retval = isis_run_spf (area, level, AF_INET6, isis->sysid); } return retval; @@ -1304,54 +1462,73 @@ isis_spf_schedule6 (struct isis_area *area, int level) #endif static void -isis_print_paths (struct vty *vty, struct list *paths) +isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid) { struct listnode *node; + struct listnode *anode; struct isis_vertex *vertex; - struct isis_dynhn *dyn, *nh_dyn = NULL; struct isis_adjacency *adj; -#if 0 u_char buff[255]; -#endif /* 0 */ - vty_out (vty, "System Id Metric Next-Hop" - " Interface SNPA%s", VTY_NEWLINE); + vty_out (vty, "Vertex Type Metric " + "Next-Hop Interface Parent%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) { + if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { + vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid), + "", ""); + vty_out (vty, "%-30s", ""); + } else { + int rows = 0; + vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff), + vtype2string (vertex->type), vertex->d_N); + for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) { + if (adj) { + if (rows) { + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%-20s %-12s %-6s ", "", "", ""); + } + vty_out (vty, "%-20s %-9s ", + print_sys_hostname (adj->sysid), + adj->circuit->interface->name); + ++rows; + } + } + if (rows == 0) + vty_out (vty, "%-30s ", ""); + } - for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) - { - if (vertex->type != VTYPE_NONPSEUDO_IS) - continue; - if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0) - { - vty_out (vty, "%s --%s", host.name?host.name:"", - VTY_NEWLINE); + /* Print list of parents for the ECMP DAG */ + if (listcount (vertex->parents) > 0) { + struct listnode *pnode; + struct isis_vertex *pvertex; + int rows = 0; + for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) { + if (rows) { + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%-72s", ""); + } + vty_out (vty, "%s(%d)", + vid2string (pvertex, buff), pvertex->type); + ++rows; } - else - { - dyn = dynhn_find_by_id ((u_char *) vertex->N.id); - adj = listgetdata (listhead (vertex->Adj_N)); - if (adj) - { - nh_dyn = dynhn_find_by_id (adj->sysid); - vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s", - (dyn != NULL) ? dyn->name.name : - (const u_char *)rawlspid_print ((u_char *) vertex->N.id), - vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name : - (const u_char *)rawlspid_print (adj->sysid), - adj->circuit->interface->name, - snpa_print (adj->snpa), VTY_NEWLINE); - } - else - { - vty_out (vty, "%s %u %s", dyn ? dyn->name.name : - (const u_char *) rawlspid_print (vertex->N.id), - vertex->d_N, VTY_NEWLINE); + } else { + vty_out (vty, " NULL "); + } + +#if 0 + if (listcount (vertex->children) > 0) { + struct listnode *cnode; + struct isis_vertex *cvertex; + for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) { + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%-72s", ""); + vty_out (vty, "%s(%d) ", + vid2string (cvertex, buff), cvertex->type); } } -#if 0 - vty_out (vty, "%s %s %u %s", vtype2string (vertex->type), - vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE); #endif + vty_out (vty, "%s", VTY_NEWLINE); } } @@ -1381,7 +1558,8 @@ DEFUN (show_isis_topology, { vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s", level + 1, VTY_NEWLINE); - isis_print_paths (vty, area->spftree[level]->paths); + isis_print_paths (vty, area->spftree[level]->paths, isis->sysid); + vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[level] @@ -1390,10 +1568,13 @@ DEFUN (show_isis_topology, vty_out (vty, "IS-IS paths to level-%d routers that speak IPv6%s", level + 1, VTY_NEWLINE); - isis_print_paths (vty, area->spftree6[level]->paths); + isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid); + vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ } + + vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; @@ -1423,7 +1604,8 @@ DEFUN (show_isis_topology_l1, { vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s", VTY_NEWLINE); - isis_print_paths (vty, area->spftree[0]->paths); + isis_print_paths (vty, area->spftree[0]->paths, isis->sysid); + vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[0] @@ -1431,9 +1613,11 @@ DEFUN (show_isis_topology_l1, { vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s", VTY_NEWLINE); - isis_print_paths (vty, area->spftree6[0]->paths); + isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid); + vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ + vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; @@ -1463,7 +1647,8 @@ DEFUN (show_isis_topology_l2, { vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s", VTY_NEWLINE); - isis_print_paths (vty, area->spftree[1]->paths); + isis_print_paths (vty, area->spftree[1]->paths, isis->sysid); + vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[1] @@ -1471,9 +1656,11 @@ DEFUN (show_isis_topology_l2, { vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s", VTY_NEWLINE); - isis_print_paths (vty, area->spftree6[1]->paths); + isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid); + vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ + vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 6bdab2da6..f31b51056 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -54,25 +54,32 @@ struct isis_vertex struct prefix prefix; } N; - struct isis_lsp *lsp; u_int32_t d_N; /* d(N) Distance from this IS */ u_int16_t depth; /* The depth in the imaginary tree */ - - struct list *Adj_N; /* {Adj(N)} */ + struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ + struct list *parents; /* list of parents for ECMP */ + struct list *children; /* list of children used for tree dump */ }; struct isis_spftree { struct thread *t_spf; /* spf threads */ - time_t lastrun; /* for scheduling */ - int pending; /* already scheduled */ struct list *paths; /* the SPT */ struct list *tents; /* TENT */ - - u_int32_t timerun; /* statistics */ + struct isis_area *area; /* back pointer to area */ + int pending; /* already scheduled */ + time_t lastrun; /* for scheduling */ + unsigned int runcount; /* number of runs since uptime */ }; +struct isis_spftree * isis_spftree_new (struct isis_area *area); +void isis_spftree_del (struct isis_spftree *spftree); +void isis_spftree_adj_del (struct isis_spftree *spftree, + struct isis_adjacency *adj); void spftree_area_init (struct isis_area *area); +void spftree_area_del (struct isis_area *area); +void spftree_area_adj_del (struct isis_area *area, + struct isis_adjacency *adj); int isis_spf_schedule (struct isis_area *area, int level); void isis_spf_cmds_init (void); #ifdef HAVE_IPV6 diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 94fa65ed3..bb57bd6be 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -43,13 +43,6 @@ #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" -extern struct isis *isis; - -/* - * Prototypes. - */ -int add_tlv (u_char, u_char, u_char *, struct stream *); - void free_tlv (void *val) { @@ -75,10 +68,10 @@ free_tlvs (struct tlvs *tlvs) list_delete (tlvs->es_neighs); if (tlvs->lsp_entries) list_delete (tlvs->lsp_entries); - if (tlvs->lan_neighs) - list_delete (tlvs->lan_neighs); if (tlvs->prefix_neighs) list_delete (tlvs->prefix_neighs); + if (tlvs->lan_neighs) + list_delete (tlvs->lan_neighs); if (tlvs->ipv4_addrs) list_delete (tlvs->ipv4_addrs); if (tlvs->ipv4_int_reachs) @@ -93,7 +86,9 @@ free_tlvs (struct tlvs *tlvs) if (tlvs->ipv6_reachs) list_delete (tlvs->ipv6_reachs); #endif /* HAVE_IPV6 */ - + + memset (tlvs, 0, sizeof (struct tlvs)); + return; } @@ -103,7 +98,7 @@ free_tlvs (struct tlvs *tlvs) */ int parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, - u_int32_t * found, struct tlvs *tlvs) + u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset) { u_char type, length; struct lan_neigh *lan_nei; @@ -122,7 +117,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, #endif /* HAVE_IPV6 */ u_char virtual; int value_len, retval = ISIS_OK; - u_char *pnt = stream; + u_char *start = stream, *pnt = stream; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); @@ -443,10 +438,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, if (*expected & TLVFLAG_AUTH_INFO) { tlvs->auth_info.type = *pnt; - tlvs->auth_info.len = length-1; + if (length == 0) + { + zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) " + "incorrect.", areatag, type, length); + return ISIS_WARNING; + } + --length; + tlvs->auth_info.len = length; pnt++; - memcpy (tlvs->auth_info.passwd, pnt, length - 1); - pnt += length - 1; + memcpy (tlvs->auth_info.passwd, pnt, length); + /* Return the authentication tlv pos for later computation + * of MD5 (RFC 5304, 2) + */ + if (auth_tlv_offset) + *auth_tlv_offset += (pnt - start - 3); + pnt += length; } else { @@ -730,10 +737,14 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, int add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) { - - if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2) + if ((stream_get_size (stream) - stream_get_endp (stream)) < + (((unsigned)len) + 2)) { - zlog_warn ("No room for TLV of type %d", tag); + zlog_warn ("No room for TLV of type %d " + "(total size %d available %d required %d)", + tag, (int)stream_get_size (stream), + (int)(stream_get_size (stream) - stream_get_endp (stream)), + len+2); return ISIS_WARNING; } @@ -873,12 +884,12 @@ tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream) } int -tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value, +tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value, struct stream *stream) { u_char value[255]; u_char *pos = value; - *pos++ = ISIS_PASSWD_TYPE_CLEARTXT; + *pos++ = auth_type; memcpy (pos, auth_value, auth_len); return add_tlv (AUTH_INFO, auth_len + 1, value, stream); @@ -1002,7 +1013,6 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream) pos += IPV4_MAX_BYTELEN; } - return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); } @@ -1023,7 +1033,7 @@ tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream) if (pos - value + (5 + prefix_size) > 255) { retval = - add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); + add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; @@ -1106,7 +1116,7 @@ tlv_add_padding (struct stream *stream) /* * How many times can we add full padding ? */ - fullpads = (STREAM_SIZE (stream) - stream_get_endp (stream)) / 257; + fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257; for (i = 0; i < fullpads; i++) { if (!stream_putc (stream, (u_char) PADDING)) /* TAG */ @@ -1116,7 +1126,7 @@ tlv_add_padding (struct stream *stream) stream_put (stream, NULL, 255); /* zero padding */ } - left = STREAM_SIZE (stream) - stream_get_endp (stream); + left = stream_get_size (stream) - stream_get_endp (stream); if (left < 2) return ISIS_OK; diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index fc9f35f8a..e092f4d6d 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -30,7 +30,7 @@ * Name Value IIH LSP SNP Status * LAN * ____________________________________________________________________________ - * + * * Area Addresses 1 y y n ISO10589 * IIS Neighbors 2 n y n ISO10589 * ES Neighbors 3 n y n ISO10589 @@ -39,52 +39,52 @@ * LSP Entries 9 n n y ISO10589 * Authentication 10 y y y ISO10589, RFC3567 * Checksum 12 y n y RFC3358 - * TE IS Reachability 22 n y n RFC3784 + * TE IS Reachability 22 n y n RFC5305 * IS Alias 24 n y n RFC3786 * IP Int. Reachability 128 n y n RFC1195 * Protocols Supported 129 y y n RFC1195 * IP Ext. Reachability 130 n y n RFC1195 * IDRPI 131 n y y RFC1195 * IP Interface Address 132 y y n RFC1195 - * TE Router ID 134 n y n RFC3784 - * Extended IP Reachability 135 n y n RFC3784 + * TE Router ID 134 n y n RFC5305 + * Extended IP Reachability 135 n y n RFC5305 * Dynamic Hostname 137 n y n RFC2763 - * Shared Risk Link Group 138 n y y draft-ietf-isis-gmpls-extensions + * Shared Risk Link Group 138 n y y RFC5307 * Restart TLV 211 y n n RFC3847 - * MT IS Reachability 222 n y n draft-ietf-isis-wg-multi-topology - * MT Supported 229 y y n draft-ietf-isis-wg-multi-topology - * IPv6 Interface Address 232 y y n draft-ietf-isis_ipv6 - * MT IP Reachability 235 n y n draft-ietf-isis-wg-multi-topology - * IPv6 IP Reachability 236 n y n draft-ietf-isis_ipv6 - * MT IPv6 IP Reachability 237 n y n draft-ietf-isis-wg-multi-topology + * MT IS Reachability 222 n y n RFC5120 + * MT Supported 229 y y n RFC5120 + * IPv6 Interface Address 232 y y n RFC5308 + * MT IP Reachability 235 n y n RFC5120 + * IPv6 IP Reachability 236 n y n RFC5308 + * MT IPv6 IP Reachability 237 n y n RFC5120 * P2P Adjacency State 240 y n n RFC3373 * IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence * Router Capability 242 - - - draft-ietf-isis-caps * - * + * * IS Reachability sub-TLVs we (should) support. * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ - * Administartive group (color) 3 RFC3784 - * Link Local/Remote Identifiers 4 draft-ietf-isis-gmpls-extensions - * IPv4 interface address 6 RFC3784 - * IPv4 neighbor address 8 RFC3784 - * Maximum link bandwidth 9 RFC3784 - * Reservable link bandwidth 10 RFC3784 - * Unreserved bandwidth 11 RFC3784 - * TE Default metric 18 RFC3784 - * Link Protection Type 20 draft-ietf-isis-gmpls-extensions - * Interface Switching Capability 21 draft-ietf-isis-gmpls-extensions + * Administartive group (color) 3 RFC5305 + * Link Local/Remote Identifiers 4 RFC5307 + * IPv4 interface address 6 RFC5305 + * IPv4 neighbor address 8 RFC5305 + * Maximum link bandwidth 9 RFC5305 + * Reservable link bandwidth 10 RFC5305 + * Unreserved bandwidth 11 RFC5305 + * TE Default metric 18 RFC5305 + * Link Protection Type 20 RFC5307 + * Interface Switching Capability 21 RFC5307 + * * - * * IP Reachability sub-TLVs we (should) support. * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ - * 32bit administrative tag 1 draft-ietf-isis-admin-tags - * 64bit administrative tag 2 draft-ietf-isis-admin-tags - * Management prefix color 117 draft-ietf-isis-wg-multi-topology + * 32bit administrative tag 1 RFC5130 + * 64bit administrative tag 2 RFC5130 + * Management prefix color 117 RFC5120 */ #define AREA_ADDRESSES 1 @@ -110,11 +110,14 @@ #define IPV6_REACHABILITY 236 #define WAY3_HELLO 240 +#define AUTH_INFO_HDRLEN 3 + #define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5) #define LAN_NEIGHBOURS_LEN 6 #define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */ #define IPV4_REACH_LEN 12 #define IPV6_REACH_LEN 22 +#define TE_IPV4_REACH_LEN 9 /* struct for neighbor */ struct is_neigh @@ -131,6 +134,15 @@ struct te_is_neigh u_char sub_tlvs_length; }; +/* Decode and encode three-octet metric into host byte order integer */ +#define GET_TE_METRIC(t) \ + (((unsigned)(t)->te_metric[0]<<16) | ((t)->te_metric[1]<<8) | \ + (t)->te_metric[2]) +#define SET_TE_METRIC(t, m) \ + (((t)->te_metric[0] = (m) >> 16), \ + ((t)->te_metric[1] = (m) >> 8), \ + ((t)->te_metric[2] = (m))) + /* struct for es neighbors */ struct es_neigh { @@ -213,7 +225,6 @@ struct ipv6_reachability u_char prefix_len; u_char prefix[16]; }; -#endif /* HAVE_IPV6 */ /* bits in control_info */ #define CTRL_INFO_DIRECTION 0x80 @@ -223,12 +234,17 @@ struct ipv6_reachability #define DISTRIBUTION_INTERNAL 0 #define DISTRIBUTION_EXTERNAL 1 #define CTRL_INFO_SUBTLVS 0x20 +#endif /* HAVE_IPV6 */ /* * Pointer to each tlv type, filled by parse_tlvs() */ struct tlvs { + struct checksum *checksum; + struct hostname *hostname; + struct nlpids *nlpids; + struct te_router_id *router_id; struct list *area_addrs; struct list *is_neighs; struct list *te_is_neighs; @@ -236,14 +252,10 @@ struct tlvs struct list *lsp_entries; struct list *prefix_neighs; struct list *lan_neighs; - struct checksum *checksum; - struct nlpids *nlpids; struct list *ipv4_addrs; struct list *ipv4_int_reachs; struct list *ipv4_ext_reachs; struct list *te_ipv4_reachs; - struct hostname *hostname; - struct te_router_id *router_id; #ifdef HAVE_IPV6 struct list *ipv6_addrs; struct list *ipv6_reachs; @@ -281,7 +293,9 @@ struct tlvs void init_tlvs (struct tlvs *tlvs, uint32_t expected); void free_tlvs (struct tlvs *tlvs); int parse_tlvs (char *areatag, u_char * stream, int size, - u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs); + u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs, + u_int32_t * auth_tlv_offset); +int add_tlv (u_char, u_char, u_char *, struct stream *); void free_tlv (void *val); int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream); @@ -290,7 +304,7 @@ int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream); int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream); int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream); int tlv_add_checksum (struct checksum *checksum, struct stream *stream); -int tlv_add_authinfo (char auth_type, char authlen, u_char *auth_value, +int tlv_add_authinfo (u_char auth_type, u_char authlen, u_char *auth_value, struct stream *stream); int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream); int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 9ee5ffc5d..467122f65 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -36,30 +36,37 @@ #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" +#include "isisd/isis_lsp.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" struct zclient *zclient = NULL; -extern struct thread_master *master; -extern struct isis *isis; - -struct in_addr router_id_zebra; - /* Router-id update message from zebra. */ static int isis_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length) { + struct isis_area *area; + struct listnode *node; struct prefix router_id; - zebra_router_id_update_read (zclient->ibuf,&router_id); - router_id_zebra = router_id.u.prefix4; + zebra_router_id_update_read (zclient->ibuf, &router_id); + if (isis->router_id == router_id.u.prefix4.s_addr) + return 0; + + isis->router_id = router_id.u.prefix4.s_addr; + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) + if (listcount (area->area_addrs) > 0) + lsp_regenerate_schedule (area, area->is_type, 0); - /* FIXME: Do we react somehow? */ return 0; } @@ -100,53 +107,28 @@ isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) zlog_debug ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu); + isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); /* Cannot call if_delete because we should retain the pseudo interface in case there is configuration info attached to it. */ if_delete_retain(ifp); - isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); - ifp->ifindex = IFINDEX_INTERNAL; return 0; } -static struct interface * -zebra_interface_if_lookup (struct stream *s) -{ - char ifname_tmp[INTERFACE_NAMSIZ]; - - /* Read interface name. */ - stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); - - /* And look it up. */ - return if_lookup_by_name_len(ifname_tmp, - strnlen(ifname_tmp, INTERFACE_NAMSIZ)); -} - static int isis_zebra_if_state_up (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; - ifp = zebra_interface_if_lookup (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf); - if (!ifp) + if (ifp == NULL) return 0; - if (if_is_operative (ifp)) - { - zebra_interface_if_set_value (zclient->ibuf, ifp); - /* HT: This is wrong actually. We can't assume that circuit exist - * if we delete circuit during if_state_down event. Needs rethink. - * TODO */ - isis_circuit_update_params (circuit_scan_by_ifp (ifp), ifp); - return 0; - } - - zebra_interface_if_set_value (zclient->ibuf, ifp); isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); return 0; @@ -157,17 +139,17 @@ isis_zebra_if_state_down (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; + struct isis_circuit *circuit; - ifp = zebra_interface_if_lookup (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; - if (if_is_operative (ifp)) - { - zebra_interface_if_set_value (zclient->ibuf, ifp); - isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); - } + circuit = isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), + ifp); + if (circuit) + SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); return 0; } @@ -251,7 +233,7 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_nexthop *nexthop; struct listnode *node; - if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) + if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; if (zclient->redist[ZEBRA_ROUTE_ISIS]) @@ -305,7 +287,8 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, stream_putw_at (stream, 0, stream_get_endp (stream)); zclient_send_message(zclient); - SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } } @@ -326,7 +309,7 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix, prefix4.prefix = prefix->u.prefix4; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, &api); } - UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); return; } @@ -344,7 +327,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, struct listnode *node; struct prefix_ipv6 prefix6; - if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) + if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.type = ZEBRA_ROUTE_ISIS; @@ -406,7 +389,8 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, &api); - SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } XFREE (MTYPE_ISIS_TMP, nexthop_list); @@ -427,7 +411,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, struct listnode *node; struct prefix_ipv6 prefix6; - if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) + if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.type = ZEBRA_ROUTE_ISIS; @@ -483,7 +467,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, &api); - UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } XFREE (MTYPE_ISIS_TMP, nexthop_list); diff --git a/isisd/isisd.c b/isisd/isisd.c index 1e84a1ced..6cbb85b1b 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -27,6 +27,7 @@ #include "command.h" #include "log.h" #include "memory.h" +#include "time.h" #include "linklist.h" #include "if.h" #include "hash.h" @@ -38,8 +39,9 @@ #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" -#include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_adjacency.h" @@ -59,19 +61,17 @@ u_char DEFAULT_TOPOLOGY_BASEIS[6] = { 0xFE, 0xED, 0xFE, 0xED, 0x00, 0x00 }; #endif /* TOPOLOGY_GENERATE */ struct isis *isis = NULL; -extern struct thread_master *master; /* * Prototypes. */ -void isis_new(unsigned long); -struct isis_area *isis_area_create(void); int isis_area_get(struct vty *, const char *); int isis_area_destroy(struct vty *, const char *); -int area_net_title(struct vty *, const u_char *); -int area_clear_net_title(struct vty *, const u_char *); -int show_clns_neigh(struct vty *, char); -void print_debug(struct vty *, int, int); +int area_net_title(struct vty *, const char *); +int area_clear_net_title(struct vty *, const char *); +int show_isis_interface_common(struct vty *, const char *ifname, char); +int show_isis_neighbor_common(struct vty *, const char *id, char); +int clear_isis_neighbor_common(struct vty *, const char *id); int isis_config_write(struct vty *); @@ -84,8 +84,8 @@ isis_new (unsigned long process_id) * Default values */ isis->max_area_addrs = 3; - isis->process_id = process_id; + isis->router_id = 0; isis->area_list = list_new (); isis->init_circ_list = list_new (); isis->uptime = time (NULL); @@ -93,6 +93,7 @@ isis_new (unsigned long process_id) #ifdef HAVE_IPV6 isis->nexthops6 = list_new (); #endif /* HAVE_IPV6 */ + dyn_cache_init (); /* * uncomment the next line for full debugs */ @@ -100,7 +101,7 @@ isis_new (unsigned long process_id) } struct isis_area * -isis_area_create () +isis_area_create (const char *area_tag) { struct isis_area *area; @@ -114,36 +115,48 @@ isis_area_create () area->is_type = IS_LEVEL_1; else area->is_type = IS_LEVEL_1_AND_2; + /* * intialize the databases */ - area->lspdb[0] = lsp_db_init (); - area->lspdb[1] = lsp_db_init (); - - spftree_area_init (area); - area->route_table[0] = route_table_init (); - area->route_table[1] = route_table_init (); + if (area->is_type & IS_LEVEL_1) + { + area->lspdb[0] = lsp_db_init (); + area->route_table[0] = route_table_init (); +#ifdef HAVE_IPV6 + area->route_table6[0] = route_table_init (); +#endif /* HAVE_IPV6 */ + } + if (area->is_type & IS_LEVEL_2) + { + area->lspdb[1] = lsp_db_init (); + area->route_table[1] = route_table_init (); #ifdef HAVE_IPV6 - area->route_table6[0] = route_table_init (); - area->route_table6[1] = route_table_init (); + area->route_table6[1] = route_table_init (); #endif /* HAVE_IPV6 */ + } + + spftree_area_init (area); + area->circuit_list = list_new (); area->area_addrs = list_new (); THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1); flags_initialize (&area->flags); + /* * Default values */ - area->max_lsp_lifetime[0] = MAX_AGE; /* 1200 */ - area->max_lsp_lifetime[1] = MAX_AGE; /* 1200 */ - area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT; - area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT; - area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900 */ - area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900 */ + area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME; /* 1200 */ + area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME; /* 1200 */ + area->lsp_refresh[0] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */ + area->lsp_refresh[1] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */ + area->lsp_gen_interval[0] = DEFAULT_MIN_LSP_GEN_INTERVAL; + area->lsp_gen_interval[1] = DEFAULT_MIN_LSP_GEN_INTERVAL; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; area->dynhostname = 1; - area->oldmetric = 1; + area->oldmetric = 0; + area->newmetric = 1; area->lsp_frag_threshold = 90; #ifdef TOPOLOGY_GENERATE memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); @@ -152,6 +165,10 @@ isis_area_create () /* FIXME: Think of a better way... */ area->min_bcast_mtu = 1497; + area->area_tag = strdup (area_tag); + listnode_add (isis->area_list, area); + area->isis = isis; + return area; } @@ -184,9 +201,7 @@ isis_area_get (struct vty *vty, const char *area_tag) return CMD_SUCCESS; } - area = isis_area_create (); - area->area_tag = strdup (area_tag); - listnode_add (isis->area_list, area); + area = isis_area_create (area_tag); if (isis->debugs & DEBUG_EVENTS) zlog_debug ("New IS-IS area instance %s", area->area_tag); @@ -203,40 +218,100 @@ isis_area_destroy (struct vty *vty, const char *area_tag) struct isis_area *area; struct listnode *node, *nnode; struct isis_circuit *circuit; + struct area_addr *addr; area = isis_area_lookup (area_tag); if (area == NULL) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_NO_MATCH; } if (area->circuit_list) { for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit)) - { - /* The fact that it's in circuit_list means that it was configured */ - isis_circuit_deconfigure (circuit, area); - isis_circuit_del (circuit); - } - + { + circuit->ip_router = 0; +#ifdef HAVE_IPV6 + circuit->ipv6_router = 0; +#endif + isis_csm_state_change (ISIS_DISABLE, circuit, area); + } list_delete (area->circuit_list); + area->circuit_list = NULL; } - listnode_delete (isis->area_list, area); + + if (area->lspdb[0] != NULL) + { + lsp_db_destroy (area->lspdb[0]); + area->lspdb[0] = NULL; + } + if (area->lspdb[1] != NULL) + { + lsp_db_destroy (area->lspdb[1]); + area->lspdb[1] = NULL; + } + + spftree_area_del (area); + + /* invalidate and validate would delete all routes from zebra */ + isis_route_invalidate (area); + isis_route_validate (area); + + if (area->route_table[0]) + { + route_table_finish (area->route_table[0]); + area->route_table[0] = NULL; + } + if (area->route_table[1]) + { + route_table_finish (area->route_table[1]); + area->route_table[1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->route_table6[0]) + { + route_table_finish (area->route_table6[0]); + area->route_table6[0] = NULL; + } + if (area->route_table6[1]) + { + route_table_finish (area->route_table6[1]); + area->route_table6[1] = NULL; + } +#endif /* HAVE_IPV6 */ + + for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr)) + { + list_delete_node (area->area_addrs, node); + XFREE (MTYPE_ISIS_AREA_ADDR, addr); + } + area->area_addrs = NULL; + THREAD_TIMER_OFF (area->t_tick); - if (area->t_remove_aged) - thread_cancel (area->t_remove_aged); THREAD_TIMER_OFF (area->t_lsp_refresh[0]); THREAD_TIMER_OFF (area->t_lsp_refresh[1]); + thread_cancel_event (master, area); + + listnode_delete (isis->area_list, area); + + free (area->area_tag); + XFREE (MTYPE_ISIS_AREA, area); + if (listcount (isis->area_list) == 0) + { + memset (isis->sysid, 0, ISIS_SYS_ID_LEN); + isis->sysid_set = 0; + } + return CMD_SUCCESS; } int -area_net_title (struct vty *vty, const u_char *net_title) +area_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr *addr; @@ -249,7 +324,7 @@ area_net_title (struct vty *vty, const u_char *net_title) if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_NO_MATCH; } /* We check that we are not over the maximal number of addresses */ @@ -257,7 +332,7 @@ area_net_title (struct vty *vty, const u_char *net_title) { vty_out (vty, "Maximum of area addresses (%d) already reached %s", isis->max_area_addrs, VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_NOTHING_TODO; } addr = XMALLOC (MTYPE_ISIS_AREA_ADDR, sizeof (struct area_addr)); @@ -269,10 +344,18 @@ area_net_title (struct vty *vty, const u_char *net_title) #endif /* EXTREME_DEBUG */ if (addr->addr_len < 8 || addr->addr_len > 20) { - zlog_warn ("area address must be at least 8..20 octets long (%d)", - addr->addr_len); + vty_out (vty, "area address must be at least 8..20 octets long (%d)%s", + addr->addr_len, VTY_NEWLINE); + XFREE (MTYPE_ISIS_AREA_ADDR, addr); + return CMD_ERR_AMBIGUOUS; + } + + if (addr->area_addr[addr->addr_len-1] != 0) + { + vty_out (vty, "nsel byte (last byte) in area address must be 0%s", + VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } if (isis->sysid_set == 0) @@ -280,7 +363,7 @@ area_net_title (struct vty *vty, const u_char *net_title) /* * First area address - get the SystemID for this router */ - memcpy (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN), ISIS_SYS_ID_LEN); + memcpy (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN); isis->sysid_set = 1; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("Router has SystemID %s", sysid_print (isis->sysid)); @@ -290,20 +373,19 @@ area_net_title (struct vty *vty, const u_char *net_title) /* * Check that the SystemID portions match */ - if (memcmp (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN), - ISIS_SYS_ID_LEN)) + if (memcmp (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN)) { vty_out (vty, "System ID must not change when defining additional area" " addresses%s", VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } /* now we see that we don't already have this address */ for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp)) { - if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) != (addr->addr_len)) + if ((addrp->addr_len + ISIS_SYS_ID_LEN + ISIS_NSEL_LEN) != (addr->addr_len)) continue; if (!memcmp (addrp->area_addr, addr->area_addr, addr->addr_len)) { @@ -311,26 +393,28 @@ area_net_title (struct vty *vty, const u_char *net_title) return CMD_SUCCESS; /* silent fail */ } } - } + /* * Forget the systemID part of the address */ - addr->addr_len -= (ISIS_SYS_ID_LEN + 1); + addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); listnode_add (area->area_addrs, addr); /* only now we can safely generate our LSPs for this area */ if (listcount (area->area_addrs) > 0) { - lsp_l1_generate (area); - lsp_l2_generate (area); + if (area->is_type & IS_LEVEL_1) + lsp_generate (area, IS_LEVEL_1); + if (area->is_type & IS_LEVEL_2) + lsp_generate (area, IS_LEVEL_2); } return CMD_SUCCESS; } int -area_clear_net_title (struct vty *vty, const u_char *net_title) +area_clear_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr addr, *addrp = NULL; @@ -341,7 +425,7 @@ area_clear_net_title (struct vty *vty, const u_char *net_title) if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_NO_MATCH; } addr.addr_len = dotformat2buff (buff, net_title); @@ -349,13 +433,13 @@ area_clear_net_title (struct vty *vty, const u_char *net_title) { vty_out (vty, "Unsupported area address length %d, should be 8...20 %s", addr.addr_len, VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } memcpy (addr.area_addr, buff, (int) addr.addr_len); for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp)) - if (addrp->addr_len == addr.addr_len && + if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len && !memcmp (addrp->area_addr, addr.area_addr, addr.addr_len)) break; @@ -363,26 +447,36 @@ area_clear_net_title (struct vty *vty, const u_char *net_title) { vty_out (vty, "No area address %s for area %s %s", net_title, area->area_tag, VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_NO_MATCH; } listnode_delete (area->area_addrs, addrp); + XFREE (MTYPE_ISIS_AREA_ADDR, addrp); + + /* + * Last area address - reset the SystemID for this router + */ + if (listcount (area->area_addrs) == 0) + { + memset (isis->sysid, 0, ISIS_SYS_ID_LEN); + isis->sysid_set = 0; + if (isis->debugs & DEBUG_EVENTS) + zlog_debug ("Router has no SystemID"); + } return CMD_SUCCESS; } /* - * 'show clns neighbors' command + * 'show isis interface' command */ int -show_clns_neigh (struct vty *vty, char detail) +show_isis_interface_common (struct vty *vty, const char *ifname, char detail) { struct listnode *anode, *cnode; struct isis_area *area; struct isis_circuit *circuit; - struct list *db; - int i; if (!isis) { @@ -395,92 +489,246 @@ show_clns_neigh (struct vty *vty, char detail) vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); if (detail == ISIS_UI_LEVEL_BRIEF) - vty_out (vty, " System Id Interface L State " - "Holdtime SNPA%s", VTY_NEWLINE); + vty_out (vty, " Interface CircId State Type Level%s", + VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) - { - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - for (i = 0; i < 2; i++) - { - db = circuit->u.bc.adjdb[i]; - if (db && db->count) - { - if (detail == ISIS_UI_LEVEL_BRIEF) - isis_adjdb_iterate (db, - (void (*) - (struct isis_adjacency *, - void *)) isis_adj_print_vty, - vty); - if (detail == ISIS_UI_LEVEL_DETAIL) - isis_adjdb_iterate (db, - (void (*) - (struct isis_adjacency *, - void *)) - isis_adj_print_vty_detail, vty); - if (detail == ISIS_UI_LEVEL_EXTENSIVE) - isis_adjdb_iterate (db, - (void (*) - (struct isis_adjacency *, - void *)) - isis_adj_print_vty_extensive, - vty); - } - } - } - else if (circuit->circ_type == CIRCUIT_T_P2P && - circuit->u.p2p.neighbor) - { - if (detail == ISIS_UI_LEVEL_BRIEF) - isis_adj_p2p_print_vty (circuit->u.p2p.neighbor, vty); - if (detail == ISIS_UI_LEVEL_DETAIL) - isis_adj_p2p_print_vty_detail (circuit->u.p2p.neighbor, vty); - if (detail == ISIS_UI_LEVEL_EXTENSIVE) - isis_adj_p2p_print_vty_extensive (circuit->u.p2p.neighbor, - vty); - } - } + if (!ifname) + isis_circuit_print_vty (circuit, vty, detail); + else if (strcmp(circuit->interface->name, ifname) == 0) + isis_circuit_print_vty (circuit, vty, detail); } return CMD_SUCCESS; } -DEFUN (show_clns_neighbors, - show_clns_neighbors_cmd, - "show clns neighbors", +DEFUN (show_isis_interface, + show_isis_interface_cmd, + "show isis interface", SHOW_STR - "clns network information\n" - "CLNS neighbor adjacencies\n") + "ISIS network information\n" + "ISIS interface\n") { - return show_clns_neigh (vty, ISIS_UI_LEVEL_BRIEF); + return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); } -ALIAS (show_clns_neighbors, - show_isis_neighbors_cmd, - "show isis neighbors", +DEFUN (show_isis_interface_detail, + show_isis_interface_detail_cmd, + "show isis interface detail", SHOW_STR - "IS-IS network information\n" - "IS-IS neighbor adjacencies\n") + "ISIS network information\n" + "ISIS interface\n" + "show detailed information\n") +{ + return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); +} -DEFUN (show_clns_neighbors_detail, - show_clns_neighbors_detail_cmd, - "show clns neighbors detail", +DEFUN (show_isis_interface_arg, + show_isis_interface_arg_cmd, + "show isis interface WORD", SHOW_STR - "clns network information\n" - "CLNS neighbor adjacencies\n" - "show detailed information\n") + "ISIS network information\n" + "ISIS interface\n" + "ISIS interface name\n") +{ + return show_isis_interface_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); +} + +/* + * 'show isis neighbor' command + */ + +int +show_isis_neighbor_common (struct vty *vty, const char *id, char detail) +{ + struct listnode *anode, *cnode, *node; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *adjdb; + struct isis_adjacency *adj; + struct isis_dynhn *dynhn; + u_char sysid[ISIS_SYS_ID_LEN]; + int i; + + if (!isis) + { + vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + memset (sysid, 0, ISIS_SYS_ID_LEN); + if (id) + { + if (sysid2buff (sysid, id) == 0) + { + dynhn = dynhn_find_by_name (id); + if (dynhn == NULL) + { + vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); + return CMD_SUCCESS; + } + memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); + } + } + + for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) + { + vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); + + if (detail == ISIS_UI_LEVEL_BRIEF) + vty_out (vty, " System Id Interface L State" + " Holdtime SNPA%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) + { + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + for (i = 0; i < 2; i++) + { + adjdb = circuit->u.bc.adjdb[i]; + if (adjdb && adjdb->count) + { + for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) + if (!id || !memcmp (adj->sysid, sysid, + ISIS_SYS_ID_LEN)) + isis_adj_print_vty (adj, vty, detail); + } + } + } + else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) + { + adj = circuit->u.p2p.neighbor; + if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_print_vty (adj, vty, detail); + } + } + } + + return CMD_SUCCESS; +} + +/* + * 'clear isis neighbor' command + */ +int +clear_isis_neighbor_common (struct vty *vty, const char *id) +{ + struct listnode *anode, *cnode, *cnextnode, *node, *nnode; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *adjdb; + struct isis_adjacency *adj; + struct isis_dynhn *dynhn; + u_char sysid[ISIS_SYS_ID_LEN]; + int i; + + if (!isis) + { + vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + memset (sysid, 0, ISIS_SYS_ID_LEN); + if (id) + { + if (sysid2buff (sysid, id) == 0) + { + dynhn = dynhn_find_by_name (id); + if (dynhn == NULL) + { + vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); + return CMD_SUCCESS; + } + memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); + } + } + + for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) + { + for (ALL_LIST_ELEMENTS (area->circuit_list, cnode, cnextnode, circuit)) + { + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + for (i = 0; i < 2; i++) + { + adjdb = circuit->u.bc.adjdb[i]; + if (adjdb && adjdb->count) + { + for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj)) + if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_state_change (adj, ISIS_ADJ_DOWN, + "clear user request"); + } + } + } + else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) + { + adj = circuit->u.p2p.neighbor; + if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_state_change (adj, ISIS_ADJ_DOWN, + "clear user request"); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_isis_neighbor, + show_isis_neighbor_cmd, + "show isis neighbor", + SHOW_STR + "ISIS network information\n" + "ISIS neighbor adjacencies\n") { - return show_clns_neigh (vty, ISIS_UI_LEVEL_DETAIL); + return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); } -ALIAS (show_clns_neighbors_detail, - show_isis_neighbors_detail_cmd, - "show isis neighbors detail", +DEFUN (show_isis_neighbor_detail, + show_isis_neighbor_detail_cmd, + "show isis neighbor detail", SHOW_STR - "IS-IS network information\n" - "IS-IS neighbor adjacencies\n" + "ISIS network information\n" + "ISIS neighbor adjacencies\n" "show detailed information\n") +{ + return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); +} + +DEFUN (show_isis_neighbor_arg, + show_isis_neighbor_arg_cmd, + "show isis neighbor WORD", + SHOW_STR + "ISIS network information\n" + "ISIS neighbor adjacencies\n" + "System id\n") +{ + return show_isis_neighbor_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); +} + +DEFUN (clear_isis_neighbor, + clear_isis_neighbor_cmd, + "clear isis neighbor", + CLEAR_STR + "Reset ISIS network information\n" + "Reset ISIS neighbor adjacencies\n") +{ + return clear_isis_neighbor_common (vty, NULL); +} + +DEFUN (clear_isis_neighbor_arg, + clear_isis_neighbor_arg_cmd, + "claer isis neighbor WORD", + CLEAR_STR + "ISIS network information\n" + "ISIS neighbor adjacencies\n" + "System id\n") +{ + return clear_isis_neighbor_common (vty, argv[0]); +} + /* * 'isis debug', 'show debugging' */ @@ -524,7 +772,8 @@ print_debug (struct vty *vty, int flags, int onoff) VTY_NEWLINE); if (flags & DEBUG_EVENTS) vty_out (vty, "IS-IS Event debugging is %s%s", onoffs, VTY_NEWLINE); - + if (flags & DEBUG_PACKET_DUMP) + vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE); } DEFUN (show_debugging, @@ -606,6 +855,11 @@ config_write_debug (struct vty *vty) vty_out (vty, "debug isis events%s", VTY_NEWLINE); write++; } + if (flags & DEBUG_PACKET_DUMP) + { + vty_out (vty, "debug isis packet-dump%s", VTY_NEWLINE); + write++; + } return write; } @@ -792,7 +1046,6 @@ DEFUN (no_debug_isis_spfevents, return CMD_SUCCESS; } - DEFUN (debug_isis_spfstats, debug_isis_spfstats_cmd, "debug isis spf-statistics ", @@ -897,6 +1150,32 @@ DEFUN (no_debug_isis_events, return CMD_SUCCESS; } +DEFUN (debug_isis_packet_dump, + debug_isis_packet_dump_cmd, + "debug isis packet-dump", + DEBUG_STR + "IS-IS information\n" + "IS-IS packet dump\n") +{ + isis->debugs |= DEBUG_PACKET_DUMP; + print_debug (vty, DEBUG_PACKET_DUMP, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_isis_packet_dump, + no_debug_isis_packet_dump_cmd, + "no debug isis packet-dump", + UNDEBUG_STR + "IS-IS information\n" + "IS-IS packet dump\n") +{ + isis->debugs &= ~DEBUG_PACKET_DUMP; + print_debug (vty, DEBUG_PACKET_DUMP, 0); + + return CMD_SUCCESS; +} + DEFUN (show_hostname, show_hostname_cmd, "show isis hostname", @@ -909,99 +1188,331 @@ DEFUN (show_hostname, return CMD_SUCCESS; } -DEFUN (show_database, - show_database_cmd, - "show isis database", - SHOW_STR "IS-IS information\n" "IS-IS link state database\n") +static void +vty_out_timestr(struct vty *vty, time_t uptime) { - struct listnode *node; + struct tm *tm; + time_t difftime = time (NULL); + difftime -= uptime; + tm = gmtime (&difftime); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (difftime < ONE_DAY_SECOND) + vty_out (vty, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (difftime < ONE_WEEK_SECOND) + vty_out (vty, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, "%02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + vty_out (vty, " ago"); +} + +DEFUN (show_isis_summary, + show_isis_summary_cmd, + "show isis summary", + SHOW_STR "IS-IS information\n" "IS-IS summary\n") +{ + struct listnode *node, *node2; struct isis_area *area; - int level, lsp_count; + struct isis_spftree *spftree; + int level; - if (isis->area_list->count == 0) + if (isis == NULL) + { + vty_out (vty, "ISIS is not running%s", VTY_NEWLINE); return CMD_SUCCESS; + } + + vty_out (vty, "Process Id : %ld%s", isis->process_id, + VTY_NEWLINE); + if (isis->sysid_set) + vty_out (vty, "System Id : %s%s", sysid_print (isis->sysid), + VTY_NEWLINE); + + vty_out (vty, "Up time : "); + vty_out_timestr(vty, isis->uptime); + vty_out (vty, "%s", VTY_NEWLINE); + + if (isis->area_list) + vty_out (vty, "Number of areas : %d%s", isis->area_list->count, + VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) + { + vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", + VTY_NEWLINE); + + if (listcount (area->area_addrs) > 0) { - vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", - VTY_NEWLINE); - for (level = 0; level < ISIS_LEVELS; level++) - { - if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) - { - vty_out (vty, "IS-IS Level-%d link-state database:%s", - level + 1, VTY_NEWLINE); + struct area_addr *area_addr; + for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr)) + { + vty_out (vty, " Net: %s%s", + isonet_print (area_addr->area_addr, + area_addr->addr_len + ISIS_SYS_ID_LEN + + 1), VTY_NEWLINE); + } + } - lsp_count = lsp_print_all (vty, area->lspdb[level], - ISIS_UI_LEVEL_BRIEF, - area->dynhostname); + for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) + { + if ((area->is_type & level) == 0) + continue; - vty_out (vty, "%s %u LSPs%s%s", - VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE); - } - } + vty_out (vty, " Level-%d:%s", level, VTY_NEWLINE); + spftree = area->spftree[level - 1]; + if (spftree->pending) + vty_out (vty, " IPv4 SPF: (pending)%s", VTY_NEWLINE); + else + vty_out (vty, " IPv4 SPF:%s", VTY_NEWLINE); + + vty_out (vty, " minimum interval : %d%s", + area->min_spf_interval[level - 1], VTY_NEWLINE); + + vty_out (vty, " last run : "); + vty_out_timestr(vty, spftree->lastrun); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " run count : %d%s", + spftree->runcount, VTY_NEWLINE); + +#ifdef HAVE_IPV6 + spftree = area->spftree6[level - 1]; + if (spftree->pending) + vty_out (vty, " IPv6 SPF: (pending)%s", VTY_NEWLINE); + else + vty_out (vty, " IPv6 SPF:%s", VTY_NEWLINE); + + vty_out (vty, " minimum interval : %d%s", + area->min_spf_interval[level - 1], VTY_NEWLINE); + + vty_out (vty, " last run : "); + vty_out_timestr(vty, spftree->lastrun); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " run count : %d%s", + spftree->runcount, VTY_NEWLINE); +#endif } + } + vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } -DEFUN (show_database_detail, - show_database_detail_cmd, - "show isis database detail", - SHOW_STR - "IS-IS information\n" - "IS-IS link state database\n") +/* + * This function supports following display options: + * [ show isis database [detail] ] + * [ show isis database [detail] ] + * [ show isis database [detail] ] + * [ show isis database . [detail] ] + * [ show isis database . [detail] ] + * [ show isis database .- [detail] ] + * [ show isis database .- [detail] ] + * [ show isis database detail ] + * [ show isis database detail ] + * [ show isis database detail . ] + * [ show isis database detail . ] + * [ show isis database detail .- ] + * [ show isis database detail .- ] + */ +static int +show_isis_database (struct vty *vty, const char *argv, int ui_level) { struct listnode *node; struct isis_area *area; + struct isis_lsp *lsp; + struct isis_dynhn *dynhn; + const char *pos = argv; + u_char lspid[ISIS_SYS_ID_LEN+2]; + char sysid[15]; /* len of xxxx.xxxx.xxxx + place for #0 termination */ + u_char number[3]; int level, lsp_count; if (isis->area_list->count == 0) return CMD_SUCCESS; + memset (&lspid, 0, ISIS_SYS_ID_LEN); + memset (&sysid, 0, 15); + + if (argv) + { + strncpy (sysid, argv, 15); + sysid[14] = '\0'; + } + + /* + * extract fragment and pseudo id from the string argv + * in the forms: + * (a) .- or + * (b) . or + * (c) or + * Where systemid is in the form: + * xxxx.xxxx.xxxx + */ + if (argv && strlen (argv) > 3) + { + pos = argv + strlen (argv) - 3; + if (strncmp (pos, "-", 1) == 0) + { + memcpy (number, ++pos, 2); + lspid[ISIS_SYS_ID_LEN+1] = (u_char) strtol ((char *)number, NULL, 16); + pos -= 4; + if (strncmp (pos, ".", 1) != 0) + return CMD_ERR_AMBIGUOUS; + } + if (strncmp (pos, ".", 1) == 0) + { + memcpy (number, ++pos, 2); + lspid[ISIS_SYS_ID_LEN] = (u_char) strtol ((char *)number, NULL, 16); + sysid[pos - argv - 1] = '\0'; + } + } + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", - VTY_NEWLINE); - for (level = 0; level < ISIS_LEVELS; level++) - { - if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) - { - vty_out (vty, "IS-IS Level-%d Link State Database:%s", - level + 1, VTY_NEWLINE); - - lsp_count = lsp_print_all (vty, area->lspdb[level], - ISIS_UI_LEVEL_DETAIL, - area->dynhostname); + VTY_NEWLINE); - vty_out (vty, "%s %u LSPs%s%s", - VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE); - } - } + for (level = 0; level < ISIS_LEVELS; level++) + { + if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) + { + lsp = NULL; + if (argv != NULL) + { + /* + * Try to find the lsp-id if the argv string is in + * the form hostname.- + */ + if (sysid2buff (lspid, sysid)) + { + lsp = lsp_search (lspid, area->lspdb[level]); + } + else if ((dynhn = dynhn_find_by_name (sysid))) + { + memcpy (lspid, dynhn->id, ISIS_SYS_ID_LEN); + lsp = lsp_search (lspid, area->lspdb[level]); + } + else if (strncmp(unix_hostname (), sysid, 15) == 0) + { + memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); + lsp = lsp_search (lspid, area->lspdb[level]); + } + } + + if (lsp != NULL || argv == NULL) + { + vty_out (vty, "IS-IS Level-%d link-state database:%s", + level + 1, VTY_NEWLINE); + + /* print the title in all cases */ + vty_out (vty, "LSP ID PduLen " + "SeqNumber Chksum Holdtime ATT/P/OL%s", + VTY_NEWLINE); + } + + if (lsp) + { + if (ui_level == ISIS_UI_LEVEL_DETAIL) + lsp_print_detail (lsp, vty, area->dynhostname); + else + lsp_print (lsp, vty, area->dynhostname); + } + else if (argv == NULL) + { + lsp_count = lsp_print_all (vty, area->lspdb[level], + ui_level, + area->dynhostname); + + vty_out (vty, " %u LSPs%s%s", + lsp_count, VTY_NEWLINE, VTY_NEWLINE); + } + } + } } return CMD_SUCCESS; } -/* - * 'router isis' command - */ -DEFUN (router_isis, - router_isis_cmd, - "router isis WORD", - ROUTER_STR - "ISO IS-IS\n" - "ISO Routing area tag") +DEFUN (show_database_brief, + show_database_cmd, + "show isis database", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n") { - return isis_area_get (vty, argv[0]); + return show_isis_database (vty, NULL, ISIS_UI_LEVEL_BRIEF); } -/* - *'no router isis' command - */ -DEFUN (no_router_isis, - no_router_isis_cmd, - "no router isis WORD", +DEFUN (show_database_lsp_brief, + show_database_arg_cmd, + "show isis database WORD", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n" + "LSP ID\n") +{ + return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_BRIEF); +} + +DEFUN (show_database_lsp_detail, + show_database_arg_detail_cmd, + "show isis database WORD detail", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n" + "LSP ID\n" + "Detailed information\n") +{ + return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL); +} + +DEFUN (show_database_detail, + show_database_detail_cmd, + "show isis database detail", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n") +{ + return show_isis_database (vty, NULL, ISIS_UI_LEVEL_DETAIL); +} + +DEFUN (show_database_detail_lsp, + show_database_detail_arg_cmd, + "show isis database detail WORD", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n" + "Detailed information\n" + "LSP ID\n") +{ + return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL); +} + +/* + * 'router isis' command + */ +DEFUN (router_isis, + router_isis_cmd, + "router isis WORD", + ROUTER_STR + "ISO IS-IS\n" + "ISO Routing area tag") +{ + return isis_area_get (vty, argv[0]); +} + +/* + *'no router isis' command + */ +DEFUN (no_router_isis, + no_router_isis_cmd, + "no router isis WORD", "no\n" ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag") { return isis_area_destroy (vty, argv[0]); @@ -1032,10 +1543,69 @@ DEFUN (no_net, return area_clear_net_title (vty, argv[0]); } -DEFUN (area_passwd, - area_passwd_cmd, - "area-password WORD", +DEFUN (area_passwd_md5, + area_passwd_md5_cmd, + "area-password md5 WORD", + "Configure the authentication password for an area\n" + "Authentication type\n" + "Area password\n") +{ + struct isis_area *area; + int len; + + area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + len = strlen (argv[0]); + if (len > 254) + { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + area->area_passwd.len = (u_char) len; + area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; + strncpy ((char *)area->area_passwd.passwd, argv[0], 255); + + if (argc > 1) + { + SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); + if (strncmp(argv[1], "v", 1) == 0) + SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + else + UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + } + else + { + UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); + UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + } + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + +ALIAS (area_passwd_md5, + area_passwd_md5_snpauth_cmd, + "area-password md5 WORD authenticate snp (send-only|validate)", + "Configure the authentication password for an area\n" + "Authentication type\n" + "Area password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n"); + +DEFUN (area_passwd_clear, + area_passwd_clear_cmd, + "area-password clear WORD", "Configure the authentication password for an area\n" + "Authentication type\n" "Area password\n") { struct isis_area *area; @@ -1045,16 +1615,17 @@ DEFUN (area_passwd, if (!area) { - vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } + area->area_passwd.len = (u_char) len; area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->area_passwd.passwd, argv[0], 255); @@ -1072,14 +1643,16 @@ DEFUN (area_passwd, UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } -ALIAS (area_passwd, - area_passwd_snpauth_cmd, - "area-password WORD authenticate snp (send-only|validate)", +ALIAS (area_passwd_clear, + area_passwd_clear_snpauth_cmd, + "area-password clear WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" + "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" @@ -1098,19 +1671,79 @@ DEFUN (no_area_passwd, if (!area) { - vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } memset (&area->area_passwd, 0, sizeof (struct isis_passwd)); + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + +DEFUN (domain_passwd_md5, + domain_passwd_md5_cmd, + "domain-password md5 WORD", + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Routing domain password\n") +{ + struct isis_area *area; + int len; + + area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + len = strlen (argv[0]); + if (len > 254) + { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + area->domain_passwd.len = (u_char) len; + area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; + strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); + + if (argc > 1) + { + SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); + if (strncmp(argv[1], "v", 1) == 0) + SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); + else + UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); + } + else + { + UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); + UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); + } + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } -DEFUN (domain_passwd, - domain_passwd_cmd, - "domain-password WORD", +ALIAS (domain_passwd_md5, + domain_passwd_md5_snpauth_cmd, + "domain-password md5 WORD authenticate snp (send-only|validate)", + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Routing domain password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n"); + +DEFUN (domain_passwd_clear, + domain_passwd_clear_cmd, + "domain-password clear WORD", "Set the authentication password for a routing domain\n" + "Authentication type\n" "Routing domain password\n") { struct isis_area *area; @@ -1120,16 +1753,17 @@ DEFUN (domain_passwd, if (!area) { - vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } + area->domain_passwd.len = (u_char) len; area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); @@ -1147,14 +1781,16 @@ DEFUN (domain_passwd, UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } -ALIAS (domain_passwd, - domain_passwd_snpauth_cmd, - "domain-password WORD authenticate snp (send-only|validate)", +ALIAS (domain_passwd_clear, + domain_passwd_clear_snpauth_cmd, + "domain-password clear WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" + "Authentication type\n" "Routing domain password\n" "Authentication\n" "SNP PDUs\n" @@ -1163,7 +1799,7 @@ ALIAS (domain_passwd, DEFUN (no_domain_passwd, no_domain_passwd_cmd, - "no domain-password WORD", + "no domain-password", NO_STR "Set the authentication password for a routing domain\n") { @@ -1173,11 +1809,12 @@ DEFUN (no_domain_passwd, if (!area) { - vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } memset (&area->domain_passwd, 0, sizeof (struct isis_passwd)); + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } @@ -1197,8 +1834,8 @@ DEFUN (is_type, if (!area) { - vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; } type = string2circuit_t (argv[0]); @@ -1229,8 +1866,9 @@ DEFUN (no_is_type, assert (area); /* - * Put the is-type back to default. Which is level-1-2 on first - * circuit for the area level-1 for the rest + * Put the is-type back to defaults: + * - level-1-2 on first area + * - level-1 for the rest */ if (listgetdata (listhead (isis->area_list)) == area) type = IS_LEVEL_1_AND_2; @@ -1242,6 +1880,36 @@ DEFUN (no_is_type, return CMD_SUCCESS; } +static int +set_lsp_gen_interval (struct vty *vty, struct isis_area *area, + uint16_t interval, int level) +{ + int lvl; + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + + if (interval >= area->lsp_refresh[lvl-1]) + { + vty_out (vty, "LSP gen interval %us must be less than " + "the LSP refresh interval %us%s", + interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + area->lsp_gen_interval[lvl-1] = interval; + } + + return CMD_SUCCESS; +} + DEFUN (lsp_gen_interval, lsp_gen_interval_cmd, "lsp-gen-interval <1-120>", @@ -1250,15 +1918,12 @@ DEFUN (lsp_gen_interval, { struct isis_area *area; uint16_t interval; + int level; area = vty->index; - assert (area); - interval = atoi (argv[0]); - area->lsp_gen_interval[0] = interval; - area->lsp_gen_interval[1] = interval; - - return CMD_SUCCESS; + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval, @@ -1268,14 +1933,13 @@ DEFUN (no_lsp_gen_interval, "Minimum interval between regenerating same LSP\n") { struct isis_area *area; + uint16_t interval; + int level; area = vty->index; - assert (area); - - area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT; - area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT; - - return CMD_SUCCESS; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval, @@ -1294,14 +1958,12 @@ DEFUN (lsp_gen_interval_l1, { struct isis_area *area; uint16_t interval; + int level; area = vty->index; - assert (area); - interval = atoi (argv[0]); - area->lsp_gen_interval[0] = interval; - - return CMD_SUCCESS; + level = IS_LEVEL_1; + return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval_l1, @@ -1312,13 +1974,13 @@ DEFUN (no_lsp_gen_interval_l1, "Set interval for level 1 only\n") { struct isis_area *area; + uint16_t interval; + int level; area = vty->index; - assert (area); - - area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT; - - return CMD_SUCCESS; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_1; + return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval_l1, @@ -1337,15 +1999,13 @@ DEFUN (lsp_gen_interval_l2, "Minimum interval in seconds\n") { struct isis_area *area; - int interval; + uint16_t interval; + int level; area = vty->index; - assert (area); - interval = atoi (argv[0]); - area->lsp_gen_interval[1] = interval; - - return CMD_SUCCESS; + level = IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval_l2, @@ -1356,15 +2016,13 @@ DEFUN (no_lsp_gen_interval_l2, "Set interval for level 2 only\n") { struct isis_area *area; - int interval; + uint16_t interval; + int level; area = vty->index; - assert (area); - - interval = atoi (argv[0]); - area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT; - - return CMD_SUCCESS; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval_l2, @@ -1384,6 +2042,8 @@ DEFUN (metric_style, "Use new style of TLVs to carry wider metric\n") { struct isis_area *area; + struct isis_circuit *circuit; + struct listnode *node; area = vty->index; assert (area); @@ -1400,6 +2060,25 @@ DEFUN (metric_style, } else if (strncmp (argv[0], "n", 1) == 0) { + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + { + if ((area->is_type & IS_LEVEL_1) && + (circuit->is_type & IS_LEVEL_1) && + (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if ((area->is_type & IS_LEVEL_2) && + (circuit->is_type & IS_LEVEL_2) && + (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } area->newmetric = 0; area->oldmetric = 1; } @@ -1425,6 +2104,40 @@ DEFUN (no_metric_style, return CMD_SUCCESS; } +DEFUN (set_overload_bit, + set_overload_bit_cmd, + "set-overload-bit", + "Set overload bit to avoid any transit traffic\n" + "Set overload bit\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->overload_bit = LSPBIT_OL; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_set_overload_bit, + no_set_overload_bit_cmd, + "no set-overload-bit", + "Reset overload bit to accept transit traffic\n" + "Reset overload bit\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->overload_bit = 0; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + DEFUN (dynamic_hostname, dynamic_hostname_cmd, "hostname dynamic", @@ -1436,7 +2149,11 @@ DEFUN (dynamic_hostname, area = vty->index; assert (area); - area->dynhostname = 1; + if (!area->dynhostname) + { + area->dynhostname = 1; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); + } return CMD_SUCCESS; } @@ -1453,7 +2170,11 @@ DEFUN (no_dynamic_hostname, area = vty->index; assert (area); - area->dynhostname = 0; + if (area->dynhostname) + { + area->dynhostname = 0; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); + } return CMD_SUCCESS; } @@ -1580,308 +2301,487 @@ ALIAS (no_spf_interval, "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") -#ifdef TOPOLOGY_GENERATE -DEFUN (topology_generate_grid, - topology_generate_grid_cmd, - "topology generate grid <1-100> <1-100> <1-65000> [param] [param] " - "[param]", - "Topology generation for IS-IS\n" - "Topology generation\n" - "Grid topology\n" - "X parameter of the grid\n" - "Y parameter of the grid\n" - "Random seed\n" - "Optional param 1\n" - "Optional param 2\n" - "Optional param 3\n" - "Topology\n") +static int +set_lsp_max_lifetime (struct vty *vty, struct isis_area *area, + uint16_t interval, int level) { - struct isis_area *area; + int lvl; + int set_refresh_interval[ISIS_LEVELS] = {0, 0}; + uint16_t refresh_interval; - area = vty->index; - assert (area); + refresh_interval = interval - 300; - if (!spgrid_check_params (vty, argc, argv)) + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { - if (area->topology) - list_delete (area->topology); - area->topology = list_new (); - memcpy (area->top_params, vty->buf, 200); - gen_spgrid_topology (vty, area->topology); - remove_topology_lsps (area); - generate_topology_lsps (area); - /* Regenerate L1 LSP to get two way connection to the generated - * topology. */ - lsp_regenerate_schedule (area); + if (!(lvl & level)) + continue; + if (refresh_interval < area->lsp_refresh[lvl-1]) + { + vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " + "the configured LSP refresh interval %us%s", + lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); + vty_out (vty, "Automatically reducing level %d LSP refresh interval " + "to %us%s", lvl, refresh_interval, VTY_NEWLINE); + set_refresh_interval[lvl-1] = 1; + + if (refresh_interval <= area->lsp_gen_interval[lvl-1]) + { + vty_out (vty, "LSP refresh interval %us must be greater than " + "the configured LSP gen interval %us%s", + refresh_interval, area->lsp_gen_interval[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + { + if (!(lvl & level)) + continue; + area->max_lsp_lifetime[lvl-1] = interval; + /* Automatically reducing lsp_refresh_interval to interval - 300 */ + if (set_refresh_interval[lvl-1]) + area->lsp_refresh[lvl-1] = refresh_interval; } + lsp_regenerate_schedule (area, level, 1); + return CMD_SUCCESS; } -DEFUN (show_isis_generated_topology, - show_isis_generated_topology_cmd, - "show isis generated-topologies", - SHOW_STR - "CLNS network information\n" - "Show generated topologies\n") +DEFUN (max_lsp_lifetime, + max_lsp_lifetime_cmd, + "max-lsp-lifetime <350-65535>", + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n") { struct isis_area *area; - struct listnode *node; - struct listnode *node2; - struct arc *arc; - - for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) - { - if (!area->topology) - continue; + uint16_t interval; + int level; - vty_out (vty, "Topology for isis area: %s%s", area->area_tag, - VTY_NEWLINE); - vty_out (vty, "From node To node Distance%s", VTY_NEWLINE); + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_max_lifetime (vty, area, interval, level); +} - for (ALL_LIST_ELEMENTS_RO (area->topology, node2, arc)) - vty_out (vty, "%9ld %11ld %12ld%s", arc->from_node, arc->to_node, - arc->distance, VTY_NEWLINE); - } - return CMD_SUCCESS; -} - -/* Base IS for topology generation. */ -DEFUN (topology_baseis, - topology_baseis_cmd, - "topology base-is WORD", - "Topology generation for IS-IS\n" - "A Network IS Base for this topology\n" - "XXXX.XXXX.XXXX Network entity title (NET)\n") +DEFUN (no_max_lsp_lifetime, + no_max_lsp_lifetime_cmd, + "no max-lsp-lifetime", + NO_STR + "LSP lifetime in seconds\n") { struct isis_area *area; - u_char buff[ISIS_SYS_ID_LEN]; + uint16_t interval; + int level; area = vty->index; - assert (area); - - if (sysid2buff (buff, argv[0])) - sysid2buff (area->topology_baseis, argv[0]); - - return CMD_SUCCESS; + interval = DEFAULT_LSP_LIFETIME; + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_max_lifetime (vty, area, interval, level); } -DEFUN (no_topology_baseis, - no_topology_baseis_cmd, - "no topology base-is WORD", +ALIAS (no_max_lsp_lifetime, + no_max_lsp_lifetime_arg_cmd, + "no max-lsp-lifetime <350-65535>", NO_STR - "Topology generation for IS-IS\n" - "A Network IS Base for this topology\n" - "XXXX.XXXX.XXXX Network entity title (NET)\n") + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n") + +DEFUN (max_lsp_lifetime_l1, + max_lsp_lifetime_l1_cmd, + "max-lsp-lifetime level-1 <350-65535>", + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n") { struct isis_area *area; + uint16_t interval; + int level; area = vty->index; - assert (area); - - memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); - return CMD_SUCCESS; + interval = atoi (argv[0]); + level = IS_LEVEL_1; + return set_lsp_max_lifetime (vty, area, interval, level); } -ALIAS (no_topology_baseis, - no_topology_baseis_noid_cmd, - "no topology base-is", +DEFUN (no_max_lsp_lifetime_l1, + no_max_lsp_lifetime_l1_cmd, + "no max-lsp-lifetime level-1", NO_STR - "Topology generation for IS-IS\n" - "A Network IS Base for this topology\n") - -DEFUN (topology_basedynh, - topology_basedynh_cmd, - "topology base-dynh WORD", - "Topology generation for IS-IS\n" - "Dynamic hostname base for this topology\n" - "Dynamic hostname base\n") + "LSP lifetime for Level 1 only in seconds\n") { struct isis_area *area; + uint16_t interval; + int level; area = vty->index; - assert (area); - - /* I hope that it's enough. */ - area->topology_basedynh = strndup (argv[0], 16); - return CMD_SUCCESS; + interval = DEFAULT_LSP_LIFETIME; + level = IS_LEVEL_1; + return set_lsp_max_lifetime (vty, area, interval, level); } -#endif /* TOPOLOGY_GENERATE */ -DEFUN (lsp_lifetime, - lsp_lifetime_cmd, - "lsp-lifetime <380-65535>", - "Maximum LSP lifetime\n" - "LSP lifetime in seconds\n") +ALIAS (no_max_lsp_lifetime_l1, + no_max_lsp_lifetime_l1_arg_cmd, + "no max-lsp-lifetime level-1 <350-65535>", + NO_STR + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n") + +DEFUN (max_lsp_lifetime_l2, + max_lsp_lifetime_l2_cmd, + "max-lsp-lifetime level-2 <350-65535>", + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n") { struct isis_area *area; uint16_t interval; + int level; area = vty->index; - assert (area); - interval = atoi (argv[0]); + level = IS_LEVEL_2; + return set_lsp_max_lifetime (vty, area, interval, level); +} - if (interval < ISIS_MIN_LSP_LIFETIME) - { - vty_out (vty, "LSP lifetime (%us) below %us%s", - interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE); +DEFUN (no_max_lsp_lifetime_l2, + no_max_lsp_lifetime_l2_cmd, + "no max-lsp-lifetime level-2", + NO_STR + "LSP lifetime for Level 2 only in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; - return CMD_WARNING; - } + area = vty->index; + interval = DEFAULT_LSP_LIFETIME; + level = IS_LEVEL_2; + return set_lsp_max_lifetime (vty, area, interval, level); +} +ALIAS (no_max_lsp_lifetime_l2, + no_max_lsp_lifetime_l2_arg_cmd, + "no max-lsp-lifetime level-2 <350-65535>", + NO_STR + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n") - area->max_lsp_lifetime[0] = interval; - area->max_lsp_lifetime[1] = interval; - area->lsp_refresh[0] = interval - 300; - area->lsp_refresh[1] = interval - 300; +static int +set_lsp_refresh_interval (struct vty *vty, struct isis_area *area, + uint16_t interval, int level) +{ + int lvl; - if (area->t_lsp_refresh[0]) + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { - thread_cancel (area->t_lsp_refresh[0]); - thread_execute (master, lsp_refresh_l1, area, 0); + if (!(lvl & level)) + continue; + if (interval <= area->lsp_gen_interval[lvl-1]) + { + vty_out (vty, "LSP refresh interval %us must be greater than " + "the configured LSP gen interval %us%s", + interval, area->lsp_gen_interval[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) + { + vty_out (vty, "LSP refresh interval %us must be less than " + "the configured LSP lifetime %us less 300%s", + interval, area->max_lsp_lifetime[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } } - if (area->t_lsp_refresh[1]) + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { - thread_cancel (area->t_lsp_refresh[1]); - thread_execute (master, lsp_refresh_l2, area, 0); + if (!(lvl & level)) + continue; + area->lsp_refresh[lvl-1] = interval; } - + lsp_regenerate_schedule (area, level, 1); return CMD_SUCCESS; } -DEFUN (no_lsp_lifetime, - no_lsp_lifetime_cmd, - "no lsp-lifetime", - NO_STR - "LSP lifetime in seconds\n") +DEFUN (lsp_refresh_interval, + lsp_refresh_interval_cmd, + "lsp-refresh-interval <1-65235>", + "LSP refresh interval\n" + "LSP refresh interval in seconds\n") { struct isis_area *area; + uint16_t interval; + int level; area = vty->index; - assert (area); + interval = atoi (argv[0]); + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_refresh_interval (vty, area, interval, level); +} - area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */ - area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */ - area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */ - area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */ +DEFUN (no_lsp_refresh_interval, + no_lsp_refresh_interval_cmd, + "no lsp-refresh-interval", + NO_STR + "LSP refresh interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; - return CMD_SUCCESS; + area = vty->index; + interval = DEFAULT_MAX_LSP_GEN_INTERVAL; + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_refresh_interval (vty, area, interval, level); } -ALIAS (no_lsp_lifetime, - no_lsp_lifetime_arg_cmd, - "no lsp-lifetime <380-65535>", +ALIAS (no_lsp_refresh_interval, + no_lsp_refresh_interval_arg_cmd, + "no lsp-refresh-interval <1-65235>", NO_STR - "Maximum LSP lifetime\n" - "LSP lifetime in seconds\n") + "LSP refresh interval\n" + "LSP refresh interval in seconds\n") -DEFUN (lsp_lifetime_l1, - lsp_lifetime_l1_cmd, - "lsp-lifetime level-1 <380-65535>", - "Maximum LSP lifetime for Level 1 only\n" - "LSP lifetime for Level 1 only in seconds\n") +DEFUN (lsp_refresh_interval_l1, + lsp_refresh_interval_l1_cmd, + "lsp-refresh-interval level-1 <1-65235>", + "LSP refresh interval for Level 1 only\n" + "LSP refresh interval for Level 1 only in seconds\n") { struct isis_area *area; uint16_t interval; + int level; area = vty->index; - assert (area); + interval = atoi (argv[0]); + level = IS_LEVEL_1; + return set_lsp_refresh_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_refresh_interval_l1, + no_lsp_refresh_interval_l1_cmd, + "no lsp-refresh-interval level-1", + NO_STR + "LSP refresh interval for Level 1 only in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MAX_LSP_GEN_INTERVAL; + level = IS_LEVEL_1; + return set_lsp_refresh_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_refresh_interval_l1, + no_lsp_refresh_interval_l1_arg_cmd, + "no lsp-refresh-interval level-1 <1-65235>", + NO_STR + "LSP refresh interval for Level 1 only\n" + "LSP refresh interval for Level 1 only in seconds\n") +DEFUN (lsp_refresh_interval_l2, + lsp_refresh_interval_l2_cmd, + "lsp-refresh-interval level-2 <1-65235>", + "LSP refresh interval for Level 2 only\n" + "LSP refresh interval for Level 2 only in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; interval = atoi (argv[0]); + level = IS_LEVEL_2; + return set_lsp_refresh_interval (vty, area, interval, level); +} - if (interval < ISIS_MIN_LSP_LIFETIME) - { - vty_out (vty, "Level-1 LSP lifetime (%us) below %us%s", - interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE); +DEFUN (no_lsp_refresh_interval_l2, + no_lsp_refresh_interval_l2_cmd, + "no lsp-refresh-interval level-2", + NO_STR + "LSP refresh interval for Level 2 only in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; - return CMD_WARNING; - } + area = vty->index; + interval = DEFAULT_MAX_LSP_GEN_INTERVAL; + level = IS_LEVEL_2; + return set_lsp_refresh_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_refresh_interval_l2, + no_lsp_refresh_interval_l2_arg_cmd, + "no lsp-refresh-interval level-2 <1-65235>", + NO_STR + "LSP refresh interval for Level 2 only\n" + "LSP refresh interval for Level 2 only in seconds\n") + +DEFUN (log_adj_changes, + log_adj_changes_cmd, + "log-adjacency-changes", + "Log changes in adjacency state\n") +{ + struct isis_area *area; + area = vty->index; + assert (area); - area->max_lsp_lifetime[0] = interval; - area->lsp_refresh[0] = interval - 300; + area->log_adj_changes = 1; return CMD_SUCCESS; } -DEFUN (no_lsp_lifetime_l1, - no_lsp_lifetime_l1_cmd, - "no lsp-lifetime level-1", - NO_STR - "LSP lifetime for Level 1 only in seconds\n") +DEFUN (no_log_adj_changes, + no_log_adj_changes_cmd, + "no log-adjacency-changes", + "Stop logging changes in adjacency state\n") { struct isis_area *area; area = vty->index; assert (area); - area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */ - area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */ + area->log_adj_changes = 0; return CMD_SUCCESS; } -ALIAS (no_lsp_lifetime_l1, - no_lsp_lifetime_l1_arg_cmd, - "no lsp-lifetime level-1 <380-65535>", - NO_STR - "Maximum LSP lifetime for Level 1 only\n" - "LSP lifetime for Level 1 only in seconds\n") +#ifdef TOPOLOGY_GENERATE -DEFUN (lsp_lifetime_l2, - lsp_lifetime_l2_cmd, - "lsp-lifetime level-2 <380-65535>", - "Maximum LSP lifetime for Level 2 only\n" - "LSP lifetime for Level 2 only in seconds\n") +DEFUN (topology_generate_grid, + topology_generate_grid_cmd, + "topology generate grid <1-100> <1-100> <1-65000> [param] [param] " + "[param]", + "Topology generation for IS-IS\n" + "Topology generation\n" + "Grid topology\n" + "X parameter of the grid\n" + "Y parameter of the grid\n" + "Random seed\n" + "Optional param 1\n" + "Optional param 2\n" + "Optional param 3\n" + "Topology\n") { struct isis_area *area; - uint16_t interval; area = vty->index; assert (area); - interval = atoi (argv[0]); + if (!spgrid_check_params (vty, argc, argv)) + { + if (area->topology) + list_delete (area->topology); + area->topology = list_new (); + memcpy (area->top_params, vty->buf, 200); + gen_spgrid_topology (vty, area->topology); + remove_topology_lsps (area); + generate_topology_lsps (area); + /* Regenerate L1 LSP to get two way connection to the generated + * topology. */ + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + } - if (interval < ISIS_MIN_LSP_LIFETIME) + return CMD_SUCCESS; +} + +DEFUN (show_isis_generated_topology, + show_isis_generated_topology_cmd, + "show isis generated-topologies", + SHOW_STR + "ISIS network information\n" + "Show generated topologies\n") +{ + struct isis_area *area; + struct listnode *node; + struct listnode *node2; + struct arc *arc; + + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { - vty_out (vty, "Level-2 LSP lifetime (%us) below %us%s", - interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE); + if (!area->topology) + continue; - return CMD_WARNING; + vty_out (vty, "Topology for isis area: %s%s", area->area_tag, + VTY_NEWLINE); + vty_out (vty, "From node To node Distance%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (area->topology, node2, arc)) + vty_out (vty, "%9ld %11ld %12ld%s", arc->from_node, arc->to_node, + arc->distance, VTY_NEWLINE); } + return CMD_SUCCESS; +} + +/* Base IS for topology generation. */ +DEFUN (topology_baseis, + topology_baseis_cmd, + "topology base-is WORD", + "Topology generation for IS-IS\n" + "A Network IS Base for this topology\n" + "XXXX.XXXX.XXXX Network entity title (NET)\n") +{ + struct isis_area *area; + u_char buff[ISIS_SYS_ID_LEN]; + + area = vty->index; + assert (area); - area->max_lsp_lifetime[1] = interval; - area->lsp_refresh[1] = interval - 300; + if (sysid2buff (buff, argv[0])) + sysid2buff (area->topology_baseis, argv[0]); return CMD_SUCCESS; } -DEFUN (no_lsp_lifetime_l2, - no_lsp_lifetime_l2_cmd, - "no lsp-lifetime level-2", +DEFUN (no_topology_baseis, + no_topology_baseis_cmd, + "no topology base-is WORD", NO_STR - "LSP lifetime for Level 2 only in seconds\n") + "Topology generation for IS-IS\n" + "A Network IS Base for this topology\n" + "XXXX.XXXX.XXXX Network entity title (NET)\n") { struct isis_area *area; area = vty->index; assert (area); - area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */ - area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */ - + memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); return CMD_SUCCESS; } -ALIAS (no_lsp_lifetime_l2, - no_lsp_lifetime_l2_arg_cmd, - "no lsp-lifetime level-2 <380-65535>", +ALIAS (no_topology_baseis, + no_topology_baseis_noid_cmd, + "no topology base-is", NO_STR - "Maximum LSP lifetime for Level 2 only\n" - "LSP lifetime for Level 2 only in seconds\n") + "Topology generation for IS-IS\n" + "A Network IS Base for this topology\n") + +DEFUN (topology_basedynh, + topology_basedynh_cmd, + "topology base-dynh WORD", + "Topology generation for IS-IS\n" + "Dynamic hostname base for this topology\n" + "Dynamic hostname base\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + /* I hope that it's enough. */ + area->topology_basedynh = strndup (argv[0], 16); + return CMD_SUCCESS; +} + +#endif /* TOPOLOGY_GENERATE */ /* IS-IS configuration write function */ int @@ -1919,34 +2819,36 @@ isis_config_write (struct vty *vty) vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE); write++; } - /* ISIS - Metric-Style - when true displays wide */ - if (area->newmetric) + /* ISIS - Metric-Style - when true displays narrow */ + if (area->oldmetric) { - if (!area->oldmetric) - vty_out (vty, " metric-style wide%s", VTY_NEWLINE); + if (!area->newmetric) + vty_out (vty, " metric-style narrow%s", VTY_NEWLINE); else vty_out (vty, " metric-style transition%s", VTY_NEWLINE); write++; } - + /* ISIS - overload-bit */ + if (area->overload_bit) + { + vty_out (vty, " set-overload-bit%s", VTY_NEWLINE); + write++; + } /* ISIS - Area is-type (level-1-2 is default) */ if (area->is_type == IS_LEVEL_1) { vty_out (vty, " is-type level-1%s", VTY_NEWLINE); write++; } - else + else if (area->is_type == IS_LEVEL_2) { - if (area->is_type == IS_LEVEL_2) - { - vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); - write++; - } + vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); + write++; } /* ISIS - Lsp generation interval */ if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1]) { - if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT) + if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); @@ -1955,13 +2857,13 @@ isis_config_write (struct vty *vty) } else { - if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT) + if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval level-1 %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); write++; } - if (area->lsp_gen_interval[1] != LSP_GEN_INTERVAL_DEFAULT) + if (area->lsp_gen_interval[1] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval level-2 %d%s", area->lsp_gen_interval[1], VTY_NEWLINE); @@ -1971,28 +2873,53 @@ isis_config_write (struct vty *vty) /* ISIS - LSP lifetime */ if (area->max_lsp_lifetime[0] == area->max_lsp_lifetime[1]) { - if (area->max_lsp_lifetime[0] != MAX_AGE) + if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME) { - vty_out (vty, " lsp-lifetime %u%s", area->max_lsp_lifetime[0], + vty_out (vty, " max-lsp-lifetime %u%s", area->max_lsp_lifetime[0], VTY_NEWLINE); write++; } } else { - if (area->max_lsp_lifetime[0] != MAX_AGE) + if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME) { - vty_out (vty, " lsp-lifetime level-1 %u%s", + vty_out (vty, " max-lsp-lifetime level-1 %u%s", area->max_lsp_lifetime[0], VTY_NEWLINE); write++; } - if (area->max_lsp_lifetime[1] != MAX_AGE) + if (area->max_lsp_lifetime[1] != DEFAULT_LSP_LIFETIME) { - vty_out (vty, " lsp-lifetime level-2 %u%s", + vty_out (vty, " max-lsp-lifetime level-2 %u%s", area->max_lsp_lifetime[1], VTY_NEWLINE); write++; } } + /* ISIS - LSP refresh interval */ + if (area->lsp_refresh[0] == area->lsp_refresh[1]) + { + if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL) + { + vty_out (vty, " lsp-refresh-interval %u%s", area->lsp_refresh[0], + VTY_NEWLINE); + write++; + } + } + else + { + if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL) + { + vty_out (vty, " lsp-refresh-interval level-1 %u%s", + area->lsp_refresh[0], VTY_NEWLINE); + write++; + } + if (area->lsp_refresh[1] != DEFAULT_MAX_LSP_GEN_INTERVAL) + { + vty_out (vty, " lsp-refresh-interval level-2 %u%s", + area->lsp_refresh[1], VTY_NEWLINE); + write++; + } + } /* Minimum SPF interval. */ if (area->min_spf_interval[0] == area->min_spf_interval[1]) { @@ -2019,9 +2946,9 @@ isis_config_write (struct vty *vty) } } /* Authentication passwords. */ - if (area->area_passwd.len > 0) + if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { - vty_out(vty, " area-password %s", area->area_passwd.passwd); + vty_out(vty, " area-password md5 %s", area->area_passwd.passwd); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); @@ -2032,10 +2959,40 @@ isis_config_write (struct vty *vty) } vty_out(vty, "%s", VTY_NEWLINE); write++; - } - if (area->domain_passwd.len > 0) + } + else if (area->area_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) + { + vty_out(vty, " area-password clear %s", area->area_passwd.passwd); + if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND)) + { + vty_out(vty, " authenticate snp "); + if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV)) + vty_out(vty, "validate"); + else + vty_out(vty, "send-only"); + } + vty_out(vty, "%s", VTY_NEWLINE); + write++; + } + if (area->domain_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + vty_out(vty, " domain-password md5 %s", + area->domain_passwd.passwd); + if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND)) + { + vty_out(vty, " authenticate snp "); + if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV)) + vty_out(vty, "validate"); + else + vty_out(vty, "send-only"); + } + vty_out(vty, "%s", VTY_NEWLINE); + write++; + } + else if (area->domain_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { - vty_out(vty, " domain-password %s", area->domain_passwd.passwd); + vty_out(vty, " domain-password clear %s", + area->domain_passwd.passwd); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); @@ -2048,12 +3005,18 @@ isis_config_write (struct vty *vty) write++; } + if (area->log_adj_changes) + { + vty_out (vty, " log-adjacency-changes%s", VTY_NEWLINE); + write++; + } + #ifdef TOPOLOGY_GENERATE if (memcmp (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN)) { vty_out (vty, " topology base-is %s%s", - sysid_print (area->topology_baseis), VTY_NEWLINE); + sysid_print ((u_char *)area->topology_baseis), VTY_NEWLINE); write++; } if (area->topology_basedynh) @@ -2076,7 +3039,7 @@ isis_config_write (struct vty *vty) return write; } -static struct cmd_node isis_node = { +struct cmd_node isis_node = { ISIS_NODE, "%s(config-router)# ", 1 @@ -2088,23 +3051,43 @@ isis_init () /* Install IS-IS top node */ install_node (&isis_node, isis_config_write); - install_element (VIEW_NODE, &show_clns_neighbors_cmd); - install_element (VIEW_NODE, &show_isis_neighbors_cmd); - install_element (VIEW_NODE, &show_clns_neighbors_detail_cmd); - install_element (VIEW_NODE, &show_isis_neighbors_detail_cmd); + install_element (VIEW_NODE, &show_isis_summary_cmd); + + install_element (VIEW_NODE, &show_isis_interface_cmd); + install_element (VIEW_NODE, &show_isis_interface_detail_cmd); + install_element (VIEW_NODE, &show_isis_interface_arg_cmd); + + install_element (VIEW_NODE, &show_isis_neighbor_cmd); + install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd); + install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd); + install_element (VIEW_NODE, &clear_isis_neighbor_cmd); + install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd); install_element (VIEW_NODE, &show_hostname_cmd); install_element (VIEW_NODE, &show_database_cmd); + install_element (VIEW_NODE, &show_database_arg_cmd); + install_element (VIEW_NODE, &show_database_arg_detail_cmd); install_element (VIEW_NODE, &show_database_detail_cmd); + install_element (VIEW_NODE, &show_database_detail_arg_cmd); + + install_element (ENABLE_NODE, &show_isis_summary_cmd); - install_element (ENABLE_NODE, &show_clns_neighbors_cmd); - install_element (ENABLE_NODE, &show_isis_neighbors_cmd); - install_element (ENABLE_NODE, &show_clns_neighbors_detail_cmd); - install_element (ENABLE_NODE, &show_isis_neighbors_detail_cmd); + install_element (ENABLE_NODE, &show_isis_interface_cmd); + install_element (ENABLE_NODE, &show_isis_interface_detail_cmd); + install_element (ENABLE_NODE, &show_isis_interface_arg_cmd); + + install_element (ENABLE_NODE, &show_isis_neighbor_cmd); + install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd); + install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd); + install_element (ENABLE_NODE, &clear_isis_neighbor_cmd); + install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd); install_element (ENABLE_NODE, &show_hostname_cmd); install_element (ENABLE_NODE, &show_database_cmd); + install_element (ENABLE_NODE, &show_database_arg_cmd); + install_element (ENABLE_NODE, &show_database_arg_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_cmd); + install_element (ENABLE_NODE, &show_database_detail_arg_cmd); install_element (ENABLE_NODE, &show_debugging_cmd); install_node (&debug_node, config_write_debug); @@ -2131,6 +3114,8 @@ isis_init () install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd); install_element (ENABLE_NODE, &debug_isis_events_cmd); install_element (ENABLE_NODE, &no_debug_isis_events_cmd); + install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd); + install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &debug_isis_adj_cmd); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd); @@ -2154,6 +3139,8 @@ isis_init () install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd); install_element (CONFIG_NODE, &debug_isis_events_cmd); install_element (CONFIG_NODE, &no_debug_isis_events_cmd); + install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd); + install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &router_isis_cmd); install_element (CONFIG_NODE, &no_router_isis_cmd); @@ -2166,12 +3153,16 @@ isis_init () install_element (ISIS_NODE, &is_type_cmd); install_element (ISIS_NODE, &no_is_type_cmd); - install_element (ISIS_NODE, &area_passwd_cmd); - install_element (ISIS_NODE, &area_passwd_snpauth_cmd); + install_element (ISIS_NODE, &area_passwd_md5_cmd); + install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); + install_element (ISIS_NODE, &area_passwd_clear_cmd); + install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_area_passwd_cmd); - install_element (ISIS_NODE, &domain_passwd_cmd); - install_element (ISIS_NODE, &domain_passwd_snpauth_cmd); + install_element (ISIS_NODE, &domain_passwd_md5_cmd); + install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd); + install_element (ISIS_NODE, &domain_passwd_clear_cmd); + install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_domain_passwd_cmd); install_element (ISIS_NODE, &lsp_gen_interval_cmd); @@ -2194,21 +3185,38 @@ isis_init () install_element (ISIS_NODE, &no_spf_interval_l2_cmd); install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); - install_element (ISIS_NODE, &lsp_lifetime_cmd); - install_element (ISIS_NODE, &no_lsp_lifetime_cmd); - install_element (ISIS_NODE, &no_lsp_lifetime_arg_cmd); - install_element (ISIS_NODE, &lsp_lifetime_l1_cmd); - install_element (ISIS_NODE, &no_lsp_lifetime_l1_cmd); - install_element (ISIS_NODE, &no_lsp_lifetime_l1_arg_cmd); - install_element (ISIS_NODE, &lsp_lifetime_l2_cmd); - install_element (ISIS_NODE, &no_lsp_lifetime_l2_cmd); - install_element (ISIS_NODE, &no_lsp_lifetime_l2_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); + + install_element (ISIS_NODE, &lsp_refresh_interval_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); + install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); + install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &set_overload_bit_cmd); + install_element (ISIS_NODE, &no_set_overload_bit_cmd); install_element (ISIS_NODE, &dynamic_hostname_cmd); install_element (ISIS_NODE, &no_dynamic_hostname_cmd); install_element (ISIS_NODE, &metric_style_cmd); install_element (ISIS_NODE, &no_metric_style_cmd); + + install_element (ISIS_NODE, &log_adj_changes_cmd); + install_element (ISIS_NODE, &no_log_adj_changes_cmd); + #ifdef TOPOLOGY_GENERATE install_element (ISIS_NODE, &topology_generate_grid_cmd); install_element (ISIS_NODE, &topology_baseis_cmd); @@ -2218,9 +3226,4 @@ isis_init () install_element (VIEW_NODE, &show_isis_generated_topology_cmd); install_element (ENABLE_NODE, &show_isis_generated_topology_cmd); #endif /* TOPOLOGY_GENERATE */ - - isis_new (0); - isis_circuit_init (); - isis_zebra_init (); - isis_spf_cmds_init (); } diff --git a/isisd/isisd.h b/isisd/isisd.h index 2277f27c6..5db485f47 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -40,6 +40,7 @@ struct isis u_long process_id; int sysid_set; u_char sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */ + u_int32_t router_id; /* Router ID from zebra */ struct list *area_list; /* list of IS-IS areas */ struct list *init_circ_list; struct list *nexthops; /* IPv4 next hops from this IS */ @@ -78,6 +79,8 @@ struct isis #endif }; +extern struct isis *isis; + struct isis_area { struct isis *isis; /* back pointer */ @@ -92,9 +95,8 @@ struct isis_area struct list *circuit_list; /* IS-IS circuits */ struct flags flags; struct thread *t_tick; /* LSP walker */ - struct thread *t_remove_aged; - int lsp_regenerate_pending[ISIS_LEVELS]; struct thread *t_lsp_refresh[ISIS_LEVELS]; + int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables @@ -112,6 +114,8 @@ struct isis_area struct list *area_addrs; u_int16_t max_lsp_lifetime[ISIS_LEVELS]; char is_type; /* level-1 level-1-2 or level-2-only */ + /* are we overloaded? */ + char overload_bit; u_int16_t lsp_refresh[ISIS_LEVELS]; /* minimum time allowed before lsp retransmission */ u_int16_t lsp_gen_interval[ISIS_LEVELS]; @@ -120,6 +124,8 @@ struct isis_area /* the percentage of LSP mtu size used, before generating a new frag */ int lsp_frag_threshold; int ip_circuits; + /* logging adjacency changes? */ + u_char log_adj_changes; #ifdef HAVE_IPV6 int ipv6_circuits; #endif /* HAVE_IPV6 */ @@ -128,14 +134,21 @@ struct isis_area #ifdef TOPOLOGY_GENERATE struct list *topology; - char topology_baseis[ISIS_SYS_ID_LEN]; /* IS for the first IS emulated. */ + u_char topology_baseis[ISIS_SYS_ID_LEN]; /* IS for the first IS emulated. */ char *topology_basedynh; /* Dynamic hostname base. */ char top_params[200]; /* FIXME: what is reasonable? */ #endif /* TOPOLOGY_GENERATE */ }; void isis_init (void); +void isis_new(unsigned long); +struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup (const char *); +int isis_area_get (struct vty *vty, const char *area_tag); +void print_debug(struct vty *, int, int); + +/* Master of threads. */ +extern struct thread_master *master; #define DEBUG_ADJ_PACKETS (1<<0) #define DEBUG_CHECKSUM_ERRORS (1<<1) @@ -149,5 +162,6 @@ struct isis_area *isis_area_lookup (const char *); #define DEBUG_RTE_EVENTS (1<<9) #define DEBUG_EVENTS (1<<10) #define DEBUG_ZEBRA (1<<11) +#define DEBUG_PACKET_DUMP (1<<12) #endif /* ISISD_H */ diff --git a/lib/memtypes.c b/lib/memtypes.c index 590206718..69beb1c95 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -242,6 +242,8 @@ struct memory_list memory_list_isis[] = { MTYPE_ISIS_ROUTE_INFO, "ISIS route info" }, { MTYPE_ISIS_NEXTHOP, "ISIS nexthop" }, { MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6" }, + { MTYPE_ISIS_DICT, "ISIS dictionary" }, + { MTYPE_ISIS_DICT_NODE, "ISIS dictionary node" }, { -1, NULL }, }; From e38e0df01ad305ad48ecf816b52fa99fd3f2a4e1 Mon Sep 17 00:00:00 2001 From: Subbaiah Venkata Date: Tue, 27 Mar 2012 23:48:05 -0700 Subject: [PATCH 0016/1342] isisd: couple of bug fixes --- isisd/AUTHORS | 7 ++- isisd/isis_adjacency.c | 98 +++++++++++++++-------------- isisd/isis_adjacency.h | 3 + isisd/isis_circuit.c | 10 +++ isisd/isis_events.c | 47 +++++++------- isisd/isis_lsp.c | 42 ++++++++----- isisd/isis_pdu.c | 138 ++++++++++++++++++++++++++++------------- isisd/isis_pdu.h | 6 +- isisd/isis_route.c | 18 ++++-- isisd/isis_route.h | 2 + isisd/isis_spf.c | 84 +++++++++++++++---------- isisd/isis_spf.h | 3 +- isisd/isisd.c | 105 +++++++++++++++++++------------ 13 files changed, 348 insertions(+), 215 deletions(-) diff --git a/isisd/AUTHORS b/isisd/AUTHORS index d9f98b22a..05fc0a507 100644 --- a/isisd/AUTHORS +++ b/isisd/AUTHORS @@ -1,3 +1,4 @@ -Sampo Saaristo -Ofer Wald -Hannes Gredler +Sampo Saaristo +Ofer Wald +Hannes Gredler +Subbaiah Venkata diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 10bce3e8a..468b0a69c 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -220,29 +220,33 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) - { - circuit->upadjcount[level - 1]++; - isis_event_adjacency_state_change (adj, new_state); - /* update counter & timers for debugging purposes */ - adj->last_flap = time (NULL); - adj->flaps++; - } + { + circuit->upadjcount[level - 1]++; + isis_event_adjacency_state_change (adj, new_state); + /* update counter & timers for debugging purposes */ + adj->last_flap = time (NULL); + adj->flaps++; + } else if (new_state == ISIS_ADJ_DOWN) - { - listnode_delete (circuit->u.bc.adjdb[level - 1], adj); - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - { - /* Clean lsp_queue when no adj is up. */ - if (circuit->lsp_queue) - list_delete_all_node (circuit->lsp_queue); - } - isis_event_adjacency_state_change (adj, new_state); - isis_delete_adj (adj); - } - list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); - isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], - circuit->u.bc.lan_neighs[level - 1]); + { + listnode_delete (circuit->u.bc.adjdb[level - 1], adj); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + { + /* Clean lsp_queue when no adj is up. */ + if (circuit->lsp_queue) + list_delete_all_node (circuit->lsp_queue); + } + isis_event_adjacency_state_change (adj, new_state); + isis_delete_adj (adj); + } + + if (circuit->u.bc.lan_neighs[level - 1]) + { + list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); + isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], + circuit->u.bc.lan_neighs[level - 1]); + } /* On adjacency state change send new pseudo LSP if we are the DR */ if (circuit->u.bc.is_dr[level - 1]) @@ -256,35 +260,35 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) - { - circuit->upadjcount[level - 1]++; - isis_event_adjacency_state_change (adj, new_state); + { + circuit->upadjcount[level - 1]++; + isis_event_adjacency_state_change (adj, new_state); - if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) - send_hello (circuit, level); + if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) + send_hello (circuit, level); - /* update counter & timers for debugging purposes */ - adj->last_flap = time (NULL); - adj->flaps++; + /* update counter & timers for debugging purposes */ + adj->last_flap = time (NULL); + adj->flaps++; - /* 7.3.17 - going up on P2P -> send CSNP */ - /* FIXME: yup, I know its wrong... but i will do it! (for now) */ - send_csnp (circuit, level); - } + /* 7.3.17 - going up on P2P -> send CSNP */ + /* FIXME: yup, I know its wrong... but i will do it! (for now) */ + send_csnp (circuit, level); + } else if (new_state == ISIS_ADJ_DOWN) - { - if (adj->circuit->u.p2p.neighbor == adj) - adj->circuit->u.p2p.neighbor = NULL; - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - { - /* Clean lsp_queue when no adj is up. */ - if (circuit->lsp_queue) - list_delete_all_node (circuit->lsp_queue); - } - isis_event_adjacency_state_change (adj, new_state); - isis_delete_adj (adj); - } + { + if (adj->circuit->u.p2p.neighbor == adj) + adj->circuit->u.p2p.neighbor = NULL; + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + { + /* Clean lsp_queue when no adj is up. */ + if (circuit->lsp_queue) + list_delete_all_node (circuit->lsp_queue); + } + isis_event_adjacency_state_change (adj, new_state); + isis_delete_adj (adj); + } } } diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 04a925059..caa3107db 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -44,6 +44,7 @@ enum isis_system_type enum isis_adj_state { + ISIS_ADJ_UNKNOWN, ISIS_ADJ_INITIALIZING, ISIS_ADJ_UP, ISIS_ADJ_DOWN @@ -83,8 +84,10 @@ struct isis_adjacency struct list *area_addrs; /* areaAdressesOfNeighbour */ struct nlpids nlpids; /* protocols spoken ... */ struct list *ipv4_addrs; + struct in_addr router_address; #ifdef HAVE_IPV6 struct list *ipv6_addrs; + struct in6_addr router_address6; #endif /* HAVE_IPV6 */ u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index cb439e877..c09c3a282 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -2720,6 +2720,15 @@ isis_if_new_hook (struct interface *ifp) int isis_if_delete_hook (struct interface *ifp) { + struct isis_circuit *circuit; + /* Clean up the circuit data */ + if (ifp && ifp->info) + { + circuit = ifp->info; + isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area); + isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area); + } + return 0; } @@ -2734,6 +2743,7 @@ isis_circuit_init () /* Install interface node */ install_node (&interface_node, isis_interface_config_write); install_element (CONFIG_NODE, &interface_cmd); + install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 750a4c384..3887b7c5a 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -130,20 +130,16 @@ isis_event_system_type_change (struct isis_area *area, int newtype) { case IS_LEVEL_1: if (newtype == IS_LEVEL_2) - { area_resign_level (area, IS_LEVEL_1); - } - else - { - if (area->lspdb[1] == NULL) - area->lspdb[1] = lsp_db_init (); - if (area->route_table[1] == NULL) - area->route_table[1] = route_table_init (); + + if (area->lspdb[1] == NULL) + area->lspdb[1] = lsp_db_init (); + if (area->route_table[1] == NULL) + area->route_table[1] = route_table_init (); #ifdef HAVE_IPV6 - if (area->route_table6[1] == NULL) - area->route_table6[1] = route_table_init (); + if (area->route_table6[1] == NULL) + area->route_table6[1] = route_table_init (); #endif /* HAVE_IPV6 */ - } break; case IS_LEVEL_1_AND_2: @@ -155,21 +151,18 @@ isis_event_system_type_change (struct isis_area *area, int newtype) case IS_LEVEL_2: if (newtype == IS_LEVEL_1) - { area_resign_level (area, IS_LEVEL_2); - } - else - { - if (area->lspdb[0] == NULL) - area->lspdb[0] = lsp_db_init (); - if (area->route_table[0] == NULL) - area->route_table[0] = route_table_init (); + + if (area->lspdb[0] == NULL) + area->lspdb[0] = lsp_db_init (); + if (area->route_table[0] == NULL) + area->route_table[0] = route_table_init (); #ifdef HAVE_IPV6 - if (area->route_table6[0] == NULL) - area->route_table6[0] = route_table_init (); + if (area->route_table6[0] == NULL) + area->route_table6[0] = route_table_init (); #endif /* HAVE_IPV6 */ - } break; + default: break; } @@ -199,8 +192,9 @@ circuit_commence_level (struct isis_circuit *circuit, int level) { if (level == 1) { - THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, - isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); + if (! circuit->is_passive) + THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, + isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { @@ -217,8 +211,9 @@ circuit_commence_level (struct isis_circuit *circuit, int level) } else { - THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, - isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); + if (! circuit->is_passive) + THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, + isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index f71794323..5c1e9931d 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -441,6 +441,19 @@ lsp_seqnum_update (struct isis_lsp *lsp0) return; } +static u_int8_t +lsp_bits_generate (int level, int overload_bit) +{ + u_int8_t lsp_bits = 0; + if (level == IS_LEVEL_1) + lsp_bits = IS_LEVEL_1; + else + lsp_bits = IS_LEVEL_1_AND_2; + if (overload_bit) + lsp_bits |= overload_bit; + return lsp_bits; +} + static void lsp_update_data (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level) @@ -470,8 +483,6 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream, expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_IS_NEIGHS; - if ((lsp->lsp_header->lsp_bits & 3) == 3) /* a level 2 LSP */ - expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS; expected |= TLVFLAG_NLPID; if (area->dynhostname) expected |= TLVFLAG_DYN_HOSTNAME; @@ -503,10 +514,9 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream, if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) { - isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, - (lsp->lsp_header->lsp_bits & LSPBIT_IST) == - IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : - (lsp->lsp_header->lsp_bits & LSPBIT_IST)); + isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, + (lsp->lsp_header->lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1); } return; @@ -1125,7 +1135,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, return lsp; } lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, - area->is_type | area->overload_bit, 0, level); + lsp_bits_generate (level, area->overload_bit), 0, level); lsp->area = area; lsp->own_lsp = 1; lsp_insert (lsp, area->lspdb[level - 1]); @@ -1644,7 +1654,7 @@ lsp_regenerate (struct isis_area *area, int level) lsp_clear_data (lsp); lsp_build (lsp, area); - lsp->lsp_header->lsp_bits = area->is_type | area->overload_bit; + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit); rem_lifetime = lsp_rem_lifetime (area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_seqnum_update (lsp); @@ -1653,7 +1663,8 @@ lsp_regenerate (struct isis_area *area, int level) lsp_set_all_srmflags (lsp); for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag)) { - frag->lsp_header->lsp_bits = area->is_type | area->overload_bit; + frag->lsp_header->lsp_bits = lsp_bits_generate (level, + area->overload_bit); /* Set the lifetime values of all the fragments to the same value, * so that no fragment expires before the lsp is refreshed. */ @@ -1803,10 +1814,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - if (level == IS_LEVEL_1) - lsp->lsp_header->lsp_bits |= IS_LEVEL_1; - else - lsp->lsp_header->lsp_bits |= IS_LEVEL_2; + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); /* * add self to IS neighbours @@ -2002,7 +2010,7 @@ lsp_regenerate_pseudo (struct isis_circuit *circuit, int level) lsp_build_pseudo (lsp, circuit, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp->lsp_header->lsp_bits = circuit->area->is_type; + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); rem_lifetime = lsp_rem_lifetime (circuit->area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_inc_seqnum (lsp, 0); @@ -2321,7 +2329,8 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, */ lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp->area = area; - lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2; + lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? + IS_LEVEL_1 : IS_LEVEL_2; /* FIXME: Should be minimal mtu? */ lsp->pdu = stream_new (1500); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); @@ -2404,7 +2413,8 @@ top_lsp_refresh (struct thread *thread) isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, IS_LEVEL_1); - lsp->lsp_header->lsp_bits = lsp->area->is_type | lsp->area->overload_bit; + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, + lsp->area->overload_bit); rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index fe943bbaa..497fad20f 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -62,7 +62,7 @@ #endif /* PNBBY */ /* Utility mask array. */ -static const u_char maskbit[] = { +static u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; @@ -225,16 +225,16 @@ lsp_authentication_check (struct stream *stream, struct isis_area *area, { struct isis_link_state_hdr *hdr; uint32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t checksum, rem_lifetime; + uint16_t checksum, rem_lifetime, pdu_len; struct tlvs tlvs; int retval = ISIS_OK; hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); + pdu_len = ntohs (hdr->pdu_len); expected |= TLVFLAG_AUTH_INFO; auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN; retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN, - ntohs (hdr->pdu_len) - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, + pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval != ISIS_OK) @@ -243,7 +243,7 @@ lsp_authentication_check (struct stream *stream, struct isis_area *area, "cksum 0x%04x, lifetime %us, len %u", area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), - ntohs (hdr->rem_lifetime), ntohs (hdr->pdu_len)); + ntohs (hdr->rem_lifetime), pdu_len); if ((isis->debugs & DEBUG_UPDATE_PACKETS) && (isis->debugs & DEBUG_PACKET_DUMP)) zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream)); @@ -397,6 +397,7 @@ process_p2p_hello (struct isis_circuit *circuit) struct isis_p2p_hello_hdr *hdr; struct isis_adjacency *adj; u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; + uint16_t pdu_len; struct tlvs tlvs; if (isis->debugs & DEBUG_ADJ_PACKETS) @@ -439,23 +440,26 @@ process_p2p_hello (struct isis_circuit *circuit) * Get the header */ hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); - stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); - - /* hdr.circuit_t = stream_getc (stream); - stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN); - hdr.hold_time = stream_getw (stream); - hdr.pdu_len = stream_getw (stream); - hdr.local_id = stream_getc (stream); */ + pdu_len = ntohs (hdr->pdu_len); - if (ntohs (hdr->pdu_len) > ISO_MTU(circuit)) + if (pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, - ntohs (hdr->pdu_len)); + circuit->area->area_tag, circuit->interface->name, pdu_len); return ISIS_WARNING; } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, pdu_len); + + stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); + /* * Lets get the TLVS now */ @@ -468,9 +472,8 @@ process_p2p_hello (struct isis_circuit *circuit) auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), - ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN - - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, - &auth_tlv_offset); + pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { @@ -821,7 +824,7 @@ process_p2p_hello (struct isis_circuit *circuit) " cir id %02d, length %d", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), - circuit->circuit_id, ntohs (hdr->pdu_len)); + circuit->circuit_id, pdu_len); } free_tlvs (&tlvs); @@ -906,15 +909,23 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) hdr.prio = stream_getc (circuit->rcv_stream); stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - if (hdr.pdu_len > ISO_MTU(circuit)) + if (hdr.pdu_len > ISO_MTU(circuit) || + hdr.pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " "invalid pdu length %d", circuit->area->area_tag, circuit->interface->name, hdr.pdu_len); - hdr.pdu_len = stream_get_endp (circuit->rcv_stream); + return ISIS_WARNING; } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, hdr.pdu_len); + if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 && hdr.circuit_t != IS_LEVEL_1_AND_2 && @@ -1167,6 +1178,7 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) int retval = ISIS_OK, comp = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; + uint16_t pdu_len; if (isis->debugs & DEBUG_UPDATE_PACKETS) { @@ -1187,6 +1199,26 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* Reference the header */ hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream); + pdu_len = ntohs (hdr->pdu_len); + + /* lsp length check */ + if (pdu_len < ISIS_LSP_HDR_LEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) + { + zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", + circuit->area->area_tag, + rawlspid_print (hdr->lsp_id), pdu_len); + + return ISIS_WARNING; + } + + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, pdu_len); if (isis->debugs & DEBUG_UPDATE_PACKETS) { @@ -1198,24 +1230,25 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), - ntohs (hdr->pdu_len), + pdu_len, circuit->interface->name); } - if (ntohs (hdr->pdu_len) <= ISIS_LSP_HDR_LEN || - ntohs (hdr->pdu_len) > ISO_MTU(circuit)) + /* lsp is_type check */ + if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 && + (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) { - zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", + zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x", circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), ntohs (hdr->pdu_len)); - - return ISIS_WARNING; + rawlspid_print (hdr->lsp_id), hdr->lsp_bits); + /* continue as per RFC1122 Be liberal in what you accept, and + * conservative in what you send */ } /* Checksum sanity check - FIXME: move to correct place */ /* 12 = sysid+pdu+remtime */ if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4, - ntohs (hdr->pdu_len) - 12, &hdr->checksum)) + pdu_len - 12, &hdr->checksum)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", circuit->area->area_tag, @@ -1403,17 +1436,19 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) * has information that the current sequence number for source S is * "greater" than that held by S, ... */ - else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) + if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { /* 7.3.16.1 */ lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); - lsp_set_all_srmflags (lsp); if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq " "0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); } + /* If the received LSP is older or equal, + * resend the LSP which will act as ACK */ + lsp_set_all_srmflags (lsp); } else { @@ -1440,7 +1475,7 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) if (!lsp) { lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, - ntohs (hdr->pdu_len), lsp0, + pdu_len, lsp0, circuit->area, level); lsp_insert (lsp, circuit->area->lspdb[level - 1]); } @@ -1489,7 +1524,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, int retval = ISIS_OK; int cmp, own_lsp; char typechar = ' '; - unsigned int len; + uint16_t pdu_len; struct isis_adjacency *adj; struct isis_complete_seqnum_hdr *chdr = NULL; struct isis_partial_seqnum_hdr *phdr = NULL; @@ -1508,12 +1543,14 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, typechar = 'C'; chdr = (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN; - len = ntohs (chdr->pdu_len); - if (len < ISIS_CSNP_HDRLEN || len > ISO_MTU(circuit)) + stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); + pdu_len = ntohs (chdr->pdu_len); + if (pdu_len < ISIS_CSNP_HDRLEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { - zlog_warn ("Received a CSNP with bogus length %d", len); - return ISIS_OK; + zlog_warn ("Received a CSNP with bogus length %d", pdu_len); + return ISIS_WARNING; } } else @@ -1521,15 +1558,24 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, typechar = 'P'; phdr = (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN; - len = ntohs (phdr->pdu_len); - if (len < ISIS_PSNP_HDRLEN || len > ISO_MTU(circuit)) + stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); + pdu_len = ntohs (phdr->pdu_len); + if (pdu_len < ISIS_PSNP_HDRLEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { - zlog_warn ("Received a CSNP with bogus length %d", len); - return ISIS_OK; + zlog_warn ("Received a CSNP with bogus length %d", pdu_len); + return ISIS_WARNING; } } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, pdu_len); + /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ if (circuit->ext_domain) { @@ -1617,7 +1663,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), - len - circuit->rcv_stream->getp, + pdu_len - stream_get_getp (circuit->rcv_stream), &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) @@ -2585,6 +2631,7 @@ max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit) auth_tlv_len = auth_tlv_length (level, circuit); lsp_count = get_max_lsp_count ( stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len); + return lsp_count; } /* @@ -2862,6 +2909,9 @@ send_psnp (int level, struct isis_circuit *circuit) dict_count (circuit->area->lspdb[level - 1]) == 0) return ISIS_OK; + if (! circuit->snd_stream) + return ISIS_ERROR; + num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); while (1) diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h index 9e215535e..3eca73193 100644 --- a/isisd/isis_pdu.h +++ b/isisd/isis_pdu.h @@ -114,7 +114,7 @@ struct isis_fixed_hdr * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Holding Time | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | PDU Lenght | 2 + * | PDU Length | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | R | Priority | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -142,7 +142,7 @@ struct isis_lan_hello_hdr * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Holding Time + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + PDU Lenght + 2 + * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Local Circuit ID | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -202,7 +202,7 @@ struct isis_link_state_hdr /* * L1 and L2 IS to IS complete sequence numbers PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + PDU Lenght + 2 + * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len + 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 96d8df8fa..c99d95831 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -244,6 +244,7 @@ adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj) { nh = isis_nexthop_create (ipv4_addr, adj->circuit->interface->ifindex); + nh->router_address = adj->router_address; listnode_add (nexthops, nh); } } @@ -267,6 +268,7 @@ adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj) { nh6 = isis_nexthop6_create (ipv6_addr, adj->circuit->interface->ifindex); + nh6->router_address6 = adj->router_address6; listnode_add (nexthops6, nh6); } } @@ -274,8 +276,8 @@ adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj) #endif /* HAVE_IPV6 */ static struct isis_route_info * -isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, - struct list *adjacencies) +isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth, + struct list *adjacencies) { struct isis_route_info *rinfo; struct isis_adjacency *adj; @@ -288,7 +290,7 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, return NULL; } - if (family == AF_INET) + if (prefix->family == AF_INET) { rinfo->nexthops = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) @@ -296,11 +298,14 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, /* check for force resync this route */ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + /* update neighbor router address */ + if (depth == 2 && prefix->prefixlen == 32) + adj->router_address = prefix->u.prefix4; adjinfo2nexthop (rinfo->nexthops, adj); } } #ifdef HAVE_IPV6 - if (family == AF_INET6) + if (prefix->family == AF_INET6) { rinfo->nexthops6 = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) @@ -308,6 +313,9 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, /* check for force resync this route */ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + /* update neighbor router address */ + if (depth == 2 && prefix->prefixlen == 128) + adj->router_address6 = prefix->u.prefix6; adjinfo2nexthop6 (rinfo->nexthops6, adj); } } @@ -415,7 +423,7 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, /* for debugs */ prefix2str (prefix, (char *) buff, BUFSIZ); - rinfo_new = isis_route_info_new (cost, depth, family, adjacencies); + rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies); if (!rinfo_new) { zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 1312400c8..5adea2293 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -30,6 +30,7 @@ struct isis_nexthop6 { unsigned int ifindex; struct in6_addr ip6; + struct in6_addr router_address6; unsigned int lock; }; #endif /* HAVE_IPV6 */ @@ -38,6 +39,7 @@ struct isis_nexthop { unsigned int ifindex; struct in_addr ip; + struct in_addr router_address; unsigned int lock; }; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index a91742b62..198104a98 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -274,7 +274,8 @@ isis_spftree_new (struct isis_area *area) tree->tents = list_new (); tree->paths = list_new (); tree->area = area; - tree->lastrun = 0; + tree->last_run_timestamp = 0; + tree->last_run_duration = 0; tree->runcount = 0; tree->pending = 0; return tree; @@ -408,12 +409,16 @@ spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj) static struct isis_lsp * isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid) { + struct isis_lsp *lsp; u_char lspid[ISIS_SYS_ID_LEN + 2]; memcpy (lspid, sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lspid) = 0; LSP_FRAGMENT (lspid) = 0; - return (lsp_search (lspid, area->lspdb[level - 1])); + lsp = lsp_search (lspid, area->lspdb[level - 1]); + if (lsp && lsp->lsp_header->rem_lifetime != 0) + return lsp; + return NULL; } /* @@ -1021,7 +1026,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, LSP_PSEUDO_ID (lsp_id) = 0; LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); - if (!lsp) + if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency " "L%d on %s (ID %u)", rawlspid_print (lsp_id), level, @@ -1171,6 +1176,13 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) u_char lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; struct route_table *table = NULL; + struct timespec time_now; + unsigned long long start_time, end_time; + + /* Get time that can't roll backwards. */ + clock_gettime(CLOCK_MONOTONIC, &time_now); + start_time = time_now.tv_sec; + start_time = (start_time * 1000000) + (time_now.tv_nsec / 1000); if (family == AF_INET) spftree = area->spftree[level - 1]; @@ -1237,7 +1249,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); - if (lsp) + if (lsp && lsp->lsp_header->rem_lifetime != 0) { if (LSP_PSEUDO_ID (lsp_id)) { @@ -1263,9 +1275,14 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) out: isis_route_validate (area); - spftree->lastrun = time (NULL); - spftree->runcount++; spftree->pending = 0; + spftree->runcount++; + spftree->last_run_timestamp = time (NULL); + clock_gettime(CLOCK_MONOTONIC, &time_now); + end_time = time_now.tv_sec; + end_time = (end_time * 1000000) + (time_now.tv_nsec / 1000); + spftree->last_run_duration = end_time - start_time; + return retval; } @@ -1332,7 +1349,7 @@ isis_spf_schedule (struct isis_area *area, int level) { struct isis_spftree *spftree = area->spftree[level - 1]; time_t now = time (NULL); - int diff = now - spftree->lastrun; + int diff = now - spftree->last_run_timestamp; assert (diff >= 0); assert (area->is_type & level); @@ -1346,20 +1363,20 @@ isis_spf_schedule (struct isis_area *area, int level) THREAD_TIMER_OFF (spftree->t_spf); - /* wait MINIMUM_SPF_INTERVAL before doing the SPF */ - if (diff >= MINIMUM_SPF_INTERVAL) + /* wait configured min_spf_interval before doing the SPF */ + if (diff >= area->min_spf_interval[level-1]) return isis_run_spf (area, level, AF_INET, isis->sysid); if (level == 1) THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, - MINIMUM_SPF_INTERVAL - diff); + area->min_spf_interval[0] - diff); else THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, - MINIMUM_SPF_INTERVAL - diff); + area->min_spf_interval[1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", - area->area_tag, level, MINIMUM_SPF_INTERVAL - diff); + area->area_tag, level, area->min_spf_interval[level-1] - diff); spftree->pending = 1; @@ -1428,34 +1445,37 @@ isis_spf_schedule6 (struct isis_area *area, int level) { int retval = ISIS_OK; struct isis_spftree *spftree = area->spftree6[level - 1]; - time_t diff, now = time (NULL); + time_t now = time (NULL); + time_t diff = now - spftree->last_run_timestamp; + + assert (diff >= 0); + assert (area->is_type & level); + + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", + area->area_tag, level, diff); if (spftree->pending) - return retval; + return ISIS_OK; THREAD_TIMER_OFF (spftree->t_spf); - /* FIXME: let's wait MINIMUM_SPF_INTERVAL before doing the SPF */ - if (now - isis->uptime < MINIMUM_SPF_INTERVAL || isis->uptime == 0) - diff = 0; + /* wait configured min_spf_interval before doing the SPF */ + if (diff >= area->min_spf_interval[level-1]) + return isis_run_spf (area, level, AF_INET6, isis->sysid); + + if (level == 1) + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, + area->min_spf_interval[0] - diff); else - diff = now - spftree->lastrun; + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, + area->min_spf_interval[1] - diff); - if (diff < MINIMUM_SPF_INTERVAL) - { - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, - MINIMUM_SPF_INTERVAL - diff); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, - MINIMUM_SPF_INTERVAL - diff); + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", + area->area_tag, level, area->min_spf_interval[level-1] - diff); - spftree->pending = 1; - } - else - { - retval = isis_run_spf (area, level, AF_INET6, isis->sysid); - } + spftree->pending = 1; return retval; } diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index f31b51056..aa543b705 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -68,8 +68,9 @@ struct isis_spftree struct list *tents; /* TENT */ struct isis_area *area; /* back pointer to area */ int pending; /* already scheduled */ - time_t lastrun; /* for scheduling */ unsigned int runcount; /* number of runs since uptime */ + time_t last_run_timestamp; /* last run timestamp for scheduling */ + time_t last_run_duration; /* last run duration in msec */ }; struct isis_spftree * isis_spftree_new (struct isis_area *area); diff --git a/isisd/isisd.c b/isisd/isisd.c index 6cbb85b1b..e8e3d9f0a 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -720,7 +720,7 @@ DEFUN (clear_isis_neighbor, DEFUN (clear_isis_neighbor_arg, clear_isis_neighbor_arg_cmd, - "claer isis neighbor WORD", + "clear isis neighbor WORD", CLEAR_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" @@ -1273,10 +1273,13 @@ DEFUN (show_isis_summary, vty_out (vty, " minimum interval : %d%s", area->min_spf_interval[level - 1], VTY_NEWLINE); - vty_out (vty, " last run : "); - vty_out_timestr(vty, spftree->lastrun); + vty_out (vty, " last run elapsed : "); + vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " last run duration : %u usec%s", + (u_int32_t)spftree->last_run_duration, VTY_NEWLINE); + vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); @@ -1290,10 +1293,13 @@ DEFUN (show_isis_summary, vty_out (vty, " minimum interval : %d%s", area->min_spf_interval[level - 1], VTY_NEWLINE); - vty_out (vty, " last run : "); - vty_out_timestr(vty, spftree->lastrun); + vty_out (vty, " last run elapsed : "); + vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " last run duration : %u msec%s", + spftree->last_run_duration, VTY_NEWLINE); + vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); #endif @@ -1329,7 +1335,7 @@ show_isis_database (struct vty *vty, const char *argv, int ui_level) struct isis_dynhn *dynhn; const char *pos = argv; u_char lspid[ISIS_SYS_ID_LEN+2]; - char sysid[15]; /* len of xxxx.xxxx.xxxx + place for #0 termination */ + char sysid[255]; u_char number[3]; int level, lsp_count; @@ -1337,13 +1343,7 @@ show_isis_database (struct vty *vty, const char *argv, int ui_level) return CMD_SUCCESS; memset (&lspid, 0, ISIS_SYS_ID_LEN); - memset (&sysid, 0, 15); - - if (argv) - { - strncpy (sysid, argv, 15); - sysid[14] = '\0'; - } + memset (&sysid, 0, 255); /* * extract fragment and pseudo id from the string argv @@ -1354,6 +1354,8 @@ show_isis_database (struct vty *vty, const char *argv, int ui_level) * Where systemid is in the form: * xxxx.xxxx.xxxx */ + if (argv) + strncpy (sysid, argv, 254); if (argv && strlen (argv) > 3) { pos = argv + strlen (argv) - 3; @@ -2033,6 +2035,44 @@ ALIAS (no_lsp_gen_interval_l2, "Set interval for level 2 only\n" "Minimum interval in seconds\n") +static int +validate_metric_style_narrow (struct vty *vty, struct isis_area *area) +{ + struct isis_circuit *circuit; + struct listnode *node; + + if (! vty) + return CMD_ERR_AMBIGUOUS; + + if (! area) + { + vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + { + if ((area->is_type & IS_LEVEL_1) && + (circuit->is_type & IS_LEVEL_1) && + (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if ((area->is_type & IS_LEVEL_2) && + (circuit->is_type & IS_LEVEL_2) && + (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + return CMD_SUCCESS; +} + DEFUN (metric_style, metric_style_cmd, "metric-style (narrow|transition|wide)", @@ -2042,8 +2082,7 @@ DEFUN (metric_style, "Use new style of TLVs to carry wider metric\n") { struct isis_area *area; - struct isis_circuit *circuit; - struct listnode *node; + int ret; area = vty->index; assert (area); @@ -2060,25 +2099,10 @@ DEFUN (metric_style, } else if (strncmp (argv[0], "n", 1) == 0) { - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - { - if ((area->is_type & IS_LEVEL_1) && - (circuit->is_type & IS_LEVEL_1) && - (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC)) - { - vty_out (vty, "ISIS circuit %s metric is invalid%s", - circuit->interface->name, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - if ((area->is_type & IS_LEVEL_2) && - (circuit->is_type & IS_LEVEL_2) && - (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC)) - { - vty_out (vty, "ISIS circuit %s metric is invalid%s", - circuit->interface->name, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + area->newmetric = 0; area->oldmetric = 1; } @@ -2093,10 +2117,15 @@ DEFUN (no_metric_style, "Use old-style (ISO 10589) or new-style packet formats\n") { struct isis_area *area; + int ret; area = vty->index; assert (area); + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + /* Default is narrow metric. */ area->newmetric = 0; area->oldmetric = 1; @@ -2819,11 +2848,11 @@ isis_config_write (struct vty *vty) vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE); write++; } - /* ISIS - Metric-Style - when true displays narrow */ - if (area->oldmetric) + /* ISIS - Metric-Style - when true displays wide */ + if (area->newmetric) { - if (!area->newmetric) - vty_out (vty, " metric-style narrow%s", VTY_NEWLINE); + if (!area->oldmetric) + vty_out (vty, " metric-style wide%s", VTY_NEWLINE); else vty_out (vty, " metric-style transition%s", VTY_NEWLINE); write++; From fc328ac9d3d49b871c1139f36deb702a254c0d4f Mon Sep 17 00:00:00 2001 From: Subbaiah Venkata Date: Tue, 27 Mar 2012 16:35:22 -0700 Subject: [PATCH 0017/1342] zebra: add more logs/asserts to rib work queue code * zebra/zebra_rib.c: (rib_queue_add, rib_queue_init) Add some more logs and asserts. From: Subbaiah Venkata Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 580b75bb8..0035eb6ee 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1271,14 +1271,30 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { + char buf[INET_ADDRSTRLEN]; + assert (zebra && rn); if (IS_ZEBRA_DEBUG_RIB_Q) + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + + /* Pointless to queue a route_node with no RIB entries to add or remove */ + if (!rn->info) { - char buf[INET6_ADDRSTRLEN]; + zlog_debug ("%s: called for route_node (%p, %d) with no ribs", + __func__, rn, rn->lock); + zlog_backtrace(LOG_DEBUG); + return; + } - zlog_info ("%s: %s/%d: work queue added", __func__, - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN), - rn->p.prefixlen); + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); + + assert (zebra); + + if (zebra->ribq == NULL) + { + zlog_err ("%s: work_queue does not exist!", __func__); + return; } /* @@ -1293,6 +1309,11 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) work_queue_add (zebra->ribq, zebra->mq); rib_meta_queue_add (zebra->mq, rn); + + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); + + return; } /* Create new meta queue. @@ -1320,6 +1341,8 @@ meta_queue_new (void) static void rib_queue_init (struct zebra_t *zebra) { + assert (zebra); + if (! (zebra->ribq = work_queue_new (zebra->master, "route_node processing"))) { @@ -1335,7 +1358,11 @@ rib_queue_init (struct zebra_t *zebra) zebra->ribq->spec.hold = rib_process_hold_time; if (!(zebra->mq = meta_queue_new ())) + { zlog_err ("%s: could not initialise meta queue!", __func__); + return; + } + return; } /* RIB updates are processed via a queue of pointers to route_nodes. From af56d404cd56d94ad3b2ec3f159650eb72baef0a Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 21 Mar 2012 18:47:51 -0700 Subject: [PATCH 0018/1342] zebra: clean up client routes when client goes away * zebra/zebra_rib.c: Add code to clean up routes added by a client (as identfied by 'rib type'). * zebra/zserv.[ch]: Maintain the type of the routes added by a client on the 'zserv' structure -- assume that a given client uses a single route type for now. Clean up routes from a client when the client goes away (in zebra_client_close()). From: Josh Bailey Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ zebra/zserv.c | 23 ++++++++++++++++++++ zebra/zserv.h | 4 ++++ 3 files changed, 82 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0035eb6ee..8da6c84a1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2905,6 +2905,61 @@ rib_sweep_route (void) rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } +/* Delete routes learned from a given client. */ +/* TODO(wsun) May need to split the sweep process into multiple batches, + * so that the process won't take too long if the table is large. */ +static void +rib_sweep_client_table (struct route_table *table, int rib_type) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + int ret = 0; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == rib_type) + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + /* TODO(wsun) Is this mandatory? What about graceful restart/ + * non-stop forwarding */ + ret = rib_uninstall_kernel (rn, rib); + if (! ret) + rib_delnode (rn, rib); + else + zlog_err ("%s: could not delete routes from kernel!", + __func__); + } + else + { + /* Always delete the node. */ + rib_delnode (rn, rib); + } + } +} + +/* Sweep all routes learned from a given client from RIB tables. */ +void +rib_sweep_client_route (struct zserv *client) +{ + assert(client); + int route_type = client->route_type; + if (route_type != ZEBRA_ROUTE_MAX) + { + zlog_debug ("%s: Removing existing routes from client type %d", + __func__, route_type); + rib_sweep_client_table (vrf_table (AFI_IP, SAFI_UNICAST, 0), route_type); + rib_sweep_client_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0), route_type); + } +} + /* Close RIB and clean up kernel routes. */ static void rib_close_table (struct route_table *table) diff --git a/zebra/zserv.c b/zebra/zserv.c index 9e6f6253c..2330135a2 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -750,6 +750,13 @@ zread_ipv4_add (struct zserv *client, u_short length) /* Type, flags, message. */ rib->type = stream_getc (s); + /* Update client's route type if it is not done yet. */ + /* It is done here since only zread_ipv4/6_add() and + * zread_ipv4/6_delete() decode Zebra messages and retrieve + * route types. */ + if (client->route_type == ZEBRA_ROUTE_MAX) + client->route_type = rib->type; + rib->flags = stream_getc (s); message = stream_getc (s); rib->uptime = time (NULL); @@ -924,6 +931,11 @@ zread_ipv6_add (struct zserv *client, u_short length) /* Type, flags, message. */ api.type = stream_getc (s); + /* Update the route type of the client. + * Same as in zread_ipv4_add(). */ + if (client->route_type == ZEBRA_ROUTE_MAX) + client->route_type = api.type; + api.flags = stream_getc (s); api.message = stream_getc (s); @@ -1077,6 +1089,14 @@ zread_router_id_delete (struct zserv *client, u_short length) static void zebra_client_close (struct zserv *client) { + struct stream *s; + + /* Sweep all routes learned from the client first. */ + rib_sweep_client_route(client); + /* Reset the route type. It may not be necessary since the + * whole client will be freed. */ + client->route_type = ZEBRA_ROUTE_MAX; + /* Close file descriptor. */ if (client->sock) { @@ -1115,6 +1135,9 @@ zebra_client_create (int sock) /* Make client input/output buffer. */ client->sock = sock; + /* Set the default route type to ZEBRA_ROUTE_MAX; it will be updated + * once new routes are received. */ + client->route_type = ZEBRA_ROUTE_MAX; client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->wb = buffer_new(0); diff --git a/zebra/zserv.h b/zebra/zserv.h index a73718304..e37041f82 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -38,6 +38,10 @@ struct zserv /* Client file descriptor. */ int sock; + /* Client route type. */ + /* Assuming each client contains only one type of route. */ + int route_type; + /* Input/output buffer to the client. */ struct stream *ibuf; struct stream *obuf; From 2dd04c5dc8b5a09cce1c251361fa58f26398fd9f Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 21 Mar 2012 10:37:03 -0700 Subject: [PATCH 0019/1342] lib: Tweak to if_delete_retain() * lib/if.c: Change if_delete_retain() to delete all connected addresses, but to not free the list that holds them. Free the list just before the interface structure itself is freed, in if_delete(). --- lib/if.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/if.c b/lib/if.c index 86f754b6b..e9ef50b76 100644 --- a/lib/if.c +++ b/lib/if.c @@ -146,7 +146,7 @@ if_delete_retain (struct interface *ifp) (*if_master.if_delete_hook) (ifp); /* Free connected address list */ - list_delete (ifp->connected); + list_delete_all_node (ifp->connected); } /* Delete and free interface structure. */ @@ -157,6 +157,8 @@ if_delete (struct interface *ifp) if_delete_retain(ifp); + list_free (ifp->connected); + XFREE (MTYPE_IF, ifp); } From 51d4ef832c1e58150325630e25c442866e5a6cf5 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 21 Mar 2012 17:13:39 -0700 Subject: [PATCH 0020/1342] zebra: include hardware addr in if up/down messages Change interface up/down notification messages to also include the hardware address of the interface. The format of these messages is now identical to the interface add message -- move the serialization code to common functions. * lib/zclient.c: Modify zebra_interface_if_set_value() to also parse the hardware address. Invoke it from zebra_interface_add_read() and and zebra_interface_state_read(). * zebra/zserv.c: Add zserv_encode_interface(). Invoke it from zserv_interface_add(), zserv_interface_delete() and zserv_interface_update(). --- lib/zclient.c | 36 ++++++------------------ zebra/zserv.c | 76 +++++++++++++++++++-------------------------------- 2 files changed, 37 insertions(+), 75 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 52a3627d0..85aa737e0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -611,24 +611,8 @@ zebra_interface_add_read (struct stream *s) /* Lookup/create interface by name. */ ifp = if_get_by_name_len (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); - /* Read interface's index. */ - ifp->ifindex = stream_getl (s); + zebra_interface_if_set_value (s, ifp); - /* Read interface's value. */ - ifp->status = stream_getc (s); - ifp->flags = stream_getq (s); - ifp->metric = stream_getl (s); - ifp->mtu = stream_getl (s); - ifp->mtu6 = stream_getl (s); - ifp->bandwidth = stream_getl (s); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); -#else - ifp->hw_addr_len = stream_getl (s); - if (ifp->hw_addr_len) - stream_get (ifp->hw_addr, s, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ - return ifp; } @@ -656,16 +640,7 @@ zebra_interface_state_read (struct stream *s) if (! ifp) return NULL; - /* Read interface's index. */ - ifp->ifindex = stream_getl (s); - - /* Read interface's value. */ - ifp->status = stream_getc (s); - ifp->flags = stream_getq (s); - ifp->metric = stream_getl (s); - ifp->mtu = stream_getl (s); - ifp->mtu6 = stream_getl (s); - ifp->bandwidth = stream_getl (s); + zebra_interface_if_set_value (s, ifp); return ifp; } @@ -715,6 +690,13 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->mtu = stream_getl (s); ifp->mtu6 = stream_getl (s); ifp->bandwidth = stream_getl (s); +#ifdef HAVE_STRUCT_SOCKADDR_DL + stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); +#else + ifp->hw_addr_len = stream_getl (s); + if (ifp->hw_addr_len) + stream_get (ifp->hw_addr, s, ifp->hw_addr_len); +#endif /* HAVE_STRUCT_SOCKADDR_DL */ } static int diff --git a/zebra/zserv.c b/zebra/zserv.c index 2330135a2..23a5c4e84 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -131,6 +131,30 @@ zserv_create_header (struct stream *s, uint16_t cmd) stream_putw (s, cmd); } +static void +zserv_encode_interface (struct stream *s, struct interface *ifp) +{ + /* Interface information. */ + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); + stream_putq (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->mtu6); + stream_putl (s, ifp->bandwidth); +#ifdef HAVE_STRUCT_SOCKADDR_DL + stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); +#else + stream_putl (s, ifp->hw_addr_len); + if (ifp->hw_addr_len) + stream_put (s, ifp->hw_addr, ifp->hw_addr_len); +#endif /* HAVE_STRUCT_SOCKADDR_DL */ + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); +} + /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: @@ -154,28 +178,8 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset (s); - /* Message type. */ zserv_create_header (s, ZEBRA_INTERFACE_ADD); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); -#else - stream_putl (s, ifp->hw_addr_len); - if (ifp->hw_addr_len) - stream_put (s, ifp->hw_addr, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); + zserv_encode_interface (s, ifp); return zebra_server_send_message(client); } @@ -192,21 +196,9 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset (s); - - zserv_create_header (s, ZEBRA_INTERFACE_DELETE); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); - /* Write packet length. */ - stream_putw_at (s, 0, stream_get_endp (s)); + zserv_create_header (s, ZEBRA_INTERFACE_DELETE); + zserv_encode_interface (s, ifp); return zebra_server_send_message (client); } @@ -319,19 +311,7 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) stream_reset (s); zserv_create_header (s, cmd); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); + zserv_encode_interface (s, ifp); return zebra_server_send_message(client); } From 3b381c32fc2c325cc4ffb9f9f30a7e96e9bd87c6 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Sun, 19 Feb 2012 10:19:52 -0800 Subject: [PATCH 0021/1342] bgpd: fix issue in capability negotiation (BZ#700) Address problem where bgpd would reject a session if a peer sent some capabilities in its Open message, but did not include a Multiprotocol extensions capability. Note that the session would come up if there were no capabilities at all in the Open message. * Add the 'mp_capability' out parameter to bgp_capability_parse(). Set it to '1' if a Multiprotocol extensions capability is encountered. * Switch on 'mp_capability' instead of 'capability' in the calling functions to determine if the peer indicated the set of AFI/SAFIs it supports. The net result is that when a peer does not send an MP capability, it is assumed to support the AFI/SAFIs configured for it locally. --- bgpd/bgp_open.c | 31 ++++++++++++++++++++++--------- bgpd/bgp_packet.c | 15 ++++++++++----- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index b5b50bb5f..0326d01bc 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -464,11 +464,16 @@ static const size_t cap_minsizes[] = [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry), }; -/* Parse given capability. +/** + * Parse given capability. * XXX: This is reading into a stream, but not using stream API + * + * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol + * capabilities were encountered. */ static int -bgp_capability_parse (struct peer *peer, size_t length, u_char **error) +bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, + u_char **error) { int ret; struct stream *s = BGP_INPUT (peer); @@ -540,6 +545,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error) { case CAPABILITY_CODE_MP: { + *mp_capability = 1; + /* Ignore capability when override-capability is set. */ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { @@ -712,9 +719,13 @@ peek_for_as4_capability (struct peer *peer, u_char length) return as4; } -/* Parse open option */ +/** + * Parse open option. + * + * @param[out] mp_capability @see bgp_capability_parse() for semantics. + */ int -bgp_open_option_parse (struct peer *peer, u_char length, int *capability) +bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { int ret; u_char *error; @@ -767,8 +778,7 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability) ret = bgp_auth_parse (peer, opt_length); break; case BGP_OPEN_OPT_CAP: - ret = bgp_capability_parse (peer, opt_length, &error); - *capability = 1; + ret = bgp_capability_parse (peer, opt_length, mp_capability, &error); break; default: bgp_notify_send (peer, @@ -811,9 +821,10 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability) } } - /* Check there is no common capability send Unsupported Capability + /* Check there are no common AFI/SAFIs and send Unsupported Capability error. */ - if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + if (*mp_capability && + ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] @@ -821,7 +832,9 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability) && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) { - plog_err (peer->log, "%s [Error] No common capability", peer->host); + plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " + "overlap with received MP capabilities", + peer->host); if (error != error_data) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 5d8087a8e..390b55635 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1152,7 +1152,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) as_t as4 = 0; struct peer *realpeer; struct in_addr remote_id; - int capability; + int mp_capability; u_int8_t notify_data_remote_as[2]; u_int8_t notify_data_remote_id[4]; @@ -1174,7 +1174,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) inet_ntoa (remote_id)); /* BEGIN to read the capability here, but dont do it yet */ - capability = 0; + mp_capability = 0; optlen = stream_getc (peer->ibuf); if (optlen != 0) @@ -1459,7 +1459,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Open option part parse. */ if (optlen != 0) { - if ((ret = bgp_open_option_parse (peer, optlen, &capability)) < 0) + if ((ret = bgp_open_option_parse (peer, optlen, &mp_capability)) < 0) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, @@ -1474,8 +1474,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) peer->host); } - /* Override capability. */ - if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + /* + * Assume that the peer supports the locally configured set of + * AFI/SAFIs if the peer did not send us any Mulitiprotocol + * capabilities, or if 'override-capability' is configured. + */ + if (! mp_capability || + CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; From a25a44dba84e9a6ac2b87e24472b6e9f959d845b Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 3 Apr 2012 20:33:24 +0400 Subject: [PATCH 0022/1342] ospfd: adjust OSPF_ROUTER_LSA_MIN_SIZE for VL case --- ospfd/ospf_lsa.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 297cd9843..6c95ff177 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -153,7 +153,14 @@ struct router_lsa_link }; /* OSPF Router-LSAs structure. */ -#define OSPF_ROUTER_LSA_MIN_SIZE 16U /* w/1 link descriptor */ +#define OSPF_ROUTER_LSA_MIN_SIZE 4U /* w/0 link descriptors */ +/* There is an edge case, when number of links in a Router-LSA may be 0 without + breaking the specification. A router, which has no other links to backbone + area besides one virtual link, will not put any VL descriptor blocks into + the Router-LSA generated for area 0 until a full adjacency over the VL is + reached (RFC2328 12.4.1.3). In this case the Router-LSA initially received + by the other end of the VL will have 0 link descriptor blocks, but soon will + be replaced with the next revision having 1 descriptor block. */ struct router_lsa { struct lsa_header header; From aa3b264282677fcd33513352aa878d00163d2dbf Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Wed, 11 Apr 2012 23:56:03 -0700 Subject: [PATCH 0023/1342] isisd: reapply patch to fix zebra protocol Reapply the bits of revision b4e45f6 that pertain to isisd. That is: git log -n 1 -p b4e45f6 -- isisd These were dropped in the merge with the Google ISIS code (14d2bbaa). The commit message for b4e45f6 is: fix zebra protocol after MP-BGP changes The previous commits modified both zebra and bgpd for additional SAFI field, but not any other routing daemon, which led to zebra daemon crashing with failed assertion. --- isisd/isis_zebra.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 467122f65..2df746291 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -256,6 +256,8 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, stream_putc (stream, flags); /* message */ stream_putc (stream, message); + /* SAFI */ + stream_putw (stream, SAFI_UNICAST); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); @@ -304,6 +306,7 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; prefix4.family = AF_INET; prefix4.prefixlen = prefix->prefixlen; prefix4.prefix = prefix->u.prefix4; @@ -333,6 +336,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); @@ -417,6 +421,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.nexthop_num = listcount (route_info->nexthops6); From 086695cb8eea5b405b21e66b92ef0348355c4821 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 16 Apr 2012 18:14:50 +0200 Subject: [PATCH 0024/1342] isisd: reapply removal of CVS cruft this re-removes CVS keywords and .cvsignore files. original commits: b82cdeb delete CVS keywords 05e54ee build: delete .cvsignore files --- isisd/.cvsignore | 12 ------------ isisd/dict.c | 3 --- isisd/include-netbsd/.cvsignore | 3 --- isisd/topology/.cvsignore | 9 --------- 4 files changed, 27 deletions(-) delete mode 100644 isisd/.cvsignore delete mode 100644 isisd/include-netbsd/.cvsignore delete mode 100644 isisd/topology/.cvsignore diff --git a/isisd/.cvsignore b/isisd/.cvsignore deleted file mode 100644 index 26aa85cbf..000000000 --- a/isisd/.cvsignore +++ /dev/null @@ -1,12 +0,0 @@ -Makefile -Makefile.in -*.o -isisd -.deps -isisd.conf -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/isisd/dict.c b/isisd/dict.c index 35cb924ca..bbcb42134 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -13,9 +13,6 @@ * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. - * - * $Id$ - * $Name$ */ #include "zebra.h" diff --git a/isisd/include-netbsd/.cvsignore b/isisd/include-netbsd/.cvsignore deleted file mode 100644 index 73bcf19d6..000000000 --- a/isisd/include-netbsd/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -.arch-inventory -.arch-ids - diff --git a/isisd/topology/.cvsignore b/isisd/topology/.cvsignore deleted file mode 100644 index b0ae823b1..000000000 --- a/isisd/topology/.cvsignore +++ /dev/null @@ -1,9 +0,0 @@ -Makefile -Makefile.in -*.o -tags -TAGS -.deps -.nfs* -.arch-inventory -.arch-ids From 1627b20fd4fe431558d0f77aff98cbee29ca15d8 Mon Sep 17 00:00:00 2001 From: Vyacheslav Trushkin Date: Fri, 25 Nov 2011 17:56:21 +0400 Subject: [PATCH 0025/1342] isisd: indent longopts array --- isisd/isis_main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 7bb84d8fc..67dc15436 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -75,16 +75,16 @@ struct zebra_privs_t isisd_privs = { /* isisd options */ struct option longopts[] = { - {"daemon", no_argument, NULL, 'd'}, + {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, - {"pid_file", required_argument, NULL, 'i'}, - {"vty_addr", required_argument, NULL, 'A'}, - {"vty_port", required_argument, NULL, 'P'}, - {"user", required_argument, NULL, 'u'}, - {"group", required_argument, NULL, 'g'}, - {"version", no_argument, NULL, 'v'}, - {"dryrun", no_argument, NULL, 'C'}, - {"help", no_argument, NULL, 'h'}, + {"pid_file", required_argument, NULL, 'i'}, + {"vty_addr", required_argument, NULL, 'A'}, + {"vty_port", required_argument, NULL, 'P'}, + {"user", required_argument, NULL, 'u'}, + {"group", required_argument, NULL, 'g'}, + {"version", no_argument, NULL, 'v'}, + {"dryrun", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, {0} }; From 48d8bea8b7c83cf186460f711ab166455b5ed676 Mon Sep 17 00:00:00 2001 From: Vyacheslav Trushkin Date: Fri, 25 Nov 2011 18:51:48 +0400 Subject: [PATCH 0026/1342] quagga: option "-z" ("--socket ") added All daemons modified to support custom path to zserv socket. [reapplied from b511468 after isisd merge] --- isisd/isis_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 67dc15436..f5266aa22 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -34,6 +34,7 @@ #include "privs.h" #include "sigevent.h" #include "filter.h" +#include "zclient.h" #include "isisd/dict.h" #include "include-netbsd/iso.h" @@ -78,6 +79,7 @@ struct option longopts[] = { {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, {"pid_file", required_argument, NULL, 'i'}, + {"socket", required_argument, NULL, 'z'}, {"vty_addr", required_argument, NULL, 'A'}, {"vty_port", required_argument, NULL, 'P'}, {"user", required_argument, NULL, 'u'}, @@ -133,6 +135,7 @@ Daemon which manages IS-IS routing\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ @@ -252,7 +255,7 @@ main (int argc, char **argv, char **envp) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:hA:p:P:u:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hA:p:P:u:g:vC", longopts, 0); if (opt == EOF) break; @@ -270,6 +273,9 @@ main (int argc, char **argv, char **envp) case 'i': pid_file = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'A': vty_addr = optarg; break; From 3cadc0cdebb8f8262b1c1fbb8bfcbcdc3baa3733 Mon Sep 17 00:00:00 2001 From: JR Rivers Date: Sun, 1 Apr 2012 12:16:31 -0700 Subject: [PATCH 0027/1342] zebra: use larger buffer (4096) for netlink messages Increase the maximum number of nexthops per route by using a larger buffer for netlink messages. * zebra/rt_netlink.c: Use a buffer of 4096 bytes to parse/build netlink messages. Add a hash define for this number (NL_PKT_BUF_SIZE). Most places in the code were previously using a buffer of 1024 bytes. --- zebra/rt_netlink.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 73097bf6e..5909131dd 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -43,6 +43,8 @@ #include "zebra/interface.h" #include "zebra/debug.h" +#define NL_PKT_BUF_SIZE 4096 + /* Socket interface to kernel */ struct nlsock { @@ -281,7 +283,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), while (1) { - char buf[4096]; + char buf[NL_PKT_BUF_SIZE]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; @@ -1363,7 +1365,7 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate, { struct nlmsghdr n; struct rtmsg r; - char buf[1024]; + char buf[NL_PKT_BUF_SIZE]; } req; memset (&req, 0, sizeof req); @@ -1438,7 +1440,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, { struct nlmsghdr n; struct rtmsg r; - char buf[1024]; + char buf[NL_PKT_BUF_SIZE]; } req; memset (&req, 0, sizeof req); @@ -1646,7 +1648,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, } else { - char buf[1024]; + char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; union g_addr *src = NULL; @@ -1690,7 +1692,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { - rta_addattr_l (rta, 4096, RTA_GATEWAY, + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->rgate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + 4; @@ -1708,7 +1710,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) { - rta_addattr_l (rta, 4096, RTA_GATEWAY, + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->rgate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) @@ -1764,7 +1766,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { - rta_addattr_l (rta, 4096, RTA_GATEWAY, + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + 4; @@ -1782,7 +1784,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - rta_addattr_l (rta, 4096, RTA_GATEWAY, + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) @@ -1828,7 +1830,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen); if (rta->rta_len > RTA_LENGTH (0)) - addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta), + addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), RTA_PAYLOAD (rta)); } @@ -1897,7 +1899,7 @@ netlink_address (int cmd, int family, struct interface *ifp, { struct nlmsghdr n; struct ifaddrmsg ifa; - char buf[1024]; + char buf[NL_PKT_BUF_SIZE]; } req; p = ifc->address; From 7939e016b3d4ecd2f5b8ad708b69607e05a084a6 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 9 Apr 2012 18:03:57 +0200 Subject: [PATCH 0028/1342] ospfd: Fixes a crash of the daemon with a snmp walk - And allows to walk the LSDB. Signed-off-by: Jorge Boncompte [DTI2] --- ospfd/ospf_snmp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index cc4974ce6..9c9dd47a7 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -934,7 +934,7 @@ ospfLsdbLookup (struct variable *v, oid *name, size_t *length, struct ospf *ospf; struct ospf_area *area; struct ospf_lsa *lsa; - unsigned int len; + int len; int type_next; int ls_id_next; int router_id_next; @@ -992,7 +992,7 @@ ospfLsdbLookup (struct variable *v, oid *name, size_t *length, if (len == IN_ADDR_SIZE) area = ospf_area_lookup_by_area_id (ospf, *area_id); else - area = ospf_area_lookup_next (ospf, area_id, len == 0 ? 1 : 0); + area = ospf_area_lookup_next (ospf, area_id, 1); if (area == NULL) return NULL; @@ -1000,8 +1000,8 @@ ospfLsdbLookup (struct variable *v, oid *name, size_t *length, do { /* Next we lookup type. */ - offset += IN_ADDR_SIZE; - offsetlen -= IN_ADDR_SIZE; + offset += len; + offsetlen -= len; len = offsetlen; if (len <= 0) From fa4094ac49b4cc23589f5c5b7e608c4b4ee6ca04 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Fri, 13 Apr 2012 13:46:09 +0200 Subject: [PATCH 0029/1342] bgpd: Fix crash when disabling dampening (BZ#687) Vladimir Podobaev reported that the following commands crashed the daemon. router bgp 123 bgp dampening no bgp dampening 1 2 3 4 no bgp dampening The problem was that bgp_damp_info_clean() tried to dereference the already freed reuse_list array in the second call to "no bgp dampening". Fixed by checking in bgp_damp_disable() that the dampening it's enabled before doing the cleanup. Signed-off-by: Jorge Boncompte [DTI2] --- bgpd/bgp_damp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index a51388335..2820f17c7 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -498,6 +498,10 @@ bgp_damp_info_clean (void) int bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi) { + /* If it wasn't enabled, there's nothing to do. */ + if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + return 0; + /* Cancel reuse thread. */ if (damp->t_reuse ) thread_cancel (damp->t_reuse); From 9665856e3718e42068e7d897f5e2468e77fb8c17 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 20 Apr 2012 17:23:39 +0200 Subject: [PATCH 0030/1342] Revert "zebra: clean up client routes when client goes away" This reverts commit af56d404cd56d94ad3b2ec3f159650eb72baef0a, which was accidentally duplicating functionality from commit 2ea1ab1 "zebra: ZEBRA_HELLO and mopping up routes (BZ#448)" Conflicts: zebra/zebra_rib.c Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 56 ----------------------------------------------- zebra/zserv.c | 23 ------------------- zebra/zserv.h | 4 ---- 3 files changed, 83 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 2fa439c0a..154e8d551 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2920,62 +2920,6 @@ rib_sweep_route (void) rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } - -/* Delete routes learned from a given client. */ -/* TODO(wsun) May need to split the sweep process into multiple batches, - * so that the process won't take too long if the table is large. */ -static void -rib_sweep_client_table (struct route_table *table, int rib_type) -{ - struct route_node *rn; - struct rib *rib; - struct rib *next; - int ret = 0; - - if (table) - for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = next) - { - next = rib->next; - - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == rib_type) - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - { - /* TODO(wsun) Is this mandatory? What about graceful restart/ - * non-stop forwarding */ - ret = rib_uninstall_kernel (rn, rib); - if (! ret) - rib_delnode (rn, rib); - else - zlog_err ("%s: could not delete routes from kernel!", - __func__); - } - else - { - /* Always delete the node. */ - rib_delnode (rn, rib); - } - } -} - -/* Sweep all routes learned from a given client from RIB tables. */ -void -rib_sweep_client_route (struct zserv *client) -{ - assert(client); - int route_type = client->route_type; - if (route_type != ZEBRA_ROUTE_MAX) - { - zlog_debug ("%s: Removing existing routes from client type %d", - __func__, route_type); - rib_sweep_client_table (vrf_table (AFI_IP, SAFI_UNICAST, 0), route_type); - rib_sweep_client_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0), route_type); - } -} - /* Remove specific by protocol routes from 'table'. */ static unsigned long diff --git a/zebra/zserv.c b/zebra/zserv.c index b1f539d3a..09152170c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -741,13 +741,6 @@ zread_ipv4_add (struct zserv *client, u_short length) /* Type, flags, message. */ rib->type = stream_getc (s); - /* Update client's route type if it is not done yet. */ - /* It is done here since only zread_ipv4/6_add() and - * zread_ipv4/6_delete() decode Zebra messages and retrieve - * route types. */ - if (client->route_type == ZEBRA_ROUTE_MAX) - client->route_type = rib->type; - rib->flags = stream_getc (s); message = stream_getc (s); safi = stream_getw (s); @@ -924,11 +917,6 @@ zread_ipv6_add (struct zserv *client, u_short length) /* Type, flags, message. */ api.type = stream_getc (s); - /* Update the route type of the client. - * Same as in zread_ipv4_add(). */ - if (client->route_type == ZEBRA_ROUTE_MAX) - client->route_type = api.type; - api.flags = stream_getc (s); api.message = stream_getc (s); api.safi = stream_getw (s); @@ -1127,14 +1115,6 @@ zebra_score_rib (int client_sock) static void zebra_client_close (struct zserv *client) { - struct stream *s; - - /* Sweep all routes learned from the client first. */ - rib_sweep_client_route(client); - /* Reset the route type. It may not be necessary since the - * whole client will be freed. */ - client->route_type = ZEBRA_ROUTE_MAX; - /* Close file descriptor. */ if (client->sock) { @@ -1174,9 +1154,6 @@ zebra_client_create (int sock) /* Make client input/output buffer. */ client->sock = sock; - /* Set the default route type to ZEBRA_ROUTE_MAX; it will be updated - * once new routes are received. */ - client->route_type = ZEBRA_ROUTE_MAX; client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->wb = buffer_new(0); diff --git a/zebra/zserv.h b/zebra/zserv.h index 3d7ebbcd8..5e8bccac3 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -38,10 +38,6 @@ struct zserv /* Client file descriptor. */ int sock; - /* Client route type. */ - /* Assuming each client contains only one type of route. */ - int route_type; - /* Input/output buffer to the client. */ struct stream *ibuf; struct stream *obuf; From 8d79efddb9c63f3b45e0ee7cac9508509b3b939c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 20 Apr 2012 17:26:48 +0200 Subject: [PATCH 0031/1342] lib: bump ZSERV_VERSION to 2 continually changing the zserv protocol without bumping up the version number has made it impossible to talk to zebra without knowing the exact version. in reality, increasing the version number more often guards against inadvertedly running incompatible versions of a daemon and zebra as well as aids external development. * lib/zclient.h: #define ZSERV_VERSION 2 Signed-off-by: David Lamparter --- lib/zclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zclient.h b/lib/zclient.h index a7d7b5487..a660bbf19 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -98,7 +98,7 @@ struct zserv_header * always set to 255 in new zserv. */ uint8_t version; -#define ZSERV_VERSION 1 +#define ZSERV_VERSION 2 uint16_t command; }; From 61a81bea6d21dedc62931d6925d0608ebc45c196 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 12 Mar 2012 13:51:49 +0100 Subject: [PATCH 0032/1342] babeld: Include babel_main.h in noinst_HEADERS. babeld wouldn't build in a dist tarball without this. From: Denis Ovsienko Signed-off-by: Juliusz Chroboczek [fixed up git message] Signed-off-by: David Lamparter --- babeld/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babeld/Makefile.am b/babeld/Makefile.am index 468b5a5f1..8703de062 100644 --- a/babeld/Makefile.am +++ b/babeld/Makefile.am @@ -18,7 +18,7 @@ libbabel_a_SOURCES = \ noinst_HEADERS = \ babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ route.h xroute.h message.h resend.h babel_interface.h babeld.h \ - babel_filter.h + babel_filter.h babel_main.h babeld_SOURCES = \ babel_main.c $(libbabel_a_SOURCES) From 27f689793a25a66cf62561ac1d1302e01983a805 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Mon, 12 Mar 2012 13:52:42 +0100 Subject: [PATCH 0033/1342] babeld: merge kernel_zebra.c into kernel.c. In upstream babel, we include different kernel_foo files depending on the platform we compile for. In Quagga, this is not needed, and it avoids tricky autotools issues. (All autotools issues are tricky.) [David: without this commit, build breaks.] From: Juliusz Chroboczek Signed-off-by: David Lamparter --- babeld/kernel.c | 240 +++++++++++++++++++++++++++++++++++- babeld/kernel_zebra.c | 275 ------------------------------------------ 2 files changed, 239 insertions(+), 276 deletions(-) delete mode 100644 babeld/kernel_zebra.c diff --git a/babeld/kernel.c b/babeld/kernel.c index c31f617b8..efbb70005 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -17,6 +17,7 @@ * Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek +Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -43,7 +44,244 @@ THE SOFTWARE. #include "babeld.h" -#include "kernel_zebra.c" + +#include +#include +#include +#include +#include + +#include +#include "prefix.h" +#include "zclient.h" +#include "kernel.h" +#include "privs.h" +#include "command.h" +#include "vty.h" +#include "memory.h" +#include "thread.h" + +#include "util.h" +#include "babel_interface.h" +#include "babel_zebra.h" + + +static int +kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric); +static int +kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric); + +int +kernel_interface_operational(struct interface *interface) +{ + return if_is_operative(interface); +} + +int +kernel_interface_mtu(struct interface *interface) +{ + return MIN(interface->mtu, interface->mtu6); +} + +int +kernel_interface_wireless(struct interface *interface) +{ + return 0; +} + +int +kernel_route(int operation, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric) +{ + int rc; + int ipv4; + + /* Check that the protocol family is consistent. */ + if(plen >= 96 && v4mapped(pref)) { + if(!v4mapped(gate)) { + errno = EINVAL; + return -1; + } + ipv4 = 1; + } else { + if(v4mapped(gate)) { + errno = EINVAL; + return -1; + } + ipv4 = 0; + } + + switch (operation) { + case ROUTE_ADD: + return ipv4 ? + kernel_route_v4(1, pref, plen, gate, ifindex, metric): + kernel_route_v6(1, pref, plen, gate, ifindex, metric); + break; + case ROUTE_FLUSH: + return ipv4 ? + kernel_route_v4(0, pref, plen, gate, ifindex, metric): + kernel_route_v6(0, pref, plen, gate, ifindex, metric); + break; + case ROUTE_MODIFY: + if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && + newifindex == ifindex) + return 0; + debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); + rc = ipv4 ? + kernel_route_v4(0, pref, plen, gate, ifindex, metric): + kernel_route_v6(0, pref, plen, gate, ifindex, metric); + + if (rc < 0) + return -1; + + rc = ipv4 ? + kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): + kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); + + return rc; + break; + default: + zlog_err("this should never appens (false value - kernel_route)"); + assert(0); + exit(1); + break; + } +} + +static int +kernel_route_v4(int add, + const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric) +{ + struct zapi_ipv4 api; /* quagga's communication system */ + struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ + struct in_addr babel_prefix_addr; /* babeld's prefix addr */ + struct in_addr nexthop; /* next router to go */ + struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ + + /* convert to be understandable by quagga */ + /* convert given addresses */ + uchar_to_inaddr(&babel_prefix_addr, pref); + uchar_to_inaddr(&nexthop, gate); + + /* make prefix structure */ + memset (&quagga_prefix, 0, sizeof(quagga_prefix)); + quagga_prefix.family = AF_INET; + IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); + quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ + apply_mask_ipv4(&quagga_prefix); + + api.type = ZEBRA_ROUTE_BABEL; + api.flags = 0; + api.message = 0; + api.safi = SAFI_UNICAST; + + /* Unlike the native Linux and BSD interfaces, Quagga doesn't like + there to be both and IPv4 nexthop and an ifindex. Omit the + ifindex, and assume that the connected prefixes be set up + correctly. */ + + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.ifindex_num = 0; + if(metric >= KERNEL_INFINITY) { + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.nexthop_num = 0; + } else { + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + } + + debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", + add ? "adding" : "removing" ); + return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD : + ZEBRA_IPV4_ROUTE_DELETE, + zclient, &quagga_prefix, &api); +} + +static int +kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric) +{ + unsigned int tmp_ifindex = ifindex; /* (for typing) */ + struct zapi_ipv6 api; /* quagga's communication system */ + struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ + struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ + struct in6_addr nexthop; /* next router to go */ + struct in6_addr *nexthop_pointer = &nexthop; + + /* convert to be understandable by quagga */ + /* convert given addresses */ + uchar_to_in6addr(&babel_prefix_addr, pref); + uchar_to_in6addr(&nexthop, gate); + + /* make prefix structure */ + memset (&quagga_prefix, 0, sizeof(quagga_prefix)); + quagga_prefix.family = AF_INET6; + IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); + quagga_prefix.prefixlen = plen; + apply_mask_ipv6(&quagga_prefix); + + api.type = ZEBRA_ROUTE_BABEL; + api.flags = 0; + api.message = 0; + api.safi = SAFI_UNICAST; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + if(metric >= KERNEL_INFINITY) { + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.nexthop_num = 0; + api.ifindex_num = 0; + } else { + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + } + + debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", + add ? "adding" : "removing" ); + return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD : + ZEBRA_IPV6_ROUTE_DELETE, + zclient, &quagga_prefix, &api); +} + +int +if_eui64(char *ifname, int ifindex, unsigned char *eui) +{ + struct interface *ifp = if_lookup_by_index(ifindex); + if (ifp == NULL) { + return -1; + } +#ifdef HAVE_STRUCT_SOCKADDR_DL + u_char len = ifp->sdl.sdl_alen; + char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen; +#else + u_char len = (u_char) ifp->hw_addr_len; + char *tmp = (void*) ifp->hw_addr; +#endif + if (len == 8) { + memcpy(eui, tmp, 8); + eui[0] ^= 2; + } else if (len == 6) { + memcpy(eui, tmp, 3); + eui[3] = 0xFF; + eui[4] = 0xFE; + memcpy(eui+5, tmp+3, 3); + } else { + return -1; + } + return 0; +} /* Like gettimeofday, but returns monotonic time. If POSIX clocks are not available, falls back to gettimeofday but enforces monotonicity. */ diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c deleted file mode 100644 index db7d0b398..000000000 --- a/babeld/kernel_zebra.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include - -#include -#include "prefix.h" -#include "zclient.h" -#include "kernel.h" -#include "privs.h" -#include "command.h" -#include "vty.h" -#include "memory.h" -#include "thread.h" - -#include "util.h" -#include "babel_interface.h" -#include "babel_zebra.h" - - -static int -kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); -static int -kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); - -int -kernel_interface_operational(struct interface *interface) -{ - return if_is_operative(interface); -} - -int -kernel_interface_mtu(struct interface *interface) -{ - return MIN(interface->mtu, interface->mtu6); -} - -int -kernel_interface_wireless(struct interface *interface) -{ - return 0; -} - -int -kernel_route(int operation, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric) -{ - int rc; - int ipv4; - - /* Check that the protocol family is consistent. */ - if(plen >= 96 && v4mapped(pref)) { - if(!v4mapped(gate)) { - errno = EINVAL; - return -1; - } - ipv4 = 1; - } else { - if(v4mapped(gate)) { - errno = EINVAL; - return -1; - } - ipv4 = 0; - } - - switch (operation) { - case ROUTE_ADD: - return ipv4 ? - kernel_route_v4(1, pref, plen, gate, ifindex, metric): - kernel_route_v6(1, pref, plen, gate, ifindex, metric); - break; - case ROUTE_FLUSH: - return ipv4 ? - kernel_route_v4(0, pref, plen, gate, ifindex, metric): - kernel_route_v6(0, pref, plen, gate, ifindex, metric); - break; - case ROUTE_MODIFY: - if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && - newifindex == ifindex) - return 0; - debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); - rc = ipv4 ? - kernel_route_v4(0, pref, plen, gate, ifindex, metric): - kernel_route_v6(0, pref, plen, gate, ifindex, metric); - - if (rc < 0) - return -1; - - rc = ipv4 ? - kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): - kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); - - return rc; - break; - default: - zlog_err("this should never appens (false value - kernel_route)"); - assert(0); - exit(1); - break; - } -} - -static int -kernel_route_v4(int add, - const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) -{ - struct zapi_ipv4 api; /* quagga's communication system */ - struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ - struct in_addr babel_prefix_addr; /* babeld's prefix addr */ - struct in_addr nexthop; /* next router to go */ - struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_inaddr(&babel_prefix_addr, pref); - uchar_to_inaddr(&nexthop, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET; - IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); - quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ - apply_mask_ipv4(&quagga_prefix); - - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - - /* Unlike the native Linux and BSD interfaces, Quagga doesn't like - there to be both and IPv4 nexthop and an ifindex. Omit the - ifindex, and assume that the connected prefixes be set up - correctly. */ - - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.ifindex_num = 0; - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_BLACKHOLE; - api.nexthop_num = 0; - } else { - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", - add ? "adding" : "removing" ); - return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD : - ZEBRA_IPV4_ROUTE_DELETE, - zclient, &quagga_prefix, &api); -} - -static int -kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) -{ - unsigned int tmp_ifindex = ifindex; /* (for typing) */ - struct zapi_ipv6 api; /* quagga's communication system */ - struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ - struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ - struct in6_addr nexthop; /* next router to go */ - struct in6_addr *nexthop_pointer = &nexthop; - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_in6addr(&babel_prefix_addr, pref); - uchar_to_in6addr(&nexthop, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET6; - IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); - quagga_prefix.prefixlen = plen; - apply_mask_ipv6(&quagga_prefix); - - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_BLACKHOLE; - api.nexthop_num = 0; - api.ifindex_num = 0; - } else { - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", - add ? "adding" : "removing" ); - return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD : - ZEBRA_IPV6_ROUTE_DELETE, - zclient, &quagga_prefix, &api); -} - -int -if_eui64(char *ifname, int ifindex, unsigned char *eui) -{ - struct interface *ifp = if_lookup_by_index(ifindex); - if (ifp == NULL) { - return -1; - } -#ifdef HAVE_STRUCT_SOCKADDR_DL - u_char len = ifp->sdl.sdl_alen; - char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen; -#else - u_char len = (u_char) ifp->hw_addr_len; - char *tmp = (void*) ifp->hw_addr; -#endif - if (len == 8) { - memcpy(eui, tmp, 8); - eui[0] ^= 2; - } else if (len == 6) { - memcpy(eui, tmp, 3); - eui[3] = 0xFF; - eui[4] = 0xFE; - memcpy(eui+5, tmp+3, 3); - } else { - return -1; - } - return 0; -} From fac3c2453a06bce773a3f4ae6834f5f9a317b88c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Apr 2012 22:37:20 +0200 Subject: [PATCH 0034/1342] bgpd: fix up multipath merge breakage the BGP multipath code was developed against a pre-f6f434b Quagga where bgp_attr_unintern and ecommunity_free took single-star pointers. They now take double-star pointers. * bgpd/bgp_mpath.c: fix up bgp_attr_unintern & ecommunity_free calls. Signed-off-by: David Lamparter --- bgpd/bgp_mpath.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index d07830d14..aa657d832 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -230,7 +230,7 @@ bgp_info_mpath_free (struct bgp_info_mpath **mpath) if (mpath && *mpath) { if ((*mpath)->mp_attr) - bgp_attr_unintern ((*mpath)->mp_attr); + bgp_attr_unintern (&(*mpath)->mp_attr); XFREE (MTYPE_BGP_MPATH_INFO, *mpath); *mpath = NULL; } @@ -605,7 +605,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, if (old_best && (old_best != new_best) && (old_attr = bgp_info_mpath_attr (old_best))) { - bgp_attr_unintern (old_attr); + bgp_attr_unintern (&old_attr); bgp_info_mpath_attr_set (old_best, NULL); } @@ -616,7 +616,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, { if ((new_attr = bgp_info_mpath_attr (new_best))) { - bgp_attr_unintern (new_attr); + bgp_attr_unintern (&new_attr); bgp_info_mpath_attr_set (new_best, NULL); SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); } @@ -692,7 +692,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, { ecommerge = ecommunity_merge (ecomm, ae->ecommunity); ecomm = ecommunity_uniq_sort (ecommerge); - ecommunity_free (ecommerge); + ecommunity_free (&ecommerge); } else ecomm = ecommunity_dup (ae->ecommunity); @@ -728,10 +728,10 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, if (new_attr != bgp_info_mpath_attr (new_best)) { if ((old_attr = bgp_info_mpath_attr (new_best))) - bgp_attr_unintern (old_attr); + bgp_attr_unintern (&old_attr); bgp_info_mpath_attr_set (new_best, new_attr); SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); } else - bgp_attr_unintern (new_attr); + bgp_attr_unintern (&new_attr); } From 2e14a748061921f1f656b07890c4932f97c2baaa Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 29 Apr 2012 16:47:03 -0400 Subject: [PATCH 0035/1342] tools: use standard interpreter path in all Perl scripts Signed-off-by: David Ward [changed /usr/bin/perl to /usr/bin/env perl] Signed-off-by: David Lamparter --- tools/rrcheck.pl | 2 +- tools/rrlookup.pl | 2 +- tools/zc.pl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/rrcheck.pl b/tools/rrcheck.pl index 5e5a983c2..279bca841 100644 --- a/tools/rrcheck.pl +++ b/tools/rrcheck.pl @@ -1,4 +1,4 @@ -#! /bin/perl +#!/usr/bin/env perl ## ## Read BGPd logfile and lookup RR's whois database. ## diff --git a/tools/rrlookup.pl b/tools/rrlookup.pl index 2c14e73ea..84410e81e 100644 --- a/tools/rrlookup.pl +++ b/tools/rrlookup.pl @@ -1,4 +1,4 @@ -#! /usr/local/bin/perl +#!/usr/bin/env perl ## ## Read BGPd logfile and lookup RR's whois database. ## diff --git a/tools/zc.pl b/tools/zc.pl index 026e8fe5b..5307fa387 100755 --- a/tools/zc.pl +++ b/tools/zc.pl @@ -1,4 +1,4 @@ -#! /usr/bin/perl +#!/usr/bin/env perl ## ## Zebra interactive console ## Copyright (C) 2000 Vladimir B. Grebenschikov From f027d331fc24c0b4aed77ab7507a9635db313f3c Mon Sep 17 00:00:00 2001 From: David Ward Date: Mon, 30 Apr 2012 11:36:15 -0400 Subject: [PATCH 0036/1342] doc: only package man pages for daemons that are built Signed-off-by: David Ward Signed-off-by: David Lamparter --- configure.ac | 11 +++++++++++ doc/Makefile.am | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4fe70e150..8cb1d4fc6 100755 --- a/configure.ac +++ b/configure.ac @@ -624,6 +624,7 @@ dnl [TODO] on Linux, and in [TODO] on Solaris. * ) ;; esac AC_SUBST(LIBREADLINE) +AM_CONDITIONAL(VTYSH, test "x$VTYSH" = "xvtysh") dnl ---------- dnl PAM module @@ -1228,36 +1229,42 @@ if test "${enable_zebra}" = "no";then else ZEBRA="zebra" fi +AM_CONDITIONAL(ZEBRA, test "x$ZEBRA" = "xzebra") if test "${enable_bgpd}" = "no";then BGPD="" else BGPD="bgpd" fi +AM_CONDITIONAL(BGPD, test "x$BGPD" = "xbgpd") if test "${enable_ripd}" = "no";then RIPD="" else RIPD="ripd" fi +AM_CONDITIONAL(RIPD, test "x$RIPD" = "xripd") if test "${enable_ospfd}" = "no";then OSPFD="" else OSPFD="ospfd" fi +AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") if test "${enable_babeld}" = "no";then BABELD="" else BABELD="babeld" fi +AM_CONDITIONAL(BABELD, test "x$BABELD" = "xbabeld") if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else WATCHQUAGGA="watchquagga" fi +AM_CONDITIONAL(WATCHQUAGGA, test "x$WATCHQUAGGA" = "xwatchquagga") OSPFCLIENT="" if test "${enable_opaque_lsa}" != "no"; then @@ -1270,24 +1277,28 @@ if test "${enable_opaque_lsa}" != "no"; then fi fi +AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") case "${enable_ripngd}" in "yes") RIPNGD="ripngd";; "no" ) RIPNGD="";; * ) ;; esac +AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd") case "${enable_ospf6d}" in "yes") OSPF6D="ospf6d";; "no" ) OSPF6D="";; * ) ;; esac +AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d") case "${enable_isisd}" in "yes") ISISD="isisd";; "no" ) ISISD="";; * ) ;; esac +AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") # XXX Perhaps auto-enable on Solaris, but that's messy for cross builds. case "${enable_solaris}" in diff --git a/doc/Makefile.am b/doc/Makefile.am index dde95ab30..4ba8f814e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -61,9 +61,43 @@ quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ .dia.png: $(DIATOPNG) "$@" $< -man_MANS = vtysh.1 bgpd.8 ospf6d.8 ospfd.8 ripd.8 ripngd.8 zebra.8 isisd.8 +man_MANS = -EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt $(man_MANS) \ +if BGPD +man_MANS += bgpd.8 +endif + +if ISISD +man_MANS += isisd.8 +endif + +if OSPF6D +man_MANS += ospf6d.8 +endif + +if OSPFD +man_MANS += ospfd.8 +endif + +if RIPD +man_MANS += ripd.8 +endif + +if RIPNGD +man_MANS += ripngd.8 +endif + +if VTYSH +man_MANS += vtysh.1 +endif + +if ZEBRA +man_MANS += zebra.8 +endif + +EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ + bgpd.8 isisd.8 ospf6d.8 ospfd.8 ripd.8 \ + ripngd.8 vtysh.1 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) From 7b0df9c5bad83e2a2eb047e84edc00b3bc1d562c Mon Sep 17 00:00:00 2001 From: David Ward Date: Mon, 30 Apr 2012 11:36:16 -0400 Subject: [PATCH 0037/1342] doc: add ospfclient(8) and watchquagga(8) man pages Taken from Fedora packaging. Signed-off-by: David Ward Signed-off-by: David Lamparter --- doc/Makefile.am | 12 ++- doc/ospfclient.8 | 42 +++++++++ doc/watchquagga.8 | 231 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 doc/ospfclient.8 create mode 100644 doc/watchquagga.8 diff --git a/doc/Makefile.am b/doc/Makefile.am index 4ba8f814e..f58657b97 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -75,6 +75,10 @@ if OSPF6D man_MANS += ospf6d.8 endif +if OSPFCLIENT +man_MANS += ospfclient.8 +endif + if OSPFD man_MANS += ospfd.8 endif @@ -91,13 +95,17 @@ if VTYSH man_MANS += vtysh.1 endif +if WATCHQUAGGA +man_MANS += watchquagga.8 +endif + if ZEBRA man_MANS += zebra.8 endif EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ - bgpd.8 isisd.8 ospf6d.8 ospfd.8 ripd.8 \ - ripngd.8 vtysh.1 zebra.8 \ + bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ + ripngd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) diff --git a/doc/ospfclient.8 b/doc/ospfclient.8 new file mode 100644 index 000000000..ccfad1aad --- /dev/null +++ b/doc/ospfclient.8 @@ -0,0 +1,42 @@ +.\" This file was originally generated by help2man 1.36. +.TH OSPFCLIENT "1" "July 2010" +.SH NAME +ospfclient \- an example ospf-api client +.SH SYNOPSIS +.B ospfclient +.I ospfd +.I lsatype +.I opaquetype +.I opaqueid +.I ifaddr +.I areaid +.SH DESCRIPTION +.B ospfclient +is a an example ospf-api client to test the ospfd daemon. +.SH OPTIONS +.TP +.I ospfd +A router where the API\-enabled OSPF daemon is running. +.TP +.I lsatype +The value has to be either "9", "10", or "11", depending on the flooding +scope. +.TP +.I opaquetype +The value has to be in the range of 0\-255 (for example, experimental +applications use +.I opaquetype +larger than 128). +.TP +.I opaqueid +Arbitrary application instance (24 bits). +.TP +.I ifaddr +Interface IP address for type 9, otherwise it will be ignored. +.TP +.I areaid +Area in the IP address format for type 10, otherwise it will be ignored. +.SH "SEE ALSO" +.BR ospfd (8). +.SH AUTHORS +See the project homepage at . diff --git a/doc/watchquagga.8 b/doc/watchquagga.8 new file mode 100644 index 000000000..ca9916461 --- /dev/null +++ b/doc/watchquagga.8 @@ -0,0 +1,231 @@ +.\" This file was originally generated by help2man 1.36. +.TH WATCHQUAGGA 8 "July 2010" +.SH NAME +watchquagga \- a program to monitor the status of quagga daemons +.SH SYNOPSIS +.B watchquagga +.RI [ option ...] +.IR daemon ... +.br +.B watchquagga +.BR \-h " | " \-v +.SH DESCRIPTION +.B watchquagga +is a watchdog program that monitors the status of supplied quagga +.IR daemon s +and tries to restart them in case they become unresponsive or shut down. +.PP +To determine whether a daemon is running, it tries to connect to the +daemon's VTY UNIX stream socket, and send echo commands to ensure the +daemon responds. When the daemon crashes, EOF is received from the socket, +so that watchquagga can react immediately. +.PP +This program can run in one of the following 5 modes: +.TP +.B Mode 0: monitor +In this mode, the program serves as a monitor and reports status changes. +.IP +Example usage: watchquagga \-d zebra ospfd bgpd +.TP +.B Mode 1: global restart +In this mode, whenever a daemon hangs or crashes, the given command is used +to restart all watched daemons. +.IP +Example usage: watchquagga \-dz \e +.br +-R '/sbin/service zebra restart; /sbin/service ospfd restart' \e +.br +zebra ospfd +.TP +.B Mode 2: individual daemon restart +In this mode, whenever a single daemon hangs or crashes, the given command +is used to restart this daemon only. +.IP +Example usage: watchquagga \-dz \-r '/sbin/service %s restart' \e +.br +zebra ospfd bgpd +.TP +.B Mode 3: phased zebra restart +In this mode, whenever a single daemon hangs or crashes, the given command +is used to restart this daemon only. The only exception is the zebra +daemon; in this case, the following steps are taken: (1) all other daemons +are stopped, (2) zebra is restarted, and (3) other daemons are started +again. +.IP +Example usage: watchquagga \-adz \-r '/sbin/service %s restart' \e +.br +\-s '/sbin/service %s start' \e +.br +\-k '/sbin/service %s stop' zebra ospfd bgpd +.TP +.B Mode 4: phased global restart for any failure +In this mode, whenever a single daemon hangs or crashes, the following +steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, +and (3) other daemons are started again. +.IP +Example usage: watchquagga \-Adz \-r '/sbin/service %s restart' \e +.br +\-s '/sbin/service %s start' \e +.br +\-k '/sbin/service %s stop' zebra ospfd bgpd +.PP +Important: It is believed that mode 2 (individual daemon restart) is not +safe, and mode 3 (phased zebra restart) may not be safe with certain +routing daemons. +.PP +In order to avoid restarting the daemons in quick succession, you can +supply the +.B \-m +and +.B \-M +options to set the minimum and maximum delay between the restart commands. +The minimum restart delay is recalculated each time a restart is attempted. +If the time since the last restart attempt exceeds twice the value of +.BR \-M , +the restart delay is set to the value of +.BR \-m , +otherwise the interval is doubled (but capped at the value of +.BR \-M ). +.SH OPTIONS +.TP +.BR \-d ", " \-\-daemon +Run in daemon mode. When supplied, error messages are sent to Syslog +instead of standard output (stdout). +.TP +.BI \-S " directory" "\fR, \fB\-\-statedir " directory +Set the VTY socket +.I directory +(the default value is "/var/run/quagga"). +.TP +.BR \-e ", " \-\-no\-echo +Do not ping the daemons to test whether they respond. This option is +necessary if one or more daemons do not support the echo command. +.TP +.BI \-l " level" "\fR, \fB\-\-loglevel " level +Set the logging +.I level +(the default value is "6"). The value should range from 0 (LOG_EMERG) to 7 +(LOG_DEBUG), but higher number can be supplied if extra debugging messages +are required. +.TP +.BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number +Set the minimum +.I number +of seconds to wait between invocations of the daemon restart commands (the +default value is "60"). +.TP +.BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number +Set the maximum +.I number +of seconds to wait between invocations of the daemon restart commands (the +default value is "600"). +.TP +.BI \-i " number" "\fR, \fB\-\-interval " number +Set the status polling interval in seconds (the default value is "5"). +.TP +.BI \-t " number" "\fR, \fB\-\-timeout " number +Set the unresponsiveness timeout in seconds (the default value is "10"). +.TP +.BI \-T " number" "\fR, \fB\-\-restart\-timeout " number +Set the restart (kill) timeout in seconds (the default value is "20"). If +any background jobs are still running after this period has elapsed, they +will be killed. +.TP +.BI \-r " command" "\fR, \fB\-\-restart " command +Supply a Bourne shell +.I command +to restart a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.IP +Note that +.B \-r +and +.B \-R +options are not compatible. +.TP +.BI \-s " command" "\fR, \fB\-\-start\-command " command +Supply a Bourne shell +.I command +to start a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.TP +.BI \-k " command" "\fR, \fB\-\-kill\-command " command +Supply a Bourne shell +.I command +to stop a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.TP +.BR \-R ", " \-\-restart\-all +When one or more daemons are shut down, try to restart them using the +Bourne shell command supplied on the command line. +.IP +Note that +.B \-r +and +.B \-R +options are not compatible. +.TP +.BR \-z ", " \-\-unresponsive\-restart +When a daemon is in an unresponsive state, treat it as being shut down for +the restart purposes. +.TP +.BR \-a ", " \-\-all\-restart +When zebra hangs or crashes, restart all daemons taking the following +steps: (1) stop all other daemons, (2) restart zebra, and (3) start other +daemons again. +.IP +Note that this option also requires +.BR \-r , +.BR \-s , +and +.B \-k +options to be specified. +.TP +.BR \-A ", " \-\-always\-all\-restart +When any daemon (i.e., not just zebra) hangs or crashes, restart all +daemons taking the following steps: (1) stop all other daemons, (2) restart +zebra, and (3) start other daemons again. +.IP +Note that this option also requires +.BR \-r , +.BR \-s , +and +.B \-k +options to be specified. +.TP +.BI \-p " filename" "\fR, \fB\-\-pid\-file " filename +Set the process identifier +.I filename +(the default value is "/var/run/quagga/watchquagga.pid"). +.TP +.BI \-b " string" "\fR, \fB\-\-blank\-string " string +When the supplied +.I string +is found in any of the command line option arguments (i.e., +.BR \-r , +.BR \-s , +.BR \-k , +or +.BR \-R ), +replace it with a space. +.IP +This is an ugly hack to circumvent problems with passing the command line +arguments containing embedded spaces. +.TP +.BR \-v ", " \-\-version +Display the version information and exit. +.TP +.BR \-h ", " \-\-help +Display the usage information and exit. +.SH SEE ALSO +.BR zebra (8), +.BR bgpd (8), +.BR isisd (8), +.BR ospfd (8), +.BR ospf6d (8), +.BR ripd (8), +.BR ripngd (8) +.PP +See the project homepage at . +.SH AUTHORS +Copyright 2004 Andrew J. Schorr From 0bd268a5232f91c8cf01366b7ae43bcfed1dc8fe Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 29 Apr 2012 16:47:06 -0400 Subject: [PATCH 0038/1342] redhat: add logrotate configuration for babeld and isisd Signed-off-by: David Ward Signed-off-by: David Lamparter --- redhat/quagga.logrotate | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/redhat/quagga.logrotate b/redhat/quagga.logrotate index 1b453d16d..9756a781a 100644 --- a/redhat/quagga.logrotate +++ b/redhat/quagga.logrotate @@ -6,6 +6,14 @@ endscript } +/var/log/quagga/babeld.log { + notifempty + missingok + postrotate + /bin/kill -USR1 `cat /var/run/quagga/babeld.pid 2> /dev/null` 2> /dev/null || true + endscript +} + /var/log/quagga/bgpd.log { notifempty missingok @@ -14,6 +22,14 @@ endscript } +/var/log/quagga/isisd.log { + notifempty + missingok + postrotate + /bin/kill -USR1 `cat /var/run/quagga/isisd.pid 2> /dev/null` 2> /dev/null || true + endscript +} + /var/log/quagga/ospfd.log { notifempty missingok From a41242bed823db77186ed7d11953cffaa0c3b733 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 29 Apr 2012 16:47:07 -0400 Subject: [PATCH 0039/1342] redhat: update initscripts Taken from Fedora packaging with additional fixes. * redhat/*.init: make all initscripts LSB-compliant; store the daemon configuration file location in $CONF_FILE, and perform existence testing before starting the daemon * redhat/babeld.init: add initscript for Babel routing engine * redhat/quagga.sysconfig: add command-line options for babeld; remove the daemon configuration file locations from $*_OPTS; clarify directions for configuring watchquagga * redhat/Makefile.am: add babeld.init to distribution Signed-off-by: David Ward Signed-off-by: David Lamparter --- redhat/Makefile.am | 2 +- redhat/babeld.init | 72 +++++++++++++++++++++++++++++++++++++++ redhat/bgpd.init | 73 +++++++++++++++++++++------------------ redhat/isisd.init | 73 ++++++++++++++++++++++----------------- redhat/ospf6d.init | 71 +++++++++++++++++++++----------------- redhat/ospfd.init | 72 +++++++++++++++++++++------------------ redhat/quagga.sysconfig | 29 ++++++++-------- redhat/ripd.init | 71 +++++++++++++++++++++----------------- redhat/ripngd.init | 71 +++++++++++++++++++++----------------- redhat/watchquagga.init | 64 ++++++++++++++++++----------------- redhat/zebra.init | 75 +++++++++++++++++++++++------------------ 11 files changed, 407 insertions(+), 266 deletions(-) create mode 100644 redhat/babeld.init diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 6a3d38f70..e037ec577 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -1,4 +1,4 @@ EXTRA_DIST = quagga.pam quagga.sysconfig quagga.spec quagga.logrotate \ zebra.init ripd.init ospfd.init ripngd.init ospf6d.init bgpd.init \ - isisd.init watchquagga.init quagga.pam.stack + isisd.init babeld.init watchquagga.init quagga.pam.stack diff --git a/redhat/babeld.init b/redhat/babeld.init new file mode 100644 index 000000000..76e8e5e08 --- /dev/null +++ b/redhat/babeld.init @@ -0,0 +1,72 @@ +#!/bin/bash +# chkconfig: - 16 84 +# config: /etc/quagga/babeld.conf + +### BEGIN INIT INFO +# Provides: babeld +# Short-Description: Babel routing engine +# Description: Babel routing engine for use with Zebra +### END INIT INFO + +# source function library +. /etc/rc.d/init.d/functions + +# Get network config +. /etc/sysconfig/network + +# quagga command line options +. /etc/sysconfig/quagga + +RETVAL=0 +PROG="babeld" +cmd=babeld +LOCK_FILE=/var/lock/subsys/babeld +CONF_FILE=/etc/quagga/babeld.conf + +case "$1" in + start) + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $BABELD_OPTS -f $CONF_FILE + RETVAL=$? + [ $RETVAL -eq 0 ] && touch $LOCK_FILE + echo + ;; + stop) + echo -n $"Shutting down $PROG: " + killproc $cmd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE + echo + ;; + restart|reload|force-reload) + $0 stop + $0 start + RETVAL=$? + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop + $0 start + fi + RETVAL=$? + ;; + status) + status $cmd + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 +esac + +exit $RETVAL diff --git a/redhat/bgpd.init b/redhat/bgpd.init index ef59c2a61..e18511a03 100644 --- a/redhat/bgpd.init +++ b/redhat/bgpd.init @@ -1,10 +1,12 @@ #!/bin/bash -# -# chkconfig: 2345 16 84 -# description: A BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra -# -# processname: bgpd -# config: /etc/zebra/bgpd.conf +# chkconfig: - 16 84 +# config: /etc/quagga/bgpd.conf + +### BEGIN INIT INFO +# Provides: bgpd +# Short-Description: BGP routing engine +# Description: BGP routing engine for use with Zebra +### END INIT INFO # source function library . /etc/rc.d/init.d/functions @@ -15,49 +17,56 @@ # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/bgpd.conf ] || exit 0 - RETVAL=0 -prog="bgpd" +PROG="bgpd" +cmd=bgpd +LOCK_FILE=/var/lock/subsys/bgpd +CONF_FILE=/etc/quagga/bgpd.conf case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/bgpd -d $BGPD_OPTS + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $BGPD_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/bgpd + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc bgpd + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/bgpd + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/bgpd ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status bgpd + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/isisd.init b/redhat/isisd.init index 0d762c043..9e805300d 100644 --- a/redhat/isisd.init +++ b/redhat/isisd.init @@ -1,61 +1,72 @@ #!/bin/bash -# -# chkconfig: 2345 16 84 -# description: An ISIS routing engine for use with Quagga -# -# processname: isisd +# chkconfig: - 16 84 # config: /etc/quagga/isisd.conf +### BEGIN INIT INFO +# Provides: isisd +# Short-Description: IS-IS routing engine +# Description: IS-IS routing engine for use with Zebra +### END INIT INFO + # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/isisd.conf ] || exit 0 +# quagga command line options +. /etc/sysconfig/quagga RETVAL=0 - -prog="isisd" +PROG="isisd" +cmd=isisd +LOCK_FILE=/var/lock/subsys/isisd +CONF_FILE=/etc/quagga/isisd.conf case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/isisd -d + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $ISISD_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/isisd + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc isisd + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/isisd + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/isisd ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status isisd + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/ospf6d.init b/redhat/ospf6d.init index c84ce678f..4133b4a14 100644 --- a/redhat/ospf6d.init +++ b/redhat/ospf6d.init @@ -1,11 +1,13 @@ #!/bin/bash -# -# chkconfig: 2345 16 84 -# description: An OSPF routing engine for use with Zebra and IPv6 -# -# processname: ospf6d +# chkconfig: - 16 84 # config: /etc/quagga/ospf6d.conf +### BEGIN INIT INFO +# Provides: ospf6d +# Short-Description: OSPF routing engine for IPv6 +# Description: OSPF routing engine for use with Zebra and IPv6 +### END INIT INFO + # source function library . /etc/rc.d/init.d/functions @@ -15,49 +17,56 @@ # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING_IPV6}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/ospf6d.conf ] || exit 0 - RETVAL=0 -prog="ospf6d" +PROG="ospf6d" +cmd=ospf6d +LOCK_FILE=/var/lock/subsys/ospf6d +CONF_FILE=/etc/quagga/ospf6d.conf case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/ospf6d -d $OSPF6D_OPTS + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $OSPF6D_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospf6d + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc ospf6d + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospf6d + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/ospf6d ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status ospf6d + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $prog {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/ospfd.init b/redhat/ospfd.init index 911f7aa59..d964f38df 100644 --- a/redhat/ospfd.init +++ b/redhat/ospfd.init @@ -1,11 +1,13 @@ #!/bin/bash -# -# chkconfig: 2345 16 84 -# description: An OSPF v2 routing engine for use with Zebra -# -# processname: ospfd +# chkconfig: - 16 84 # config: /etc/quagga/ospfd.conf +### BEGIN INIT INFO +# Provides: ospfd +# Short-Description: OSPF routing engine +# Description: OSPF routing engine for use with Zebra +### END INIT INFO + # source function library . /etc/rc.d/init.d/functions @@ -15,50 +17,56 @@ # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/ospfd.conf ] || exit 0 - RETVAL=0 - -prog="ospfd" +PROG="ospfd" +cmd=ospfd +LOCK_FILE=/var/lock/subsys/ospfd +CONF_FILE=/etc/quagga/ospfd.conf case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/ospfd -d $OSPFD_OPTS + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $OSPFD_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospfd + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc ospfd + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospfd + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/ospfd ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status ospfd + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/quagga.sysconfig b/redhat/quagga.sysconfig index 9e9da5ef3..2befc0fdd 100644 --- a/redhat/quagga.sysconfig +++ b/redhat/quagga.sysconfig @@ -1,18 +1,19 @@ # # Default: Bind all daemon vtys to the loopback(s) only # -QCONFDIR="/etc/quagga" -BGPD_OPTS="-A 127.0.0.1 -f ${QCONFDIR}/bgpd.conf" -OSPF6D_OPTS="-A ::1 -f ${QCONFDIR}/ospf6d.conf" -OSPFD_OPTS="-A 127.0.0.1 -f ${QCONFDIR}/ospfd.conf" -RIPD_OPTS="-A 127.0.0.1 -f ${QCONFDIR}/ripd.conf" -RIPNGD_OPTS="-A ::1 -f ${QCONFDIR}/ripngd.conf" -ZEBRA_OPTS="-A 127.0.0.1 -f ${QCONFDIR}/zebra.conf" -ISISD_OPTS="-A ::1 -f ${QCONFDIR}/isisd.conf" +BABELD_OPTS="-A 127.0.0.1" +BGPD_OPTS="-A 127.0.0.1" +ISISD_OPTS="-A ::1" +OSPF6D_OPTS="-A ::1" +OSPFD_OPTS="-A 127.0.0.1" +RIPD_OPTS="-A 127.0.0.1" +RIPNGD_OPTS="-A ::1" +ZEBRA_OPTS="-A 127.0.0.1" -# Watchquagga configuration (please check timer values before using): -WATCH_OPTS="" -WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" -# To enable restarts, uncomment this line (but first be sure to edit -# the WATCH_DAEMONS line to reflect the daemons you are actually using): -#WATCH_OPTS="-Az -b_ -r/sbin/service_%s_restart -s/sbin/service_%s_start -k/sbin/service_%s_stop" +# Watchquagga configuration +# +# Uncomment and edit this line to reflect the daemons you are actually using: +#WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" +# +# Timer values can be adjusting by editing this line: +WATCH_OPTS="-Az -b_ -r/sbin/service_%s_restart -s/sbin/service_%s_start -k/sbin/service_%s_stop" diff --git a/redhat/ripd.init b/redhat/ripd.init index 766422194..9b412cb96 100644 --- a/redhat/ripd.init +++ b/redhat/ripd.init @@ -1,11 +1,13 @@ #!/bin/bash -# -# chkconfig: 2345 16 84 -# description: A RIP routing engine for use with Zebra -# -# processname: ripd +# chkconfig: - 16 84 # config: /etc/quagga/ripd.conf +### BEGIN INIT INFO +# Provides: ripd +# Short-Description: RIP routing engine +# Description: RIP routing engine for use with Zebra +### END INIT INFO + # source function library . /etc/rc.d/init.d/functions @@ -15,49 +17,56 @@ # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/ripd.conf ] || exit 0 - RETVAL=0 -prog="ripd" +PROG="ripd" +cmd=ripd +LOCK_FILE=/var/lock/subsys/ripd +CONF_FILE=/etc/quagga/ripd.conf case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/ripd -d $RIPD_OPTS + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $RIPD_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripd + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc ripd + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripd + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/ripd ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status ripd + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/ripngd.init b/redhat/ripngd.init index 57ae928c7..88f346f86 100644 --- a/redhat/ripngd.init +++ b/redhat/ripngd.init @@ -1,11 +1,13 @@ #!/bin/bash -# -# chkconfig: 2345 16 84 -# description: A RIP routing engine for use with Zebra and IPv6 -# -# processname: ripngd +# chkconfig: - 16 84 # config: /etc/quagga/ripngd.conf +### BEGIN INIT INFO +# Provides: ripngd +# Short-Description: RIP routing engine for IPv6 +# Description: RIP routing engine for use with Zebra and IPv6 +### END INIT INFO + # source function library . /etc/rc.d/init.d/functions @@ -15,49 +17,56 @@ # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING_IPV6}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/ripngd.conf ] || exit 0 - RETVAL=0 -prog="ripngd" +PROG="ripngd" +cmd=ripngd +LOCK_FILE=/var/lock/subsys/ripngd +CONF_FILE=/etc/quagga/ripngd.conf case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/ripngd -d $RIPNGD_OPTS + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $RIPNGD_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripngd + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc ripngd + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripngd + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/ripngd ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status ripngd + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/watchquagga.init b/redhat/watchquagga.init index 74299e373..dda350662 100644 --- a/redhat/watchquagga.init +++ b/redhat/watchquagga.init @@ -1,9 +1,11 @@ #!/bin/bash -# # chkconfig: 2345 17 83 -# description: A Quagga watchdog for use with Zebra -# -# processname: watchquagga + +### BEGIN INIT INFO +# Provides: watchquagga +# Short-Description: Quagga watchdog +# Description: Quagga watchdog for use with Zebra +### END INIT INFO # source function library . /etc/rc.d/init.d/functions @@ -14,49 +16,51 @@ # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# Check that there are daemons to be monitored. -[ -z "$WATCH_DAEMONS" ] && exit 0 - RETVAL=0 -prog="watchquagga" +PROG="watchquagga" +cmd=watchquagga +LOCK_FILE=/var/lock/subsys/watchquagga case "$1" in start) - echo -n $"Starting $prog: " - daemon /usr/sbin/watchquagga -d $WATCH_OPTS $WATCH_DAEMONS + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # Check that there are daemons to be monitored. + [ -z "$WATCH_DAEMONS" ] && exit 1 + + echo -n $"Starting $PROG: " + daemon $cmd -d $WATCH_OPTS $WATCH_DAEMONS RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/watchquagga + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc watchquagga + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/watchquagga + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/watchquagga ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status watchquagga + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL diff --git a/redhat/zebra.init b/redhat/zebra.init index 8caae1f16..4242b16c4 100644 --- a/redhat/zebra.init +++ b/redhat/zebra.init @@ -1,64 +1,73 @@ #!/bin/bash -# -# chkconfig: 2345 15 85 -# description: GNU Zebra routing manager -# -# processname: zebra +# chkconfig: - 15 85 # config: /etc/quagga/zebra.conf +### BEGIN INIT INFO +# Provides: zebra +# Short-Description: GNU Zebra routing manager +# Description: GNU Zebra routing manager +### END INIT INFO + # source function library . /etc/rc.d/init.d/functions +# Get network config +. /etc/sysconfig/network + # quagga command line options . /etc/sysconfig/quagga -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# The process must be configured first. -[ -f /etc/quagga/zebra.conf ] || exit 0 - RETVAL=0 - -prog="zebra" +PROG="zebra" +cmd=zebra +LOCK_FILE=/var/lock/subsys/zebra +CONF_FILE=/etc/quagga/zebra.conf case "$1" in start) - echo -n $"Starting $prog: " + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " /sbin/ip route flush proto zebra - - daemon /usr/sbin/zebra -d $ZEBRA_OPTS + daemon $cmd -d $ZEBRA_OPTS -f $CONF_FILE RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/zebra + [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) - echo -n $"Shutting down $prog: " - killproc zebra + echo -n $"Shutting down $PROG: " + killproc $cmd RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/zebra + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; - restart|reload) - $0 stop - $0 start + restart|reload|force-reload) + $0 stop + $0 start RETVAL=$? - ;; - condrestart) - if [ -f /var/lock/subsys/zebra ]; then - $0 stop + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop $0 start - fi + fi RETVAL=$? - ;; + ;; status) - status zebra + status $cmd RETVAL=$? - ;; + ;; *) - echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}" - exit 1 + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 esac exit $RETVAL From 4b5a2103b7d03b9209cfa3668d9cebead697bc82 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 29 Apr 2012 16:47:08 -0400 Subject: [PATCH 0040/1342] redhat: add systemd service files * redhat/*.service: add systemd service file for each routing daemon * redhat/quagga.sysconfig: add comment about watchquagga and systemd * redhat/Makefile.am: add systemd service files to distribution Signed-off-by: David Ward Signed-off-by: David Lamparter --- redhat/Makefile.am | 8 +++++--- redhat/babeld.service | 14 ++++++++++++++ redhat/bgpd.service | 14 ++++++++++++++ redhat/isisd.service | 14 ++++++++++++++ redhat/ospf6d.service | 14 ++++++++++++++ redhat/ospfd.service | 14 ++++++++++++++ redhat/quagga.sysconfig | 7 ++++++- redhat/ripd.service | 14 ++++++++++++++ redhat/ripngd.service | 14 ++++++++++++++ redhat/zebra.service | 14 ++++++++++++++ 10 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 redhat/babeld.service create mode 100644 redhat/bgpd.service create mode 100644 redhat/isisd.service create mode 100644 redhat/ospf6d.service create mode 100644 redhat/ospfd.service create mode 100644 redhat/ripd.service create mode 100644 redhat/ripngd.service create mode 100644 redhat/zebra.service diff --git a/redhat/Makefile.am b/redhat/Makefile.am index e037ec577..c83e9591f 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -1,4 +1,6 @@ -EXTRA_DIST = quagga.pam quagga.sysconfig quagga.spec quagga.logrotate \ - zebra.init ripd.init ospfd.init ripngd.init ospf6d.init bgpd.init \ - isisd.init babeld.init watchquagga.init quagga.pam.stack +EXTRA_DIST = babeld.init babeld.service bgpd.init bgpd.service isisd.init \ + isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ + quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ + quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ + watchquagga.init zebra.init zebra.service diff --git a/redhat/babeld.service b/redhat/babeld.service new file mode 100644 index 000000000..b1ea9432e --- /dev/null +++ b/redhat/babeld.service @@ -0,0 +1,14 @@ +[Unit] +Description=Babel routing daemon +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/babeld.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/babeld -d $BABELD_OPTS -f /etc/quagga/babeld.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/bgpd.service b/redhat/bgpd.service new file mode 100644 index 000000000..5040284db --- /dev/null +++ b/redhat/bgpd.service @@ -0,0 +1,14 @@ +[Unit] +Description=BGP routing daemon +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/bgpd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/bgpd -d $BGPD_OPTS -f /etc/quagga/bgpd.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/isisd.service b/redhat/isisd.service new file mode 100644 index 000000000..4cdf67d67 --- /dev/null +++ b/redhat/isisd.service @@ -0,0 +1,14 @@ +[Unit] +Description=IS-IS routing daemon +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/isisd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/isisd -d $ISISD_OPTS -f /etc/quagga/isisd.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/ospf6d.service b/redhat/ospf6d.service new file mode 100644 index 000000000..3c9c46689 --- /dev/null +++ b/redhat/ospf6d.service @@ -0,0 +1,14 @@ +[Unit] +Description=OSPF routing daemon for IPv6 +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/ospf6d.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/ospf6d -d $OSPF6D_OPTS -f /etc/quagga/ospf6d.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/ospfd.service b/redhat/ospfd.service new file mode 100644 index 000000000..5e3de2393 --- /dev/null +++ b/redhat/ospfd.service @@ -0,0 +1,14 @@ +[Unit] +Description=OSPF routing daemon +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/ospfd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/ospfd -d $OSPFD_OPTS -f /etc/quagga/ospfd.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/quagga.sysconfig b/redhat/quagga.sysconfig index 2befc0fdd..4d6ec5ad1 100644 --- a/redhat/quagga.sysconfig +++ b/redhat/quagga.sysconfig @@ -10,7 +10,12 @@ RIPD_OPTS="-A 127.0.0.1" RIPNGD_OPTS="-A ::1" ZEBRA_OPTS="-A 127.0.0.1" -# Watchquagga configuration +# Watchquagga configuration for LSB initscripts +# +# (Not needed with systemd: the service files are configured to automatically +# restart any daemon on failure. If zebra fails, all running daemons will be +# stopped; zebra will be started again; and then the previously running daemons +# will be started again.) # # Uncomment and edit this line to reflect the daemons you are actually using: #WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" diff --git a/redhat/ripd.service b/redhat/ripd.service new file mode 100644 index 000000000..d35dc47a1 --- /dev/null +++ b/redhat/ripd.service @@ -0,0 +1,14 @@ +[Unit] +Description=RIP routing daemon +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/ripd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/ripd -d $RIPD_OPTS -f /etc/quagga/ripd.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/ripngd.service b/redhat/ripngd.service new file mode 100644 index 000000000..567e88806 --- /dev/null +++ b/redhat/ripngd.service @@ -0,0 +1,14 @@ +[Unit] +Description=RIP routing daemon for IPv6 +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/ripngd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/ripngd -d $RIPNGD_OPTS -f /etc/quagga/ripngd.conf +Restart=on-abort + +[Install] +WantedBy=network.target diff --git a/redhat/zebra.service b/redhat/zebra.service new file mode 100644 index 000000000..27c3a5229 --- /dev/null +++ b/redhat/zebra.service @@ -0,0 +1,14 @@ +[Unit] +Description=GNU Zebra routing manager +After=syslog.target network.target +ConditionPathExists=/etc/quagga/zebra.conf + +[Service] +Type=forking +EnvironmentFile=-/etc/sysconfig/quagga +ExecStartPre=/sbin/ip route flush proto zebra +ExecStart=/usr/sbin/zebra -d $ZEBRA_OPTS -f /etc/quagga/zebra.conf +Restart=on-abort + +[Install] +WantedBy=network.target From d78e2b8b562f8496aaf2977f7371415b71e82433 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 1 May 2012 18:08:43 +0200 Subject: [PATCH 0041/1342] tests: disable broken tests/bgp_mp_attr_test.c it doesn't compile currently; it'll be fixed after the 0.99.21 release. * tests/bgp_mp_attr_test.c: wrap in #if 0 for now Signed-off-by: David Lamparter --- tests/bgp_mp_attr_test.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 9cbe9f224..cf0b2b1c5 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -1,3 +1,8 @@ +/* this testcase is currently broken + * -- 2012-05-01 David Lamparter + */ +int main() { return 0; } + #include #include "vty.h" @@ -24,6 +29,7 @@ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; +#if 0 static int failed = 0; static int tty = 0; @@ -533,3 +539,4 @@ main (void) printf ("failures: %d\n", failed); return failed; } +#endif /* #if 0 */ From 828f235df4b6a322aac58e1b7d5089c7f9d6cc0a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 1 May 2012 21:43:53 +0200 Subject: [PATCH 0042/1342] release: 0.99.21 --- NEWS | 14 ++++++++++++++ configure.ac | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e9d3a998c..d67d66469 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,17 @@ +Note: this file lists major user-visible changes only. + +* Changes in Quagga 0.99.21 + +- [bgpd] BGP multipath support has been merged +- [bgpd] SAFI (Multicast topology) support has been extended to propagate + the topology to zebra. +- [bgpd] AS path limit functionality has been removed +- [babeld] a new routing daemon implementing the BABEL ad-hoc mesh routing + protocol has been merged. +- [isisd] a major overhaul has been picked up. Please note that isisd is + STILL NOT SUITABLE FOR PRODUCTION USE. +- [*] a lot of bugs have been fixed, please refer to the git log + * Changes in Quagga 0.99.10 - [bgpd] 4-byte AS support added diff --git a/configure.ac b/configure.ac index 8cb1d4fc6..80f65b98b 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.20, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.21, [https://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) From 6ebeebb50610cc86d16e56bc1a33d63340094215 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 2 May 2012 11:01:01 +0100 Subject: [PATCH 0043/1342] Revert "tests: disable broken tests/bgp_mp_attr_test.c" This reverts commit d78e2b8b562f8496aaf2977f7371415b71e82433. Next 2 commits fix it. --- tests/bgp_mp_attr_test.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index cf0b2b1c5..9cbe9f224 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -1,8 +1,3 @@ -/* this testcase is currently broken - * -- 2012-05-01 David Lamparter - */ -int main() { return 0; } - #include #include "vty.h" @@ -29,7 +24,6 @@ int main() { return 0; } struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; -#if 0 static int failed = 0; static int tty = 0; @@ -539,4 +533,3 @@ main (void) printf ("failures: %d\n", failed); return failed; } -#endif /* #if 0 */ From 1dba254e107dd0c4254d58e9304fc6293b46fd4d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 1 May 2012 16:20:33 +0100 Subject: [PATCH 0044/1342] tests: Fix some compile errors and warnings * aspath_test.c: match changes in aspath_unintern. Fix printf size_t warning. * bgp_capability_test.c: compile warnings. * bgp_mp_attr_test.c: update for attr parser context struct * ecommunity_test.c: ecommunity_free/ecommunity * test-checksum.c: some unused vars and funcs without need of prototypes. --- tests/aspath_test.c | 32 ++++++++++++++++---------------- tests/bgp_capability_test.c | 5 +++-- tests/bgp_mp_attr_test.c | 16 +++++++++++++--- tests/ecommunity_test.c | 6 +++--- tests/test-checksum.c | 9 +++------ 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 4a2ce9aa0..83eb9d808 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -983,8 +983,8 @@ validate (struct aspath *as, const struct test_spec *sp) printf ("private check: %d %d\n", sp->private_as, aspath_private_as_check (as)); } - aspath_unintern (asinout); - aspath_unintern (as4); + aspath_unintern (&asinout); + aspath_unintern (&as4); aspath_free (asconfeddel); aspath_free (asstr); @@ -1030,7 +1030,7 @@ parse_test (struct test_segment *t) printf ("\n"); if (asp) - aspath_unintern (asp); + aspath_unintern (&asp); } /* prepend testing */ @@ -1046,7 +1046,7 @@ prepend_test (struct tests *t) asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_dup (asp2); - aspath_unintern (asp2); + aspath_unintern (&asp2); asp2 = aspath_prepend (asp1, ascratch); @@ -1058,7 +1058,7 @@ prepend_test (struct tests *t) printf ("%s!\n", FAILED); printf ("\n"); - aspath_unintern (asp1); + aspath_unintern (&asp1); aspath_free (asp2); } @@ -1074,7 +1074,7 @@ empty_prepend_test (struct test_segment *t) asp2 = aspath_empty (); ascratch = aspath_dup (asp2); - aspath_unintern (asp2); + aspath_unintern (&asp2); asp2 = aspath_prepend (asp1, ascratch); @@ -1087,7 +1087,7 @@ empty_prepend_test (struct test_segment *t) printf ("\n"); if (asp1) - aspath_unintern (asp1); + aspath_unintern (&asp1); aspath_free (asp2); } @@ -1111,8 +1111,8 @@ as4_reconcile_test (struct tests *t) printf (FAILED "!\n"); printf ("\n"); - aspath_unintern (asp1); - aspath_unintern (asp2); + aspath_unintern (&asp1); + aspath_unintern (&asp2); aspath_free (ascratch); } @@ -1137,8 +1137,8 @@ aggregate_test (struct tests *t) printf (FAILED "!\n"); printf ("\n"); - aspath_unintern (asp1); - aspath_unintern (asp2); + aspath_unintern (&asp1); + aspath_unintern (&asp2); aspath_free (ascratch); /* aspath_unintern (ascratch);*/ } @@ -1185,8 +1185,8 @@ cmp_test () printf (OK "\n"); printf ("\n"); - aspath_unintern (asp1); - aspath_unintern (asp2); + aspath_unintern (&asp1); + aspath_unintern (&asp2); } } @@ -1218,7 +1218,7 @@ handle_attr_test (struct aspath_tests *t) if (ret != t->result) { printf ("bgp_attr_parse returned %d, expected %d\n", ret, t->result); - printf ("datalen %d\n", datalen); + printf ("datalen %zd\n", datalen); failed++; } if (ret != 0) @@ -1240,9 +1240,9 @@ handle_attr_test (struct aspath_tests *t) out: if (attr.aspath) - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); if (asp) - aspath_unintern (asp); + aspath_unintern (&asp); return failed - initfail; } diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index 9b43159c7..83da2e48f 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -8,6 +8,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" +#include "bgpd/bgp_packet.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" @@ -35,7 +36,7 @@ static struct test_segment { #define SHOULD_PARSE 0 #define SHOULD_ERR -1 int parses; /* whether it should parse or not */ - int peek_for; /* what peek_for_as4_capability should say */ + as_t peek_for; /* what peek_for_as4_capability should say */ /* AFI/SAFI validation */ int validate_afi; @@ -625,7 +626,7 @@ main (void) return -1; peer = peer_create_accept (bgp); - peer->host = "foo"; + peer->host = (char *) "foo"; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 9cbe9f224..1a48f4b74 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -438,6 +438,15 @@ parse_test (struct peer *peer, struct test_segment *t, int type) int oldfailed = failed; struct attr attr; struct bgp_nlri nlri; + struct bgp_attr_parser_args attr_args = { + .peer = peer, + .length = t->len, + .total = 1, + .attr = &attr, + .type = BGP_ATTR_MP_REACH_NLRI, + .flags = BGP_ATTR_FLAG_OPTIONAL, + .startp = BGP_INPUT_PNT (peer), + }; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); @@ -447,11 +456,12 @@ parse_test (struct peer *peer, struct test_segment *t, int type) stream_write (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); - + + if (type == BGP_ATTR_MP_REACH_NLRI) - ret = bgp_mp_reach_parse (peer, t->len, &attr, BGP_ATTR_FLAG_OPTIONAL, BGP_INPUT_PNT (peer), &nlri); + ret = bgp_mp_reach_parse (&attr_args, &nlri); else - ret = bgp_mp_unreach_parse (peer, t->len, BGP_ATTR_FLAG_OPTIONAL, BGP_INPUT_PNT (peer), &nlri); + ret = bgp_mp_unreach_parse (&attr_args, &nlri); if (!ret) { diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c index 418f659f7..87f20f282 100644 --- a/tests/ecommunity_test.c +++ b/tests/ecommunity_test.c @@ -25,7 +25,7 @@ struct test_spec static struct test_segment { const char *name; const char *desc; - const u_char data[1024]; + const u_int8_t data[1024]; int len; struct test_spec sp; } test_segments [] = @@ -97,7 +97,7 @@ validate (struct ecommunity *ecom, const struct test_spec *sp) str1, (etmp && str2) ? str2 : "NULL"); } - ecommunity_free (etmp); + ecommunity_free (&etmp); XFREE (MTYPE_ECOMMUNITY_STR, str1); XFREE (MTYPE_ECOMMUNITY_STR, str2); @@ -122,7 +122,7 @@ parse_test (struct test_segment *t) printf ("failed\n"); printf ("\n"); - ecommunity_unintern (ecom); + ecommunity_unintern (&ecom); } diff --git a/tests/test-checksum.c b/tests/test-checksum.c index bd156baa1..fc4eb02d0 100644 --- a/tests/test-checksum.c +++ b/tests/test-checksum.c @@ -32,7 +32,7 @@ accumulate (u_char *buffer, testsz_t len, testoff_t off) { u_int8_t *p; u_int16_t *csum; - int i, init_len, partial_len; + int i, partial_len; struct acc_vals ret; csum = (u_int16_t *) (buffer + off); @@ -41,7 +41,6 @@ accumulate (u_char *buffer, testsz_t len, testoff_t off) p = buffer; ret.c0 = 0; ret.c1 = 0; - init_len = len; while (len != 0) { @@ -397,11 +396,9 @@ verify (u_char * buffer, testsz_t len) u_int8_t *p; u_int32_t c0; u_int32_t c1; - u_int16_t checksum; int i, partial_len; p = buffer; - checksum = 0; c0 = 0; c1 = 0; @@ -427,7 +424,7 @@ verify (u_char * buffer, testsz_t len) return 1; } -int /* return checksum in low-order 16 bits */ +static int /* return checksum in low-order 16 bits */ in_cksum_optimized(void *parg, int nbytes) { u_short *ptr = parg; @@ -459,7 +456,7 @@ in_cksum_optimized(void *parg, int nbytes) } -int /* return checksum in low-order 16 bits */ +static int /* return checksum in low-order 16 bits */ in_cksum_rfc(void *parg, int count) /* from RFC 1071 */ { From 7621f336e2f346edee43227f0b1ef93fe769720b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 1 May 2012 16:24:35 +0100 Subject: [PATCH 0045/1342] bgpd: Make socket init separate, so unit tests work again. * Separate out BGP socket initialisation from bgp_get, and make it an explicit function. Allows unit tests to work again and probably also benefits dry-run. * bgpd.c: (bgp_get) move socket init out... (bgp_socket_init) to here * bgp_main.c: and call it after dry-run. * bgpd.h: (bgp_socket_init) add prototype --- bgpd/bgp_main.c | 6 ++++++ bgpd/bgpd.c | 16 +++++++++------- bgpd/bgpd.h | 1 + 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 0f1d4829c..5abc87565 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -441,6 +441,12 @@ main (int argc, char **argv) if(dryrun) return(0); + if (bgp_socket_init ()) + { + zlog_err ("BGP socket creation failed"); + return 1; + } + /* Turn into daemon if daemon_mode is set. */ if (daemon_mode && daemon (0, 0) < 0) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 9c8eda889..ab27783fa 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2055,13 +2055,6 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name) bgp_router_id_set(bgp, &router_id_zebra); *bgp_val = bgp; - /* Create BGP server socket, if first instance. */ - if (list_isempty(bm->bgp)) - { - if (bgp_socket (bm->port, bm->address) < 0) - return BGP_ERR_INVALID_VALUE; - } - listnode_add (bm->bgp, bgp); return 0; @@ -5341,6 +5334,15 @@ bgp_master_init (void) } +int +bgp_socket_init (void) +{ + /* Create BGP server socket */ + if (bgp_socket (bm->port, bm->address) < 0) + return BGP_ERR_INVALID_VALUE; + return 0; +} + void bgp_init (void) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 09a3435c3..d1e4f8e96 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -844,6 +844,7 @@ extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); extern void bgp_master_init (void); extern void bgp_init (void); +extern int bgp_socket_init (void); extern void bgp_route_map_init (void); extern int bgp_option_set (int); From 8794e8d229dc9fe29ea31424883433d4880ef408 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 13 Feb 2012 13:53:07 +0000 Subject: [PATCH 0046/1342] bgpd: Fix regression in args consolidation, total should be inited from args * bgp_attr.c: (bgp_attr_unknown) total should be initialised from the args. --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0d82aba04..81802ce81 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1646,7 +1646,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) { - bgp_size_t total; + bgp_size_t total = args->total; struct transit *transit; struct attr_extra *attre; struct peer *const peer = args->peer; From ddc943dec3c017583f81cce388c7d453293156c7 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Fri, 13 Apr 2012 13:46:07 +0200 Subject: [PATCH 0047/1342] bgpd, zebra: Fix format for some metric outputs Metrics are unsigned values. * bgpd/bgp_{debug,route,vty}.c, * zebra/zebra_vty.c: replace %d with %u for metrics & distances Signed-off-by: Jorge Boncompte [DTI2] [reworded commit message] Signed-off-by: David Lamparter --- bgpd/bgp_debug.c | 4 ++-- bgpd/bgp_route.c | 2 +- bgpd/bgp_vty.c | 2 +- zebra/zebra_vty.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 8e1618645..e3e3ec86f 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -194,11 +194,11 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) #endif /* HAVE_IPV6 */ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) - snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %d", + snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", attr->local_pref); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) - snprintf (buf + strlen (buf), size - strlen (buf), ", metric %d", + snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u", attr->med); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 087f83961..9f8d82327 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5954,7 +5954,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) vty_out (vty, " (inaccessible)"); else if (binfo->extra && binfo->extra->igpmetric) - vty_out (vty, " (metric %d)", binfo->extra->igpmetric); + vty_out (vty, " (metric %u)", binfo->extra->igpmetric); vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cbe0b4434..bba1c7de6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8966,7 +8966,7 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, vty_out (vty, " redistribute %s", zebra_route_string(i)); if (bgp->redist_metric_flag[afi][i]) - vty_out (vty, " metric %d", bgp->redist_metric[afi][i]); + vty_out (vty, " metric %u", bgp->redist_metric[afi][i]); if (bgp->rmap[afi][i].name) vty_out (vty, " route-map %s", bgp->rmap[afi][i].name); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index dafcf75af..8a57be916 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -541,7 +541,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); - vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); if (rib->refcnt) @@ -1519,7 +1519,7 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) rn->p.prefixlen, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); - vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); if (rib->refcnt) From 4fe080d7ee4c924a962d14423d94b4b8d8aba110 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Fri, 13 Apr 2012 13:46:08 +0200 Subject: [PATCH 0048/1342] bgpd: fix for route-maps with "match peer local" statements A route-map with a 'match peer local' statement it's shown like 'match peer (null)' on config output... ... and it's unparsable on daemon startup. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index abb85fd21..f95cab130 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -172,7 +172,7 @@ route_match_peer_compile (const char *arg) su = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union sockunion)); - ret = str2sockunion ( (arg)? arg : "0.0.0.0", su); + ret = str2sockunion (strcmp(arg, "local") ? arg : "0.0.0.0", su); if (ret < 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, su); return NULL; @@ -2430,7 +2430,7 @@ DEFUN (match_peer_local, "Match peer address\n" "Static or Redistributed routes\n") { - return bgp_route_match_add (vty, vty->index, "peer", NULL); + return bgp_route_match_add (vty, vty->index, "peer", "local"); } DEFUN (no_match_peer, From 0c5ed3ed00f630ae95dc2dfd4b5a938683e2a99e Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 10 Apr 2012 16:57:22 +0200 Subject: [PATCH 0049/1342] bgpd: Fix memory leak with 'set ip next-hop peer-address' A route-map with the mentioned statement causes a memory leak for every prefix that matches. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 7 ++----- lib/sockunion.h | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index f95cab130..fa645ac41 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -878,7 +878,6 @@ route_set_ip_nexthop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_ip_nexthop_set *rins = rule; - struct in_addr peer_address; struct bgp_info *bgp_info; struct peer *peer; @@ -894,16 +893,14 @@ route_set_ip_nexthop (void *rule, struct prefix *prefix, && peer->su_remote && sockunion_family (peer->su_remote) == AF_INET) { - inet_aton (sockunion_su2str (peer->su_remote), &peer_address); - bgp_info->attr->nexthop = peer_address; + bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_remote); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); } else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) && peer->su_local && sockunion_family (peer->su_local) == AF_INET) { - inet_aton (sockunion_su2str (peer->su_local), &peer_address); - bgp_info->attr->nexthop = peer_address; + bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_local); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); } } diff --git a/lib/sockunion.h b/lib/sockunion.h index 4531f620a..15b97fc54 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -86,6 +86,8 @@ enum connect_result #define sockunion_family(X) (X)->sa.sa_family +#define sockunion2ip(X) (X)->sin.sin_addr.s_addr + /* Prototypes. */ extern int str2sockunion (const char *, union sockunion *); extern const char *sockunion2str (union sockunion *, char *, size_t); From d227617a972bb20a974be68bea5032e692a0970f Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 10 Apr 2012 16:57:23 +0200 Subject: [PATCH 0050/1342] lib: remove last uses of sockunion_su2str() Use of this function is prone to memory leaks. This fixes a memory accounting bug for vty denied connections. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- lib/sockunion.c | 19 ------------------- lib/sockunion.h | 1 - lib/vty.c | 21 ++++++++------------- lib/vty.h | 7 ++++--- 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/lib/sockunion.c b/lib/sockunion.c index 597705293..cfb6f9c5a 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -207,25 +207,6 @@ sockunion_str2su (const char *str) return NULL; } -char * -sockunion_su2str (union sockunion *su) -{ - char str[SU_ADDRSTRLEN]; - - switch (su->sa.sa_family) - { - case AF_INET: - inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str)); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str)); - break; -#endif /* HAVE_IPV6 */ - } - return XSTRDUP (MTYPE_TMP, str); -} - /* Convert IPv4 compatible IPv6 address to IPv4 address. */ static void sockunion_normalise_mapped (union sockunion *su) diff --git a/lib/sockunion.h b/lib/sockunion.h index 15b97fc54..8b0605868 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -94,7 +94,6 @@ extern const char *sockunion2str (union sockunion *, char *, size_t); extern int sockunion_cmp (union sockunion *, union sockunion *); extern int sockunion_same (union sockunion *, union sockunion *); -extern char *sockunion_su2str (union sockunion *su); extern union sockunion *sockunion_str2su (const char *str); extern struct in_addr sockunion_get_in_addr (union sockunion *su); extern int sockunion_accept (int sock, union sockunion *); diff --git a/lib/vty.c b/lib/vty.c index 9a4efe641..70bf5645b 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1612,13 +1612,16 @@ vty_flush (struct thread *thread) static struct vty * vty_create (int vty_sock, union sockunion *su) { + char buf[SU_ADDRSTRLEN]; struct vty *vty; + sockunion2str(su, buf, SU_ADDRSTRLEN); + /* Allocate new vty structure and set up default values. */ vty = vty_new (); vty->fd = vty_sock; vty->type = VTY_TERM; - vty->address = sockunion_su2str (su); + strcpy (vty->address, buf); if (no_password_check) { if (restricted_mode) @@ -1693,7 +1696,7 @@ vty_accept (struct thread *thread) int accept_sock; struct prefix *p = NULL; struct access_list *acl = NULL; - char *bufp; + char buf[SU_ADDRSTRLEN]; accept_sock = THREAD_FD (thread); @@ -1719,10 +1722,8 @@ vty_accept (struct thread *thread) if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && (access_list_apply (acl, p) == FILTER_DENY)) { - char *buf; zlog (NULL, LOG_INFO, "Vty connection refused from %s", - (buf = sockunion_su2str (&su))); - free (buf); + sockunion2str (&su, buf, SU_ADDRSTRLEN)); close (vty_sock); /* continue accepting connections */ @@ -1741,10 +1742,8 @@ vty_accept (struct thread *thread) if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && (access_list_apply (acl, p) == FILTER_DENY)) { - char *buf; zlog (NULL, LOG_INFO, "Vty connection refused from %s", - (buf = sockunion_su2str (&su))); - free (buf); + sockunion2str (&su, buf, SU_ADDRSTRLEN)); close (vty_sock); /* continue accepting connections */ @@ -1767,9 +1766,7 @@ vty_accept (struct thread *thread) safe_strerror (errno)); zlog (NULL, LOG_INFO, "Vty connection from %s", - (bufp = sockunion_su2str (&su))); - if (bufp) - XFREE (MTYPE_TMP, bufp); + sockunion2str (&su, buf, SU_ADDRSTRLEN)); vty_create (vty_sock, &su); @@ -2193,8 +2190,6 @@ vty_close (struct vty *vty) if (vty->fd > 0) close (vty->fd); - if (vty->address) - XFREE (MTYPE_TMP, vty->address); if (vty->buf) XFREE (MTYPE_VTY, vty->buf); diff --git a/lib/vty.h b/lib/vty.h index 639d74175..e5158687d 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "log.h" +#include "sockunion.h" #define VTY_BUFSIZ 512 #define VTY_MAXHIST 20 @@ -39,9 +40,6 @@ struct vty /* Node status of this vty */ int node; - /* What address is this vty comming from. */ - char *address; - /* Failure count */ int fail; @@ -118,6 +116,9 @@ struct vty /* Timeout seconds and thread. */ unsigned long v_timeout; struct thread *t_timeout; + + /* What address is this vty comming from. */ + char address[SU_ADDRSTRLEN]; }; /* Integrated configuration file. */ From c63b83fe8d1addecc949258479b8d54180c4da60 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 10 Apr 2012 16:57:24 +0200 Subject: [PATCH 0051/1342] bgpd: Fix memory leak of some "show ip bgp neighbor" commands sockunion_str2su() use is prone to memory leaks. Remove it's use all over the code. At least these commands leaked a sockunion union: - show ip bgp vpnv4 ... routes - show ip bgp ... received prefix-filter Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_mplsvpn.c | 27 ++++++++++---------- bgpd/bgp_route.c | 60 +++++++++++++++++++++++++++------------------ bgpd/bgp_routemap.c | 11 +++------ bgpd/bgp_vty.c | 12 ++++----- lib/sockunion.c | 33 ------------------------- lib/sockunion.h | 1 - 6 files changed, 59 insertions(+), 85 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index c1f1fbb37..b0cf2a988 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -581,24 +581,25 @@ DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, "Neighbor to display information about\n" "Display routes learned from neighbor\n") { - union sockunion *su; + union sockunion su; struct peer *peer; - - su = sockunion_str2su (argv[0]); - if (su == NULL) + int ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; + return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0); + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, @@ -615,7 +616,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, "Display routes learned from neighbor\n") { int ret; - union sockunion *su; + union sockunion su; struct peer *peer; struct prefix_rd prd; @@ -626,21 +627,21 @@ DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, return CMD_WARNING; } - su = sockunion_str2su (argv[1]); - if (su == NULL) + ret = str2sockunion (argv[1], &su); + if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; + return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0); + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9f8d82327..d96224db4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10202,15 +10202,18 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter, "Display the prefixlist filter\n") { char name[BUFSIZ]; - union sockunion *su; + union sockunion su; struct peer *peer; - int count; + int count, ret; - su = sockunion_str2su (argv[0]); - if (su == NULL) - return CMD_WARNING; + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; @@ -10241,15 +10244,18 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, "Display the prefixlist filter\n") { char name[BUFSIZ]; - union sockunion *su; + union sockunion su; struct peer *peer; - int count; + int count, ret; - su = sockunion_str2su (argv[1]); - if (su == NULL) - return CMD_WARNING; + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; @@ -10312,15 +10318,18 @@ DEFUN (show_bgp_neighbor_received_prefix_filter, "Display the prefixlist filter\n") { char name[BUFSIZ]; - union sockunion *su; + union sockunion su; struct peer *peer; - int count; + int count, ret; - su = sockunion_str2su (argv[0]); - if (su == NULL) - return CMD_WARNING; + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; @@ -10394,10 +10403,10 @@ DEFUN (show_bgp_view_neighbor_received_prefix_filter, "Display the prefixlist filter\n") { char name[BUFSIZ]; - union sockunion *su; + union sockunion su; struct peer *peer; struct bgp *bgp; - int count; + int count, ret; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); @@ -10407,11 +10416,14 @@ DEFUN (show_bgp_view_neighbor_received_prefix_filter, return CMD_WARNING; } - su = sockunion_str2su (argv[1]); - if (su == NULL) - return CMD_WARNING; + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup (bgp, su); + peer = peer_lookup (bgp, &su); if (! peer) return CMD_WARNING; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index fa645ac41..f22040032 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -111,7 +111,8 @@ route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { union sockunion *su; - union sockunion *su2; + union sockunion su_def = { .sa.sa_family = AF_INET, + .sin.sin_addr.s_addr = INADDR_ANY }; struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; @@ -127,8 +128,7 @@ route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH */ - su2 = sockunion_str2su ("0.0.0.0"); - if ( sockunion_same (su, su2) ) + if (sockunion_same (su, &su_def)) { int ret; if ( CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_NETWORK) || @@ -137,12 +137,9 @@ route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, ret = RMAP_MATCH; else ret = RMAP_NOMATCH; - - sockunion_free (su2); return ret; } - sockunion_free (su2); - + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (sockunion_same (su, &peer->su)) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bba1c7de6..03746bdd0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2943,7 +2943,6 @@ peer_update_source_vty (struct vty *vty, const char *peer_str, const char *source_str) { struct peer *peer; - union sockunion *su; peer = peer_and_group_lookup_vty (vty, peer_str); if (! peer) @@ -2951,12 +2950,11 @@ peer_update_source_vty (struct vty *vty, const char *peer_str, if (source_str) { - su = sockunion_str2su (source_str); - if (su) - { - peer_update_source_addr_set (peer, su); - sockunion_free (su); - } + union sockunion su; + int ret = str2sockunion (source_str, &su); + + if (ret == 0) + peer_update_source_addr_set (peer, &su); else peer_update_source_if_set (peer, source_str); } diff --git a/lib/sockunion.c b/lib/sockunion.c index cfb6f9c5a..4c2837b12 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -174,39 +174,6 @@ sockunion2str (union sockunion *su, char *buf, size_t len) return NULL; } -union sockunion * -sockunion_str2su (const char *str) -{ - int ret; - union sockunion *su; - - su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); - - ret = inet_pton (AF_INET, str, &su->sin.sin_addr); - if (ret > 0) /* Valid IPv4 address format. */ - { - su->sin.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - su->sin.sin_len = sizeof(struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - return su; - } -#ifdef HAVE_IPV6 - ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); - if (ret > 0) /* Valid IPv6 address format. */ - { - su->sin6.sin6_family = AF_INET6; -#ifdef SIN6_LEN - su->sin6.sin6_len = sizeof(struct sockaddr_in6); -#endif /* SIN6_LEN */ - return su; - } -#endif /* HAVE_IPV6 */ - - XFREE (MTYPE_SOCKUNION, su); - return NULL; -} - /* Convert IPv4 compatible IPv6 address to IPv4 address. */ static void sockunion_normalise_mapped (union sockunion *su) diff --git a/lib/sockunion.h b/lib/sockunion.h index 8b0605868..180b2b4d2 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -94,7 +94,6 @@ extern const char *sockunion2str (union sockunion *, char *, size_t); extern int sockunion_cmp (union sockunion *, union sockunion *); extern int sockunion_same (union sockunion *, union sockunion *); -extern union sockunion *sockunion_str2su (const char *str); extern struct in_addr sockunion_get_in_addr (union sockunion *su); extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); From 128293286a8be01b99ed60db53e19ce6e2669558 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 10 Apr 2012 16:57:25 +0200 Subject: [PATCH 0052/1342] lib, zebra: extend use of sockunion2ip macro * lib/sockunion.c, * zebra/zebra_rib.c: replace ->sin.sin_addr.s_addr with sockunion2ip Signed-off-by: Jorge Boncompte [DTI2] [reworded commit message] Signed-off-by: David Lamparter --- lib/sockunion.c | 6 +++--- zebra/zebra_rib.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/sockunion.c b/lib/sockunion.c index 4c2837b12..37dc3f90b 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -370,7 +370,7 @@ sockunion_bind (int sock, union sockunion *su, unsigned short port, su->sin.sin_len = size; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ if (su_addr == NULL) - su->sin.sin_addr.s_addr = htonl (INADDR_ANY); + sockunion2ip (su) = htonl (INADDR_ANY); } #ifdef HAVE_IPV6 else if (su->sa.sa_family == AF_INET6) @@ -727,9 +727,9 @@ sockunion_cmp (union sockunion *su1, union sockunion *su2) if (su1->sa.sa_family == AF_INET) { - if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr)) + if (ntohl (sockunion2ip (su1)) == ntohl (sockunion2ip (su2))) return 0; - if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr)) + if (ntohl (sockunion2ip (su1)) > ntohl (sockunion2ip (su2))) return 1; else return -1; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 154e8d551..50674ee88 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -678,8 +678,8 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { /* We are happy with either direct or recursive hexthop */ - if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr || - nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr) + if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) || + nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate)) return ZEBRA_RIB_FOUND_EXACT; else { @@ -688,7 +688,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) char gate_buf[INET_ADDRSTRLEN], rgate_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->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); - inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN); + inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN); zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); } return ZEBRA_RIB_FOUND_NOGATE; From 37beff6feb7c1715a19b59b8a87edcb6b50d5ac2 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 10 Apr 2012 16:57:26 +0200 Subject: [PATCH 0053/1342] lib: remove sockunion related unused definitions Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- lib/sockunion.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/sockunion.h b/lib/sockunion.h index 180b2b4d2..1a0a3c95c 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -78,12 +78,6 @@ enum connect_result #define SET_IN6_LINKLOCAL_IFINDEX(a, i) #endif /* KAME */ -/* shortcut macro to specify address field of struct sockaddr */ -#define sock2ip(X) (((struct sockaddr_in *)(X))->sin_addr.s_addr) -#ifdef HAVE_IPV6 -#define sock2ip6(X) (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr) -#endif /* HAVE_IPV6 */ - #define sockunion_family(X) (X)->sa.sa_family #define sockunion2ip(X) (X)->sin.sin_addr.s_addr @@ -94,7 +88,6 @@ extern const char *sockunion2str (union sockunion *, char *, size_t); extern int sockunion_cmp (union sockunion *, union sockunion *); extern int sockunion_same (union sockunion *, union sockunion *); -extern struct in_addr sockunion_get_in_addr (union sockunion *su); extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); extern int sockopt_reuseaddr (int); From 682ca04c4032bfbf31e51df2472345fda1ff7b2c Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 10 Apr 2012 16:57:27 +0200 Subject: [PATCH 0054/1342] bgpd: cleanup, use correct buffer sizes for sockunion2str() Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_fsm.c | 4 ++-- bgpd/bgp_network.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 813e59ef8..d92004579 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -597,8 +597,6 @@ bgp_stop_with_error (struct peer *peer) static int bgp_connect_success (struct peer *peer) { - char buf1[BUFSIZ]; - if (peer->fd < 0) { zlog_err ("bgp_connect_success peer's fd is negative value %d", @@ -612,6 +610,8 @@ bgp_connect_success (struct peer *peer) if (BGP_DEBUG (normal, NORMAL)) { + char buf1[SU_ADDRSTRLEN]; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) zlog_debug ("%s open active, local address %s", peer->host, sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN)); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index a7dca5313..73234fe26 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -185,7 +185,7 @@ bgp_accept (struct thread *thread) zlog_debug ("[Event] Make dummy peer structure until read Open packet"); { - char buf[SU_ADDRSTRLEN + 1]; + char buf[SU_ADDRSTRLEN]; peer = peer_create_accept (peer1->bgp); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); From a4c06dec1ebe41dd4444d387478500e6022e2209 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Fri, 20 Apr 2012 14:28:40 +0200 Subject: [PATCH 0055/1342] zebra: no need to clear memory of the netlink buffers The memory is always written before sending. Clearing it before use slows netlink_route_multipath() down considerably and it's pretty noticeable in a full-internet table scenario loading. * zebra/rt_netlink.c: subtract bulk buffer size from clear Signed-off-by: Jorge Boncompte [DTI2] [reworded commit message] Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5909131dd..15475e205 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1368,7 +1368,7 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate, char buf[NL_PKT_BUF_SIZE]; } req; - memset (&req, 0, sizeof req); + memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); @@ -1443,7 +1443,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, char buf[NL_PKT_BUF_SIZE]; } req; - memset (&req, 0, sizeof req); + memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); @@ -1903,7 +1903,7 @@ netlink_address (int cmd, int family, struct interface *ifp, } req; p = ifc->address; - memset (&req, 0, sizeof req); + memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); From 42cb6b6655d0cc141374ec373220d244f81fbba0 Mon Sep 17 00:00:00 2001 From: "G.Balaji" Date: Mon, 2 Apr 2012 23:31:29 +0530 Subject: [PATCH 0056/1342] zebra: feed Connected routes into MRIB The SAFI_MULTICAST RIB needs to contain Connected routes so that the nexthop lookup does not fail and so that multicast routing daemons do not need to sidestep and look into SAFI_UNICAST to be aware of connected subnets. * zebra/connected.c: add & delete connected in SAFI_MULTICAST Signed-off-by: G.Balaji [merged add/delete patches] Signed-off-by: David Lamparter --- zebra/connected.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/connected.c b/zebra/connected.c index f699b147d..05538c5d4 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -191,6 +191,9 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); + rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, + RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); + rib_update (); } @@ -297,6 +300,8 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) /* Same logic as for connected_up_ipv4(): push the changes into the head. */ rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_MULTICAST); + rib_update (); } From 36735ed988f96810e78d0ace2f7d8e6397db5c50 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 9 May 2012 13:38:36 +0200 Subject: [PATCH 0057/1342] zebra: fix up compilation without rtadv/IPv6 let's ground the rtadv.h file if route advertisements are disabled. And fix up the CLI for it, as well as move the "show ip mroute" to its proper place. * zebra/rtadv.h: #ifdef RTADV * zebra/main.c: #ifdef RTADV * zebra/zebra_vty.c: move "show ip mroute" out of #ifdef IPV6 From: Joachim Nilsson [moved #ifdef RTADV to rtadv.h] Signed-off-by: David Lamparter --- zebra/main.c | 2 ++ zebra/rtadv.h | 5 ++++ zebra/zebra_vty.c | 73 ++++++++++++++++++++++------------------------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/zebra/main.c b/zebra/main.c index 5f26ce243..5b5265f27 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -327,7 +327,9 @@ main (int argc, char **argv) zebra_vty_init (); access_list_init (); prefix_list_init (); +#ifdef RTADV rtadv_init (); +#endif #ifdef HAVE_IRDP irdp_init(); #endif diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 564a4c66d..8cb933e0b 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -26,6 +26,9 @@ #include "vty.h" #include "zebra/interface.h" +/* NB: RTADV is defined in zebra/interface.h above */ +#ifdef RTADV + /* Router advertisement prefix. */ struct rtadv_prefix { @@ -96,4 +99,6 @@ struct nd_opt_homeagent_info { /* Home Agent info */ extern const char *rtadv_pref_strs[]; +#endif /* RTADV */ + #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 8a57be916..743c13fe7 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1197,6 +1197,40 @@ DEFUN (show_ip_protocol, return CMD_SUCCESS; } +/* + * Show IP mroute command to dump the BGP Multicast + * routing table + */ +DEFUN (show_ip_mroute, + show_ip_mroute_cmd, + "show ip mroute", + SHOW_STR + IP_STR + "IP Multicast routing table\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + table = vrf_table (AFI_IP, SAFI_MULTICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + #ifdef HAVE_IPV6 /* General fucntion for IPv6 static route. */ @@ -1951,40 +1985,6 @@ DEFUN (show_ipv6_route_summary, return CMD_SUCCESS; } -/* - * Show IP mroute command to dump the BGP Multicast - * routing table - */ -DEFUN (show_ip_mroute, - show_ip_mroute_cmd, - "show ip mroute", - SHOW_STR - IP_STR - "IP Multicast routing table\n") -{ - struct route_table *table; - struct route_node *rn; - struct rib *rib; - int first = 1; - - table = vrf_table (AFI_IP, SAFI_MULTICAST, 0); - if (! table) - return CMD_SUCCESS; - - /* Show all IPv4 routes. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V4_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } - return CMD_SUCCESS; -} - /* * Show IPv6 mroute command.Used to dump * the Multicast routing table. @@ -2020,11 +2020,6 @@ DEFUN (show_ipv6_mroute, return CMD_SUCCESS; } - - - - - /* Write IPv6 static route configuration. */ static int static_config_ipv6 (struct vty *vty) From 7c9c6aebe8daabece9e78d47727dcdcb757c0a63 Mon Sep 17 00:00:00 2001 From: Roman Hoog Antink Date: Wed, 9 May 2012 06:35:34 +0000 Subject: [PATCH 0058/1342] lib: drop heuristic IPv6 address recognition * command.c: (cmd_ipv6_match) Drop IPv6 address recognition heuristics and solely rely on inet_pton, because strings like "abcd" were mistaken for IPv6 addresses. This affects e.g. the command "neighbour WORD peer-group", which won't work with words consisting of up to 4 characters between 'a' and 'f' and digits. From: Roman Hoog Antink [full delete instead of #if 0] Signed-off-by: David Lamparter --- lib/command.c | 81 +-------------------------------------------------- 1 file changed, 1 insertion(+), 80 deletions(-) diff --git a/lib/command.c b/lib/command.c index e62a7a7e6..4d95e924d 100644 --- a/lib/command.c +++ b/lib/command.c @@ -868,86 +868,7 @@ cmd_ipv6_match (const char *str) if (ret == 1) return exact_match; - while (*str != '\0') - { - switch (state) - { - case STATE_START: - if (*str == ':') - { - if (*(str + 1) != ':' && *(str + 1) != '\0') - return no_match; - colons--; - state = STATE_COLON; - } - else - { - sp = str; - state = STATE_ADDR; - } - - continue; - case STATE_COLON: - colons++; - if (*(str + 1) == ':') - state = STATE_DOUBLE; - else - { - sp = str + 1; - state = STATE_ADDR; - } - break; - case STATE_DOUBLE: - if (double_colon) - return no_match; - - if (*(str + 1) == ':') - return no_match; - else - { - if (*(str + 1) != '\0') - colons++; - sp = str + 1; - state = STATE_ADDR; - } - - double_colon++; - nums++; - break; - case STATE_ADDR: - if (*(str + 1) == ':' || *(str + 1) == '\0') - { - if (str - sp > 3) - return no_match; - - nums++; - state = STATE_COLON; - } - if (*(str + 1) == '.') - state = STATE_DOT; - break; - case STATE_DOT: - state = STATE_ADDR; - break; - default: - break; - } - - if (nums > 8) - return no_match; - - if (colons > 7) - return no_match; - - str++; - } - -#if 0 - if (nums < 11) - return partly_match; -#endif /* 0 */ - - return exact_match; + return no_match; } static enum match_type From 1b79fcb646f66682a62cf34f3cc343b1a9706699 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 15:17:31 +0000 Subject: [PATCH 0059/1342] lib: fix thread_cancel_event() ospfd was crashing some times on neighbour going down. The cause was that ospf_nsm_event() was accessing already freed memory in ospf_nbr_delete() call from ospf_nsm_event(). What happens is that since commit b5043aab (lib: fix incorrect thread list...) now a thread can be on the event and ready lists but thread_cancel_event() doesn't account for that. * thread.c: (thread_cancel_event) loop on the ready list too to cancel pending events. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- lib/thread.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/thread.c b/lib/thread.c index b36c43a9a..dd0413b34 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -916,6 +916,24 @@ thread_cancel_event (struct thread_master *m, void *arg) thread_add_unuse (m, t); } } + + /* thread can be on the ready list too */ + thread = m->ready.head; + while (thread) + { + struct thread *t; + + t = thread; + thread = t->next; + + if (t->arg == arg) + { + ret++; + thread_list_delete (&m->ready, t); + t->type = THREAD_UNUSED; + thread_add_unuse (m, t); + } + } return ret; } From 8692c506520f6b268525b80890702432c95f13c4 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 15:17:34 +0000 Subject: [PATCH 0060/1342] bgpd: fix crash with vpnv4 soft-reconfiguration bgp_afi_node_get() expects a non-NULL prd for a SAFI_MPLS_VPN prefix. * bgp_route.c: pass down the struct prefix_rd from bgp_soft_reconfig_in() and bgp_soft_reconfig_rsclient(). Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d96224db4..589c0738a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2616,7 +2616,7 @@ bgp_announce_route_all (struct peer *peer) static void bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, - safi_t safi, struct bgp_table *table) + safi_t safi, struct bgp_table *table, struct prefix_rd *prd) { struct bgp_node *rn; struct bgp_adj_in *ain; @@ -2627,8 +2627,11 @@ bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ain = rn->adj_in; ain; ain = ain->next) { + struct bgp_info *ri = rn->info; + bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, - &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); + &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, + (bgp_info_extra_get (ri))->tag); } } @@ -2639,18 +2642,25 @@ bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) struct bgp_node *rn; if (safi != SAFI_MPLS_VPN) - bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL); + bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL, NULL); else for (rn = bgp_table_top (rsclient->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) - bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table); + { + struct prefix_rd prd; + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy(&prd.val, rn->p.u.val, 8); + + bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table, &prd); + } } static void bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, - struct bgp_table *table) + struct bgp_table *table, struct prefix_rd *prd) { int ret; struct bgp_node *rn; @@ -2664,9 +2674,12 @@ bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, { if (ain->peer == peer) { + struct bgp_info *ri = rn->info; + ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - NULL, NULL, 1); + prd, (bgp_info_extra_get (ri))->tag, 1); + if (ret < 0) { bgp_unlock_node (rn); @@ -2687,12 +2700,19 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) return; if (safi != SAFI_MPLS_VPN) - bgp_soft_reconfig_table (peer, afi, safi, NULL); + bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) - bgp_soft_reconfig_table (peer, afi, safi, table); + { + struct prefix_rd prd; + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy(&prd.val, rn->p.u.val, 8); + + bgp_soft_reconfig_table (peer, afi, safi, table, &prd); + } } From f669f7d25f0f491d5e487897227ff434aef20406 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:51 +0000 Subject: [PATCH 0061/1342] bgpd: optimize aspath string representation and assegments handling * bgp_aspath.h: Add str_len to struct aspath. * bgp_aspath.c: Save the aspath string representation length and use it instead of strlen(). (aspath_make_str_count) assign the string buffer directly for consistency with the string length and change the return type to void. (aspath_dup) use str_len and copy the string instead of calling aspath_make_str_count(). (assegment_data_new) change from XCALLOC to XMALLOC. All users initialize the memory before use. (assegment_data_free) unused, removed. (aspath_intern) check that there's always a ->str pointer. (aspath_hash_alloc) reuse assegments and string representation instead of copying them. (aspath_parse) now aspath_hash_alloc does not dupes memory, free the temporary structures only if the aspath it is in the hash. (aspath_cmp_left) remove useless NULL initialization. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_aspath.c | 141 ++++++++++++++++++++++++---------------------- bgpd/bgp_aspath.h | 1 + 2 files changed, 76 insertions(+), 66 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 64b36775f..c37a8897f 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -91,16 +91,11 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; +/* Callers are required to initialize the memory */ static as_t * assegment_data_new (int num) { - return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); -} - -static void -assegment_data_free (as_t *asdata) -{ - XFREE (MTYPE_AS_SEG_DATA,asdata); + return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } /* Get a new segment. Note that 0 is an allowed length, @@ -191,6 +186,7 @@ static struct assegment * assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) { as_t *newas; + int i; if (!num) return seg; @@ -199,22 +195,16 @@ assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) return seg; /* we don't do huge prepends */ newas = assegment_data_new (seg->length + num); - - if (newas) - { - int i; - for (i = 0; i < num; i++) - newas[i] = asnum; - - memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); - XFREE (MTYPE_AS_SEG_DATA, seg->as); - seg->as = newas; - seg->length += num; - return seg; - } - assegment_free_all (seg); - return NULL; + for (i = 0; i < num; i++) + newas[i] = asnum; + + memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); + XFREE (MTYPE_AS_SEG_DATA, seg->as); + seg->as = newas; + seg->length += num; + + return seg; } /* append given array of as numbers to the segment */ @@ -504,7 +494,7 @@ aspath_has_as4 (struct aspath *aspath) } /* Convert aspath structure to string expression. */ -static char * +static void aspath_make_str_count (struct aspath *as) { struct assegment *seg; @@ -515,9 +505,10 @@ aspath_make_str_count (struct aspath *as) /* Empty aspath. */ if (!as->segments) { - str_buf = XMALLOC (MTYPE_AS_STR, 1); - str_buf[0] = '\0'; - return str_buf; + as->str = XMALLOC (MTYPE_AS_STR, 1); + as->str[0] = '\0'; + as->str_len = 0; + return; } seg = as->segments; @@ -554,7 +545,9 @@ aspath_make_str_count (struct aspath *as) break; default: XFREE (MTYPE_AS_STR, str_buf); - return NULL; + as->str = NULL; + as->str_len = 0; + return; } /* We might need to increase str_buf, particularly if path has @@ -601,8 +594,10 @@ aspath_make_str_count (struct aspath *as) assert (len < str_size); str_buf[len] = '\0'; + as->str = str_buf; + as->str_len = len; - return str_buf; + return; } static void @@ -610,7 +605,7 @@ aspath_str_update (struct aspath *as) { if (as->str) XFREE (MTYPE_AS_STR, as->str); - as->str = aspath_make_str_count (as); + aspath_make_str_count (as); } /* Intern allocated AS path. */ @@ -618,21 +613,19 @@ struct aspath * aspath_intern (struct aspath *aspath) { struct aspath *find; - - /* Assert this AS path structure is not interned. */ + + /* Assert this AS path structure is not interned and has the string + representation built. */ assert (aspath->refcnt == 0); + assert (aspath->str); /* Check AS path hash. */ find = hash_get (ashash, aspath, hash_alloc_intern); - if (find != aspath) aspath_free (aspath); find->refcnt++; - if (! find->str) - find->str = aspath_make_str_count (find); - return find; } @@ -641,16 +634,25 @@ aspath_intern (struct aspath *aspath) struct aspath * aspath_dup (struct aspath *aspath) { + unsigned short buflen = aspath->str_len + 1; struct aspath *new; new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); if (aspath->segments) new->segments = assegment_dup_all (aspath->segments); - else - new->segments = NULL; - new->str = aspath_make_str_count (aspath); + if (!aspath->str) + return new; + + new->str = XMALLOC (MTYPE_AS_STR, buflen); + new->str_len = aspath->str_len; + + /* copy the string data */ + if (aspath->str_len > 0) + memcpy (new->str, aspath->str, buflen); + else + new->str[0] = '\0'; return new; } @@ -658,19 +660,24 @@ aspath_dup (struct aspath *aspath) static void * aspath_hash_alloc (void *arg) { - struct aspath *aspath; + const struct aspath *aspath = arg; + struct aspath *new; - /* New aspath structure is needed. */ - aspath = aspath_dup (arg); - /* Malformed AS path value. */ + assert (aspath->str); if (! aspath->str) - { - aspath_free (aspath); - return NULL; - } + return NULL; - return aspath; + /* New aspath structure is needed. */ + new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + + /* Reuse segments and string representation */ + new->refcnt = 0; + new->segments = aspath->segments; + new->str = aspath->str; + new->str_len = aspath->str_len; + + return new; } /* parse as-segment byte stream in struct assegment */ @@ -794,19 +801,21 @@ aspath_parse (struct stream *s, size_t length, int use32bit) memset (&as, 0, sizeof (struct aspath)); if (assegments_parse (s, length, &as.segments, use32bit) < 0) return NULL; - + /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); - - /* aspath_hash_alloc dupes segments too. that probably could be - * optimised out. - */ - assegment_free_all (as.segments); - if (as.str) - XFREE (MTYPE_AS_STR, as.str); - - if (! find) - return NULL; + + /* bug! should not happen, let the daemon crash below */ + assert (find); + + /* if the aspath was already hashed free temporary memory. */ + if (find->refcnt) + { + assegment_free_all (as.segments); + /* aspath_key_make() always updates the string */ + XFREE (MTYPE_AS_STR, as.str); + } + find->refcnt++; return find; @@ -1400,8 +1409,8 @@ aspath_add_seq (struct aspath *aspath, as_t asno) int aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) { - const struct assegment *seg1 = NULL; - const struct assegment *seg2 = NULL; + const struct assegment *seg1; + const struct assegment *seg2; if (!(aspath1 && aspath2)) return 0; @@ -1639,7 +1648,7 @@ aspath_empty_get (void) struct aspath *aspath; aspath = aspath_new (); - aspath->str = aspath_make_str_count (aspath); + aspath_make_str_count (aspath); return aspath; } @@ -1798,7 +1807,7 @@ aspath_str2aspath (const char *str) } } - aspath->str = aspath_make_str_count (aspath); + aspath_make_str_count (aspath); return aspath; } @@ -1807,13 +1816,13 @@ aspath_str2aspath (const char *str) unsigned int aspath_key_make (void *p) { - struct aspath * aspath = (struct aspath *) p; + struct aspath *aspath = (struct aspath *) p; unsigned int key = 0; if (!aspath->str) aspath_str_update (aspath); - - key = jhash (aspath->str, strlen(aspath->str), 2334325); + + key = jhash (aspath->str, aspath->str_len, 2334325); return key; } @@ -1876,7 +1885,7 @@ aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const { assert (format); vty_out (vty, format, as->str); - if (strlen (as->str) && strlen (suffix)) + if (as->str_len && strlen (suffix)) vty_out (vty, "%s", suffix); } diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index fc4dd6b79..e8764cca2 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -58,6 +58,7 @@ struct aspath /* String expression of AS path. This string is used by vty output and AS path regular expression match. */ char *str; + unsigned short str_len; }; #define ASPATH_STR_DEFAULT_LEN 32 From 10f9bf3f2021f874e574e4ebae9413bee982ed2b Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:52 +0000 Subject: [PATCH 0062/1342] bgpd: optimize bgp_nexthop_self() This function scores 2nd, profiling a full internet table load. It's called for every prefix received. Instead of looping in the interface lists comparing addresses use a hash to mantain them. * bgpd.c: Init the own address hash. * bgp_nexthop.c: Introduce methods to maintain an own address hash. (bgp_connected_add) add addresses to the hash. (bgp_connected_delete) delete addresses from the hash. (bgp_nexthop_self) lookup addresses in the hash. Removed the unused afi_t parameter. * bgp_route.c: (bgp_update_main) Micro-optimization, rearranged condition to not lookup the hash for bogus nexthops (0.0.0.0 or a class D/E address) Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_nexthop.c | 106 ++++++++++++++++++++++++++++++++++++++------- bgpd/bgp_nexthop.h | 3 +- bgpd/bgp_route.c | 6 +-- bgpd/bgpd.c | 1 + lib/memtypes.c | 1 + 5 files changed, 97 insertions(+), 20 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index fdf251b2a..723057b68 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -28,6 +28,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "network.h" #include "log.h" #include "memory.h" +#include "hash.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -524,6 +526,83 @@ bgp_scan_timer (struct thread *t) return 0; } + +/* BGP own address structure */ +struct bgp_addr +{ + struct in_addr addr; + int refcnt; +}; + +static struct hash *bgp_address_hash; + +static void * +bgp_address_hash_alloc (void *p) +{ + struct in_addr *val = p; + struct bgp_addr *addr; + + addr = XMALLOC (MTYPE_BGP_ADDR, sizeof (struct bgp_addr)); + addr->refcnt = 0; + addr->addr.s_addr = val->s_addr; + + return addr; +} + +static unsigned int +bgp_address_hash_key_make (void *p) +{ + const struct bgp_addr *addr = p; + + return jhash_1word(addr->addr.s_addr, 0); +} + +static int +bgp_address_hash_cmp (const void *p1, const void *p2) +{ + const struct bgp_addr *addr1 = p1; + const struct bgp_addr *addr2 = p2; + + return addr1->addr.s_addr == addr2->addr.s_addr; +} + +void +bgp_address_init (void) +{ + bgp_address_hash = hash_create (bgp_address_hash_key_make, + bgp_address_hash_cmp); +} + +static void +bgp_address_add (struct prefix *p) +{ + struct bgp_addr tmp; + struct bgp_addr *addr; + + tmp.addr = p->u.prefix4; + + addr = hash_get (bgp_address_hash, &tmp, bgp_address_hash_alloc); + addr->refcnt++; +} + +static void +bgp_address_del (struct prefix *p) +{ + struct bgp_addr tmp; + struct bgp_addr *addr; + + tmp.addr = p->u.prefix4; + + addr = hash_lookup (bgp_address_hash, &tmp); + addr->refcnt--; + + if (addr->refcnt == 0) + { + hash_release (bgp_address_hash, addr); + XFREE (MTYPE_BGP_ADDR, addr); + } +} + struct bgp_connected_ref { @@ -557,6 +636,8 @@ bgp_connected_add (struct connected *ifc) if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; + bgp_address_add (addr); + rn = bgp_node_get (bgp_connected_table[AFI_IP], (struct prefix *) &p); if (rn->info) { @@ -622,6 +703,8 @@ bgp_connected_delete (struct connected *ifc) if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; + bgp_address_del (addr); + rn = bgp_node_lookup (bgp_connected_table[AFI_IP], &p); if (! rn) return; @@ -666,25 +749,16 @@ bgp_connected_delete (struct connected *ifc) } int -bgp_nexthop_self (afi_t afi, struct attr *attr) +bgp_nexthop_self (struct attr *attr) { - struct listnode *node; - struct listnode *node2; - struct interface *ifp; - struct connected *ifc; - struct prefix *p; + struct bgp_addr tmp, *addr; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) - { - for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) - { - p = ifc->address; + tmp.addr = attr->nexthop; + + addr = hash_lookup (bgp_address_hash, &tmp); + if (addr) + return 1; - if (p && p->family == AF_INET - && IPV4_ADDR_SAME (&p->u.prefix4, &attr->nexthop)) - return 1; - } - } return 0; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 874f3bba0..6e5350ead 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -55,6 +55,7 @@ extern void bgp_connected_delete (struct connected *c); extern int bgp_multiaccess_check_v4 (struct in_addr, char *); extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); -extern int bgp_nexthop_self (afi_t, struct attr *); +extern int bgp_nexthop_self (struct attr *); +extern void bgp_address_init (void); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 589c0738a..12cb693aa 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2147,9 +2147,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ - if (bgp_nexthop_self (afi, &new_attr) - || new_attr.nexthop.s_addr == 0 - || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr))) + if (new_attr.nexthop.s_addr == 0 + || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)) + || bgp_nexthop_self (&new_attr)) { reason = "martian next-hop;"; goto filtered; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ab27783fa..30fb091f4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5358,6 +5358,7 @@ bgp_init (void) bgp_dump_init (); bgp_route_init (); bgp_route_map_init (); + bgp_address_init (); bgp_scan_init (); bgp_mplsvpn_init (); diff --git a/lib/memtypes.c b/lib/memtypes.c index acbd16b96..1723490f6 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -150,6 +150,7 @@ struct memory_list memory_list_bgp[] = { MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" }, { MTYPE_BGP_REGEXP, "BGP regexp" }, { MTYPE_BGP_AGGREGATE, "BGP aggregate" }, + { MTYPE_BGP_ADDR, "BGP own address" }, { -1, NULL } }; From 14542f3edaa43113880e8bb69612c553f02bdf22 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:53 +0000 Subject: [PATCH 0063/1342] bgpd: debug buffers cleanup and optimization Just the first change pushes bgp_update_receive() from 6th to ~14th on a full internet table load profiling session. * bgp_debug.c: (bgp_update_receive) The attrstr initialization is expensive, moved under the debug conditional where it is used and just initialize the first char to NULL. (bgp_update_default_send) Initialize attrstr needed for bgp_dump_attr(). Moved some buffers used for printing IP[4|6] addresses under the debug conditionals that use them and reduced its size. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 72 +++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 390b55635..95ed8046e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -149,7 +149,6 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; unsigned long pos; - char buf[BUFSIZ]; s = peer->work; stream_reset (s); @@ -199,10 +198,14 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) stream_put_prefix (s, &rn->p); if (BGP_DEBUG (update, UPDATE_OUT)) - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d", - peer->host, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), - rn->p.prefixlen); + { + char buf[INET6_BUFSIZ]; + + zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d", + peer->host, + inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), + rn->p.prefixlen); + } /* Synchnorize attribute. */ if (adj->attr) @@ -285,7 +288,6 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) unsigned long pos; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; - char buf[BUFSIZ]; s = peer->work; stream_reset (s); @@ -324,10 +326,14 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) } if (BGP_DEBUG (update, UPDATE_OUT)) - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", - peer->host, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), - rn->p.prefixlen); + { + char buf[INET6_BUFSIZ]; + + zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", + peer->host, + inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), + rn->p.prefixlen); + } peer->scount[afi][safi]--; @@ -366,8 +372,6 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, struct prefix p; unsigned long pos; bgp_size_t total_attr_len; - char attrstr[BUFSIZ]; - char buf[BUFSIZ]; if (DISABLE_BGP_ANNOUNCE) return; @@ -382,9 +386,13 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_OUT)) { + char attrstr[BUFSIZ]; + char buf[INET6_BUFSIZ]; + attrstr[0] = '\0'; + bgp_dump_attr (peer, attr, attrstr, BUFSIZ); zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d %s", - peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), + peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), p.prefixlen, attrstr); } @@ -435,7 +443,6 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; - char buf[BUFSIZ]; if (DISABLE_BGP_ANNOUNCE) return; @@ -451,9 +458,13 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) pos = 0; if (BGP_DEBUG (update, UPDATE_OUT)) - zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", - peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), - p.prefixlen); + { + char buf[INET6_BUFSIZ]; + + zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", + peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), + p.prefixlen); + } s = stream_new (BGP_MAX_PACKET_SIZE); @@ -1515,7 +1526,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) struct bgp_nlri withdraw; struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; - char attrstr[BUFSIZ] = ""; /* Status must be Established. */ if (peer->status != Established) @@ -1632,6 +1642,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW || BGP_DEBUG (update, UPDATE_IN)) { + char attrstr[BUFSIZ]; + attrstr[0] = '\0'; + ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) ? LOG_ERR : LOG_DEBUG; @@ -2027,7 +2040,6 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) u_int32_t seq; int psize; char name[BUFSIZ]; - char buf[BUFSIZ]; int ret; if (BGP_DEBUG (normal, NORMAL)) @@ -2097,15 +2109,19 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) p_pnt += psize; if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s", - peer->host, - (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), - (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), - orfp.seq, - inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ), - orfp.p.prefixlen, orfp.ge, orfp.le, - ok ? "" : " MALFORMED"); - + { + char buf[INET6_BUFSIZ]; + + zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s", + peer->host, + (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), + (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), + orfp.seq, + inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, INET6_BUFSIZ), + orfp.p.prefixlen, orfp.ge, orfp.le, + ok ? "" : " MALFORMED"); + } + if (ok) ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), From 6d85b15bbb2fd3c263d5d4b402c88ff348af877b Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:54 +0000 Subject: [PATCH 0064/1342] bgpd: remove calls to peer_sort() from fast-path peer_sort() it's called so much as to be annoying. In the assumption that the 'sort' of the peer doesn't change during an established session, I have changed all calls to peer_sort() in the 'fast-path' to only check the 'sort'. All the calls from the vty and such still recalculate the sort and store it in the peer. There's a lot of other calls to peer_sort() that could be changed but some maube tricky, someone more knowledgeable may try to reduce them. This hits peer_sort() from 5th out of the stadium^H^H list on a full internet table loading profiling session. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 30 ++++++++++---------- bgpd/bgp_mpath.c | 2 +- bgpd/bgp_network.c | 4 +-- bgpd/bgp_nexthop.c | 2 +- bgpd/bgp_route.c | 70 +++++++++++++++++++++++----------------------- bgpd/bgp_vty.c | 4 +-- bgpd/bgp_zebra.c | 8 +++--- bgpd/bgpd.c | 56 +++++++++++++++++++++---------------- bgpd/bgpd.h | 24 ++++++++-------- 9 files changed, 104 insertions(+), 96 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 81802ce81..8144cd36d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -722,7 +722,7 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, u_char *notify_datap = (length > 0 ? args->startp : NULL); /* Only relax error handling for eBGP peers */ - if (peer_sort (peer) != BGP_PEER_EBGP) + if (peer->sort != BGP_PEER_EBGP) { bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); @@ -996,11 +996,9 @@ bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr) struct bgp *bgp = peer->bgp; struct aspath *aspath; - bgp = peer->bgp; - /* Confederation sanity check. */ - if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || - (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) + if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || + (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, @@ -1011,7 +1009,7 @@ bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr) /* First AS check for EBGP. */ if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) { - if (peer_sort (peer) == BGP_PEER_EBGP + if (peer->sort == BGP_PEER_EBGP && ! aspath_firstas_check (attr->aspath, peer->as)) { zlog (peer->log, LOG_ERR, @@ -1155,7 +1153,7 @@ bgp_attr_local_pref (struct bgp_attr_parser_args *args) /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the receiving speaker. */ - if (peer_sort (peer) == BGP_PEER_EBGP) + if (peer->sort == BGP_PEER_EBGP) { stream_forward_getp (peer->ibuf, length); return BGP_ATTR_PARSE_PROCEED; @@ -2020,7 +2018,7 @@ bgp_attr_check (struct peer *peer, struct attr *attr) if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) type = BGP_ATTR_NEXT_HOP; - if (peer_sort (peer) == BGP_PEER_IBGP + if (peer->sort == BGP_PEER_IBGP && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) type = BGP_ATTR_LOCAL_PREF; @@ -2069,7 +2067,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, /* AS path attribute. */ /* If remote-peer is EBGP */ - if (peer_sort (peer) == BGP_PEER_EBGP + if (peer->sort == BGP_PEER_EBGP && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || attr->aspath->segments == NULL) && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) @@ -2090,7 +2088,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, aspath = aspath_add_seq (aspath, peer->change_local_as); } } - else if (peer_sort (peer) == BGP_PEER_CONFED) + else if (peer->sort == BGP_PEER_CONFED) { /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ aspath = aspath_dup (attr->aspath); @@ -2147,8 +2145,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Local preference. */ - if (peer_sort (peer) == BGP_PEER_IBGP || - peer_sort (peer) == BGP_PEER_CONFED) + if (peer->sort == BGP_PEER_IBGP || + peer->sort == BGP_PEER_CONFED) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LOCAL_PREF); @@ -2221,9 +2219,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Route Reflector. */ - if (peer_sort (peer) == BGP_PEER_IBGP + if (peer->sort == BGP_PEER_IBGP && from - && peer_sort (from) == BGP_PEER_IBGP) + && from->sort == BGP_PEER_IBGP) { /* Originator ID. */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); @@ -2359,8 +2357,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, assert (attre); - if (peer_sort (peer) == BGP_PEER_IBGP - || peer_sort (peer) == BGP_PEER_CONFED) + if (peer->sort == BGP_PEER_IBGP + || peer->sort == BGP_PEER_CONFED) { if (attre->ecommunity->size * 8 > 255) { diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index aa657d832..7999d16b6 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -420,7 +420,7 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, mpath_count++; if (new_best != old_best) bgp_info_mpath_dequeue (new_best); - maxpaths = (peer_sort (new_best->peer) == BGP_PEER_IBGP) ? + maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp; } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 73234fe26..79d5d27d0 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -174,7 +174,7 @@ bgp_accept (struct thread *thread) } /* In case of peer is EBGP, we should set TTL for this connection. */ - if (peer_sort (peer1) == BGP_PEER_EBGP) { + if (peer1->sort == BGP_PEER_EBGP) { sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); if (peer1->gtsm_hops) sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops); @@ -307,7 +307,7 @@ bgp_connect (struct peer *peer) return -1; /* If we can get socket for the peer, adjest TTL and make connection. */ - if (peer_sort (peer) == BGP_PEER_EBGP) { + if (peer->sort == BGP_PEER_EBGP) { sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); if (peer->gtsm_hops) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 723057b68..0e56d3686 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -453,7 +453,7 @@ bgp_scan (afi_t afi, safi_t safi) changed = 0; metricchanged = 0; - if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) + if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1) valid = bgp_nexthop_onlink (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 12cb693aa..f80bcfa97 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -447,17 +447,17 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } /* 7. Peer type check. */ - if (peer_sort (new->peer) == BGP_PEER_EBGP - && peer_sort (exist->peer) == BGP_PEER_IBGP) + if (new->peer->sort == BGP_PEER_EBGP + && exist->peer->sort == BGP_PEER_IBGP) return 1; - if (peer_sort (new->peer) == BGP_PEER_EBGP - && peer_sort (exist->peer) == BGP_PEER_CONFED) + if (new->peer->sort == BGP_PEER_EBGP + && exist->peer->sort == BGP_PEER_CONFED) return 1; - if (peer_sort (new->peer) == BGP_PEER_IBGP - && peer_sort (exist->peer) == BGP_PEER_EBGP) + if (new->peer->sort == BGP_PEER_IBGP + && exist->peer->sort == BGP_PEER_EBGP) return 0; - if (peer_sort (new->peer) == BGP_PEER_CONFED - && peer_sort (exist->peer) == BGP_PEER_EBGP) + if (new->peer->sort == BGP_PEER_CONFED + && exist->peer->sort == BGP_PEER_EBGP) return 0; /* 8. IGP metric check. */ @@ -471,7 +471,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, /* 9. Maximum path check. */ if (newm == existm) { - if ((peer_sort (new->peer) == BGP_PEER_IBGP)) + if (new->peer->sort == BGP_PEER_IBGP) { if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) *paths_eq = 1; @@ -493,8 +493,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, newer path won't displace an older one, even if it was the preferred route based on the additional decision criteria below. */ if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID) - && peer_sort (new->peer) == BGP_PEER_EBGP - && peer_sort (exist->peer) == BGP_PEER_EBGP) + && new->peer->sort == BGP_PEER_EBGP + && exist->peer->sort == BGP_PEER_EBGP) { if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) return 1; @@ -632,13 +632,13 @@ bgp_community_filter (struct peer *peer, struct attr *attr) return 1; /* NO_EXPORT check. */ - if (peer_sort (peer) == BGP_PEER_EBGP && + if (peer->sort == BGP_PEER_EBGP && community_include (attr->community, COMMUNITY_NO_EXPORT)) return 1; /* NO_EXPORT_SUBCONFED check. */ - if (peer_sort (peer) == BGP_PEER_EBGP - || peer_sort (peer) == BGP_PEER_CONFED) + if (peer->sort == BGP_PEER_EBGP + || peer->sort == BGP_PEER_CONFED) if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED)) return 1; } @@ -905,7 +905,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } /* Route-Reflect check. */ - if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP) + if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) reflect = 1; else reflect = 0; @@ -937,8 +937,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, bgp_attr_dup (attr, riattr); /* If local-preference is not set. */ - if ((peer_sort (peer) == BGP_PEER_IBGP - || peer_sort (peer) == BGP_PEER_CONFED) + if ((peer->sort == BGP_PEER_IBGP + || peer->sort == BGP_PEER_CONFED) && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))) { attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); @@ -946,7 +946,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ - if (peer_sort (peer) == BGP_PEER_EBGP + if (peer->sort == BGP_PEER_EBGP && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) { if (ri->peer != bgp->peer_self && ! transparent @@ -972,7 +972,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ - || (peer_sort (peer) == BGP_PEER_EBGP + || (peer->sort == BGP_PEER_EBGP && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) { /* Set IPv4 nexthop. */ @@ -1038,7 +1038,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, #endif /* HAVE_IPV6 */ /* If this is EBGP peer and remove-private-AS is set. */ - if (peer_sort (peer) == BGP_PEER_EBGP + if (peer->sort == BGP_PEER_EBGP && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && aspath_private_as_check (attr->aspath)) attr->aspath = aspath_empty_get (); @@ -1055,8 +1055,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, /* The route reflector is not allowed to modify the attributes of the reflected IBGP routes. */ - if (peer_sort (from) == BGP_PEER_IBGP - && peer_sort (peer) == BGP_PEER_IBGP) + if (from->sort == BGP_PEER_IBGP + && peer->sort == BGP_PEER_IBGP) { bgp_attr_dup (&dummy_attr, attr); info.attr = &dummy_attr; @@ -1253,7 +1253,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, /* If this is EBGP peer and remove-private-AS is set. */ - if (peer_sort (rsclient) == BGP_PEER_EBGP + if (rsclient->sort == BGP_PEER_EBGP && peer_af_flag_check (rsclient, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && aspath_private_as_check (attr->aspath)) attr->aspath = aspath_empty_get (); @@ -1809,7 +1809,7 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, * the bgp_info in the RIB for historical reference. */ if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer_sort (peer) == BGP_PEER_EBGP) + && peer->sort == BGP_PEER_EBGP) if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0)) == BGP_DAMP_SUPPRESSED) { @@ -2137,7 +2137,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, { /* If the peer is EBGP and nexthop is not on connected route, discard it. */ - if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1 + if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! bgp_nexthop_onlink (afi, &new_attr) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { @@ -2170,7 +2170,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer_sort (peer) == BGP_PEER_EBGP + && peer->sort == BGP_PEER_EBGP && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (BGP_DEBUG (update, UPDATE_IN)) @@ -2241,7 +2241,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer_sort (peer) == BGP_PEER_EBGP) + && peer->sort == BGP_PEER_EBGP) { /* This is implicit withdraw so we should update dampening information. */ @@ -2259,7 +2259,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer_sort (peer) == BGP_PEER_EBGP) + && peer->sort == BGP_PEER_EBGP) { /* Now we do normal update dampening. */ ret = bgp_damp_update (ri, rn, afi, safi); @@ -2274,9 +2274,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST - && (peer_sort (peer) == BGP_PEER_IBGP - || peer_sort (peer) == BGP_PEER_CONFED - || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + && (peer->sort == BGP_PEER_IBGP + || peer->sort == BGP_PEER_CONFED + || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) @@ -2321,9 +2321,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST - && (peer_sort (peer) == BGP_PEER_IBGP - || peer_sort (peer) == BGP_PEER_CONFED - || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + && (peer->sort == BGP_PEER_IBGP + || peer->sort == BGP_PEER_CONFED + || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) @@ -11794,7 +11794,7 @@ bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) } } - if (peer_sort (peer) == BGP_PEER_EBGP) + if (peer->sort == BGP_PEER_EBGP) { if (bgp->distance_ebgp) return bgp->distance_ebgp; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 03746bdd0..cb7ff1fa3 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4340,7 +4340,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; if (stype == BGP_CLEAR_SOFT_NONE) @@ -7781,7 +7781,7 @@ bgp_show_peer (struct vty *vty, struct peer *p) } /* EBGP Multihop and GTSM */ - if (peer_sort (p) != BGP_PEER_IBGP) + if (p->sort != BGP_PEER_IBGP) { if (p->gtsm_hops > 0) vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5c0dbb887..604438304 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -664,13 +664,13 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa flags = 0; peer = info->peer; - if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED) + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { SET_FLAG (flags, ZEBRA_FLAG_IBGP); SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); } - if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); @@ -828,13 +828,13 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) peer = info->peer; flags = 0; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) { SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); SET_FLAG (flags, ZEBRA_FLAG_IBGP); } - if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 30fb091f4..31ce5a164 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -201,7 +201,7 @@ bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) /* Clear all IBGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer_sort (peer) != BGP_PEER_IBGP) + if (peer->sort != BGP_PEER_IBGP) continue; if (peer->status == Established) @@ -229,7 +229,7 @@ bgp_cluster_id_unset (struct bgp *bgp) /* Clear all IBGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer_sort (peer) != BGP_PEER_IBGP) + if (peer->sort != BGP_PEER_IBGP) continue; if (peer->status == Established) @@ -645,9 +645,9 @@ peer_global_config_reset (struct peer *peer) peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; } -/* Check peer's AS number and determin is this peer IBGP or EBGP */ -int -peer_sort (struct peer *peer) +/* Check peer's AS number and determines if this peer is IBGP or EBGP */ +static bgp_peer_sort_t +peer_calc_sort (struct peer *peer) { struct bgp *bgp; @@ -696,6 +696,14 @@ peer_sort (struct peer *peer) } } +/* Calculate and cache the peer "sort" */ +bgp_peer_sort_t +peer_sort (struct peer *peer) +{ + peer->sort = peer_calc_sort (peer); + return peer->sort; +} + static void peer_free (struct peer *peer) { @@ -866,7 +874,7 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as, peer->readtime = peer->resettime = bgp_clock (); /* Default TTL set. */ - peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); + peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1; /* Make peer's address string. */ sockunion2str (su, buf, SU_ADDRSTRLEN); @@ -897,7 +905,7 @@ peer_create_accept (struct bgp *bgp) static void peer_as_change (struct peer *peer, as_t as) { - int type; + bgp_peer_sort_t type; /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) @@ -2666,7 +2674,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) struct listnode *node, *nnode; struct peer *peer1; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) return 0; /* see comment in peer_ttl_security_hops_set() */ @@ -2680,7 +2688,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { - if (peer_sort (peer1) == BGP_PEER_IBGP) + if (peer1->sort == BGP_PEER_IBGP) continue; if (peer1->gtsm_hops != 0) @@ -2698,7 +2706,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else @@ -2706,7 +2714,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = group->conf->ttl; @@ -2724,7 +2732,7 @@ peer_ebgp_multihop_unset (struct peer *peer) struct peer_group *group; struct listnode *node, *nnode; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) return 0; if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL) @@ -2737,7 +2745,7 @@ peer_ebgp_multihop_unset (struct peer *peer) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else @@ -2745,7 +2753,7 @@ peer_ebgp_multihop_unset (struct peer *peer) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = 1; @@ -3297,7 +3305,7 @@ peer_advertise_interval_unset (struct peer *peer) UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = 0; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; @@ -4372,7 +4380,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) return BGP_ERR_NO_IBGP_WITH_TTLHACK; /* We cannot configure ttl-security hops when ebgp-multihop is already @@ -4392,7 +4400,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { - if (peer_sort (peer1) == BGP_PEER_IBGP) + if (peer1->sort == BGP_PEER_IBGP) continue; if (peer1->ttl != 1) @@ -4414,7 +4422,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); } else @@ -4422,7 +4430,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; peer->gtsm_hops = group->conf->gtsm_hops; @@ -4459,7 +4467,7 @@ peer_ttl_security_hops_unset (struct peer *peer) zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) return 0; /* if a peer-group member, then reset to peer-group default rather than 0 */ @@ -4471,7 +4479,7 @@ peer_ttl_security_hops_unset (struct peer *peer) opeer = peer; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } else @@ -4479,7 +4487,7 @@ peer_ttl_security_hops_unset (struct peer *peer) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; peer->gtsm_hops = 0; @@ -4794,7 +4802,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); /* EBGP multihop. */ - if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1 && + if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 && !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) if (! peer_group_active (peer) || g_peer->ttl != peer->ttl) @@ -4802,7 +4810,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, VTY_NEWLINE); /* ttl-security hops */ - if (peer_sort (peer) != BGP_PEER_IBGP && peer->gtsm_hops != 0) + if (peer->sort != BGP_PEER_IBGP && peer->gtsm_hops != 0) if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, peer->gtsm_hops, VTY_NEWLINE); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d1e4f8e96..03a998b96 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -259,6 +259,16 @@ struct bgp_filter } usmap; }; +/* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, + a peer who's AS is part of our Confederation. */ +typedef enum +{ + BGP_PEER_IBGP = 1, + BGP_PEER_EBGP, + BGP_PEER_INTERNAL, + BGP_PEER_CONFED, +} bgp_peer_sort_t; + /* BGP neighbor structure. */ struct peer { @@ -282,6 +292,8 @@ struct peer /* Peer's local AS number. */ as_t local_as; + bgp_peer_sort_t sort; + /* Peer's Change local AS number. */ as_t change_local_as; @@ -749,16 +761,6 @@ struct bgp_nlri /* Check AS path loop when we send NLRI. */ /* #define BGP_SEND_ASPATH_CHECK */ -/* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, - a peer who's AS is part of our Confederation. */ -enum -{ - BGP_PEER_IBGP, - BGP_PEER_EBGP, - BGP_PEER_INTERNAL, - BGP_PEER_CONFED -}; - /* Flag for peer_clear_soft(). */ enum bgp_clear_type { @@ -833,7 +835,7 @@ extern struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_ad int *); extern struct peer *peer_lock (struct peer *); extern struct peer *peer_unlock (struct peer *); -extern int peer_sort (struct peer *peer); +extern bgp_peer_sort_t peer_sort (struct peer *peer); extern int peer_active (struct peer *); extern int peer_active_nego (struct peer *); extern struct peer *peer_create_accept (struct bgp *); From c76275ee960c708408646d8a680b201b27cb9c1a Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:55 +0000 Subject: [PATCH 0065/1342] bgpd: optimize loops on [e]community_hash_make() This change reduces loop count. Less jumps. * bgp_community.c: One loop per community. * bgp_ecommunity.c: One loop per ecommunity. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_community.c | 19 +++++++++++-------- bgpd/bgp_ecommunity.c | 21 ++++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 2ba45f6e4..fc1bef88b 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -394,16 +394,19 @@ community_str (struct community *com) unsigned int community_hash_make (struct community *com) { + unsigned char *pnt = (unsigned char *)com->val; + int size = com->size * 4; + unsigned int key = 0; int c; - unsigned int key; - unsigned char *pnt; - key = 0; - pnt = (unsigned char *)com->val; - - for(c = 0; c < com->size * 4; c++) - key += pnt[c]; - + for (c = 0; c < size; c += 4) + { + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + } + return key; } diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 9f4aaa4bf..5722425e1 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -233,15 +233,22 @@ unsigned int ecommunity_hash_make (void *arg) { const struct ecommunity *ecom = arg; + int size = ecom->size * ECOMMUNITY_SIZE; + u_int8_t *pnt = ecom->val; + unsigned int key = 0; int c; - unsigned int key; - u_int8_t *pnt; - key = 0; - pnt = ecom->val; - - for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++) - key += pnt[c]; + for (c = 0; c < size; c += ECOMMUNITY_SIZE) + { + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + key += pnt[c + 4]; + key += pnt[c + 5]; + key += pnt[c + 6]; + key += pnt[c + 7]; + } return key; } From 8ff56318a8bd188cfcc1cdab689c46c326b50d38 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:56 +0000 Subject: [PATCH 0066/1342] bgpd: optimize bgp_info_cmp() * bgp_route.c: (bgp_info_cmp) Reduce indirections, precalculate some values that are used several times, reduce conditionals. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 151 ++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f80bcfa97..cb15c152a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -322,20 +322,24 @@ static int bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, int *paths_eq) { + struct attr *newattr, *existattr; + struct attr_extra *newattre, *existattre; + bgp_peer_sort_t new_sort; + bgp_peer_sort_t exist_sort; u_int32_t new_pref; u_int32_t exist_pref; u_int32_t new_med; u_int32_t exist_med; - u_int32_t new_weight = 0; - u_int32_t exist_weight = 0; + u_int32_t new_weight; + u_int32_t exist_weight; + uint32_t newm, existm; struct in_addr new_id; struct in_addr exist_id; int new_cluster; int exist_cluster; - int internal_as_route = 0; - int confed_as_route = 0; + int internal_as_route; + int confed_as_route; int ret; - uint32_t newm, existm; *paths_eq = 0; @@ -345,60 +349,59 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, if (exist == NULL) return 1; + newattr = new->attr; + existattr = exist->attr; + newattre = newattr->extra; + existattre = existattr->extra; + /* 1. Weight check. */ - if (new->attr->extra) - new_weight = new->attr->extra->weight; - if (exist->attr->extra) - exist_weight = exist->attr->extra->weight; + new_weight = exist_weight = 0; + + if (newattre) + new_weight = newattre->weight; + if (existattre) + exist_weight = existattre->weight; + if (new_weight > exist_weight) return 1; if (new_weight < exist_weight) return 0; /* 2. Local preference check. */ - if (new->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) - new_pref = new->attr->local_pref; - else - new_pref = bgp->default_local_pref; + new_pref = exist_pref = bgp->default_local_pref; + + if (newattr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + new_pref = newattr->local_pref; + if (existattr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + exist_pref = existattr->local_pref; - if (exist->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) - exist_pref = exist->attr->local_pref; - else - exist_pref = bgp->default_local_pref; - if (new_pref > exist_pref) return 1; if (new_pref < exist_pref) return 0; - /* 3. Local route check. */ - if (new->sub_type == BGP_ROUTE_STATIC) - return 1; - if (exist->sub_type == BGP_ROUTE_STATIC) - return 0; - - if (new->sub_type == BGP_ROUTE_REDISTRIBUTE) - return 1; - if (exist->sub_type == BGP_ROUTE_REDISTRIBUTE) - return 0; - - if (new->sub_type == BGP_ROUTE_AGGREGATE) - return 1; - if (exist->sub_type == BGP_ROUTE_AGGREGATE) - return 0; + /* 3. Local route check. We prefer: + * - BGP_ROUTE_STATIC + * - BGP_ROUTE_AGGREGATE + * - BGP_ROUTE_REDISTRIBUTE + */ + if (! (new->sub_type == BGP_ROUTE_NORMAL)) + return 1; + if (! (exist->sub_type == BGP_ROUTE_NORMAL)) + return 0; /* 4. AS path length check. */ if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) { - int exist_hops = aspath_count_hops (exist->attr->aspath); - int exist_confeds = aspath_count_confeds (exist->attr->aspath); + int exist_hops = aspath_count_hops (existattr->aspath); + int exist_confeds = aspath_count_confeds (existattr->aspath); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED)) { int aspath_hops; - aspath_hops = aspath_count_hops (new->attr->aspath); - aspath_hops += aspath_count_confeds (new->attr->aspath); + aspath_hops = aspath_count_hops (newattr->aspath); + aspath_hops += aspath_count_confeds (newattr->aspath); if ( aspath_hops < (exist_hops + exist_confeds)) return 1; @@ -407,7 +410,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } else { - int newhops = aspath_count_hops (new->attr->aspath); + int newhops = aspath_count_hops (newattr->aspath); if (newhops < exist_hops) return 1; @@ -417,24 +420,24 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } /* 5. Origin check. */ - if (new->attr->origin < exist->attr->origin) + if (newattr->origin < existattr->origin) return 1; - if (new->attr->origin > exist->attr->origin) + if (newattr->origin > existattr->origin) return 0; /* 6. MED check. */ - internal_as_route = (aspath_count_hops (new->attr->aspath) == 0 - && aspath_count_hops (exist->attr->aspath) == 0); - confed_as_route = (aspath_count_confeds (new->attr->aspath) > 0 - && aspath_count_confeds (exist->attr->aspath) > 0 - && aspath_count_hops (new->attr->aspath) == 0 - && aspath_count_hops (exist->attr->aspath) == 0); + internal_as_route = (aspath_count_hops (newattr->aspath) == 0 + && aspath_count_hops (existattr->aspath) == 0); + confed_as_route = (aspath_count_confeds (newattr->aspath) > 0 + && aspath_count_confeds (existattr->aspath) > 0 + && aspath_count_hops (newattr->aspath) == 0 + && aspath_count_hops (existattr->aspath) == 0); if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED) || (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) && confed_as_route) - || aspath_cmp_left (new->attr->aspath, exist->attr->aspath) - || aspath_cmp_left_confed (new->attr->aspath, exist->attr->aspath) + || aspath_cmp_left (newattr->aspath, existattr->aspath) + || aspath_cmp_left_confed (newattr->aspath, existattr->aspath) || internal_as_route) { new_med = bgp_med_value (new->attr, bgp); @@ -447,22 +450,24 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } /* 7. Peer type check. */ - if (new->peer->sort == BGP_PEER_EBGP - && exist->peer->sort == BGP_PEER_IBGP) - return 1; - if (new->peer->sort == BGP_PEER_EBGP - && exist->peer->sort == BGP_PEER_CONFED) + new_sort = new->peer->sort; + exist_sort = exist->peer->sort; + + if (new_sort == BGP_PEER_EBGP + && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) return 1; - if (new->peer->sort == BGP_PEER_IBGP - && exist->peer->sort == BGP_PEER_EBGP) - return 0; - if (new->peer->sort == BGP_PEER_CONFED - && exist->peer->sort == BGP_PEER_EBGP) + if (exist_sort == BGP_PEER_EBGP + && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) return 0; /* 8. IGP metric check. */ - newm = (new->extra ? new->extra->igpmetric : 0); - existm = (exist->extra ? exist->extra->igpmetric : 0); + newm = existm = 0; + + if (new->extra) + newm = new->extra->igpmetric; + if (exist->extra) + existm = exist->extra->igpmetric; + if (newm < existm) ret = 1; if (newm > existm) @@ -493,8 +498,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, newer path won't displace an older one, even if it was the preferred route based on the additional decision criteria below. */ if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID) - && new->peer->sort == BGP_PEER_EBGP - && exist->peer->sort == BGP_PEER_EBGP) + && new_sort == BGP_PEER_EBGP + && exist_sort == BGP_PEER_EBGP) { if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) return 1; @@ -503,12 +508,12 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } /* 11. Rourter-ID comparision. */ - if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - new_id.s_addr = new->attr->extra->originator_id.s_addr; + if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + new_id.s_addr = newattre->originator_id.s_addr; else new_id.s_addr = new->peer->remote_id.s_addr; - if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - exist_id.s_addr = exist->attr->extra->originator_id.s_addr; + if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + exist_id.s_addr = existattre->originator_id.s_addr; else exist_id.s_addr = exist->peer->remote_id.s_addr; @@ -518,14 +523,12 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, return 0; /* 12. Cluster length comparision. */ - if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) - new_cluster = new->attr->extra->cluster->length; - else - new_cluster = 0; - if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) - exist_cluster = exist->attr->extra->cluster->length; - else - exist_cluster = 0; + new_cluster = exist_cluster = 0; + + if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) + new_cluster = newattre->cluster->length; + if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) + exist_cluster = existattre->cluster->length; if (new_cluster < exist_cluster) return 1; From e16a413313cf985ae2b8d2f1a9e8fd0ab6f5b9fc Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:57 +0000 Subject: [PATCH 0067/1342] bgpd: remove some useless initializations * bgp_attr.c: (bgp_attr_default_intern) bgp_attr_default_set() already initializes the memory. Fixes a struct attr_extra leak. * bgp_route.c: Remove useless on stack struct initializations. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 5 +---- bgpd/bgp_route.c | 10 +++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 8144cd36d..7c0f6cc6d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -559,10 +559,7 @@ bgp_attr_default_intern (u_char origin) { struct attr attr; struct attr *new; - - memset (&attr, 0, sizeof (struct attr)); - bgp_attr_extra_get (&attr); - + bgp_attr_default_set(&attr, origin); new = bgp_attr_intern (&attr); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cb15c152a..68eae6a03 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2465,7 +2465,7 @@ void bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) { struct bgp *bgp; - struct attr attr = { 0 }; + struct attr attr; struct aspath *aspath = { 0 }; struct prefix p; struct bgp_info binfo; @@ -3270,8 +3270,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, struct bgp_info *new; struct bgp_info info; struct attr *attr_new; - struct attr attr = {0 }; - struct attr new_attr = { .extra = 0 }; + struct attr attr; + struct attr new_attr = { 0 }; struct bgp *bgp; int ret; char buf[SU_ADDRSTRLEN]; @@ -3423,7 +3423,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, struct bgp_info *ri; struct bgp_info *new; struct bgp_info info; - struct attr attr = { 0 }; + struct attr attr; struct attr *attr_new; int ret; @@ -5352,7 +5352,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, struct bgp_info *bi; struct bgp_info info; struct bgp_node *bn; - struct attr attr = { 0 }; + struct attr attr; struct attr attr_new = { 0 }; struct attr *new_attr; afi_t afi; From 7fb0cd82c26492004a106bec7ca4afdf4684fabb Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:58 +0000 Subject: [PATCH 0068/1342] bgpd: reduce attrhash_make_key() indirections Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7c0f6cc6d..96429090a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -342,7 +342,8 @@ attr_unknown_count (void) unsigned int attrhash_key_make (void *p) { - const struct attr * attr = (struct attr *) p; + const struct attr *attr = (struct attr *) p; + const struct attr_extra *extra = attr->extra; uint32_t key = 0; #define MIX(val) key = jhash_1word(val, key) @@ -356,12 +357,12 @@ attrhash_key_make (void *p) key += attr->med; key += attr->local_pref; - if (attr->extra) + if (extra) { - MIX(attr->extra->aggregator_as); - MIX(attr->extra->aggregator_addr.s_addr); - MIX(attr->extra->weight); - MIX(attr->extra->mp_nexthop_global_in.s_addr); + MIX(extra->aggregator_as); + MIX(extra->aggregator_addr.s_addr); + MIX(extra->weight); + MIX(extra->mp_nexthop_global_in.s_addr); } if (attr->aspath) @@ -369,19 +370,19 @@ attrhash_key_make (void *p) if (attr->community) MIX(community_hash_make (attr->community)); - if (attr->extra) + if (extra) { - if (attr->extra->ecommunity) - MIX(ecommunity_hash_make (attr->extra->ecommunity)); - if (attr->extra->cluster) - MIX(cluster_hash_key_make (attr->extra->cluster)); - if (attr->extra->transit) - MIX(transit_hash_key_make (attr->extra->transit)); + if (extra->ecommunity) + MIX(ecommunity_hash_make (extra->ecommunity)); + if (extra->cluster) + MIX(cluster_hash_key_make (extra->cluster)); + if (extra->transit) + MIX(transit_hash_key_make (extra->transit)); #ifdef HAVE_IPV6 - MIX(attr->extra->mp_nexthop_len); - key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key); - key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key); + MIX(extra->mp_nexthop_len); + key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); + key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); #endif /* HAVE_IPV6 */ } From 938ef3a22535292dd36c250e5329f97d977e51df Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:52:59 +0000 Subject: [PATCH 0069/1342] bgpd: use on stack struct attr_extra on bgp_attr_aggregate_intern() Reduce memory heap fragmentation and pressure on the memory allocator. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 96429090a..bb21fe19d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -577,11 +577,12 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, { struct attr attr; struct attr *new; - struct attr_extra *attre; + struct attr_extra attre; memset (&attr, 0, sizeof (struct attr)); - attre = bgp_attr_extra_get (&attr); - + memset (&attre, 0, sizeof (struct attr_extra)); + attr.extra = &attre; + /* Origin attribute. */ attr.origin = origin; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); @@ -602,22 +603,21 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } - attre->weight = BGP_ATTR_DEFAULT_WEIGHT; + attre.weight = BGP_ATTR_DEFAULT_WEIGHT; #ifdef HAVE_IPV6 - attre->mp_nexthop_len = IPV6_MAX_BYTELEN; + attre.mp_nexthop_len = IPV6_MAX_BYTELEN; #endif if (! as_set) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) - attre->aggregator_as = bgp->confed_id; + attre.aggregator_as = bgp->confed_id; else - attre->aggregator_as = bgp->as; - attre->aggregator_addr = bgp->router_id; + attre.aggregator_as = bgp->as; + attre.aggregator_addr = bgp->router_id; new = bgp_attr_intern (&attr); - bgp_attr_extra_free (&attr); - + aspath_unintern (&new->aspath); return new; } From 1a2fd7078f943e2207ee0f1b0dafdcd2d9c81925 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:00 +0000 Subject: [PATCH 0070/1342] bgpd: cleanup bgp_attr_unintern() Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index bb21fe19d..974978210 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -652,30 +652,31 @@ bgp_attr_unintern_sub (struct attr *attr) /* Free bgp attribute and aspath. */ void -bgp_attr_unintern (struct attr **attr) +bgp_attr_unintern (struct attr **pattr) { + struct attr *attr = *pattr; struct attr *ret; struct attr tmp; /* Decrement attribute reference. */ - (*attr)->refcnt--; + attr->refcnt--; - tmp = *(*attr); + tmp = *attr; - if ((*attr)->extra) + if (attr->extra) { tmp.extra = bgp_attr_extra_new (); - memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra)); + memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra)); } /* If reference becomes zero then free attribute object. */ - if ((*attr)->refcnt == 0) - { - ret = hash_release (attrhash, *attr); + if (attr->refcnt == 0) + { + ret = hash_release (attrhash, attr); assert (ret != NULL); - bgp_attr_extra_free (*attr); - XFREE (MTYPE_ATTR, *attr); - *attr = NULL; + bgp_attr_extra_free (attr); + XFREE (MTYPE_ATTR, attr); + *pattr = NULL; } bgp_attr_unintern_sub (&tmp); From b9f1dca10f9a9bf853a9999a117c8cdeec5b7b69 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:01 +0000 Subject: [PATCH 0071/1342] bgpd: use on stack struct attr_extra in bgp_attr_unintern() Reduce memory heap fragmentation and pressure on the memory allocator. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 974978210..b63ac4c80 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -657,6 +657,7 @@ bgp_attr_unintern (struct attr **pattr) struct attr *attr = *pattr; struct attr *ret; struct attr tmp; + struct attr_extra tmp_extra; /* Decrement attribute reference. */ attr->refcnt--; @@ -665,7 +666,7 @@ bgp_attr_unintern (struct attr **pattr) if (attr->extra) { - tmp.extra = bgp_attr_extra_new (); + tmp.extra = &tmp_extra; memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra)); } @@ -680,7 +681,6 @@ bgp_attr_unintern (struct attr **pattr) } bgp_attr_unintern_sub (&tmp); - bgp_attr_extra_free (&tmp); } void From 6182d65b23fc0362b173e2a9314fa4551523a1c2 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:02 +0000 Subject: [PATCH 0072/1342] bgpd: fix struct attr_extra leak in bgp_default_originate() The call to bgp_attr_default_set() above creates the attr_extra struct, but the attr.extra = NULL initialization was leaking it. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 68eae6a03..a421fd7ce 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2488,12 +2488,8 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { - struct attr_extra *ae; - attr.extra = NULL; - - ae = bgp_attr_extra_get (&attr); - attr.extra = ae; - + struct attr_extra *ae = attr.extra; + str2prefix ("::/0", &p); /* IPv6 global nexthop must be included. */ From 489d005a9ad94675f40dc7bceff6176cfad36d45 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:03 +0000 Subject: [PATCH 0073/1342] bgpd: use on stack struct attr_extra in bgp_update_receive() Reduce memory heap fragmentation and pressure on the memory allocator. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 95ed8046e..cfa0b57cb 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1519,6 +1519,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) u_char *end; struct stream *s; struct attr attr; + struct attr_extra extra; bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; @@ -1538,10 +1539,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Set initial values. */ memset (&attr, 0, sizeof (struct attr)); + memset (&extra, 0, sizeof (struct attr_extra)); memset (&update, 0, sizeof (struct bgp_nlri)); memset (&withdraw, 0, sizeof (struct bgp_nlri)); memset (&mp_update, 0, sizeof (struct bgp_nlri)); memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); + attr.extra = &extra; s = peer->ibuf; end = stream_pnt (s) + size; @@ -1669,8 +1672,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (ret < 0) { bgp_attr_unintern_sub (&attr); - if (attr.extra) - bgp_attr_extra_free (&attr); return -1; } @@ -1697,8 +1698,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (ret < 0) { bgp_attr_unintern_sub (&attr); - if (attr.extra) - bgp_attr_extra_free (&attr); return -1; } @@ -1845,9 +1844,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&attr); - if (attr.extra) - bgp_attr_extra_free (&attr); - + /* If peering is stopped due to some reason, do not generate BGP event. */ if (peer->status != Established) From 558d1fec11749d3257e32561d45b5c1ec0622cf4 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:05 +0000 Subject: [PATCH 0074/1342] bgpd: reduce struct attr_extra allocations/freeing Try to use on stack structs for temporary uses. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 6 ++- bgpd/bgp_route.c | 101 ++++++++++++++++++++++------------------------- 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b63ac4c80..2d82acc22 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -319,10 +319,14 @@ bgp_attr_extra_get (struct attr *attr) void bgp_attr_dup (struct attr *new, struct attr *orig) { + struct attr_extra *extra = new->extra; + *new = *orig; if (orig->extra) { - new->extra = bgp_attr_extra_new(); + /* if caller provided attr_extra space use it */ + if (! extra) + new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; } } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a421fd7ce..c2045a8fb 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1051,8 +1051,11 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, || (ri->extra && ri->extra->suppress) ) { struct bgp_info info; - struct attr dummy_attr = { 0 }; - + struct attr dummy_attr; + struct attr_extra dummy_extra; + + dummy_attr.extra = &dummy_extra; + info.peer = peer; info.attr = attr; @@ -1073,10 +1076,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); peer->rmap_type = 0; - - if (dummy_attr.extra) - bgp_attr_extra_free (&dummy_attr); - + if (ret == RMAP_DENYMATCH) { bgp_attr_flush (attr); @@ -1212,9 +1212,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, if (p->family == AF_INET6) { struct attr_extra *attre = attr->extra; - - assert (attr->extra); - + /* Left nexthop_local unchanged if so configured. */ if ( CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) @@ -1429,7 +1427,8 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, struct bgp_node *rn, afi_t afi, safi_t safi) { struct prefix *p; - struct attr attr = { 0 }; + struct attr attr; + struct attr_extra extra; p = &rn->p; @@ -1446,6 +1445,9 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, PEER_STATUS_ORF_WAIT_REFRESH)) return 0; + /* It's initialized in bgp_announce_[check|check_rsclient]() */ + attr.extra = &extra; + switch (rn->table->type) { case BGP_TABLE_MAIN: @@ -1466,9 +1468,7 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, bgp_adj_out_unset (rn, peer, p, afi, safi); break; } - - bgp_attr_extra_free (&attr); - + return 0; } @@ -1830,7 +1830,8 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, { struct bgp_node *rn; struct bgp *bgp; - struct attr new_attr = { 0 }; + struct attr new_attr; + struct attr_extra new_extra; struct attr *attr_new; struct attr *attr_new2; struct bgp_info *ri; @@ -1865,6 +1866,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, goto filtered; } + new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); /* Apply export policy. */ @@ -1902,10 +1904,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, goto filtered; } } - - /* new_attr isn't passed to any functions after here */ - bgp_attr_extra_free (&new_attr); - + /* If the update is implicit withdraw. */ if (ri) { @@ -1993,9 +1992,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, /* Process change. */ bgp_process (bgp, rn, afi, safi); - - bgp_attr_extra_free (&new_attr); - + return; filtered: @@ -2012,10 +2009,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, bgp_rib_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); - - if (new_attr.extra) - bgp_attr_extra_free (&new_attr); - + return; } @@ -2060,7 +2054,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, int aspath_loop_count = 0; struct bgp_node *rn; struct bgp *bgp; - struct attr new_attr = { 0 }; + struct attr new_attr; + struct attr_extra new_extra; struct attr *attr_new; struct bgp_info *ri; struct bgp_info *new; @@ -2126,9 +2121,10 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, goto filtered; } - /* Apply incoming route-map. */ + new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); + /* Apply incoming route-map. */ if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "route-map;"; @@ -2207,8 +2203,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); - bgp_attr_extra_free (&new_attr); - + return 0; } @@ -2269,7 +2264,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, if (ret == BGP_DAMP_SUPPRESSED) { bgp_unlock_node (rn); - bgp_attr_extra_free (&new_attr); return 0; } } @@ -2295,8 +2289,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); - bgp_attr_extra_free (&new_attr); - + return 0; } @@ -2345,9 +2338,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* route_node_get lock */ bgp_unlock_node (rn); - - bgp_attr_extra_free (&new_attr); - + /* If maximum prefix count is configured and current prefix count exeed it. */ if (bgp_maximum_prefix_overflow (peer, afi, safi, 0)) @@ -2372,9 +2363,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_rib_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); - - bgp_attr_extra_free (&new_attr); - + return 0; } @@ -2550,8 +2539,9 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, { struct bgp_node *rn; struct bgp_info *ri; - struct attr attr = { 0 }; - + struct attr attr; + struct attr_extra extra; + if (! table) table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; @@ -2559,6 +2549,9 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) bgp_default_originate (peer, afi, safi, 0); + /* It's initialized in bgp_announce_[check|check_rsclient]() */ + attr.extra = &extra; + for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn)) for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) @@ -2569,8 +2562,6 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); else bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); - - bgp_attr_extra_free (&attr); } } @@ -3267,7 +3258,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, struct bgp_info info; struct attr *attr_new; struct attr attr; - struct attr new_attr = { 0 }; + struct attr new_attr; + struct attr_extra new_extra; struct bgp *bgp; int ret; char buf[SU_ADDRSTRLEN]; @@ -3319,7 +3311,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, } else attr_new = bgp_attr_intern (&attr); - + + new_attr.extra = &new_extra; bgp_attr_dup(&new_attr, attr_new); SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); @@ -3349,7 +3342,6 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, bgp_attr_unintern (&attr_new); attr_new = bgp_attr_intern (&new_attr); - bgp_attr_extra_free (&new_attr); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP @@ -5349,7 +5341,6 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, struct bgp_info info; struct bgp_node *bn; struct attr attr; - struct attr attr_new = { 0 }; struct attr *new_attr; afi_t afi; int ret; @@ -5377,7 +5368,11 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, if (bgp->redist[afi][type]) { + struct attr attr_new; + struct attr_extra extra_new; + /* Copy attribute for modification. */ + attr_new.extra = &extra_new; bgp_attr_dup (&attr_new, &attr); if (bgp->redist_metric_flag[afi][type]) @@ -5400,8 +5395,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, { /* Free uninterned attribute. */ bgp_attr_flush (&attr_new); - bgp_attr_extra_free (&attr_new); - + /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); @@ -5414,8 +5408,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, afi, SAFI_UNICAST, p, NULL); new_attr = bgp_attr_intern (&attr_new); - bgp_attr_extra_free (&attr_new); - + for (bi = bn->info; bi; bi = bi->next) if (bi->peer == bgp->peer_self && bi->sub_type == BGP_ROUTE_REDISTRIBUTE) @@ -6183,17 +6176,17 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router { struct route_map *rmap = output_arg; struct bgp_info binfo; - struct attr dummy_attr = { 0 }; + struct attr dummy_attr; + struct attr_extra dummy_extra; int ret; + dummy_attr.extra = &dummy_extra; bgp_attr_dup (&dummy_attr, ri->attr); + binfo.peer = ri->peer; binfo.attr = &dummy_attr; ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); - - bgp_attr_extra_free (&dummy_attr); - if (ret == RMAP_DENYMATCH) continue; } From 577ac57b78e0ee3cbc5afdb5f54a660bd0126136 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:06 +0000 Subject: [PATCH 0075/1342] bgpd: Remove useless initialization It's initialized below Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c2045a8fb..65a3ac174 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2455,7 +2455,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) { struct bgp *bgp; struct attr attr; - struct aspath *aspath = { 0 }; + struct aspath *aspath; struct prefix p; struct bgp_info binfo; struct peer *from; From 6a4677b723b6f79997ca15ee202c36d528d3dfcf Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:07 +0000 Subject: [PATCH 0076/1342] bgpd: optimize holdtime timer cancelling * bgp_packet.c: (bgp_update_receive) for every update received we queue an event just to cancel the holdtime timer, done in bgp_fsm_update(). Instead cancel the timer directly an avoid a scheduling pass. This incidently fixes another problem found on a slow box, where thousands of events threads were queued, and run, but never freed, because they are moved to the unused list that grows without bounds. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index cfa0b57cb..024f5e7be 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1854,8 +1854,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) peer->update_in++; peer->update_time = bgp_clock (); - /* Generate BGP event. */ - BGP_EVENT_ADD (peer, Receive_UPDATE_message); + /* Cancel holdtime timer */ + BGP_TIMER_OFF (peer->t_holdtime); return 0; } From 343aa82219c0cab0315e29267eb303127215caea Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:08 +0000 Subject: [PATCH 0077/1342] bgpd: optimize bgp_update_main() in the soft_reconfig case Avoids 3 checks per call. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 65a3ac174..ce0b57b91 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2067,8 +2067,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ - if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) - && peer != bgp->peer_self && ! soft_reconfig) + if (! soft_reconfig && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) + && peer != bgp->peer_self) bgp_adj_in_set (rn, peer, attr); /* Check previously received route. */ From f018db83a0746f9336d04e50dd06f3bbf6565f1c Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:10 +0000 Subject: [PATCH 0078/1342] bgpd: optimize bgp_aggregate_[increment|decrement]() If there were no aggregates configured this functions were allocating and freeing a struct bgp_node for every call, and it's called for every prefix received. * bgp_route.c: Bail out early if the there are no aggregates configured. Change from bgp_node_get() to bgp_node_lookup() that does not allocate a new struct bgp_node if not found. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ce0b57b91..cd8f3fea9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4660,18 +4660,27 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, struct bgp_node *child; struct bgp_node *rn; struct bgp_aggregate *aggregate; + struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ if (safi == SAFI_MPLS_VPN) return; + table = bgp->aggregate[afi][safi]; + + /* No aggregates configured. */ + if (table->top == NULL) + return; + if (p->prefixlen == 0) return; if (BGP_INFO_HOLDDOWN (ri)) return; - child = bgp_node_get (bgp->aggregate[afi][safi], p); + child = bgp_node_lookup (table, p); + if (! child) + return; /* Aggregate address configuration check. */ for (rn = child; rn; rn = rn->parent) @@ -4690,15 +4699,24 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, struct bgp_node *child; struct bgp_node *rn; struct bgp_aggregate *aggregate; + struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ if (safi == SAFI_MPLS_VPN) return; + table = bgp->aggregate[afi][safi]; + + /* No aggregates configured. */ + if (table->top == NULL) + return; + if (p->prefixlen == 0) return; - child = bgp_node_get (bgp->aggregate[afi][safi], p); + child = bgp_node_lookup (table, p); + if (! child) + return; /* Aggregate address configuration check. */ for (rn = child; rn; rn = rn->parent) From 47d3b6078a6c885e03d28bae3397b71a827473f5 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:11 +0000 Subject: [PATCH 0079/1342] micro-op bgp_node_[get|lookup]() and route_node_[get|lookup]() Reduce indirection for values that doesn't change in the loop. Signed-off-by: Jorge Boncompte [DTI2] [adjusted after dropping previous patch] Signed-off-by: David Lamparter --- bgpd/bgp_table.c | 18 +++++++++++------- lib/table.c | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index a249c23d9..3385a9342 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -289,16 +289,18 @@ struct bgp_node * bgp_node_lookup (const struct bgp_table *table, struct prefix *p) { struct bgp_node *node; + u_char prefixlen = p->prefixlen; + const u_char *prefix = &p->u.prefix; node = table->top; - while (node && node->p.prefixlen <= p->prefixlen && + while (node && node->p.prefixlen <= prefixlen && prefix_match (&node->p, p)) { - if (node->p.prefixlen == p->prefixlen && node->info) + if (node->p.prefixlen == prefixlen && node->info) return bgp_lock_node (node); - node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; + node = node->link[prefix_bit(prefix, node->p.prefixlen)]; } return NULL; @@ -311,19 +313,21 @@ bgp_node_get (struct bgp_table *const table, struct prefix *p) struct bgp_node *new; struct bgp_node *node; struct bgp_node *match; + u_char prefixlen = p->prefixlen; + const u_char *prefix = &p->u.prefix; match = NULL; node = table->top; - while (node && node->p.prefixlen <= p->prefixlen && + while (node && node->p.prefixlen <= prefixlen && prefix_match (&node->p, p)) { - if (node->p.prefixlen == p->prefixlen) + if (node->p.prefixlen == prefixlen) { bgp_lock_node (node); return node; } match = node; - node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; + node = node->link[prefix_bit(prefix, node->p.prefixlen)]; } if (node == NULL) @@ -347,7 +351,7 @@ bgp_node_get (struct bgp_table *const table, struct prefix *p) else table->top = new; - if (new->p.prefixlen != p->prefixlen) + if (new->p.prefixlen != prefixlen) { match = new; new = bgp_node_set (table, p); diff --git a/lib/table.c b/lib/table.c index e40e67072..fcb7ecc0b 100644 --- a/lib/table.c +++ b/lib/table.c @@ -258,16 +258,18 @@ struct route_node * route_node_lookup (struct route_table *table, struct prefix *p) { struct route_node *node; + u_char prefixlen = p->prefixlen; + const u_char *prefix = &p->u.prefix; node = table->top; - while (node && node->p.prefixlen <= p->prefixlen && + while (node && node->p.prefixlen <= prefixlen && prefix_match (&node->p, p)) { - if (node->p.prefixlen == p->prefixlen) + if (node->p.prefixlen == prefixlen) return node->info ? route_lock_node (node) : NULL; - node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; + node = node->link[prefix_bit(prefix, node->p.prefixlen)]; } return NULL; @@ -280,17 +282,19 @@ route_node_get (struct route_table *table, struct prefix *p) struct route_node *new; struct route_node *node; struct route_node *match; + u_char prefixlen = p->prefixlen; + const u_char *prefix = &p->u.prefix; match = NULL; node = table->top; - while (node && node->p.prefixlen <= p->prefixlen && + while (node && node->p.prefixlen <= prefixlen && prefix_match (&node->p, p)) { - if (node->p.prefixlen == p->prefixlen) + if (node->p.prefixlen == prefixlen) return route_lock_node (node); - + match = node; - node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; + node = node->link[prefix_bit(prefix, node->p.prefixlen)]; } if (node == NULL) From 41af338ecd56b9891d996f0fc850e02318b0c01a Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:12 +0000 Subject: [PATCH 0080/1342] lib: remove RUSAGE_T from struct thread * thread.c: It's only temporarily used in thread_call() to calculate the diffs. Saves 80 bytes per copy. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- lib/thread.c | 11 ++++++----- lib/thread.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index dd0413b34..784b29c67 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1146,7 +1146,7 @@ int thread_should_yield (struct thread *thread) { quagga_get_relative (NULL); - return (timeval_elapsed(relative_time, thread->ru.real) > + return (timeval_elapsed(relative_time, thread->real) > THREAD_YIELD_TIME_SLOT); } @@ -1175,7 +1175,7 @@ void thread_call (struct thread *thread) { unsigned long realtime, cputime; - RUSAGE_T ru; + RUSAGE_T before, after; /* Cache a pointer to the relevant cpu history thread, if the thread * does not have it yet. @@ -1194,13 +1194,14 @@ thread_call (struct thread *thread) (void * (*) (void *))cpu_record_hash_alloc); } - GETRUSAGE (&thread->ru); + GETRUSAGE (&before); + thread->real = before.real; (*thread->func) (thread); - GETRUSAGE (&ru); + GETRUSAGE (&after); - realtime = thread_consumed_time (&ru, &thread->ru, &cputime); + realtime = thread_consumed_time (&after, &before, &cputime); thread->hist->real.total += realtime; if (thread->hist->real.max < realtime) thread->hist->real.max = realtime; diff --git a/lib/thread.h b/lib/thread.h index dfc51e283..56f4d0731 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -77,7 +77,7 @@ struct thread int fd; /* file descriptor in case of read/write. */ struct timeval sands; /* rest of time sands value. */ } u; - RUSAGE_T ru; /* Indepth usage info. */ + struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ char* funcname; }; From 64018324d5e5071eea3b3f72f939d91dc7aef029 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:13 +0000 Subject: [PATCH 0081/1342] lib: micro-op for thread_get() thread_trim_head() already checks that the list is not empty. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- lib/thread.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 784b29c67..3740147e2 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -667,11 +667,10 @@ static struct thread * thread_get (struct thread_master *m, u_char type, int (*func) (struct thread *), void *arg, const char* funcname) { - struct thread *thread; + struct thread *thread = thread_trim_head (&m->unuse); - if (!thread_empty (&m->unuse)) + if (thread) { - thread = thread_trim_head (&m->unuse); if (thread->funcname) XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname); } From 22714f99c4ffeb4d1bade7ad6374adeba0e06e4c Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 16:53:14 +0000 Subject: [PATCH 0082/1342] lib: do not allocate/free thread funcnames This avoids memory heap fragmentation and imposses less load on the system memory allocator. * thread.h: FUNCNAME_LEN defined to 64 (ISO C99 says max 63) Signed-off-by: Jorge Boncompte [DTI2] [changed FUNCNAME_LEN to a less arbitrary value] Signed-off-by: David Lamparter --- lib/memtypes.c | 1 - lib/thread.c | 37 +++++++++++-------------------------- lib/thread.h | 7 +++++-- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index 1723490f6..bbf96929f 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -21,7 +21,6 @@ struct memory_list memory_list_lib[] = { MTYPE_THREAD, "Thread" }, { MTYPE_THREAD_MASTER, "Thread master" }, { MTYPE_THREAD_STATS, "Thread stats" }, - { MTYPE_THREAD_FUNCNAME, "Thread function name" }, { MTYPE_VTY, "VTY" }, { MTYPE_VTY_OUT_BUF, "VTY output buffer" }, { MTYPE_VTY_HIST, "VTY history" }, diff --git a/lib/thread.c b/lib/thread.c index 3740147e2..86d0ff8cb 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -235,7 +235,7 @@ cpu_record_hash_alloc (struct cpu_thread_history *a) struct cpu_thread_history *new; new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history)); new->func = a->func; - new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname); + strcpy(new->funcname, a->funcname); return new; } @@ -244,7 +244,6 @@ cpu_record_hash_free (void *a) { struct cpu_thread_history *hist = a; - XFREE (MTYPE_THREAD_FUNCNAME, hist->funcname); XFREE (MTYPE_THREAD_STATS, hist); } @@ -303,7 +302,7 @@ cpu_record_print(struct vty *vty, thread_type filter) void *args[3] = {&tmp, vty, &filter}; memset(&tmp, 0, sizeof tmp); - tmp.funcname = (char *)"TOTAL"; + strcpy(tmp.funcname, "TOTAL"); tmp.types = filter; #ifdef HAVE_RUSAGE @@ -577,8 +576,6 @@ thread_list_free (struct thread_master *m, struct thread_list *list) for (t = list->head; t; t = next) { next = t->next; - if (t->funcname) - XFREE (MTYPE_THREAD_FUNCNAME, t->funcname); XFREE (MTYPE_THREAD, t); list->count--; m->alloc--; @@ -636,11 +633,11 @@ thread_timer_remain_second (struct thread *thread) } /* Trim blankspace and "()"s */ -static char * -strip_funcname (const char *funcname) +void +strip_funcname (char *dest, const char *funcname) { - char buff[100]; - char tmp, *ret, *e, *b = buff; + char buff[FUNCNAME_LEN]; + char tmp, *e, *b = buff; strncpy(buff, funcname, sizeof(buff)); buff[ sizeof(buff) -1] = '\0'; @@ -656,10 +653,8 @@ strip_funcname (const char *funcname) tmp = *e; *e = '\0'; - ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b); + strcpy (dest, b); *e = tmp; - - return ret; } /* Get new thread. */ @@ -669,12 +664,7 @@ thread_get (struct thread_master *m, u_char type, { struct thread *thread = thread_trim_head (&m->unuse); - if (thread) - { - if (thread->funcname) - XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname); - } - else + if (! thread) { thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); m->alloc++; @@ -685,7 +675,7 @@ thread_get (struct thread_master *m, u_char type, thread->func = func; thread->arg = arg; - thread->funcname = strip_funcname(funcname); + strip_funcname (thread->funcname, funcname); return thread; } @@ -953,7 +943,6 @@ thread_run (struct thread_master *m, struct thread *thread, { *fetch = *thread; thread->type = THREAD_UNUSED; - thread->funcname = NULL; /* thread_call will free fetch's copied pointer */ thread_add_unuse (m, thread); return fetch; } @@ -1187,7 +1176,7 @@ thread_call (struct thread *thread) struct cpu_thread_history tmp; tmp.func = thread->func; - tmp.funcname = thread->funcname; + strcpy(tmp.funcname, thread->funcname); thread->hist = hash_get (cpu_record, &tmp, (void * (*) (void *))cpu_record_hash_alloc); @@ -1227,8 +1216,6 @@ thread_call (struct thread *thread) realtime/1000, cputime/1000); } #endif /* CONSUMED_TIME_CHECK */ - - XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname); } /* Execute thread */ @@ -1249,10 +1236,8 @@ funcname_thread_execute (struct thread_master *m, dummy.func = func; dummy.arg = arg; dummy.u.val = val; - dummy.funcname = strip_funcname (funcname); + strip_funcname (dummy.funcname, funcname); thread_call (&dummy); - XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname); - return NULL; } diff --git a/lib/thread.h b/lib/thread.h index 56f4d0731..67902cf6c 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -62,6 +62,9 @@ struct thread_master typedef unsigned char thread_type; +/* ISO C99 maximum function name length is 63 */ +#define FUNCNAME_LEN 64 + /* Thread itself. */ struct thread { @@ -79,13 +82,12 @@ struct thread } u; struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ - char* funcname; + char funcname[FUNCNAME_LEN]; }; struct cpu_thread_history { int (*func)(struct thread *); - char *funcname; unsigned int total_calls; struct time_stats { @@ -95,6 +97,7 @@ struct cpu_thread_history struct time_stats cpu; #endif thread_type types; + char funcname[FUNCNAME_LEN]; }; /* Clocks supported by Quagga */ From ad12dde6f9596997337ebc210dd2d4593438556b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 13 Jun 2012 22:50:07 +0100 Subject: [PATCH 0083/1342] Revert "bgpd: Make socket init separate, so unit tests work again." This reverts commit 7621f336e2f346edee43227f0b1ef93fe769720b. See bug #727 --- bgpd/bgp_main.c | 6 ------ bgpd/bgpd.c | 16 +++++++--------- bgpd/bgpd.h | 1 - 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 5abc87565..0f1d4829c 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -441,12 +441,6 @@ main (int argc, char **argv) if(dryrun) return(0); - if (bgp_socket_init ()) - { - zlog_err ("BGP socket creation failed"); - return 1; - } - /* Turn into daemon if daemon_mode is set. */ if (daemon_mode && daemon (0, 0) < 0) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 31ce5a164..bdc4e2896 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2063,6 +2063,13 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name) bgp_router_id_set(bgp, &router_id_zebra); *bgp_val = bgp; + /* Create BGP server socket, if first instance. */ + if (list_isempty(bm->bgp)) + { + if (bgp_socket (bm->port, bm->address) < 0) + return BGP_ERR_INVALID_VALUE; + } + listnode_add (bm->bgp, bgp); return 0; @@ -5342,15 +5349,6 @@ bgp_master_init (void) } -int -bgp_socket_init (void) -{ - /* Create BGP server socket */ - if (bgp_socket (bm->port, bm->address) < 0) - return BGP_ERR_INVALID_VALUE; - return 0; -} - void bgp_init (void) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 03a998b96..bb3071600 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -846,7 +846,6 @@ extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); extern void bgp_master_init (void); extern void bgp_init (void); -extern int bgp_socket_init (void); extern void bgp_route_map_init (void); extern int bgp_option_set (int); From 2fb2a455263c569119ca32be59b0337a3d8cd9b3 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 14 Jun 2012 10:37:40 +0100 Subject: [PATCH 0084/1342] lib: Add back sockunion_str2su * sockunion.h: Add back sockunion_str2su, its removal breaks things needlessly (e.g. our own unit tests). * sockunion.c: (sockunion_str2su) implement on top of str2sockunion. --- lib/sockunion.c | 12 ++++++++++++ lib/sockunion.h | 1 + 2 files changed, 13 insertions(+) diff --git a/lib/sockunion.c b/lib/sockunion.c index 37dc3f90b..5dcf72563 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -174,6 +174,18 @@ sockunion2str (union sockunion *su, char *buf, size_t len) return NULL; } +union sockunion * +sockunion_str2su (const char *str) +{ + union sockunion *su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); + + if (!str2sockunion (str, su)) + return su; + + XFREE (MTYPE_SOCKUNION, su); + return NULL; +} + /* Convert IPv4 compatible IPv6 address to IPv4 address. */ static void sockunion_normalise_mapped (union sockunion *su) diff --git a/lib/sockunion.h b/lib/sockunion.h index 1a0a3c95c..b9f351424 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -88,6 +88,7 @@ extern const char *sockunion2str (union sockunion *, char *, size_t); extern int sockunion_cmp (union sockunion *, union sockunion *); extern int sockunion_same (union sockunion *, union sockunion *); +extern union sockunion *sockunion_str2su (const char *str); extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); extern int sockopt_reuseaddr (int); From cccbc0151883cfb4f43d6fa0a4a3caedc27e6cf5 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 14 Jun 2012 10:40:26 +0100 Subject: [PATCH 0085/1342] bgpd: Add "no listen" socket option for the BGP master configuration * bgpd.h: add a BGP_OPT_NO_LISTEN option for the master BGP configuration, to prevent any listen socket being created automatically. Allows code to be used outside of BGP daemon settings. * bgpd.c: (bgp_get) honour above the flag, suppress auto-creation of listen socket on first BGP instance if set. (bgp_option_set) whitelist BGP_OPT_NO_LISTEN --- bgpd/bgpd.c | 4 +++- bgpd/bgpd.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index bdc4e2896..69c8c0a33 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -82,6 +82,7 @@ bgp_option_set (int flag) case BGP_OPT_NO_FIB: case BGP_OPT_MULTIPLE_INSTANCE: case BGP_OPT_CONFIG_CISCO: + case BGP_OPT_NO_LISTEN: SET_FLAG (bm->options, flag); break; default: @@ -2064,7 +2065,8 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name) *bgp_val = bgp; /* Create BGP server socket, if first instance. */ - if (list_isempty(bm->bgp)) + if (list_isempty(bm->bgp) + && !bgp_option_check (BGP_OPT_NO_LISTEN)) { if (bgp_socket (bm->port, bm->address) < 0) return BGP_ERR_INVALID_VALUE; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bb3071600..63e326af9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -59,6 +59,7 @@ struct bgp_master #define BGP_OPT_NO_FIB (1 << 0) #define BGP_OPT_MULTIPLE_INSTANCE (1 << 1) #define BGP_OPT_CONFIG_CISCO (1 << 2) +#define BGP_OPT_NO_LISTEN (1 << 3) }; /* BGP instance structure. */ From c9e4f8623642fc005c97830256000bef5680aa26 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 14 Jun 2012 10:42:39 +0100 Subject: [PATCH 0086/1342] tests: BGP unit tests to set BGP_OPT_NO_LISTEN so they can run BGP tests had been broken by auto-creation of listen socket. This allows them to run at least, though at least 1 test seems to have other breakage, aspath_test. --- tests/aspath_test.c | 1 + tests/bgp_capability_test.c | 1 + tests/bgp_mp_attr_test.c | 1 + tests/bgp_mpath_test.c | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 83eb9d808..9170455fb 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -1259,6 +1259,7 @@ main (void) int i = 0; bgp_master_init (); master = bm->master; + bgp_option_set (BGP_OPT_NO_LISTEN); bgp_attr_init (); while (test_segments[i].name) diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index 83da2e48f..65c6a7002 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -618,6 +618,7 @@ main (void) master = thread_master_create (); bgp_master_init (); + bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 1a48f4b74..f086740fd 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -515,6 +515,7 @@ main (void) master = thread_master_create (); bgp_master_init (); + bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index 15e450a20..3d0ecb78b 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -378,7 +378,8 @@ global_test_init (void) master = thread_master_create (); zclient = zclient_new (); bgp_master_init (); - + bgp_option_set (BGP_OPT_NO_LISTEN); + if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); return 0; From e2c38e6c9767e30d5683022653b1cf91b186f9d4 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Wed, 20 Jun 2012 17:45:50 +0200 Subject: [PATCH 0087/1342] bgpd: Fix for commit 6a4677b7, fixes BZ#729 The timers are rearmed after events processing. After 6a4677b7 we do not generate events that can rearm the holdtime timer. Fix it's to call bgp_timer_set() directly as it's done from bgp_event(). Signed-off-by: Jorge Boncompte [DTI2] Tested-by: Martin Winter Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 024f5e7be..2d62c8dac 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1854,8 +1854,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) peer->update_in++; peer->update_time = bgp_clock (); - /* Cancel holdtime timer */ + /* Rearm holdtime timer */ BGP_TIMER_OFF (peer->t_holdtime); + bgp_timer_set (peer); return 0; } From bb782fb50efcd972d4357f9a7164de2c317d2eef Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Wed, 20 Jun 2012 16:34:01 +0200 Subject: [PATCH 0088/1342] bgpd: Partially revert f018db8, fixes BZ#730 The change from bgp_node_get() to bgp_node_lookup() broke aggregation. Signed-off-by: Jorge Boncompte [DTI2] Tested-by: Martin Winter Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cd8f3fea9..0337224ad 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4678,9 +4678,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, if (BGP_INFO_HOLDDOWN (ri)) return; - child = bgp_node_lookup (table, p); - if (! child) - return; + child = bgp_node_get (table, p); /* Aggregate address configuration check. */ for (rn = child; rn; rn = rn->parent) @@ -4714,9 +4712,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, if (p->prefixlen == 0) return; - child = bgp_node_lookup (table, p); - if (! child) - return; + child = bgp_node_get (table, p); /* Aggregate address configuration check. */ for (rn = child; rn; rn = rn->parent) From a47c5838e9f445ab887ad927706b11ccbb181364 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 21 Jun 2012 09:55:38 +0200 Subject: [PATCH 0089/1342] isisd: fix typo in topology generator (BZ#731) There was a "lsp->" missing before "level" in line 2416. (introduced by git commit e38e0df) Reported-by: Seblu Signed-off-by: David Lamparter --- isisd/isis_lsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 5c1e9931d..082e9dcd1 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -2413,7 +2413,7 @@ top_lsp_refresh (struct thread *thread) isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, IS_LEVEL_1); - lsp->lsp_header->lsp_bits = lsp_bits_generate (level, + lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level, lsp->area->overload_bit); rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); From 9e7a548ce421660b0d22bfeb90c2b2b53742aac7 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 22 May 2012 14:32:22 +0200 Subject: [PATCH 0090/1342] build: allow configure and build in a separate directory Some .h files in lib/ are autogenerated. The search path should include the build directory and the source directory. They usually match but sometimes, they may be different. For example: $ mkdir build $ cd build $ ../configure $ make --- babeld/Makefile.am | 2 +- bgpd/Makefile.am | 2 +- guile/Makefile.am | 2 +- isisd/Makefile.am | 2 +- isisd/topology/Makefile.am | 2 +- lib/Makefile.am | 2 +- ospf6d/Makefile.am | 2 +- ospfclient/Makefile.am | 2 +- ospfd/Makefile.am | 2 +- ripd/Makefile.am | 2 +- ripngd/Makefile.am | 2 +- tests/Makefile.am | 2 +- vtysh/Makefile.am | 2 +- vtysh/extract.pl.in | 2 +- watchquagga/Makefile.am | 2 +- zebra/Makefile.am | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/babeld/Makefile.am b/babeld/Makefile.am index 8703de062..81f661261 100644 --- a/babeld/Makefile.am +++ b/babeld/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 3051555b9..e5ee893a1 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/guile/Makefile.am b/guile/Makefile.am index 5beb71c41..8d7008e99 100644 --- a/guile/Makefile.am +++ b/guile/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with Automake to create Makefile.in -INCLUDES = @GUILE_CFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INCLUDES = @GUILE_CFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -I. -I$(srcdir) AM_CFLAGS = $(PICFLAGS) diff --git a/isisd/Makefile.am b/isisd/Makefile.am index 26b8ee7c1..4e9b2441e 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib \ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/isisd/topology/Makefile.am b/isisd/topology/Makefile.am index b25497cb3..ccd2e7174 100644 --- a/isisd/topology/Makefile.am +++ b/isisd/topology/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) diff --git a/lib/Makefile.am b/lib/Makefile.am index 890cc5ca9..4c67858cc 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index 01bc6fe06..d05b02075 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index b8aae84bb..607bbed6f 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -1,6 +1,6 @@ ## Automake.am for OSPF API client -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version 0:0:0 diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 2e4d5c8e1..d0b4ae84a 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ripd/Makefile.am b/ripd/Makefile.am index 2fa26659e..3196090c0 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index c6bd4868d..83ddca0a4 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/tests/Makefile.am b/tests/Makefile.am index 2e98ff793..0c262a4ab 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 0fd2f1487..7550173c5 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with Automake to create Makefile.in -INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib +INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" LIBS = @LIBS@ @CURSES@ @LIBPAM@ diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 61b2d2a21..99224f80f 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -63,7 +63,7 @@ $ignore{'"show history"'} = "ignore"; foreach (@ARGV) { $file = $_; - open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |"); + open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |"); local $/; undef $/; $line = ; close (FH); diff --git a/watchquagga/Makefile.am b/watchquagga/Makefile.am index a49f62e8f..badaa5b5d 100644 --- a/watchquagga/Makefile.am +++ b/watchquagga/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with Automake to create Makefile.in -INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib +INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" AM_CFLAGS = $(PICFLAGS) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 542f36f4b..e5b749a61 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 From 6b1e37f8537fa2a4560de32e83ca5089763e2d39 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 22 May 2012 22:15:20 +0200 Subject: [PATCH 0091/1342] build: only define HAVE_SNMP NetSNMP is the only SNMP implementation for Quagga. We don't need two different symbols. --- bgpd/bgp_snmp.c | 6 ------ configure.ac | 3 +-- lib/smux.c | 6 ------ ospf6d/ospf6_snmp.c | 6 ------ ospfd/ospf_snmp.c | 6 ------ ripd/rip_snmp.c | 6 ------ zebra/zebra_snmp.c | 6 ------ 7 files changed, 1 insertion(+), 38 deletions(-) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 86cc08794..f6b105631 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -21,14 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include #ifdef HAVE_SNMP -#ifdef HAVE_NETSNMP #include #include -#else -#include -#include -#include -#endif #include "if.h" #include "log.h" diff --git a/configure.ac b/configure.ac index 80f65b98b..c3c651f1c 100755 --- a/configure.ac +++ b/configure.ac @@ -1370,8 +1370,7 @@ if test "${enable_snmp}" = "yes"; then LIBS="${LIBS} -lcrypto"; fi AC_CHECK_LIB(netsnmp, asn_parse_int, - [AC_DEFINE(HAVE_NETSNMP,,Net SNMP) - AC_DEFINE(HAVE_SNMP,,SNMP) + [AC_DEFINE(HAVE_SNMP,,SNMP) LIBS="${LIBS} -lnetsnmp"], [AC_MSG_ERROR([--enable-snmp given, but cannot find support for SNMP])]) diff --git a/lib/smux.c b/lib/smux.c index b7cd18d14..145ec90bb 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -22,14 +22,8 @@ #include #ifdef HAVE_SNMP -#ifdef HAVE_NETSNMP #include #include -#else -#include -#include -#include -#endif #include "log.h" #include "thread.h" diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 5ac7846d2..11b733b8c 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -23,14 +23,8 @@ #ifdef HAVE_SNMP -#ifdef HAVE_NETSNMP #include #include -#else -#include -#include -#include -#endif #include "log.h" #include "vty.h" diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 9c9dd47a7..739dcae1c 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -25,14 +25,8 @@ #include #ifdef HAVE_SNMP -#ifdef HAVE_NETSNMP #include #include -#else -#include -#include -#include -#endif #include "if.h" #include "log.h" diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 61c47c71d..803ac856a 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -22,14 +22,8 @@ #include #ifdef HAVE_SNMP -#ifdef HAVE_NETSNMP #include #include -#else -#include -#include -#include -#endif #include "if.h" #include "log.h" diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 0fde4bb81..3dbfb5875 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -22,14 +22,8 @@ #include #ifdef HAVE_SNMP -#ifdef HAVE_NETSNMP #include #include -#else -#include -#include -#include -#endif #include "if.h" #include "log.h" From 08d7f6533ecc0f935a76918c462982004534864d Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 22 May 2012 22:29:17 +0200 Subject: [PATCH 0092/1342] build: use net-snmp-config to configure NetSNMP The correct method to link to NetSNMP is to use net-snmp-config (which is like pkg-config). Explicit link to libcrypto is also dropped (NetSNMP libs are linked to libcrypto, no need to link Quagga to it). Moreover, @SNMP_INCLUDES@ is dropped because useless. Due to a bug in configure.ac, it was properly populated. --- babeld/Makefile.am | 2 +- bgpd/Makefile.am | 2 +- configure.ac | 35 +++++++++++++++++++---------------- lib/Makefile.am | 2 +- ospf6d/Makefile.am | 2 +- ospfd/Makefile.am | 2 +- ripd/Makefile.am | 2 +- ripngd/Makefile.am | 2 +- vtysh/extract.pl.in | 2 +- zebra/Makefile.am | 2 +- 10 files changed, 28 insertions(+), 25 deletions(-) diff --git a/babeld/Makefile.am b/babeld/Makefile.am index 81f661261..af1201a71 100644 --- a/babeld/Makefile.am +++ b/babeld/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index e5ee893a1..9928734ee 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/configure.ac b/configure.ac index c3c651f1c..a2738a950 100755 --- a/configure.ac +++ b/configure.ac @@ -221,8 +221,6 @@ AC_ARG_ENABLE(netlink, [ --enable-netlink force to use Linux netlink interface]) AC_ARG_ENABLE(broken-aliases, [ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X]) -AC_ARG_WITH(crypto, -[ --without-crypto do not use libcrypto in SNMP]) AC_ARG_ENABLE(snmp, [ --enable-snmp enable SNMP support]) AC_ARG_WITH(libpam, @@ -1366,19 +1364,24 @@ dnl ------------------ dnl check Net-SNMP library dnl ------------------ if test "${enable_snmp}" = "yes"; then - if test "$with_crypto" != "no"; then - LIBS="${LIBS} -lcrypto"; - fi - AC_CHECK_LIB(netsnmp, asn_parse_int, - [AC_DEFINE(HAVE_SNMP,,SNMP) - LIBS="${LIBS} -lnetsnmp"], - [AC_MSG_ERROR([--enable-snmp given, but cannot find support for SNMP])]) - - AC_CHECK_HEADER([net-snmp/net-snmp-config.h], - [], - [AC_MSG_ERROR([--enable-snmp given, but cannot find net-snmp-config.h])], - QUAGGA_INCLUDES) - AC_SUBST(SNMP_INCLUDES) + AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no]) + if test x"$NETSNMP_CONFIG" = x"no"; then + AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config]) + fi + LIBS="$LIBS `${NETSNMP_CONFIG} --agent-libs`" + CFLAGS="`${NETSNMP_CONFIG} --base-cflags` $CFLAGS" + AC_MSG_CHECKING([whether we can link to Net-SNMP]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +int main(void); +], +[ +{ + return 0; +} +])],[AC_MSG_RESULT(yes)],[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([--enable-snmp given but not usable])]) + AC_DEFINE(HAVE_SNMP,,SNMP) fi dnl --------------------------- @@ -1624,7 +1627,7 @@ source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} make : ${MAKE-make} -includes : ${INCLUDES} ${SNMP_INCLUDES} +includes : ${INCLUDES} linker flags : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${quagga_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` diff --git a/lib/Makefile.am b/lib/Makefile.am index 4c67858cc..d01cf7244 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index d05b02075..726ce543e 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index d0b4ae84a..f968d7d61 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ripd/Makefile.am b/ripd/Makefile.am index 3196090c0..b0bc7a875 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index 83ddca0a4..de5bebaef 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 99224f80f..2dbaf0a10 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -63,7 +63,7 @@ $ignore{'"show history"'} = "ignore"; foreach (@ARGV) { $file = $_; - open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |"); + open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/isisd/topology @CPPFLAGS@ $file |"); local $/; undef $/; $line = ; close (FH); diff --git a/zebra/Makefile.am b/zebra/Makefile.am index e5b749a61..9ac90f8ed 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @SNMP_INCLUDES@ +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 From 3a4c96885ec878ae4631b0fb7bb7839578725976 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Wed, 23 May 2012 00:52:46 +0200 Subject: [PATCH 0093/1342] smux: isolate SMUX implementation from SNMP implementation lib/snmp.c gets OID related helper functions that can be used with another SNMP interface. smux.h is cleaned of SMUX specific bits to only expose functions that may be used by an alternative implementation. We also do not redefine functions already present in NetSNMP. Just use the appropriate headers. --- lib/Makefile.am | 2 +- lib/smux.c | 123 ++++++++++++++++-------------------------------- lib/smux.h | 81 ++----------------------------- lib/snmp.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 161 deletions(-) create mode 100644 lib/snmp.c diff --git a/lib/Makefile.am b/lib/Makefile.am index d01cf7244..73417ad8e 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -11,7 +11,7 @@ libzebra_la_SOURCES = \ checksum.c vector.c linklist.c vty.c command.c \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ - zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c \ + zclient.c sockopt.c smux.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c BUILT_SOURCES = memtypes.h route_types.h diff --git a/lib/smux.c b/lib/smux.c index 145ec90bb..a5d84a8f4 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -34,6 +34,45 @@ #include "sockunion.h" #include "smux.h" +#define SMUX_PORT_DEFAULT 199 + +#define SMUXMAXPKTSIZE 1500 +#define SMUXMAXSTRLEN 256 + +#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0) +#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1) +#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2) +#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3) +#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4) + +#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0) +#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1) +#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2) +#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3) +#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4) + +#define SMUX_MAX_FAILURE 3 + +/* SNMP tree. */ +struct subtree +{ + /* Tree's oid. */ + oid name[MAX_OID_LEN]; + u_char name_len; + + /* List of the variables. */ + struct variable *variables; + + /* Length of the variables list. */ + int variables_num; + + /* Width of the variables list. */ + int variables_width; + + /* Registered flag. */ + int registered; +}; + #define min(A,B) ((A) < (B) ? (A) : (B)) enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ}; @@ -76,62 +115,6 @@ static struct cmd_node smux_node = /* thread master */ static struct thread_master *master; -void * -oid_copy (void *dest, const void *src, size_t size) -{ - return memcpy (dest, src, size * sizeof (oid)); -} - -void -oid2in_addr (oid oid[], int len, struct in_addr *addr) -{ - int i; - u_char *pnt; - - if (len == 0) - return; - - pnt = (u_char *) addr; - - for (i = 0; i < len; i++) - *pnt++ = oid[i]; -} - -void -oid_copy_addr (oid oid[], struct in_addr *addr, int len) -{ - int i; - u_char *pnt; - - if (len == 0) - return; - - pnt = (u_char *) addr; - - for (i = 0; i < len; i++) - oid[i] = *pnt++; -} - -int -oid_compare (oid *o1, int o1_len, oid *o2, int o2_len) -{ - int i; - - for (i = 0; i < min (o1_len, o2_len); i++) - { - if (o1[i] < o2[i]) - return -1; - else if (o1[i] > o2[i]) - return 1; - } - if (o1_len < o2_len) - return -1; - if (o1_len > o2_len) - return 1; - - return 0; -} - static int oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len) { @@ -473,7 +456,7 @@ smux_set (oid *reqid, size_t *reqid_len, if (write_method) { return (*write_method)(action, val, val_type, val_len, - statP, suffix, suffix_len, v); + statP, suffix, suffix_len); } else { @@ -1354,32 +1337,6 @@ smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str) return 0; } -int -smux_header_generic (struct variable *v, oid *name, size_t *length, int exact, - size_t *var_len, WriteMethod **write_method) -{ - oid fulloid[MAX_OID_LEN]; - int ret; - - oid_copy (fulloid, v->name, v->namelen); - fulloid[v->namelen] = 0; - /* Check against full instance. */ - ret = oid_compare (name, *length, fulloid, v->namelen + 1); - - /* Check single instance. */ - if ((exact && (ret != 0)) || (!exact && (ret >= 0))) - return MATCH_FAILED; - - /* In case of getnext, fill in full instance. */ - memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid)); - *length = v->namelen + 1; - - *write_method = 0; - *var_len = sizeof(long); /* default to 'long' results */ - - return MATCH_SUCCEEDED; -} - static int smux_peer_default (void) { diff --git a/lib/smux.h b/lib/smux.h index f5754ed90..83ae56ce9 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -22,24 +22,8 @@ #ifndef _ZEBRA_SNMP_H #define _ZEBRA_SNMP_H -#define SMUX_PORT_DEFAULT 199 - -#define SMUXMAXPKTSIZE 1500 -#define SMUXMAXSTRLEN 256 - -#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0) -#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1) -#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2) -#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3) -#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4) - -#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0) -#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1) -#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2) -#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3) -#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4) - -#define SMUX_MAX_FAILURE 3 +#include +#include /* Structures here are mostly compatible with UCD SNMP 4.1.1 */ #define MATCH_FAILED (-1) @@ -55,69 +39,12 @@ #define IN_ADDR_SIZE sizeof(struct in_addr) -struct variable; - +#undef REGISTER_MIB #define REGISTER_MIB(descr, var, vartype, theoid) \ smux_register_mib(descr, (struct variable *)var, sizeof(struct vartype), \ sizeof(var)/sizeof(struct vartype), \ theoid, sizeof(theoid)/sizeof(oid)) -typedef int (WriteMethod)(int action, - u_char *var_val, - u_char var_val_type, - size_t var_val_len, - u_char *statP, - oid *name, - size_t length, - struct variable *v); - -typedef u_char *(FindVarMethod)(struct variable *v, - oid *name, - size_t *length, - int exact, - size_t *var_len, - WriteMethod **write_method); - -/* SNMP variable */ -struct variable -{ - /* Index of the MIB.*/ - u_char magic; - - /* Type of variable. */ - char type; - - /* Access control list. */ - u_short acl; - - /* Callback function. */ - FindVarMethod *findVar; - - /* Suffix of the MIB. */ - int namelen; - oid name[MAX_OID_LEN]; -}; - -/* SNMP tree. */ -struct subtree -{ - /* Tree's oid. */ - oid name[MAX_OID_LEN]; - u_char name_len; - - /* List of the variables. */ - struct variable *variables; - - /* Length of the variables list. */ - int variables_num; - - /* Width of the variables list. */ - int variables_width; - - /* Registered flag. */ - int registered; -}; - struct trap_object { FindVarMethod *findVar; @@ -145,7 +72,6 @@ struct trap_object ) extern void smux_init (struct thread_master *tm); -extern void smux_start (void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid [], size_t); extern int smux_header_generic (struct variable *, oid [], size_t *, @@ -153,6 +79,7 @@ extern int smux_header_generic (struct variable *, oid [], size_t *, extern int smux_trap (const oid *, size_t, const oid *, size_t, const struct trap_object *, size_t, unsigned int, u_char); + extern int oid_compare (oid *, int, oid *, int); extern void oid2in_addr (oid [], int, struct in_addr *); extern void *oid_copy (void *, const void *, size_t); diff --git a/lib/snmp.c b/lib/snmp.c new file mode 100644 index 000000000..d7b1d9539 --- /dev/null +++ b/lib/snmp.c @@ -0,0 +1,113 @@ +/* SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP +#include +#include + +#include "smux.h" + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +int +oid_compare (oid *o1, int o1_len, oid *o2, int o2_len) +{ + int i; + + for (i = 0; i < min (o1_len, o2_len); i++) + { + if (o1[i] < o2[i]) + return -1; + else if (o1[i] > o2[i]) + return 1; + } + if (o1_len < o2_len) + return -1; + if (o1_len > o2_len) + return 1; + + return 0; +} + +void * +oid_copy (void *dest, const void *src, size_t size) +{ + return memcpy (dest, src, size * sizeof (oid)); +} + +void +oid2in_addr (oid oid[], int len, struct in_addr *addr) +{ + int i; + u_char *pnt; + + if (len == 0) + return; + + pnt = (u_char *) addr; + + for (i = 0; i < len; i++) + *pnt++ = oid[i]; +} + +void +oid_copy_addr (oid oid[], struct in_addr *addr, int len) +{ + int i; + u_char *pnt; + + if (len == 0) + return; + + pnt = (u_char *) addr; + + for (i = 0; i < len; i++) + oid[i] = *pnt++; +} + +int +smux_header_generic (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + oid fulloid[MAX_OID_LEN]; + int ret; + + oid_copy (fulloid, v->name, v->namelen); + fulloid[v->namelen] = 0; + /* Check against full instance. */ + ret = oid_compare (name, *length, fulloid, v->namelen + 1); + + /* Check single instance. */ + if ((exact && (ret != 0)) || (!exact && (ret >= 0))) + return MATCH_FAILED; + + /* In case of getnext, fill in full instance. */ + memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid)); + *length = v->namelen + 1; + + *write_method = 0; + *var_len = sizeof(long); /* default to 'long' results */ + + return MATCH_SUCCEEDED; +} +#endif /* HAVE_SNMP */ From d6be5fb9bc41ea77547204eeedd12132b26ad662 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 24 May 2012 09:44:43 +0200 Subject: [PATCH 0094/1342] agentx: add AgentX support to Quagga. --enable-snmp will enable AgentX support in Quagga. SMUX is still here and can be enabled with --enable-snmp=smux. AgentX support can be enabled with "agentx" in configuration file. As for SMUX, this command is not understood by vtysh. It can be disabled with "no agentx", though there is no real use of this since this command cannot be used with vtysh. If "agentx" and "no agentx" command were added to vtysh, it would not be possible to disable agentx support after enabling it because NetSNMP does not expose the appropriate methods for this. The internals of AgentX are hidden by NetSNMP. Therefore, we don't have a file descriptor to add to the threading system. We do not have the timers to set either. Therefore, the event loop is modified to make use of snmp_select_info() from NetSNMP. Traps are not supported yet. --- configure.ac | 18 ++++++- lib/Makefile.am | 2 +- lib/agentx.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/smux.c | 2 +- lib/thread.c | 49 ++++++++++++++++++ 5 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 lib/agentx.c diff --git a/configure.ac b/configure.ac index a2738a950..277bad55b 100755 --- a/configure.ac +++ b/configure.ac @@ -222,7 +222,7 @@ AC_ARG_ENABLE(netlink, AC_ARG_ENABLE(broken-aliases, [ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X]) AC_ARG_ENABLE(snmp, -[ --enable-snmp enable SNMP support]) +[ --enable-snmp=ARG enable SNMP support (smux or agentx)]) AC_ARG_WITH(libpam, [ --with-libpam use libpam for PAM support in vtysh]) AC_ARG_ENABLE(tcp-zebra, @@ -1363,7 +1363,7 @@ AC_SUBST(LIB_REGEX) dnl ------------------ dnl check Net-SNMP library dnl ------------------ -if test "${enable_snmp}" = "yes"; then +if test "${enable_snmp}" != ""; then AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no]) if test x"$NETSNMP_CONFIG" = x"no"; then AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config]) @@ -1382,6 +1382,20 @@ int main(void); AC_MSG_RESULT(no) AC_MSG_ERROR([--enable-snmp given but not usable])]) AC_DEFINE(HAVE_SNMP,,SNMP) + case "${enable_snmp}" in + yes) + SNMP_METHOD=agentx + ;; + smux|agentx) + SNMP_METHOD="${enable_snmp}" + ;; + *) + AC_MSG_ERROR([--enable-snmp given with an unknown method (${enable_snmp}). Use smux or agentx]) + ;; + esac + AH_TEMPLATE([SNMP_SMUX], [Use SNMP SMUX to interface with snmpd]) + AH_TEMPLATE([SNMP_AGENTX], [Use SNMP AgentX to interface with snmpd]) + AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd) fi dnl --------------------------- diff --git a/lib/Makefile.am b/lib/Makefile.am index 73417ad8e..e00ad54dc 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -11,7 +11,7 @@ libzebra_la_SOURCES = \ checksum.c vector.c linklist.c vty.c command.c \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ - zclient.c sockopt.c smux.c snmp.c md5.c if_rmap.c keychain.c privs.c \ + zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c BUILT_SOURCES = memtypes.h route_types.h diff --git a/lib/agentx.c b/lib/agentx.c new file mode 100644 index 000000000..9cf6de5e0 --- /dev/null +++ b/lib/agentx.c @@ -0,0 +1,133 @@ +/* SNMP support + * Copyright (C) 2012 Vincent Bernat + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#if defined HAVE_SNMP && defined SNMP_AGENTX +#include +#include + +#include "command.h" +#include "smux.h" + +int agentx_enabled = 0; + +/* AgentX node. */ +static struct cmd_node agentx_node = +{ + SMUX_NODE, + "" /* AgentX has no interface. */ +}; + +/* Logging NetSNMP messages */ +static int +agentx_log_callback(int major, int minor, + void *serverarg, void *clientarg) +{ + struct snmp_log_message *slm = (struct snmp_log_message *)serverarg; + char *msg = strdup (slm->msg); + if (msg) msg[strlen(msg)-1] = '\0'; + switch (slm->priority) + { + case LOG_EMERG: zlog_err ("snmp[emerg]: %s", msg?msg:slm->msg); break; + case LOG_ALERT: zlog_err ("snmp[alert]: %s", msg?msg:slm->msg); break; + case LOG_CRIT: zlog_err ("snmp[crit]: %s", msg?msg:slm->msg); break; + case LOG_ERR: zlog_err ("snmp[err]: %s", msg?msg:slm->msg); break; + case LOG_WARNING: zlog_warn ("snmp[warning]: %s", msg?msg:slm->msg); break; + case LOG_NOTICE: zlog_notice("snmp[notice]: %s", msg?msg:slm->msg); break; + case LOG_INFO: zlog_info ("snmp[info]: %s", msg?msg:slm->msg); break; + case LOG_DEBUG: zlog_debug ("snmp[debug]: %s", msg?msg:slm->msg); break; + } + free(msg); + return SNMP_ERR_NOERROR; +} + +static int +config_write_agentx (struct vty *vty) +{ + if (agentx_enabled) + vty_out (vty, "agentx%s", VTY_NEWLINE); + return 0; +} + +DEFUN (agentx_enable, + agentx_enable_cmd, + "agentx", + "SNMP AgentX protocol settings\n" + "SNMP AgentX settings\n") +{ + if (!agentx_enabled) + { + init_snmp("quagga"); + agentx_enabled = 1; + return CMD_SUCCESS; + } + vty_out (vty, "SNMP AgentX already enabled%s", VTY_NEWLINE); + return CMD_WARNING; +} + +DEFUN (no_agentx, + no_agentx_cmd, + "no agentx", + NO_STR + "SNMP AgentX protocol settings\n" + "SNMP AgentX settings\n") +{ + if (!agentx_enabled) return CMD_SUCCESS; + vty_out (vty, "SNMP AgentX support cannot be disabled once enabled%s", VTY_NEWLINE); + return CMD_WARNING; +} + +void +smux_init (struct thread_master *tm) +{ + netsnmp_enable_subagent (); + snmp_disable_log (); + snmp_enable_calllog (); + snmp_register_callback (SNMP_CALLBACK_LIBRARY, + SNMP_CALLBACK_LOGGING, + agentx_log_callback, + NULL); + init_agent ("quagga"); + + install_node (&agentx_node, config_write_agentx); + install_element (CONFIG_NODE, &agentx_enable_cmd); + install_element (CONFIG_NODE, &no_agentx_cmd); +} + +void +smux_register_mib (const char *descr, struct variable *var, + size_t width, int num, + oid name[], size_t namelen) +{ + register_mib (descr, var, width, num, name, namelen); +} + +int +smux_trap (const oid *name, size_t namelen, + const oid *iname, size_t inamelen, + const struct trap_object *trapobj, size_t trapobjlen, + unsigned int tick, u_char sptrap) +{ + return 1; +} + +#endif /* HAVE_SNMP */ diff --git a/lib/smux.c b/lib/smux.c index a5d84a8f4..29370050f 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -21,7 +21,7 @@ #include -#ifdef HAVE_SNMP +#if defined HAVE_SNMP && defined SNMP_SMUX #include #include diff --git a/lib/thread.c b/lib/thread.c index 86d0ff8cb..6341dfd77 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -29,6 +29,16 @@ #include "hash.h" #include "command.h" #include "sigevent.h" + +#if defined HAVE_SNMP && defined SNMP_AGENTX +#include +#include +#include +#include + +extern int agentx_enabled; +#endif + /* Recent absolute time of day */ struct timeval recent_time; @@ -1030,6 +1040,11 @@ thread_fetch (struct thread_master *m, struct thread *fetch) while (1) { int num = 0; +#if defined HAVE_SNMP && defined SNMP_AGENTX + struct timeval snmp_timer_wait; + int snmpblock = 0; + int fdsetsize; +#endif /* Signals pre-empt everything */ quagga_sigevent_process (); @@ -1065,6 +1080,26 @@ thread_fetch (struct thread_master *m, struct thread *fetch) timer_wait = timer_wait_bg; } +#if defined HAVE_SNMP && defined SNMP_AGENTX + /* When SNMP is enabled, we may have to select() on additional + FD. snmp_select_info() will add them to `readfd'. The trick + with this function is its last argument. We need to set it to + 0 if timer_wait is not NULL and we need to use the provided + new timer only if it is still set to 0. */ + if (agentx_enabled) + { + fdsetsize = FD_SETSIZE; + snmpblock = 1; + if (timer_wait) + { + snmpblock = 0; + memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval)); + } + snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); + if (snmpblock == 0) + timer_wait = &snmp_timer_wait; + } +#endif num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); /* Signals should get quick treatment */ @@ -1076,6 +1111,20 @@ thread_fetch (struct thread_master *m, struct thread *fetch) return NULL; } +#if defined HAVE_SNMP && defined SNMP_AGENTX + if (agentx_enabled) + { + if (num > 0) + snmp_read(&readfd); + else if (num == 0) + { + snmp_timeout(); + run_alarms(); + } + netsnmp_check_outstanding_agent_requests(); + } +#endif + /* Check foreground timers. Historically, they have had higher priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ From 4b89e45d928d41bb5d32a00ba7b402d6a3bbdf44 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 24 May 2012 21:22:01 +0200 Subject: [PATCH 0095/1342] smux: remove `tick` argument from smux_trap() smux_trap() contains an argument whose use appears to be to set sysUpTime.0/timestamp field in SNMP trap. However, this value is not used in smux_trap(). Moreover, it is expected that this field is the value of sysUpTime.0 when the trap was sent and not any other time related to the trap. To avoid any confusion, we remove this field from the signature of the function. --- bgpd/bgp_snmp.c | 4 ++-- lib/agentx.c | 2 +- lib/smux.c | 2 +- lib/smux.h | 2 +- ospfd/ospf_snmp.c | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index f6b105631..a995ff6c2 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -853,7 +853,7 @@ bgpTrapEstablished (struct peer *peer) smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), - bm->start_time - bgp_clock (), BGPESTABLISHED); + BGPESTABLISHED); } void @@ -872,7 +872,7 @@ bgpTrapBackwardTransition (struct peer *peer) smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), - bm->start_time - bgp_clock (), BGPBACKWARDTRANSITION); + BGPBACKWARDTRANSITION); } void diff --git a/lib/agentx.c b/lib/agentx.c index 9cf6de5e0..2358581f8 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -125,7 +125,7 @@ int smux_trap (const oid *name, size_t namelen, const oid *iname, size_t inamelen, const struct trap_object *trapobj, size_t trapobjlen, - unsigned int tick, u_char sptrap) + u_char sptrap) { return 1; } diff --git a/lib/smux.c b/lib/smux.c index 29370050f..38c7018e9 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -972,7 +972,7 @@ int smux_trap (const oid *name, size_t namelen, const oid *iname, size_t inamelen, const struct trap_object *trapobj, size_t trapobjlen, - unsigned int tick, u_char sptrap) + u_char sptrap) { unsigned int i; u_char buf[BUFSIZ]; diff --git a/lib/smux.h b/lib/smux.h index 83ae56ce9..78460e68b 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -78,7 +78,7 @@ extern int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); extern int smux_trap (const oid *, size_t, const oid *, size_t, const struct trap_object *, - size_t, unsigned int, u_char); + size_t, u_char); extern int oid_compare (oid *, int, oid *, int); extern void oid2in_addr (oid [], int, struct in_addr *); diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 739dcae1c..409153b83 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -2616,7 +2616,7 @@ ospfTrapNbrStateChange (struct ospf_neighbor *on) index, IN_ADDR_SIZE + 1, ospfNbrTrapList, sizeof ospfNbrTrapList / sizeof (struct trap_object), - time (NULL), NBRSTATECHANGE); + NBRSTATECHANGE); } void @@ -2633,7 +2633,7 @@ ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) index, IN_ADDR_SIZE + 1, ospfVirtNbrTrapList, sizeof ospfVirtNbrTrapList / sizeof (struct trap_object), - time (NULL), VIRTNBRSTATECHANGE); + VIRTNBRSTATECHANGE); } void @@ -2652,7 +2652,7 @@ ospfTrapIfStateChange (struct ospf_interface *oi) index, IN_ADDR_SIZE + 1, ospfIfTrapList, sizeof ospfIfTrapList / sizeof (struct trap_object), - time (NULL), IFSTATECHANGE); + IFSTATECHANGE); } void @@ -2669,7 +2669,7 @@ ospfTrapVirtIfStateChange (struct ospf_interface *oi) index, IN_ADDR_SIZE + 1, ospfVirtIfTrapList, sizeof ospfVirtIfTrapList / sizeof (struct trap_object), - time (NULL), VIRTIFSTATECHANGE); + VIRTIFSTATECHANGE); } /* Register OSPF2-MIB. */ void From b8cf46b715b2c21db5dce8118c70b4dd9b5255a3 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Fri, 25 May 2012 08:56:44 +0200 Subject: [PATCH 0096/1342] smux: drop findVar element from trap object struct This element was not unused. --- bgpd/bgp_snmp.c | 4 ++-- lib/smux.h | 3 +-- ospfd/ospf_snmp.c | 32 ++++++++++++++++---------------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index a995ff6c2..73406d59a 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -833,8 +833,8 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, /* BGP Traps. */ struct trap_object bgpTrapList[] = { - {bgpPeerTable, 3, {3, 1, BGPPEERLASTERROR}}, - {bgpPeerTable, 3, {3, 1, BGPPEERSTATE}} + {3, {3, 1, BGPPEERLASTERROR}}, + {3, {3, 1, BGPPEERSTATE}} }; void diff --git a/lib/smux.h b/lib/smux.h index 78460e68b..b7d5096ee 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -47,8 +47,7 @@ struct trap_object { - FindVarMethod *findVar; - int namelen; + int namelen; /* Negative if the object is not indexed */ oid name[MAX_OID_LEN]; }; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 409153b83..b2d568600 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -2568,35 +2568,35 @@ ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, struct trap_object ospfNbrTrapList[] = { - {ospfGeneralGroup, -2, {1, OSPFROUTERID}}, - {ospfNbrEntry, 3, {10, 1, OSPFNBRIPADDR}}, - {ospfNbrEntry, 3, {10, 1, OSPFNBRRTRID}}, - {ospfNbrEntry, 3, {10, 1, OSPFNBRSTATE}} + {-2, {1, OSPFROUTERID}}, + {3, {10, 1, OSPFNBRIPADDR}}, + {3, {10, 1, OSPFNBRRTRID}}, + {3, {10, 1, OSPFNBRSTATE}} }; struct trap_object ospfVirtNbrTrapList[] = { - {ospfGeneralGroup, -2, {1, 1}}, - {ospfVirtNbrEntry, 3, {11, 1, OSPFVIRTNBRAREA}}, - {ospfVirtNbrEntry, 3, {11, 1, OSPFVIRTNBRRTRID}}, - {ospfVirtNbrEntry, 3, {11, 1, OSPFVIRTNBRSTATE}} + {-2, {1, 1}}, + {3, {11, 1, OSPFVIRTNBRAREA}}, + {3, {11, 1, OSPFVIRTNBRRTRID}}, + {3, {11, 1, OSPFVIRTNBRSTATE}} }; struct trap_object ospfIfTrapList[] = { - {ospfGeneralGroup, -2, {1, OSPFROUTERID}}, - {ospfIfEntry, 3, {7, 1, OSPFIFIPADDRESS}}, - {ospfIfEntry, 3, {7, 1, OSPFADDRESSLESSIF}}, - {ospfIfEntry, 3, {7, 1, OSPFIFSTATE}} + {-2, {1, OSPFROUTERID}}, + {3, {7, 1, OSPFIFIPADDRESS}}, + {3, {7, 1, OSPFADDRESSLESSIF}}, + {3, {7, 1, OSPFIFSTATE}} }; struct trap_object ospfVirtIfTrapList[] = { - {ospfGeneralGroup, -2, {1, OSPFROUTERID}}, - {ospfVirtIfEntry, 3, {9, 1, OSPFVIRTIFAREAID}}, - {ospfVirtIfEntry, 3, {9, 1, OSPFVIRTIFNEIGHBOR}}, - {ospfVirtIfEntry, 3, {9, 1, OSPFVIRTIFSTATE}} + {-2, {1, OSPFROUTERID}}, + {3, {9, 1, OSPFVIRTIFAREAID}}, + {3, {9, 1, OSPFVIRTIFNEIGHBOR}}, + {3, {9, 1, OSPFVIRTIFSTATE}} }; void From b7c0d0651cd64f644d02ef5e4d1b82febe7e57d8 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Fri, 25 May 2012 11:17:01 +0200 Subject: [PATCH 0097/1342] agentx: handle SNMP traps smux_trap() signature has been changed to provide appropriate level information to send SNMPv2 notifications. This includes the addition of the enterprise OID to use (from which is derived the SNMP trap OID) and the MIB registry to locate the appropriate function for variable bindings provided by the trap. The SMUX implementation has been updated but ignore the provided enterprise OID. Instead, it still uses the SMUX peer OID to keep compatibility with previous versions of Quagga. The SMUX implementation also ignores the provided MIB registry since it uses smux_get() function to grab the appropriate values. This is not possible with the AgentX implementation since there is no such function provided by NetSNMP. --- bgpd/bgp_snmp.c | 9 ++++-- lib/agentx.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++- lib/smux.c | 9 +++++- lib/smux.h | 31 ++++++++++++++++-- ospfd/ospf_snmp.c | 17 +++++++--- 5 files changed, 137 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 73406d59a..36fd4ef44 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -118,6 +118,7 @@ SNMP_LOCAL_VARIABLES /* BGP-MIB instances. */ oid bgp_oid [] = { BGP4MIB }; +oid bgp_trap_oid [] = { BGP4MIB, 0 }; /* IP address 0.0.0.0. */ static struct in_addr bgp_empty_addr = {0}; @@ -850,7 +851,9 @@ bgpTrapEstablished (struct peer *peer) oid_copy_addr (index, &addr, IN_ADDR_SIZE); - smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), + smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable), + bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid), + bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPESTABLISHED); @@ -869,7 +872,9 @@ bgpTrapBackwardTransition (struct peer *peer) oid_copy_addr (index, &addr, IN_ADDR_SIZE); - smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), + smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable), + bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid), + bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPBACKWARDTRANSITION); diff --git a/lib/agentx.c b/lib/agentx.c index 2358581f8..be6b4320e 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -122,11 +122,91 @@ smux_register_mib (const char *descr, struct variable *var, } int -smux_trap (const oid *name, size_t namelen, +smux_trap (struct variable *vp, size_t vp_len, + const oid *ename, size_t enamelen, + const oid *name, size_t namelen, const oid *iname, size_t inamelen, const struct trap_object *trapobj, size_t trapobjlen, u_char sptrap) { + oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; + size_t objid_snmptrap_len = sizeof objid_snmptrap / sizeof (oid); + oid notification_oid[MAX_OID_LEN]; + size_t notification_oid_len; + unsigned int i; + + netsnmp_variable_list *notification_vars = NULL; + if (!agentx_enabled) return 0; + + /* snmpTrapOID */ + oid_copy (notification_oid, ename, enamelen); + notification_oid[enamelen] = sptrap; + notification_oid_len = enamelen + 1; + snmp_varlist_add_variable (¬ification_vars, + objid_snmptrap, objid_snmptrap_len, + ASN_OBJECT_ID, + (u_char *) notification_oid, + notification_oid_len * sizeof(oid)); + + /* Provided bindings */ + for (i = 0; i < trapobjlen; i++) + { + unsigned int j; + oid oid[MAX_OID_LEN]; + size_t oid_len, onamelen; + u_char *val; + size_t val_len; + WriteMethod *wm = NULL; + struct variable cvp; + + /* Make OID. */ + if (trapobj[i].namelen > 0) + { + /* Columnar object */ + onamelen = trapobj[i].namelen; + oid_copy (oid, name, namelen); + oid_copy (oid + namelen, trapobj[i].name, onamelen); + oid_copy (oid + namelen + onamelen, iname, inamelen); + oid_len = namelen + onamelen + inamelen; + } + else + { + /* Scalar object */ + onamelen = trapobj[i].namelen * (-1); + oid_copy (oid, name, namelen); + oid_copy (oid + namelen, trapobj[i].name, onamelen); + oid[onamelen + namelen] = 0; + oid_len = namelen + onamelen + 1; + } + + /* Locate the appropriate function and type in the MIB registry. */ + for (j = 0; j < vp_len; j++) + { + if (oid_compare (trapobj[i].name, onamelen, vp[j].name, vp[j].namelen) != 0) + continue; + /* We found the appropriate variable in the MIB registry. */ + oid_copy(cvp.name, name, namelen); + oid_copy(cvp.name + namelen, vp[j].name, vp[j].namelen); + cvp.namelen = namelen + vp[j].namelen; + cvp.type = vp[j].type; + cvp.magic = vp[j].magic; + cvp.acl = vp[j].acl; + cvp.findVar = vp[j].findVar; + /* Grab the result. */ + val = cvp.findVar (&cvp, oid, &oid_len, 1, &val_len, &wm); + if (!val) break; + snmp_varlist_add_variable (¬ification_vars, + oid, oid_len, + vp[j].type, + val, + val_len); + break; + } + } + + + send_v2trap (notification_vars); + snmp_free_varbind (notification_vars); return 1; } diff --git a/lib/smux.c b/lib/smux.c index 38c7018e9..074664001 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -968,8 +968,15 @@ smux_open (int sock) return send (sock, buf, (ptr - buf), 0); } +/* `ename` is ignored. Instead of using the provided enterprise OID, + the SMUX peer is used. This keep compatibility with the previous + versions of Quagga. + + All other fields are used as they are intended. */ int -smux_trap (const oid *name, size_t namelen, +smux_trap (struct variable *vp, size_t vp_len, + const oid *ename, size_t enamelen, + const oid *name, size_t namelen, const oid *iname, size_t inamelen, const struct trap_object *trapobj, size_t trapobjlen, u_char sptrap) diff --git a/lib/smux.h b/lib/smux.h index b7d5096ee..b29fdc72b 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -75,9 +75,34 @@ extern void smux_register_mib(const char *, struct variable *, size_t, int, oid [], size_t); extern int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); -extern int smux_trap (const oid *, size_t, const oid *, size_t, - const struct trap_object *, - size_t, u_char); + +/* For traps, three OID are provided: + + 1. The enterprise OID to use (the last argument will be appended to + it to form the SNMP trap OID) + + 2. The base OID for objects to be sent in traps. + + 3. The index OID for objects to be sent in traps. This index is used + to designate a particular instance of a column. + + The provided trap object contains the bindings to be sent with the + trap. The base OID will be prefixed to the provided OID and, if the + length is positive, the requested OID is assumed to be a columnar + object and the index OID will be appended. + + The two first arguments are the MIB registry used to locate the trap + objects. + + The use of the arguments may differ depending on the implementation + used. +*/ +extern int smux_trap (struct variable *, size_t, + const oid *, size_t, + const oid *, size_t, + const oid *, size_t, + const struct trap_object *, size_t, + u_char); extern int oid_compare (oid *, int, oid *, int); extern void oid2in_addr (oid [], int, struct in_addr *); diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index b2d568600..c8416de6f 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -210,6 +210,7 @@ SNMP_LOCAL_VARIABLES /* OSPF-MIB instances. */ oid ospf_oid [] = { OSPF2MIB }; +oid ospf_trap_oid [] = { OSPF2MIB, 16, 2 }; /* Not reverse mappable! */ /* IP address 0.0.0.0. */ static struct in_addr ospf_empty_addr = {0}; @@ -2612,7 +2613,9 @@ ospfTrapNbrStateChange (struct ospf_neighbor *on) oid_copy_addr (index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap (ospf_oid, sizeof ospf_oid / sizeof (oid), + smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), + ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), + ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfNbrTrapList, sizeof ospfNbrTrapList / sizeof (struct trap_object), @@ -2629,7 +2632,9 @@ ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) oid_copy_addr (index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap (ospf_oid, sizeof ospf_oid / sizeof (oid), + smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), + ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), + ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfVirtNbrTrapList, sizeof ospfVirtNbrTrapList / sizeof (struct trap_object), @@ -2648,7 +2653,9 @@ ospfTrapIfStateChange (struct ospf_interface *oi) oid_copy_addr (index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap (ospf_oid, sizeof ospf_oid / sizeof (oid), + smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), + ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), + ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfIfTrapList, sizeof ospfIfTrapList / sizeof (struct trap_object), @@ -2665,7 +2672,9 @@ ospfTrapVirtIfStateChange (struct ospf_interface *oi) oid_copy_addr (index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap (ospf_oid, sizeof ospf_oid / sizeof (oid), + smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), + ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), + ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfVirtIfTrapList, sizeof ospfVirtIfTrapList / sizeof (struct trap_object), From 0ff4b9c96793898429052de576d8da368e48997e Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Fri, 25 May 2012 12:04:51 +0200 Subject: [PATCH 0098/1342] agentx: add appropriate documentation --- doc/overview.texi | 5 ++- doc/snmp.texi | 89 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/doc/overview.texi b/doc/overview.texi index 435834b71..7acfc0e9e 100644 --- a/doc/overview.texi +++ b/doc/overview.texi @@ -7,7 +7,7 @@ provides TCP/IP based routing services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, BGP-4, and BGP-4+ (@pxref{Supported RFCs}). Quagga also supports special BGP Route Reflector and Route Server behavior. In addition to traditional IPv4 routing protocols, Quagga also -supports IPv6 routing protocols. With SNMP daemon which supports SMUX +supports IPv6 routing protocols. With SNMP daemon which supports SMUX and AgentX protocol, Quagga provides routing protocol MIBs (@pxref{SNMP Support}). Quagga uses an advanced software architecture to provide you with a high @@ -238,6 +238,9 @@ J. Chu, Editor. July 1994.} @cite{OSPF Version 2 Management Information Base. F. Baker, R. Coltun. November 1995.} +@item @asis{RFC2741} +@cite{Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.} + @end table @node How to get Quagga diff --git a/doc/snmp.texi b/doc/snmp.texi index 3f80cc58f..0918a462f 100644 --- a/doc/snmp.texi +++ b/doc/snmp.texi @@ -5,11 +5,12 @@ feature for collecting network information from router and/or host. Quagga itself does not support SNMP agent (server daemon) functionality but is able to connect to a SNMP agent using the SMUX protocol -(@cite{RFC1227}) and make the routing protocol MIBs available through -it. +(@cite{RFC1227}) or the AgentX protocol (@cite{RFC2741}) and make the +routing protocol MIBs available through it. @menu * Getting and installing an SNMP agent:: +* AgentX configuration:: * SMUX configuration:: * MIB and command reference:: * Handling SNMP Traps:: @@ -18,20 +19,82 @@ it. @node Getting and installing an SNMP agent @section Getting and installing an SNMP agent -There are several SNMP agent which support SMUX. We recommend to use the latest +There are several SNMP agent which support SMUX or AgentX. We recommend to use the latest version of @code{net-snmp} which was formerly known as @code{ucd-snmp}. It is free and open software and available at @uref{http://www.net-snmp.org/} and as binary package for most Linux distributions. -@code{net-snmp} has to be compiled with @code{--with-mib-modules=smux} to -be able to accept connections from Quagga. +@code{net-snmp} has to be compiled with @code{--with-mib-modules=agentx} to +be able to accept connections from Quagga using AgentX protocol or with +@code{--with-mib-modules=smux} to use SMUX protocol. + +Nowadays, SMUX is a legacy protocol. The AgentX protocol should be +preferred for any new deployment. Both protocols have the same coverage. + +@node AgentX configuration +@section AgentX configuration + +To enable AgentX protocol support, Quagga must have been build with the +@code{--enable-snmp} or @code{--enable-snmp=agentx} option. Both the +master SNMP agent (snmpd) and each of the Quagga daemons must be +configured. In @code{/etc/snmp/snmpd.conf}, @code{master agentx} +directive should be added. In each of the Quagga daemons, @code{agentx} +command will enable AgentX support. + +@example +/etc/snmp/snmpd.conf: + # + # example access restrictions setup + # + com2sec readonly default public + group MyROGroup v1 readonly + view all included .1 80 + access MyROGroup "" any noauth exact all none none + # + # enable master agent for AgentX subagents + # + master agentx + +/etc/quagga/ospfd.conf: + ! ... the rest of ospfd.conf has been omitted for clarity ... + ! + agentx + ! +@end example + +Upon successful connection, you should get something like this in the +log of each Quagga daemons: + +@example +2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected +@end example + +Then, you can use the following command to check everything works as expected: + +@example +# snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 +OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 +[...] +@end example + +The AgentX protocol can be transported over a Unix socket or using TCP +or UDP. It usually defaults to a Unix socket and depends on how NetSNMP +was built. If need to configure Quagga to use another transport, you can +configure it through @code{/etc/snmp/quagga.conf}: + +@example +/etc/snmp/quagga.conf: + [snmpd] + # Use a remote master agent + agentXSocket tcp:192.168.15.12:705 +@end example @node SMUX configuration @section SMUX configuration To enable SMUX protocol support, Quagga must have been build with the -@code{--enable-snmp} option. +@code{--enable-snmp=smux} option. -A separate connection has then to be established between between the +A separate connection has then to be established between the SNMP agent (snmpd) and each of the Quagga daemons. This connections each use different OID numbers and passwords. Be aware that this OID number is not the one that is used in queries by clients, it is solely @@ -85,7 +148,7 @@ troublesome @code{snmp_log()} line in the function @section MIB and command reference The following OID numbers are used for the interprocess communication of snmpd and -the Quagga daemons. Sadly, SNMP has not been implemented in all daemons yet. +the Quagga daemons with SMUX only. @example (OIDs below .iso.org.dod.internet.private.enterprises) zebra .1.3.6.1.4.1.3317.1.2.1 .gnome.gnomeProducts.zebra.zserv @@ -95,7 +158,8 @@ ospfd .1.3.6.1.4.1.3317.1.2.5 .gnome.gnomeProducts.zebra.ospfd ospf6d .1.3.6.1.4.1.3317.1.2.6 .gnome.gnomeProducts.zebra.ospf6d @end example -The following OID numbers are used for querying the SNMP daemon by a client: +Sadly, SNMP has not been implemented in all daemons yet. The following +OID numbers are used for querying the SNMP daemon by a client: @example zebra .1.3.6.1.2.1.4.24 .iso.org.dot.internet.mgmt.mib-2.ip.ipForward ospfd .1.3.6.1.2.1.14 .iso.org.dot.internet.mgmt.mib-2.ospf @@ -104,7 +168,7 @@ ripd .1.3.6.1.2.1.23 .iso.org.dot.internet.mgmt.mib-2.rip2 ospf6d .1.3.6.1.3.102 .iso.org.dod.internet.experimental.ospfv3 @end example -The following syntax is understood by the Quagga daemons for configuring SNMP: +The following syntax is understood by the Quagga daemons for configuring SNMP using SMUX: @deffn {Command} {smux peer @var{oid}} {} @deffnx {Command} {no smux peer @var{oid}} {} @end deffn @@ -113,4 +177,9 @@ The following syntax is understood by the Quagga daemons for configuring SNMP: @deffnx {Command} {no smux peer @var{oid} @var{password}} {} @end deffn +Here is the syntax for using AgentX: +@deffn {Command} {agentx} {} +@deffnx {Command} {no agentx} {} +@end deffn + @include snmptrap.texi From 8046ba6ec4d6e87bf8da6563c0f3e5e66c4652b3 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 31 May 2012 13:30:28 +0200 Subject: [PATCH 0099/1342] snmp: let handlers accept OID from a lesser prefix Most table handlers do not expect to be given an OID whose prefix is outside what they can handle. This is not a problem with the SMUX implementation since it always correct the OID such that the prefix matches. However, this is not the case for the AgentX implementation. A new function, smux_header_table() is used to do this normalization. --- bgpd/bgp_snmp.c | 7 ++++++- lib/smux.h | 2 ++ lib/snmp.c | 20 +++++++++++++++++++ ospf6d/ospf6_snmp.c | 8 ++++++++ ospfd/ospf_snmp.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ ripd/rip_snmp.c | 12 ++++++++++++ zebra/zebra_snmp.c | 8 ++++++++ 7 files changed, 104 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 36fd4ef44..c8f2aa54b 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -455,7 +455,9 @@ bgpPeerTable (struct variable *v, oid name[], size_t *length, static struct in_addr addr; struct peer *peer; - *write_method = NULL; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; memset (&addr, 0, sizeof (struct in_addr)); peer = bgpPeerTable_lookup (v, name, length, &addr, exact); @@ -765,6 +767,9 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, if (! bgp) return NULL; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; memset (&addr, 0, sizeof (struct prefix_ipv4)); binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact); diff --git a/lib/smux.h b/lib/smux.h index b29fdc72b..72b4eaf09 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -75,6 +75,8 @@ extern void smux_register_mib(const char *, struct variable *, size_t, int, oid [], size_t); extern int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); +extern int smux_header_table (struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); /* For traps, three OID are provided: diff --git a/lib/snmp.c b/lib/snmp.c index d7b1d9539..79595a1ea 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -110,4 +110,24 @@ smux_header_generic (struct variable *v, oid *name, size_t *length, int exact, return MATCH_SUCCEEDED; } + +int +smux_header_table (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + /* If the requested OID name is less than OID prefix we + handle, adjust it to our prefix. */ + if ((oid_compare (name, *length, v->name, v->namelen)) < 0) + { + if (exact) + return MATCH_FAILED; + oid_copy(name, v->name, v->namelen); + *length = v->namelen; + } + + *write_method = 0; + *var_len = sizeof(long); + + return MATCH_SUCCEEDED; +} #endif /* HAVE_SNMP */ diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 11b733b8c..d252f549f 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -306,6 +306,10 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, if (ospf6 == NULL) return NULL; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + len = *length - v->namelen; len = (len >= sizeof (u_int32_t) ? sizeof (u_int32_t) : 0); if (exact && len != sizeof (u_int32_t)) @@ -372,6 +376,10 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, struct ospf6_area *oa; struct listnode *node; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&area_id, 0, sizeof (struct in_addr)); type = 0; memset (&id, 0, sizeof (struct in_addr)); diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index c8416de6f..1daf0d6aa 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -704,6 +704,10 @@ ospfAreaEntry (struct variable *v, oid *name, size_t *length, int exact, struct ospf_area *area; struct in_addr addr; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&addr, 0, sizeof (struct in_addr)); area = ospfAreaLookup (v, name, length, &addr, exact); @@ -847,6 +851,10 @@ ospfStubAreaEntry (struct variable *v, oid *name, size_t *length, struct ospf_area *area; struct in_addr addr; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&addr, 0, sizeof (struct in_addr)); area = ospfStubAreaLookup (v, name, length, &addr, exact); @@ -1078,6 +1086,10 @@ ospfLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, struct in_addr router_id; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + /* INDEX { ospfLsdbAreaId, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } */ @@ -1240,6 +1252,10 @@ ospfAreaRangeEntry (struct variable *v, oid *name, size_t *length, int exact, struct in_addr mask; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) @@ -1344,6 +1360,10 @@ ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact, struct in_addr addr; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) @@ -1679,6 +1699,10 @@ ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, struct ospf_interface *oi; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + ifindex = 0; memset (&ifaddr, 0, sizeof (struct in_addr)); @@ -1847,6 +1871,10 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, struct ospf_interface *oi; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + ifindex = 0; memset (&ifaddr, 0, sizeof (struct in_addr)); @@ -2039,6 +2067,10 @@ ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, struct in_addr area_id; struct in_addr neighbor; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&area_id, 0, sizeof (struct in_addr)); memset (&neighbor, 0, sizeof (struct in_addr)); @@ -2272,6 +2304,10 @@ ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, struct ospf_neighbor *nbr; struct ospf_interface *oi; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&nbr_addr, 0, sizeof (struct in_addr)); ifindex = 0; @@ -2334,6 +2370,10 @@ ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact, struct in_addr neighbor; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&area_id, 0, sizeof (struct in_addr)); memset (&neighbor, 0, sizeof (struct in_addr)); @@ -2482,6 +2522,10 @@ ospfExtLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, struct in_addr router_id; struct ospf *ospf; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + type = OSPF_AS_EXTERNAL_LSA; memset (&ls_id, 0, sizeof (struct in_addr)); memset (&router_id, 0, sizeof (struct in_addr)); @@ -2533,6 +2577,10 @@ static u_char * ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + /* Return the current value of the variable */ switch (v->magic) { diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 803ac856a..090ebfae2 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -345,6 +345,10 @@ rip2IfStatEntry (struct variable *v, oid name[], size_t *length, static struct in_addr addr; static long valid = SNMP_VALID; + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ @@ -448,6 +452,10 @@ rip2IfConfAddress (struct variable *v, oid name[], size_t *length, struct interface *ifp; struct rip_interface *ri; + if (smux_header_table(v, name, length, exact, val_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ @@ -518,6 +526,10 @@ rip2PeerTable (struct variable *v, oid name[], size_t *length, struct rip_peer *peer; + if (smux_header_table(v, name, length, exact, val_len, write_method) + == MATCH_FAILED) + return NULL; + memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 3dbfb5875..f52bbcb8d 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -451,6 +451,10 @@ ipFwTable (struct variable *v, oid objid[], size_t *objid_len, static struct in_addr netmask; struct nexthop *nexthop; + if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) + == MATCH_FAILED) + return NULL; + get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib); if (!np) return NULL; @@ -549,6 +553,10 @@ static u_char * ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { + if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) + == MATCH_FAILED) + return NULL; + switch (v->magic) { case IPCIDRROUTEDEST: From 0f0ab5180877559e92b71daacb8a106a815a5ade Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 22 May 2012 13:34:24 +0200 Subject: [PATCH 0100/1342] snmp: fix OSPFV3-MIB implementation Use the real MIB from RFC 5643. Fix used ASN1 types. Indexes are not exported any more (they are "no access"). Fix some endian issues. Also, ID are just integers, not IPv4 addresses. No additional OID are supported in this commit. --- ospf6d/OSPFv3-MIB.txt | 6709 ++++++++++++++++++++++++----------------- ospf6d/ospf6_snmp.c | 410 +-- 2 files changed, 4188 insertions(+), 2931 deletions(-) diff --git a/ospf6d/OSPFv3-MIB.txt b/ospf6d/OSPFv3-MIB.txt index 80e6cb2d3..258f533ef 100644 --- a/ospf6d/OSPFv3-MIB.txt +++ b/ospf6d/OSPFv3-MIB.txt @@ -1,2758 +1,3951 @@ -OSPFV3-MIB DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-IDENTITY, OBJECT-TYPE, mib-2, experimental, - Counter32, Gauge32, Integer32, IpAddress, - Unsigned32 - FROM SNMPv2-SMI - TEXTUAL-CONVENTION, TruthValue, StorageType, RowStatus - FROM SNMPv2-TC - MODULE-COMPLIANCE, OBJECT-GROUP - FROM SNMPv2-CONF - InterfaceIndex - FROM IF-MIB - InetAddressType, InetAddress, InetAddressPrefixLength - FROM INET-ADDRESS-MIB - AreaID, RouterID, Metric, BigMetric, Status, - HelloRange, DesignatedRouterPriority - FROM OSPF-MIB; - -ospfv3MIB MODULE-IDENTITY - LAST-UPDATED "200404081200Z" - ORGANIZATION "IETF OSPF Working Group" - CONTACT-INFO - "WG E-Mail: ospf@peach.ease.lsoft.com - WG Chairs: John.Moy@sycamorenet.com - acee@redback.com - rohit@xebeo.com - - Dan Joyal - Nortel Networks - 600 Technology Park Drive - Billerica, MA 01821, USA - djoyal@nortelnetworks.com - - Vishwas Manral - SiNett Corporation - 2/1, First Floor - Embassy Icon Annex - Infantry Road - Bangalore 560001 - vishwas@sinett.com" - - DESCRIPTION - "The MIB module to describe OSPF version 3" - REVISION "200404081200Z" - DESCRIPTION -- RFC Editor assigns RFC xxxx - "Initial version, published as RFC xxxx" - ::= { experimental 102 } -- IANA assigns xx - --- Texual conventions - -UpToRefreshInterval ::= TEXTUAL-CONVENTION - STATUS current - DESCRIPTION - "The values one might be able to configure for - variables bounded by the Refresh Interval" - SYNTAX Integer32 (1..1800) - -RouterDeadRange ::= TEXTUAL-CONVENTION - STATUS current - DESCRIPTION - "The range of intervals in seconds that a routers hello - must have not been seen before a neighbor declares the - router down" - SYNTAX Integer32 (1..'FFFF'h) - - --- Top-level structure of MIB -ospfv3Objects OBJECT IDENTIFIER ::= { ospfv3MIB 1 } -ospfv3Conformance OBJECT IDENTIFIER ::= { ospfv3MIB 2 } - --- OSPFv3 General Variables - --- These parameters apply globally to the Router's --- OSPFv3 Process. - -ospfv3GeneralGroup OBJECT IDENTIFIER ::= { ospfv3Objects 1 } - -ospfv3RouterId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "A 32-bit integer uniquely identifying the - router in the Autonomous System. - To ensure uniqueness, this may - default to the value of one of the - router's IPv4 interface addresses if IPv4 is - configured on the router." - ::= { ospfv3GeneralGroup 1 } - -ospfv3AdminStat OBJECT-TYPE - SYNTAX Status - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The administrative status of OSPFv3 in the - router. The value 'enabled' denotes that the - OSPFv3 Process is active on at least one inter- - face; 'disabled' disables it on all inter- - faces." - ::= { ospfv3GeneralGroup 2 } - -ospfv3VersionNumber OBJECT-TYPE - SYNTAX INTEGER { version3(3) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The version number of OSPF for IPv6 is 3." - ::= { ospfv3GeneralGroup 3 } - -ospfv3AreaBdrRtrStatus OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A flag to note whether this router is an area - border router." - REFERENCE - "OSPF Version 2, Section 3 Splitting the AS into - Areas" - ::= { ospfv3GeneralGroup 4 } - -ospfv3ASBdrRtrStatus OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "A flag to note whether this router is config- - ured as an Autonomous System border router." - REFERENCE - "OSPF Version 2, Section 3.3 Classification of - routers" - ::= { ospfv3GeneralGroup 5 } - -ospfv3AsScopeLsaCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of AS-Scope (e.g. AS-External) link-state - advertisements in the link-state database." - ::= { ospfv3GeneralGroup 6 } - -ospfv3AsScopeLsaCksumSum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32-bit unsigned sum of the LS checksums of - the AS-scoped link-state advertisements con- - tained in the link-state database. This sum - can be used to determine if there has been a - change in a router's link state database, and - to compare the link-state database of two - routers." - ::= { ospfv3GeneralGroup 7 } - -ospfv3OriginateNewLsas OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of new link-state advertisements - that have been originated. This number is in- - cremented each time the router originates a new - LSA." - ::= { ospfv3GeneralGroup 8 } - -ospfv3RxNewLsas OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of link-state advertisements re- - ceived determined to be new instantiations. - This number does not include newer instantia- - tions of self-originated link-state advertise- - ments." - ::= { ospfv3GeneralGroup 9 } - -ospfv3ExtLsaCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of External(LS type 0x4005) in the link- - state database" - ::= { ospfv3GeneralGroup 10 } - - -ospfv3ExtAreaLsdbLimit OBJECT-TYPE - SYNTAX Integer32 (-1..'7FFFFFFF'h) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The maximum number of non-default AS- - external-LSAs entries that can be stored in the - link-state database. If the value is -1, then - there is no limit. - - When the number of non-default AS-external-LSAs - in a router's link-state database reaches - ospfv3ExtAreaLsdbLimit, the router enters Overflow- - State. The router never holds more than - ospfv3ExtAreaLsdbLimit non-default AS-external-LSAs - in its database. OspfExtAreaLsdbLimit MUST be set - identically in all routers attached to the OSPFv3 - backbone and/or any regular OSPFv3 area. (i.e., - OSPFv3 stub areas and NSSAs are excluded)." - ::= { ospfv3GeneralGroup 11 } - -ospfv3MulticastExtensions OBJECT-TYPE - SYNTAX BITS { - intraAreaMulticast(0), - interAreaMulticast(1), - interAsMulticast(2) - } - - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "A Bit Mask indicating whether the router is - forwarding IPv6 multicast datagrams - based on the algorithms defined in the Multi- - cast Extensions to OSPF. - - If intraAreaMulticast set, indicates that the router - can forward IPv6 multicast datagrams in the router's - directly attached areas (called intra-area mul- - ticast routing). - - If interAreaMulticast set, indicates that the router - can forward IPv6 multicast datagrams between OSPFv3 - areas (called inter-area multicast routing). - - If interAsMulticast set, indicates that the router can - forward IPv6 multicast datagrams between Auto- - nomous Systems (called inter-AS multicast rout- - ing). - - Only certain combinations of bit settings are - allowed, namely: - - All bits cleared (no multicasting) - - intraAreaMulticast only, - - intraAreaMulticast and interAreaMulticast, - - intraAreaMulticast and interAsMulticast - - intraAreaMulticast, interAreaMulticast and - interAsMulticast - By default, all bits are cleared." - ::= { ospfv3GeneralGroup 12 } - -ospfv3ExitOverflowInterval OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The number of seconds that, after entering - OverflowState, a router will attempt to leave - OverflowState. This allows the router to again - originate non-default AS-External-LSAs. When - set to 0, the router will not leave Overflow- - State until restarted." - ::= { ospfv3GeneralGroup 13 } - -ospfv3DemandExtensions OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The router's support for demand routing." - REFERENCE - "OSPF Version 2, Appendix on Demand Routing" - ::= { ospfv3GeneralGroup 14 } - -ospfv3TrafficEngineeringSupport OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The router's support for traffic engineering - extensions." - ::= { ospfv3GeneralGroup 15 } - -ospfv3ReferenceBandwidth OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Reference bandwidth in kilobits/second for - calculating default interface metrics. The - default value is 100,000 KBPS (100 MBPS)" - ::= { ospfv3GeneralGroup 16 } - -ospfv3RestartSupport OBJECT-TYPE - SYNTAX INTEGER { none (1), - plannedOnly (2), - plannedAndUnplanned (3) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The router's support for OSPF hitless restart. - Options include: no restart support, only planned - restarts or both planned and unplanned restarts." - ::= { ospfv3GeneralGroup 17 } - -ospfv3RestartInterval OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Configured OSPF hitless restart timeout interval." - ::= { ospfv3GeneralGroup 18 } - -ospfv3RestartStatus OBJECT-TYPE - SYNTAX INTEGER { notRestarting (1), - plannedRestart (2), - unplannedRestart (3) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Current status of OSPF hitless restart." - ::= { ospfv3GeneralGroup 19 } - -ospfv3RestartAge OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Remaining time in current OSPF hitless restart - interval." - ::= { ospfv3GeneralGroup 20 } - -ospfv3RestartExitReason OBJECT-TYPE - SYNTAX INTEGER { none (1), -- none attempted - inProgress (2), -- restart in - -- progress - completed (3), -- successfully - -- completed - timedOut (4), -- timed out - topologyChanged (5) -- aborted due to - -- topologychange. - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Describes the outcome of the last attempt at a - hitless restart. If the value is 'none', no restart - has yet been attempted. If the value is 'inProgress', - a restart attempt is currently underway." - ::= { ospfv3GeneralGroup 21 } - - --- The OSPFv3 Area Data Structure contains information --- regarding the various areas. The interfaces and --- virtual links are configured as part of these areas. --- Area 0.0.0.0, by definition, is the Backbone Area - -ospfv3AreaTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3AreaEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Information describing the configured parame- - ters and cumulative statistics of the router's - attached areas." - REFERENCE - "OSPF Version 2, Section 6 The Area Data Struc- - ture" - ::= { ospfv3Objects 2 } - -ospfv3AreaEntry OBJECT-TYPE - SYNTAX Ospfv3AreaEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Information describing the configured parame- - ters and cumulative statistics of one of the - router's attached areas." - INDEX { ospfv3AreaId } - ::= { ospfv3AreaTable 1 } - -Ospfv3AreaEntry ::= SEQUENCE { - ospfv3AreaId - AreaID, - ospfv3ImportAsExtern - INTEGER, - ospfv3AreaSpfRuns - Counter32, - ospfv3AreaBdrRtrCount - Gauge32, - ospfv3AreaAsBdrRtrCount - Gauge32, - ospfv3AreaScopeLsaCount - Gauge32, - ospfv3AreaScopeLsaCksumSum - Integer32, - ospfv3AreaSummary - INTEGER, - ospfv3AreaStatus - RowStatus, - ospfv3StubMetric - BigMetric, - ospfv3AreaNssaTranslatorRole - INTEGER, - ospfv3AreaNssaTranslatorState - INTEGER, - ospfv3AreaNssaTranslatorStabilityInterval - Unsigned32, - ospfv3AreaNssaTranslatorEvents - Counter32, - ospfv3AreaStubMetricType - INTEGER - } - -ospfv3AreaId OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A 32-bit integer uniquely identifying an area. - Area ID 0.0.0.0 is used for the OSPFv3 backbone." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3AreaEntry 1 } - -ospfv3ImportAsExtern OBJECT-TYPE - SYNTAX INTEGER { - importExternal(1), -- normal area - importNoExternal(2), -- stub area - importNssa(3) -- not-so-stubby-area - } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "Indicates whether an area is a Stub area, NSSA, or - standard area. AS-scope LSAs are not imported into Stub - Areas or NSSAs. NSSAs import AS-External data as Type-7 - LSAs which have Area-scope" - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - DEFVAL { importExternal } - ::= { ospfv3AreaEntry 2 } - -ospfv3AreaSpfRuns OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times that the intra-area route - table has been calculated using this area's - link-state database. This is typically done - using Dijkstra's algorithm." - ::= { ospfv3AreaEntry 3 } - -ospfv3AreaBdrRtrCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of area border routers reach- - able within this area. This is initially zero, - and is calculated in each SPF Pass." - ::= { ospfv3AreaEntry 4 } - -ospfv3AreaAsBdrRtrCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Autonomous System border - routers reachable within this area. This is - initially zero, and is calculated in each SPF - Pass." - ::= { ospfv3AreaEntry 5 } - -ospfv3AreaScopeLsaCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Area-Scope link-state - advertisements in this area's link-state - database." - ::= { ospfv3AreaEntry 6 } - -ospfv3AreaScopeLsaCksumSum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32-bit unsigned sum of the Area-Scope link-state - advertisements' LS checksums contained in this - area's link-state database. The sum can be used - to determine if there has been a change in a - router's link state database, and to compare the - link-state database of two routers." - ::= { ospfv3AreaEntry 7 } - -ospfv3AreaSummary OBJECT-TYPE - SYNTAX INTEGER { - noAreaSummary(1), - sendAreaSummary(2) - } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The variable ospfv3AreaSummary controls the im- - port of Inter-Area LSAs into stub areas. It has - no effect on other areas. - - If it is noAreaSummary, the router will neither - originate nor propagate Inter-Area LSAs into the - stub area. It will rely entirely on its de- - fault route. - - If it is sendAreaSummary, the router will both - summarize and propagate Inter-Area LSAs." - DEFVAL { sendAreaSummary } - ::= { ospfv3AreaEntry 8 } - -ospfv3AreaStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable controls the status of the en- - try. The use of RowStatus is covered in more detail - in [6]." - ::= { ospfv3AreaEntry 9 } - -ospfv3StubMetric OBJECT-TYPE - SYNTAX BigMetric - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The metric value advertised for the default route - into Stub and NSSA areas." - ::= { ospfv3AreaEntry 10 } - -ospfv3AreaNssaTranslatorRole OBJECT-TYPE - SYNTAX INTEGER { always(1), candidate(2) } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "Indicates an NSSA Border router's ability to - perform NSSA translation of type-7 LSAs into - type-5 LSAs." - DEFVAL { candidate } - ::= { ospfv3AreaEntry 11 } - -ospfv3AreaNssaTranslatorState OBJECT-TYPE - SYNTAX INTEGER { - enabled(1), - elected(2), - disabled(3) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates if and how an NSSA Border router is - performing NSSA translation of type-7 LSAs into type-5 - LSAs. When this object is set to enabled, the NSSA - Border router's ospfv3AreaNssTranslatorRole - has been set to always. When this object is set to - elected, a candidate NSSA Border router is translating - type-7 LSAs into type-5. When this object is set to - disabled, a candidate NSSA Border router is NOT - translating type-7 LSAs into type-5." - ::= { ospfv3AreaEntry 12 } - -ospfv3AreaNssaTranslatorStabilityInterval OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The number of seconds after an elected translator - determines its services are no longer required, that - it should continue to perform its translation duties." - DEFVAL { 40 } - ::= { ospfv3AreaEntry 13 } - -ospfv3AreaNssaTranslatorEvents OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates the number of Translator State changes - that have occurred since the last boot-up." - ::= { ospfv3AreaEntry 14 } - -ospfv3AreaStubMetricType OBJECT-TYPE - SYNTAX INTEGER { - ospfv3Metric (1), -- OSPF Metric - comparableCost (2), -- external type 1 - nonComparable (3) -- external type 2 - } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable displays the type of metric ad- - vertised as a default route." - DEFVAL { ospfv3Metric } - ::= { ospfv3AreaEntry 15 } - --- OSPFv3 AS-Scope Link State Database - --- The Link State Database contains the AS-Scope Link State --- Advertisements from throughout the areas that the --- device is attached to. - -ospfv3AsLsdbTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3AsLsdbEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The OSPFv3 Process's AS-Scope Link State Database." - ::= { ospfv3Objects 3 } - -ospfv3AsLsdbEntry OBJECT-TYPE - SYNTAX Ospfv3AsLsdbEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A single AS-Scope Link State Advertisement." - INDEX { ospfv3AsLsdbType, - ospfv3AsLsdbRouterId, - ospfv3AsLsdbLsid } - ::= { ospfv3AsLsdbTable 1 } - -Ospfv3AsLsdbEntry ::= SEQUENCE { - ospfv3AsLsdbType - Unsigned32, - ospfv3AsLsdbRouterId - RouterID, - ospfv3AsLsdbLsid - IpAddress, - ospfv3AsLsdbSequence - Integer32, - ospfv3AsLsdbAge - Integer32, - ospfv3AsLsdbChecksum - Integer32, - ospfv3AsLsdbAdvertisement - OCTET STRING, - ospfv3AsLsdbTypeKnown - TruthValue - } - -ospfv3AsLsdbType OBJECT-TYPE - SYNTAX Unsigned32 (0..4294967295) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The type of the link state advertisement. - Each link state type has a separate advertise- - ment format. AS-Scope LSAs not recognized by - the router may be stored in the database." - ::= { ospfv3AsLsdbEntry 1 } - -ospfv3AsLsdbRouterId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32 bit number that uniquely identifies the - originating router in the Autonomous System." - REFERENCE - "OSPF Version 2, Appendix C.1 Global parameters" - ::= { ospfv3AsLsdbEntry 2 } - -ospfv3AsLsdbLsid OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Link State ID is an LS Type Specific field - containing a unique identifier; - it identifies the piece of the routing domain - that is being described by the advertisement. - In contrast to OSPFv2, the LSID has no - addressing semantics." - ::= { ospfv3AsLsdbEntry 3 } - --- Note that the OSPF Sequence Number is a 32 bit signed --- integer. It starts with the value '80000001'h, --- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h --- Thus, a typical sequence number will be very negative. - -ospfv3AsLsdbSequence OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The sequence number field is a signed 32-bit - integer. It is used to detect old and dupli- - cate link state advertisements. The space of - sequence numbers is linearly ordered. The - larger the sequence number the more recent the - advertisement." - REFERENCE - "OSPF Version 2, Section 12.1.6 LS sequence - number" - ::= { ospfv3AsLsdbEntry 4 } - -ospfv3AsLsdbAge OBJECT-TYPE - SYNTAX Integer32 -- Should be 0..MaxAge - -- unless DoNotAge bit is set - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "This field is the age of the link state adver- - tisement in seconds." - REFERENCE - "OSPF Version 2, Section 12.1.1 LS age" - ::= { ospfv3AsLsdbEntry 5 } - -ospfv3AsLsdbChecksum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "This field is the checksum of the complete - contents of the advertisement, excepting the - age field. The age field is excepted so that - an advertisement's age can be incremented - without updating the checksum. The checksum - used is the same that is used for ISO connec- - tionless datagrams; it is commonly referred to - as the Fletcher checksum." - REFERENCE - "OSPF Version 2, Section 12.1.7 LS checksum" - ::= { ospfv3AsLsdbEntry 6 } - -ospfv3AsLsdbAdvertisement OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (1..65535)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The entire Link State Advertisement, including - its header." - ::= { ospfv3AsLsdbEntry 7 } - -ospfv3AsLsdbTypeKnown OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Is the LSA type recognized by this Router?" - ::= { ospfv3AsLsdbEntry 8 } - - --- OSPFv3 Area-Scope Link State Database - --- The Link State Database contains the Area-Scope Link State --- Advertisements from throughout the area that the --- device is attached to. - -ospfv3AreaLsdbTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3AreaLsdbEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The OSPFv3 Process's Area-Scope Link State Database." - ::= { ospfv3Objects 4 } - -ospfv3AreaLsdbEntry OBJECT-TYPE - SYNTAX Ospfv3AreaLsdbEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A single Area-Scope Link State Advertisement." - INDEX { ospfv3AreaLsdbAreaId, - ospfv3AreaLsdbType, - ospfv3AreaLsdbRouterId, - ospfv3AreaLsdbLsid } - ::= { ospfv3AreaLsdbTable 1 } - -Ospfv3AreaLsdbEntry ::= SEQUENCE { - ospfv3AreaLsdbAreaId - AreaID, - ospfv3AreaLsdbType - Unsigned32, - ospfv3AreaLsdbRouterId - RouterID, - ospfv3AreaLsdbLsid - IpAddress, - ospfv3AreaLsdbSequence - Integer32, - ospfv3AreaLsdbAge - Integer32, - ospfv3AreaLsdbChecksum - Integer32, - ospfv3AreaLsdbAdvertisement - OCTET STRING, - ospfv3AreaLsdbTypeKnown - TruthValue - } - -ospfv3AreaLsdbAreaId OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32 bit identifier of the Area from which the - LSA was received." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3AreaLsdbEntry 1 } - -ospfv3AreaLsdbType OBJECT-TYPE - SYNTAX Unsigned32 (0..4294967295) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The type of the link state advertisement. - Each link state type has a separate advertise- - ment format. Area-Scope LSAs unrecognized by the - router are also stored in this database." - ::= { ospfv3AreaLsdbEntry 2 } - -ospfv3AreaLsdbRouterId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32 bit number that uniquely identifies the - originating router in the Autonomous System." - REFERENCE - "OSPF Version 2, Appendix C.1 Global parameters" - ::= { ospfv3AreaLsdbEntry 3 } - -ospfv3AreaLsdbLsid OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Link State ID is an LS Type Specific field - containing a unique identifier; - it identifies the piece of the routing domain - that is being described by the advertisement. - In contrast to OSPFv2, the LSID has no - addressing semantics." - ::= { ospfv3AreaLsdbEntry 4 } - --- Note that the OSPF Sequence Number is a 32 bit signed --- integer. It starts with the value '80000001'h, --- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h --- Thus, a typical sequence number will be very negative. - -ospfv3AreaLsdbSequence OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The sequence number field is a signed 32-bit - integer. It is used to detect old and dupli- - cate link state advertisements. The space of - sequence numbers is linearly ordered. The - larger the sequence number the more recent the - advertisement." - REFERENCE - "OSPF Version 2, Section 12.1.6 LS sequence - number" - ::= { ospfv3AreaLsdbEntry 5 } - -ospfv3AreaLsdbAge OBJECT-TYPE - SYNTAX Integer32 -- Should be 0..MaxAge - -- unless DoNotAge bit is set - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "This field is the age of the link state adver- - tisement in seconds." - REFERENCE - "OSPF Version 2, Section 12.1.1 LS age" - ::= { ospfv3AreaLsdbEntry 6 } - -ospfv3AreaLsdbChecksum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "This field is the checksum of the complete - contents of the advertisement, excepting the - age field. The age field is excepted so that - an advertisement's age can be incremented - without updating the checksum. The checksum - used is the same that is used for ISO connec- - tionless datagrams; it is commonly referred to - as the Fletcher checksum." - REFERENCE - "OSPF Version 2, Section 12.1.7 LS checksum" - ::= { ospfv3AreaLsdbEntry 7 } - -ospfv3AreaLsdbAdvertisement OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (1..65535)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The entire Link State Advertisement, including - its header." - ::= { ospfv3AreaLsdbEntry 8 } - -ospfv3AreaLsdbTypeKnown OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Is the LSA type recognized by this Router?" - ::= { ospfv3AreaLsdbEntry 9 } - --- OSPFv3 Link-Scope Link State Database - --- The Link State Database contains the Link-Scope Link State --- Advertisements from the links that the --- device is attached to. - -ospfv3LinkLsdbTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3LinkLsdbEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The OSPFv3 Process's Link-Scope Link State Database." - ::= { ospfv3Objects 5 } - -ospfv3LinkLsdbEntry OBJECT-TYPE - SYNTAX Ospfv3LinkLsdbEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A single Link-Scope Link State Advertisement." - INDEX { ospfv3LinkLsdbIfIndex, - ospfv3LinkLsdbType, - ospfv3LinkLsdbRouterId, - ospfv3LinkLsdbLsid } - ::= { ospfv3LinkLsdbTable 1 } - -Ospfv3LinkLsdbEntry ::= SEQUENCE { - ospfv3LinkLsdbIfIndex - InterfaceIndex, - ospfv3LinkLsdbType - Unsigned32, - ospfv3LinkLsdbRouterId - RouterID, - ospfv3LinkLsdbLsid - IpAddress, - ospfv3LinkLsdbSequence - Integer32, - ospfv3LinkLsdbAge - Integer32, - ospfv3LinkLsdbChecksum - Integer32, - ospfv3LinkLsdbAdvertisement - OCTET STRING, - ospfv3LinkLsdbTypeKnown - TruthValue - } - -ospfv3LinkLsdbIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The identifier of the link from which the LSA - was received." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3LinkLsdbEntry 1 } - -ospfv3LinkLsdbType OBJECT-TYPE - SYNTAX Unsigned32 (0..4294967295) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The type of the link state advertisement. - Each link state type has a separate advertise- - ment format. Link-Scope LSAs unrecognized by the - router are also stored in this database." - ::= { ospfv3LinkLsdbEntry 2 } - -ospfv3LinkLsdbRouterId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32 bit number that uniquely identifies the - originating router in the Autonomous System." - REFERENCE - "OSPF Version 2, Appendix C.1 Global parameters" - ::= { ospfv3LinkLsdbEntry 3 } - -ospfv3LinkLsdbLsid OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Link State ID is an LS Type Specific field - containing a unique identifier; - it identifies the piece of the routing domain - that is being described by the advertisement. - In contrast to OSPFv2, the LSID has no - addressing semantics." - ::= { ospfv3LinkLsdbEntry 4 } - --- Note that the OSPF Sequence Number is a 32 bit signed --- integer. It starts with the value '80000001'h, --- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h --- Thus, a typical sequence number will be very negative. - -ospfv3LinkLsdbSequence OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The sequence number field is a signed 32-bit - integer. It is used to detect old and dupli- - cate link state advertisements. The space of - sequence numbers is linearly ordered. The - larger the sequence number the more recent the - advertisement." - REFERENCE - "OSPF Version 2, Section 12.1.6 LS sequence - number" - ::= { ospfv3LinkLsdbEntry 5 } - -ospfv3LinkLsdbAge OBJECT-TYPE - SYNTAX Integer32 -- Should be 0..MaxAge - -- unless DoNotAge bit is set - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "This field is the age of the link state - advertisement in seconds." - REFERENCE - "OSPF Version 2, Section 12.1.1 LS age" - ::= { ospfv3LinkLsdbEntry 6 } - -ospfv3LinkLsdbChecksum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "This field is the checksum of the complete - contents of the advertisement, excepting the - age field. The age field is excepted so that - an advertisement's age can be incremented - without updating the checksum. The checksum - used is the same that is used for ISO connec- - tionless datagrams; it is commonly referred to - as the Fletcher checksum." - REFERENCE - "OSPF Version 2, Section 12.1.7 LS checksum" - ::= { ospfv3LinkLsdbEntry 7 } - -ospfv3LinkLsdbAdvertisement OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (1..65535)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The entire Link State Advertisement, including - its header." - ::= { ospfv3LinkLsdbEntry 8 } - -ospfv3LinkLsdbTypeKnown OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates whether the LSA type is recognized by this - Router." - ::= { ospfv3LinkLsdbEntry 9 } - - --- OSPF Host Table - --- The Host/Metric Table indicates what hosts are directly --- attached to the Router, and what metrics and types of --- service should be advertised for them. - -ospfv3HostTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3HostEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The list of Hosts, and their metrics, that the - router will advertise as host routes." - REFERENCE - "OSPF Version 2, Appendix C.6 Host route param- - eters" - ::= { ospfv3Objects 6 } - -ospfv3HostEntry OBJECT-TYPE - SYNTAX Ospfv3HostEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A metric to be advertised when a given host is - reachable." - INDEX { ospfv3HostAddressType, - ospfv3HostAddress } - ::= { ospfv3HostTable 1 } - -Ospfv3HostEntry ::= SEQUENCE { - ospfv3HostAddressType - InetAddressType, - ospfv3HostAddress - InetAddress, - ospfv3HostMetric - Metric, - ospfv3HostStatus - RowStatus, - ospfv3HostAreaID - AreaID - } - -ospfv3HostAddressType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The address type of ospfv3HostAddress. Only IPv6 - addresses without zone index are expected." - REFERENCE - "OSPF Version 2, Appendix C.6 Host route parame- - ters" - ::= { ospfv3HostEntry 1 } - - -ospfv3HostAddress OBJECT-TYPE - SYNTAX InetAddress (SIZE (16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The IPv6 Address of the Host. Must be a Global - or Site-local address." - REFERENCE - "OSPF Version 2, Appendix C.6 Host route parame- - ters" - ::= { ospfv3HostEntry 2 } - -ospfv3HostMetric OBJECT-TYPE - SYNTAX Metric - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The Metric to be advertised." - REFERENCE - "OSPF Version 2, Appendix C.6 Host route parame- - ters" - ::= { ospfv3HostEntry 3 } - -ospfv3HostStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable controls the status of the en- - try. The use of RowStatus is covered in more detail - in [6]." - ::= { ospfv3HostEntry 4 } - -ospfv3HostAreaID OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The Area the Host Entry is to be found within. - By default, the area that a subsuming OSPFv3 in- - terface is in, or 0.0.0.0" - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3HostEntry 5 } - --- OSPFv3 Interface Table - -ospfv3IfTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3IfEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The OSPFv3 Interface Table describes the inter- - faces from the viewpoint of OSPFv3." - REFERENCE - "OSPF Version 2, Appendix C.3 Router interface - parameters" - ::= { ospfv3Objects 7 } - -ospfv3IfEntry OBJECT-TYPE - SYNTAX Ospfv3IfEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The OSPFv3 Interface Entry describes one inter- - face from the viewpoint of OSPFv3." - INDEX { ospfv3IfIndex } - ::= { ospfv3IfTable 1 } - - -Ospfv3IfEntry ::= SEQUENCE { - ospfv3IfIndex - InterfaceIndex, - ospfv3IfAreaId - AreaID, - ospfv3IfType - INTEGER, - ospfv3IfAdminStat - Status, - ospfv3IfRtrPriority - DesignatedRouterPriority, - ospfv3IfTransitDelay - UpToRefreshInterval, - ospfv3IfRetransInterval - UpToRefreshInterval, - ospfv3IfHelloInterval - HelloRange, - ospfv3IfRtrDeadInterval - RouterDeadRange, - ospfv3IfPollInterval - Unsigned32, - ospfv3IfState - INTEGER, - ospfv3IfDesignatedRouter - RouterID, - ospfv3IfBackupDesignatedRouter - RouterID, - ospfv3IfEvents - Counter32, - ospfv3IfStatus - RowStatus, - ospfv3IfMulticastForwarding - INTEGER, - ospfv3IfDemand - TruthValue, - ospfv3IfMetricValue - Metric, - ospfv3IfLinkScopeLsaCount - Gauge32, - ospfv3IfLinkLsaCksumSum - Integer32, - ospfv3IfInstId - Integer32, - ospfv3IfDemandNbrProbe - TruthValue, - ospfv3IfDemandNbrProbeRetxLimit - Unsigned32, - ospfv3IfDemandNbrProbeInterval - Unsigned32 - } - -ospfv3IfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The interface index of this OSPFv3 interface. - It corresponds to the interface index of the - IPv6 interface on which OSPFv3 is configured." - ::= { ospfv3IfEntry 1 } - -ospfv3IfAreaId OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "A 32-bit integer uniquely identifying the area - to which the interface connects. Area ID - 0.0.0.0 is used for the OSPFv3 backbone." - DEFVAL { '00000000'H } -- 0.0.0.0 - ::= { ospfv3IfEntry 2 } - -ospfv3IfType OBJECT-TYPE - SYNTAX INTEGER { - broadcast(1), - nbma(2), - pointToPoint(3), - pointToMultipoint(5) - } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The OSPFv3 interface type." - ::= { ospfv3IfEntry 3 } - -ospfv3IfAdminStat OBJECT-TYPE - SYNTAX Status - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The OSPFv3 interface's administrative status. - The value formed on the interface, and the in- - terface will be advertised as an internal route - to some area. The value 'disabled' denotes - that the interface is external to OSPFv3." - DEFVAL { enabled } - ::= { ospfv3IfEntry 4 } - -ospfv3IfRtrPriority OBJECT-TYPE - SYNTAX DesignatedRouterPriority - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The priority of this interface. Used in - multi-access networks, this field is used in - the designated router election algorithm. The - value 0 signifies that the router is not eligi- - ble to become the designated router on this - particular network. In the event of a tie in - this value, routers will use their Router ID as - a tie breaker." - DEFVAL { 1 } - ::= { ospfv3IfEntry 5 } - -ospfv3IfTransitDelay OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The estimated number of seconds it takes to - transmit a link state update packet over this - interface." - DEFVAL { 1 } - ::= { ospfv3IfEntry 6 } - -ospfv3IfRetransInterval OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The number of seconds between link-state ad- - vertisement retransmissions, for adjacencies - belonging to this interface. This value is - also used when retransmitting database descrip- - tion and link-state request packets." - DEFVAL { 5 } - ::= { ospfv3IfEntry 7 } - -ospfv3IfHelloInterval OBJECT-TYPE - SYNTAX HelloRange - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The length of time, in seconds, between the - Hello packets that the router sends on the in- - terface. This value must be the same for all - routers attached to a common network." - DEFVAL { 10 } - ::= { ospfv3IfEntry 8 } - -ospfv3IfRtrDeadInterval OBJECT-TYPE - SYNTAX RouterDeadRange - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The number of seconds that a router's Hello - packets have not been seen before it's neigh- - bors declare the router down. This should be - some multiple of the Hello interval. This - value must be the same for all routers attached - to a common network." - DEFVAL { 40 } - ::= { ospfv3IfEntry 9 } - -ospfv3IfPollInterval OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The larger time interval, in seconds, between - the Hello packets sent to an inactive non- - broadcast multi- access neighbor." - DEFVAL { 120 } - ::= { ospfv3IfEntry 10 } - -ospfv3IfState OBJECT-TYPE - SYNTAX INTEGER { - down(1), - loopback(2), - waiting(3), - pointToPoint(4), - designatedRouter(5), - backupDesignatedRouter(6), - otherDesignatedRouter(7) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The OSPFv3 Interface State." - ::= { ospfv3IfEntry 11 } - -ospfv3IfDesignatedRouter OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Router ID of the Designated Router." - ::= { ospfv3IfEntry 12 } - -ospfv3IfBackupDesignatedRouter OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Router ID of the Backup Designated - Router." - ::= { ospfv3IfEntry 14 } - -ospfv3IfEvents OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times this OSPF interface has - changed its state, or an error has occurred." - ::= { ospfv3IfEntry 15 } - - ospfv3IfStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable controls the status of the en- - try. The use of RowStatus is covered in more detail in - [6]." - ::= { ospfv3IfEntry 17 } - -ospfv3IfMulticastForwarding OBJECT-TYPE - SYNTAX INTEGER { - blocked(1), -- no multicast forwarding - multicast(2), -- using multicast address - unicast(3) -- to each OSPFv3 neighbor - } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The way multicasts should forwarded on this - interface; not forwarded, forwarded as data - link multicasts, or forwarded as data link uni- - casts. Data link multicasting is not meaning- - ful on point to point and NBMA interfaces, and - setting ospfv3MulticastForwarding to 0 effective- - ly disables all multicast forwarding." - DEFVAL { blocked } - ::= { ospfv3IfEntry 18 } - -ospfv3IfDemand OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "Indicates whether Demand OSPFv3 procedures (hel- - lo suppression to FULL neighbors and setting the - DoNotAge flag on propagated LSAs) should be per- - formed on this interface." - DEFVAL { false } - ::= { ospfv3IfEntry 19 } - -ospfv3IfMetricValue OBJECT-TYPE - SYNTAX Metric - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The metric assigned to this interface. - The default value of the Metric is - Reference Bandwidth / ifSpeed. The value of the - reference bandwidth is configured by the - ospfv3ReferenceBandwidth object." - ::= { ospfv3IfEntry 20 } - - ospfv3IfLinkScopeLsaCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Link-Scope link-state - advertisements in this link's link-state database." - ::= { ospfv3IfEntry 21 } - - ospfv3IfLinkLsaCksumSum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32-bit unsigned sum of the Link-Scope link-state - advertisements' LS checksums contained in this - link's link-state database. The sum can be used - to determine if there has been a change in a - router's link state database, and to compare the - link-state database of two routers." - ::= { ospfv3IfEntry 22 } - -ospfv3IfInstId OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "Enables multiple instances of OSPFv3 to be run over - a single link. Each protocol instance would be assigned - a separate ID. This ID has local link significance - only." - DEFVAL { 0 } - ::= { ospfv3IfEntry 23 } - -ospfv3IfDemandNbrProbe OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-create - STATUS current - DESCRIPTION - " Indicates whether or not neighbor probing is - enabled to determine whether or not the neighbor - is inactive. Neighbor probing is disabled by - default." - DEFVAL { false } - ::= { ospfv3IfEntry 24 } - - ospfv3IfDemandNbrProbeRetxLimit OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - " The number of consecutive LSA retransmissions before - the neighbor is deemed inactive and the neighbor - adjacency is brought down." - DEFVAL { 10 } - ::= { ospfv3IfEntry 25 } - - - ospfv3IfDemandNbrProbeInterval OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - " Defines how often the neighbor will be probed." - DEFVAL { 120 } - ::= { ospfv3IfEntry 26 } - - --- OSPFv3 Virtual Interface Table - --- The Virtual Interface Table describes the virtual --- links that the OSPFv3 Process is configured to --- carry on. - -ospfv3VirtIfTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3VirtIfEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Information about this router's virtual inter- - faces." - REFERENCE - "OSPF Version 2, Appendix C.4 Virtual link - parameters" - ::= { ospfv3Objects 8 } - -ospfv3VirtIfEntry OBJECT-TYPE - SYNTAX Ospfv3VirtIfEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Information about a single Virtual Interface." - INDEX { ospfv3VirtIfAreaId, - ospfv3VirtIfNeighbor } - ::= { ospfv3VirtIfTable 1 } - -Ospfv3VirtIfEntry ::= SEQUENCE { - ospfv3VirtIfAreaId - AreaID, - ospfv3VirtIfNeighbor - RouterID, - ospfv3VirtIfIndex - InterfaceIndex, - ospfv3VirtIfTransitDelay - UpToRefreshInterval, - ospfv3VirtIfRetransInterval - UpToRefreshInterval, - ospfv3VirtIfHelloInterval - HelloRange, - ospfv3VirtIfRtrDeadInterval - RouterDeadRange, - ospfv3VirtIfState - INTEGER, - ospfv3VirtIfEvents - Counter32, - ospfv3VirtIfStatus - RowStatus, - ospfv3VirtIfLinkScopeLsaCount - Gauge32, - ospfv3VirtIfLinkLsaCksumSum - Integer32 - } - -ospfv3VirtIfAreaId OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Transit Area that the Virtual Link - traverses. By definition, this is not 0.0.0.0" - ::= { ospfv3VirtIfEntry 1 } - -ospfv3VirtIfNeighbor OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Router ID of the Virtual Neighbor." - ::= { ospfv3VirtIfEntry 2 } - -ospfv3VirtIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The interface ID assigned to this OSPFv3 virtual - interface. It is advertised in Hello's sent over - the virtal link and in the router's router-LSAs." - ::= { ospfv3VirtIfEntry 3 } - -ospfv3VirtIfTransitDelay OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The estimated number of seconds it takes to - transmit a link- state update packet over this - interface." - DEFVAL { 1 } - ::= { ospfv3VirtIfEntry 4 } - -ospfv3VirtIfRetransInterval OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The number of seconds between link-state ad- - vertisement retransmissions, for adjacencies - belonging to this interface. This value is - also used when retransmitting database descrip- - tion and link-state request packets. This - value should be well over the expected round- - trip time." - DEFVAL { 5 } - ::= { ospfv3VirtIfEntry 5 } - -ospfv3VirtIfHelloInterval OBJECT-TYPE - SYNTAX HelloRange - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The length of time, in seconds, between the - Hello packets that the router sends on the in- - terface. This value must be the same for the - virtual neighbor." - DEFVAL { 10 } - ::= { ospfv3VirtIfEntry 6 } - -ospfv3VirtIfRtrDeadInterval OBJECT-TYPE - SYNTAX RouterDeadRange - UNITS "seconds" - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The number of seconds that a router's Hello - packets have not been seen before it's neigh- - bors declare the router down. This should be - some multiple of the Hello interval. This - value must be the same for the virtual neigh- - bor." - DEFVAL { 60 } - ::= { ospfv3VirtIfEntry 7 } - -ospfv3VirtIfState OBJECT-TYPE - SYNTAX INTEGER { - down(1), -- these use the same encoding - pointToPoint(4) -- as the ospfv3IfTable - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "OSPF virtual interface states." - ::= { ospfv3VirtIfEntry 8 } - -ospfv3VirtIfEvents OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of state changes or error events on - this Virtual Link" - ::= { ospfv3VirtIfEntry 9 } - -ospfv3VirtIfStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable controls the status of the en- - try. The use of RowStatus is covered in more detail - in [6]." - ::= { ospfv3VirtIfEntry 10 } - -ospfv3VirtIfLinkScopeLsaCount OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Link-Scope link-state - advertisements in this virtual link's link-state - database." - ::= { ospfv3VirtIfEntry 11 } - -ospfv3VirtIfLinkLsaCksumSum OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The 32-bit unsigned sum of the Link-Scope link-state - advertisements' LS checksums contained in this - virtual link's link-state database. The sum can be used - to determine if there has been a change in a - router's link state database, and to compare the - link-state database of two routers." - ::= { ospfv3VirtIfEntry 12 } - - --- OSPFv3 Neighbor Table - --- The OSPFv3 Neighbor Table describes all neighbors in --- the locality of the subject router. - -ospfv3NbrTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3NbrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table of non-virtual neighbor information." - REFERENCE - "OSPF Version 2, Section 10 The Neighbor Data - Structure" - ::= { ospfv3Objects 9 } - -ospfv3NbrEntry OBJECT-TYPE - SYNTAX Ospfv3NbrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The information regarding a single neighbor." - REFERENCE - "OSPF Version 2, Section 10 The Neighbor Data - Structure" - INDEX { ospfv3NbrIfIndex, - ospfv3NbrRtrId } - ::= { ospfv3NbrTable 1 } - -Ospfv3NbrEntry ::= SEQUENCE { - ospfv3NbrIfIndex - InterfaceIndex, - ospfv3NbrRtrId - RouterID, - ospfv3NbrAddressType - InetAddressType, - ospfv3NbrAddress - InetAddress, - ospfv3NbrOptions - Integer32, - ospfv3NbrPriority - DesignatedRouterPriority, - ospfv3NbrState - INTEGER, - ospfv3NbrEvents - Counter32, - ospfv3NbrLsRetransQLen - Gauge32, - ospfv3NbrHelloSuppressed - TruthValue, - ospfv3NbrIfId - InterfaceIndex, - ospfv3NbrRestartHelperStatus - INTEGER, - ospfv3NbrRestartHelperAge - UpToRefreshInterval, - ospfv3NbrRestartHelperExitReason - INTEGER - } - -ospfv3NbrIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The local link ID of the link over which the - neighbor can be reached." - ::= { ospfv3NbrEntry 1 } - -ospfv3NbrRtrId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A 32-bit integer (represented as a type IpAd- - dress) uniquely identifying the neighboring - router in the Autonomous System." - ::= { ospfv3NbrEntry 2 } - -ospfv3NbrAddressType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The address type of ospfv3NbrAddress. Only IPv6 - addresses without zone index are expected." - ::= { ospfv3NbrEntry 3 } - -ospfv3NbrAddress OBJECT-TYPE - SYNTAX InetAddress (SIZE (16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The IPv6 address of the neighbor associated with - the local link." - ::= { ospfv3NbrEntry 4 } - -ospfv3NbrOptions OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A Bit Mask corresponding to the neighbor's op- - tions field." - REFERENCE - "OSPF Version 3, Appendix A.2 the Options field" - ::= { ospfv3NbrEntry 5 } - -ospfv3NbrPriority OBJECT-TYPE - SYNTAX DesignatedRouterPriority - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The priority of this neighbor in the designat- - ed router election algorithm. The value 0 sig- - nifies that the neighbor is not eligible to be- - come the designated router on this particular - network." - ::= { ospfv3NbrEntry 6 } - -ospfv3NbrState OBJECT-TYPE - SYNTAX INTEGER { - down(1), - attempt(2), - init(3), - twoWay(4), - exchangeStart(5), - exchange(6), - loading(7), - full(8) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The State of the relationship with this Neigh- - bor." - REFERENCE - "OSPF Version 2, Section 10.1 Neighbor States" - ::= { ospfv3NbrEntry 7 } - -ospfv3NbrEvents OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times this neighbor relationship - has changed state, or an error has occurred." - ::= { ospfv3NbrEntry 8 } - -ospfv3NbrLsRetransQLen OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The current length of the retransmission - queue." - ::= { ospfv3NbrEntry 9 } - -ospfv3NbrHelloSuppressed OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates whether Hellos are being suppressed - to the neighbor" - ::= { ospfv3NbrEntry 10 } - -ospfv3NbrIfId OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The interface ID that the neighbor advertises - in its Hello Packets on this link, that is, the - neighbor's local interface index." - ::= { ospfv3NbrEntry 11 } - -ospfv3NbrRestartHelperStatus OBJECT-TYPE - SYNTAX INTEGER { notHelping (1), - helping (2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates whether the router is acting - as a hitless restart helper for the neighbor." - ::= { ospfv3NbrEntry 12 } - -ospfv3NbrRestartHelperAge OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Remaining time in current OSPF hitless restart - interval, if the router is acting as a restart - helper for the neighbor." - ::= { ospfv3NbrEntry 13 } - -ospfv3NbrRestartHelperExitReason OBJECT-TYPE - SYNTAX INTEGER { none (1), -- not attempted - inProgress (2), -- restart in - -- progress - completed (3), -- successfully - -- completed - timedOut (4), -- timed out - topologyChanged (5) -- aborted due to - -- topology - -- change. - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Describes the outcome of the last attempt at acting - as a hitless restart helper for the neighbor." - ::= { ospfv3NbrEntry 14 } - - --- OSPFv3 NBMA Neighbor Table - --- The OSPFv3 NBMA Neighbor Table describes all configured --- NBMA neighbors and neighbors dynamically discovered by --- lower-level protocols such as Inverse Neighbor Discovery. - -ospfv3NbmaNbrTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3NbmaNbrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table of configured non-virtual neighbor - information and neighbors dynamically discovered - by lower-level protocols such as Inverse Neighbor - Discovery." - REFERENCE - "OSPF Version 2, Section 10 The Neighbor Data - Structure" - ::= { ospfv3Objects 10 } - -ospfv3NbmaNbrEntry OBJECT-TYPE - SYNTAX Ospfv3NbmaNbrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The information regarding a single configured - neighbor or neighbor discovered by lower-level - protocols such as Inverse Neighbor Discovery." - REFERENCE - "OSPF Version 2, Section 10 The Neighbor Data - Structure" - INDEX { ospfv3NbmaNbrIfIndex, - ospfv3NbmaNbrAddressType, - ospfv3NbmaNbrAddress } - ::= { ospfv3NbmaNbrTable 1 } - -Ospfv3NbmaNbrEntry ::= SEQUENCE { - ospfv3NbmaNbrIfIndex - InterfaceIndex, - ospfv3NbmaNbrAddressType - InetAddressType, - ospfv3NbmaNbrAddress - InetAddress, - ospfv3NbmaNbrPriority - DesignatedRouterPriority, - ospfv3NbmaNbrRtrId - RouterID, - ospfv3NbmaNbrState - INTEGER, - ospfv3NbmaNbrStorageType - StorageType, - ospfv3NbmaNbrStatus - RowStatus - } - -ospfv3NbmaNbrIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The local link ID of the link over which the - neighbor can be reached." - ::= { ospfv3NbmaNbrEntry 1 } - -ospfv3NbmaNbrAddressType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The address type of ospfv3NbrAddress. Only IPv6 - addresses without zone index are expected." - ::= { ospfv3NbmaNbrEntry 2 } - -ospfv3NbmaNbrAddress OBJECT-TYPE - SYNTAX InetAddress (SIZE (16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The IPv6 address of the neighbor associated with - the local link." - ::= { ospfv3NbmaNbrEntry 3 } - -ospfv3NbmaNbrPriority OBJECT-TYPE - SYNTAX DesignatedRouterPriority - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The priority of this neighbor in the designat- - ed router election algorithm. The value 0 sig- - nifies that the neighbor is not eligible to be- - come the designated router on this particular - network." - DEFVAL { 1 } - ::= { ospfv3NbmaNbrEntry 4 } - -ospfv3NbmaNbrRtrId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A 32-bit integer (represented as a type IpAd- - dress) uniquely identifying the neighboring - router in the Autonomous System. A value of - 0.0.0.0 is returned until a Hello is received - from the configured neighbor." - ::= { ospfv3NbmaNbrEntry 5 } - -ospfv3NbmaNbrState OBJECT-TYPE - SYNTAX INTEGER { - down(1), - attempt(2), - init(3), - twoWay(4), - exchangeStart(5), - exchange(6), - loading(7), - full(8) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The State of the relationship with this Neigh- - bor." - REFERENCE - "OSPF Version 2, Section 10.1 Neighbor States" - ::= { ospfv3NbmaNbrEntry 6 } - -ospfv3NbmaNbrStorageType OBJECT-TYPE - SYNTAX StorageType - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "The storage type for this conceptual row. - Conceptual rows having the value 'permanent' need not - allow write-access to any columnar objects in the row. - Manually configured entries will have a storage type - of nonVolatile while entries dynamically created as a - result of a lower-level protocol such as Inverse - Neighbor Discovery will have a storage type of - volatile." - DEFVAL { nonVolatile } - ::= { ospfv3NbmaNbrEntry 7 } - -ospfv3NbmaNbrStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable controls the status of the en- - try. The use of RowStatus is covered in more detail - in [6]." - ::= { ospfv3NbmaNbrEntry 8 } - --- OSPFv3 Virtual Neighbor Table - --- This table describes all virtual neighbors. --- Since Virtual Links are configured in the --- virtual interface table, this table is read-only. - -ospfv3VirtNbrTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3VirtNbrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table of virtual neighbor information." - REFERENCE - "OSPF Version 2, Section 15 Virtual Links" - ::= { ospfv3Objects 11 } - -ospfv3VirtNbrEntry OBJECT-TYPE - SYNTAX Ospfv3VirtNbrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Virtual neighbor information." - INDEX { ospfv3VirtNbrArea, - ospfv3VirtNbrRtrId } - ::= { ospfv3VirtNbrTable 1 } - -Ospfv3VirtNbrEntry ::= SEQUENCE { - ospfv3VirtNbrArea - AreaID, - ospfv3VirtNbrRtrId - RouterID, - ospfv3VirtNbrIfIndex - InterfaceIndex, - ospfv3VirtNbrAddressType - InetAddressType, - ospfv3VirtNbrAddress - InetAddress, - ospfv3VirtNbrOptions - Integer32, - ospfv3VirtNbrState - INTEGER, - ospfv3VirtNbrEvents - Counter32, - ospfv3VirtNbrLsRetransQLen - Gauge32, - ospfv3VirtNbrHelloSuppressed - TruthValue, - ospfv3VirtNbrIfId - InterfaceIndex, - ospfv3VirtNbrRestartHelperStatus - INTEGER, - ospfv3VirtNbrRestartHelperAge - UpToRefreshInterval, - ospfv3VirtNbrRestartHelperExitReason - INTEGER - } - -ospfv3VirtNbrArea OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Transit Area Identifier." - ::= { ospfv3VirtNbrEntry 1 } - -ospfv3VirtNbrRtrId OBJECT-TYPE - SYNTAX RouterID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A 32-bit integer uniquely identifying the - neighboring router in the Autonomous System." - ::= { ospfv3VirtNbrEntry 2 } - -ospfv3VirtNbrIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The local interface ID for the virtual link over - which the neighbor can be reached." - ::= { ospfv3VirtNbrEntry 3 } - -ospfv3VirtNbrAddressType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The address type of ospfv3VirtNbrAddress. Only IPv6 - addresses without zone index are expected." - ::= { ospfv3VirtNbrEntry 4 } - -ospfv3VirtNbrAddress OBJECT-TYPE - SYNTAX InetAddress (SIZE (16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The IPv6 address advertised by this Virtual Neighbor. - It must be a Site-Local or Global scope address." - ::= { ospfv3VirtNbrEntry 5 } - -ospfv3VirtNbrOptions OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "A Bit Mask corresponding to the neighbor's op- - tions field." - REFERENCE - "OSPF Version 3, Appendix A.2 the Options field" - ::= { ospfv3VirtNbrEntry 6 } - -ospfv3VirtNbrState OBJECT-TYPE - SYNTAX INTEGER { - down(1), - attempt(2), - init(3), - twoWay(4), - exchangeStart(5), - exchange(6), - loading(7), - full(8) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The state of the Virtual Neighbor Relation- - ship." - ::= { ospfv3VirtNbrEntry 7 } - -ospfv3VirtNbrEvents OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times this virtual link has - changed its state, or an error has occurred." - ::= { ospfv3VirtNbrEntry 8 } - -ospfv3VirtNbrLsRetransQLen OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The current length of the retransmission - queue." - ::= { ospfv3VirtNbrEntry 9 } - -ospfv3VirtNbrHelloSuppressed OBJECT-TYPE - SYNTAX TruthValue - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates whether Hellos are being suppressed - to the neighbor" - ::= { ospfv3VirtNbrEntry 10 } - -ospfv3VirtNbrIfId OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The interface ID that the neighbor advertises - in its Hello Packets on this virtual link, that is, - the neighbor's local interface ID." - ::= { ospfv3VirtNbrEntry 11 } - - ospfv3VirtNbrRestartHelperStatus OBJECT-TYPE - SYNTAX INTEGER { notHelping (1), - helping (2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Indicates whether the router is acting - as a hitless restart helper for the neighbor." - ::= { ospfv3VirtNbrEntry 12 } - -ospfv3VirtNbrRestartHelperAge OBJECT-TYPE - SYNTAX UpToRefreshInterval - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Remaining time in current OSPF hitless restart - interval, if the router is acting as a restart - helper for the neighbor." - ::= { ospfv3VirtNbrEntry 13 } - -ospfv3VirtNbrRestartHelperExitReason OBJECT-TYPE - SYNTAX INTEGER { none (1), -- not attempted - inProgress (2), -- restart in - -- progress - completed (3), -- successfully - -- completed - timedOut (4), -- timed out - topologyChanged (5) -- aborted due to - -- topology - -- change. - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Describes the outcome of the last attempt at acting - as a hitless restart helper for the neighbor." - ::= { ospfv3VirtNbrEntry 14 } - - --- --- The OSPFv3 Area Aggregate Table --- - -ospfv3AreaAggregateTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ospfv3AreaAggregateEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A range of IPv6 prefixes specified by a - prefix/prefix length pair. Note that if - ranges are configured such that one range sub- - sumes another range the most specific match is - the preferred one." - ::= { ospfv3Objects 12 } - -ospfv3AreaAggregateEntry OBJECT-TYPE - SYNTAX Ospfv3AreaAggregateEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A range of IPv6 prefixes specified by a - prefix/prefix length pair. Note that if - ranges are configured such that one range sub- - sumes another range the most specific match is - the preferred one." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - INDEX { ospfv3AreaAggregateAreaID, - ospfv3AreaAggregateAreaLsdbType, - ospfv3AreaAggregatePrefixType, - ospfv3AreaAggregatePrefix, - ospfv3AreaAggregatePrefixLength } - ::= { ospfv3AreaAggregateTable 1 } - -Ospfv3AreaAggregateEntry ::= SEQUENCE { - ospfv3AreaAggregateAreaID - AreaID, - ospfv3AreaAggregateAreaLsdbType - INTEGER, - ospfv3AreaAggregatePrefixType - InetAddressType, - ospfv3AreaAggregatePrefix - InetAddress, - ospfv3AreaAggregatePrefixLength - InetAddressPrefixLength, - ospfv3AreaAggregateStatus - RowStatus, - ospfv3AreaAggregateEffect - INTEGER, - ospfv3AreaAggregateRouteTag - INTEGER - } - -ospfv3AreaAggregateAreaID OBJECT-TYPE - SYNTAX AreaID - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Area the Address Aggregate is to be found - within." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3AreaAggregateEntry 1 } - -ospfv3AreaAggregateAreaLsdbType OBJECT-TYPE - SYNTAX INTEGER { - interAreaPrefixLsa(8195), -- 0x2003 - nssaExternalLsa(8199) -- 0x2007 - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The type of the Address Aggregate. This field - specifies the Area Lsdb type that this Address Ag- - gregate applies to." - REFERENCE - "OSPF Version 2, Appendix A.4.1 The Link State - Advertisement header" - ::= { ospfv3AreaAggregateEntry 2 } - -ospfv3AreaAggregatePrefixType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The prefix type of ospfv3AreaAggregatePrefix. Only - IPv6 addresses are expected." - ::= { ospfv3AreaAggregateEntry 4 } - -ospfv3AreaAggregatePrefix OBJECT-TYPE - SYNTAX InetAddress (SIZE (0..16)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The IPv6 Prefix." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3AreaAggregateEntry 5 } - -ospfv3AreaAggregatePrefixLength OBJECT-TYPE - SYNTAX InetAddressPrefixLength (3..128) - UNITS "bits" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The length of the prefix (in bits). A prefix can - not be shorter than 3 bits." - REFERENCE - "OSPF Version 2, Appendix C.2 Area parameters" - ::= { ospfv3AreaAggregateEntry 6 } - -ospfv3AreaAggregateStatus OBJECT-TYPE - SYNTAX RowStatus - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This variable controls the status of the en- - try. The use of RowStatus is covered in more detail - in [6]." - ::= { ospfv3AreaAggregateEntry 7 } - -ospfv3AreaAggregateEffect OBJECT-TYPE - SYNTAX INTEGER { - advertiseMatching(1), - doNotAdvertiseMatching(2) - } - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "Prefixes subsumed by ranges either trigger the - advertisement of the indicated aggregate (ad- - vertiseMatching), or result in the prefix not - being advertised at all outside the area." - DEFVAL { advertiseMatching } - ::= { ospfv3AreaAggregateEntry 8 } - -ospfv3AreaAggregateRouteTag OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-create - STATUS current - DESCRIPTION - "This tag is advertised only in the summarized - As-External LSA when summarizing from type-7 to - type-5." - DEFVAL { 0 } - ::= { ospfv3AreaAggregateEntry 9 } - - --- conformance information - -ospfv3Groups OBJECT IDENTIFIER ::= { ospfv3Conformance 1 } -ospfv3Compliances OBJECT IDENTIFIER ::= { ospfv3Conformance 2 } - --- compliance statements - -ospfv3Compliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION "The compliance statement " - MODULE -- this module - MANDATORY-GROUPS { - ospfv3BasicGroup, - ospfv3AreaGroup, - ospfv3IfGroup, - ospfv3VirtIfGroup, - ospfv3NbrGroup, - ospfv3NbmaNbrGroup, - ospfv3VirtNbrGroup, - ospfv3AreaAggregateGroup - } - - GROUP ospfv3AsLsdbGroup - DESCRIPTION - "This group is required for OSPFv3 systems that - display their AS-scope link state database." - - GROUP ospfv3AreaLsdbGroup - DESCRIPTION - "This group is required for OSPFv3 systems that - display their Area-scope link state database." - - GROUP ospfv3LinkLsdbGroup - DESCRIPTION - "This group is required for OSPFv3 systems that - display their Link-scope link state database." - - GROUP ospfv3HostGroup - DESCRIPTION - "This group is required for OSPFv3 systems that - support attached hosts." - - OBJECT ospfv3NbrAddressType - SYNTAX InetAddressType { ipv6(2) } - DESCRIPTION - "An implementation is only required to support IPv6 - address without zone index." - - OBJECT ospfv3VirtNbrAddressType - SYNTAX InetAddressType { ipv6(2) } - DESCRIPTION - "An implementation is only required to support IPv6 - address without zone index." - - ::= { ospfv3Compliances 1 } - --- units of conformance - -ospfv3BasicGroup OBJECT-GROUP - OBJECTS { - ospfv3RouterId, - ospfv3AdminStat, - ospfv3VersionNumber, - ospfv3AreaBdrRtrStatus, - ospfv3ASBdrRtrStatus, - ospfv3AsScopeLsaCount, - ospfv3AsScopeLsaCksumSum, - ospfv3OriginateNewLsas, - ospfv3RxNewLsas, - ospfv3ExtLsaCount, - ospfv3ExtAreaLsdbLimit, - ospfv3MulticastExtensions, - ospfv3ExitOverflowInterval, - ospfv3DemandExtensions, - ospfv3TrafficEngineeringSupport, - ospfv3ReferenceBandwidth, - ospfv3RestartSupport, - ospfv3RestartInterval, - ospfv3RestartStatus, - ospfv3RestartAge, - ospfv3RestartExitReason - } - STATUS current - DESCRIPTION - "These objects are required for OSPFv3 systems." - ::= { ospfv3Groups 1 } - - -ospfv3AreaGroup OBJECT-GROUP - OBJECTS { - ospfv3ImportAsExtern, - ospfv3AreaSpfRuns, - ospfv3AreaBdrRtrCount, - ospfv3AreaAsBdrRtrCount, - ospfv3AreaScopeLsaCount, - ospfv3AreaScopeLsaCksumSum, - ospfv3AreaSummary, - ospfv3AreaStatus, - ospfv3StubMetric, - ospfv3AreaNssaTranslatorRole, - ospfv3AreaNssaTranslatorState, - ospfv3AreaNssaTranslatorStabilityInterval, - ospfv3AreaNssaTranslatorEvents, - ospfv3AreaStubMetricType - } - STATUS current - DESCRIPTION - "These objects are required for OSPFv3 systems - supporting areas." - ::= { ospfv3Groups 2 } - -ospfv3AsLsdbGroup OBJECT-GROUP - OBJECTS { - ospfv3AsLsdbSequence, - ospfv3AsLsdbAge, - ospfv3AsLsdbChecksum, - ospfv3AsLsdbAdvertisement, - ospfv3AsLsdbTypeKnown - } - STATUS current - DESCRIPTION - "These objects are required for OSPFv3 systems - that display their AS-scope link state database." - ::= { ospfv3Groups 3 } - -ospfv3AreaLsdbGroup OBJECT-GROUP - OBJECTS { - ospfv3AreaLsdbSequence, - ospfv3AreaLsdbAge, - ospfv3AreaLsdbChecksum, - ospfv3AreaLsdbAdvertisement, - ospfv3AreaLsdbTypeKnown - } - STATUS current - DESCRIPTION - "These objects are required for OSPFv3 systems - that display their Area-scope link state database." - ::= { ospfv3Groups 4 } - -ospfv3LinkLsdbGroup OBJECT-GROUP - OBJECTS { - ospfv3LinkLsdbSequence, - ospfv3LinkLsdbAge, - ospfv3LinkLsdbChecksum, - ospfv3LinkLsdbAdvertisement, - ospfv3LinkLsdbTypeKnown - } - STATUS current - DESCRIPTION - "These objects are required for OSPFv3 systems - that display their Link-scope link state database." - ::= { ospfv3Groups 5 } - -ospfv3HostGroup OBJECT-GROUP - OBJECTS { - ospfv3HostMetric, - ospfv3HostStatus, - ospfv3HostAreaID - } - STATUS current - DESCRIPTION - "These objects are required for OSPFv3 systems - that support attached hosts." - ::= { ospfv3Groups 6 } - -ospfv3IfGroup OBJECT-GROUP - OBJECTS { - ospfv3IfAreaId, - ospfv3IfType, - ospfv3IfAdminStat, - ospfv3IfRtrPriority, - ospfv3IfTransitDelay, - ospfv3IfRetransInterval, - ospfv3IfHelloInterval, - ospfv3IfRtrDeadInterval, - ospfv3IfPollInterval, - ospfv3IfState, - ospfv3IfDesignatedRouter, - ospfv3IfBackupDesignatedRouter, - ospfv3IfEvents, - ospfv3IfStatus, - ospfv3IfMulticastForwarding, - ospfv3IfDemand, - ospfv3IfMetricValue, - ospfv3IfLinkScopeLsaCount, - ospfv3IfLinkLsaCksumSum, - ospfv3IfInstId, - ospfv3IfDemandNbrProbe, - ospfv3IfDemandNbrProbeRetxLimit, - ospfv3IfDemandNbrProbeInterval - } - STATUS current - DESCRIPTION - "These interface objects are required for - OSPFv3 systems." - ::= { ospfv3Groups 7 } - -ospfv3VirtIfGroup OBJECT-GROUP - OBJECTS { - ospfv3VirtIfIndex, - ospfv3VirtIfTransitDelay, - ospfv3VirtIfRetransInterval, - ospfv3VirtIfHelloInterval, - ospfv3VirtIfRtrDeadInterval, - ospfv3VirtIfState, - ospfv3VirtIfEvents, - ospfv3VirtIfStatus, - ospfv3VirtIfLinkScopeLsaCount, - ospfv3VirtIfLinkLsaCksumSum - } - STATUS current - DESCRIPTION - "These virtual interface objects are required for - OSPFv3 systems." - ::= { ospfv3Groups 8 } - -ospfv3NbrGroup OBJECT-GROUP - OBJECTS { - ospfv3NbrAddressType, - ospfv3NbrAddress, - ospfv3NbrOptions, - ospfv3NbrPriority, - ospfv3NbrState, - ospfv3NbrEvents, - ospfv3NbrLsRetransQLen, - ospfv3NbrHelloSuppressed, - ospfv3NbrIfId, - ospfv3NbrRestartHelperStatus, - ospfv3NbrRestartHelperAge, - ospfv3NbrRestartHelperExitReason - } - STATUS current - DESCRIPTION - "These neighbor objects are required for - OSPFv3 systems." - ::= { ospfv3Groups 9 } - -ospfv3NbmaNbrGroup OBJECT-GROUP - OBJECTS { - ospfv3NbmaNbrPriority, - ospfv3NbmaNbrRtrId, - ospfv3NbmaNbrState, - ospfv3NbmaNbrStorageType, - ospfv3NbmaNbrStatus - } - STATUS current - DESCRIPTION - "These NBMA neighbor objects are required for - OSPFv3 systems." - ::= { ospfv3Groups 10 } - -ospfv3VirtNbrGroup OBJECT-GROUP - OBJECTS { - ospfv3VirtNbrIfIndex, - ospfv3VirtNbrAddressType, - ospfv3VirtNbrAddress, - ospfv3VirtNbrOptions, - ospfv3VirtNbrState, - ospfv3VirtNbrEvents, - ospfv3VirtNbrLsRetransQLen, - ospfv3VirtNbrHelloSuppressed, - ospfv3VirtNbrIfId, - ospfv3VirtNbrRestartHelperStatus, - ospfv3VirtNbrRestartHelperAge, - ospfv3VirtNbrRestartHelperExitReason - } - STATUS current - DESCRIPTION - "These virtual neighbor objects are required for - OSPFv3 systems." - ::= { ospfv3Groups 11 } - -ospfv3AreaAggregateGroup OBJECT-GROUP - OBJECTS { - ospfv3AreaAggregateStatus, - ospfv3AreaAggregateEffect, - ospfv3AreaAggregateRouteTag - } - STATUS current - DESCRIPTION - "These area aggregate objects are required for - OSPFv3 systems." - ::= { ospfv3Groups 12 } - -END + OSPFV3-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, mib-2, + Counter32, Gauge32, Integer32, Unsigned32 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, TruthValue, RowStatus, TimeStamp + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF + InterfaceIndex + FROM IF-MIB + InetAddressType, InetAddress, InetAddressPrefixLength, + InetAddressIPv6 + FROM INET-ADDRESS-MIB + Metric, BigMetric, Status, + HelloRange, DesignatedRouterPriority + FROM OSPF-MIB; + + ospfv3MIB MODULE-IDENTITY + LAST-UPDATED "200908130000Z" + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + "WG E-Mail: ospf@ietf.org + WG Chairs: Acee Lindem + acee@redback.com + + Abhay Roy + akr@cisco.com + + Editors: Dan Joyal + Nortel + 600 Technology Park Drive + Billerica, MA 01821, USA + djoyal@nortel.com + + Vishwas Manral + IP Infusion + Almora, Uttarakhand + India + vishwas@ipinfusion.com" + DESCRIPTION + "The MIB module for OSPF version 3. + + Copyright (c) 2009 IETF Trust and the persons + identified as authors of the code. All rights + reserved. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that + the following conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + - Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or + other materials provided with the distribution. + + - Neither the name of Internet Society, IETF or IETF + Trust, nor the names of specific contributors, may be + used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + This version of this MIB module is part of RFC 5643; + see the RFC itself for full legal notices." + + REVISION "200908130000Z" + DESCRIPTION + "Initial version, published as RFC 5643" + ::= { mib-2 191 } + + -- Textual conventions + + Ospfv3UpToRefreshIntervalTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "The values one might be able to configure for + variables bounded by the Refresh Interval." + REFERENCE + "OSPF Version 2, Appendix B, Architectural Constants" + SYNTAX Unsigned32 (1..1800) + + Ospfv3DeadIntervalRangeTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "The range, in seconds, of dead interval value." + REFERENCE + "OSPF for IPv6, Appendix C.3, Router Interface + Parameters" + SYNTAX Unsigned32 (1..'FFFF'h) + + Ospfv3RouterIdTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "A 32-bit, unsigned integer uniquely identifying the + router in the Autonomous System. To ensure + uniqueness, this may default to the value of one of + the router's IPv4 host addresses if IPv4 is + configured on the router." + REFERENCE + "OSPF for IPv6, Appendix C.1, Global Parameters" + SYNTAX Unsigned32 (1..'FFFFFFFF'h) + + Ospfv3LsIdTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "A unique 32-bit identifier of the piece of the + routing domain that is being described by a link + state advertisement. In contrast to OSPFv2, the + Link State ID (LSID) has no addressing semantics." + REFERENCE + "OSPF Version 2, Section 12.1.4, Link State ID" + SYNTAX Unsigned32 (1..'FFFFFFFF'h) + + Ospfv3AreaIdTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "An OSPFv3 Area Identifier. A value of zero + identifies the backbone area." + REFERENCE + "OSPF for IPv6, Appendix C.3 Router Interface + Parameters" + SYNTAX Unsigned32 (0..'FFFFFFFF'h) + + Ospfv3IfInstIdTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "An OSPFv3 Interface Instance ID." + REFERENCE + "OSPF for IPv6, Appendix C.3, Router Interface + Parameters" + SYNTAX Unsigned32 (0..255) + + Ospfv3LsaSequenceTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and duplicate + link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number, the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6, LS sequence + number" + SYNTAX Integer32 + + Ospfv3LsaAgeTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "The age of the link state advertisement in + seconds. The high-order bit of the LS age + field is considered the DoNotAge bit for + support of on-demand circuits." + REFERENCE + "OSPF Version 2, Section 12.1.1, LS age; + Extending OSPF to Support Demand Circuits, + Section 2.2, The LS age field" + SYNTAX Unsigned32 (0..3600 | 32768..36368) + + -- Top-level structure of MIB + ospfv3Notifications OBJECT IDENTIFIER ::= { ospfv3MIB 0 } + ospfv3Objects OBJECT IDENTIFIER ::= { ospfv3MIB 1 } + ospfv3Conformance OBJECT IDENTIFIER ::= { ospfv3MIB 2 } + + -- OSPFv3 General Variables + + -- These parameters apply globally to the Router's + -- OSPFv3 Process. + + ospfv3GeneralGroup OBJECT IDENTIFIER ::= { ospfv3Objects 1 } + + ospfv3RouterId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A 32-bit unsigned integer uniquely identifying + the router in the Autonomous System. To ensure + uniqueness, this may default to the 32-bit + unsigned integer representation of one of + the router's IPv4 interface addresses (if IPv4 + is configured on the router). + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + REFERENCE + "OSPF for IPv6, Appendix C.1, Global Parameters" + ::= { ospfv3GeneralGroup 1 } + + ospfv3AdminStatus OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The administrative status of OSPFv3 in the + router. The value 'enabled' denotes that the + OSPFv3 Process is active on at least one + interface; 'disabled' disables it on all + interfaces. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + ::= { ospfv3GeneralGroup 2 } + + ospfv3VersionNumber OBJECT-TYPE + SYNTAX INTEGER { version3 (3) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The version number of OSPF for IPv6 is 3." + ::= { ospfv3GeneralGroup 3 } + + ospfv3AreaBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A flag to denote whether this router is an area + border router. The value of this object is true (1) + when the router is an area border router." + REFERENCE + "OSPF Version 2, Section 3, Splitting the AS into + Areas" + ::= { ospfv3GeneralGroup 4 } + + ospfv3ASBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A flag to note whether this router is + configured as an Autonomous System border router. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + REFERENCE + "OSPF Version 2, Section 3.3, Classification of + routers" + ::= { ospfv3GeneralGroup 5 } + + ospfv3AsScopeLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of AS-scope (e.g., AS-External) link state + advertisements in the link state database." + ::= { ospfv3GeneralGroup 6 } + + ospfv3AsScopeLsaCksumSum OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the LS checksums of + the AS-scoped link state advertisements + contained in the link state database. This sum + can be used to determine if there has been a + change in a router's link state database or + to compare the link state database of two + routers." + ::= { ospfv3GeneralGroup 7 } + + ospfv3OriginateNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of new link state advertisements + that have been originated. This number is + incremented each time the router originates a new + LSA. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3GeneralGroup 8 } + + ospfv3RxNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of link state advertisements + received that are determined to be new + instantiations. This number does not include + newer instantiations of self-originated link state + advertisements. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3GeneralGroup 9 } + + ospfv3ExtLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of External (LS type 0x4005) in the + link state database." + ::= { ospfv3GeneralGroup 10 } + + ospfv3ExtAreaLsdbLimit OBJECT-TYPE + SYNTAX Integer32 (-1..'7FFFFFFF'h) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The maximum number of non-default + AS-external-LSA entries that can be stored in the + link state database. If the value is -1, then + there is no limit. + + When the number of non-default AS-external-LSAs + in a router's link state database reaches + ospfv3ExtAreaLsdbLimit, the router enters Overflow + state. The router never holds more than + ospfv3ExtAreaLsdbLimit non-default AS-external-LSAs + in its database. ospfv3ExtAreaLsdbLimit MUST be set + identically in all routers attached to the OSPFv3 + backbone and/or any regular OSPFv3 area (i.e., + OSPFv3 stub areas and not-so-stubby-areas (NSSAs) + are excluded). + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + ::= { ospfv3GeneralGroup 11 } + + ospfv3ExitOverflowInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The number of seconds that, after entering + Overflow state, a router will attempt to leave + Overflow state. This allows the router to again + originate non-default, AS-External-LSAs. When + set to 0, the router will not leave Overflow + state until restarted. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + ::= { ospfv3GeneralGroup 12 } + + ospfv3DemandExtensions OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for demand circuits. + The value of this object is true (1) when + demand circuits are supported. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + REFERENCE + "OSPF Version 2; Extending OSPF to Support Demand + Circuits" + ::= { ospfv3GeneralGroup 13 } + + ospfv3ReferenceBandwidth OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "kilobits per second" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Reference bandwidth in kilobits per second for + calculating default interface metrics. The + default value is 100,000 KBPS (100 MBPS). + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + REFERENCE + "OSPF Version 2, Appendix C.3, Router interface + parameters" + DEFVAL { 100000 } + ::= { ospfv3GeneralGroup 14 } + + ospfv3RestartSupport OBJECT-TYPE + SYNTAX INTEGER { none(1), + plannedOnly(2), + plannedAndUnplanned(3) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for OSPF graceful restart. + Options include no restart support, only planned + + restarts, or both planned and unplanned restarts. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + REFERENCE "Graceful OSPF Restart, Appendix B.1, Global + Parameters (Minimum subset)" + ::= { ospfv3GeneralGroup 15 } + + ospfv3RestartInterval OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Configured OSPF graceful restart timeout interval. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + REFERENCE "Graceful OSPF Restart, Appendix B.1, Global + Parameters (Minimum subset)" + DEFVAL { 120 } + ::= { ospfv3GeneralGroup 16 } + + ospfv3RestartStrictLsaChecking OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Indicates if strict LSA checking is enabled for + graceful restart. A value of true (1) indicates that + strict LSA checking is enabled. + + This object is persistent, and when written, + the entity SHOULD save the change to non-volatile + storage." + REFERENCE "Graceful OSPF Restart, Appendix B.2, Global + Parameters (Optional)" + DEFVAL { true } + ::= { ospfv3GeneralGroup 17 } + + ospfv3RestartStatus OBJECT-TYPE + SYNTAX INTEGER { notRestarting(1), + plannedRestart(2), + unplannedRestart(3) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current status of OSPF graceful restart capability." + ::= { ospfv3GeneralGroup 18 } + + ospfv3RestartAge OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Remaining time in the current OSPF graceful restart + interval." + ::= { ospfv3GeneralGroup 19 } + + ospfv3RestartExitReason OBJECT-TYPE + SYNTAX INTEGER { none(1), + inProgress(2), + completed(3), + timedOut(4), + topologyChanged(5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Describes the outcome of the last attempt at a + graceful restart. + + none: no restart has yet been attempted. + inProgress: a restart attempt is currently underway. + completed: the last restart completed successfully. + timedOut: the last restart timed out. + topologyChanged: the last restart was aborted due to + a topology change." + ::= { ospfv3GeneralGroup 20 } + + ospfv3NotificationEnable OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This object provides a coarse level of control + over the generation of OSPFv3 notifications. + + If this object is set to true (1), then it enables + the generation of OSPFv3 notifications. If it is + set to false (2), these notifications are not + generated. + + This object is persistent, and when written, the + entity SHOULD save the change to non-volatile + storage." + ::= { ospfv3GeneralGroup 21 } + +ospfv3StubRouterSupport OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The router's support for stub router functionality. An + object value of true (1) indicates that stub router + functionality is supported." + REFERENCE + "OSPF Stub Router Advertisement" + ::= { ospfv3GeneralGroup 22 } + + ospfv3StubRouterAdvertisement OBJECT-TYPE + SYNTAX INTEGER { + doNotAdvertise(1), + advertise(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This object controls the advertisement of + stub LSAs by the router. The value + doNotAdvertise (1) will result in the advertisement + of standard LSAs and is the default value. + + This object is persistent, and when written, + the entity SHOULD save the change to non-volatile + storage." + REFERENCE + "OSPF Stub Router Advertisement, Section 2, Proposed + Solution" + DEFVAL { doNotAdvertise } + ::= { ospfv3GeneralGroup 23 } + +ospfv3DiscontinuityTime OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion + at which any one of this MIB's counters suffered + a discontinuity. + + If no such discontinuities have occurred since the last + re-initialization of the local management subsystem, + then this object contains a zero value." + ::= { ospfv3GeneralGroup 24 } + + ospfv3RestartTime OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime on the most recent occasion + at which the ospfv3RestartExitReason was updated." + ::= { ospfv3GeneralGroup 25 } + + -- The OSPFv3 Area Data Structure contains information + -- regarding the various areas. The interfaces and + -- virtual links are configured as part of these areas. + -- Area 0, by definition, is the backbone area. + + ospfv3AreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3AreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured + parameters and cumulative statistics of the router's + attached areas. The interfaces and + virtual links are configured as part of these areas. + Area 0, by definition, is the backbone area." + REFERENCE + "OSPF Version 2, Section 6, The Area Data + Structure" + ::= { ospfv3Objects 2 } + + ospfv3AreaEntry OBJECT-TYPE + SYNTAX Ospfv3AreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured + parameters and cumulative statistics of one of the + router's attached areas. + + The information in this table is persistent, + and when written, the entity SHOULD save the a + change to non-volatile storage." + INDEX { ospfv3AreaId } + ::= { ospfv3AreaTable 1 } + + Ospfv3AreaEntry ::= SEQUENCE { + ospfv3AreaId + Ospfv3AreaIdTC, + ospfv3AreaImportAsExtern + INTEGER, + ospfv3AreaSpfRuns + Counter32, + ospfv3AreaBdrRtrCount + Gauge32, + ospfv3AreaAsBdrRtrCount + Gauge32, + ospfv3AreaScopeLsaCount + Gauge32, + ospfv3AreaScopeLsaCksumSum + Unsigned32, + ospfv3AreaSummary + INTEGER, + ospfv3AreaRowStatus + RowStatus, + ospfv3AreaStubMetric + BigMetric, + ospfv3AreaNssaTranslatorRole + INTEGER, + ospfv3AreaNssaTranslatorState + INTEGER, + ospfv3AreaNssaTranslatorStabInterval + Unsigned32, + ospfv3AreaNssaTranslatorEvents + Counter32, + ospfv3AreaStubMetricType + INTEGER, + ospfv3AreaTEEnabled + TruthValue + } + + ospfv3AreaId OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A 32-bit unsigned integer uniquely identifying an area. + Area ID 0 is used for the OSPFv3 backbone." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + ::= { ospfv3AreaEntry 1 } + + ospfv3AreaImportAsExtern OBJECT-TYPE + SYNTAX INTEGER { + importExternal(1), -- normal area + importNoExternal(2), -- stub area + importNssa(3) -- not-so-stubby-area + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether an area is a stub area, NSSA, or + standard area. AS-scope LSAs are not imported into stub + areas or NSSAs. NSSAs import AS-External data as NSSA + LSAs that have Area-scope." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + DEFVAL { importExternal } + ::= { ospfv3AreaEntry 2 } + + ospfv3AreaSpfRuns OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that the intra-area route + table has been calculated using this area's + link state database. This is typically done + using Dijkstra's algorithm. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3AreaEntry 3 } + + ospfv3AreaBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of area border routers + reachable within this area. This is initially zero, + and is calculated in each Shortest Path First (SPF) + pass." + DEFVAL { 0 } + ::= { ospfv3AreaEntry 4 } + + ospfv3AreaAsBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Autonomous System border + routers reachable within this area. This is + initially zero, and is calculated in each SPF + pass." + DEFVAL { 0 } + ::= { ospfv3AreaEntry 5 } + + ospfv3AreaScopeLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Area-scope link state + advertisements in this area's link state + database." + DEFVAL { 0 } + ::= { ospfv3AreaEntry 6 } + + ospfv3AreaScopeLsaCksumSum OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the Area-scope link state + advertisements' LS checksums contained in this + area's link state database. The sum can be used + to determine if there has been a change in a + router's link state database or to compare the + link state database of two routers." + ::= { ospfv3AreaEntry 7 } + + ospfv3AreaSummary OBJECT-TYPE + SYNTAX INTEGER { + noAreaSummary(1), + sendAreaSummary(2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The variable ospfv3AreaSummary controls the + import of Inter-Area LSAs into stub and + NSSA areas. It has no effect on other areas. + + If it is noAreaSummary, the router will neither + originate nor propagate Inter-Area LSAs into the + stub or NSSA area. It will only advertise a + default route. + + If it is sendAreaSummary, the router will both + summarize and propagate Inter-Area LSAs." + DEFVAL { sendAreaSummary } + ::= { ospfv3AreaEntry 8 } + + ospfv3AreaRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object permits management of the table by + facilitating actions such as row creation, + construction, and destruction. + + The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ospfv3AreaEntry 9 } + + ospfv3AreaStubMetric OBJECT-TYPE + SYNTAX BigMetric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric value advertised for the default route + into stub and NSSA areas. By default, this equals the + least metric among the interfaces to other areas." + ::= { ospfv3AreaEntry 10 } + + ospfv3AreaNssaTranslatorRole OBJECT-TYPE + SYNTAX INTEGER { always(1), candidate(2) } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates an NSSA border router's policy to + perform NSSA translation of NSSA-LSAs into + AS-External-LSAs." + DEFVAL { candidate } + ::= { ospfv3AreaEntry 11 } + + ospfv3AreaNssaTranslatorState OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + elected(2), + disabled(3) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates if and how an NSSA border router is + performing NSSA translation of NSSA-LSAs into + AS-External-LSAs. When this object is set to + 'enabled', the NSSA border router's + ospfv3AreaNssaTranslatorRole has been set to 'always'. + When this object is set to 'elected', a candidate + NSSA border router is translating NSSA-LSAs into + AS-External-LSAs. When this object is set to + 'disabled', a candidate NSSA Border router is NOT + translating NSSA-LSAs into AS-External-LSAs." + ::= { ospfv3AreaEntry 12 } + + ospfv3AreaNssaTranslatorStabInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The stability interval defined as the number of + seconds after an elected translator determines its + services are no longer required that it should + continue to perform its translation duties." + DEFVAL { 40 } + ::= { ospfv3AreaEntry 13 } + + ospfv3AreaNssaTranslatorEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates the number of Translator state changes + that have occurred since the last start-up of the + OSPFv3 routing process. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3AreaEntry 14 } + + ospfv3AreaStubMetricType OBJECT-TYPE + SYNTAX INTEGER { + ospfv3Metric(1), -- OSPF Metric + comparableCost(2), -- external type 1 + nonComparable(3) -- external type 2 + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable assigns the type of metric + advertised as a default route." + DEFVAL { ospfv3Metric } + ::= { ospfv3AreaEntry 15 } + + ospfv3AreaTEEnabled OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether or not traffic engineering + is enabled in the area. The object is set + to the value true (1) to enable traffic engineering. + Traffic engineering is disabled by default." + DEFVAL { false } + ::= { ospfv3AreaEntry 16 } + + -- OSPFv3 AS-Scope Link State Database + + ospfv3AsLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3AsLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPFv3 Process's AS-scope link state database + (LSDB). The LSDB contains the AS-scope link state + advertisements from throughout the areas that the + device is attached to." + ::= { ospfv3Objects 3 } + + ospfv3AsLsdbEntry OBJECT-TYPE + SYNTAX Ospfv3AsLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single AS-scope link state advertisement." + INDEX { ospfv3AsLsdbType, + ospfv3AsLsdbRouterId, + ospfv3AsLsdbLsid } + ::= { ospfv3AsLsdbTable 1 } + + Ospfv3AsLsdbEntry ::= SEQUENCE { + ospfv3AsLsdbType + Unsigned32, + ospfv3AsLsdbRouterId + Ospfv3RouterIdTC, + ospfv3AsLsdbLsid + Ospfv3LsIdTC, + ospfv3AsLsdbSequence + Ospfv3LsaSequenceTC, + ospfv3AsLsdbAge + Ospfv3LsaAgeTC, + ospfv3AsLsdbChecksum + Integer32, + ospfv3AsLsdbAdvertisement + OCTET STRING, + ospfv3AsLsdbTypeKnown + TruthValue + } + + ospfv3AsLsdbType OBJECT-TYPE + SYNTAX Unsigned32(0..'FFFFFFFF'h) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate + advertisement format. AS-scope LSAs not recognized + by the router may be stored in the database." + ::= { ospfv3AsLsdbEntry 1 } + + ospfv3AsLsdbRouterId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The 32-bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1, Global parameters" + ::= { ospfv3AsLsdbEntry 2 } + + ospfv3AsLsdbLsid OBJECT-TYPE + SYNTAX Ospfv3LsIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Link State ID is an LS type-specific field + containing a unique identifier; + it identifies the piece of the routing domain + that is being described by the advertisement. + In contrast to OSPFv2, the LSID has no + addressing semantics." + ::= { ospfv3AsLsdbEntry 3 } + + -- Note that the OSPF sequence number is a 32-bit signed + -- integer. It starts with the value '80000001'h + -- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h. + -- Thus, a typical sequence number will be very negative. + + ospfv3AsLsdbSequence OBJECT-TYPE + SYNTAX Ospfv3LsaSequenceTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and duplicate + link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number, the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6, LS sequence + number" + ::= { ospfv3AsLsdbEntry 4 } + + ospfv3AsLsdbAge OBJECT-TYPE + SYNTAX Ospfv3LsaAgeTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state + advertisement in seconds. The high-order bit + of the LS age field is considered the DoNotAge + bit for support of on-demand circuits." + REFERENCE + "OSPF Version 2, Section 12.1.1, LS age; + Extending OSPF to Support Demand Circuits, + Section 2.2, The LS age field." + ::= { ospfv3AsLsdbEntry 5 } + + ospfv3AsLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO + connectionless datagrams; it is commonly + referred to as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7, LS checksum" + ::= { ospfv3AsLsdbEntry 6 } + + ospfv3AsLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire link state advertisement, including + its header." + ::= { ospfv3AsLsdbEntry 7 } + + ospfv3AsLsdbTypeKnown OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value true (1) indicates that the LSA type + is recognized by this router." + ::= { ospfv3AsLsdbEntry 8 } + + -- OSPFv3 Area-Scope Link State Database + + ospfv3AreaLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3AreaLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPFv3 Process's Area-scope LSDB. + The LSDB contains the Area-scope link state + advertisements from throughout the area that the + device is attached to." + ::= { ospfv3Objects 4 } + + ospfv3AreaLsdbEntry OBJECT-TYPE + SYNTAX Ospfv3AreaLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Area-scope link state advertisement." + INDEX { ospfv3AreaLsdbAreaId, + ospfv3AreaLsdbType, + ospfv3AreaLsdbRouterId, + ospfv3AreaLsdbLsid } + ::= { ospfv3AreaLsdbTable 1 } + + Ospfv3AreaLsdbEntry ::= SEQUENCE { + ospfv3AreaLsdbAreaId + Ospfv3AreaIdTC, + ospfv3AreaLsdbType + Unsigned32, + ospfv3AreaLsdbRouterId + Ospfv3RouterIdTC, + ospfv3AreaLsdbLsid + Ospfv3LsIdTC, + ospfv3AreaLsdbSequence + Ospfv3LsaSequenceTC, + ospfv3AreaLsdbAge + Ospfv3LsaAgeTC, + ospfv3AreaLsdbChecksum + Integer32, + ospfv3AreaLsdbAdvertisement + OCTET STRING, + ospfv3AreaLsdbTypeKnown + TruthValue + } + + ospfv3AreaLsdbAreaId OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The 32-bit identifier of the Area from which the + LSA was received." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + ::= { ospfv3AreaLsdbEntry 1 } + + ospfv3AreaLsdbType OBJECT-TYPE + SYNTAX Unsigned32(0..'FFFFFFFF'h) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate + advertisement format. Area-scope LSAs unrecognized + by the router are also stored in this database." + ::= { ospfv3AreaLsdbEntry 2 } + + ospfv3AreaLsdbRouterId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The 32-bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1, Global parameters" + ::= { ospfv3AreaLsdbEntry 3 } + + ospfv3AreaLsdbLsid OBJECT-TYPE + SYNTAX Ospfv3LsIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Link State ID is an LS type-specific field + containing a unique identifier; + it identifies the piece of the routing domain + that is being described by the advertisement. + In contrast to OSPFv2, the LSID has no + addressing semantics." + ::= { ospfv3AreaLsdbEntry 4 } + + -- Note that the OSPF sequence number is a 32-bit signed + -- integer. It starts with the value '80000001'h + -- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h. + -- Thus, a typical sequence number will be very negative. + + ospfv3AreaLsdbSequence OBJECT-TYPE + SYNTAX Ospfv3LsaSequenceTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and + duplicate link state advertisements. The space + of sequence numbers is linearly ordered. The + larger the sequence number, the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6, LS sequence + number" + ::= { ospfv3AreaLsdbEntry 5 } + + ospfv3AreaLsdbAge OBJECT-TYPE + SYNTAX Ospfv3LsaAgeTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state + advertisement in seconds. The high-order bit + of the LS age field is considered the DoNotAge + bit for support of on-demand circuits." + REFERENCE + "OSPF Version 2, Section 12.1.1, LS age; + Extending OSPF to Support Demand Circuits, + Section 2.2, The LS age field." + ::= { ospfv3AreaLsdbEntry 6 } + + ospfv3AreaLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO + connectionless datagrams; it is commonly + referred to as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7, LS checksum" + ::= { ospfv3AreaLsdbEntry 7 } + + ospfv3AreaLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire link state advertisement, including + its header." + ::= { ospfv3AreaLsdbEntry 8 } + + ospfv3AreaLsdbTypeKnown OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value true (1) indicates that the LSA type is + recognized by this router." + ::= { ospfv3AreaLsdbEntry 9 } + + -- OSPFv3 Link-Scope Link State Database, for non-virtual interfaces + + ospfv3LinkLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3LinkLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPFv3 Process's Link-scope LSDB for non-virtual + interfaces. The LSDB contains the Link-scope link + state advertisements from the interfaces that the + device is attached to." + ::= { ospfv3Objects 5 } + + ospfv3LinkLsdbEntry OBJECT-TYPE + SYNTAX Ospfv3LinkLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link-scope link state advertisement." + INDEX { ospfv3LinkLsdbIfIndex, + ospfv3LinkLsdbIfInstId, + ospfv3LinkLsdbType, + ospfv3LinkLsdbRouterId, + ospfv3LinkLsdbLsid } + ::= { ospfv3LinkLsdbTable 1 } + + Ospfv3LinkLsdbEntry ::= SEQUENCE { + ospfv3LinkLsdbIfIndex + InterfaceIndex, + ospfv3LinkLsdbIfInstId + Ospfv3IfInstIdTC, + ospfv3LinkLsdbType + Unsigned32, + ospfv3LinkLsdbRouterId + Ospfv3RouterIdTC, + ospfv3LinkLsdbLsid + Ospfv3LsIdTC, + ospfv3LinkLsdbSequence + Ospfv3LsaSequenceTC, + ospfv3LinkLsdbAge + Ospfv3LsaAgeTC, + ospfv3LinkLsdbChecksum + Integer32, + ospfv3LinkLsdbAdvertisement + OCTET STRING, + ospfv3LinkLsdbTypeKnown + TruthValue + } + + ospfv3LinkLsdbIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The identifier of the link from which the LSA + was received." + ::= { ospfv3LinkLsdbEntry 1 } + + ospfv3LinkLsdbIfInstId OBJECT-TYPE + SYNTAX Ospfv3IfInstIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The identifier of the interface instance from + which the LSA was received." + ::= { ospfv3LinkLsdbEntry 2 } + + ospfv3LinkLsdbType OBJECT-TYPE + SYNTAX Unsigned32(0..'FFFFFFFF'h) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate + advertisement format. Link-scope LSAs unrecognized + by the router are also stored in this database." + ::= { ospfv3LinkLsdbEntry 3 } + + ospfv3LinkLsdbRouterId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The 32-bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1, Global parameters" + ::= { ospfv3LinkLsdbEntry 4 } + + ospfv3LinkLsdbLsid OBJECT-TYPE + SYNTAX Ospfv3LsIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Link State ID is an LS type-specific field + containing a unique identifier; + it identifies the piece of the routing domain + that is being described by the advertisement. + In contrast to OSPFv2, the LSID has no + addressing semantics. However, in OSPFv3 + the Link State ID always contains the flooding + scope of the LSA." + ::= { ospfv3LinkLsdbEntry 5 } + + -- Note that the OSPF sequence number is a 32-bit signed + -- integer. It starts with the value '80000001'h + -- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h. + -- Thus, a typical sequence number will be very negative. + + ospfv3LinkLsdbSequence OBJECT-TYPE + SYNTAX Ospfv3LsaSequenceTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and duplicate + link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number, the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6, LS sequence + number" + ::= { ospfv3LinkLsdbEntry 6 } + + ospfv3LinkLsdbAge OBJECT-TYPE + SYNTAX Ospfv3LsaAgeTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state + advertisement in seconds. The high-order bit + of the LS age field is considered the DoNotAge + bit for support of on-demand circuits." + REFERENCE + "OSPF Version 2, Section 12.1.1, LS age; + Extending OSPF to Support Demand Circuits, + Section 2.2, The LS age field." + ::= { ospfv3LinkLsdbEntry 7 } + + ospfv3LinkLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO + connectionless datagrams; it is commonly + referred to as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7, LS checksum" + ::= { ospfv3LinkLsdbEntry 8 } + + ospfv3LinkLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire link state advertisement, including + its header." + ::= { ospfv3LinkLsdbEntry 9 } + + ospfv3LinkLsdbTypeKnown OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value true (1) indicates that the LSA type is + recognized by this router." + ::= { ospfv3LinkLsdbEntry 10 } + + -- OSPF Host Table + + ospfv3HostTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3HostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Host/Metric Table indicates what hosts are + directly attached to the router and their + corresponding metrics." + REFERENCE + "OSPF Version 2, Appendix C.7, Host route + parameters" + ::= { ospfv3Objects 6 } + + ospfv3HostEntry OBJECT-TYPE + SYNTAX Ospfv3HostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A metric to be advertised when a given host is + reachable. + + The information in this table is persistent, and + when written, the entity SHOULD save the change + to non-volatile storage." + INDEX { ospfv3HostAddressType, + ospfv3HostAddress } + ::= { ospfv3HostTable 1 } + + Ospfv3HostEntry ::= SEQUENCE { + ospfv3HostAddressType + InetAddressType, + ospfv3HostAddress + InetAddress, + ospfv3HostMetric + Metric, + ospfv3HostRowStatus + RowStatus, + ospfv3HostAreaID + Ospfv3AreaIdTC + } + + ospfv3HostAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of ospfv3HostAddress. Only IPv6 + global address type is expected." + REFERENCE + "OSPF Version 2, Appendix C.7, Host route + parameters" + ::= { ospfv3HostEntry 1 } + + ospfv3HostAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IPv6 address of the host. Must be an + IPv6 global address." + REFERENCE + "OSPF Version 2, Appendix C.7, Host route + parameters" + ::= { ospfv3HostEntry 2 } + + ospfv3HostMetric OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric to be advertised." + REFERENCE + "OSPF Version 2, Appendix C.7, Host route + parameters" + ::= { ospfv3HostEntry 3 } + + ospfv3HostRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object permits management of the table by + facilitating actions such as row creation, + construction, and destruction. + + The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ospfv3HostEntry 4 } + + ospfv3HostAreaID OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Area the host entry is to be found within. + By default, the area for the subsuming OSPFv3 + interface, or Area 0 if there is no subsuming + interface." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + ::= { ospfv3HostEntry 5 } + + -- OSPFv3 Interface Table + + ospfv3IfTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3IfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPFv3 Interface Table describes the + interfaces from the viewpoint of OSPFv3." + REFERENCE + "OSPF for IPv6, Appendix C.3, Router Interface + Parameters" + ::= { ospfv3Objects 7 } + + ospfv3IfEntry OBJECT-TYPE + SYNTAX Ospfv3IfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPFv3 Interface Entry describes one + interface from the viewpoint of OSPFv3. + + The information in this table is persistent, + and when written, the entity SHOULD save the + change to non-volatile storage." + INDEX { ospfv3IfIndex, + ospfv3IfInstId } + ::= { ospfv3IfTable 1 } + + Ospfv3IfEntry ::= SEQUENCE { + ospfv3IfIndex + InterfaceIndex, + ospfv3IfInstId + Ospfv3IfInstIdTC, + ospfv3IfAreaId + Ospfv3AreaIdTC, + ospfv3IfType + INTEGER, + ospfv3IfAdminStatus + Status, + ospfv3IfRtrPriority + DesignatedRouterPriority, + ospfv3IfTransitDelay + Ospfv3UpToRefreshIntervalTC, + ospfv3IfRetransInterval + Ospfv3UpToRefreshIntervalTC, + ospfv3IfHelloInterval + HelloRange, + ospfv3IfRtrDeadInterval + Ospfv3DeadIntervalRangeTC, + ospfv3IfPollInterval + Unsigned32, + ospfv3IfState + INTEGER, + ospfv3IfDesignatedRouter + Ospfv3RouterIdTC, + ospfv3IfBackupDesignatedRouter + Ospfv3RouterIdTC, + ospfv3IfEvents + Counter32, + ospfv3IfRowStatus + RowStatus, + ospfv3IfDemand + TruthValue, + ospfv3IfMetricValue + Metric, + ospfv3IfLinkScopeLsaCount + Gauge32, + ospfv3IfLinkLsaCksumSum + Unsigned32, + ospfv3IfDemandNbrProbe + TruthValue, + ospfv3IfDemandNbrProbeRetransLimit + Unsigned32, + ospfv3IfDemandNbrProbeInterval + Unsigned32, + ospfv3IfTEDisabled + TruthValue, + ospfv3IfLinkLSASuppression + TruthValue + } + + ospfv3IfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The interface index of this OSPFv3 interface. + It corresponds to the interface index of the + IPv6 interface on which OSPFv3 is configured." + ::= { ospfv3IfEntry 1 } + + ospfv3IfInstId OBJECT-TYPE + SYNTAX Ospfv3IfInstIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Enables multiple interface instances of OSPFv3 + to be run over a single link. Each interface + instance would be assigned a separate ID. This ID + has local link significance only." + ::= { ospfv3IfEntry 2 } + + ospfv3IfAreaId OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the area + to which the interface connects. Area ID + 0 is used for the OSPFv3 backbone." + DEFVAL { 0 } + ::= { ospfv3IfEntry 3 } + + ospfv3IfType OBJECT-TYPE + SYNTAX INTEGER { + broadcast(1), + nbma(2), + pointToPoint(3), + pointToMultipoint(5) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPFv3 interface type." + ::= { ospfv3IfEntry 4 } + + ospfv3IfAdminStatus OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPFv3 interface's administrative status. + The value formed on the interface; the interface + will be advertised as an internal route to some + area. The value 'disabled' denotes that the + interface is external to OSPFv3. + + Note that a value of 'disabled' for the object + ospfv3AdminStatus will override a value of + 'enabled' for the interface." + DEFVAL { enabled } + ::= { ospfv3IfEntry 5 } + + ospfv3IfRtrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this interface. Used in + multi-access networks, this field is used in + the designated-router election algorithm. The + value 0 signifies that the router is not + eligible to become the Designated Router on this + particular network. In the event of a tie in + this value, routers will use their Router ID as + a tie breaker." + DEFVAL { 1 } + ::= { ospfv3IfEntry 6 } + + ospfv3IfTransitDelay OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to transmit + a Link State Update packet over this interface. LSAs + contained in the update packet must have their age + incremented by this amount before transmission. This + value should take into account the transmission and + propagation delays of the interface." + REFERENCE + "OSPF for IPv6, Appendix C.3, Router Interface + Parameters." + DEFVAL { 1 } + ::= { ospfv3IfEntry 7 } + + ospfv3IfRetransInterval OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link state + advertisement retransmissions for adjacencies + + belonging to this interface. This value is + also used when retransmitting database + description and Link State Request packets." + DEFVAL { 5 } + ::= { ospfv3IfEntry 8 } + + ospfv3IfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the + interface. This value must be the same for all + routers attached to a common network." + DEFVAL { 10 } + ::= { ospfv3IfEntry 9 } + + ospfv3IfRtrDeadInterval OBJECT-TYPE + SYNTAX Ospfv3DeadIntervalRangeTC + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before its + neighbors declare the router down on the interface. + This should be some multiple of the Hello interval. + This value must be the same for all routers attached + to a common network." + DEFVAL { 40 } + ::= { ospfv3IfEntry 10 } + + ospfv3IfPollInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The larger time interval, in seconds, between + the Hello packets sent to an inactive, + non-broadcast multi-access neighbor." + DEFVAL { 120 } + ::= { ospfv3IfEntry 11 } + + ospfv3IfState OBJECT-TYPE + SYNTAX INTEGER { + down(1), + loopback(2), + waiting(3), + pointToPoint(4), + designatedRouter(5), + backupDesignatedRouter(6), + otherDesignatedRouter(7), + standby(8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The OSPFv3 interface state. An interface may be + in standby state if there are multiple interfaces + on the link and another interface is active. The + interface may be in Down state if the underlying + IPv6 interface is down or if the admin status is + 'disabled' either globally or for the interface." + ::= { ospfv3IfEntry 12 } + + ospfv3IfDesignatedRouter OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Router ID of the Designated Router." + ::= { ospfv3IfEntry 13 } + + ospfv3IfBackupDesignatedRouter OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Router ID of the Backup Designated + Router." + ::= { ospfv3IfEntry 14 } + + ospfv3IfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this OSPFv3 interface has + changed its state or an error has occurred. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3IfEntry 15 } + + ospfv3IfRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object permits management of the table by + facilitating actions such as row creation, + construction, and destruction. + + The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ospfv3IfEntry 16 } + + ospfv3IfDemand OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether Demand OSPFv3 procedures + (Hello suppression to FULL neighbors and + setting the DoNotAge flag on propagated LSAs) + should be performed on this interface." + DEFVAL { false } + ::= { ospfv3IfEntry 17 } + + ospfv3IfMetricValue OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric assigned to this interface. + The default value of the metric is + 'Reference Bandwidth / ifSpeed'. The value + of the reference bandwidth can be set + in the ospfv3ReferenceBandwidth object." + ::= { ospfv3IfEntry 18 } + + ospfv3IfLinkScopeLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Link-scope link state + advertisements in this link's link state + database." + ::= { ospfv3IfEntry 19 } + + ospfv3IfLinkLsaCksumSum OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the Link-scope link state + advertisements' LS checksums contained in this + link's link state database. The sum can be used + to determine if there has been a change in a + router's link state database or to compare the + link state database of two routers." + ::= { ospfv3IfEntry 20 } + + ospfv3IfDemandNbrProbe OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether or not neighbor probing is + enabled to determine whether or not the neighbor + is inactive. Neighbor probing is disabled by + default." + DEFVAL { false } + ::= { ospfv3IfEntry 21 } + +ospfv3IfDemandNbrProbeRetransLimit OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of consecutive LSA retransmissions before + the neighbor is deemed inactive and the neighbor + adjacency is brought down." + DEFVAL { 10 } + ::= { ospfv3IfEntry 22} + +ospfv3IfDemandNbrProbeInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Defines how often the neighbor will be probed." + DEFVAL { 120 } + ::= { ospfv3IfEntry 23 } + + ospfv3IfTEDisabled OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether or not traffic engineering + is disabled on the interface when traffic + engineering is enabled in the area where the + interface is attached. The object is set + to the value true (1) to disable traffic engineering + on the interface. Traffic engineering is enabled + by default on the interface when traffic engineering + is enabled in the area where the interface is + attached." + DEFVAL { false } + ::= { ospfv3IfEntry 24 } + + ospfv3IfLinkLSASuppression OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Specifies whether or not link LSA origination is + suppressed for broadcast or NBMA interface types. + The object is set to value true (1) to suppress + the origination." + REFERENCE + "OSPF for IPv6, Appendix C.3, Router Interface + Parameters" + DEFVAL { false } + ::= { ospfv3IfEntry 25 } + + -- OSPFv3 Virtual Interface Table + + ospfv3VirtIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3VirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about this router's virtual + interfaces that the OSPFv3 Process is configured + to carry on." + REFERENCE + "OSPF for IPv6, Appendix C.4, Virtual Link + Parameters" + ::= { ospfv3Objects 8 } + + ospfv3VirtIfEntry OBJECT-TYPE + SYNTAX Ospfv3VirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a single virtual interface. + + The information in this table is persistent, + and when written, the entity SHOULD save the + change to non-volatile storage." + INDEX { ospfv3VirtIfAreaId, + ospfv3VirtIfNeighbor } + ::= { ospfv3VirtIfTable 1 } + + Ospfv3VirtIfEntry ::= SEQUENCE { + ospfv3VirtIfAreaId + Ospfv3AreaIdTC, + ospfv3VirtIfNeighbor + Ospfv3RouterIdTC, + ospfv3VirtIfIndex + InterfaceIndex, + ospfv3VirtIfInstId + Ospfv3IfInstIdTC, + ospfv3VirtIfTransitDelay + Ospfv3UpToRefreshIntervalTC, + ospfv3VirtIfRetransInterval + Ospfv3UpToRefreshIntervalTC, + ospfv3VirtIfHelloInterval + HelloRange, + ospfv3VirtIfRtrDeadInterval + Ospfv3DeadIntervalRangeTC, + ospfv3VirtIfState + INTEGER, + ospfv3VirtIfEvents + Counter32, + ospfv3VirtIfRowStatus + RowStatus, + ospfv3VirtIfLinkScopeLsaCount + Gauge32, + ospfv3VirtIfLinkLsaCksumSum + Unsigned32 + } + + ospfv3VirtIfAreaId OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The transit area that the virtual link + traverses. By definition, this is not + Area 0." + ::= { ospfv3VirtIfEntry 1 } + + ospfv3VirtIfNeighbor OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Router ID of the virtual neighbor." + ::= { ospfv3VirtIfEntry 2 } + + ospfv3VirtIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local interface index assigned by the + OSPFv3 Process to this OSPFv3 virtual interface. + It is advertised in Hellos sent over the virtual + link and in the router's router-LSAs." + ::= { ospfv3VirtIfEntry 3 } + + ospfv3VirtIfInstId OBJECT-TYPE + SYNTAX Ospfv3IfInstIdTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local Interface Instance ID assigned by the + OSPFv3 Process to this OSPFv3 virtual interface." + ::= { ospfv3VirtIfEntry 4 } + + ospfv3VirtIfTransitDelay OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a Link State Update packet over this + interface." + DEFVAL { 1 } + ::= { ospfv3VirtIfEntry 5 } + + ospfv3VirtIfRetransInterval OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link state + advertisement retransmissions for adjacencies + belonging to this interface. This value is + also used when retransmitting database + description and Link State Request packets. This + value should be well over the expected + round-trip time." + DEFVAL { 5 } + ::= { ospfv3VirtIfEntry 6 } + + ospfv3VirtIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the + interface. This value must be the same for the + virtual neighbor." + DEFVAL { 10 } + ::= { ospfv3VirtIfEntry 7 } + + ospfv3VirtIfRtrDeadInterval OBJECT-TYPE + SYNTAX Ospfv3DeadIntervalRangeTC + UNITS "seconds" + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before its + neighbors declare the router down. This should + be some multiple of the Hello interval. This + value must be the same for the virtual + neighbor." + DEFVAL { 60 } + ::= { ospfv3VirtIfEntry 8 } + + ospfv3VirtIfState OBJECT-TYPE + SYNTAX INTEGER { + down(1), + pointToPoint(4) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF virtual interface states. The same encoding + as the ospfV3IfTable is used." + ::= { ospfv3VirtIfEntry 9 } + + ospfv3VirtIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of state changes or error events on + this virtual link. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3VirtIfEntry 10 } + + ospfv3VirtIfRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object permits management of the table by + facilitating actions such as row creation, + construction, and destruction. + + The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ospfv3VirtIfEntry 11 } + + ospfv3VirtIfLinkScopeLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Link-scope link state + advertisements in this virtual link's link state + database." + ::= { ospfv3VirtIfEntry 12 } + + ospfv3VirtIfLinkLsaCksumSum OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the Link-scope link state + advertisements' LS checksums contained in this + virtual link's link state database. The sum can be used + to determine if there has been a change in a + router's link state database or to compare the + link state database of two routers." + ::= { ospfv3VirtIfEntry 13 } + + -- OSPFv3 Neighbor Table + + ospfv3NbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3NbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table describing all neighbors in the + locality of the OSPFv3 router." + REFERENCE + "OSPF Version 2, Section 10, The Neighbor Data + Structure" + ::= { ospfv3Objects 9 } + + ospfv3NbrEntry OBJECT-TYPE + SYNTAX Ospfv3NbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The information regarding a single neighbor." + REFERENCE + "OSPF Version 2, Section 10, The Neighbor Data + Structure" + INDEX { ospfv3NbrIfIndex, + ospfv3NbrIfInstId, + ospfv3NbrRtrId } + ::= { ospfv3NbrTable 1 } + + Ospfv3NbrEntry ::= SEQUENCE { + ospfv3NbrIfIndex + InterfaceIndex, + ospfv3NbrIfInstId + Ospfv3IfInstIdTC, + ospfv3NbrRtrId + Ospfv3RouterIdTC, + ospfv3NbrAddressType + InetAddressType, + ospfv3NbrAddress + InetAddress, + ospfv3NbrOptions + Integer32, + ospfv3NbrPriority + DesignatedRouterPriority, + ospfv3NbrState + INTEGER, + ospfv3NbrEvents + Counter32, + ospfv3NbrLsRetransQLen + Gauge32, + ospfv3NbrHelloSuppressed + TruthValue, + ospfv3NbrIfId + InterfaceIndex, + ospfv3NbrRestartHelperStatus + INTEGER, + ospfv3NbrRestartHelperAge + Ospfv3UpToRefreshIntervalTC, + ospfv3NbrRestartHelperExitReason + INTEGER + } + + ospfv3NbrIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Local Link ID of the link over which the + neighbor can be reached." + ::= { ospfv3NbrEntry 1 } + + ospfv3NbrIfInstId OBJECT-TYPE + SYNTAX Ospfv3IfInstIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Interface instance over which the neighbor + can be reached. This ID has local link + significance only." + ::= { ospfv3NbrEntry 2 } + + ospfv3NbrRtrId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A 32-bit unsigned integer uniquely identifying the + neighboring router in the Autonomous System." + ::= { ospfv3NbrEntry 3 } + + ospfv3NbrAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The address type of ospfv3NbrAddress. Only IPv6 + addresses without zone index are expected." + ::= { ospfv3NbrEntry 4 } + + ospfv3NbrAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IPv6 address of the neighbor associated with + the local link." + ::= { ospfv3NbrEntry 5 } + + ospfv3NbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A bit mask corresponding to the neighbor's + options field." + REFERENCE + "OSPF for IPv6, Appendix A.2, The Options Field" + ::= { ospfv3NbrEntry 6 } + + ospfv3NbrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The priority of this neighbor in the designated- + router election algorithm. The value 0 signifies + that the neighbor is not eligible to become the + Designated Router on this particular network." + ::= { ospfv3NbrEntry 7 } + + ospfv3NbrState OBJECT-TYPE + SYNTAX INTEGER { + down(1), + attempt(2), + init(3), + twoWay(4), + exchangeStart(5), + exchange(6), + loading(7), + full(8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of the relationship with this + neighbor." + REFERENCE + "OSPF Version 2, Section 10.1, Neighbor states" + ::= { ospfv3NbrEntry 8 } + + ospfv3NbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this neighbor relationship + has changed state or an error has occurred. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3NbrEntry 9 } + + ospfv3NbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfv3NbrEntry 10 } + + ospfv3NbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor." + ::= { ospfv3NbrEntry 11 } + + ospfv3NbrIfId OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Interface ID that the neighbor advertises + in its Hello packets on this link, that is, the + neighbor's local interface index." + ::= { ospfv3NbrEntry 12 } + + ospfv3NbrRestartHelperStatus OBJECT-TYPE + SYNTAX INTEGER { notHelping(1), + helping(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether the router is acting + as a graceful restart helper for the neighbor." + ::= { ospfv3NbrEntry 13 } + + ospfv3NbrRestartHelperAge OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Remaining time in current OSPF graceful restart + interval, if the router is acting as a restart + helper for the neighbor." + ::= { ospfv3NbrEntry 14 } + + ospfv3NbrRestartHelperExitReason OBJECT-TYPE + SYNTAX INTEGER { none(1), + inProgress(2), + completed(3), + timedOut(4), + topologyChanged(5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Describes the outcome of the last attempt at acting + as a graceful restart helper for the neighbor. + + none: no restart has yet been attempted. + inProgress: a restart attempt is currently underway. + completed: the last restart completed successfully. + timedOut: the last restart timed out. + topologyChanged: the last restart was aborted due to + a topology change." + ::= { ospfv3NbrEntry 15 } + + -- OSPFv3 Configured Neighbor Table + + ospfv3CfgNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3CfgNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table describing all configured neighbors. + + The Configured Neighbors table just gives + OSPFv3 information for sending OSPFv3 packets + to potential neighbors and is typically used + on NBMA and Point-to-Multipoint networks. + Once a Hello is received from a neighbor in + the Configured Neighbor table, an entry for + that neighbor is created in the Neighbor table + and adjacency state is maintained there. + Neighbors on multi-access or Point-to-Point + networks can use multicast addressing, so only + Neighbor table entries are created for them." + REFERENCE + "OSPF Version 2, Section 10, The Neighbor Data + Structure" + ::= { ospfv3Objects 10 } + + ospfv3CfgNbrEntry OBJECT-TYPE + SYNTAX Ospfv3CfgNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The information regarding a single configured + neighbor. + + The information in this table is persistent, + and when written, the entity SHOULD save the + change to non-volatile storage." + REFERENCE + "OSPF Version 2, Section 10, The Neighbor Data + Structure" + INDEX { ospfv3CfgNbrIfIndex, + ospfv3CfgNbrIfInstId, + ospfv3CfgNbrAddressType, + ospfv3CfgNbrAddress } + ::= { ospfv3CfgNbrTable 1 } + + Ospfv3CfgNbrEntry ::= SEQUENCE { + ospfv3CfgNbrIfIndex + InterfaceIndex, + ospfv3CfgNbrIfInstId + Ospfv3IfInstIdTC, + ospfv3CfgNbrAddressType + InetAddressType, + ospfv3CfgNbrAddress + InetAddress, + ospfv3CfgNbrPriority + DesignatedRouterPriority, + ospfv3CfgNbrRowStatus + RowStatus + } + + ospfv3CfgNbrIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Local Link ID of the link over which the + neighbor can be reached." + ::= { ospfv3CfgNbrEntry 1 } + + ospfv3CfgNbrIfInstId OBJECT-TYPE + SYNTAX Ospfv3IfInstIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Interface instance over which the neighbor + can be reached. This ID has local link + significance only." + ::= { ospfv3CfgNbrEntry 2 } + + ospfv3CfgNbrAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of ospfv3NbrAddress. Only IPv6 + addresses without zone index are expected." + ::= { ospfv3CfgNbrEntry 3 } + + ospfv3CfgNbrAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IPv6 address of the neighbor associated with + the local link." + ::= { ospfv3CfgNbrEntry 4 } + + ospfv3CfgNbrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this neighbor in the designated- + router election algorithm. The value 0 signifies + that the neighbor is not eligible to become the + Designated Router on this particular network." + DEFVAL { 1 } + ::= { ospfv3CfgNbrEntry 5 } + + ospfv3CfgNbrRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object permits management of the table by + facilitating actions such as row creation, + construction, and destruction. + + The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ospfv3CfgNbrEntry 6 } + + -- OSPFv3 Virtual Neighbor Table + + ospfv3VirtNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3VirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table describing all virtual neighbors." + REFERENCE + "OSPF Version 2, Section 15, Virtual Links" + ::= { ospfv3Objects 11 } + + ospfv3VirtNbrEntry OBJECT-TYPE + SYNTAX Ospfv3VirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Virtual neighbor information." + INDEX { ospfv3VirtNbrArea, + ospfv3VirtNbrRtrId } + ::= { ospfv3VirtNbrTable 1 } + + Ospfv3VirtNbrEntry ::= SEQUENCE { + ospfv3VirtNbrArea + Ospfv3AreaIdTC, + ospfv3VirtNbrRtrId + Ospfv3RouterIdTC, + ospfv3VirtNbrIfIndex + InterfaceIndex, + ospfv3VirtNbrIfInstId + Ospfv3IfInstIdTC, + ospfv3VirtNbrAddressType + InetAddressType, + ospfv3VirtNbrAddress + InetAddress, + ospfv3VirtNbrOptions + Integer32, + ospfv3VirtNbrState + INTEGER, + ospfv3VirtNbrEvents + Counter32, + ospfv3VirtNbrLsRetransQLen + Gauge32, + ospfv3VirtNbrHelloSuppressed + TruthValue, + ospfv3VirtNbrIfId + InterfaceIndex, + ospfv3VirtNbrRestartHelperStatus + INTEGER, + ospfv3VirtNbrRestartHelperAge + Ospfv3UpToRefreshIntervalTC, + ospfv3VirtNbrRestartHelperExitReason + INTEGER + } + + ospfv3VirtNbrArea OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The transit area Identifier." + ::= { ospfv3VirtNbrEntry 1 } + + ospfv3VirtNbrRtrId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + neighboring router in the Autonomous System." + ::= { ospfv3VirtNbrEntry 2 } + + ospfv3VirtNbrIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local Interface ID for the virtual link over + which the neighbor can be reached." + ::= { ospfv3VirtNbrEntry 3 } + + ospfv3VirtNbrIfInstId OBJECT-TYPE + SYNTAX Ospfv3IfInstIdTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The interface instance for the virtual link over + which the neighbor can be reached." + ::= { ospfv3VirtNbrEntry 4 } + + ospfv3VirtNbrAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The address type of ospfv3VirtNbrAddress. Only IPv6 + addresses without zone index are expected." + ::= { ospfv3VirtNbrEntry 5 } + + ospfv3VirtNbrAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IPv6 address advertised by this virtual neighbor. + It must be a global scope address." + ::= { ospfv3VirtNbrEntry 6 } + + ospfv3VirtNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A bit mask corresponding to the neighbor's options + field." + REFERENCE + "OSPF for IPv6, Appendix A.2, The Options Field" + ::= { ospfv3VirtNbrEntry 7 } + + ospfv3VirtNbrState OBJECT-TYPE + SYNTAX INTEGER { + down(1), + attempt(2), + init(3), + twoWay(4), + exchangeStart(5), + exchange(6), + loading(7), + full(8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of the virtual neighbor relationship." + ::= { ospfv3VirtNbrEntry 8 } + + ospfv3VirtNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this virtual link has + changed its state or an error has occurred. + + Discontinuities in the value of this counter + can occur at re-initialization of the management + system and at other times as indicated by the + value of ospfv3DiscontinuityTime." + ::= { ospfv3VirtNbrEntry 9 } + + ospfv3VirtNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfv3VirtNbrEntry 10 } + + ospfv3VirtNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor." + ::= { ospfv3VirtNbrEntry 11 } + + ospfv3VirtNbrIfId OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Interface ID that the neighbor advertises + in its Hello packets on this virtual link, that is, + the neighbor's local Interface ID." + ::= { ospfv3VirtNbrEntry 12 } + +ospfv3VirtNbrRestartHelperStatus OBJECT-TYPE + SYNTAX INTEGER { notHelping(1), + helping(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether the router is acting + as a graceful restart helper for the neighbor." + ::= { ospfv3VirtNbrEntry 13 } + + ospfv3VirtNbrRestartHelperAge OBJECT-TYPE + SYNTAX Ospfv3UpToRefreshIntervalTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Remaining time in the current OSPF graceful restart + interval, if the router is acting as a restart + helper for the neighbor." + ::= { ospfv3VirtNbrEntry 14 } + + ospfv3VirtNbrRestartHelperExitReason OBJECT-TYPE + SYNTAX INTEGER { none(1), + inProgress(2), + completed(3), + timedOut(4), + topologyChanged(5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Describes the outcome of the last attempt at acting + as a graceful restart helper for the neighbor. + + none: no restart has yet been attempted. + inProgress: a restart attempt is currently underway. + completed: the last restart completed successfully. + timedOut: the last restart timed out. + topologyChanged: the last restart was aborted due to + a topology change." + ::= { ospfv3VirtNbrEntry 15 } + + -- + -- The OSPFv3 Area Aggregate Table + -- + + ospfv3AreaAggregateTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3AreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Area Aggregate Table acts as an adjunct + to the Area Table. It describes those address + aggregates that are configured to be propagated + from an area. Its purpose is to reduce the amount + of information that is known beyond an area's + borders. + + A range of IPv6 prefixes specified by a + prefix / prefix length pair. Note that if + ranges are configured such that one range + subsumes another range, the most specific + match is the preferred one." + ::= { ospfv3Objects 12 } + + ospfv3AreaAggregateEntry OBJECT-TYPE + SYNTAX Ospfv3AreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single area aggregate entry. + + Information in this table is persistent, and + when this object is written, the entity SHOULD + save the change to non-volatile storage." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + INDEX { ospfv3AreaAggregateAreaID, + ospfv3AreaAggregateAreaLsdbType, + ospfv3AreaAggregatePrefixType, + ospfv3AreaAggregatePrefix, + ospfv3AreaAggregatePrefixLength } + ::= { ospfv3AreaAggregateTable 1 } + + Ospfv3AreaAggregateEntry ::= SEQUENCE { + ospfv3AreaAggregateAreaID + Ospfv3AreaIdTC, + ospfv3AreaAggregateAreaLsdbType + INTEGER, + ospfv3AreaAggregatePrefixType + InetAddressType, + ospfv3AreaAggregatePrefix + InetAddress, + ospfv3AreaAggregatePrefixLength + InetAddressPrefixLength, + ospfv3AreaAggregateRowStatus + RowStatus, + ospfv3AreaAggregateEffect + INTEGER, + ospfv3AreaAggregateRouteTag + Unsigned32 + } + + ospfv3AreaAggregateAreaID OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The area the Address Aggregate is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + ::= { ospfv3AreaAggregateEntry 1 } + + ospfv3AreaAggregateAreaLsdbType OBJECT-TYPE + SYNTAX INTEGER { + interAreaPrefixLsa(8195), -- 0x2003 + nssaExternalLsa(8199) -- 0x2007 + } + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of the Address Aggregate. This field + specifies the Area LSDB type that this Address + Aggregate applies to." + REFERENCE + "OSPF Version 2, Appendix A.4.1, The LSA header" + ::= { ospfv3AreaAggregateEntry 2 } + + ospfv3AreaAggregatePrefixType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The prefix type of ospfv3AreaAggregatePrefix. Only + IPv6 addresses are expected." + ::= { ospfv3AreaAggregateEntry 3 } + + ospfv3AreaAggregatePrefix OBJECT-TYPE + SYNTAX InetAddress (SIZE (0..16)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IPv6 prefix." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + ::= { ospfv3AreaAggregateEntry 4 } + + ospfv3AreaAggregatePrefixLength OBJECT-TYPE + SYNTAX InetAddressPrefixLength (3..128) + UNITS "bits" + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The length of the prefix (in bits). A prefix can + not be shorter than 3 bits." + REFERENCE + "OSPF Version 2, Appendix C.2, Area parameters" + ::= { ospfv3AreaAggregateEntry 5 } + + ospfv3AreaAggregateRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object permits management of the table by + facilitating actions such as row creation, + construction, and destruction. + + The value of this object has no effect on + whether other objects in this conceptual row can be + modified." + ::= { ospfv3AreaAggregateEntry 6 } + + ospfv3AreaAggregateEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching(1), + doNotAdvertiseMatching(2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Prefixes subsumed by ranges will either trigger the + advertisement of the indicated aggregate + (advertiseMatching) or result in the prefix not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfv3AreaAggregateEntry 7 } + + ospfv3AreaAggregateRouteTag OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This tag is advertised only in the summarized + As-External LSA when summarizing from NSSA-LSAs to + AS-External-LSAs." + DEFVAL { 0 } + ::= { ospfv3AreaAggregateEntry 8 } + + -- OSPFv3 Link-Scope Link State Database, for virtual interfaces + + ospfv3VirtLinkLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF Ospfv3VirtLinkLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPFv3 Process's Link-scope LSDB for virtual + interfaces. The LSDB contains the Link-scope link + state advertisements from virtual interfaces." + ::= { ospfv3Objects 13 } + + ospfv3VirtLinkLsdbEntry OBJECT-TYPE + SYNTAX Ospfv3VirtLinkLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link-scope link state advertisement + for a virtual interface." + INDEX { ospfv3VirtLinkLsdbIfAreaId, + ospfv3VirtLinkLsdbIfNeighbor, + ospfv3VirtLinkLsdbType, + ospfv3VirtLinkLsdbRouterId, + ospfv3VirtLinkLsdbLsid } + ::= { ospfv3VirtLinkLsdbTable 1 } + + Ospfv3VirtLinkLsdbEntry ::= SEQUENCE { + ospfv3VirtLinkLsdbIfAreaId + Ospfv3AreaIdTC, + ospfv3VirtLinkLsdbIfNeighbor + Ospfv3RouterIdTC, + ospfv3VirtLinkLsdbType + Unsigned32, + ospfv3VirtLinkLsdbRouterId + Ospfv3RouterIdTC, + ospfv3VirtLinkLsdbLsid + Ospfv3LsIdTC, + ospfv3VirtLinkLsdbSequence + Ospfv3LsaSequenceTC, + ospfv3VirtLinkLsdbAge + Ospfv3LsaAgeTC, + ospfv3VirtLinkLsdbChecksum + Integer32, + ospfv3VirtLinkLsdbAdvertisement + OCTET STRING, + ospfv3VirtLinkLsdbTypeKnown + TruthValue + } + + ospfv3VirtLinkLsdbIfAreaId OBJECT-TYPE + SYNTAX Ospfv3AreaIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The transit area that the virtual link + traverses. By definition, this is not + Area 0." + ::= { ospfv3VirtLinkLsdbEntry 1 } + + ospfv3VirtLinkLsdbIfNeighbor OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Router ID of the virtual neighbor." + ::= { ospfv3VirtLinkLsdbEntry 2 } + + ospfv3VirtLinkLsdbType OBJECT-TYPE + SYNTAX Unsigned32(0..'FFFFFFFF'h) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate + advertisement format. Link-scope LSAs unrecognized + by the router are also stored in this database." + ::= { ospfv3VirtLinkLsdbEntry 3 } + + ospfv3VirtLinkLsdbRouterId OBJECT-TYPE + SYNTAX Ospfv3RouterIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The 32-bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1, Global parameters" + ::= { ospfv3VirtLinkLsdbEntry 4 } + + ospfv3VirtLinkLsdbLsid OBJECT-TYPE + SYNTAX Ospfv3LsIdTC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Link State ID is an LS type-specific field + containing a unique identifier; + it identifies the piece of the routing domain + that is being described by the advertisement. + In contrast to OSPFv2, the LSID has no + addressing semantics." + ::= { ospfv3VirtLinkLsdbEntry 5 } + + -- Note that the OSPF sequence number is a 32-bit signed + -- integer. It starts with the value '80000001'h + -- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h. + -- Thus, a typical sequence number will be very negative. + + ospfv3VirtLinkLsdbSequence OBJECT-TYPE + SYNTAX Ospfv3LsaSequenceTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and duplicate + link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number, the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6, LS sequence + number" + ::= { ospfv3VirtLinkLsdbEntry 6 } + + ospfv3VirtLinkLsdbAge OBJECT-TYPE + SYNTAX Ospfv3LsaAgeTC + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state + advertisement in seconds. The high-order bit + of the LS age field is considered the DoNotAge + bit for support of on-demand circuits." + REFERENCE + "OSPF Version 2, Section 12.1.1, LS age; + Extending OSPF to Support Demand Circuits, + Section 2.2, The LS age field." + ::= { ospfv3VirtLinkLsdbEntry 7 } + + ospfv3VirtLinkLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO + connectionless datagrams; it is commonly + referred to as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7, LS checksum" + ::= { ospfv3VirtLinkLsdbEntry 8 } + + ospfv3VirtLinkLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire link state advertisement, including + its header." + ::= { ospfv3VirtLinkLsdbEntry 9 } + + ospfv3VirtLinkLsdbTypeKnown OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value true (1) indicates that the LSA type is + recognized by this router." + ::= { ospfv3VirtLinkLsdbEntry 10 } + + -- The Ospfv3 Notification Table + + -- The Ospfv3 Notification Table records fields that are + -- required for notifications. + + ospfv3NotificationEntry OBJECT IDENTIFIER + ::= { ospfv3Objects 14 } + + ospfv3ConfigErrorType OBJECT-TYPE + SYNTAX INTEGER { + badVersion(1), + areaMismatch(2), + unknownNbmaNbr(3), -- Router is DR eligible + unknownVirtualNbr(4), + helloIntervalMismatch(5), + deadIntervalMismatch(6), + optionMismatch(7), + mtuMismatch(8), + duplicateRouterId(9), + noError(10) } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Potential types of configuration conflicts. + Used by the ospfv3ConfigError and + ospfv3ConfigVirtError notifications." + ::= { ospfv3NotificationEntry 1 } + + ospfv3PacketType OBJECT-TYPE + SYNTAX INTEGER { + hello(1), + dbDescript(2), + lsReq(3), + lsUpdate(4), + lsAck(5), + nullPacket(6) } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "OSPFv3 packet types." + ::= { ospfv3NotificationEntry 2 } + + ospfv3PacketSrc OBJECT-TYPE + SYNTAX InetAddressIPv6 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "The IPv6 address of an inbound packet that cannot + be identified by a neighbor instance. + + Only IPv6 addresses without zone index are expected." + ::= { ospfv3NotificationEntry 3 } + + -- Notification Definitions + + -- The notifications need to be throttled so as to not overwhelm the + -- management agent in case of rapid changes to the OSPFv3 module. + +ospfv3VirtIfStateChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3VirtIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfv3VirtIfStateChange notification signifies that + there has been a change in the state of an OSPFv3 virtual + interface. + + This notification should be generated when the interface + state regresses (e.g., goes from Point-to-Point to Down) + or progresses to a terminal state (i.e., Point-to-Point)." + ::= { ospfv3Notifications 1 } + +ospfv3NbrStateChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3NbrState -- The new state + + } + STATUS current + DESCRIPTION + "An ospfv3NbrStateChange notification signifies that + there has been a change in the state of a + non-virtual OSPFv3 neighbor. This notification should be + generated when the neighbor state regresses + (e.g., goes from Attempt or Full to 1-Way or + Down) or progresses to a terminal state (e.g., + 2-Way or Full). When a neighbor transitions + from or to Full on non-broadcast multi-access + and broadcast networks, the notification should be + generated by the Designated Router. A Designated + Router transitioning to Down will be noted by + ospfIfStateChange." + ::= { ospfv3Notifications 2 } + +ospfv3VirtNbrStateChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3VirtNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfv3VirtNbrStateChange notification signifies + that there has been a change in the state of an OSPFv3 + virtual neighbor. This notification should be generated + when the neighbor state regresses (e.g., goes + from Attempt or Full to 1-Way or Down) or + progresses to a terminal state (e.g., Full)." + ::= { ospfv3Notifications 3 } + +ospfv3IfConfigError NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3IfState, -- State of the interface + ospfv3PacketSrc, -- IPv6 address of source + ospfv3ConfigErrorType, -- Type of error + ospfv3PacketType -- Type of packet + } + STATUS current + DESCRIPTION + "An ospfv3IfConfigError notification signifies that a + packet has been received on a non-virtual + interface from a router whose configuration + parameters conflict with this router's + configuration parameters. Note that the event + optionMismatch should cause a notification only if it + prevents an adjacency from forming." + ::= { ospfv3Notifications 4 } + +ospfv3VirtIfConfigError NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3VirtIfState, -- State of the interface + ospfv3ConfigErrorType, -- Type of error + ospfv3PacketType + } + STATUS current + DESCRIPTION + "An ospfv3VirtIfConfigError notification signifies that a + packet has been received on a virtual interface + from a router whose configuration parameters + conflict with this router's configuration + parameters. Note that the event optionMismatch + should cause a notification only if it prevents an + adjacency from forming." + ::= { ospfv3Notifications 5 } + +ospfv3IfRxBadPacket NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3IfState, -- State of the interface + ospfv3PacketSrc, -- The source IPv6 address + ospfv3PacketType -- Type of packet + } + STATUS current + DESCRIPTION + "An ospfv3IfRxBadPacket notification signifies that an + OSPFv3 packet that cannot be parsed has been received on a + non-virtual interface." + ::= { ospfv3Notifications 6 } + +ospfv3VirtIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3VirtIfState, -- State of the interface + ospfv3PacketType -- Type of packet + } + STATUS current + DESCRIPTION + "An ospfv3VirtIfRxBadPacket notification signifies + that an OSPFv3 packet that cannot be parsed has been + received on a virtual interface." + ::= { ospfv3Notifications 7 } + +ospfv3LsdbOverflow NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3ExtAreaLsdbLimit -- Limit on External LSAs + } + STATUS current + DESCRIPTION + "An ospfv3LsdbOverflow notification signifies that the + number of LSAs in the router's link state + database has exceeded ospfv3ExtAreaLsdbLimit." + ::= { ospfv3Notifications 8 } + +ospfv3LsdbApproachingOverflow NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3ExtAreaLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfv3LsdbApproachingOverflow notification signifies + that the number of LSAs in the router's + link state database has exceeded ninety percent of + ospfv3ExtAreaLsdbLimit." + ::= { ospfv3Notifications 9 } + +ospfv3IfStateChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3IfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfv3IfStateChange notification signifies that there + has been a change in the state of a non-virtual + OSPFv3 interface. This notification should be generated + when the interface state regresses (e.g., goes + from DR to Down) or progresses to a terminal + state (i.e., Point-to-Point, DR Other, DR, or + Backup)." + ::= { ospfv3Notifications 10 } + +ospfv3NssaTranslatorStatusChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3AreaNssaTranslatorState -- new state + } + STATUS current + DESCRIPTION + "An ospfv3NssaTranslatorStatusChange notification + indicates that there has been a change in the router's + ability to translate OSPFv3 NSSA LSAs into OSPFv3 External + LSAs. This notification should be generated when the + Translator Status transitions from or to any defined + status on a per-area basis." + ::= { ospfv3Notifications 11 } + +ospfv3RestartStatusChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3RestartStatus, -- new status + ospfv3RestartInterval, + ospfv3RestartExitReason + } + STATUS current + DESCRIPTION + "An ospfv3RestartStatusChange notification signifies that + there has been a change in the graceful restart + state for the router. This notification should be + generated when the router restart status + changes." + ::= { ospfv3Notifications 12 } + +ospfv3NbrRestartHelperStatusChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3NbrRestartHelperStatus, -- new status + ospfv3NbrRestartHelperAge, + ospfv3NbrRestartHelperExitReason + } + STATUS current + DESCRIPTION + "An ospfv3NbrRestartHelperStatusChange notification + signifies that there has been a change in the + graceful restart helper state for the neighbor. + This notification should be generated when the + neighbor restart helper status transitions for a neighbor." + ::= { ospfv3Notifications 13 } + +ospfv3VirtNbrRestartHelperStatusChange NOTIFICATION-TYPE + OBJECTS { ospfv3RouterId, -- The originator of the notification + ospfv3VirtNbrRestartHelperStatus, -- new status + ospfv3VirtNbrRestartHelperAge, + ospfv3VirtNbrRestartHelperExitReason + } + STATUS current + DESCRIPTION + "An ospfv3VirtNbrRestartHelperStatusChange + notification signifies that there has been a + change in the graceful restart helper state for + the virtual neighbor. This notification should be + generated when the virtual neighbor restart helper status + transitions for a virtual neighbor." + ::= { ospfv3Notifications 14 } + + -- Conformance Information + + ospfv3Groups OBJECT IDENTIFIER ::= { ospfv3Conformance 1 } + ospfv3Compliances OBJECT IDENTIFIER ::= { ospfv3Conformance 2 } + + -- Compliance Statements + + ospfv3FullCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION "The compliance statement" + MODULE -- this module + MANDATORY-GROUPS { + ospfv3BasicGroup, + ospfv3AreaGroup, + ospfv3IfGroup, + ospfv3VirtIfGroup, + ospfv3NbrGroup, + ospfv3CfgNbrGroup, + ospfv3VirtNbrGroup, + ospfv3AreaAggregateGroup + } + + GROUP ospfv3AsLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their AS-scope link state database." + + GROUP ospfv3AreaLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their Area-scope link state database." + + GROUP ospfv3LinkLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their Link-scope link state database + for non-virtual interfaces." + + GROUP ospfv3VirtLinkLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their Link-scope link state database + for virtual interfaces." + + GROUP ospfv3HostGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + support attached hosts." + + GROUP ospfv3NotificationObjectGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + support OSPFv3 notifications." + + GROUP ospfv3NotificationGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + support OSPFv3 notifications." + + OBJECT ospfv3NbrAddressType + SYNTAX InetAddressType { ipv6(2) } + DESCRIPTION + "An implementation is only required to support IPv6 + address without zone index." + + OBJECT ospfv3NbrAddress + SYNTAX InetAddress (SIZE (16)) + DESCRIPTION + "An implementation is only required to support IPv6 + address without zone index." + + OBJECT ospfv3VirtNbrAddressType + SYNTAX InetAddressType { ipv6(2) } + DESCRIPTION + "An implementation is only required to support IPv6 + address without zone index." + + OBJECT ospfv3VirtNbrAddress + SYNTAX InetAddress (SIZE (16)) + DESCRIPTION + "An implementation is only required to support IPv6 + address without zone index." + ::= { ospfv3Compliances 1 } + + ospfv3ReadOnlyCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "When this MIB module is implemented without + support for read-create (i.e., in read-only + mode), the implementation can claim read-only + compliance. Such a device can then be monitored, + but cannot be configured with this MIB." + + MODULE -- this module + MANDATORY-GROUPS { + ospfv3BasicGroup, + ospfv3AreaGroup, + ospfv3IfGroup, + ospfv3VirtIfGroup, + ospfv3NbrGroup, + ospfv3CfgNbrGroup, + ospfv3VirtNbrGroup, + ospfv3AreaAggregateGroup + } + + GROUP ospfv3AsLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their AS-scope link state database." + + GROUP ospfv3AreaLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their Area-scope link state database." + + GROUP ospfv3LinkLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their Link-scope link state database + for non-virtual interfaces." + + GROUP ospfv3VirtLinkLsdbGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + display their Link-scope link state database + for virtual interfaces." + + GROUP ospfv3HostGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + support attached hosts." + + GROUP ospfv3NotificationObjectGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + support OSPFv3 notifications." + + GROUP ospfv3NotificationGroup + DESCRIPTION + "This group is required for OSPFv3 systems that + support OSPFv3 notifications." + + OBJECT ospfv3RouterId + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AdminStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3ExtAreaLsdbLimit + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3ExitOverflowInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3DemandExtensions + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3ReferenceBandwidth + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3RestartSupport + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3RestartInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3RestartStrictLsaChecking + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3NotificationEnable + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3StubRouterAdvertisement + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaImportAsExtern + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaSummary + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaRowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaStubMetric + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaNssaTranslatorRole + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaNssaTranslatorStabInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaStubMetricType + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaTEEnabled + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3HostMetric + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3HostRowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3HostAreaID + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfAreaId + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfType + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfAdminStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfRtrPriority + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfTransitDelay + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfRetransInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfHelloInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfRtrDeadInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfPollInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfRowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfDemand + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfMetricValue + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfDemandNbrProbe + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfDemandNbrProbeRetransLimit + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfDemandNbrProbeInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfTEDisabled + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3IfLinkLSASuppression + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3VirtIfTransitDelay + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3VirtIfRetransInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3VirtIfHelloInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3VirtIfRtrDeadInterval + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3VirtIfRowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3CfgNbrPriority + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3CfgNbrRowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaAggregateRowStatus + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaAggregateEffect + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + + OBJECT ospfv3AreaAggregateRouteTag + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + ::= { ospfv3Compliances 2 } + + -- units of conformance + + ospfv3BasicGroup OBJECT-GROUP + OBJECTS { + ospfv3RouterId, + ospfv3AdminStatus, + ospfv3VersionNumber, + ospfv3AreaBdrRtrStatus, + ospfv3ASBdrRtrStatus, + ospfv3AsScopeLsaCount, + ospfv3AsScopeLsaCksumSum, + ospfv3OriginateNewLsas, + ospfv3RxNewLsas, + ospfv3ExtLsaCount, + ospfv3ExtAreaLsdbLimit, + ospfv3ExitOverflowInterval, + ospfv3DemandExtensions, + ospfv3ReferenceBandwidth, + ospfv3RestartSupport, + ospfv3RestartInterval, + ospfv3RestartStrictLsaChecking, + ospfv3RestartStatus, + ospfv3RestartAge, + ospfv3RestartExitReason, + ospfv3NotificationEnable, + ospfv3StubRouterSupport, + ospfv3StubRouterAdvertisement, + ospfv3DiscontinuityTime, + ospfv3RestartTime + } + STATUS current + DESCRIPTION + "These objects are used for managing/monitoring + OSPFv3 global parameters." + ::= { ospfv3Groups 1 } + + ospfv3AreaGroup OBJECT-GROUP + OBJECTS { + ospfv3AreaImportAsExtern, + ospfv3AreaSpfRuns, + ospfv3AreaBdrRtrCount, + ospfv3AreaAsBdrRtrCount, + ospfv3AreaScopeLsaCount, + ospfv3AreaScopeLsaCksumSum, + ospfv3AreaSummary, + ospfv3AreaRowStatus, + ospfv3AreaStubMetric, + ospfv3AreaNssaTranslatorRole, + ospfv3AreaNssaTranslatorState, + ospfv3AreaNssaTranslatorStabInterval, + ospfv3AreaNssaTranslatorEvents, + ospfv3AreaStubMetricType, + ospfv3AreaTEEnabled + } + STATUS current + DESCRIPTION + "These objects are used for OSPFv3 systems + supporting areas." + ::= { ospfv3Groups 2 } + + ospfv3AsLsdbGroup OBJECT-GROUP + OBJECTS { + ospfv3AsLsdbSequence, + ospfv3AsLsdbAge, + ospfv3AsLsdbChecksum, + ospfv3AsLsdbAdvertisement, + ospfv3AsLsdbTypeKnown + } + STATUS current + DESCRIPTION + "These objects are used for OSPFv3 systems + that display their AS-scope link state database." + ::= { ospfv3Groups 3 } + + ospfv3AreaLsdbGroup OBJECT-GROUP + OBJECTS { + ospfv3AreaLsdbSequence, + ospfv3AreaLsdbAge, + ospfv3AreaLsdbChecksum, + ospfv3AreaLsdbAdvertisement, + ospfv3AreaLsdbTypeKnown + } + STATUS current + DESCRIPTION + "These objects are used for OSPFv3 systems + that display their Area-scope link state database." + ::= { ospfv3Groups 4 } + + ospfv3LinkLsdbGroup OBJECT-GROUP + OBJECTS { + ospfv3LinkLsdbSequence, + ospfv3LinkLsdbAge, + ospfv3LinkLsdbChecksum, + ospfv3LinkLsdbAdvertisement, + ospfv3LinkLsdbTypeKnown + } + STATUS current + DESCRIPTION + "These objects are used for OSPFv3 systems + that display their Link-scope link state database + for non-virtual interfaces." + ::= { ospfv3Groups 5 } + + ospfv3HostGroup OBJECT-GROUP + OBJECTS { + ospfv3HostMetric, + ospfv3HostRowStatus, + ospfv3HostAreaID + } + STATUS current + DESCRIPTION + "These objects are used for OSPFv3 systems + that support attached hosts." + ::= { ospfv3Groups 6 } + + ospfv3IfGroup OBJECT-GROUP + OBJECTS { + ospfv3IfAreaId, + ospfv3IfType, + ospfv3IfAdminStatus, + ospfv3IfRtrPriority, + ospfv3IfTransitDelay, + ospfv3IfRetransInterval, + ospfv3IfHelloInterval, + ospfv3IfRtrDeadInterval, + ospfv3IfPollInterval, + ospfv3IfState, + ospfv3IfDesignatedRouter, + ospfv3IfBackupDesignatedRouter, + ospfv3IfEvents, + ospfv3IfRowStatus, + ospfv3IfDemand, + ospfv3IfMetricValue, + ospfv3IfLinkScopeLsaCount, + ospfv3IfLinkLsaCksumSum, + ospfv3IfDemandNbrProbe, + ospfv3IfDemandNbrProbeRetransLimit, + ospfv3IfDemandNbrProbeInterval, + ospfv3IfTEDisabled, + ospfv3IfLinkLSASuppression + } + STATUS current + DESCRIPTION + "These interface objects are used for + managing/monitoring OSPFv3 interfaces." + ::= { ospfv3Groups 7 } + + ospfv3VirtIfGroup OBJECT-GROUP + OBJECTS { + ospfv3VirtIfIndex, + ospfv3VirtIfInstId, + ospfv3VirtIfTransitDelay, + ospfv3VirtIfRetransInterval, + ospfv3VirtIfHelloInterval, + ospfv3VirtIfRtrDeadInterval, + ospfv3VirtIfState, + ospfv3VirtIfEvents, + ospfv3VirtIfRowStatus, + ospfv3VirtIfLinkScopeLsaCount, + ospfv3VirtIfLinkLsaCksumSum + } + STATUS current + DESCRIPTION + "These virtual interface objects are used for + managing/monitoring OSPFv3 virtual interfaces." + ::= { ospfv3Groups 8 } + + ospfv3NbrGroup OBJECT-GROUP + OBJECTS { + ospfv3NbrAddressType, + ospfv3NbrAddress, + ospfv3NbrOptions, + ospfv3NbrPriority, + ospfv3NbrState, + ospfv3NbrEvents, + ospfv3NbrLsRetransQLen, + ospfv3NbrHelloSuppressed, + ospfv3NbrIfId, + ospfv3NbrRestartHelperStatus, + ospfv3NbrRestartHelperAge, + ospfv3NbrRestartHelperExitReason + } + STATUS current + DESCRIPTION + "These neighbor objects are used for + managing/monitoring OSPFv3 neighbors." + ::= { ospfv3Groups 9 } + + ospfv3CfgNbrGroup OBJECT-GROUP + OBJECTS { + ospfv3CfgNbrPriority, + ospfv3CfgNbrRowStatus + } + STATUS current + DESCRIPTION + "These configured neighbor objects are used for + managing/monitoring OSPFv3-configured neighbors." + ::= { ospfv3Groups 10 } + + ospfv3VirtNbrGroup OBJECT-GROUP + OBJECTS { + ospfv3VirtNbrIfIndex, + ospfv3VirtNbrIfInstId, + ospfv3VirtNbrAddressType, + ospfv3VirtNbrAddress, + ospfv3VirtNbrOptions, + ospfv3VirtNbrState, + ospfv3VirtNbrEvents, + ospfv3VirtNbrLsRetransQLen, + ospfv3VirtNbrHelloSuppressed, + ospfv3VirtNbrIfId, + ospfv3VirtNbrRestartHelperStatus, + ospfv3VirtNbrRestartHelperAge, + ospfv3VirtNbrRestartHelperExitReason + } + STATUS current + DESCRIPTION + "These virtual neighbor objects are used for + managing/monitoring OSPFv3 virtual neighbors." + ::= { ospfv3Groups 11 } + + ospfv3AreaAggregateGroup OBJECT-GROUP + OBJECTS { + ospfv3AreaAggregateRowStatus, + ospfv3AreaAggregateEffect, + ospfv3AreaAggregateRouteTag + } + STATUS current + DESCRIPTION + "These area aggregate objects are required for + aggregating OSPFv3 prefixes for summarization + across areas." + ::= { ospfv3Groups 12 } + + ospfv3VirtLinkLsdbGroup OBJECT-GROUP + OBJECTS { + ospfv3VirtLinkLsdbSequence, + ospfv3VirtLinkLsdbAge, + ospfv3VirtLinkLsdbChecksum, + ospfv3VirtLinkLsdbAdvertisement, + ospfv3VirtLinkLsdbTypeKnown + } + STATUS current + DESCRIPTION + "These objects are used for OSPFv3 systems + that display their Link-scope link state database + for virtual interfaces." + ::= { ospfv3Groups 13 } + + ospfv3NotificationObjectGroup OBJECT-GROUP + OBJECTS { + ospfv3ConfigErrorType, + ospfv3PacketType, + ospfv3PacketSrc + } + STATUS current + DESCRIPTION + "These objects are used to record notification + parameters." + ::= { ospfv3Groups 14 } + + ospfv3NotificationGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ospfv3VirtIfStateChange, + ospfv3NbrStateChange, + ospfv3VirtNbrStateChange, + ospfv3IfConfigError, + ospfv3VirtIfConfigError, + ospfv3IfRxBadPacket, + ospfv3VirtIfRxBadPacket, + ospfv3LsdbOverflow, + ospfv3LsdbApproachingOverflow, + ospfv3IfStateChange, + ospfv3NssaTranslatorStatusChange, + ospfv3RestartStatusChange, + ospfv3NbrRestartHelperStatusChange, + ospfv3VirtNbrRestartHelperStatusChange + } + STATUS current + DESCRIPTION + "This group is used for OSPFv3 notifications." + ::= { ospfv3Groups 15 } + + END diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index d252f549f..95b4fc08c 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -44,7 +44,7 @@ #include "ospf6_snmp.h" /* OSPFv3-MIB */ -#define OSPFv3MIB 1,3,6,1,3,102 +#define OSPFv3MIB 1,3,6,1,2,1,191 /* OSPFv3 MIB General Group values. */ #define OSPFv3ROUTERID 1 @@ -58,19 +58,22 @@ #define OSPFv3RXNEWLSAS 9 #define OSPFv3EXTLSACOUNT 10 #define OSPFv3EXTAREALSDBLIMIT 11 -#define OSPFv3MULTICASTEXTENSIONS 12 -#define OSPFv3EXITOVERFLOWINTERVAL 13 -#define OSPFv3DEMANDEXTENSIONS 14 -#define OSPFv3TRAFFICENGINEERINGSUPPORT 15 -#define OSPFv3REFERENCEBANDWIDTH 16 -#define OSPFv3RESTARTSUPPORT 17 -#define OSPFv3RESTARTINTERVAL 18 -#define OSPFv3RESTARTSTATUS 19 -#define OSPFv3RESTARTAGE 20 -#define OSPFv3RESTARTEXITREASON 21 - -/* OSPFv3 MIB Area Table values. */ -#define OSPFv3AREAID 1 +#define OSPFv3EXITOVERFLOWINTERVAL 12 +#define OSPFv3DEMANDEXTENSIONS 13 +#define OSPFv3REFERENCEBANDWIDTH 14 +#define OSPFv3RESTARTSUPPORT 15 +#define OSPFv3RESTARTINTERVAL 16 +#define OSPFv3RESTARTSTRICTLSACHECKING 17 +#define OSPFv3RESTARTSTATUS 18 +#define OSPFv3RESTARTAGE 19 +#define OSPFv3RESTARTEXITREASON 20 +#define OSPFv3NOTIFICATIONENABLE 21 +#define OSPFv3STUBROUTERSUPPORT 22 +#define OSPFv3STUBROUTERADVERTISEMENT 23 +#define OSPFv3DISCONTINUITYTIME 24 +#define OSPFv3RESTARTTIME 25 + +/* OSPFv3 MIB Area Table values: ospfv3AreaTable */ #define OSPFv3IMPORTASEXTERN 2 #define OSPFv3AREASPFRUNS 3 #define OSPFv3AREABDRRTRCOUNT 4 @@ -78,25 +81,124 @@ #define OSPFv3AREASCOPELSACOUNT 6 #define OSPFv3AREASCOPELSACKSUMSUM 7 #define OSPFv3AREASUMMARY 8 -#define OSPFv3AREASTATUS 9 -#define OSPFv3STUBMETRIC 10 +#define OSPFv3AREAROWSTATUS 9 +#define OSPFv3AREASTUBMETRIC 10 #define OSPFv3AREANSSATRANSLATORROLE 11 #define OSPFv3AREANSSATRANSLATORSTATE 12 -#define OSPFv3AREANSSATRANSLATORSTABILITYINTERVAL 13 +#define OSPFv3AREANSSATRANSLATORSTABINTERVAL 13 #define OSPFv3AREANSSATRANSLATOREVENTS 14 #define OSPFv3AREASTUBMETRICTYPE 15 +#define OSPFv3AREATEENABLED 16 -/* OSPFv3 MIB Area Lsdb Table values. */ -#define OSPFv3AREALSDBAREAID 1 -#define OSPFv3AREALSDBTYPE 2 -#define OSPFv3AREALSDBROUTERID 3 -#define OSPFv3AREALSDBLSID 4 +/* OSPFv3 MIB AS Lsdb Table values: ospfv3AsLsdbTable */ +#define OSPFv3ASLSDBSEQUENCE 4 +#define OSPFv3ASLSDBAGE 5 +#define OSPFv3ASLSDBCHECKSUM 6 +#define OSPFv3ASLSDBADVERTISEMENT 7 +#define OSPFv3ASLSDBTYPEKNOWN 8 + +/* OSPFv3 MIB Area Lsdb Table values: ospfv3AreaLsdbTable */ #define OSPFv3AREALSDBSEQUENCE 5 #define OSPFv3AREALSDBAGE 6 #define OSPFv3AREALSDBCHECKSUM 7 #define OSPFv3AREALSDBADVERTISEMENT 8 #define OSPFv3AREALSDBTYPEKNOWN 9 +/* OSPFv3 MIB Link Lsdb Table values: ospfv3LinkLsdbTable */ +#define OSPFv3LINKLSDBSEQUENCE 6 +#define OSPFv3LINKLSDBAGE 7 +#define OSPFv3LINKLSDBCHECKSUM 8 +#define OSPFv3LINKLSDBADVERTISEMENT 9 +#define OSPFv3LINKLSDBTYPEKNOWN 10 + +/* OSPFv3 MIB Host Table values: ospfv3HostTable */ +#define OSPFv3HOSTMETRIC 3 +#define OSPFv3HOSTROWSTATUS 4 +#define OSPFv3HOSTAREAID 5 + +/* OSPFv3 MIB Interface Table values: ospfv3IfTable */ +#define OSPFv3IFAREAID 3 +#define OSPFv3IFTYPE 4 +#define OSPFv3IFADMINSTATUS 5 +#define OSPFv3IFRTRPRIORITY 6 +#define OSPFv3IFTRANSITDELAY 7 +#define OSPFv3IFRETRANSINTERVAL 8 +#define OSPFv3IFHELLOINTERVAL 9 +#define OSPFv3IFRTRDEADINTERVAL 10 +#define OSPFv3IFPOLLINTERVAL 11 +#define OSPFv3IFSTATE 12 +#define OSPFv3IFDESIGNATEDROUTER 13 +#define OSPFv3IFBACKUPDESIGNATEDROUTER 14 +#define OSPFv3IFEVENTS 15 +#define OSPFv3IFROWSTATUS 16 +#define OSPFv3IFDEMAND 17 +#define OSPFv3IFMETRICVALUE 18 +#define OSPFv3IFLINKSCOPELSACOUNT 19 +#define OSPFv3IFLINKLSACKSUMSUM 20 +#define OSPFv3IFDEMANDNBRPROBE 21 +#define OSPFv3IFDEMANDNBRPROBERETRANSLIMIT 22 +#define OSPFv3IFDEMANDNBRPROBEINTERVAL 23 +#define OSPFv3IFTEDISABLED 24 +#define OSPFv3IFLINKLSASUPPRESSION 25 + +/* OSPFv3 MIB Virtual Interface Table values: ospfv3VirtIfTable */ +#define OSPFv3VIRTIFINDEX 3 +#define OSPFv3VIRTIFINSTID 4 +#define OSPFv3VIRTIFTRANSITDELAY 5 +#define OSPFv3VIRTIFRETRANSINTERVAL 6 +#define OSPFv3VIRTIFHELLOINTERVAL 7 +#define OSPFv3VIRTIFRTRDEADINTERVAL 8 +#define OSPFv3VIRTIFSTATE 9 +#define OSPFv3VIRTIFEVENTS 10 +#define OSPFv3VIRTIFROWSTATUS 11 +#define OSPFv3VIRTIFLINKSCOPELSACOUNT 12 +#define OSPFv3VIRTIFLINKLSACKSUMSUM 13 + +/* OSPFv3 MIB Neighbors Table values: ospfv3NbrTable */ +#define OSPFv3NBRADDRESSTYPE 4 +#define OSPFv3NBRADDRESS 5 +#define OSPFv3NBROPTIONS 6 +#define OSPFv3NBRPRIORITY 7 +#define OSPFv3NBRSTATE 8 +#define OSPFv3NBREVENTS 9 +#define OSPFv3NBRLSRETRANSQLEN 10 +#define OSPFv3NBRHELLOSUPPRESSED 11 +#define OSPFv3NBRIFID 12 +#define OSPFv3NBRRESTARTHELPERSTATUS 13 +#define OSPFv3NBRRESTARTHELPERAGE 14 +#define OSPFv3NBRRESTARTHELPEREXITREASON 15 + +/* OSPFv3 MIB Configured Neighbors Table values: ospfv3CfgNbrTable */ +#define OSPFv3CFGNBRPRIORITY 5 +#define OSPFv3CFGNBRROWSTATUS 6 + +/* OSPFv3 MIB Virtual Neighbors Table values: ospfv3VirtNbrTable */ +#define OSPFv3VIRTNBRIFINDEX 3 +#define OSPFv3VIRTNBRIFINSTID 4 +#define OSPFv3VIRTNBRADDRESSTYPE 5 +#define OSPFv3VIRTNBRADDRESS 6 +#define OSPFv3VIRTNBROPTIONS 7 +#define OSPFv3VIRTNBRSTATE 8 +#define OSPFv3VIRTNBREVENTS 9 +#define OSPFv3VIRTNBRLSRETRANSQLEN 10 +#define OSPFv3VIRTNBRHELLOSUPPRESSED 11 +#define OSPFv3VIRTNBRIFID 12 +#define OSPFv3VIRTNBRRESTARTHELPERSTATUS 13 +#define OSPFv3VIRTNBRRESTARTHELPERAGE 14 +#define OSPFv3VIRTNBRRESTARTHELPEREXITREASON 15 + +/* OSPFv3 MIB Area Aggregate Table values: ospfv3AreaAggregateTable */ +#define OSPFv3AREAAGGREGATEROWSTATUS 6 +#define OSPFv3AREAAGGREGATEEFFECT 7 +#define OSPFv3AREAAGGREGATEROUTETAG 8 + +/* OSPFv3 MIB Virtual Link Lsdb Table values: ospfv3VirtLinkLsdbTable */ +#define OSPFv3VIRTLINKLSDBSEQUENCE 6 +#define OSPFv3VIRTLINKLSDBAGE 7 +#define OSPFv3VIRTLINKLSDBCHECKSUM 8 +#define OSPFv3VIRTLINKLSDBADVERTISEMENT 9 +#define OSPFv3VIRTLINKLSDBTYPEKNOWN 10 + /* SYNTAX Status from OSPF-MIB. */ #define OSPF_STATUS_ENABLED 1 #define OSPF_STATUS_DISABLED 2 @@ -105,6 +207,7 @@ #define COUNTER ASN_COUNTER #define INTEGER ASN_INTEGER #define GAUGE ASN_GAUGE +#define UNSIGNED ASN_UNSIGNED #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR @@ -112,16 +215,9 @@ /* For return values e.g. SNMP_INTEGER macro */ SNMP_LOCAL_VARIABLES -static struct in_addr tmp; -#define INT32_INADDR(x) \ - (tmp.s_addr = (x), tmp) - /* OSPFv3-MIB instances. */ oid ospfv3_oid [] = { OSPFv3MIB }; -/* empty ID 0.0.0.0 e.g. empty router-id */ -static struct in_addr ospf6_empty_id = {0}; - /* Hook functions. */ static u_char *ospfv3GeneralGroup (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); @@ -133,7 +229,7 @@ static u_char *ospfv3AreaLsdbEntry (struct variable *, oid *, size_t *, struct variable ospfv3_variables[] = { /* OSPF general variables */ - {OSPFv3ROUTERID, IPADDRESS, RWRITE, ospfv3GeneralGroup, + {OSPFv3ROUTERID, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 1}}, {OSPFv3ADMINSTAT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 2}}, @@ -145,7 +241,7 @@ struct variable ospfv3_variables[] = 3, {1, 1, 5}}, {OSPFv3ASSCOPELSACOUNT, GAUGE, RONLY, ospfv3GeneralGroup, 3, {1, 1, 6}}, - {OSPFv3ASSCOPELSACHECKSUMSUM, INTEGER, RONLY, ospfv3GeneralGroup, + {OSPFv3ASSCOPELSACHECKSUMSUM,UNSIGNED, RONLY, ospfv3GeneralGroup, 3, {1, 1, 7}}, {OSPFv3ORIGINATENEWLSAS, COUNTER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 8}}, @@ -155,30 +251,36 @@ struct variable ospfv3_variables[] = 3, {1, 1, 10}}, {OSPFv3EXTAREALSDBLIMIT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 11}}, - {OSPFv3MULTICASTEXTENSIONS, INTEGER, RWRITE, ospfv3GeneralGroup, + {OSPFv3EXITOVERFLOWINTERVAL, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 12}}, - {OSPFv3EXITOVERFLOWINTERVAL, INTEGER, RWRITE, ospfv3GeneralGroup, - 3, {1, 1, 13}}, {OSPFv3DEMANDEXTENSIONS, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 13}}, + {OSPFv3REFERENCEBANDWIDTH, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 14}}, - {OSPFv3TRAFFICENGINEERINGSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, + {OSPFv3RESTARTSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 15}}, - {OSPFv3REFERENCEBANDWIDTH, INTEGER, RWRITE, ospfv3GeneralGroup, + {OSPFv3RESTARTINTERVAL, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 16}}, - {OSPFv3RESTARTSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, + {OSPFv3RESTARTSTRICTLSACHECKING, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 17}}, - {OSPFv3RESTARTINTERVAL, INTEGER, RWRITE, ospfv3GeneralGroup, - 3, {1, 1, 18}}, {OSPFv3RESTARTSTATUS, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 18}}, + {OSPFv3RESTARTAGE, UNSIGNED, RONLY, ospfv3GeneralGroup, 3, {1, 1, 19}}, - {OSPFv3RESTARTAGE, INTEGER, RONLY, ospfv3GeneralGroup, - 3, {1, 1, 20}}, {OSPFv3RESTARTEXITREASON, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 20}}, + {OSPFv3NOTIFICATIONENABLE, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 21}}, + {OSPFv3STUBROUTERSUPPORT, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 22}}, + {OSPFv3STUBROUTERADVERTISEMENT, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 23}}, + {OSPFv3DISCONTINUITYTIME, TIMETICKS, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 24}}, + {OSPFv3RESTARTTIME, TIMETICKS, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 25}}, /* OSPFv3 Area Data Structure */ - {OSPFv3AREAID, IPADDRESS, RONLY, ospfv3AreaEntry, - 4, {1, 2, 1, 1}}, {OSPFv3IMPORTASEXTERN, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 2}}, {OSPFv3AREASPFRUNS, COUNTER, RONLY, ospfv3AreaEntry, @@ -189,36 +291,31 @@ struct variable ospfv3_variables[] = 4, {1, 2, 1, 5}}, {OSPFv3AREASCOPELSACOUNT, GAUGE, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 6}}, - {OSPFv3AREASCOPELSACKSUMSUM, INTEGER, RONLY, ospfv3AreaEntry, + {OSPFv3AREASCOPELSACKSUMSUM, UNSIGNED, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 7}}, {OSPFv3AREASUMMARY, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 8}}, - {OSPFv3AREASTATUS, INTEGER, RWRITE, ospfv3AreaEntry, + {OSPFv3AREAROWSTATUS, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 9}}, - {OSPFv3STUBMETRIC, INTEGER, RWRITE, ospfv3AreaEntry, + {OSPFv3AREASTUBMETRIC, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 10}}, {OSPFv3AREANSSATRANSLATORROLE, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 11}}, {OSPFv3AREANSSATRANSLATORSTATE, INTEGER, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 12}}, - {OSPFv3AREANSSATRANSLATORSTABILITYINTERVAL, INTEGER, RWRITE, ospfv3AreaEntry, + {OSPFv3AREANSSATRANSLATORSTABINTERVAL, UNSIGNED, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 13}}, {OSPFv3AREANSSATRANSLATOREVENTS, COUNTER, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 14}}, {OSPFv3AREASTUBMETRICTYPE, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 15}}, + {OSPFv3AREATEENABLED, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 16}}, - {OSPFv3AREALSDBAREAID, IPADDRESS, RONLY, ospfv3AreaLsdbEntry, - 4, {1, 4, 1, 1}}, - {OSPFv3AREALSDBTYPE, GAUGE, RONLY, ospfv3AreaLsdbEntry, - 4, {1, 4, 1, 2}}, - {OSPFv3AREALSDBROUTERID, IPADDRESS, RONLY, ospfv3AreaLsdbEntry, - 4, {1, 4, 1, 3}}, - {OSPFv3AREALSDBLSID, IPADDRESS, RONLY, ospfv3AreaLsdbEntry, - 4, {1, 4, 1, 4}}, + /* OSPFv3 Area LSDB */ {OSPFv3AREALSDBSEQUENCE, INTEGER, RONLY, ospfv3AreaLsdbEntry, 4, {1, 4, 1, 5}}, - {OSPFv3AREALSDBAGE, INTEGER, RONLY, ospfv3AreaLsdbEntry, + {OSPFv3AREALSDBAGE, UNSIGNED, RONLY, ospfv3AreaLsdbEntry, 4, {1, 4, 1, 6}}, {OSPFv3AREALSDBCHECKSUM, INTEGER, RONLY, ospfv3AreaLsdbEntry, 4, {1, 4, 1, 7}}, @@ -241,54 +338,36 @@ ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, /* Return the current value of the variable */ switch (v->magic) { - case OSPFv3ROUTERID: /* 1*/ + case OSPFv3ROUTERID: /* Router-ID of this OSPF instance. */ if (ospf6) - return SNMP_IPADDRESS (INT32_INADDR (ospf6->router_id)); - else - return SNMP_IPADDRESS (ospf6_empty_id); - break; - case OSPFv3ADMINSTAT: /* 2*/ - break; - case OSPFv3VERSIONNUMBER: /* 3*/ - break; - case OSPFv3AREABDRRTRSTATUS: /* 4*/ - break; - case OSPFv3ASBDRRTRSTATUS: /* 5*/ - break; - case OSPFv3ASSCOPELSACOUNT: /* 6*/ - break; - case OSPFv3ASSCOPELSACHECKSUMSUM: /* 7*/ - break; - case OSPFv3ORIGINATENEWLSAS: /* 8*/ - break; - case OSPFv3RXNEWLSAS: /* 9*/ - break; - case OSPFv3EXTLSACOUNT: /*10*/ - break; - case OSPFv3EXTAREALSDBLIMIT: /*11*/ - break; - case OSPFv3MULTICASTEXTENSIONS: /*12*/ - break; - case OSPFv3EXITOVERFLOWINTERVAL: /*13*/ - break; - case OSPFv3DEMANDEXTENSIONS: /*14*/ - break; - case OSPFv3TRAFFICENGINEERINGSUPPORT: /*15*/ - break; - case OSPFv3REFERENCEBANDWIDTH: /*16*/ - break; - case OSPFv3RESTARTSUPPORT: /*17*/ - break; - case OSPFv3RESTARTINTERVAL: /*18*/ - break; - case OSPFv3RESTARTSTATUS: /*19*/ - break; - case OSPFv3RESTARTAGE: /*20*/ - break; - case OSPFv3RESTARTEXITREASON: /*21*/ - break; - default: + return SNMP_INTEGER (ntohl (ospf6->router_id)); + return SNMP_INTEGER (0); + case OSPFv3ADMINSTAT: + case OSPFv3VERSIONNUMBER: + case OSPFv3AREABDRRTRSTATUS: + case OSPFv3ASBDRRTRSTATUS: + case OSPFv3ASSCOPELSACOUNT: + case OSPFv3ASSCOPELSACHECKSUMSUM: + case OSPFv3ORIGINATENEWLSAS: + case OSPFv3RXNEWLSAS: + case OSPFv3EXTLSACOUNT: + case OSPFv3EXTAREALSDBLIMIT: + case OSPFv3EXITOVERFLOWINTERVAL: + case OSPFv3DEMANDEXTENSIONS: + case OSPFv3REFERENCEBANDWIDTH: + case OSPFv3RESTARTSUPPORT: + case OSPFv3RESTARTINTERVAL: + case OSPFv3RESTARTSTRICTLSACHECKING: + case OSPFv3RESTARTSTATUS: + case OSPFv3RESTARTAGE: + case OSPFv3RESTARTEXITREASON: + case OSPFv3NOTIFICATIONENABLE: + case OSPFv3STUBROUTERSUPPORT: + case OSPFv3STUBROUTERADVERTISEMENT: + case OSPFv3DISCONTINUITYTIME: + case OSPFv3RESTARTTIME: + /* TODO: Not implemented */ return NULL; } return NULL; @@ -302,6 +381,7 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, u_int32_t area_id = 0; struct listnode *node; unsigned int len; + char a[16]; if (ospf6 == NULL) return NULL; @@ -311,15 +391,15 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, return NULL; len = *length - v->namelen; - len = (len >= sizeof (u_int32_t) ? sizeof (u_int32_t) : 0); - if (exact && len != sizeof (u_int32_t)) + len = (len >= 1 ? sizeof 1 : 0); + if (exact && len != 1) return NULL; if (len) - oid2in_addr (name + v->namelen, len, (struct in_addr *) &area_id); + area_id = htonl (name[v->namelen]); + inet_ntop (AF_INET, &area_id, a, sizeof (a)); zlog_debug ("SNMP access by area: %s, exact=%d len=%d length=%lu", - inet_ntoa (* (struct in_addr *) &area_id), - exact, len, (u_long)*length); + a, exact, len, (u_long)*length); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { @@ -337,25 +417,34 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, if (area == NULL) return NULL; - *length = v->namelen + sizeof (u_int32_t); - oid_copy_addr (name + v->namelen, (struct in_addr *) &area->area_id, - sizeof (u_int32_t)); + *length = v->namelen + 1; + name[v->namelen] = ntohl (area->area_id); + inet_ntop (AF_INET, &area->area_id, a, sizeof (a)); zlog_debug ("SNMP found area: %s, exact=%d len=%d length=%lu", - inet_ntoa (* (struct in_addr *) &area->area_id), - exact, len, (u_long)*length); + a, exact, len, (u_long)*length); switch (v->magic) { - case OSPFv3AREAID: /* 1*/ - return SNMP_IPADDRESS (INT32_INADDR (area->area_id)); - break; - case OSPFv3IMPORTASEXTERN: /* 2*/ + case OSPFv3IMPORTASEXTERN: return SNMP_INTEGER (ospf6->external_table->count); break; - default: + case OSPFv3AREASPFRUNS: + case OSPFv3AREABDRRTRCOUNT: + case OSPFv3AREAASBDRRTRCOUNT: + case OSPFv3AREASCOPELSACOUNT: + case OSPFv3AREASCOPELSACKSUMSUM: + case OSPFv3AREASUMMARY: + case OSPFv3AREAROWSTATUS: + case OSPFv3AREASTUBMETRIC: + case OSPFv3AREANSSATRANSLATORROLE: + case OSPFv3AREANSSATRANSLATORSTATE: + case OSPFv3AREANSSATRANSLATORSTABINTERVAL: + case OSPFv3AREANSSATRANSLATOREVENTS: + case OSPFv3AREASTUBMETRICTYPE: + case OSPFv3AREATEENABLED: + /* Not implemented. */ return NULL; - break; } return NULL; } @@ -365,10 +454,8 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; - struct in_addr area_id; + u_int32_t area_id, id, adv_router; u_int16_t type; - struct in_addr id; - struct in_addr adv_router; int len; oid *offset; int offsetlen; @@ -380,10 +467,7 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, == MATCH_FAILED) return NULL; - memset (&area_id, 0, sizeof (struct in_addr)); - type = 0; - memset (&id, 0, sizeof (struct in_addr)); - memset (&adv_router, 0, sizeof (struct in_addr)); + area_id = type = id = adv_router = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) @@ -393,37 +477,36 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, offset = name + v->namelen; offsetlen = *length - v->namelen; -#define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET \ - (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) +#define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET 4 if (exact && offsetlen != OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET) return NULL; /* Parse area-id */ - len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); + len = (offsetlen < 1 ? 0 : 1); if (len) - oid2in_addr (offset, len, &area_id); + area_id = htonl (*offset); offset += len; offsetlen -= len; /* Parse type */ - len = (offsetlen < 1 ? offsetlen : 1); + len = (offsetlen < 1 ? 0 : 1); if (len) type = htons (*offset); offset += len; offsetlen -= len; /* Parse Router-ID */ - len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); + len = (offsetlen < 1 ? 0 : 1); if (len) - oid2in_addr (offset, len, &adv_router); + adv_router = htonl (*offset); offset += len; offsetlen -= len; /* Parse LS-ID */ - len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); + len = (offsetlen < 1 ? 0 : 1); if (len) - oid2in_addr (offset, len, &id); + id = htonl (*offset); offset += len; offsetlen -= len; @@ -436,8 +519,8 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, if (exact) { - oa = ospf6_area_lookup (area_id.s_addr, ospf6); - lsa = ospf6_lsdb_lookup (type, id.s_addr, adv_router.s_addr, oa->lsdb); + oa = ospf6_area_lookup (area_id, ospf6); + lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); } else { @@ -445,16 +528,16 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, { if (lsa) continue; - if (ntohl (oa->area_id) < ntohl (area_id.s_addr)) + if (oa->area_id < area_id) continue; - lsa = ospf6_lsdb_lookup_next (type, id.s_addr, adv_router.s_addr, + lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oa->lsdb); if (! lsa) { type = 0; - memset (&id, 0, sizeof (struct in_addr)); - memset (&adv_router, 0, sizeof (struct in_addr)); + id = 0; + adv_router = 0; } } } @@ -471,55 +554,36 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, /* Add Index (AreaId, Type, RouterId, Lsid) */ *length = v->namelen + OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET; offset = name + v->namelen; - oid_copy_addr (offset, (struct in_addr *) &oa->area_id, IN_ADDR_SIZE); - offset += IN_ADDR_SIZE; + *offset = ntohl (oa->area_id); + offset++; *offset = ntohs (lsa->header->type); offset++; - oid_copy_addr (offset, (struct in_addr *) &lsa->header->adv_router, - IN_ADDR_SIZE); - offset += IN_ADDR_SIZE; - oid_copy_addr (offset, (struct in_addr *) &lsa->header->id, IN_ADDR_SIZE); - offset += IN_ADDR_SIZE; + *offset = ntohl (lsa->header->adv_router); + offset++; + *offset = ntohl (lsa->header->id); + offset++; /* Return the current value of the variable */ switch (v->magic) { - case OSPFv3AREALSDBAREAID: /* 1 */ - area_id.s_addr = OSPF6_AREA (lsa->lsdb->data)->area_id; - return SNMP_IPADDRESS (area_id); - break; - case OSPFv3AREALSDBTYPE: /* 2 */ - return SNMP_INTEGER (ntohs (lsa->header->type)); + case OSPFv3AREALSDBSEQUENCE: + return SNMP_INTEGER (ntohl (lsa->header->seqnum)); break; - case OSPFv3AREALSDBROUTERID: /* 3 */ - adv_router.s_addr = lsa->header->adv_router; - return SNMP_IPADDRESS (adv_router); - break; - case OSPFv3AREALSDBLSID: /* 4 */ - id.s_addr = lsa->header->id; - return SNMP_IPADDRESS (id); - break; - case OSPFv3AREALSDBSEQUENCE: /* 5 */ - return SNMP_INTEGER (lsa->header->seqnum); - break; - case OSPFv3AREALSDBAGE: /* 6 */ + case OSPFv3AREALSDBAGE: ospf6_lsa_age_current (lsa); - return SNMP_INTEGER (lsa->header->age); + return SNMP_INTEGER (ntohs (lsa->header->age)); break; - case OSPFv3AREALSDBCHECKSUM: /* 7 */ - return SNMP_INTEGER (lsa->header->checksum); + case OSPFv3AREALSDBCHECKSUM: + return SNMP_INTEGER (ntohs (lsa->header->checksum)); break; - case OSPFv3AREALSDBADVERTISEMENT: /* 8 */ + case OSPFv3AREALSDBADVERTISEMENT: *var_len = ntohs (lsa->header->length); return (u_char *) lsa->header; break; - case OSPFv3AREALSDBTYPEKNOWN: /* 9 */ + case OSPFv3AREALSDBTYPEKNOWN: return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ? SNMP_TRUE : SNMP_FALSE); break; - default: - return NULL; - break; } return NULL; } From 061bc735b4fb3b8768fa5f52295d85838ed55770 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 31 May 2012 20:21:15 +0200 Subject: [PATCH 0101/1342] ospf6d: add SNMP support for ospfv3NbrTable --- ospf6d/ospf6_neighbor.c | 2 + ospf6d/ospf6_neighbor.h | 1 + ospf6d/ospf6_snmp.c | 164 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index f6c3aeac7..ab157ca86 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -89,6 +89,7 @@ ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi) buf, oi->interface->name); on->ospf6_if = oi; on->state = OSPF6_NEIGHBOR_DOWN; + on->state_change = 0; quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed); on->router_id = router_id; @@ -154,6 +155,7 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on) if (prev_state == next_state) return; + on->state_change++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed); /* log */ diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index b3bd173fc..5f46c6f38 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -46,6 +46,7 @@ struct ospf6_neighbor u_char state; /* timestamp of last changing state */ + u_int32_t state_change; struct timeval last_changed; /* Neighbor Router ID */ diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 95b4fc08c..5e4ca0f66 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -225,6 +225,8 @@ static u_char *ospfv3AreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3AreaLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); +static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); struct variable ospfv3_variables[] = { @@ -324,6 +326,31 @@ struct variable ospfv3_variables[] = {OSPFv3AREALSDBTYPEKNOWN, INTEGER, RONLY, ospfv3AreaLsdbEntry, 4, {1, 4, 1, 9}}, + /* OSPFv3 neighbors */ + {OSPFv3NBRADDRESSTYPE, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 4}}, + {OSPFv3NBRADDRESS, STRING, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 5}}, + {OSPFv3NBROPTIONS, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 6}}, + {OSPFv3NBRPRIORITY, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 7}}, + {OSPFv3NBRSTATE, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 8}}, + {OSPFv3NBREVENTS, COUNTER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 9}}, + {OSPFv3NBRLSRETRANSQLEN, GAUGE, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 10}}, + {OSPFv3NBRHELLOSUPPRESSED, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 11}}, + {OSPFv3NBRIFID, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 12}}, + {OSPFv3NBRRESTARTHELPERSTATUS, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 13}}, + {OSPFv3NBRRESTARTHELPERAGE, UNSIGNED, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 14}}, + {OSPFv3NBRRESTARTHELPEREXITREASON, INTEGER, RONLY, ospfv3NbrEntry, + 4, {1, 9, 1, 15}}, }; static u_char * @@ -588,6 +615,143 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, return NULL; } +static int +if_icmp_func (struct interface *ifp1, struct interface *ifp2) +{ + return (ifp1->ifindex - ifp2->ifindex); +} + +static u_char * +ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + unsigned int ifindex, instid, rtrid; + struct ospf6_interface *oi = NULL; + struct ospf6_neighbor *on = NULL; + struct interface *iif; + struct listnode *i, *j; + struct list *ifslist; + oid *offset; + int offsetlen, len; + + if (smux_header_table (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + ifindex = instid = rtrid = 0; + + /* Check OSPFv3 instance. */ + if (ospf6 == NULL) + return NULL; + + /* Get variable length. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + + if (exact && offsetlen != 3) + return NULL; + + /* Parse if index */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + ifindex = *offset; + offset += len; + offsetlen -= len; + + /* Parse instance ID */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + instid = *offset; + offset += len; + offsetlen -= len; + + /* Parse router ID */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + rtrid = htonl (*offset); + offset += len; + offsetlen -= len; + + if (exact) + { + oi = ospf6_interface_lookup_by_ifindex (ifindex); + on = ospf6_neighbor_lookup (rtrid, oi); + if (oi->instance_id != instid) return NULL; + } + else + { + /* We build a sorted list of interfaces */ + ifslist = list_new (); + if (!ifslist) return NULL; + ifslist->cmp = (int (*)(void *, void *))if_icmp_func; + for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) + listnode_add_sort (ifslist, iif); + + for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) + { + if (!iif->ifindex) continue; + oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); + if (!oi) continue; + for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) { + if (iif->ifindex > ifindex || + (iif->ifindex == ifindex && + (oi->instance_id > instid || + (oi->instance_id == instid && + ntohl (on->router_id) > ntohl (rtrid))))) + break; + } + if (on) break; + oi = on = NULL; + } + + list_delete_all_node (ifslist); + } + + if (!oi || !on) return NULL; + + /* Add Index (IfIndex, IfInstId, RtrId) */ + *length = v->namelen + 3; + offset = name + v->namelen; + *offset = oi->interface->ifindex; + offset++; + *offset = oi->instance_id; + offset++; + *offset = ntohl (on->router_id); + offset++; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFv3NBRADDRESSTYPE: + return SNMP_INTEGER (2); /* IPv6 only */ + case OSPFv3NBRADDRESS: + *var_len = sizeof (struct in6_addr); + return (u_char *) &on->linklocal_addr; + case OSPFv3NBROPTIONS: + return SNMP_INTEGER (on->options[2]); + case OSPFv3NBRPRIORITY: + return SNMP_INTEGER (on->priority); + case OSPFv3NBRSTATE: + return SNMP_INTEGER (on->state); + case OSPFv3NBREVENTS: + return SNMP_INTEGER (on->state_change); + case OSPFv3NBRLSRETRANSQLEN: + return SNMP_INTEGER (on->retrans_list->count); + case OSPFv3NBRHELLOSUPPRESSED: + return SNMP_INTEGER (SNMP_FALSE); + case OSPFv3NBRIFID: + return SNMP_INTEGER (on->ifindex); + case OSPFv3NBRRESTARTHELPERSTATUS: + case OSPFv3NBRRESTARTHELPERAGE: + case OSPFv3NBRRESTARTHELPEREXITREASON: + /* Not implemented. Only works if all the last ones are not + implemented! */ + return NULL; + } + + return NULL; +} + /* Register OSPFv3-MIB. */ void From 2c5f148065c074d51ff10808a2b6ac2b3296a828 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Fri, 1 Jun 2012 11:38:34 +0200 Subject: [PATCH 0102/1342] ospf6d: complete SNMP implementation for scalar objects --- ospf6d/ospf6_snmp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 5e4ca0f66..9f333a816 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -357,6 +357,10 @@ static u_char * ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { + u_int16_t sum; + u_int32_t count; + struct ospf6_lsa *lsa = NULL; + /* Check whether the instance identifier is valid */ if (smux_header_generic (v, name, length, exact, var_len, write_method) == MATCH_FAILED) @@ -371,18 +375,58 @@ ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, return SNMP_INTEGER (ntohl (ospf6->router_id)); return SNMP_INTEGER (0); case OSPFv3ADMINSTAT: + if (ospf6) + return SNMP_INTEGER (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)? + OSPF_STATUS_DISABLED:OSPF_STATUS_ENABLED); + return SNMP_INTEGER (OSPF_STATUS_DISABLED); case OSPFv3VERSIONNUMBER: + return SNMP_INTEGER (3); case OSPFv3AREABDRRTRSTATUS: + if (ospf6) + return SNMP_INTEGER (ospf6_is_router_abr (ospf6)?SNMP_TRUE:SNMP_FALSE); + return SNMP_INTEGER (SNMP_FALSE); case OSPFv3ASBDRRTRSTATUS: + if (ospf6) + return SNMP_INTEGER (ospf6_asbr_is_asbr (ospf6)?SNMP_TRUE:SNMP_FALSE); + return SNMP_INTEGER (SNMP_FALSE); case OSPFv3ASSCOPELSACOUNT: + if (ospf6) + return SNMP_INTEGER (ospf6->lsdb->count); + return SNMP_INTEGER (0); case OSPFv3ASSCOPELSACHECKSUMSUM: + if (ospf6) + { + for (sum = 0, lsa = ospf6_lsdb_head (ospf6->lsdb); + lsa; + lsa = ospf6_lsdb_next (lsa)) + sum += ntohs (lsa->header->checksum); + return SNMP_INTEGER (sum); + } + return SNMP_INTEGER (0); case OSPFv3ORIGINATENEWLSAS: + return SNMP_INTEGER (0); /* Don't know where to get this value... */ case OSPFv3RXNEWLSAS: + return SNMP_INTEGER (0); /* Don't know where to get this value... */ case OSPFv3EXTLSACOUNT: + if (ospf6) + { + for (count = 0, lsa = ospf6_lsdb_type_head (htons (OSPF6_LSTYPE_AS_EXTERNAL), + ospf6->lsdb); + lsa; + lsa = ospf6_lsdb_type_next (htons (OSPF6_LSTYPE_AS_EXTERNAL), + lsa)) + count += 1; + return SNMP_INTEGER (count); + } + return SNMP_INTEGER (0); case OSPFv3EXTAREALSDBLIMIT: + return SNMP_INTEGER (-1); case OSPFv3EXITOVERFLOWINTERVAL: + return SNMP_INTEGER (0); /* Not supported */ case OSPFv3DEMANDEXTENSIONS: + return SNMP_INTEGER (0); /* Not supported */ case OSPFv3REFERENCEBANDWIDTH: + return SNMP_INTEGER (100000); case OSPFv3RESTARTSUPPORT: case OSPFv3RESTARTINTERVAL: case OSPFv3RESTARTSTRICTLSACHECKING: From ea86e4042b7459fbf5d96835c509cb743bf013c0 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 4 Jun 2012 10:29:49 +0200 Subject: [PATCH 0103/1342] ospf6d: complete SNMP implementation of ospfv3AreaTable --- ospf6d/ospf6_area.h | 1 + ospf6d/ospf6_snmp.c | 30 ++++++++++++++++++++++++++++-- ospf6d/ospf6_spf.c | 2 ++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index c7c5ee358..e8a4fbd87 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -57,6 +57,7 @@ struct ospf6_area struct thread *thread_spf_calculation; struct thread *thread_route_calculation; + u_int32_t spf_calculation; /* SPF calculation count */ struct thread *thread_router_lsa; struct thread *thread_intra_prefix_lsa; diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 9f333a816..293d66a12 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -449,10 +449,14 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_area *oa, *area = NULL; + struct ospf6_lsa *lsa = NULL; u_int32_t area_id = 0; + u_int32_t count; + u_int16_t sum; struct listnode *node; unsigned int len; char a[16]; + struct ospf6_route *ro; if (ospf6 == NULL) return NULL; @@ -498,15 +502,37 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, switch (v->magic) { case OSPFv3IMPORTASEXTERN: - return SNMP_INTEGER (ospf6->external_table->count); - break; + /* No NSSA support */ + return SNMP_INTEGER (IS_AREA_STUB(area)?2:1); case OSPFv3AREASPFRUNS: + return SNMP_INTEGER (area->spf_calculation); case OSPFv3AREABDRRTRCOUNT: case OSPFv3AREAASBDRRTRCOUNT: + count = 0; + for (ro = ospf6_route_head (ospf6->brouter_table); ro; + ro = ospf6_route_next (ro)) + { + if (ntohl (ro->path.area_id) != ntohl (area->area_id)) continue; + if (v->magic == OSPFv3AREABDRRTRCOUNT && + CHECK_FLAG (ro->path.router_bits, OSPF6_ROUTER_BIT_B)) + count++; + if (v->magic == OSPFv3AREAASBDRRTRCOUNT && + CHECK_FLAG (ro->path.router_bits, OSPF6_ROUTER_BIT_E)) + count++; + } + return SNMP_INTEGER (count); case OSPFv3AREASCOPELSACOUNT: + return SNMP_INTEGER (area->lsdb->count); case OSPFv3AREASCOPELSACKSUMSUM: + for (sum = 0, lsa = ospf6_lsdb_head (area->lsdb); + lsa; + lsa = ospf6_lsdb_next (lsa)) + sum += ntohs (lsa->header->checksum); + return SNMP_INTEGER (sum); case OSPFv3AREASUMMARY: + return SNMP_INTEGER (2); /* sendAreaSummary */ case OSPFv3AREAROWSTATUS: + return SNMP_INTEGER (1); /* Active */ case OSPFv3AREASTUBMETRIC: case OSPFv3AREANSSATRANSLATORROLE: case OSPFv3AREANSSATRANSLATORSTATE: diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index a4a5b7218..da0ee131b 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -473,6 +473,8 @@ ospf6_spf_calculation (u_int32_t router_id, } pqueue_delete (candidate_list); + + oa->spf_calculation++; } static void From 3bc4f84efe147ebc65fccbe898b81d78341c542b Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 4 Jun 2012 11:40:04 +0200 Subject: [PATCH 0104/1342] ospf6d: add SNMP implementation of ospfv3IfTable --- ospf6d/ospf6_interface.c | 1 + ospf6d/ospf6_interface.h | 2 + ospf6d/ospf6_snmp.c | 204 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 206 insertions(+), 1 deletion(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 71aa6859c..6f7aaa8af 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -394,6 +394,7 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) ospf6_interface_state_str[prev_state], ospf6_interface_state_str[next_state]); } + oi->state_change++; if ((prev_state == OSPF6_INTERFACE_DR || prev_state == OSPF6_INTERFACE_BDR) && diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 2d1ff34db..d80b07303 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -64,6 +64,8 @@ struct ospf6_interface u_int16_t dead_interval; u_int32_t rxmt_interval; + u_int32_t state_change; + /* Cost */ u_int32_t cost; diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 293d66a12..1880fc0a3 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -227,6 +227,8 @@ static u_char *ospfv3AreaLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); +static u_char *ospfv3IfEntry (struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); struct variable ospfv3_variables[] = { @@ -326,6 +328,54 @@ struct variable ospfv3_variables[] = {OSPFv3AREALSDBTYPEKNOWN, INTEGER, RONLY, ospfv3AreaLsdbEntry, 4, {1, 4, 1, 9}}, + /* OSPFv3 interfaces */ + {OSPFv3IFAREAID, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 3}}, + {OSPFv3IFTYPE, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 4}}, + {OSPFv3IFADMINSTATUS, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 5}}, + {OSPFv3IFRTRPRIORITY, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 6}}, + {OSPFv3IFTRANSITDELAY, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 7}}, + {OSPFv3IFRETRANSINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 8}}, + {OSPFv3IFHELLOINTERVAL, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 9}}, + {OSPFv3IFRTRDEADINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 10}}, + {OSPFv3IFPOLLINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 11}}, + {OSPFv3IFSTATE, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 12}}, + {OSPFv3IFDESIGNATEDROUTER, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 13}}, + {OSPFv3IFBACKUPDESIGNATEDROUTER, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 14}}, + {OSPFv3IFEVENTS, COUNTER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 15}}, + {OSPFv3IFROWSTATUS, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 16}}, + {OSPFv3IFDEMAND, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 17}}, + {OSPFv3IFMETRICVALUE, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 18}}, + {OSPFv3IFLINKSCOPELSACOUNT, GAUGE, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 19}}, + {OSPFv3IFLINKLSACKSUMSUM, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 20}}, + {OSPFv3IFDEMANDNBRPROBE, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 21}}, + {OSPFv3IFDEMANDNBRPROBERETRANSLIMIT, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 22}}, + {OSPFv3IFDEMANDNBRPROBEINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 23}}, + {OSPFv3IFTEDISABLED, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 24}}, + {OSPFv3IFLINKLSASUPPRESSION, INTEGER, RONLY, ospfv3IfEntry, + 4, {1, 7, 1, 25}}, + /* OSPFv3 neighbors */ {OSPFv3NBRADDRESSTYPE, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 4}}, @@ -691,6 +741,159 @@ if_icmp_func (struct interface *ifp1, struct interface *ifp2) return (ifp1->ifindex - ifp2->ifindex); } +static u_char * +ospfv3IfEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + unsigned int ifindex, instid; + struct ospf6_interface *oi = NULL; + struct ospf6_lsa *lsa = NULL; + struct interface *iif; + struct listnode *i; + struct list *ifslist; + oid *offset; + int offsetlen, len; + u_int32_t sum; + + if (smux_header_table (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + ifindex = instid = 0; + + /* Check OSPFv3 instance. */ + if (ospf6 == NULL) + return NULL; + + /* Get variable length. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + + if (exact && offsetlen != 2) + return NULL; + + /* Parse if index */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + ifindex = *offset; + offset += len; + offsetlen -= len; + + /* Parse instance ID */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + instid = *offset; + offset += len; + offsetlen -= len; + + if (exact) + { + oi = ospf6_interface_lookup_by_ifindex (ifindex); + if (oi->instance_id != instid) return NULL; + } + else + { + /* We build a sorted list of interfaces */ + ifslist = list_new (); + if (!ifslist) return NULL; + ifslist->cmp = (int (*)(void *, void *))if_icmp_func; + for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) + listnode_add_sort (ifslist, iif); + + for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) + { + if (!iif->ifindex) continue; + oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); + if (!oi) continue; + if (iif->ifindex > ifindex || + (iif->ifindex == ifindex && + (oi->instance_id > instid))) + break; + oi = NULL; + } + + list_delete_all_node (ifslist); + } + + if (!oi) return NULL; + + /* Add Index (IfIndex, IfInstId) */ + *length = v->namelen + 2; + offset = name + v->namelen; + *offset = oi->interface->ifindex; + offset++; + *offset = oi->instance_id; + offset++; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFv3IFAREAID: + if (oi->area) + return SNMP_INTEGER (ntohl (oi->area->area_id)); + break; + case OSPFv3IFTYPE: + if (if_is_broadcast (oi->interface)) + return SNMP_INTEGER (1); + else if (if_is_pointopoint (oi->interface)) + return SNMP_INTEGER (3); + else break; /* Unknown, don't put anything */ + case OSPFv3IFADMINSTATUS: + if (oi->area) + return SNMP_INTEGER (OSPF_STATUS_ENABLED); + return SNMP_INTEGER (OSPF_STATUS_DISABLED); + case OSPFv3IFRTRPRIORITY: + return SNMP_INTEGER (oi->priority); + case OSPFv3IFTRANSITDELAY: + return SNMP_INTEGER (oi->transdelay); + case OSPFv3IFRETRANSINTERVAL: + return SNMP_INTEGER (oi->rxmt_interval); + case OSPFv3IFHELLOINTERVAL: + return SNMP_INTEGER (oi->hello_interval); + case OSPFv3IFRTRDEADINTERVAL: + return SNMP_INTEGER (oi->dead_interval); + case OSPFv3IFPOLLINTERVAL: + /* No support for NBMA */ + break; + case OSPFv3IFSTATE: + return SNMP_INTEGER (oi->state); + case OSPFv3IFDESIGNATEDROUTER: + return SNMP_INTEGER (ntohl (oi->drouter)); + case OSPFv3IFBACKUPDESIGNATEDROUTER: + return SNMP_INTEGER (ntohl (oi->bdrouter)); + case OSPFv3IFEVENTS: + return SNMP_INTEGER (oi->state_change); + case OSPFv3IFROWSTATUS: + return SNMP_INTEGER (1); + case OSPFv3IFDEMAND: + return SNMP_INTEGER (SNMP_FALSE); + case OSPFv3IFMETRICVALUE: + return SNMP_INTEGER (oi->cost); + case OSPFv3IFLINKSCOPELSACOUNT: + return SNMP_INTEGER (oi->lsdb->count); + case OSPFv3IFLINKLSACKSUMSUM: + for (sum = 0, lsa = ospf6_lsdb_head (oi->lsdb); + lsa; + lsa = ospf6_lsdb_next (lsa)) + sum += ntohs (lsa->header->checksum); + return SNMP_INTEGER (sum); + case OSPFv3IFDEMANDNBRPROBE: + case OSPFv3IFDEMANDNBRPROBERETRANSLIMIT: + case OSPFv3IFDEMANDNBRPROBEINTERVAL: + case OSPFv3IFTEDISABLED: + case OSPFv3IFLINKLSASUPPRESSION: + /* Not implemented. Only works if all the last ones are not + implemented! */ + return NULL; + } + + /* Try an internal getnext. Some columns are missing in this table. */ + if (!exact && (name[*length-1] < MAX_SUBID)) + return ospfv3IfEntry(v, name, length, + exact, var_len, write_method); + return NULL; +} + static u_char * ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) @@ -822,7 +1025,6 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, return NULL; } - /* Register OSPFv3-MIB. */ void ospf6_snmp_init (struct thread_master *master) From c349bb86927d1f5fc8aa8ebc6f553786f8e70634 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 4 Jun 2012 12:59:20 +0200 Subject: [PATCH 0105/1342] ospf6d: add SNMP support for ospfv3*LsdbTable This includes: - ospfv3AsLsdbTable - ospfv3AreaLsdbTable - ospfv3LinkLsdbTable --- ospf6d/ospf6_snmp.c | 263 +++++++++++++++++++++++++++++--------------- 1 file changed, 174 insertions(+), 89 deletions(-) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 1880fc0a3..ce49331c3 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -90,26 +90,20 @@ #define OSPFv3AREASTUBMETRICTYPE 15 #define OSPFv3AREATEENABLED 16 -/* OSPFv3 MIB AS Lsdb Table values: ospfv3AsLsdbTable */ -#define OSPFv3ASLSDBSEQUENCE 4 -#define OSPFv3ASLSDBAGE 5 -#define OSPFv3ASLSDBCHECKSUM 6 -#define OSPFv3ASLSDBADVERTISEMENT 7 -#define OSPFv3ASLSDBTYPEKNOWN 8 - -/* OSPFv3 MIB Area Lsdb Table values: ospfv3AreaLsdbTable */ -#define OSPFv3AREALSDBSEQUENCE 5 -#define OSPFv3AREALSDBAGE 6 -#define OSPFv3AREALSDBCHECKSUM 7 -#define OSPFv3AREALSDBADVERTISEMENT 8 -#define OSPFv3AREALSDBTYPEKNOWN 9 - -/* OSPFv3 MIB Link Lsdb Table values: ospfv3LinkLsdbTable */ -#define OSPFv3LINKLSDBSEQUENCE 6 -#define OSPFv3LINKLSDBAGE 7 -#define OSPFv3LINKLSDBCHECKSUM 8 -#define OSPFv3LINKLSDBADVERTISEMENT 9 -#define OSPFv3LINKLSDBTYPEKNOWN 10 +/* OSPFv3 MIB * Lsdb Table values: ospfv3*LsdbTable */ +#define OSPFv3WWLSDBSEQUENCE 1 +#define OSPFv3WWLSDBAGE 2 +#define OSPFv3WWLSDBCHECKSUM 3 +#define OSPFv3WWLSDBADVERTISEMENT 4 +#define OSPFv3WWLSDBTYPEKNOWN 5 + +/* Three first bits are to identify column */ +#define OSPFv3WWCOLUMN 0x7 +/* Then we use other bits to identify table */ +#define OSPFv3WWASTABLE (1 << 3) +#define OSPFv3WWAREATABLE (1 << 4) +#define OSPFv3WWLINKTABLE (1 << 5) +#define OSPFv3WWVIRTLINKTABLE (1 << 6) /* OSPFv3 MIB Host Table values: ospfv3HostTable */ #define OSPFv3HOSTMETRIC 3 @@ -192,13 +186,6 @@ #define OSPFv3AREAAGGREGATEEFFECT 7 #define OSPFv3AREAAGGREGATEROUTETAG 8 -/* OSPFv3 MIB Virtual Link Lsdb Table values: ospfv3VirtLinkLsdbTable */ -#define OSPFv3VIRTLINKLSDBSEQUENCE 6 -#define OSPFv3VIRTLINKLSDBAGE 7 -#define OSPFv3VIRTLINKLSDBCHECKSUM 8 -#define OSPFv3VIRTLINKLSDBADVERTISEMENT 9 -#define OSPFv3VIRTLINKLSDBTYPEKNOWN 10 - /* SYNTAX Status from OSPF-MIB. */ #define OSPF_STATUS_ENABLED 1 #define OSPF_STATUS_DISABLED 2 @@ -223,8 +210,8 @@ static u_char *ospfv3GeneralGroup (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3AreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); -static u_char *ospfv3AreaLsdbEntry (struct variable *, oid *, size_t *, - int, size_t *, WriteMethod **); +static u_char *ospfv3WwLsdbEntry (struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3IfEntry (struct variable *, oid *, size_t *, @@ -316,18 +303,42 @@ struct variable ospfv3_variables[] = {OSPFv3AREATEENABLED, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 16}}, + /* OSPFv3 AS LSDB */ + {OSPFv3WWLSDBSEQUENCE | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, + 4, {1, 3, 1, 4}}, + {OSPFv3WWLSDBAGE | OSPFv3WWASTABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, + 4, {1, 3, 1, 5}}, + {OSPFv3WWLSDBCHECKSUM | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, + 4, {1, 3, 1, 6}}, + {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWASTABLE, STRING, RONLY, ospfv3WwLsdbEntry, + 4, {1, 3, 1, 7}}, + {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, + 4, {1, 3, 1, 8}}, + /* OSPFv3 Area LSDB */ - {OSPFv3AREALSDBSEQUENCE, INTEGER, RONLY, ospfv3AreaLsdbEntry, + {OSPFv3WWLSDBSEQUENCE | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 5}}, - {OSPFv3AREALSDBAGE, UNSIGNED, RONLY, ospfv3AreaLsdbEntry, + {OSPFv3WWLSDBAGE | OSPFv3WWAREATABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 6}}, - {OSPFv3AREALSDBCHECKSUM, INTEGER, RONLY, ospfv3AreaLsdbEntry, + {OSPFv3WWLSDBCHECKSUM | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 7}}, - {OSPFv3AREALSDBADVERTISEMENT, STRING, RONLY, ospfv3AreaLsdbEntry, + {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWAREATABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 8}}, - {OSPFv3AREALSDBTYPEKNOWN, INTEGER, RONLY, ospfv3AreaLsdbEntry, + {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 9}}, + /* OSPFv3 Link LSDB */ + {OSPFv3WWLSDBSEQUENCE | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, + 4, {1, 5, 1, 6}}, + {OSPFv3WWLSDBAGE | OSPFv3WWLINKTABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, + 4, {1, 5, 1, 7}}, + {OSPFv3WWLSDBCHECKSUM | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, + 4, {1, 5, 1, 8}}, + {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWLINKTABLE, STRING, RONLY, ospfv3WwLsdbEntry, + 4, {1, 5, 1, 9}}, + {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, + 4, {1, 5, 1, 10}}, + /* OSPFv3 interfaces */ {OSPFv3IFAREAID, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 3}}, @@ -596,12 +607,18 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, return NULL; } +static int +if_icmp_func (struct interface *ifp1, struct interface *ifp2) +{ + return (ifp1->ifindex - ifp2->ifindex); +} + static u_char * -ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, +ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; - u_int32_t area_id, id, adv_router; + u_int32_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; @@ -609,12 +626,15 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, char a[16], b[16], c[16]; struct ospf6_area *oa; struct listnode *node; + struct interface *iif; + struct ospf6_interface *oi = NULL; + struct list *ifslist; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; - area_id = type = id = adv_router = 0; + instid = ifindex = area_id = type = id = adv_router = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) @@ -624,17 +644,38 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, offset = name + v->namelen; offsetlen = *length - v->namelen; -#define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET 4 - - if (exact && offsetlen != OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET) + if (exact && (v->magic & OSPFv3WWASTABLE) && offsetlen != 3) + return NULL; + if (exact && (v->magic & OSPFv3WWAREATABLE) && offsetlen != 4) + return NULL; + if (exact && (v->magic & OSPFv3WWLINKTABLE) && offsetlen != 5) return NULL; - /* Parse area-id */ - len = (offsetlen < 1 ? 0 : 1); - if (len) - area_id = htonl (*offset); - offset += len; - offsetlen -= len; + if (v->magic & OSPFv3WWLINKTABLE) + { + /* Parse ifindex */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + ifindex = *offset; + offset += len; + offsetlen -= len; + + /* Parse instance ID */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + instid = *offset; + offset += len; + offsetlen -= len; + } + else if (v->magic & OSPFv3WWAREATABLE) + { + /* Parse area-id */ + len = (offsetlen < 1 ? 0 : 1); + if (len) + area_id = htonl (*offset); + offset += len; + offsetlen -= len; + } /* Parse type */ len = (offsetlen < 1 ? 0 : 1); @@ -657,52 +698,102 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, offset += len; offsetlen -= len; - inet_ntop (AF_INET, &area_id, a, sizeof (a)); - inet_ntop (AF_INET, &adv_router, b, sizeof (b)); - inet_ntop (AF_INET, &id, c, sizeof (c)); - zlog_debug ("SNMP access by lsdb: area=%s exact=%d length=%lu magic=%d" - " type=%#x adv_router=%s id=%s", - a, exact, (u_long)*length, v->magic, ntohs (type), b, c); - if (exact) { - oa = ospf6_area_lookup (area_id, ospf6); - lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); + if (v->magic & OSPFv3WWASTABLE) + { + lsa = ospf6_lsdb_lookup (type, id, adv_router, ospf6->lsdb); + } + else if (v->magic & OSPFv3WWAREATABLE) + { + oa = ospf6_area_lookup (area_id, ospf6); + lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); + } + else if (v->magic & OSPFv3WWLINKTABLE) + { + oi = ospf6_interface_lookup_by_ifindex (ifindex); + if (oi->instance_id != instid) return NULL; + lsa = ospf6_lsdb_lookup (type, id, adv_router, oi->lsdb); + } } else { - for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) + if (v->magic & OSPFv3WWASTABLE) + { + if (ospf6->lsdb->count) + lsa = ospf6_lsdb_lookup_next (type, id, adv_router, + ospf6->lsdb); + } + else if (v->magic & OSPFv3WWAREATABLE) + for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) + { + if (oa->area_id < area_id) + continue; + + if (oa->lsdb->count) + lsa = ospf6_lsdb_lookup_next (type, id, adv_router, + oa->lsdb); + if (lsa) break; + type = 0; + id = 0; + adv_router = 0; + } + else if (v->magic & OSPFv3WWLINKTABLE) { - if (lsa) - continue; - if (oa->area_id < area_id) - continue; - - lsa = ospf6_lsdb_lookup_next (type, id, adv_router, - oa->lsdb); - if (! lsa) + /* We build a sorted list of interfaces */ + ifslist = list_new (); + if (!ifslist) return NULL; + ifslist->cmp = (int (*)(void *, void *))if_icmp_func; + for (ALL_LIST_ELEMENTS_RO (iflist, node, iif)) + listnode_add_sort (ifslist, iif); + + for (ALL_LIST_ELEMENTS_RO (ifslist, node, iif)) { + if (!iif->ifindex) continue; + oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); + if (!oi) continue; + if (iif->ifindex < ifindex) continue; + if (oi->instance_id < instid) continue; + + if (oi->lsdb->count) + lsa = ospf6_lsdb_lookup_next (type, id, adv_router, + oi->lsdb); + if (lsa) break; type = 0; - id = 0; - adv_router = 0; + id = 0; + adv_router = 0; + oi = NULL; } + + list_delete_all_node (ifslist); } } if (! lsa) - { - zlog_debug ("SNMP respond: No LSA to return"); return NULL; - } - oa = OSPF6_AREA (lsa->lsdb->data); - - zlog_debug ("SNMP respond: area: %s lsa: %s", oa->name, lsa->name); - /* Add Index (AreaId, Type, RouterId, Lsid) */ - *length = v->namelen + OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET; - offset = name + v->namelen; - *offset = ntohl (oa->area_id); - offset++; + /* Add indexes */ + if (v->magic & OSPFv3WWASTABLE) + { + *length = v->namelen + 3; + offset = name + v->namelen; + } + else if (v->magic & OSPFv3WWAREATABLE) + { + *length = v->namelen + 4; + offset = name + v->namelen; + *offset = ntohl (oa->area_id); + offset++; + } + else if (v->magic & OSPFv3WWLINKTABLE) + { + *length = v->namelen + 5; + offset = name + v->namelen; + *offset = oi->interface->ifindex; + offset++; + *offset = oi->instance_id; + offset++; + } *offset = ntohs (lsa->header->type); offset++; *offset = ntohl (lsa->header->adv_router); @@ -711,23 +802,23 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, offset++; /* Return the current value of the variable */ - switch (v->magic) + switch (v->magic & OSPFv3WWCOLUMN) { - case OSPFv3AREALSDBSEQUENCE: + case OSPFv3WWLSDBSEQUENCE: return SNMP_INTEGER (ntohl (lsa->header->seqnum)); break; - case OSPFv3AREALSDBAGE: + case OSPFv3WWLSDBAGE: ospf6_lsa_age_current (lsa); return SNMP_INTEGER (ntohs (lsa->header->age)); break; - case OSPFv3AREALSDBCHECKSUM: + case OSPFv3WWLSDBCHECKSUM: return SNMP_INTEGER (ntohs (lsa->header->checksum)); break; - case OSPFv3AREALSDBADVERTISEMENT: + case OSPFv3WWLSDBADVERTISEMENT: *var_len = ntohs (lsa->header->length); return (u_char *) lsa->header; break; - case OSPFv3AREALSDBTYPEKNOWN: + case OSPFv3WWLSDBTYPEKNOWN: return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ? SNMP_TRUE : SNMP_FALSE); break; @@ -735,12 +826,6 @@ ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, return NULL; } -static int -if_icmp_func (struct interface *ifp1, struct interface *ifp2) -{ - return (ifp1->ifindex - ifp2->ifindex); -} - static u_char * ospfv3IfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) From bf836661ef8ef880350bc41f0a82566ed5075066 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 4 Jun 2012 14:36:12 +0200 Subject: [PATCH 0106/1342] ospf6d: add SNMP notifications/traps support Only implement ospfv3NbrStateChange and ospfv3IfStateChange. --- ospf6d/ospf6_interface.c | 11 ++++++++ ospf6d/ospf6_neighbor.c | 9 +++++++ ospf6d/ospf6_snmp.c | 56 ++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_snmp.h | 2 ++ 4 files changed, 78 insertions(+) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 6f7aaa8af..40cda2460 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -421,6 +421,17 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } + +#ifdef HAVE_SNMP + /* Terminal state or regression */ + if ((next_state == OSPF6_INTERFACE_POINTTOPOINT) || + (next_state == OSPF6_INTERFACE_DROTHER) || + (next_state == OSPF6_INTERFACE_BDR) || + (next_state == OSPF6_INTERFACE_DR) || + (next_state < prev_state)) + ospf6TrapIfStateChange (oi); +#endif + } diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index ab157ca86..806767dd5 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -182,6 +182,15 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on) (next_state != OSPF6_NEIGHBOR_EXCHANGE && next_state != OSPF6_NEIGHBOR_LOADING)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); + +#ifdef HAVE_SNMP + /* Terminal state or regression */ + if ((next_state == OSPF6_NEIGHBOR_FULL) || + (next_state == OSPF6_NEIGHBOR_TWOWAY) || + (next_state < prev_state)) + ospf6TrapNbrStateChange (on); +#endif + } /* RFC2328 section 10.4 */ diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index ce49331c3..a42e57acf 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -204,6 +204,7 @@ SNMP_LOCAL_VARIABLES /* OSPFv3-MIB instances. */ oid ospfv3_oid [] = { OSPFv3MIB }; +oid ospfv3_trap_oid [] = { OSPFv3MIB, 0 }; /* Hook functions. */ static u_char *ospfv3GeneralGroup (struct variable *, oid *, size_t *, @@ -1110,6 +1111,61 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, return NULL; } +/* OSPF Traps. */ +#define NBRSTATECHANGE 2 +#define IFSTATECHANGE 10 + +static struct trap_object ospf6NbrTrapList[] = +{ + {-3, {1, 1, OSPFv3ROUTERID}}, + {4, {1, 9, 1, OSPFv3NBRADDRESSTYPE}}, + {4, {1, 9, 1, OSPFv3NBRADDRESS}}, + {4, {1, 9, 1, OSPFv3NBRSTATE}} +}; + +static struct trap_object ospf6IfTrapList[] = +{ + {-3, {1, 1, OSPFv3ROUTERID}}, + {4, {1, 7, 1, OSPFv3IFSTATE}}, + {4, {1, 7, 1, OSPFv3IFADMINSTATUS}}, + {4, {1, 7, 1, OSPFv3IFAREAID}} +}; + +void +ospf6TrapNbrStateChange (struct ospf6_neighbor *on) +{ + oid index[3]; + + index[0] = on->ospf6_if->interface->ifindex; + index[1] = on->ospf6_if->instance_id; + index[2] = ntohl (on->router_id); + + smux_trap (ospfv3_variables, sizeof ospfv3_variables / sizeof (struct variable), + ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof (oid), + ospfv3_oid, sizeof ospfv3_oid / sizeof (oid), + index, 3, + ospf6NbrTrapList, + sizeof ospf6NbrTrapList / sizeof (struct trap_object), + NBRSTATECHANGE); +} + +void +ospf6TrapIfStateChange (struct ospf6_interface *oi) +{ + oid index[2]; + + index[0] = oi->interface->ifindex; + index[1] = oi->instance_id; + + smux_trap (ospfv3_variables, sizeof ospfv3_variables / sizeof (struct variable), + ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof (oid), + ospfv3_oid, sizeof ospfv3_oid / sizeof (oid), + index, 2, + ospf6IfTrapList, + sizeof ospf6IfTrapList / sizeof (struct trap_object), + IFSTATECHANGE); +} + /* Register OSPFv3-MIB. */ void ospf6_snmp_init (struct thread_master *master) diff --git a/ospf6d/ospf6_snmp.h b/ospf6d/ospf6_snmp.h index 5c67893c4..fa1b0c37a 100644 --- a/ospf6d/ospf6_snmp.h +++ b/ospf6d/ospf6_snmp.h @@ -22,6 +22,8 @@ #ifndef OSPF6_SNMP_H #define OSPF6_SNMP_H +extern void ospf6TrapNbrStateChange (struct ospf6_neighbor *); +extern void ospf6TrapIfStateChange (struct ospf6_interface *); extern void ospf6_snmp_init (struct thread_master *); #endif /*OSPF6_SNMP_H*/ From 0402ca4e92fa0904d5ee0926482ebca08ffd5c81 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 10 Jul 2012 09:27:57 +0200 Subject: [PATCH 0107/1342] ospf6d: fix segfault when requesting inexistant interfaces or areas --- ospf6d/ospf6_snmp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index a42e57acf..f8a3b9204 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -708,12 +708,13 @@ ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, else if (v->magic & OSPFv3WWAREATABLE) { oa = ospf6_area_lookup (area_id, ospf6); + if (!oa) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); } else if (v->magic & OSPFv3WWLINKTABLE) { oi = ospf6_interface_lookup_by_ifindex (ifindex); - if (oi->instance_id != instid) return NULL; + if (!oi || oi->instance_id != instid) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oi->lsdb); } } @@ -875,7 +876,7 @@ ospfv3IfEntry (struct variable *v, oid *name, size_t *length, if (exact) { oi = ospf6_interface_lookup_by_ifindex (ifindex); - if (oi->instance_id != instid) return NULL; + if (!oi || oi->instance_id != instid) return NULL; } else { @@ -1034,8 +1035,8 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, if (exact) { oi = ospf6_interface_lookup_by_ifindex (ifindex); + if (!oi || oi->instance_id != instid) return NULL; on = ospf6_neighbor_lookup (rtrid, oi); - if (oi->instance_id != instid) return NULL; } else { @@ -1060,7 +1061,8 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, break; } if (on) break; - oi = on = NULL; + oi = NULL; + on = NULL; } list_delete_all_node (ifslist); From 1080c13f5d3979149c1950a1c46f45e2d4bd0dc8 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 30 May 2012 08:15:48 +0200 Subject: [PATCH 0108/1342] configure: Add --with-pkg-extra-version=VER for packagers/distributions. This change adds a --with-pkg-extra-version option to ./configure to allow packagers and distributions to fine tune the version displayed to the end user to assist in support. It is also very useful when reporting bugs on the official Quagga mailing lists. There are two ways of utilsing this functionality: a) ./configure --with-pkg-extra-version=-wmo1 b) EXTRAVERSION=-wmo1 ./configure The latter is a common way for many distributions to add extra version strings to signify their own patch level to a given package. Also, minor whitespace fix in configure summary. Signed-off-by: Joachim Nilsson Signed-off-by: Joachim Nilsson Signed-off-by: David Lamparter --- configure.ac | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 277bad55b..0d6e6efff 100755 --- a/configure.ac +++ b/configure.ac @@ -189,6 +189,9 @@ AC_PROG_LIBTOOL dnl ---------------------- dnl Packages configuration dnl ---------------------- +AC_ARG_WITH(pkg-extra-version, + AS_HELP_STRING([--with-pkg-extra-version=VER], [add extra version field, for packagers/distributions]), + [EXTRAVERSION=$withval],) AC_ARG_ENABLE(vtysh, [ --enable-vtysh include integrated vty shell for Quagga]) AC_ARG_ENABLE(ipv6, @@ -382,6 +385,16 @@ esac AC_SUBST(MULTIPATH_NUM) +dnl ----------------------------------- +dnl Add extra version string to package +dnl name, string and version fields. +dnl ----------------------------------- +if test "x${EXTRAVERSION}" != "x" ; then + VERSION=${VERSION}${EXTRAVERSION} + PACKAGE_VERSION=${PACKAGE_VERSION}${EXTRAVERSION} + PACKAGE_STRING=${PACKAGE_STRING}${EXTRAVERSION} +fi + dnl ------------------------------------ dnl Check C keywords and standard types dnl ------------------------------------ @@ -1636,7 +1649,7 @@ echo " Quagga configuration -------------------- quagga version : ${PACKAGE_VERSION} -host operating system : ${host_os} +host operating system : ${host_os} source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} From 7f062c217b262e362a3362c677dea6c5e820adf1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 1 Feb 2010 16:41:26 +0100 Subject: [PATCH 0109/1342] zebra: lingering IP address after deletion (BZ#486) zebra address bookkeeping is a mess. this is just a workaround to have IPv4 address deletion somewhat working on Linux. the if_unset_prefix call is synchronous, when it returns success the address deletion completed successfully. this is either signaled by a netlink ACK or by an OK return value from ioctl(). This version is wrapped by #ifdef HAVE_NETLINK so we don't touch the BSDs for now. * zebra/interface.c: On Linux, update zebra internal state after deleting an address. Signed-off-by: David Lamparter --- zebra/interface.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 22422594c..3578b7900 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1297,13 +1297,28 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } + /* success! call returned that the address deletion went through. + * this is a synchronous operation, so we know it succeeded and can + * now update all internal state. */ + + /* the HAVE_NETLINK check is only here because, on BSD, although the + * call above is still synchronous, we get a second confirmation later + * through the route socket, and we don't want to touch that behaviour + * for now. It should work without the #ifdef, but why take the risk... + * -- equinox 2012-07-13 */ +#ifdef HAVE_NETLINK + + /* Remove connected route. */ + connected_down_ipv4 (ifp, ifc); -#if 0 /* Redistribute this information. */ zebra_interface_address_delete_update (ifp, ifc); - /* Remove connected route. */ - connected_down_ipv4 (ifp, ifc); + /* IP address propery set. */ + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + /* remove from interface, remark secondaries */ + if_subnet_delete (ifp, ifc); /* Free address information. */ listnode_delete (ifp->connected, ifc); From ee1ac2d52a6656e589ca2fb4feb3ec5fd366ecb7 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 19 Jul 2012 12:58:59 +0200 Subject: [PATCH 0110/1342] build: fix isisd topology out of tree build isisd got the include directory wrong on building with a separate build directory. * configure.ac: adjust ISIS_TOPOLOGY_INCLUDES Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0d6e6efff..7764df717 100755 --- a/configure.ac +++ b/configure.ac @@ -330,7 +330,7 @@ fi if test "${enable_isisd}" = "yes" && test "${enable_isis_topology}" = yes; then AC_DEFINE(TOPOLOGY_GENERATE,,Enable IS-IS topology generator code) - ISIS_TOPOLOGY_INCLUDES="-I./topology" + ISIS_TOPOLOGY_INCLUDES="-I\$(srcdir)/topology" ISIS_TOPOLOGY_DIR="topology" ISIS_TOPOLOGY_LIB="./topology/libtopology.a" fi From aa5cf24b9de96245f2166ef1c4e9612890ced1b3 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 19 Jul 2012 16:11:50 +0200 Subject: [PATCH 0111/1342] lib: make IPv6 prefix parser slightly more strict This makes it possible to have both "show babel route A.B.C.D/M" and "show babel route X:X::X:X/M" commands at the same time without the parser complaining about ambiguity. * lib/command.c: only accept STATE_DOT after : was seen. Reported-by: Juliusz Chroboczek Signed-off-by: David Lamparter --- lib/command.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/command.c b/lib/command.c index 4d95e924d..64563b5d0 100644 --- a/lib/command.c +++ b/lib/command.c @@ -954,7 +954,12 @@ cmd_ipv6_prefix_match (const char *str) if (*(str + 1) == ':') state = STATE_COLON; else if (*(str + 1) == '.') - state = STATE_DOT; + { + if (colons || double_colon) + state = STATE_DOT; + else + return no_match; + } else if (*(str + 1) == '/') state = STATE_SLASH; } From 7b92589c225ae46417fc3fa0714a1b6f53f19c51 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 23 Jul 2012 18:17:57 +0200 Subject: [PATCH 0112/1342] ospfd: avoid exhausting memory with OSPF vertices (BZ#476) This was found in scale testing at OSR; ospfd is adding the same link over and over again to the SPF tree. This fix prevents the resulting memory corruption from happening and adds a debug message to track occurence of this issue and/or confirm a proper fix. (This version was improved by Scott Feldman over the earlier RFC.) * ospfd/ospf_spf.c: (ospf_spf_add_parent) loop over existing vertices and refuse to add duplicates. Tested-by: Martin Winter Signed-off-by: Scott Feldman Signed-off-by: David Lamparter --- ospfd/ospf_spf.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index d7f9ba27d..974875ebc 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -422,7 +422,8 @@ ospf_spf_add_parent (struct vertex *v, struct vertex *w, struct vertex_nexthop *newhop, unsigned int distance) { - struct vertex_parent *vp; + struct vertex_parent *vp, *wp; + struct listnode *node; /* we must have a newhop, and a distance */ assert (v && w && newhop); @@ -456,7 +457,19 @@ ospf_spf_add_parent (struct vertex *v, struct vertex *w, w->distance = distance; } - /* new parent is <= existing parents, add it to parent list */ + /* new parent is <= existing parents, add it to parent list (if nexthop + * not on parent list) + */ + for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) + { + if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("%s: ... nexthop already on parent list, skipping add", __func__); + return; + } + } + vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop); listnode_add (w->parents, vp); From c81ee5c94f5b34375f3ef276fdb9bde9098e7ecb Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Sat, 7 Jul 2012 17:06:11 +0200 Subject: [PATCH 0113/1342] ospfd: Optimize and improve SPF nexthop calculation Maintain router LSA positions in OSPF interface. Find the OSPF interface in nexthop_calculation using the position in the router LSA. This is possible because the only time nexthop_calculation needs to look up interfaces is when dealing with its own Router LSA. This has the following advantages: - Multiple PtP interfaces with the same IP address between two routers. - Use Unnumbered PtP on just one end of the link. - Faster OI lookup for the OSPF interface and only done once for PtoP links. *ospf_interface.h: (struct ospf_interface) Add storage for storing router LSA position. *ospf_interface.c: (ospf_if_lookup_by_lsa_pos) lookup OSPF I/F in an area using LSA position. *ospf_lsa.c: (router_lsa_link_set) record Router LSA position. *ospf_spf.c: (ospf_spf_next) Count and pass along lsa position. (ospf_nexthop_calculation) Add lsa position argument. call ospf_if_lookup_by_lsa_pos() for OSFP interface handle. Clean up and remove all calls ospf_if_is_configured() the rest. Adjust a few debug logs. Signed-off-by: Joakim Tjernlund Signed-off-by: David Lamparter --- ospfd/ospf_interface.c | 18 +++++ ospfd/ospf_interface.h | 6 ++ ospfd/ospf_lsa.c | 2 + ospfd/ospf_spf.c | 157 +++++++++++++++++++---------------------- 4 files changed, 100 insertions(+), 83 deletions(-) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index dc0787d56..a37dde12e 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -392,6 +392,21 @@ ospf_if_exists (struct ospf_interface *oic) return NULL; } +/* Lookup OSPF interface by router LSA posistion */ +struct ospf_interface * +ospf_if_lookup_by_lsa_pos (struct ospf_area *area, int lsa_pos) +{ + struct listnode *node; + struct ospf_interface *oi; + + for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) + { + if (lsa_pos >= oi->lsa_pos_beg && lsa_pos < oi->lsa_pos_end) + return oi; + } + return NULL; +} + struct ospf_interface * ospf_if_lookup_by_local_addr (struct ospf *ospf, struct interface *ifp, struct in_addr address) @@ -801,6 +816,9 @@ ospf_if_down (struct ospf_interface *oi) return 0; OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + /* delete position in router LSA */ + oi->lsa_pos_beg = 0; + oi->lsa_pos_end = 0; /* Shutdown packet reception and sending */ ospf_if_stream_unset (oi); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 6db887738..9de655076 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -127,6 +127,10 @@ struct ospf_interface /* OSPF Area. */ struct ospf_area *area; + /* Position range in Router LSA */ + uint16_t lsa_pos_beg; /* inclusive, >= */ + uint16_t lsa_pos_end; /* exclusive, < */ + /* Interface data from zebra. */ struct interface *ifp; struct ospf_vl_data *vl_data; /* Data for Virtual Link */ @@ -244,6 +248,8 @@ extern int ospf_if_down (struct ospf_interface *); extern int ospf_if_is_up (struct ospf_interface *); extern struct ospf_interface *ospf_if_exists (struct ospf_interface *); +extern struct ospf_interface *ospf_if_lookup_by_lsa_pos (struct ospf_area *, + int); extern struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *, struct interface *, diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index d5959eb11..493209a0b 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -670,6 +670,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area *area) { if (oi->state != ISM_Down) { + oi->lsa_pos_beg = links; /* Describe each link. */ switch (oi->type) { @@ -691,6 +692,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area *area) case OSPF_IFTYPE_LOOPBACK: links += lsa_link_loopback_set (s, oi); } + oi->lsa_pos_end = links; } } } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 974875ebc..26fe4851b 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -490,13 +490,15 @@ ospf_spf_add_parent (struct vertex *v, struct vertex *w, static unsigned int ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, struct vertex *w, struct router_lsa_link *l, - unsigned int distance) + unsigned int distance, int lsa_pos) { struct listnode *node, *nnode; struct vertex_nexthop *nh; struct vertex_parent *vp; struct ospf_interface *oi = NULL; unsigned int added = 0; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; if (IS_DEBUG_OSPF_EVENT) { @@ -515,30 +517,38 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, the OSPF interface connecting to the destination network/router. */ + /* we *must* be supplied with the link data */ + assert (l != NULL); + oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos); + if (!oi) + { + zlog_debug("%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s", + __func__, lsa_pos, + inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), + inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); + return 0; + } + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_debug("%s: considering link:%s " + "type:%d link_id:%s link_data:%s", + __func__, oi->ifp->name, l->m[0].type, + inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), + inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); + } + if (w->type == OSPF_VERTEX_ROUTER) { /* l is a link from v to w * l2 will be link from w to v */ struct router_lsa_link *l2 = NULL; - - /* we *must* be supplied with the link data */ - assert (l != NULL); - - if (IS_DEBUG_OSPF_EVENT) - { - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; - - zlog_debug("ospf_nexthop_calculation(): considering link " - "type %d link_id %s link_data %s", - l->m[0].type, - inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), - inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); - } if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) { + struct in_addr nexthop; + /* If the destination is a router which connects to the calculating router via a Point-to-MultiPoint network, the destination's next hop IP address(es) @@ -549,68 +559,53 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, provides an IP address of the next hop router. At this point l is a link from V to W, and V is the - root ("us"). Find the local interface associated - with l (its address is in l->link_data). If it - is a point-to-multipoint interface, then look through - the links in the opposite direction (W to V). If - any of them have an address that lands within the + root ("us"). If it is a point-to-multipoint interface, + then look through the links in the opposite direction (W to V). + If any of them have an address that lands within the subnet declared by the PtMP link, then that link - is a constituent of the PtMP link, and its address is + is a constituent of the PtMP link, and its address is a nexthop address for V. */ - oi = ospf_if_is_configured (area->ospf, &l->link_data); - if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - { - struct prefix_ipv4 la; - - la.family = AF_INET; - la.prefixlen = oi->address->prefixlen; - - /* V links to W on PtMP interface - - find the interface address on W */ - while ((l2 = ospf_get_next_link (w, v, l2))) - { - la.prefix = l2->link_data; - - if (prefix_cmp ((struct prefix *) &la, - oi->address) == 0) - /* link_data is on our PtMP network */ - break; - } - } /* end l is on point-to-multipoint link */ - else - { - /* l is a regular point-to-point link. - Look for a link from W to V. - */ - while ((l2 = ospf_get_next_link (w, v, l2))) - { - oi = ospf_if_is_configured (area->ospf, - &(l2->link_data)); - - if (oi == NULL) - continue; - - if (!IPV4_ADDR_SAME (&oi->address->u.prefix4, - &l->link_data)) - continue; - - break; - } - } - - if (oi && l2) + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + { + added = 1; + nexthop.s_addr = 0; /* Nexthop not required */ + } + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + { + struct prefix_ipv4 la; + + la.family = AF_INET; + la.prefixlen = oi->address->prefixlen; + + /* V links to W on PtMP interface + - find the interface address on W */ + while ((l2 = ospf_get_next_link (w, v, l2))) + { + la.prefix = l2->link_data; + + if (prefix_cmp ((struct prefix *) &la, + oi->address) != 0) + continue; + /* link_data is on our PtMP network */ + added = 1; + nexthop = l2->link_data; + break; + } + } + + if (added) { /* found all necessary info to build nexthop */ nh = vertex_nexthop_new (); nh->oi = oi; - nh->router = l2->link_data; + nh->router = nexthop; ospf_spf_add_parent (v, w, nh, distance); return 1; } else - zlog_info("ospf_nexthop_calculation(): " - "could not determine nexthop for link"); + zlog_info("%s: could not determine nexthop for link %s", + __func__, oi->ifp->name); } /* end point-to-point link from V to W */ else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) { @@ -643,19 +638,13 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, else { assert(w->type == OSPF_VERTEX_NETWORK); - oi = ospf_if_is_configured (area->ospf, &(l->link_data)); - if (oi) - { - nh = vertex_nexthop_new (); - nh->oi = oi; - nh->router.s_addr = 0; - ospf_spf_add_parent (v, w, nh, distance); - return 1; - } + + nh = vertex_nexthop_new (); + nh->oi = oi; + nh->router.s_addr = 0; /* Nexthop not required */ + ospf_spf_add_parent (v, w, nh, distance); + return 1; } - zlog_info("ospf_nexthop_calculation(): " - "Unknown attached link"); - return 0; } /* end V is the root */ /* Check if W's parent is a network connected to root. */ else if (v->type == OSPF_VERTEX_NETWORK) @@ -736,7 +725,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area, u_char *lim; struct router_lsa_link *l = NULL; struct in_addr *r; - int type = 0; + int type = 0, lsa_pos=-1, lsa_pos_next=0; /* If this is a router-LSA, and bit V of the router-LSA (see Section A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ @@ -765,6 +754,8 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area, { l = (struct router_lsa_link *) p; + lsa_pos = lsa_pos_next; /* LSA link position */ + lsa_pos_next++; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); @@ -886,7 +877,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area, w = ospf_vertex_new (w_lsa); /* Calculate nexthop to W. */ - if (ospf_nexthop_calculation (area, v, w, l, distance)) + if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) pqueue_enqueue (w, candidate); else if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Nexthop Calc failed"); @@ -906,7 +897,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area, { /* Found an equal-cost path to W. * Calculate nexthop of to W from V. */ - ospf_nexthop_calculation (area, v, w, l, distance); + ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos); } /* less than. */ else @@ -916,7 +907,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area, * valid nexthop it will call spf_add_parents, which * will flush the old parents */ - if (ospf_nexthop_calculation (area, v, w, l, distance)) + if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) /* Decrease the key of the node in the heap. * trickle-sort it up towards root, just in case this * node should now be the new root due the cost change. From 57c639f01ec6be70ac858f412d32b638a9756bed Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Sat, 7 Jul 2012 17:06:12 +0200 Subject: [PATCH 0114/1342] ospf_spf_process_stubs: use LSA pos to find OSFP interface This is better than a prefix lookup as prefixes may not be unique, that is, the same prefix can exist on several interfaces. Signed-off-by: Joakim Tjernlund Signed-off-by: David Lamparter --- ospfd/ospf_route.c | 4 ++-- ospfd/ospf_route.h | 2 +- ospfd/ospf_spf.c | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index d2e5e1e7d..a5d6d18c9 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -429,7 +429,7 @@ ospf_intra_add_transit (struct route_table *rt, struct vertex *v, void ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, struct vertex *v, struct ospf_area *area, - int parent_is_root) + int parent_is_root, int lsa_pos) { u_int32_t cost; struct route_node *rn; @@ -577,7 +577,7 @@ ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): this network is on this router"); - if ((oi = ospf_if_lookup_by_prefix (area->ospf, &p))) + if ((oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos))) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): the interface is %s", diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 17ab68e5d..5742b462c 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -141,7 +141,7 @@ extern void ospf_intra_add_transit (struct route_table *, struct vertex *, extern void ospf_intra_add_stub (struct route_table *, struct router_lsa_link *, struct vertex *, struct ospf_area *, - int parent_is_root); + int parent_is_root, int); extern int ospf_route_cmp (struct ospf *, struct ospf_route *, struct ospf_route *); diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 26fe4851b..668295119 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -973,6 +973,7 @@ ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v, u_char *lim; struct router_lsa_link *l; struct router_lsa *rlsa; + int lsa_pos = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_process_stubs():processing router LSA, id: %s", @@ -994,7 +995,8 @@ ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v, (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type == LSA_LINK_TYPE_STUB) - ospf_intra_add_stub (rt, l, v, area, parent_is_root); + ospf_intra_add_stub (rt, l, v, area, parent_is_root, lsa_pos); + lsa_pos++; } } From c963c20346c0e3cd75735b88beded98389607cd5 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Sat, 7 Jul 2012 17:06:13 +0200 Subject: [PATCH 0115/1342] zebra: Add support for ZEBRA_NEXTHOP_IPV4_IFINDEX Actually implement the IPV4_IFINDEX nexthop type that has been drifting around as a definition forever (without any warning about it being a placeholder). Signed-off-by: Joakim Tjernlund Signed-off-by: David Lamparter --- zebra/zserv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zebra/zserv.c b/zebra/zserv.c index 09152170c..9e47f23fe 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -775,6 +775,11 @@ zread_ipv4_add (struct zserv *client, u_short length) nexthop.s_addr = stream_get_ipv4 (s); nexthop_ipv4_add (rib, &nexthop, NULL); break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + nexthop.s_addr = stream_get_ipv4 (s); + ifindex = stream_getl (s); + nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; @@ -852,6 +857,10 @@ zread_ipv4_delete (struct zserv *client, u_short length) nexthop.s_addr = stream_get_ipv4 (s); nexthop_p = &nexthop; break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + nexthop.s_addr = stream_get_ipv4 (s); + ifindex = stream_getl (s); + break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; From ba281d3d04053b7c59ecdfdbea91a62c09e9f8a4 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Sat, 7 Jul 2012 17:06:13 +0200 Subject: [PATCH 0116/1342] ospfd: use ZEBRA_NEXTHOP_IPV4_IFINDEX OSPF really needs to specify interface in its routes. Otherwise ospf may change the wrong route. Signed-off-by: Joakim Tjernlund [fixed up some whitespace errors, split patch in two] Signed-off-by: David Lamparter --- ospfd/ospf_zebra.c | 124 +++++++++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 45 deletions(-) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index f8d1cb7c6..f5f49f644 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -371,7 +371,14 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) { - if (path->nexthop.s_addr != INADDR_ANY) + if (path->nexthop.s_addr != INADDR_ANY && + path->ifindex != 0) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); + stream_put_in_addr (s, &path->nexthop); + stream_putl (s, path->ifindex); + } + else if (path->nexthop.s_addr != INADDR_ANY) { stream_putc (s, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (s, &path->nexthop); @@ -418,60 +425,87 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) void ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) { - struct zapi_ipv4 api; + u_char message; + u_char distance; + u_char flags; + int psize; + struct stream *s; struct ospf_path *path; - struct in_addr *nexthop; - struct listnode *node, *nnode; + struct listnode *node; if (zclient->redist[ZEBRA_ROUTE_OSPF]) { - api.type = ZEBRA_ROUTE_OSPF; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - api.ifindex_num = 0; - api.nexthop_num = 0; + message = 0; + flags = 0; + /* Distance value. */ + distance = ospf_distance_apply (p, or); + /* Make packet. */ + s = zclient->obuf; + stream_reset (s); - for (ALL_LIST_ELEMENTS (or->paths, node, nnode, path)) - { - if (path->nexthop.s_addr != INADDR_ANY) - { - SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - nexthop = &path->nexthop; - api.nexthop = &nexthop; - } - else if (if_lookup_by_index(path->ifindex)) - { - SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.ifindex_num = 1; - api.ifindex = &path->ifindex; - } - else if ( IS_DEBUG_OSPF(zebra,ZEBRA_REDISTRIBUTE) ) - { - zlog_debug("Zebra: no ifp %s %d", - inet_ntoa(p->prefix), - p->prefixlen); - } + /* Put command, type, flags, message. */ + zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE); + stream_putc (s, ZEBRA_ROUTE_OSPF); + stream_putc (s, flags); + stream_putc (s, message); + stream_putw (s, SAFI_UNICAST); - zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *) & p->prefix, psize); - if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE) && api.nexthop_num) - { + /* Nexthop count. */ + stream_putc (s, or->paths->count); + + /* Nexthop, ifindex, distance and metric information. */ + for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) + { + if (path->nexthop.s_addr != INADDR_ANY && + path->ifindex != 0) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); + stream_put_in_addr (s, &path->nexthop); + stream_putl (s, path->ifindex); + } + else if (path->nexthop.s_addr != INADDR_ANY) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, &path->nexthop); + } + else + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, path->ifindex); + } + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + { char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra: Route delete %s/%d nexthop %s", - inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), + zlog_debug("Zebra: Route add %s/%d nexthop %s", + inet_ntop(AF_INET, &p->prefix, + buf[0], sizeof(buf[0])), p->prefixlen, - inet_ntop(AF_INET, *api.nexthop, + inet_ntop(AF_INET, &path->nexthop, buf[1], sizeof(buf[1]))); - } - if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE) && api.ifindex_num) - { - zlog_debug ("Zebra: Route delete %s/%d ifindex %d", - inet_ntoa (p->prefix), - p->prefixlen, *api.ifindex); - } - } + } + } + + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, distance); + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + { + if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) + stream_putl (s, or->cost + or->u.ext.type2_cost); + else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) + stream_putl (s, or->u.ext.type2_cost); + else + stream_putl (s, or->cost); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + zclient_send_message(zclient); } } From 9289c6ff55cd96c943d23e43fc9e5f987aa965ed Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Sat, 7 Jul 2012 17:06:14 +0200 Subject: [PATCH 0117/1342] ospfd: Do not fall back to intervening router. The patch in bug 330 did two things. It add a return value whether ospf_nexthop_calculation() failed or not and also moved the return stmt for 16.1.1 para 5 so now SPF will fallback to the intervening router when no back links are found by 16.1.1 para 5. This is wrong and can potentially create black holes or routing loops according to Dave Katz and Acee Lindem at ospf@ietf.org Even if the current code could be proved to be harmless in all cases, it adds substantial extra processing and memory allocations. Signed-off-by: Joakim Tjernlund Signed-off-by: David Lamparter --- ospfd/ospf_spf.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 668295119..abc8a91a8 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -675,23 +675,11 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, added = 1; ospf_spf_add_parent (v, w, nh, distance); } + /* Always return here as we known that 16.1.1 para 4 + does not apply one you have found a connection to root */ + return added; } } - /* NB: This code is non-trivial. - * - * E.g. it is not enough to know that V connects to the root. It is - * also important that the while above, looping through all links from - * W->V found at least one link, so that we know there is - * bi-directional connectivity between V and W. Otherwise, if we - * /always/ return here, but don't check that W->V exists then we - * we will prevent SPF from finding/using higher cost paths.. - * - * See also bug #330, and also: - * - * http://blogs.sun.com/paulj/entry/the_difference_a_line_makes - */ - if (added) - return added; } /* 16.1.1 para 4. If there is at least one intervening router in the From 4bed21c402fa1079301d47811a4579985997c881 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 9 Aug 2012 00:40:09 +0000 Subject: [PATCH 0118/1342] build: correct libtool parameter used within Makefiles This corrects the parameters passed to libtool when linking the shared libraries. The paramter name is -version-info not -version. Signed-off-by: David Lamparter --- ospfclient/Makefile.am | 2 +- ospfd/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index 607bbed6f..0f37aa988 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -3,7 +3,7 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib lib_LTLIBRARIES = libospfapiclient.la -libospfapiclient_la_LDFLAGS = -version 0:0:0 +libospfapiclient_la_LDFLAGS = -version-info 0:0:0 sbin_PROGRAMS = ospfclient diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index f968d7d61..4e1a4fe9f 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -5,7 +5,7 @@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la -libospf_la_LDFLAGS = -version 0:0:0 +libospf_la_LDFLAGS = -version-info 0:0:0 sbin_PROGRAMS = ospfd From 1b54f798d3cc359bec036db83c1c9bfab75d1244 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 9 Aug 2012 00:44:28 +0000 Subject: [PATCH 0119/1342] build: fix autoconf multicast check on OpenBSD Fix the "BSD struct ip_mreq hack" autoconf test to work with OpenBSD. Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7764df717..4cc940061 100755 --- a/configure.ac +++ b/configure.ac @@ -957,7 +957,7 @@ AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES) AC_MSG_CHECKING([for BSD struct ip_mreq hack]) AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H #include -#endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) +#endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) return (0); #else #error No support for BSD struct ip_mreq hack detected From bb2315f2878da685fae094aece13409667d21f97 Mon Sep 17 00:00:00 2001 From: Nick Hilliard Date: Sat, 18 Aug 2012 15:10:57 +0000 Subject: [PATCH 0120/1342] ripd: clear sockaddr_in before using ripd_create_socket() failed in bind() on Mac OS X 10.7 since there was garbage in unused fields of struct sockaddr_in. * ripd/ripd.c: zero out struct sockaddr_sin from before filling. Signed-off-by: David Lamparter --- ripd/ripd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ripd/ripd.c b/ripd/ripd.c index 5a6dbc8c9..db29d54a2 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1475,6 +1475,7 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); /* multicast send should bind to local interface address */ + memset (&from, 0, sizeof (from)); from.sin_family = AF_INET; from.sin_port = htons (RIP_PORT_DEFAULT); from.sin_addr = ifc->address->u.prefix4; From ed6e297972318a0070ad4d973401fbc6e0def558 Mon Sep 17 00:00:00 2001 From: Serj Kalichev Date: Fri, 7 Sep 2012 13:29:42 +0400 Subject: [PATCH 0121/1342] build: fix extract.pl for cross compilation extract.pl should invoke the C preprocessor for the target system, not the host. * vtysh/extract.pl.in: use @CPP@ to get target cpp Signed-off-by: David Lamparter --- vtysh/extract.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 2dbaf0a10..37763043a 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -63,7 +63,7 @@ $ignore{'"show history"'} = "ignore"; foreach (@ARGV) { $file = $_; - open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/isisd/topology @CPPFLAGS@ $file |"); + open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/isisd/topology @CPPFLAGS@ $file |"); local $/; undef $/; $line = ; close (FH); From 3eb8ef37bc463f88bfa36bd26fd43f7f6ad36c20 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Fri, 17 Aug 2012 08:19:47 -0700 Subject: [PATCH 0122/1342] lib: bring some changes over from bgp_table to table * lib/table.c - Maintain table node count. Expose it via the route_table_count() function (from revision cbdfbaa5). - route_unlock_node(): Add assertion (from revision 228da428). - route_table_free(): Make static and fix up cleanup code (from revision 228da428). - route_node_delete(): Change to be static. - Add 'const' qualifier in a couple places. Signed-off-by: David Lamparter --- lib/table.c | 35 ++++++++++++++++++++++++++--------- lib/table.h | 8 +++++--- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/lib/table.c b/lib/table.c index fcb7ecc0b..7efb8c4fe 100644 --- a/lib/table.c +++ b/lib/table.c @@ -27,8 +27,8 @@ #include "memory.h" #include "sockunion.h" -void route_node_delete (struct route_node *); -void route_table_free (struct route_table *); +static void route_node_delete (struct route_node *); +static void route_table_free (struct route_table *); struct route_table * route_table_init (void) @@ -76,7 +76,7 @@ route_node_free (struct route_node *node) } /* Free route table. */ -void +static void route_table_free (struct route_table *rt) { struct route_node *tmp_node; @@ -87,6 +87,9 @@ route_table_free (struct route_table *rt) node = rt->top; + /* Bulk deletion of nodes remaining in this table. This function is not + called until workers have completed their dependency on this table. + A final route_unlock_node() will not be called for these nodes. */ while (node) { if (node->l_left) @@ -104,22 +107,25 @@ route_table_free (struct route_table *rt) tmp_node = node; node = node->parent; + tmp_node->table->count--; + tmp_node->lock = 0; /* to cause assert if unlocked after this */ + route_node_free (tmp_node); + if (node != NULL) { if (node->l_left == tmp_node) node->l_left = NULL; else node->l_right = NULL; - - route_node_free (tmp_node); } else { - route_node_free (tmp_node); break; } } + assert (rt->count == 0); + XFREE (MTYPE_ROUTE_TABLE, rt); return; } @@ -186,6 +192,7 @@ route_lock_node (struct route_node *node) void route_unlock_node (struct route_node *node) { + assert (node->lock > 0); node->lock--; if (node->lock == 0) @@ -255,7 +262,7 @@ route_node_match_ipv6 (const struct route_table *table, /* Lookup same prefix node. Return NULL when we can't find route. */ struct route_node * -route_node_lookup (struct route_table *table, struct prefix *p) +route_node_lookup (const struct route_table *table, struct prefix *p) { struct route_node *node; u_char prefixlen = p->prefixlen; @@ -277,7 +284,7 @@ route_node_lookup (struct route_table *table, struct prefix *p) /* Add node to routing table. */ struct route_node * -route_node_get (struct route_table *table, struct prefix *p) +route_node_get (struct route_table *const table, struct prefix *p) { struct route_node *new; struct route_node *node; @@ -323,15 +330,17 @@ route_node_get (struct route_table *table, struct prefix *p) match = new; new = route_node_set (table, p); set_link (match, new); + table->count++; } } + table->count++; route_lock_node (new); return new; } /* Delete node from the routing table. */ -void +static void route_node_delete (struct route_node *node) { struct route_node *child; @@ -363,6 +372,8 @@ route_node_delete (struct route_node *node) else node->table->top = child; + node->table->count--; + route_node_free (node); /* If parent node is stub then delete it also. */ @@ -465,3 +476,9 @@ route_next_until (struct route_node *node, struct route_node *limit) route_unlock_node (start); return NULL; } + +unsigned long +route_table_count (const struct route_table *table) +{ + return table->count; +} diff --git a/lib/table.h b/lib/table.h index 41d1fa708..1e8df46d5 100644 --- a/lib/table.h +++ b/lib/table.h @@ -27,6 +27,8 @@ struct route_table { struct route_node *top; + + unsigned long count; }; /* Each routing entry. */ @@ -56,14 +58,13 @@ struct route_node extern struct route_table *route_table_init (void); extern void route_table_finish (struct route_table *); extern void route_unlock_node (struct route_node *node); -extern void route_node_delete (struct route_node *node); extern struct route_node *route_top (struct route_table *); extern struct route_node *route_next (struct route_node *); extern struct route_node *route_next_until (struct route_node *, struct route_node *); -extern struct route_node *route_node_get (struct route_table *, +extern struct route_node *route_node_get (struct route_table *const, struct prefix *); -extern struct route_node *route_node_lookup (struct route_table *, +extern struct route_node *route_node_lookup (const struct route_table *, struct prefix *); extern struct route_node *route_lock_node (struct route_node *node); extern struct route_node *route_node_match (const struct route_table *, @@ -75,4 +76,5 @@ extern struct route_node *route_node_match_ipv6 (const struct route_table *, const struct in6_addr *); #endif /* HAVE_IPV6 */ +extern unsigned long route_table_count (const struct route_table *); #endif /* _ZEBRA_TABLE_H */ From f9c1b7bb9b98342f1f3b0bfe3af01844f364dce9 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Fri, 17 Aug 2012 08:19:48 -0700 Subject: [PATCH 0123/1342] lib: prepare table code for reuse by bgp_table * lib/table.[ch] - Add a macro (ROUTE_NODE_FIELDS) that expands to all the fields of a route_node structure. - Add the route_table_delegate_t structure, a function vector which allows clients to customize the behavior of one or more tables. The delegate currently contains the 'create_node' and 'destroy_node' functions, and hence enables a table to use an alternative node structure. The alternative node is expected to embed the fields of a route_node using ROUTE_NODE_FIELDS. - Add route_table_init_with_delegate() to create a new table with a given delegate. - Make route_table_init() a thin wrapper around route_table_init_with_delegate(). The delegate it passes in simply creates/destroys route_node structures as before. - Add a user data pointer (info) to the route_table structure. This can be used by a client to keep per-table state. Signed-off-by: David Lamparter --- lib/table.c | 68 ++++++++++++++++++++++++++++++++++++++-------- lib/table.h | 78 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 120 insertions(+), 26 deletions(-) diff --git a/lib/table.c b/lib/table.c index 7efb8c4fe..6bbc9c621 100644 --- a/lib/table.c +++ b/lib/table.c @@ -30,12 +30,17 @@ static void route_node_delete (struct route_node *); static void route_table_free (struct route_table *); + +/* + * route_table_init_with_delegate + */ struct route_table * -route_table_init (void) +route_table_init_with_delegate (route_table_delegate_t *delegate) { struct route_table *rt; rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table)); + rt->delegate = delegate; return rt; } @@ -47,11 +52,9 @@ route_table_finish (struct route_table *rt) /* Allocate new route node. */ static struct route_node * -route_node_new (void) +route_node_new (struct route_table *table) { - struct route_node *node; - node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node)); - return node; + return table->delegate->create_node (table->delegate, table); } /* Allocate new route node with prefix set. */ @@ -60,7 +63,7 @@ route_node_set (struct route_table *table, struct prefix *prefix) { struct route_node *node; - node = route_node_new (); + node = route_node_new (table); prefix_copy (&node->p, prefix); node->table = table; @@ -70,9 +73,9 @@ route_node_set (struct route_table *table, struct prefix *prefix) /* Free route node. */ static void -route_node_free (struct route_node *node) +route_node_free (struct route_table *table, struct route_node *node) { - XFREE (MTYPE_ROUTE_NODE, node); + table->delegate->destroy_node (table->delegate, table, node); } /* Free route table. */ @@ -109,7 +112,7 @@ route_table_free (struct route_table *rt) tmp_node->table->count--; tmp_node->lock = 0; /* to cause assert if unlocked after this */ - route_node_free (tmp_node); + route_node_free (rt, tmp_node); if (node != NULL) { @@ -314,7 +317,7 @@ route_node_get (struct route_table *const table, struct prefix *p) } else { - new = route_node_new (); + new = route_node_new (table); route_common (&node->p, p, &new->p); new->p.family = p->family; new->table = table; @@ -374,7 +377,7 @@ route_node_delete (struct route_node *node) node->table->count--; - route_node_free (node); + route_node_free (node->table, node); /* If parent node is stub then delete it also. */ if (parent && parent->lock == 0) @@ -482,3 +485,46 @@ route_table_count (const struct route_table *table) { return table->count; } + +/** + * route_node_create + * + * Default function for creating a route node. + */ +static struct route_node * +route_node_create (route_table_delegate_t *delegate, + struct route_table *table) +{ + struct route_node *node; + node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node)); + return node; +} + +/** + * route_node_destroy + * + * Default function for destroying a route node. + */ +static void +route_node_destroy (route_table_delegate_t *delegate, + struct route_table *table, struct route_node *node) +{ + XFREE (MTYPE_ROUTE_NODE, node); +} + +/* + * Default delegate. + */ +static route_table_delegate_t default_delegate = { + .create_node = route_node_create, + .destroy_node = route_node_destroy +}; + +/* + * route_table_init + */ +struct route_table * +route_table_init (void) +{ + return route_table_init_with_delegate (&default_delegate); +} diff --git a/lib/table.h b/lib/table.h index 1e8df46d5..4d3eddb1d 100644 --- a/lib/table.h +++ b/lib/table.h @@ -23,39 +23,87 @@ #ifndef _ZEBRA_TABLE_H #define _ZEBRA_TABLE_H +/* + * Forward declarations. + */ +struct route_node; +struct route_table; + +/* + * route_table_delegate_t + * + * Function vector that can be used by a client to customize the + * behavior of one or more route tables. + */ +typedef struct route_table_delegate_t_ route_table_delegate_t; + +typedef struct route_node * (*route_table_create_node_func_t) + (route_table_delegate_t *, struct route_table *); + +typedef void (*route_table_destroy_node_func_t) + (route_table_delegate_t *, struct route_table *, struct route_node *); + +struct route_table_delegate_t_ +{ + route_table_create_node_func_t create_node; + route_table_destroy_node_func_t destroy_node; +}; + /* Routing table top structure. */ struct route_table { struct route_node *top; + /* + * Delegate that performs certain functions for this table. + */ + route_table_delegate_t *delegate; + unsigned long count; + + /* + * User data. + */ + void *info; }; +/* + * Macro that defines all fields in a route node. + */ +#define ROUTE_NODE_FIELDS \ + /* Actual prefix of this radix. */ \ + struct prefix p; \ + \ + /* Tree link. */ \ + struct route_table *table; \ + struct route_node *parent; \ + struct route_node *link[2]; \ + \ + /* Lock of this radix */ \ + unsigned int lock; \ + \ + /* Each node of route. */ \ + void *info; \ + \ + /* Aggregation. */ \ + void *aggregate; + + /* Each routing entry. */ struct route_node { - /* Actual prefix of this radix. */ - struct prefix p; + ROUTE_NODE_FIELDS; - /* Tree link. */ - struct route_table *table; - struct route_node *parent; - struct route_node *link[2]; #define l_left link[0] #define l_right link[1] - - /* Lock of this radix */ - unsigned int lock; - - /* Each node of route. */ - void *info; - - /* Aggregation. */ - void *aggregate; }; /* Prototypes. */ extern struct route_table *route_table_init (void); + +extern struct route_table * +route_table_init_with_delegate (route_table_delegate_t *); + extern void route_table_finish (struct route_table *); extern void route_unlock_node (struct route_node *node); extern struct route_node *route_top (struct route_table *); From 67174041d2d9d8908f8b2c915bc0d186d8442c68 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Fri, 17 Aug 2012 08:19:49 -0700 Subject: [PATCH 0124/1342] bgpd: make bgp_table a wrapper around table library Make the BGP table code a thin wrapper around the table implementation in libzebra. * bgpd/bgp_table.[ch] - Use the ROUTE_NODE_FIELDS macro to embed the fields of a route_node in the bgp_node structure. - Add a route_table field to the bgp_table structure. Initialize the route_table with a delegate, such that the nodes in the table are bgp_node structures. - Add inline wrappers that call route_table functions underneath, and accept/return the correct BGP types. * bgpd/bgp_route.c Change some code to use inline wrappers instead of accessing fields of nodes/tables directly. The latter does not always work because the types of some fields need to be translated now. Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 44 +++-- bgpd/bgp_table.c | 481 +++++------------------------------------------ bgpd/bgp_table.h | 240 ++++++++++++++++++++--- 3 files changed, 285 insertions(+), 480 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0337224ad..2412503d3 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -240,11 +240,15 @@ bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri) static void bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) { - assert (rn && rn->table); + struct bgp_table *table; + + assert (rn && bgp_node_table (rn)); assert (ri && ri->peer && ri->peer->bgp); + table = bgp_node_table (rn); + /* Ignore 'pcount' for RS-client tables */ - if (rn->table->type != BGP_TABLE_MAIN + if (table->type != BGP_TABLE_MAIN || ri->peer == ri->peer->bgp->peer_self) return; @@ -255,8 +259,8 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) UNSET_FLAG (ri->flags, BGP_INFO_COUNTED); /* slight hack, but more robust against errors. */ - if (ri->peer->pcount[rn->table->afi][rn->table->safi]) - ri->peer->pcount[rn->table->afi][rn->table->safi]--; + if (ri->peer->pcount[table->afi][table->safi]) + ri->peer->pcount[table->afi][table->safi]--; else { zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s", @@ -269,7 +273,7 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) && !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { SET_FLAG (ri->flags, BGP_INFO_COUNTED); - ri->peer->pcount[rn->table->afi][rn->table->safi]++; + ri->peer->pcount[table->afi][table->safi]++; } } @@ -1448,7 +1452,7 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, /* It's initialized in bgp_announce_[check|check_rsclient]() */ attr.extra = &extra; - switch (rn->table->type) + switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: /* Announcement to peer->conf. If the route is filtered, @@ -1492,7 +1496,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data) struct bgp_info *old_select; struct bgp_info_pair old_and_new; struct listnode *node, *nnode; - struct peer *rsclient = rn->table->owner; + struct peer *rsclient = bgp_node_table (rn)->owner; /* Best path selection. */ bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); @@ -1623,7 +1627,7 @@ static void bgp_processq_del (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; - struct bgp_table *table = pq->rn->table; + struct bgp_table *table = bgp_node_table (pq->rn); bgp_unlock (pq->bgp); bgp_unlock_node (pq->rn); @@ -1674,14 +1678,14 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) return; /* all unlocked in bgp_processq_del */ - bgp_table_lock (rn->table); + bgp_table_lock (bgp_node_table (rn)); pqnode->rn = bgp_lock_node (rn); pqnode->bgp = bgp; bgp_lock (bgp); pqnode->afi = afi; pqnode->safi = safi; - switch (rn->table->type) + switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: work_queue_add (bm->process_main_queue, pqnode); @@ -2719,8 +2723,8 @@ bgp_clear_route_node (struct work_queue *wq, void *data) struct bgp_node *rn = cnq->rn; struct peer *peer = wq->spec.data; struct bgp_info *ri; - afi_t afi = rn->table->afi; - safi_t safi = rn->table->safi; + afi_t afi = bgp_node_table (rn)->afi; + safi_t safi = bgp_node_table (rn)->safi; assert (rn && peer); @@ -2745,7 +2749,7 @@ bgp_clear_node_queue_del (struct work_queue *wq, void *data) { struct bgp_clear_node_queue *cnq = data; struct bgp_node *rn = cnq->rn; - struct bgp_table *table = rn->table; + struct bgp_table *table = bgp_node_table (rn); bgp_unlock_node (rn); bgp_table_unlock (table); @@ -2847,7 +2851,7 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_clear_node_queue *cnq; /* both unlocked in bgp_clear_node_queue_del */ - bgp_table_lock (rn->table); + bgp_table_lock (bgp_node_table (rn)); bgp_lock_node (rn); cnq = XCALLOC (MTYPE_BGP_CLEAR_NODE_QUEUE, sizeof (struct bgp_clear_node_queue)); @@ -4669,7 +4673,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, table = bgp->aggregate[afi][safi]; /* No aggregates configured. */ - if (table->top == NULL) + if (bgp_table_top_nolock (table) == NULL) return; if (p->prefixlen == 0) @@ -4681,7 +4685,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, child = bgp_node_get (table, p); /* Aggregate address configuration check. */ - for (rn = child; rn; rn = rn->parent) + for (rn = child; rn; rn = bgp_node_parent_nolock (rn)) if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) { bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); @@ -4706,7 +4710,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, table = bgp->aggregate[afi][safi]; /* No aggregates configured. */ - if (table->top == NULL) + if (bgp_table_top_nolock (table) == NULL) return; if (p->prefixlen == 0) @@ -4715,7 +4719,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, child = bgp_node_get (table, p); /* Aggregate address configuration check. */ - for (rn = child; rn; rn = rn->parent) + for (rn = child; rn; rn = bgp_node_parent_nolock (rn)) if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) { bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); @@ -9299,7 +9303,7 @@ bgp_table_stats_walker (struct thread *t) for (rn = top; rn; rn = bgp_route_next (rn)) { struct bgp_info *ri; - struct bgp_node *prn = rn->parent; + struct bgp_node *prn = bgp_node_parent_nolock (rn); unsigned int rinum = 0; if (rn == top) @@ -9320,7 +9324,7 @@ bgp_table_stats_walker (struct thread *t) /* check if the prefix is included by any other announcements */ while (prn && !prn->info) - prn = prn->parent; + prn = bgp_node_parent_nolock (prn); if (prn == NULL || prn == top) { diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 3385a9342..7a6c675dc 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -28,24 +28,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" -static void bgp_node_delete (struct bgp_node *); -static void bgp_table_free (struct bgp_table *); - -struct bgp_table * -bgp_table_init (afi_t afi, safi_t safi) -{ - struct bgp_table *rt; - - rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); - - bgp_table_lock(rt); - rt->type = BGP_TABLE_MAIN; - rt->afi = afi; - rt->safi = safi; - - return rt; -} - void bgp_table_lock (struct bgp_table *rt) { @@ -58,97 +40,13 @@ bgp_table_unlock (struct bgp_table *rt) assert (rt->lock > 0); rt->lock--; - if (rt->lock == 0) - bgp_table_free (rt); -} - -void -bgp_table_finish (struct bgp_table **rt) -{ - if (*rt != NULL) + if (rt->lock != 0) { - bgp_table_unlock(*rt); - *rt = NULL; + return; } -} - -static struct bgp_node * -bgp_node_create (void) -{ - return XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); -} - -/* Allocate new route node with prefix set. */ -static struct bgp_node * -bgp_node_set (struct bgp_table *table, struct prefix *prefix) -{ - struct bgp_node *node; - - node = bgp_node_create (); - - prefix_copy (&node->p, prefix); - node->table = table; - - return node; -} - -/* Free route node. */ -static void -bgp_node_free (struct bgp_node *node) -{ - XFREE (MTYPE_BGP_NODE, node); -} - -/* Free route table. */ -static void -bgp_table_free (struct bgp_table *rt) -{ - struct bgp_node *tmp_node; - struct bgp_node *node; - - if (rt == NULL) - return; - - node = rt->top; - - /* Bulk deletion of nodes remaining in this table. This function is not - called until workers have completed their dependency on this table. - A final bgp_unlock_node() will not be called for these nodes. */ - while (node) - { - if (node->l_left) - { - node = node->l_left; - continue; - } - - if (node->l_right) - { - node = node->l_right; - continue; - } - tmp_node = node; - node = node->parent; - - tmp_node->table->count--; - tmp_node->lock = 0; /* to cause assert if unlocked after this */ - bgp_node_free (tmp_node); - - if (node != NULL) - { - if (node->l_left == tmp_node) - node->l_left = NULL; - else - node->l_right = NULL; - } - else - { - break; - } - } - - assert (rt->count == 0); + route_table_finish (rt->route_table); + rt->route_table = NULL; if (rt->owner) { @@ -157,354 +55,71 @@ bgp_table_free (struct bgp_table *rt) } XFREE (MTYPE_BGP_TABLE, rt); - return; -} - -/* Utility mask array. */ -static u_char maskbit[] = -{ - 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff -}; - -/* Common prefix route genaration. */ -static void -route_common (struct prefix *n, struct prefix *p, struct prefix *new) -{ - int i; - u_char diff; - u_char mask; - - u_char *np = (u_char *)&n->u.prefix; - u_char *pp = (u_char *)&p->u.prefix; - u_char *newp = (u_char *)&new->u.prefix; - - for (i = 0; i < p->prefixlen / 8; i++) - { - if (np[i] == pp[i]) - newp[i] = np[i]; - else - break; - } - - new->prefixlen = i * 8; - - if (new->prefixlen != p->prefixlen) - { - diff = np[i] ^ pp[i]; - mask = 0x80; - while (new->prefixlen < p->prefixlen && !(mask & diff)) - { - mask >>= 1; - new->prefixlen++; - } - newp[i] = np[i] & maskbit[new->prefixlen % 8]; - } -} - -static void -set_link (struct bgp_node *node, struct bgp_node *new) -{ - unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen); - - node->link[bit] = new; - new->parent = node; } -/* Lock node. */ -struct bgp_node * -bgp_lock_node (struct bgp_node *node) -{ - node->lock++; - return node; -} - -/* Unlock node. */ void -bgp_unlock_node (struct bgp_node *node) -{ - assert (node->lock > 0); - node->lock--; - - if (node->lock == 0) - bgp_node_delete (node); -} - -/* Find matched prefix. */ -struct bgp_node * -bgp_node_match (const struct bgp_table *table, struct prefix *p) -{ - struct bgp_node *node; - struct bgp_node *matched; - - matched = NULL; - node = table->top; - - /* Walk down tree. If there is matched route then store it to - matched. */ - while (node && node->p.prefixlen <= p->prefixlen && - prefix_match (&node->p, p)) - { - if (node->info) - matched = node; - node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; - } - - /* If matched route found, return it. */ - if (matched) - return bgp_lock_node (matched); - - return NULL; -} - -struct bgp_node * -bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) -{ - struct prefix_ipv4 p; - - memset (&p, 0, sizeof (struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = *addr; - - return bgp_node_match (table, (struct prefix *) &p); -} - -#ifdef HAVE_IPV6 -struct bgp_node * -bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) -{ - struct prefix_ipv6 p; - - memset (&p, 0, sizeof (struct prefix_ipv6)); - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_PREFIXLEN; - p.prefix = *addr; - - return bgp_node_match (table, (struct prefix *) &p); -} -#endif /* HAVE_IPV6 */ - -/* Lookup same prefix node. Return NULL when we can't find route. */ -struct bgp_node * -bgp_node_lookup (const struct bgp_table *table, struct prefix *p) +bgp_table_finish (struct bgp_table **rt) { - struct bgp_node *node; - u_char prefixlen = p->prefixlen; - const u_char *prefix = &p->u.prefix; - - node = table->top; - - while (node && node->p.prefixlen <= prefixlen && - prefix_match (&node->p, p)) + if (*rt != NULL) { - if (node->p.prefixlen == prefixlen && node->info) - return bgp_lock_node (node); - - node = node->link[prefix_bit(prefix, node->p.prefixlen)]; + bgp_table_unlock(*rt); + *rt = NULL; } - - return NULL; } -/* Add node to routing table. */ -struct bgp_node * -bgp_node_get (struct bgp_table *const table, struct prefix *p) +/* + * bgp_node_create + */ +static struct route_node * +bgp_node_create (route_table_delegate_t *delegate, struct route_table *table) { - struct bgp_node *new; struct bgp_node *node; - struct bgp_node *match; - u_char prefixlen = p->prefixlen; - const u_char *prefix = &p->u.prefix; - - match = NULL; - node = table->top; - while (node && node->p.prefixlen <= prefixlen && - prefix_match (&node->p, p)) - { - if (node->p.prefixlen == prefixlen) - { - bgp_lock_node (node); - return node; - } - match = node; - node = node->link[prefix_bit(prefix, node->p.prefixlen)]; - } - - if (node == NULL) - { - new = bgp_node_set (table, p); - if (match) - set_link (match, new); - else - table->top = new; - } - else - { - new = bgp_node_create (); - route_common (&node->p, p, &new->p); - new->p.family = p->family; - new->table = table; - set_link (new, node); - - if (match) - set_link (match, new); - else - table->top = new; - - if (new->p.prefixlen != prefixlen) - { - match = new; - new = bgp_node_set (table, p); - set_link (match, new); - table->count++; - } - } - table->count++; - bgp_lock_node (new); - - return new; + node = XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); + return bgp_node_to_rnode (node); } -/* Delete node from the routing table. */ +/* + * bgp_node_destroy + */ static void -bgp_node_delete (struct bgp_node *node) +bgp_node_destroy (route_table_delegate_t *delegate, + struct route_table *table, struct route_node *node) { - struct bgp_node *child; - struct bgp_node *parent; - - assert (node->lock == 0); - assert (node->info == NULL); - - if (node->l_left && node->l_right) - return; - - if (node->l_left) - child = node->l_left; - else - child = node->l_right; - - parent = node->parent; - - if (child) - child->parent = parent; - - if (parent) - { - if (parent->l_left == node) - parent->l_left = child; - else - parent->l_right = child; - } - else - node->table->top = child; - - node->table->count--; - - bgp_node_free (node); - - /* If parent node is stub then delete it also. */ - if (parent && parent->lock == 0) - bgp_node_delete (parent); + struct bgp_node *bgp_node; + bgp_node = bgp_node_from_rnode (node); + XFREE (MTYPE_BGP_NODE, bgp_node); } -/* Get fist node and lock it. This function is useful when one want - to lookup all the node exist in the routing table. */ -struct bgp_node * -bgp_table_top (const struct bgp_table *const table) -{ - /* If there is no node in the routing table return NULL. */ - if (table->top == NULL) - return NULL; - - /* Lock the top node and return it. */ - bgp_lock_node (table->top); - return table->top; -} +/* + * Function vector to customize the behavior of the route table + * library for BGP route tables. + */ +route_table_delegate_t bgp_table_delegate = { + .create_node = bgp_node_create, + .destroy_node = bgp_node_destroy +}; -/* Unlock current node and lock next node then return it. */ -struct bgp_node * -bgp_route_next (struct bgp_node *node) +/* + * bgp_table_init + */ +struct bgp_table * +bgp_table_init (afi_t afi, safi_t safi) { - struct bgp_node *next; - struct bgp_node *start; - - /* Node may be deleted from bgp_unlock_node so we have to preserve - next node's pointer. */ - - if (node->l_left) - { - next = node->l_left; - bgp_lock_node (next); - bgp_unlock_node (node); - return next; - } - if (node->l_right) - { - next = node->l_right; - bgp_lock_node (next); - bgp_unlock_node (node); - return next; - } + struct bgp_table *rt; - start = node; - while (node->parent) - { - if (node->parent->l_left == node && node->parent->l_right) - { - next = node->parent->l_right; - bgp_lock_node (next); - bgp_unlock_node (start); - return next; - } - node = node->parent; - } - bgp_unlock_node (start); - return NULL; -} + rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); -/* Unlock current node and lock next node until limit. */ -struct bgp_node * -bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) -{ - struct bgp_node *next; - struct bgp_node *start; + rt->route_table = route_table_init_with_delegate (&bgp_table_delegate); - /* Node may be deleted from bgp_unlock_node so we have to preserve - next node's pointer. */ + /* + * Set up back pointer to bgp_table. + */ + rt->route_table->info = rt; - if (node->l_left) - { - next = node->l_left; - bgp_lock_node (next); - bgp_unlock_node (node); - return next; - } - if (node->l_right) - { - next = node->l_right; - bgp_lock_node (next); - bgp_unlock_node (node); - return next; - } - - start = node; - while (node->parent && node != limit) - { - if (node->parent->l_left == node && node->parent->l_right) - { - next = node->parent->l_right; - bgp_lock_node (next); - bgp_unlock_node (start); - return next; - } - node = node->parent; - } - bgp_unlock_node (start); - return NULL; -} + bgp_table_lock (rt); + rt->type = BGP_TABLE_MAIN; + rt->afi = afi; + rt->safi = safi; -unsigned long -bgp_table_count (const struct bgp_table *table) -{ - return table->count; + return rt; } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 53df0bc6c..ff42399f1 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_TABLE_H #define _QUAGGA_BGP_TABLE_H +#include "table.h" + typedef enum { BGP_TABLE_MAIN, @@ -40,22 +42,20 @@ struct bgp_table /* The owner of this 'bgp_table' structure. */ struct peer *owner; - struct bgp_node *top; - - unsigned long count; + struct route_table *route_table; }; struct bgp_node { - struct prefix p; - - struct bgp_table *table; - struct bgp_node *parent; - struct bgp_node *link[2]; -#define l_left link[0] -#define l_right link[1] - - void *info; + /* + * CAUTION + * + * These fields must be the very first fields in this structure. + * + * @see bgp_node_to_rnode + * @see bgp_node_from_rnode + */ + ROUTE_NODE_FIELDS; struct bgp_adj_out *adj_out; @@ -63,8 +63,6 @@ struct bgp_node struct bgp_node *prn; - int lock; - u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) }; @@ -73,19 +71,207 @@ extern struct bgp_table *bgp_table_init (afi_t, safi_t); extern void bgp_table_lock (struct bgp_table *); extern void bgp_table_unlock (struct bgp_table *); extern void bgp_table_finish (struct bgp_table **); -extern void bgp_unlock_node (struct bgp_node *node); -extern struct bgp_node *bgp_table_top (const struct bgp_table *const); -extern struct bgp_node *bgp_route_next (struct bgp_node *); -extern struct bgp_node *bgp_route_next_until (struct bgp_node *, struct bgp_node *); -extern struct bgp_node *bgp_node_get (struct bgp_table *const, struct prefix *); -extern struct bgp_node *bgp_node_lookup (const struct bgp_table *const, struct prefix *); -extern struct bgp_node *bgp_lock_node (struct bgp_node *node); -extern struct bgp_node *bgp_node_match (const struct bgp_table *, struct prefix *); -extern struct bgp_node *bgp_node_match_ipv4 (const struct bgp_table *, - struct in_addr *); + + +/* + * bgp_node_from_rnode + * + * Returns the bgp_node structure corresponding to a route_node. + */ +static inline struct bgp_node * +bgp_node_from_rnode (struct route_node *rnode) +{ + return (struct bgp_node *) rnode; +} + +/* + * bgp_node_to_rnode + * + * Returns the route_node structure corresponding to a bgp_node. + */ +static inline struct route_node * +bgp_node_to_rnode (struct bgp_node *node) +{ + return (struct route_node *) node; +} + +/* + * bgp_node_table + * + * Returns the bgp_table that the given node is in. + */ +static inline struct bgp_table * +bgp_node_table (struct bgp_node *node) +{ + return bgp_node_to_rnode (node)->table->info; +} + +/* + * bgp_node_info + * + * Returns the 'info' pointer corresponding to a bgp node. + */ +static inline void * +bgp_node_info (const struct bgp_node *node) +{ + return node->info; +} + +/* + * bgp_node_set_info + */ +static inline void +bgp_node_set_info (struct bgp_node *node, void *info) +{ + node->info = info; +} + +/* + * bgp_node_prefix + */ +static inline struct prefix * +bgp_node_prefix (struct bgp_node *node) +{ + return &node->p; +} + +/* + * bgp_node_prefixlen + */ +static inline u_char +bgp_node_prefixlen (struct bgp_node *node) +{ + return bgp_node_prefix (node)->prefixlen; +} + +/* + * bgp_node_parent_nolock + * + * Gets the parent node of the given node without locking it. + */ +static inline struct bgp_node * +bgp_node_parent_nolock (struct bgp_node *node) +{ + return bgp_node_from_rnode (node->parent); +} + +/* + * bgp_unlock_node + */ +static inline void +bgp_unlock_node (struct bgp_node *node) +{ + route_unlock_node (bgp_node_to_rnode (node)); +} + +/* + * bgp_table_top_nolock + * + * Gets the top node in the table without locking it. + * + * @see bgp_table_top + */ +static inline struct bgp_node * +bgp_table_top_nolock (const struct bgp_table *const table) +{ + return bgp_node_from_rnode (table->route_table->top); +} + +/* + * bgp_table_top + */ +static inline struct bgp_node * +bgp_table_top (const struct bgp_table *const table) +{ + return bgp_node_from_rnode (route_top (table->route_table)); +} + +/* + * bgp_route_next + */ +static inline struct bgp_node * +bgp_route_next (struct bgp_node *node) +{ + return bgp_node_from_rnode (route_next (bgp_node_to_rnode (node))); +} + +/* + * bgp_route_next_until + */ +static inline struct bgp_node * +bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) +{ + struct route_node *rnode; + + rnode = route_next_until (bgp_node_to_rnode (node), + bgp_node_to_rnode (limit)); + return bgp_node_from_rnode (rnode); +} + +/* + * bgp_node_get + */ +static inline struct bgp_node * +bgp_node_get (struct bgp_table *const table, struct prefix *p) +{ + return bgp_node_from_rnode (route_node_get (table->route_table, p)); +} + +/* + * bgp_node_lookup + */ +static inline struct bgp_node * +bgp_node_lookup (const struct bgp_table *const table, struct prefix *p) +{ + return bgp_node_from_rnode (route_node_lookup (table->route_table, p)); +} + +/* + * bgp_lock_node + */ +static inline struct bgp_node * +bgp_lock_node (struct bgp_node *node) +{ + return bgp_node_from_rnode (route_lock_node (bgp_node_to_rnode (node))); +} + +/* + * bgp_node_match + */ +static inline struct bgp_node * +bgp_node_match (const struct bgp_table *table, struct prefix *p) +{ + return bgp_node_from_rnode (route_node_match (table->route_table, p)); +} + +/* + * bgp_node_match_ipv4 + */ +static inline struct bgp_node * +bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) +{ + return bgp_node_from_rnode (route_node_match_ipv4 (table->route_table, + addr)); +} + #ifdef HAVE_IPV6 -extern struct bgp_node *bgp_node_match_ipv6 (const struct bgp_table *, - struct in6_addr *); + +/* + * bgp_node_match_ipv6 + */ +static inline struct bgp_node * +bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) +{ + return bgp_node_from_rnode (route_node_match_ipv6 (table->route_table, + addr)); +} + #endif /* HAVE_IPV6 */ -extern unsigned long bgp_table_count (const struct bgp_table *const); + +static inline unsigned long +bgp_table_count (const struct bgp_table *const table) +{ + return route_table_count (table->route_table); +} + #endif /* _QUAGGA_BGP_TABLE_H */ From 28971c8cb1138700e87dc7da673e59b5596bb51b Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Fri, 17 Aug 2012 08:19:50 -0700 Subject: [PATCH 0125/1342] lib/table: add route_table_get_next() and iterator * lib/table.[ch] - Add a function (route_table_get_next()) to get the route_node in a tree that succeeds a given prefix in iteration order. This allows one to reliably walk nodes in a tree while allowing modifications, and is useful for achieving scale and performance. Other approaches are also possible -- the main plus point of this one is that it does not require any state about the walk to be maintained in the table data structures. - Add an iterator for walking the nodes in a tree. This introduces a new structure (route_table_iter_t) and the following main functions. route_table_iter_init() route_table_iter_pause() route_table_iter_next() route_table_iter_cleanup() The iterator normally uses node pointers and the existing route_next() function to walk nodes efficiently. When an iteration is 'paused' with route_table_iter_pause(), it stores the last prefix processed. The next call to route_table_iter_next() transparently invokes route_table_get_next() with the prefix to resume iteration. * bgpd/bgp_table.[ch] Add wrappers for the new table features described above. * tests/table_test.c Add tests for the new table code. Signed-off-by: David Lamparter --- bgpd/bgp_table.h | 78 +++++++ lib/table.c | 282 +++++++++++++++++++++++ lib/table.h | 126 ++++++++++ tests/.gitignore | 1 + tests/Makefile.am | 4 +- tests/table_test.c | 555 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1045 insertions(+), 1 deletion(-) create mode 100644 tests/table_test.c diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index ff42399f1..04a1d379e 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -67,6 +67,17 @@ struct bgp_node #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) }; +/* + * bgp_table_iter_t + * + * Structure that holds state for iterating over a bgp table. + */ +typedef struct bgp_table_iter_t_ +{ + struct bgp_table *table; + route_table_iter_t rt_iter; +} bgp_table_iter_t; + extern struct bgp_table *bgp_table_init (afi_t, safi_t); extern void bgp_table_lock (struct bgp_table *); extern void bgp_table_unlock (struct bgp_table *); @@ -274,4 +285,71 @@ bgp_table_count (const struct bgp_table *const table) return route_table_count (table->route_table); } +/* + * bgp_table_get_next + */ +static inline struct bgp_node * +bgp_table_get_next (const struct bgp_table *table, struct prefix *p) +{ + return bgp_node_from_rnode (route_table_get_next (table->route_table, p)); +} + +/* + * bgp_table_iter_init + */ +static inline void +bgp_table_iter_init (bgp_table_iter_t * iter, struct bgp_table *table) +{ + bgp_table_lock (table); + iter->table = table; + route_table_iter_init (&iter->rt_iter, table->route_table); +} + +/* + * bgp_table_iter_next + */ +static inline struct bgp_node * +bgp_table_iter_next (bgp_table_iter_t * iter) +{ + return bgp_node_from_rnode (route_table_iter_next (&iter->rt_iter)); +} + +/* + * bgp_table_iter_cleanup + */ +static inline void +bgp_table_iter_cleanup (bgp_table_iter_t * iter) +{ + route_table_iter_cleanup (&iter->rt_iter); + bgp_table_unlock (iter->table); + iter->table = NULL; +} + +/* + * bgp_table_iter_pause + */ +static inline void +bgp_table_iter_pause (bgp_table_iter_t * iter) +{ + route_table_iter_pause (&iter->rt_iter); +} + +/* + * bgp_table_iter_is_done + */ +static inline int +bgp_table_iter_is_done (bgp_table_iter_t * iter) +{ + return route_table_iter_is_done (&iter->rt_iter); +} + +/* + * bgp_table_iter_started + */ +static inline int +bgp_table_iter_started (bgp_table_iter_t * iter) +{ + return route_table_iter_started (&iter->rt_iter); +} + #endif /* _QUAGGA_BGP_TABLE_H */ diff --git a/lib/table.c b/lib/table.c index 6bbc9c621..19b5d1b18 100644 --- a/lib/table.c +++ b/lib/table.c @@ -528,3 +528,285 @@ route_table_init (void) { return route_table_init_with_delegate (&default_delegate); } + +/** + * route_table_prefix_iter_cmp + * + * Compare two prefixes according to the order in which they appear in + * an iteration over a tree. + * + * @return -1 if p1 occurs before p2 (p1 < p2) + * 0 if the prefixes are identical (p1 == p2) + * +1 if p1 occurs after p2 (p1 > p2) + */ +int +route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2) +{ + struct prefix common_space; + struct prefix *common = &common_space; + + if (p1->prefixlen <= p2->prefixlen) + { + if (prefix_match (p1, p2)) + { + + /* + * p1 contains p2, or is equal to it. + */ + return (p1->prefixlen == p2->prefixlen) ? 0 : -1; + } + } + else + { + + /* + * Check if p2 contains p1. + */ + if (prefix_match (p2, p1)) + return 1; + } + + route_common (p1, p2, common); + assert (common->prefixlen < p1->prefixlen); + assert (common->prefixlen < p2->prefixlen); + + /* + * Both prefixes are longer than the common prefix. + * + * We need to check the bit after the common prefixlen to determine + * which one comes later. + */ + if (prefix_bit (&p1->u.prefix, common->prefixlen)) + { + + /* + * We branch to the right to get to p1 from the common prefix. + */ + assert (!prefix_bit (&p2->u.prefix, common->prefixlen)); + return 1; + } + + /* + * We branch to the right to get to p2 from the common prefix. + */ + assert (prefix_bit (&p2->u.prefix, common->prefixlen)); + return -1; +} + +/* + * route_get_subtree_next + * + * Helper function that returns the first node that follows the nodes + * in the sub-tree under 'node' in iteration order. + */ +static struct route_node * +route_get_subtree_next (struct route_node *node) +{ + while (node->parent) + { + if (node->parent->l_left == node && node->parent->l_right) + return node->parent->l_right; + + node = node->parent; + } + + return NULL; +} + +/** + * route_table_get_next_internal + * + * Helper function to find the node that occurs after the given prefix in + * order of iteration. + * + * @see route_table_get_next + */ +static struct route_node * +route_table_get_next_internal (const struct route_table *table, + struct prefix *p) +{ + struct route_node *node, *tmp_node; + u_char prefixlen; + int cmp; + + prefixlen = p->prefixlen; + + node = table->top; + + while (node) + { + int match; + + if (node->p.prefixlen < p->prefixlen) + match = prefix_match (&node->p, p); + else + match = prefix_match (p, &node->p); + + if (match) + { + if (node->p.prefixlen == p->prefixlen) + { + + /* + * The prefix p exists in the tree, just return the next + * node. + */ + route_lock_node (node); + node = route_next (node); + if (node) + route_unlock_node (node); + + return (node); + } + + if (node->p.prefixlen > p->prefixlen) + { + + /* + * Node is in the subtree of p, and hence greater than p. + */ + return node; + } + + /* + * p is in the sub-tree under node. + */ + tmp_node = node->link[prefix_bit (&p->u.prefix, node->p.prefixlen)]; + + if (tmp_node) + { + node = tmp_node; + continue; + } + + /* + * There are no nodes in the direction where p should be. If + * node has a right child, then it must be greater than p. + */ + if (node->l_right) + return node->l_right; + + /* + * No more children to follow, go upwards looking for the next + * node. + */ + return route_get_subtree_next (node); + } + + /* + * Neither node prefix nor 'p' contains the other. + */ + cmp = route_table_prefix_iter_cmp (&node->p, p); + if (cmp > 0) + { + + /* + * Node follows p in iteration order. Return it. + */ + return node; + } + + assert (cmp < 0); + + /* + * Node and the subtree under it come before prefix p in + * iteration order. Prefix p and its sub-tree are not present in + * the tree. Go upwards and find the first node that follows the + * subtree. That node will also succeed p. + */ + return route_get_subtree_next (node); + } + + return NULL; +} + +/** + * route_table_get_next + * + * Find the node that occurs after the given prefix in order of + * iteration. + */ +struct route_node * +route_table_get_next (const struct route_table *table, struct prefix *p) +{ + struct route_node *node; + + node = route_table_get_next_internal (table, p); + if (node) + { + assert (route_table_prefix_iter_cmp (&node->p, p) > 0); + route_lock_node (node); + } + return node; +} + +/* + * route_table_iter_init + */ +void +route_table_iter_init (route_table_iter_t * iter, struct route_table *table) +{ + memset (iter, 0, sizeof (*iter)); + iter->state = RT_ITER_STATE_INIT; + iter->table = table; +} + +/* + * route_table_iter_pause + * + * Pause an iteration over the table. This allows the iteration to be + * resumed point after arbitrary additions/deletions from the table. + * An iteration can be resumed by just calling route_table_iter_next() + * on the iterator. + */ +void +route_table_iter_pause (route_table_iter_t * iter) +{ + switch (iter->state) + { + + case RT_ITER_STATE_INIT: + case RT_ITER_STATE_PAUSED: + case RT_ITER_STATE_DONE: + return; + + case RT_ITER_STATE_ITERATING: + + /* + * Save the prefix that we are currently at. The next call to + * route_table_iter_next() will return the node after this prefix + * in the tree. + */ + prefix_copy (&iter->pause_prefix, &iter->current->p); + route_unlock_node (iter->current); + iter->current = NULL; + iter->state = RT_ITER_STATE_PAUSED; + return; + + default: + assert (0); + } + +} + +/* + * route_table_iter_cleanup + * + * Release any resources held by the iterator. + */ +void +route_table_iter_cleanup (route_table_iter_t * iter) +{ + if (iter->state == RT_ITER_STATE_ITERATING) + { + route_unlock_node (iter->current); + iter->current = NULL; + } + assert (!iter->current); + + /* + * Set the state to RT_ITER_STATE_DONE to make any + * route_table_iter_next() calls on this iterator return NULL. + */ + iter->state = RT_ITER_STATE_DONE; +} diff --git a/lib/table.h b/lib/table.h index 4d3eddb1d..ab357a074 100644 --- a/lib/table.h +++ b/lib/table.h @@ -98,6 +98,43 @@ struct route_node #define l_right link[1] }; +typedef struct route_table_iter_t_ route_table_iter_t; + +typedef enum +{ + RT_ITER_STATE_INIT, + RT_ITER_STATE_ITERATING, + RT_ITER_STATE_PAUSED, + RT_ITER_STATE_DONE +} route_table_iter_state_t; + +/* + * route_table_iter_t + * + * Structure that holds state for iterating over a route table. + */ +struct route_table_iter_t_ +{ + + route_table_iter_state_t state; + + /* + * Routing table that we are iterating over. The caller must ensure + * that that table outlives the iterator. + */ + struct route_table *table; + + /* + * The node that the iterator is currently on. + */ + struct route_node *current; + + /* + * The last prefix that the iterator processed before it was paused. + */ + struct prefix pause_prefix; +}; + /* Prototypes. */ extern struct route_table *route_table_init (void); @@ -125,4 +162,93 @@ extern struct route_node *route_node_match_ipv6 (const struct route_table *, #endif /* HAVE_IPV6 */ extern unsigned long route_table_count (const struct route_table *); + +extern struct route_node * +route_table_get_next (const struct route_table *table, struct prefix *p); +extern int +route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2); + +/* + * Iterator functions. + */ +extern void route_table_iter_init (route_table_iter_t *iter, + struct route_table *table); +extern void route_table_iter_pause (route_table_iter_t *iter); +extern void route_table_iter_cleanup (route_table_iter_t *iter); + +/* + * Inline functions. + */ + +/* + * route_table_iter_next + * + * Get the next node in the tree. + */ +static inline struct route_node * +route_table_iter_next (route_table_iter_t * iter) +{ + struct route_node *node; + + switch (iter->state) + { + + case RT_ITER_STATE_INIT: + + /* + * We're just starting the iteration. + */ + node = route_top (iter->table); + break; + + case RT_ITER_STATE_ITERATING: + node = route_next (iter->current); + break; + + case RT_ITER_STATE_PAUSED: + + /* + * Start with the node following pause_prefix. + */ + node = route_table_get_next (iter->table, &iter->pause_prefix); + break; + + case RT_ITER_STATE_DONE: + return NULL; + + default: + assert (0); + } + + iter->current = node; + if (node) + iter->state = RT_ITER_STATE_ITERATING; + else + iter->state = RT_ITER_STATE_DONE; + + return node; +} + +/* + * route_table_iter_is_done + * + * Returns TRUE if the iteration is complete. + */ +static inline int +route_table_iter_is_done (route_table_iter_t *iter) +{ + return iter->state == RT_ITER_STATE_DONE; +} + +/* + * route_table_iter_started + * + * Returns TRUE if this iterator has started iterating over the tree. + */ +static inline int +route_table_iter_started (route_table_iter_t *iter) +{ + return iter->state != RT_ITER_STATE_INIT; +} + #endif /* _ZEBRA_TABLE_H */ diff --git a/tests/.gitignore b/tests/.gitignore index ca0859438..e6ab706c0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -8,6 +8,7 @@ TAGS *.lo *.la *.libs +tabletest testsig .arch-inventory .arch-ids diff --git a/tests/Makefile.am b/tests/Makefile.am index 0c262a4ab..e510a1588 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,7 +6,7 @@ AM_LDFLAGS = $(PILDFLAGS) noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ aspathtest testprivs teststream testbgpcap ecommtest \ - testbgpmpattr testchecksum testbgpmpath + testbgpmpattr testchecksum testbgpmpath tabletest testsig_SOURCES = test-sig.c testbuffer_SOURCES = test-buffer.c @@ -22,6 +22,7 @@ ecommtest_SOURCES = ecommunity_test.c testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c +tabletest_SOURCES = table_test.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ @@ -37,3 +38,4 @@ ecommtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a testbgpmpattr_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ testbgpmpath_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a +tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm diff --git a/tests/table_test.c b/tests/table_test.c new file mode 100644 index 000000000..fc9cc3dd9 --- /dev/null +++ b/tests/table_test.c @@ -0,0 +1,555 @@ +/* $QuaggaId: Format:%an, %ai, %h$ $ + * + * Routing table test + * Copyright (C) 2012 OSR. + * + * 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 + +#include "prefix.h" +#include "table.h" + +/* + * test_node_t + * + * Information that is kept for each node in the radix tree. + */ +typedef struct test_node_t_ +{ + + /* + * Human readable representation of the string. Allocated using + * malloc()/dup(). + */ + char *prefix_str; +} test_node_t; + +struct thread_master *master; + +/* + * add_node + * + * Add the given prefix (passed in as a string) to the given table. + */ +static void +add_node (struct route_table *table, const char *prefix_str) +{ + struct prefix_ipv4 p; + test_node_t *node; + struct route_node *rn; + + assert (prefix_str); + + if (str2prefix_ipv4 (prefix_str, &p) <= 0) + { + assert (0); + } + + rn = route_node_get (table, (struct prefix *) &p); + if (rn->info) + { + assert (0); + return; + } + + node = malloc (sizeof (test_node_t)); + assert (node); + node->prefix_str = strdup (prefix_str); + assert (node->prefix_str); + rn->info = node; +} + +/* + * add_nodes + * + * Convenience function to add a bunch of nodes together. + * + * The arguments must be prefixes in string format, with a NULL as the + * last argument. + */ +static void +add_nodes (struct route_table *table, ...) +{ + va_list arglist; + char *prefix; + + va_start (arglist, table); + + prefix = va_arg (arglist, char *); + while (prefix) + { + add_node (table, prefix); + prefix = va_arg (arglist, char *); + } + + va_end (arglist); +} + +/* + * print_subtree + * + * Recursive function to print a route node and its children. + * + * @see print_table + */ +static void +print_subtree (struct route_node *rn, const char *legend, int indent_level) +{ + char buf[INET_ADDRSTRLEN + 4]; + int i; + + /* + * Print this node first. + */ + for (i = 0; i < indent_level; i++) + { + printf (" "); + } + + prefix2str (&rn->p, buf, sizeof (buf)); + printf ("%s: %s", legend, buf); + if (!rn->info) + { + printf (" (internal)"); + } + printf ("\n"); + if (rn->l_left) + { + print_subtree (rn->l_left, "Left", indent_level + 1); + } + if (rn->l_right) + { + print_subtree (rn->l_right, "Right", indent_level + 1); + } +} + +/* + * print_table + * + * Function that prints out the internal structure of a route table. + */ +static void +print_table (struct route_table *table) +{ + struct route_node *rn; + + rn = table->top; + + if (!rn) + { + printf ("\n"); + return; + } + + print_subtree (rn, "Top", 0); +} + +/* + * clear_table + * + * Remove all nodes from the given table. + */ +static void +clear_table (struct route_table *table) +{ + route_table_iter_t iter; + struct route_node *rn; + test_node_t *node; + + route_table_iter_init (&iter, table); + + while ((rn = route_table_iter_next (&iter))) + { + node = rn->info; + if (!node) + { + continue; + } + rn->info = NULL; + route_unlock_node (rn); + free (node->prefix_str); + free (node); + } + + route_table_iter_cleanup (&iter); + + assert (table->top == NULL); +} + +/* + * verify_next_by_iterating + * + * Iterate over the tree to make sure that the first prefix after + * target_pfx is the expected one. Note that target_pfx may not be + * present in the tree. + */ +static void +verify_next_by_iterating (struct route_table *table, + struct prefix *target_pfx, struct prefix *next_pfx) +{ + route_table_iter_t iter; + struct route_node *rn; + + route_table_iter_init (&iter, table); + while ((rn = route_table_iter_next (&iter))) + { + if (route_table_prefix_iter_cmp (&rn->p, target_pfx) > 0) + { + assert (!prefix_cmp (&rn->p, next_pfx)); + break; + } + } + + if (!rn) + { + assert (!next_pfx); + } + + route_table_iter_cleanup (&iter); +} + +/* + * verify_next + * + * Verifies that route_table_get_next() returns the expected result + * (result) for the prefix string 'target'. + */ +static void +verify_next (struct route_table *table, const char *target, const char *next) +{ + struct prefix_ipv4 target_pfx, next_pfx; + struct route_node *rn; + char result_buf[INET_ADDRSTRLEN + 4]; + + if (str2prefix_ipv4 (target, &target_pfx) <= 0) + { + assert (0); + } + + rn = route_table_get_next (table, (struct prefix *) &target_pfx); + if (rn) + { + prefix2str (&rn->p, result_buf, sizeof (result_buf)); + } + else + { + snprintf (result_buf, sizeof (result_buf), "(Null)"); + } + + printf ("\n"); + print_table (table); + printf ("Verifying successor of %s. Expected: %s, Result: %s\n", target, + next ? next : "(Null)", result_buf); + + if (!rn) + { + assert (!next); + verify_next_by_iterating (table, (struct prefix *) &target_pfx, NULL); + return; + } + + assert (next); + + if (str2prefix_ipv4 (next, &next_pfx) <= 0) + { + assert (0); + } + + if (prefix_cmp (&rn->p, (struct prefix *) &next_pfx)) + { + assert (0); + } + route_unlock_node (rn); + + verify_next_by_iterating (table, (struct prefix *) &target_pfx, + (struct prefix *) &next_pfx); +} + +/* + * test_get_next + */ +static void +test_get_next (void) +{ + struct route_table *table; + + printf ("\n\nTesting route_table_get_next()\n"); + table = route_table_init (); + + /* + * Target exists in tree, but has no successor. + */ + add_nodes (table, "1.0.1.0/24", NULL); + verify_next (table, "1.0.1.0/24", NULL); + clear_table (table); + + /* + * Target exists in tree, and there is a node in its left subtree. + */ + add_nodes (table, "1.0.1.0/24", "1.0.1.0/25", NULL); + verify_next (table, "1.0.1.0/24", "1.0.1.0/25"); + clear_table (table); + + /* + * Target exists in tree, and there is a node in its right subtree. + */ + add_nodes (table, "1.0.1.0/24", "1.0.1.128/25", NULL); + verify_next (table, "1.0.1.0/24", "1.0.1.128/25"); + clear_table (table); + + /* + * Target exists in the tree, next node is outside subtree. + */ + add_nodes (table, "1.0.1.0/24", "1.1.0.0/16", NULL); + verify_next (table, "1.0.1.0/24", "1.1.0.0/16"); + clear_table (table); + + /* + * The target node does not exist in the tree for all the test cases + * below this point. + */ + + /* + * There is no successor in the tree. + */ + add_nodes (table, "1.0.0.0/16", NULL); + verify_next (table, "1.0.1.0/24", NULL); + clear_table (table); + + /* + * There exists a node that would be in the target's left subtree. + */ + add_nodes (table, "1.0.0.0/16", "1.0.1.0/25", NULL); + verify_next (table, "1.0.1.0/24", "1.0.1.0/25"); + clear_table (table); + + /* + * There exists a node would be in the target's right subtree. + */ + add_nodes (table, "1.0.0.0/16", "1.0.1.128/25", NULL); + verify_next (table, "1.0.1.0/24", "1.0.1.128/25"); + clear_table (table); + + /* + * A search for the target reaches a node where there are no child + * nodes in the direction of the target (left), but the node has a + * right child. + */ + add_nodes (table, "1.0.0.0/16", "1.0.128.0/17", NULL); + verify_next (table, "1.0.0.0/17", "1.0.128.0/17"); + clear_table (table); + + /* + * A search for the target reaches a node with no children. We have + * to go upwards in the tree to find a successor. + */ + add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/24", + "1.0.128.0/17", NULL); + verify_next (table, "1.0.1.0/25", "1.0.128.0/17"); + clear_table (table); + + /* + * A search for the target reaches a node where neither the node nor + * the target prefix contain each other. + * + * In first case below the node succeeds the target. + * + * In the second case, the node comes before the target, so we have + * to go up the tree looking for a successor. + */ + add_nodes (table, "1.0.0.0/16", "1.0.1.0/24", NULL); + verify_next (table, "1.0.0.0/24", "1.0.1.0/24"); + clear_table (table); + + add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/25", + "1.0.128.0/17", NULL); + verify_next (table, "1.0.1.128/25", "1.0.128.0/17"); + clear_table (table); + + route_table_finish (table); +} + +/* + * verify_prefix_iter_cmp + */ +static void +verify_prefix_iter_cmp (const char *p1, const char *p2, int exp_result) +{ + struct prefix_ipv4 p1_pfx, p2_pfx; + int result; + + if (str2prefix_ipv4 (p1, &p1_pfx) <= 0) + { + assert (0); + } + + if (str2prefix_ipv4 (p2, &p2_pfx) <= 0) + { + assert (0); + } + + result = route_table_prefix_iter_cmp ((struct prefix *) &p1_pfx, + (struct prefix *) &p2_pfx); + + printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result); + + assert (exp_result == result); + + /* + * Also check the reverse comparision. + */ + result = route_table_prefix_iter_cmp ((struct prefix *) &p2_pfx, + (struct prefix *) &p1_pfx); + + if (exp_result) + { + exp_result = -exp_result; + } + + printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result); + assert (result == exp_result); +} + +/* + * test_prefix_iter_cmp + * + * Tests comparision of prefixes according to order of iteration. + */ +static void +test_prefix_iter_cmp () +{ + printf ("\n\nTesting route_table_prefix_iter_cmp()\n"); + + verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/8", 0); + + verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/16", -1); + + verify_prefix_iter_cmp ("1.0.0.0/16", "1.128.0.0/16", -1); +} + +/* + * verify_iter_with_pause + * + * Iterates over a tree using two methods: 'normal' iteration, and an + * iterator that pauses at each node. Verifies that the two methods + * yield the same results. + */ +static void +verify_iter_with_pause (struct route_table *table) +{ + unsigned long num_nodes; + struct route_node *rn, *iter_rn; + route_table_iter_t iter_space; + route_table_iter_t *iter = &iter_space; + + route_table_iter_init (iter, table); + num_nodes = 0; + + for (rn = route_top (table); rn; rn = route_next (rn)) + { + num_nodes++; + route_table_iter_pause (iter); + + assert (iter->current == NULL); + if (route_table_iter_started (iter)) + { + assert (iter->state == RT_ITER_STATE_PAUSED); + } + else + { + assert (rn == table->top); + assert (iter->state == RT_ITER_STATE_INIT); + } + + iter_rn = route_table_iter_next (iter); + + /* + * Make sure both iterations return the same node. + */ + assert (rn == iter_rn); + } + + assert (num_nodes == route_table_count (table)); + + route_table_iter_pause (iter); + iter_rn = route_table_iter_next (iter); + + assert (iter_rn == NULL); + assert (iter->state == RT_ITER_STATE_DONE); + + assert (route_table_iter_next (iter) == NULL); + assert (iter->state == RT_ITER_STATE_DONE); + + route_table_iter_cleanup (iter); + + print_table (table); + printf ("Verified pausing iteration on tree with %lu nodes\n", num_nodes); +} + +/* + * test_iter_pause + */ +static void +test_iter_pause (void) +{ + struct route_table *table; + int i, num_prefixes; + const char *prefixes[] = { + "1.0.1.0/24", + "1.0.1.0/25", + "1.0.1.128/25", + "1.0.2.0/24", + "2.0.0.0/8" + }; + + num_prefixes = sizeof (prefixes) / sizeof (prefixes[0]); + + printf ("\n\nTesting that route_table_iter_pause() works as expected\n"); + table = route_table_init (); + for (i = 0; i < num_prefixes; i++) + { + add_nodes (table, prefixes[i], NULL); + } + + verify_iter_with_pause (table); + + clear_table (table); + route_table_finish (table); +} + +/* + * run_tests + */ +static void +run_tests (void) +{ + test_prefix_iter_cmp (); + test_get_next (); + test_iter_pause (); +} + +/* + * main + */ +int +main (void) +{ + run_tests (); +} From 945ea293399af6c9ff3efd07686ff30c3d2a3e8b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 6 Aug 2012 12:17:12 +0100 Subject: [PATCH 0126/1342] Revert "ospfd: Do not fall back to intervening router." This reverts commit 9289c6ff55cd96c943d23e43fc9e5f987aa965ed. The commit reverted an earlier change which was fixed a bug that caused black-holes to remote destinations with multiple paths, that could occur during convergence. Overall, the previous code is more correct. --- ospfd/ospf_spf.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index abc8a91a8..a5242b686 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -675,11 +675,37 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, added = 1; ospf_spf_add_parent (v, w, nh, distance); } - /* Always return here as we known that 16.1.1 para 4 - does not apply one you have found a connection to root */ - return added; - } + /* Note lack of return is deliberate. See next comment. */ + } } + /* NB: This code is non-trivial. + * + * E.g. it is not enough to know that V connects to the root. It is + * also important that the while above, looping through all links from + * W->V found at least one link, so that we know there is + * bi-directional connectivity between V and W (which need not be the + * case, e.g. when OSPF has not yet converged fully). Otherwise, if + * we /always/ return here, without having checked that root->V->-W + * actually resulted in a valid nexthop being created, then we we will + * prevent SPF from finding/using higher cost paths. + * + * It is important, if root->V->W has not been added, that we continue + * through to the intervening-router nexthop code below. So as to + * ensure other paths to V may be used. This avoids unnecessary + * blackholes while OSPF is convergening. + * + * I.e. we may have arrived at this function, examining V -> W, via + * workable paths other than root -> V, and it's important to avoid + * getting "confused" by non-working root->V->W path - it's important + * to *not* lose the working non-root paths, just because of a + * non-viable root->V->W. + * + * See also bug #330 (required reading!), and: + * + * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes + */ + if (added) + return added; } /* 16.1.1 para 4. If there is at least one intervening router in the From b0145ddb4bf75d2c8853aa3d0bc7c522f4f17531 Mon Sep 17 00:00:00 2001 From: Nolan Leake Date: Thu, 13 Sep 2012 17:17:31 +0000 Subject: [PATCH 0127/1342] zebra: make static routes respect table setting Make static routes respect non-default routing tables. BEFORE PATCH ------------ ! in zebra.conf table 1 ! add static route vtysh> ip route 10.0.0.0/30 eth0 cumulus@net-top0:~$ ip route default via 192.168.0.2 dev eth0 10.0.0.0/30 dev eth0 proto zebra 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15 ! nothing in table 1 cumulus@net-top0:~$ ip route show table 1 AFTER PATCH ----------- ! in zebra.conf table 1 ! add static route vtysh> ip route 10.0.0.0/30 eth0 cumulus@net-top0:~$ ip route default via 192.168.0.2 dev eth0 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15 ! static route in table 1 cumulus@net-top0:~$ ip route show table 1 10.0.0.0/30 dev eth0 proto zebra Signed-off-by: Nolan Leake Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 50674ee88..b8a47031f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2036,6 +2036,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; + rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; switch (si->type) From d8a4e42b7d19a87eacc00c825e913907a58f39ee Mon Sep 17 00:00:00 2001 From: JR Rivers Date: Thu, 13 Sep 2012 17:17:36 +0000 Subject: [PATCH 0128/1342] lib: improve fletcher checksum validation OVERVIEW The checksum used in OSPF (rfc2328) is specified in rc905 annex B. There is an sample implementation in rfc1008 which forms the basis of the quagga implementation. This algorithm works perfectly when generating a checksum; however, validation is a bit problematic. The following LSA (generated by a non-quagga implementation) is received by quagga and marked with an invalid checksum; however, it passes both the rfc905 and rfc1008 validation checks. static uint8_t lsa_10_121_233_29[] = { 0x0e, 0x10, 0x02, 0x03, 0x09, 0x00, 0x35, 0x40, 0x0a, 0x79, 0xe9, 0x1d, 0x80, 0x00, 0x00, 0x03, 0x00, 0x8a, 0x00, 0x1c, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x36, 0xb0 }; LS Type: Summary-LSA (IP network) LS Age: 3600 seconds Do Not Age: False Options: 0x02 (E) Link-State Advertisement Type: Summary-LSA (IP network) (3) Link State ID: 9.0.53.64 Advertising Router: 10.121.233.29 (10.121.233.29) LS Sequence Number: 0x80000003 LS Checksum: 0x008a Length: 28 Netmask: 255.255.255.224 Metric: 14000 You'll note that one byte of the checksum is 0x00; quagga would calculate the checksum as 0xff8a. It can be argued that the sourcing implementation generates an incorrect checksum; however, rfc905 indicates that, for 1's complement arithmetic, the value 255 shall be regarded as 0, thus either values are valid. EXPLANATION The quagga ospfd and ospf6d implementations operate by copying the PDU's existing checksum in a holding variable, calculating the checksum, and comparing the resulting checksum to the original. As a note, this implementation has the side effect of modifying the contents of the PDU. Evaluation of both rfc905 and rfc1008 shows that checksum validation should involve calculating the sum over the PDU and checking that both resulting C0 and C1 values are zero. This behavior is enacted in the rfc1008 implementation by calling encodecc with k = 0 (checksum offset); however, this functionality had been omitted from the quagga implementation. PATCH This patch adds the ability to call the quagga's fletcher_checksum() with a checksum offset value of 0xffff (aka FLETCHER_CHECKSUM_VALIDATE) which returns the sum over the buffer (a value of 0 indicates a valid checksum). This is similar to the mechanism in rfc1008 when called with k = 0. The patch also introduces ospf_lsa_checksum_valid(). ospf6d had it's own implementation of the fletcher checksum in ospf6_lsa_checksum(); it's the same algorithm as in fletcher_checksum(). This patch removes the local implementation in favor of the library's as well as creates and uses ospf6_lsa_checksum_valid(). quagga's ISIS implementation suffers from the same problem; however, I do not have the facilities to validate a fix to ISIS, thus this change has been left to the ISIS maintainers. The function iso_csum_verify() should be reduced to running the fletcher checksum over the buffer using an offset of 0. Signed-off-by: JR Rivers Reviewed-by: Scott Feldman Reviewed-by: Nolan Leake Reviewed-by: Ayan Banerjee Reviewed-by: Shrijeet Mukherjee Signed-off-by: David Lamparter --- lib/checksum.c | 46 ++++++++++++++++++++++--------------- lib/checksum.h | 1 + ospf6d/ospf6_flood.c | 4 +--- ospf6d/ospf6_lsa.c | 54 ++++++++++++++++++-------------------------- ospf6d/ospf6_lsa.h | 1 + ospfd/ospf_lsa.c | 12 ++++++++++ ospfd/ospf_packet.c | 2 +- 7 files changed, 66 insertions(+), 54 deletions(-) diff --git a/lib/checksum.c b/lib/checksum.c index 3ddde8152..43940b715 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -51,6 +51,8 @@ in_cksum(void *parg, int nbytes) /* To be consistent, offset is 0-based index, rather than the 1-based index required in the specification ISO 8473, Annex C.1 */ +/* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum + without modifying the buffer; a valid checksum returns 0 */ u_int16_t fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) { @@ -62,13 +64,14 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) checksum = 0; - assert (offset < len); - /* - * Zero the csum in the packet. - */ - csum = (u_int16_t *) (buffer + offset); - *(csum) = 0; + if (offset != FLETCHER_CHECKSUM_VALIDATE) + /* Zero the csum in the packet. */ + { + assert (offset < (len - 1)); /* account for two bytes of checksum */ + csum = (u_int16_t *) (buffer + offset); + *(csum) = 0; + } p = buffer; c0 = 0; @@ -89,7 +92,7 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) left -= partial_len; } - + /* The cast is important, to ensure the mod is taken as a signed value. */ x = (int)((len - offset - 1) * c0 - c1) % 255; @@ -98,17 +101,24 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) y = 510 - c0 - x; if (y > 255) y -= 255; - - /* - * Now we write this to the packet. - * We could skip this step too, since the checksum returned would - * be stored into the checksum field by the caller. - */ - buffer[offset] = x; - buffer[offset + 1] = y; - - /* Take care of the endian issue */ - checksum = htons((x << 8) | (y & 0xFF)); + + if (offset == FLETCHER_CHECKSUM_VALIDATE) + { + checksum = (c1 << 8) + c0; + } + else + { + /* + * Now we write this to the packet. + * We could skip this step too, since the checksum returned would + * be stored into the checksum field by the caller. + */ + buffer[offset] = x; + buffer[offset + 1] = y; + + /* Take care of the endian issue */ + checksum = htons((x << 8) | (y & 0xFF)); + } return checksum; } diff --git a/lib/checksum.h b/lib/checksum.h index da1d3cbad..b310f744c 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,2 +1,3 @@ extern int in_cksum(void *, int); +#define FLETCHER_CHECKSUM_VALIDATE 0xffff extern u_int16_t fletcher_checksum(u_char *, const size_t len, const uint16_t offset); diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 670c5d1d1..b81597290 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -733,7 +733,6 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, { struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL; int ismore_recent; - unsigned short cksum; int is_debug = 0; ismore_recent = 1; @@ -751,8 +750,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, } /* (1) LSA Checksum */ - cksum = ntohs (new->header->checksum); - if (ntohs (ospf6_lsa_checksum (new->header)) != cksum) + if (! ospf6_lsa_checksum_valid (new->header)) { if (is_debug) zlog_debug ("Wrong LSA Checksum, discard"); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index e65752d8c..ff061dfb1 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -29,6 +29,7 @@ #include "command.h" #include "memory.h" #include "thread.h" +#include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -672,47 +673,36 @@ ospf6_lsa_refresh (struct thread *thread) -/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */ -#define MODX 4102 -#define LSA_CHECKSUM_OFFSET 15 +/* Fletcher Checksum -- Refer to RFC1008. */ +/* All the offsets are zero-based. The offsets in the RFC1008 are + one-based. */ unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) { - u_char *sp, *ep, *p, *q; - int c0 = 0, c1 = 0; - int x, y; - u_int16_t length; + u_char *buffer = (u_char *) &lsa_header->type; + int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ - lsa_header->checksum = 0; - length = ntohs (lsa_header->length) - 2; - sp = (u_char *) &lsa_header->type; + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa_header->length) - type_offset; - for (ep = sp + length; sp < ep; sp = q) - { - q = sp + MODX; - if (q > ep) - q = ep; - for (p = sp; p < q; p++) - { - c0 += *p; - c1 += c0; - } - c0 %= 255; - c1 %= 255; - } + /* Checksum offset starts from "type" field, not the beginning of the + lsa_header struct. The offset is 14, rather than 16. */ + int checksum_offset = (u_char *) &lsa_header->checksum - buffer; + + return (unsigned short)fletcher_checksum(buffer, len, checksum_offset); +} - /* r = (c1 << 8) + c0; */ - x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; - if (x <= 0) - x += 255; - y = 510 - c0 - x; - if (y > 255) - y -= 255; +int +ospf6_lsa_checksum_valid (struct ospf6_lsa_header *lsa_header) +{ + u_char *buffer = (u_char *) &lsa_header->type; + int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ - lsa_header->checksum = htons ((x << 8) + y); + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa_header->length) - type_offset; - return (lsa_header->checksum); + return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); } void diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 7d93f5cba..263411fc7 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -237,6 +237,7 @@ extern int ospf6_lsa_expire (struct thread *); extern int ospf6_lsa_refresh (struct thread *); extern unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *); +extern int ospf6_lsa_checksum_valid (struct ospf6_lsa_header *); extern int ospf6_lsa_prohibited_duration (u_int16_t type, u_int32_t id, u_int32_t adv_router, void *scope); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 493209a0b..5579d8efd 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -192,6 +192,18 @@ ospf_lsa_checksum (struct lsa_header *lsa) return fletcher_checksum(buffer, len, checksum_offset); } +int +ospf_lsa_checksum_valid (struct lsa_header *lsa) +{ + u_char *buffer = (u_char *) &lsa->options; + int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ + + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa->length) - options_offset; + + return(fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); +} + /* Create OSPF LSA. */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 351fb210b..ede59088c 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1590,7 +1590,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, /* Validate the LSA's LS checksum. */ sum = lsah->checksum; - if (sum != ospf_lsa_checksum (lsah)) + if (! ospf_lsa_checksum_valid (lsah)) { /* (bug #685) more details in a one-line message make it possible * to identify problem source on the one hand and to have a better From 8fc9e007ee752a982fe47311702d7ff3b9c5b5cd Mon Sep 17 00:00:00 2001 From: JR Rivers Date: Mon, 24 Sep 2012 17:26:46 +0000 Subject: [PATCH 0129/1342] ospfd: blackhole route removal for area range ISSUE When an area range is created in which there the sub-area has routes that are smaller than the range, an ABR creates a blackhole route to cover the range. When the range is removed, the blackhole route is not removed. --A----B----C--- B is an ABR with A in area 1 and C in area 0. If A advertises `10.2.0.0/30` and `10.2.0.4/30` and B is configured with `area 0.0.0.1 range 10.2.0.0/29` a blackhole is created on B (`blackhole 10.2.0.0/29 proto zebra`). When the area/range is removed via the command line, the blackhole remains in existence even though the "range" route is removed from area 0 and the individual routes are propagated. PATCH The reason for this behavior is that, prior to this patch, the range is deleted from the area's list, so when ospf_abr_manage_discard_routes() gets called, there is nothing to clean up. The patch removes the discard route as part of the processing of the command line (ospf_area_range_unset()). Signed-off-by: JR Rivers Signed-off-by: Scott Feldman Reviewed-by: Shrijeet Mukherjee Signed-off-by: David Lamparter --- ospfd/ospf_abr.c | 36 +++++++++++++++------------------ ospfd/ospf_route.c | 50 +++++++++++++++++++++++++++++++++++++++++++++- ospfd/ospf_route.h | 2 +- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index b7cc20dd8..ef1048b23 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -88,23 +88,18 @@ ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range) } static void -ospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range) +ospf_area_range_delete (struct ospf_area *area, struct route_node *rn) { - struct route_node *rn; - struct prefix_ipv4 p; + struct ospf_area_range *range = rn->info; - p.family = AF_INET; - p.prefixlen = range->masklen; - p.prefix = range->addr; + if (range->specifics != 0) + ospf_delete_discard_route (area->ospf->new_table, + (struct prefix_ipv4 *) &rn->p); - rn = route_node_lookup (area->ranges, (struct prefix *)&p); - if (rn) - { - ospf_area_range_free (rn->info); - rn->info = NULL; - route_unlock_node (rn); - route_unlock_node (rn); - } + ospf_area_range_free (range); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); } struct ospf_area_range * @@ -263,20 +258,20 @@ ospf_area_range_unset (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p) { struct ospf_area *area; - struct ospf_area_range *range; + struct route_node *rn; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; - range = ospf_area_range_lookup (area, p); - if (range == NULL) + rn = route_node_lookup (area->ranges, (struct prefix*)p); + if (rn == NULL) return 0; - if (ospf_area_range_active (range)) + if (ospf_area_range_active (rn->info)) ospf_schedule_abr_task (ospf); - ospf_area_range_delete (area, range); + ospf_area_range_delete (area, rn); return 1; } @@ -1695,7 +1690,8 @@ ospf_abr_manage_discard_routes (struct ospf *ospf) ospf_add_discard_route (ospf->new_table, area, (struct prefix_ipv4 *) &rn->p); else - ospf_delete_discard_route ((struct prefix_ipv4 *) &rn->p); + ospf_delete_discard_route (ospf->new_table, + (struct prefix_ipv4 *) &rn->p); } } diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index a5d6d18c9..c3acba348 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -954,6 +954,10 @@ ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, ospf_route_free (rn->info); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_add_discard_route(): " + "adding %s/%d", inet_ntoa (p->prefix), p->prefixlen); + new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_DISCARD; new_or->id.s_addr = 0; @@ -969,8 +973,52 @@ ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, } void -ospf_delete_discard_route (struct prefix_ipv4 *p) +ospf_delete_discard_route (struct route_table *rt, struct prefix_ipv4 *p) { + struct route_node *rn; + struct ospf_route *or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_delete_discard_route(): " + "deleting %s/%d", inet_ntoa (p->prefix), p->prefixlen); + + rn = route_node_lookup (rt, (struct prefix*)p); + + if (rn == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("ospf_delete_discard_route(): no route found"); + return; + } + + or = rn->info; + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_delete_discard_route(): " + "an intra-area route exists"); + return; + } + + if (or->type != OSPF_DESTINATION_DISCARD) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_delete_discard_route(): " + "not a discard entry"); + return; + } + + /* free the route entry and the route node */ + ospf_route_free (rn->info); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + /* remove the discard entry from the rib */ ospf_zebra_delete_discard(p); + + return; } diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 5742b462c..6c202b0cc 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -159,7 +159,7 @@ extern void ospf_prune_unreachable_networks (struct route_table *); extern void ospf_prune_unreachable_routers (struct route_table *); extern int ospf_add_discard_route (struct route_table *, struct ospf_area *, struct prefix_ipv4 *); -extern void ospf_delete_discard_route (struct prefix_ipv4 *); +extern void ospf_delete_discard_route (struct route_table *, struct prefix_ipv4 *); extern int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *, struct ospf_route *); From 821755530e328182c885c98891af799926bd56bd Mon Sep 17 00:00:00 2001 From: JR Rivers Date: Mon, 24 Sep 2012 17:26:50 +0000 Subject: [PATCH 0130/1342] ospfd: ABR algorithm not propagating MAXAGE LSAs into area When a range (or sub-range) is deleted, the area is notified by propagating a MAXAGE LSA. This LSA stays in the database for a while to both insure propagation as well as in the off chance that it's useful in the near future. Unfortunately, the ABR algorithm was treating these MAXAGE LSAs as unchanged and not propagating them within the areas. Signed-off-by: JR Rivers Signed-off-by: Scott Feldman Reviewed-by: Dinesh Dutt Reviewed-by: Shrijeet Mukherjee Signed-off-by: David Lamparter --- ospfd/ospf_abr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index ef1048b23..2876eaa71 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -729,8 +729,9 @@ ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, zlog_debug ("ospf_abr_announce_network_to_area(): " "old metric: %d, new metric: %d", GET_METRIC (sl->metric), cost); - - if (GET_METRIC (sl->metric) == cost) + + if ((GET_METRIC (sl->metric) == cost) && + ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { /* unchanged. simply reapprove it */ if (IS_DEBUG_OSPF_EVENT) From b4154c145a2d1d0679983130413b81d44fbb04ab Mon Sep 17 00:00:00 2001 From: JR Rivers Date: Mon, 24 Sep 2012 17:26:53 +0000 Subject: [PATCH 0131/1342] ospfd: respect max-metric over configured cost for summary LSAs ISSUE When max-metric router-lsa administrative is invoked on an ABR created with... area range the summary LSAs are sent out with 65535 (max-metric) added to the normal cost. When max-metric router-lsa administrative is invoked on an ABR created with... area range cost the summary LSAs are sent out with (the max-metric is ignored). This second behavior effectively incapacitates the max-metric function. PATCH This patch evaluates the state of the router and if it's isolated as a stub router (rfc3137) via `max-metric router-lsa`, we unconditionally uses the value of 0xff0000 when advertising summary LSAs. Signed-off-by: JR Rivers Signed-off-by: Scott Feldman Reviewed-by: Ayan Banerjee Reviewed-by: Dinesh Dutt Signed-off-by: David Lamparter --- ospfd/ospf_abr.c | 36 ++++++++++++++++++++++++++++-------- ospfd/ospfd.h | 2 ++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 2876eaa71..f5edc99e5 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -566,12 +566,20 @@ ospf_check_abr_status (struct ospf *ospf) static void ospf_abr_update_aggregate (struct ospf_area_range *range, - struct ospf_route *or) + struct ospf_route *or, struct ospf_area *area) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): Start"); - if (range->cost_config != OSPF_AREA_RANGE_COST_UNSPEC) + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED) && + (range->cost != OSPF_STUB_MAX_METRIC_SUMMARY_COST)) + { + range->cost = OSPF_STUB_MAX_METRIC_SUMMARY_COST; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_abr_update_aggregate(): use summary max-metric 0x%08x", + range->cost); + } + else if (range->cost_config != OSPF_AREA_RANGE_COST_UNSPEC) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use configured cost %d", @@ -582,12 +590,18 @@ ospf_abr_update_aggregate (struct ospf_area_range *range, else { if (range->specifics == 0) - range->cost = or->cost; /* 1st time get 1st cost */ + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_abr_update_aggregate(): use or->cost %d", + or->cost); + + range->cost = or->cost; /* 1st time get 1st cost */ + } if (or->cost > range->cost) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_abr_update_aggregate(): largest cost, update"); + zlog_debug ("ospf_abr_update_aggregate(): update to %d", or->cost); range->cost = or->cost; } @@ -711,10 +725,16 @@ ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, { struct ospf_lsa *lsa, *old = NULL; struct summary_lsa *sl = NULL; + u_int32_t full_cost; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): Start"); + if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) + full_cost = OSPF_STUB_MAX_METRIC_SUMMARY_COST; + else + full_cost = cost; + old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_SUMMARY_LSA, (struct prefix_ipv4 *) p, area->ospf->router_id); @@ -730,7 +750,7 @@ ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, "old metric: %d, new metric: %d", GET_METRIC (sl->metric), cost); - if ((GET_METRIC (sl->metric) == cost) && + if ((GET_METRIC (sl->metric) == full_cost) && ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { /* unchanged. simply reapprove it */ @@ -745,7 +765,7 @@ ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "refreshing summary"); - set_metric (old, cost); + set_metric (old, full_cost); lsa = ospf_lsa_refresh (area->ospf, old); if (!lsa) @@ -769,7 +789,7 @@ ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "creating new summary"); - lsa = ospf_summary_lsa_originate ( (struct prefix_ipv4 *)p, cost, area); + lsa = ospf_summary_lsa_originate ( (struct prefix_ipv4 *)p, full_cost, area); /* This will flood through area. */ if (!lsa) @@ -930,7 +950,7 @@ ospf_abr_announce_network (struct ospf *ospf, inet_ntoa (p->prefix), p->prefixlen); if ((range = ospf_area_range_match (or_area, p)) && !ospf_area_is_transit (area)) - ospf_abr_update_aggregate (range, or); + ospf_abr_update_aggregate (range, or, area); else ospf_abr_announce_network_to_area (p, or->cost, area); } diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 7a56d163f..bf825d177 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -196,6 +196,8 @@ struct ospf unsigned int stub_router_shutdown_time; /* seconds */ #define OSPF_STUB_ROUTER_UNCONFIGURED 0 +#define OSPF_STUB_MAX_METRIC_SUMMARY_COST 0x00ff0000 + /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ From 4effc29fb1c33a87a8d386de39c20d36a6956645 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Sat, 5 May 2012 17:42:43 -0700 Subject: [PATCH 0132/1342] lib: improve sanity checks in stream_set_endp() * lib/stream.c: (stream_set_endp) Add checks to make sure that the supplied 'endp' is within the 'size' of the stream, and that the current read pointer 'getp' is not beyond the specified 'endp'. --- lib/stream.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/stream.c b/lib/stream.c index b226a25ea..ee2920e64 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -219,13 +219,23 @@ stream_set_endp (struct stream *s, size_t pos) { STREAM_VERIFY_SANE(s); - if (!GETP_VALID (s, pos)) + if (!ENDP_VALID(s, pos)) { STREAM_BOUND_WARN (s, "set endp"); - pos = s->endp; + return; + } + + /* + * Make sure the current read pointer is not beyond the new endp. + */ + if (s->getp > pos) + { + STREAM_BOUND_WARN(s, "set endp"); + return; } s->endp = pos; + STREAM_VERIFY_SANE(s); } /* Forward pointer. */ From a22ab5a560c7a46f6ecc6feb874c0dbbde9699c6 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Sat, 5 May 2012 23:50:30 -0700 Subject: [PATCH 0133/1342] isisd: tighten checks on ISIS pdu length * isisd/isis_pdu.c: Fix problem where isisd would crash if it received a LAN IIH with the 'pdu length' field set to zero. Similar problems can occur in parsing other ISIS PDUs as well -- check that the PDU length in an ISIS hello, LSP or SNP packet is at least as big as the size of the respective fixed header. --- isisd/isis_pdu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 497fad20f..7375a3ebf 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -442,7 +442,8 @@ process_p2p_hello (struct isis_circuit *circuit) hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); pdu_len = ntohs (hdr->pdu_len); - if (pdu_len > ISO_MTU(circuit) || + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) || + pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " @@ -909,7 +910,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) hdr.prio = stream_getc (circuit->rcv_stream); stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - if (hdr.pdu_len > ISO_MTU(circuit) || + if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) || + hdr.pdu_len > ISO_MTU(circuit) || hdr.pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " @@ -1202,7 +1204,7 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) pdu_len = ntohs (hdr->pdu_len); /* lsp length check */ - if (pdu_len < ISIS_LSP_HDR_LEN || + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { @@ -1545,7 +1547,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); pdu_len = ntohs (chdr->pdu_len); - if (pdu_len < ISIS_CSNP_HDRLEN || + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { @@ -1560,7 +1562,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); pdu_len = ntohs (phdr->pdu_len); - if (pdu_len < ISIS_PSNP_HDRLEN || + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { From 0fece074e8c9e282ae2cecf9a0a79dc6c930cfb1 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Sun, 6 May 2012 00:03:07 -0700 Subject: [PATCH 0134/1342] isisd: fix null pointer dereference in send_lsp() * isisd/isis_pdu.c: (send_lsp) Handle case where there are no LSPs on the LSP transmission queue. This can happen if, for instance, the queue is cleared because of protocol events before the send_lsp thread gets a chance to run. --- isisd/isis_pdu.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 7375a3ebf..ffc67178b 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -3033,7 +3033,19 @@ send_lsp (struct thread *thread) return retval; } - lsp = listgetdata ((node = listhead (circuit->lsp_queue))); + node = listhead (circuit->lsp_queue); + + /* + * Handle case where there are no LSPs on the queue. This can + * happen, for instance, if an adjacency goes down before this + * thread gets a chance to run. + */ + if (!node) + { + return retval; + } + + lsp = listgetdata(node); /* * Do not send if levels do not match From 948b6bef7f9cf841a98fe3ea40419696500c8c4c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 8 May 2012 06:27:04 +0200 Subject: [PATCH 0135/1342] isisd: pull up invalid prefix assert() processing invalid prefixes causes isisd to assert() or otherwise misbehave in ip_masklen/apply_mask. pull up the assert() to indicate better there's broken data in isisd's LSDB. * isisd/isis_spf.c: assert() prefix lengths Signed-off-by: David Lamparter --- isisd/isis_spf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 198104a98..eff7c4761 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -813,6 +813,8 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, node, te_ipv4_reach)) { + assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN); + dist = cost + ntohl (te_ipv4_reach->te_metric); vtype = VTYPE_IPREACH_TE; prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, @@ -829,6 +831,8 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach)) { + assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN); + dist = cost + ip6reach->metric; vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; From f02a09925db53d3e1d29b1917ebbcaa8edf72c12 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 8 May 2012 13:15:45 +0200 Subject: [PATCH 0136/1342] isisd: don't process invalid prefixes from TLVs it's possible to feed invalid prefixes (1.2.3.4/40 or dead::beef/200) on IS-IS. if this is not checked, it will later cause an assert in processing. let's simply abort processing the TLV if the prefix is invalid. * isisd/isis_tlv.c: check prefix lengths for validity Signed-off-by: David Lamparter --- isisd/isis_tlv.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index bb57bd6be..f3b2c338f 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -117,7 +117,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, #endif /* HAVE_IPV6 */ u_char virtual; int value_len, retval = ISIS_OK; - u_char *start = stream, *pnt = stream; + u_char *start = stream, *pnt = stream, *endpnt; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); @@ -584,11 +584,20 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ + endpnt = pnt + length; if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) { while (length > value_len) { te_ipv4_reach = (struct te_ipv4_reachability *) pnt; + if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN) + { + zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach" + "ability prefix length %d", areatag, + te_ipv4_reach->control & 0x3F); + retval = ISIS_WARNING; + break; + } if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new (); listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach); @@ -600,10 +609,8 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); } } - else - { - pnt += length; - } + + pnt = endpnt; break; #ifdef HAVE_IPV6 @@ -648,11 +655,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, * +---------------------------------------------------------------+ */ *found |= TLVFLAG_IPV6_REACHABILITY; + endpnt = pnt + length; + if (*expected & TLVFLAG_IPV6_REACHABILITY) { while (length > value_len) { ipv6_reach = (struct ipv6_reachability *) pnt; + if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN) + { + zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach" + "ability prefix length %d", areatag, + ipv6_reach->prefix_len); + retval = ISIS_WARNING; + break; + } + prefix_octets = ((ipv6_reach->prefix_len + 7) / 8); value_len += prefix_octets + 6; pnt += prefix_octets + 6; @@ -662,10 +680,8 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, listnode_add (tlvs->ipv6_reachs, ipv6_reach); } } - else - { - pnt += length; - } + + pnt = endpnt; break; #endif /* HAVE_IPV6 */ From 80a21dc60fa007bb00437fdc047c3e059232639f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 8 May 2012 13:32:12 +0200 Subject: [PATCH 0137/1342] lib: add array_size() helper implement array_size as sizeof(array) / sizeof(array element) Signed-off-by: David Lamparter --- lib/memory.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/memory.h b/lib/memory.h index a7eddce4e..23962235d 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _ZEBRA_MEMORY_H #define _ZEBRA_MEMORY_H +#define array_size(ar) (sizeof(ar) / sizeof(ar[0])) + /* For pretty printing of memory allocate information. */ struct memory_list { From 655071f44aab42e89bcece3a93da456fdd0d913a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 8 May 2012 13:32:53 +0200 Subject: [PATCH 0138/1342] isisd: don't overrun list of protocols isisd currently has a list of supported protocols as a fixed array of size 4. this can be overran, leading to an overwrite of the ipv4_addrs pointer. * isisd/isis_pdu.c: don't accept more protocols than there's space for Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index ffc67178b..bfa1e4e93 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -311,7 +311,7 @@ tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) } } -static void +static int tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) { int i; @@ -321,6 +321,8 @@ tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) { tlv_nlpids = tlvs->nlpids; + if (tlv_nlpids->count > array_size (adj->nlpids.nlpids)) + return 1; adj->nlpids.count = tlv_nlpids->count; @@ -329,6 +331,7 @@ tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; } } + return 0; } static void @@ -548,7 +551,8 @@ process_p2p_hello (struct isis_circuit *circuit) /* which protocol are spoken ??? */ if (found & TLVFLAG_NLPID) - tlvs_to_adj_nlpids (&tlvs, adj); + if (tlvs_to_adj_nlpids (&tlvs, adj)) + return ISIS_ERROR; /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) From 837d16ccbe0fca413f8927da6a34b1e97ccada8a Mon Sep 17 00:00:00 2001 From: "Balaji.G" Date: Wed, 26 Sep 2012 14:09:10 +0530 Subject: [PATCH 0139/1342] *: use array_size() helper macro Use the array_size() helper macro. Replaces several instances of local macros with the same definition. Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- babeld/babel_main.c | 2 +- bgpd/bgp_attr.c | 5 ++--- bgpd/bgp_main.c | 4 ++-- bgpd/bgp_open.c | 8 +++----- isisd/isis_main.c | 2 +- lib/buffer.c | 2 +- lib/log.c | 24 ++++++++++-------------- lib/sigevent.c | 9 +++++---- lib/sigevent.h | 1 - ospf6d/ospf6_main.c | 2 +- ospf6d/ospf6_message.c | 3 +-- ospfd/ospf_api.c | 4 ++-- ospfd/ospf_main.c | 4 ++-- ripd/rip_main.c | 2 +- ripngd/ripng_main.c | 2 +- tests/test-sig.c | 2 +- vtysh/vtysh.c | 21 ++++++++++----------- watchquagga/watchquagga.c | 3 ++- zebra/main.c | 4 ++-- zebra/rt_netlink.c | 2 +- zebra/test_main.c | 2 +- zebra/zebra_rib.c | 2 +- 22 files changed, 51 insertions(+), 59 deletions(-) diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 2f3b5552e..7b1d87996 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -444,7 +444,7 @@ babel_init_signals(void) }, }; - signal_init (master, Q_SIGC(babel_signals), babel_signals); + signal_init (master, array_size(babel_signals), babel_signals); } static void diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2d82acc22..cdc99ab3a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -62,7 +62,7 @@ static const struct message attr_str [] = { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, }; -static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); +static const int attr_str_max = array_size(attr_str); static const struct message attr_flag_str[] = { @@ -72,8 +72,7 @@ static const struct message attr_flag_str[] = /* bgp_attr_flags_diagnose() relies on this bit being last in this list */ { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, }; -static const size_t attr_flag_str_max = - sizeof (attr_flag_str) / sizeof (attr_flag_str[0]); +static const size_t attr_flag_str_max = array_size(attr_flag_str); static struct hash *cluster_hash; diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 0f1d4829c..1ff1ac952 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -135,7 +135,7 @@ struct zebra_privs_t bgpd_privs = .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_p = array_size(_caps_p), .cap_num_i = 0, }; @@ -422,7 +422,7 @@ main (int argc, char **argv) /* Initializations. */ srand (time (NULL)); - signal_init (master, Q_SIGC(bgp_signals), bgp_signals); + signal_init (master, array_size(bgp_signals), bgp_signals); zprivs_init (&bgpd_privs); cmd_init (1); vty_init (master); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 0326d01bc..d045dde54 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -187,8 +187,7 @@ static const struct message orf_type_str[] = { ORF_TYPE_PREFIX, "Prefixlist" }, { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" }, }; -static const int orf_type_str_max - = sizeof(orf_type_str)/sizeof(orf_type_str[0]); +static const int orf_type_str_max = array_size(orf_type_str); static const struct message orf_mode_str[] = { @@ -196,8 +195,7 @@ static const struct message orf_mode_str[] = { ORF_MODE_SEND, "Send" }, { ORF_MODE_BOTH, "Both" }, }; -static const int orf_mode_str_max - = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]); +static const int orf_mode_str_max = array_size(orf_mode_str); static int bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) @@ -449,7 +447,7 @@ static const struct message capcode_str[] = { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" }, { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" }, }; -static const int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]); +static const int capcode_str_max = array_size(capcode_str); /* Minimum sizes for length field of each cap (so not inc. the header) */ static const size_t cap_minsizes[] = diff --git a/isisd/isis_main.c b/isisd/isis_main.c index f5266aa22..dcbc3de96 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -325,7 +325,7 @@ main (int argc, char **argv, char **envp) * initializations */ zprivs_init (&isisd_privs); - signal_init (master, Q_SIGC (isisd_signals), isisd_signals); + signal_init (master, array_size (isisd_signals), isisd_signals); cmd_init (1); vty_init (master); memory_init (); diff --git a/lib/buffer.c b/lib/buffer.c index f19a9e0c8..45e2e1c50 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -262,7 +262,7 @@ buffer_flush_window (struct buffer *b, int fd, int width, int height, /* For erase and more data add two to b's buffer_data count.*/ if (b->head->next == NULL) { - iov_alloc = sizeof(small_iov)/sizeof(small_iov[0]); + iov_alloc = array_size(small_iov); iov = small_iov; } else diff --git a/lib/log.c b/lib/log.c index cbc935b65..e4ec7c228 100644 --- a/lib/log.c +++ b/lib/log.c @@ -443,8 +443,8 @@ zlog_backtrace_sigsafe(int priority, void *program_counter) #define LOC s,buf+sizeof(buf)-s #ifdef HAVE_GLIBC_BACKTRACE - if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) || - ((size_t)size > sizeof(array)/sizeof(array[0]))) + if (((size = backtrace(array,array_size(array)) <= 0) || + ((size_t)size > array_size(array)))) return; #define DUMP(FD) { \ @@ -526,12 +526,12 @@ zlog_backtrace(int priority) int size, i; char **strings; - if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) || - ((size_t)size > sizeof(array)/sizeof(array[0]))) + if (((size = backtrace(array,array_size(array))) <= 0) || + ((size_t)size > array_size(array))) { zlog_err("Cannot get backtrace, returned invalid # of frames %d " "(valid range is between 1 and %lu)", - size, (unsigned long)(sizeof(array)/sizeof(array[0]))); + size, (unsigned long)(array_size(array))); return; } zlog(NULL, priority, "Backtrace for %d stack frames:", size); @@ -636,7 +636,7 @@ openzlog (const char *progname, zlog_proto_t protocol, zl->syslog_options = syslog_flags; /* Set default logging levels. */ - for (i = 0; i < sizeof(zl->maxlvl)/sizeof(zl->maxlvl[0]); i++) + for (i = 0; i < array_size(zl->maxlvl); i++) zl->maxlvl[i] = ZLOG_DISABLED; zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG; zl->default_lvl = LOG_DEBUG; @@ -855,14 +855,14 @@ zroute_lookup(u_int zroute) { u_int i; - if (zroute >= sizeof(route_types)/sizeof(route_types[0])) + if (zroute >= array_size(route_types)) { zlog_err("unknown zebra route type: %u", zroute); return &unknown; } if (zroute == route_types[zroute].type) return &route_types[zroute]; - for (i = 0; i < sizeof(route_types)/sizeof(route_types[0]); i++) + for (i = 0; i < array_size(route_types); i++) { if (zroute == route_types[i].type) { @@ -890,7 +890,7 @@ zebra_route_char(u_int zroute) const char * zserv_command_string (unsigned int command) { - if (command >= sizeof(command_types)/sizeof(command_types[0])) + if (command >= array_size(command_types)) { zlog_err ("unknown zserv command type: %u", command); return unknown.string; @@ -898,21 +898,17 @@ zserv_command_string (unsigned int command) return command_types[command].string; } -#define RTSIZE (sizeof(route_types)/sizeof(route_types[0])) - int proto_name2num(const char *s) { unsigned i; - for (i=0; i #include #include +#include #ifdef SA_SIGINFO #ifdef HAVE_UCONTEXT_H @@ -266,13 +267,13 @@ trap_default_signals(void) #endif ); } sigmap[] = { - { core_signals, sizeof(core_signals)/sizeof(core_signals[0]), core_handler}, - { exit_signals, sizeof(exit_signals)/sizeof(exit_signals[0]), exit_handler}, - { ignore_signals, sizeof(ignore_signals)/sizeof(ignore_signals[0]), NULL}, + { core_signals, array_size(core_signals), core_handler}, + { exit_signals, array_size(exit_signals), exit_handler}, + { ignore_signals, array_size(ignore_signals), NULL}, }; u_int i; - for (i = 0; i < sizeof(sigmap)/sizeof(sigmap[0]); i++) + for (i = 0; i < array_size(sigmap); i++) { u_int j; diff --git a/lib/sigevent.h b/lib/sigevent.h index 62b944a7c..248fa2c05 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -27,7 +27,6 @@ #include #define QUAGGA_SIGNAL_TIMER_INTERVAL 2L -#define Q_SIGC(sig) (sizeof(sig)/sizeof(sig[0])) struct quagga_signal_t { diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index d3ef0a6a8..1bdf52fb4 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -308,7 +308,7 @@ main (int argc, char *argv[], char *envp[]) LOG_DAEMON); zprivs_init (&ospf6d_privs); /* initialize zebra libraries */ - signal_init (master, Q_SIGC(ospf6_signals), ospf6_signals); + signal_init (master, array_size(ospf6_signals), ospf6_signals); cmd_init (1); vty_init (master); memory_init (); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 01d61263e..5edb70ce6 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -58,8 +58,7 @@ static const struct message ospf6_message_type_str [] = { OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate" }, { OSPF6_MESSAGE_TYPE_LSACK, "LSAck" }, }; -static const size_t ospf6_message_type_str_max = - sizeof (ospf6_message_type_str) / sizeof (ospf6_message_type_str[0]); +static const size_t ospf6_message_type_str_max = array_size(ospf6_message_type_str); /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index fc3b51ddf..74a49e3be 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -155,7 +155,7 @@ ospf_api_typename (int msgtype) { MSG_NSM_CHANGE, "NSM change", }, }; - int i, n = sizeof (NameTab) / sizeof (NameTab[0]); + int i, n = array_size(NameTab); const char *name = NULL; for (i = 0; i < n; i++) @@ -187,7 +187,7 @@ ospf_api_errname (int errcode) { OSPF_API_UNDEF, "Undefined", }, }; - int i, n = sizeof (NameTab) / sizeof (NameTab[0]); + int i, n = array_size(NameTab); const char *name = NULL; for (i = 0; i < n; i++) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index bad674b6a..1448c7d8e 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -68,7 +68,7 @@ struct zebra_privs_t ospfd_privs = .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_p = array_size(_caps_p), .cap_num_i = 0 }; @@ -285,7 +285,7 @@ main (int argc, char **argv) /* Library inits. */ zprivs_init (&ospfd_privs); - signal_init (master, Q_SIGC(ospf_signals), ospf_signals); + signal_init (master, array_size(ospf_signals), ospf_signals); cmd_init (1); debug_init (); vty_init (master); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index ccb5fa012..6a9fa71da 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -275,7 +275,7 @@ main (int argc, char **argv) /* Library initialization. */ zprivs_init (&ripd_privs); - signal_init (master, Q_SIGC(ripd_signals), ripd_signals); + signal_init (master, array_size(ripd_signals), ripd_signals); cmd_init (1); vty_init (master); memory_init (); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index f4a62440a..20225b7d5 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -272,7 +272,7 @@ main (int argc, char **argv) /* Library inits. */ zprivs_init (&ripngd_privs); - signal_init (master, Q_SIGC(ripng_signals), ripng_signals); + signal_init (master, array_size(ripng_signals), ripng_signals); cmd_init (1); vty_init (master); memory_init (); diff --git a/tests/test-sig.c b/tests/test-sig.c index 63aab6f0b..fe428dea9 100644 --- a/tests/test-sig.c +++ b/tests/test-sig.c @@ -43,7 +43,7 @@ int main (void) { master = thread_master_create (); - signal_init (master, Q_SIGC(sigs), sigs); + signal_init (master, array_size(sigs), sigs); zlog_default = openzlog("testsig", ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 431c08e22..e3709e07e 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -61,7 +61,6 @@ struct vtysh_client { .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH}, }; -#define VTYSH_INDEX_MAX (sizeof(vtysh_client)/sizeof(vtysh_client[0])) /* We need direct access to ripd to implement vtysh_exit_ripd_only. */ static struct vtysh_client *ripd_client = NULL; @@ -374,7 +373,7 @@ vtysh_execute_func (const char *line, int pager) if (! strcmp(cmd->string,"configure terminal")) { - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) { cmd_stat = vtysh_client_execute(&vtysh_client[i], line, fp); if (cmd_stat == CMD_WARNING) @@ -413,7 +412,7 @@ vtysh_execute_func (const char *line, int pager) } cmd_stat = CMD_SUCCESS; - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) { if (cmd->daemon & vtysh_client[i].flag) { @@ -525,7 +524,7 @@ vtysh_config_from_file (struct vty *vty, FILE *fp) u_int i; int cmd_stat = CMD_SUCCESS; - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) { if (cmd->daemon & vtysh_client[i].flag) { @@ -1354,7 +1353,7 @@ DEFUN (vtysh_show_memory, int ret = CMD_SUCCESS; char line[] = "show memory\n"; - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { fprintf (stdout, "Memory statistics for %s:\n", @@ -1377,7 +1376,7 @@ DEFUN (vtysh_show_logging, int ret = CMD_SUCCESS; char line[] = "show logging\n"; - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { fprintf (stdout,"Logging configuration for %s:\n", @@ -1733,7 +1732,7 @@ DEFUN (vtysh_write_terminal, VTY_NEWLINE); vty_out (vty, "!%s", VTY_NEWLINE); - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) ret = vtysh_client_config (&vtysh_client[i], line); /* Integrate vtysh specific configuration. */ @@ -1807,7 +1806,7 @@ write_config_integrated(void) return CMD_SUCCESS; } - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) ret = vtysh_client_config (&vtysh_client[i], line); vtysh_config_dump (fp); @@ -1844,7 +1843,7 @@ DEFUN (vtysh_write_memory, fprintf (stdout,"Building Configuration...\n"); - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"[OK]\n"); @@ -1934,7 +1933,7 @@ DEFUN (vtysh_show_daemons, { u_int i; - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) vty_out(vty, " %s", vtysh_client[i].name); vty_out(vty, "%s", VTY_NEWLINE); @@ -2184,7 +2183,7 @@ vtysh_connect_all(const char *daemon_name) int rc = 0; int matches = 0; - for (i = 0; i < VTYSH_INDEX_MAX; i++) + for (i = 0; i < array_size(vtysh_client); i++) { if (!daemon_name || !strcmp(daemon_name, vtysh_client[i].name)) { diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index b57fd3ae0..c1c889210 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifndef MIN #define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y)) @@ -1279,7 +1280,7 @@ main(int argc, char **argv) gs.restart.interval = gs.min_restart_interval; master = thread_master_create(); - signal_init (master, Q_SIGC(my_signals), my_signals); + signal_init (master, array_size(my_signals), my_signals); srandom(time(NULL)); { diff --git a/zebra/main.c b/zebra/main.c index 5b5265f27..50ac224e2 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -104,7 +104,7 @@ struct zebra_privs_t zserv_privs = .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_p = array_size(_caps_p), .cap_num_i = 0 }; @@ -313,7 +313,7 @@ main (int argc, char **argv) zprivs_init (&zserv_privs); /* Vty related initialize. */ - signal_init (zebrad.master, Q_SIGC(zebra_signals), zebra_signals); + signal_init (zebrad.master, array_size(zebra_signals), zebra_signals); cmd_init (1); vty_init (zebrad.master); memory_init (); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 15475e205..ab28ad271 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1985,7 +1985,7 @@ static void netlink_install_filter (int sock, __u32 pid) }; struct sock_fprog prog = { - .len = sizeof(filter) / sizeof(filter[0]), + .len = array_size(filter), .filter = filter, }; diff --git a/zebra/test_main.c b/zebra/test_main.c index 70a1a3a65..a9518637d 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -280,7 +280,7 @@ main (int argc, char **argv) zebrad.master = thread_master_create (); /* Vty related initialize. */ - signal_init (zebrad.master, Q_SIGC(zebra_signals), zebra_signals); + signal_init (zebrad.master, array_size(zebra_signals), zebra_signals); cmd_init (1); vty_init (zebrad.master); memory_init (); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b8a47031f..0e29e616a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1546,7 +1546,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Set default distance by route type. */ if (distance == 0) { - if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0])) + if ((unsigned)type >= array_size(route_info)) distance = 150; else distance = route_info[type].distance; From 3f0bfc9e82e0d735be2cb06d5c4a3028650637bf Mon Sep 17 00:00:00 2001 From: Doug VanLeuven Date: Wed, 26 Sep 2012 12:01:23 +0000 Subject: [PATCH 0140/1342] lib: treat OSX as BSD for IP_HDRINCL (BZ#739) Mac OS X needs HAVE_IP_HDRINCL_BSD_ORDER defined like BSD. If it's not defined, it'll fail like this: *** sendmsg in ospf_write failed to 224.0.0.5, id 0, off 0, len 64, interface en0, mtu 1500: Invalid argument Which is caused by reordering iph->ip_len in sockopt_iphdrincl_swab_htosys. Signed-off-by: David Lamparter --- lib/zebra.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/zebra.h b/lib/zebra.h index ab072d6e5..f8a6be306 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -357,6 +357,7 @@ struct in_pktinfo */ #if defined(__NetBSD__) || defined(__FreeBSD__) \ || (defined(__OpenBSD__) && (OpenBSD < 200311)) \ + || (defined(__APPLE__)) \ || (defined(SUNOS_5) && defined(WORDS_BIGENDIAN)) #define HAVE_IP_HDRINCL_BSD_ORDER #endif From b07458a055493dd37cb955ae90f11ae8bc334d3a Mon Sep 17 00:00:00 2001 From: Daniel Kozlowski Date: Wed, 26 Sep 2012 12:01:24 +0000 Subject: [PATCH 0141/1342] bgpd: flock() dump files (BZ#742) flock()ing the BGP dump files helps consumers determine when they're safe to read. Signed-off-by: David Lamparter --- bgpd/bgp_dump.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index edb725a97..775486012 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -95,6 +95,7 @@ static FILE * bgp_dump_open_file (struct bgp_dump *bgp_dump) { int ret; + int fd; time_t clock; struct tm *tm; char fullpath[MAXPATHLEN]; @@ -131,6 +132,16 @@ bgp_dump_open_file (struct bgp_dump *bgp_dump) umask(oldumask); return NULL; } + else + { + fd = fileno(bgp_dump->fp); + ret = flock( fd, LOCK_EX ); + if (ret != 0) + { + zlog_warn ("bgp_dump_open_file: Unable to flock() file %s: %s", realpath, strerror (errno)); + } + } + umask(oldumask); return bgp_dump->fp; @@ -195,6 +206,7 @@ bgp_dump_set_size (struct stream *s, int type) static void bgp_dump_routes_index_table(struct bgp *bgp) { + int ret; struct peer *peer; struct listnode *node; uint16_t peerno = 0; @@ -266,7 +278,11 @@ bgp_dump_routes_index_table(struct bgp *bgp) bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); - fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); + ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); + if (ret != 1) + { + zlog_warn ("bgp_dump_routes_index_table: fwrite returned %d, expected 1: %s", ret, strerror (errno)); + } fflush (bgp_dump_routes.fp); } @@ -275,6 +291,7 @@ bgp_dump_routes_index_table(struct bgp *bgp) static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { + int ret; struct stream *obuf; struct bgp_info *info; struct bgp_node *rn; @@ -373,8 +390,11 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq) seq++; bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); - fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); - + ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); + if (ret != 1) + { + zlog_warn ("bgp_dump_routes_func: fwrite returned %d, expected 1: %s", ret, strerror (errno)); + } } fflush (bgp_dump_routes.fp); @@ -464,6 +484,7 @@ bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4) void bgp_dump_state (struct peer *peer, int status_old, int status_new) { + int ret; struct stream *obuf; /* If dump file pointer is disabled return immediately. */ @@ -484,7 +505,11 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new) bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); /* Write to the stream. */ - fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp); + ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp); + if (ret != 1) + { + zlog_warn ("bgp_dump_state: fwrite returned %d, expected 1: %s", ret, strerror (errno)); + } fflush (bgp_dump_all.fp); } @@ -492,6 +517,7 @@ static void bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, struct stream *packet) { + int ret; struct stream *obuf; /* If dump file pointer is disabled return immediately. */ @@ -520,7 +546,11 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); /* Write to the stream. */ - fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp); + ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp); + if (ret != 1) + { + zlog_warn ("bgp_dump_packet_func: fwrite returned %d, expected 1: %s", ret, strerror (errno)); + } fflush (bgp_dump->fp); } From d1d3ac9bad0caf7a9c465bb382b924009f0d9168 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Thu, 4 Oct 2012 16:21:34 +0000 Subject: [PATCH 0142/1342] build: reorder libraries to address linker error The linker on some systems (for example, Ubuntu 12.04 LTS x86_64) appears to be sensitive to the order in which libraries are specified. On these systems, if a library 'A' depends on a library 'B', it has to be specified before 'B' when linking an executable. * zebra/Makefile.am: Make sure LIBCAP comes after libzebra. * tests/Makefile.am: Ensure libm comes after libbgp. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- tests/Makefile.am | 10 +++++----- zebra/Makefile.am | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index e510a1588..cd6b2f1b4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -32,10 +32,10 @@ teststream_LDADD = ../lib/libzebra.la @LIBCAP@ heavy_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm -aspathtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a -testbgpcap_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a -ecommtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a -testbgpmpattr_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a +aspathtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm +testbgpcap_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm +ecommtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm +testbgpmpattr_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ -testbgpmpath_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a +testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 9ac90f8ed..ea962bf4e 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -39,9 +39,9 @@ noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h -zebra_LDADD = $(otherobj) $(LIBCAP) $(LIB_IPV6) ../lib/libzebra.la +zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) -testzebra_LDADD = $(LIBCAP) $(LIB_IPV6) ../lib/libzebra.la +testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) zebra_DEPENDENCIES = $(otherobj) From fe9bb6459afe0d55e56619cdc5061d8407cd1f15 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Thu, 19 Apr 2012 20:34:13 +0400 Subject: [PATCH 0143/1342] bgpd: CVE-2012-1820, DoS in bgp_capability_orf() An ORF (code 3) capability TLV is defined to contain exactly one AFI/SAFI block. Function bgp_capability_orf(), which parses ORF capability TLV, uses do-while cycle to call its helper function bgp_capability_orf_entry(), which actually processes the AFI/SAFI data block. The call is made at least once and repeated as long as the input buffer has enough data for the next call. The helper function, bgp_capability_orf_entry(), uses "Number of ORFs" field of the provided AFI/SAFI block to verify, if it fits the input buffer. However, the check is made based on the total length of the ORF TLV regardless of the data already consumed by the previous helper function call(s). This way, the check condition is only valid for the first AFI/SAFI block inside an ORF capability TLV. For the subsequent calls of the helper function, if any are made, the check condition may erroneously tell, that the current "Number of ORFs" field fits the buffer boundary, where in fact it does not. This makes it possible to trigger an assertion by feeding an OPEN message with a specially-crafted malformed ORF capability TLV. This commit fixes the vulnerability by making the implementation follow the spec. --- bgpd/bgp_open.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index d045dde54..af711cc8c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -230,7 +230,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) } /* validate number field */ - if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) + if (sizeof (struct capability_orf_entry) + (entry.num * 2) != hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", @@ -333,28 +333,6 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) return 0; } -static int -bgp_capability_orf (struct peer *peer, struct capability_header *hdr) -{ - struct stream *s = BGP_INPUT (peer); - size_t end = stream_get_getp (s) + hdr->length; - - assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end); - - /* We must have at least one ORF entry, as the caller has already done - * minimum length validation for the capability code - for ORF there must - * at least one ORF entry (header and unknown number of pairs of bytes). - */ - do - { - if (bgp_capability_orf_entry (peer, hdr) == -1) - return -1; - } - while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end); - - return 0; -} - static int bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { @@ -573,7 +551,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, break; case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: - if (bgp_capability_orf (peer, &caphdr)) + if (bgp_capability_orf_entry (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_RESTART: From 326fe3df2c659d62fc76f8579a414ba271e7f3e9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 3 Nov 2012 09:13:23 -0700 Subject: [PATCH 0144/1342] tests: fix missing array_size() include * tests/test-sig.c: add #include "lib/memory.h" to get array_size() Signed-off-by: David Lamparter --- tests/test-sig.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-sig.c b/tests/test-sig.c index fe428dea9..df023fac6 100644 --- a/tests/test-sig.c +++ b/tests/test-sig.c @@ -1,6 +1,7 @@ #include #include #include "lib/log.h" +#include "lib/memory.h" void sighup (void) From e2b1580cbc450b55491efd2cf03c967e53e63f5f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 3 Nov 2012 09:14:29 -0700 Subject: [PATCH 0145/1342] build: compile tests/ by default Broke the tests again... let's just build them by default so it's easier to notice. If anyone doesn't want to build tests, there's --disable-tests. NB: tests will be neither run nor installed. Signed-off-by: David Lamparter --- Makefile.am | 2 +- configure.ac | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 19a90227d..8371041ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \ @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ - redhat @SOLARIS@ + redhat @SOLARIS@ @BUILD_TESTS@ DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ diff --git a/configure.ac b/configure.ac index 4cc940061..dcca9682c 100755 --- a/configure.ac +++ b/configure.ac @@ -198,6 +198,8 @@ AC_ARG_ENABLE(ipv6, [ --disable-ipv6 turn off IPv6 related features and daemons]) AC_ARG_ENABLE(doc, [ --disable-doc do not build docs]) +AC_ARG_ENABLE(tests, +[ --disable-tests do not build tests]) AC_ARG_ENABLE(zebra, [ --disable-zebra do not build zebra daemon]) AC_ARG_ENABLE(bgpd, @@ -1232,6 +1234,13 @@ else DOC="doc" fi +dnl can't use TESTS as name, that's special with automake +if test "${enable_tests}" = "no";then + BUILD_TESTS="" +else + BUILD_TESTS="tests" +fi + dnl -------------------- dnl Daemon disable check dnl -------------------- @@ -1325,6 +1334,7 @@ else fi AC_SUBST(DOC) +AC_SUBST(BUILD_TESTS) AC_SUBST(ZEBRA) AC_SUBST(BGPD) AC_SUBST(RIPD) From 7d50ad444ffadd4110152113cc9583db96b3ad67 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 3 Nov 2012 11:19:52 -0700 Subject: [PATCH 0146/1342] doc: update installation instructions configure parameters have changed quite a bit, several options are enabled by default now and there's --disable-tests. Update documentation to match. Signed-off-by: David Lamparter --- doc/install.texi | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/install.texi b/doc/install.texi index 16e29c99e..1cc655742 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -79,21 +79,27 @@ file does not match to the current running kernel, configure script will not turn on netlink support. @item --enable-snmp Enable SNMP support. By default, SNMP support is disabled. -@item --enable-opaque-lsa -Enable support for Opaque LSAs (RFC2370) in ospfd. +@item --disable-opaque-lsa +Disable support for Opaque LSAs (RFC2370) in ospfd. @item --disable-ospfapi Disable support for OSPF-API, an API to interface directly with ospfd. OSPF-API is enabled if --enable-opaque-lsa is set. @item --disable-ospfclient Disable building of the example OSPF-API client. -@item --enable-ospf-te -Enable support for OSPF Traffic Engineering Extension (internet-draft) this +@item --disable-ospf-te +Disable support for OSPF Traffic Engineering Extension (internet-draft) this requires support for Opaque LSAs. @item --enable-multipath=@var{ARG} Enable support for Equal Cost Multipath. @var{ARG} is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. -@item --enable-rtadv -Enable support IPV6 router advertisement in zebra. +@item --disable-rtadv +Disable support IPV6 router advertisement in zebra. +@item --disable-tests +Do not build tests. Test programs are built by default, but not ran or +installed. They can be excluded from build with this option, which will +minimally decrease compile time and overhead. They can always be built and +executed at a later time by running @command{make check} in the @file{tests/} +subdirectory, even if they're excluded from build. @end table You may specify any combination of the above options to the configure From 3b33de676ac8e84b82f40520ecd0f4722e16b349 Mon Sep 17 00:00:00 2001 From: Doug VanLeuven Date: Wed, 10 Oct 2012 22:10:14 +0000 Subject: [PATCH 0147/1342] zebra: kernel_socket: fix 64bit MacOS X alignment In OS X 10.7 zebra crashed on invalid execution address. sockaddr padding in *_msghdr is observed to be 4 bytes in 64bit OS X. The ROUNDUP macro assumed alignment on sizeof(long) which allocates 8 bytes on 64bit systems, 4 bytes on 32bit systems which is true for BSD generally. Test for Apple and use sizeof(int) which allocates 4 bytes on 32 & 64bit systems. Tested on 64bit OS X 10.7, FreeBSD 9.0 amd64 & i386 (32bit) using gcc & clang Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index b7061e762..ecc6e7905 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -48,9 +48,15 @@ extern struct zebra_t zebrad; * XXX: why is ROUNDUP(0) sizeof(long)? 0 is an illegal sockaddr * length anyway (< sizeof (struct sockaddr)), so this shouldn't * matter. + * On OS X, both 32, 64bit syatems align on 4 byte boundary */ +#ifdef __APPLE__ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int)) +#else #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#endif /* * Given a pointer (sockaddr or void *), return the number of bytes From a05df8fd279e4af0f077de181fb6c4e7d7174267 Mon Sep 17 00:00:00 2001 From: Doug VanLeuven Date: Wed, 10 Oct 2012 16:11:36 -0700 Subject: [PATCH 0148/1342] zebra: kernel_socket: fix overflow in RTA_ADDR & RTA_ATTR In zebra/kernel_socket.c, copying sockaddr from *_msghdr: There are really 2 different lengths that need to be determined. 1) the length required to point to the next sockaddr in the mesg buffer which might include any required padding and 2) the actual length of the sockaddr data that needs to be copied into the destination field. They may or may not be the same value. Sizeof sockaddr_in6 is 28, which to pad for alignment purposes on 32 bit systems with a long of 4 bytes is evenly divided and requires no padding. On 64 bit systems, with a long of 8 it is padded with 4 extra bytes.So the current RTA_* macros are copying 32 bytes into a 28 byte field on 64 bitsystems, where the field overflow did not occur on the 32 bit systems. Since using sa_len required the use of an #ifdef which couldn't be used directly inside a #define, it made sense to move the copy into the function to allow typdef checking throughout and eliminate the hack to suppress compiler warnings. Fixed declaration of cp in ifm_read after compiler noticed type mismatch. Tested on 64bit OS X 10.7, FreeBSD 9.0 amd64 & i386 (32bit) using gcc & clang Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index ecc6e7905..20c17f9ee 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -84,28 +84,41 @@ extern struct zebra_t zebrad; ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr))) #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ -/* We use an additional pointer in following, pdest, rather than (DEST) - * directly, because gcc will warn if the macro is expanded and DEST is NULL, - * complaining that memcpy is being passed a NULL value, despite the fact - * the if (NULL) makes it impossible. +/* + * We use a call to an inline function to copy (PNT) to (DEST) + * 1. Calculating the length of the copy requires an #ifdef to determine + * if sa_len is a field and can't be used directly inside a #define + * 2. So the compiler doesn't complain when DEST is NULL, which is only true + * when we are skipping the copy and incrementing to the next SA */ +static void inline +rta_copy (union sockunion *dest, caddr_t src) { + int len; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + len = (((struct sockaddr *)src)->sa_len > sizeof (*dest)) ? + sizeof (*dest) : ((struct sockaddr *)src)->sa_len ; +#else + len = (SAROUNDUP (src) > sizeof (*dest)) ? + sizeof (*dest) : SAROUNDUP (src) ; +#endif + memcpy (dest, src, len); +} + #define RTA_ADDR_GET(DEST, RTA, RTMADDRS, PNT) \ if ((RTMADDRS) & (RTA)) \ { \ - void *pdest = (DEST); \ int len = SAROUNDUP ((PNT)); \ if ( ((DEST) != NULL) && \ af_check (((struct sockaddr *)(PNT))->sa_family)) \ - memcpy (pdest, (PNT), len); \ + rta_copy((DEST), (PNT)); \ (PNT) += len; \ } #define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \ if ((RTMADDRS) & (RTA)) \ { \ - void *pdest = (DEST); \ int len = SAROUNDUP ((PNT)); \ if ((DEST) != NULL) \ - memcpy (pdest, (PNT), len); \ + rta_copy((DEST), (PNT)); \ (PNT) += len; \ } @@ -328,7 +341,7 @@ ifm_read (struct if_msghdr *ifm) struct sockaddr_dl *sdl; char ifname[IFNAMSIZ]; short ifnlen = 0; - caddr_t *cp; + caddr_t cp; /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; From 9234b382735b690f403ce018ce392316b2ad6e38 Mon Sep 17 00:00:00 2001 From: Doug VanLeuven Date: Wed, 10 Oct 2012 16:12:32 -0700 Subject: [PATCH 0149/1342] build: check actually-used BSD link state fields ifi_link_state missing in OS X. There could be other *BSD's that haven't implemented it and possibly affects older implementations. The existing HAVE_BSD_LINK_DETECT configure.ac check is only confirming the link state detection using ifmediareq.ifm_status found in . This is the link state detection used in zebra/ioctl.c. Later, *BSD redefined struct if_data in and included link state detection. This is the method used in zebra/kernel_socket.c Additional test defined in config.ac to test for member struct if_data.ifi_link_state defined in separate from test for ifmediareq.ifm_status Fixed #ifdef's in zebra/kernel_socket.c to use the new #define No impact on older function calls in zebra/ioctl.c Tested on 64bit OS X 10.7, FreeBSD 9.0 amd64 & i386 (32bit) using gcc & clang. Tested on linux 64bit. Signed-off-by: David Lamparter --- configure.ac | 10 ++++++++++ zebra/kernel_socket.c | 12 ++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index dcca9682c..425fe2737 100755 --- a/configure.ac +++ b/configure.ac @@ -992,6 +992,16 @@ AC_CHECK_HEADER([net/if.h], QUAGGA_INCLUDES)], [], QUAGGA_INCLUDES ) +dnl --------------------------------------------------------------- +dnl Additional, newer way to check link-state using ifi_link_state. +dnl Not available in all BSD's when ifmediareq available +dnl --------------------------------------------------------------- +AC_CHECK_HEADER([net/if.h], + AC_CHECK_MEMBERS([struct if_data.ifi_link_state], + AC_DEFINE(HAVE_BSD_IFI_LINK_STATE,,[BSD ifi_link_state available]), + [], QUAGGA_INCLUDES), + ,) + dnl ------------------------ dnl TCP_MD5SIG socket option dnl ------------------------ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 20c17f9ee..cde36bd03 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -316,7 +316,7 @@ ifan_read (struct if_announcemsghdr *ifan) } #endif /* RTM_IFANNOUNCE */ -#ifdef HAVE_BSD_LINK_DETECT +#ifdef HAVE_BSD_IFI_LINK_STATE /* BSD link detect translation */ static void bsd_linkdetect_translate (struct if_msghdr *ifm) @@ -327,7 +327,7 @@ bsd_linkdetect_translate (struct if_msghdr *ifm) else UNSET_FLAG(ifm->ifm_flags, IFF_RUNNING); } -#endif /* HAVE_BSD_LINK_DETECT */ +#endif /* HAVE_BSD_IFI_LINK_STATE */ /* * Handle struct if_msghdr obtained from reading routing socket or @@ -463,9 +463,9 @@ ifm_read (struct if_msghdr *ifm) */ ifp->ifindex = ifm->ifm_index; -#ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ +#ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); -#endif /* HAVE_BSD_LINK_DETECT */ +#endif /* HAVE_BSD_IFI_LINK_STATE */ if_flags_update (ifp, ifm->ifm_flags); #if defined(__bsdi__) @@ -504,9 +504,9 @@ ifm_read (struct if_msghdr *ifm) return -1; } -#ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ +#ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); -#endif /* HAVE_BSD_LINK_DETECT */ +#endif /* HAVE_BSD_IFI_LINK_STATE */ /* update flags and handle operative->inoperative transition, if any */ if_flags_update (ifp, ifm->ifm_flags); From 8c9ed279852393804c26e3c8c556a13d08654907 Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Thu, 11 Oct 2012 11:15:18 +0000 Subject: [PATCH 0150/1342] ospfd: remove some buggy extra ';' symbols. * ospfd/ospf_apiserver.c: extra ; causing lookup to fail always * ospfd/ospf_lsa.c: extra ; causing debug output even when disabled Signed-off-by: David Lamparter --- ospfd/ospf_apiserver.c | 2 +- ospfd/ospf_lsa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 2a9003b72..84d70ccc1 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -105,7 +105,7 @@ ospf_apiserver_if_lookup_by_ifp (struct interface *ifp) struct ospf_interface *oi; struct ospf *ospf; - if (!(ospf = ospf_lookup ())); + if (!(ospf = ospf_lookup ())) return NULL; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 5579d8efd..e778251ca 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1866,7 +1866,7 @@ ospf_translated_nssa_originate (struct ospf *ospf, struct ospf_lsa *type7) if ( (new = ospf_lsa_install (ospf, NULL, new)) == NULL) { - if (IS_DEBUG_OSPF_NSSA); + if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_lsa_translated_nssa_originate(): " "Could not install LSA " "id %s", inet_ntoa (type7->data->id)); From 43057bf22a4240b5e163c30a1f66deb702ce746e Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Thu, 11 Oct 2012 11:19:51 +0000 Subject: [PATCH 0151/1342] isisd: clock_gettime() -> quagga_gettime() conversion. * isisd/isis_spf.c: Use portable quagga_gettime() like the rest of the Quagga code. Signed-off-by: David Lamparter --- isisd/isis_spf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index eff7c4761..07b855b40 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1180,13 +1180,13 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) u_char lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; struct route_table *table = NULL; - struct timespec time_now; + struct timeval time_now; unsigned long long start_time, end_time; /* Get time that can't roll backwards. */ - clock_gettime(CLOCK_MONOTONIC, &time_now); + quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now); start_time = time_now.tv_sec; - start_time = (start_time * 1000000) + (time_now.tv_nsec / 1000); + start_time = (start_time * 1000000) + time_now.tv_usec; if (family == AF_INET) spftree = area->spftree[level - 1]; @@ -1282,9 +1282,9 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) spftree->pending = 0; spftree->runcount++; spftree->last_run_timestamp = time (NULL); - clock_gettime(CLOCK_MONOTONIC, &time_now); + quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now); end_time = time_now.tv_sec; - end_time = (end_time * 1000000) + (time_now.tv_nsec / 1000); + end_time = (end_time * 1000000) + time_now.tv_usec; spftree->last_run_duration = end_time - start_time; From 3b96b78136d04ddb7e39d86577cad75acb25237a Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Thu, 11 Oct 2012 11:31:54 +0000 Subject: [PATCH 0152/1342] lib: Implement monotonically increasing clock for Darwin. There is no Posix CLOCK_MONOTONIC in Darwin, but monotonically increasing clock can be implemented using mach_absolute_time(). Signed-off-by: David Lamparter --- lib/thread.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 6341dfd77..16c92c246 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -39,6 +39,11 @@ extern int agentx_enabled; #endif +#if defined(__APPLE__) +#include +#include +#endif + /* Recent absolute time of day */ struct timeval recent_time; @@ -103,7 +108,7 @@ timeval_elapsed (struct timeval a, struct timeval b) + (a.tv_usec - b.tv_usec)); } -#ifndef HAVE_CLOCK_MONOTONIC +#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__) static void quagga_gettimeofday_relative_adjust (void) { @@ -122,7 +127,7 @@ quagga_gettimeofday_relative_adjust (void) } last_recent_time = recent_time; } -#endif /* !HAVE_CLOCK_MONOTONIC */ +#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ /* gettimeofday wrapper, to keep recent_time updated */ static int @@ -162,7 +167,23 @@ quagga_get_relative (struct timeval *tv) relative_time.tv_usec = tp.tv_nsec / 1000; } } -#else /* !HAVE_CLOCK_MONOTONIC */ +#elif defined(__APPLE__) + { + uint64_t ticks; + uint64_t useconds; + static mach_timebase_info_data_t timebase_info; + + ticks = mach_absolute_time(); + if (timebase_info.denom == 0) + mach_timebase_info(&timebase_info); + + useconds = ticks * timebase_info.numer / timebase_info.denom / 1000; + relative_time.tv_sec = useconds / 1000000; + relative_time.tv_usec = useconds % 1000000; + + return 0; + } +#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ if (!(ret = quagga_gettimeofday (&recent_time))) quagga_gettimeofday_relative_adjust(); #endif /* HAVE_CLOCK_MONOTONIC */ From 9d3f9705d8b386ccf006c106967c700141e5d049 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Wed, 7 Nov 2012 23:50:07 +0000 Subject: [PATCH 0153/1342] bgpd: add replace-as modifier for BGP neighbor Added replace-as modifier for BGP neighbors when using local-as. If the replace-as modifier is specified, only the replacement AS as specified by the local-as modifier is prepended to the AS_PATH, not the process's AS. In bgp_attr.c, I decided that if (peer->change_local_as) { /* If replace-as is specified, we only use the change_local_as when advertising routes. */ if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) { aspath = aspath_add_seq (aspath, peer->local_as); } aspath = aspath_add_seq (aspath, peer->change_local_as); } else { aspath = aspath_add_seq (aspath, peer->local_as); } was clearer than the alternative that didn't duplicate the prepending of the process's AS: /* First, append the process local AS unless we have an alternate local_as * and we're replacing it (as opposed to just prepending it). */ if (! (peer->change_local_as && CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) ) { aspath = aspath_add_seq (aspath, peer->local_as); } if (peer->change_local_as) aspath = aspath_add_seq (aspath, peer->change_local_as); } But I could be convinced otherwise. Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 11 +++++++++-- bgpd/bgp_vty.c | 45 +++++++++++++++++++++++++++++++++++++++++---- bgpd/bgpd.c | 29 +++++++++++++++++++++++++---- bgpd/bgpd.h | 4 +++- 4 files changed, 78 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index cdc99ab3a..f48a5438b 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2085,9 +2085,16 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } else { - aspath = aspath_add_seq (aspath, peer->local_as); - if (peer->change_local_as) + if (peer->change_local_as) { + /* If replace-as is specified, we only use the change_local_as when + advertising routes. */ + if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) { + aspath = aspath_add_seq (aspath, peer->local_as); + } aspath = aspath_add_seq (aspath, peer->change_local_as); + } else { + aspath = aspath_add_seq (aspath, peer->local_as); + } } } else if (peer->sort == BGP_PEER_CONFED) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cb7ff1fa3..0f2889481 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1570,7 +1570,7 @@ DEFUN (neighbor_local_as, if (! peer) return CMD_WARNING; - ret = peer_local_as_set (peer, atoi (argv[1]), 0); + ret = peer_local_as_set (peer, atoi (argv[1]), 0, 0); return bgp_vty_return (vty, ret); } @@ -1590,10 +1590,32 @@ DEFUN (neighbor_local_as_no_prepend, if (! peer) return CMD_WARNING; - ret = peer_local_as_set (peer, atoi (argv[1]), 1); + ret = peer_local_as_set (peer, atoi (argv[1]), 1, 0); return bgp_vty_return (vty, ret); } +DEFUN (neighbor_local_as_no_prepend_replace_as, + neighbor_local_as_no_prepend_replace_as_cmd, + NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n" + "Do not prepend local-as to updates from ibgp peers\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_set (peer, atoi (argv[1]), 1, 1); + return bgp_vty_return (vty, ret); +} + + DEFUN (no_neighbor_local_as, no_neighbor_local_as_cmd, NO_NEIGHBOR_CMD2 "local-as", @@ -1631,6 +1653,17 @@ ALIAS (no_neighbor_local_as, "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n") + +ALIAS (no_neighbor_local_as, + no_neighbor_local_as_val3_cmd, + NO_NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n" + "Do not prepend local-as to updates from ibgp peers\n") DEFUN (neighbor_password, neighbor_password_cmd, @@ -7494,10 +7527,12 @@ bgp_show_peer (struct vty *vty, struct peer *p) /* Configured IP address. */ vty_out (vty, "BGP neighbor is %s, ", p->host); vty_out (vty, "remote AS %u, ", p->as); - vty_out (vty, "local AS %u%s, ", + vty_out (vty, "local AS %u%s%s, ", p->change_local_as ? p->change_local_as : p->local_as, CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? - " no-prepend" : ""); + " no-prepend" : "", + CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? + " replace-as" : ""); vty_out (vty, "%s link%s", p->as == p->local_as ? "internal" : "external", VTY_NEWLINE); @@ -9175,9 +9210,11 @@ bgp_vty_init (void) /* "neighbor local-as" commands. */ install_element (BGP_NODE, &neighbor_local_as_cmd); install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd); + install_element (BGP_NODE, &neighbor_local_as_no_prepend_replace_as_cmd); install_element (BGP_NODE, &no_neighbor_local_as_cmd); install_element (BGP_NODE, &no_neighbor_local_as_val_cmd); install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd); + install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd); /* "neighbor password" commands. */ install_element (BGP_NODE, &neighbor_password_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 69c8c0a33..908bdd94f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -962,6 +962,7 @@ peer_as_change (struct peer *peer, as_t as) { peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); } } @@ -1830,6 +1831,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, { group->conf->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); } } @@ -3405,7 +3407,7 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi) } int -peer_local_as_set (struct peer *peer, as_t as, int no_prepend) +peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as) { struct bgp *bgp = peer->bgp; struct peer_group *group; @@ -3421,9 +3423,14 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend) if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + if (peer->as == as) + return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS; + if (peer->change_local_as == as && ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend) - || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend))) + || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend)) && + ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && replace_as) + || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && ! replace_as))) return 0; peer->change_local_as = as; @@ -3432,6 +3439,11 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend) else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + if (replace_as) + SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); + else + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->status == Established) @@ -3455,6 +3467,11 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend) else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + if (replace_as) + SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); + else + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); + if (peer->status == Established) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; @@ -3482,6 +3499,7 @@ peer_local_as_unset (struct peer *peer) peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { @@ -3502,6 +3520,7 @@ peer_local_as_unset (struct peer *peer) { peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (peer->status == Established) { @@ -4770,10 +4789,12 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, /* local-as. */ if (peer->change_local_as) if (! peer_group_active (peer)) - vty_out (vty, " neighbor %s local-as %u%s%s", addr, + vty_out (vty, " neighbor %s local-as %u%s%s%s", addr, peer->change_local_as, CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? - " no-prepend" : "", VTY_NEWLINE); + " no-prepend" : "", + CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? + " replace-as" : "", VTY_NEWLINE); /* Description. */ if (peer->desc) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 63e326af9..0746f0dd7 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -381,6 +381,7 @@ struct peer #define PEER_FLAG_DYNAMIC_CAPABILITY (1 << 5) /* dynamic capability */ #define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */ #define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */ +#define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */ /* NSF mode (graceful restart) */ u_char nsf[AFI_MAX][SAFI_MAX]; @@ -814,6 +815,7 @@ enum bgp_clear_type #define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30 #define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 #define BGP_ERR_MAX -32 +#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -33 extern struct bgp_master *bm; @@ -941,7 +943,7 @@ extern int peer_distribute_unset (struct peer *, afi_t, safi_t, int); extern int peer_allowas_in_set (struct peer *, afi_t, safi_t, int); extern int peer_allowas_in_unset (struct peer *, afi_t, safi_t); -extern int peer_local_as_set (struct peer *, as_t, int); +extern int peer_local_as_set (struct peer *, as_t, int, int); extern int peer_local_as_unset (struct peer *); extern int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, const char *); From 8b366b9cfd1f3ec1a45e0f82db7fdb27e3bb3594 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Wed, 7 Nov 2012 23:50:08 +0000 Subject: [PATCH 0154/1342] bgpd: Fixed out-of-date comment When going through the code to write the documentation for local-as, I discovered that one of the comments was out-of-date. Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f48a5438b..2cbd7bc35 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1709,7 +1709,7 @@ bgp_attr_unknown (struct bgp_attr_parser_args *args) } /* Read attribute of update packet. This function is called from - bgp_update() in bgpd.c. */ + bgp_update_receive() in bgp_packet.c. */ bgp_attr_parse_ret_t bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) From 5aebb9c77fc2257c9d9df72db66668fabb24fc52 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Wed, 7 Nov 2012 23:50:09 +0000 Subject: [PATCH 0155/1342] bgpd: document bgp neighbor local-as peer command Signed-off-by: David Lamparter --- doc/bgpd.texi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 63834600a..dd37d3ecd 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -339,6 +339,27 @@ routes. @deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {} @end deffn +@deffn {BGP} {neighbor @var{peer} local-as @var{as-number}} {} +@deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend} {} +@deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend replace-as} {} +@deffnx {BGP} {no neighbor @var{peer} local-as} {} +Specify an alternate AS for this BGP process when interacting with the +specified peer. With no modifiers, the specified local-as is prepended to +the received AS_PATH when receiving routing updates from the peer, and +prepended to the outgoing AS_PATH (after the process local AS) when +transmitting local routes to the peer. + +If the no-prepend attribute is specified, then the supplied local-as is not +prepended to the received AS_PATH. + +If the replace-as attribute is specified, then only the supplied local-as is +prepended to the AS_PATH when transmitting local-route updates to this peer. + +Note that replace-as can only be specified if no-prepend is. + +This command is only allowed for eBGP peers. +@end deffn + @node Peer filtering @subsection Peer filtering From 9fd92e3c4bdcc78e0f0d94d53a2d4c7b0e893fcb Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:53 +0000 Subject: [PATCH 0156/1342] zebra: add structure to hold per-prefix state in RIB Add the rib_dest_t structure to hold per-prefix state in the routing information base. This gives us an appropriate place to maintain the queueing state of a route_node. Queuing state was previously being stored on the first rib in the list of ribs hanging off the route_node. * zebra/rib.h - Add new structure rib_dest_t. - Remove the rn_status field from 'struct rib', it is no longer required. - Add macros (RNODE_FOREACH_RIB, RNODE_FOREACH_RIB_SAFE) for walking all 'struct ribs' corresponding to a route_node. These hide the fact that there is an intermediate rib_dest_t structure. - Add a few utility inlines to go between a rib_dest_t and associated structures. * zebra/zebra_rib.c - rib_link()/rib_unlink() Tweak for new behavior, where the 'info' pointer of a route_node points to a rib_dest_t. The list of ribs for a prefix now hangs off of the dest. Change the way we ref count route_nodes. We now hold a single ref count on a route_node if there is a corresponding rib_dest_t. - Maintain the queuing state of a route_node on the flags field of the rib_dest_t. - Add the rib_gc_dest() function, which deletes a rib_dest_t if it is no longer required. A rib_dest_t can be deleted iff there are no struct ribs hanging off of it. - Call rib_gc_dest() any time we unlink a rib from the rib_dest_t. Currently we only need to call it once, just before we return from rib_process(). * zebra/{redistribute,zebra_rib,zebra_snmp,zebra_vty}.c Use new macros to walk over route_node ribs. * lib/memtypes.c Add memory type for rib_dest_t. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/memtypes.c | 1 + zebra/redistribute.c | 8 +- zebra/rib.h | 118 +++++++++++++++++++++++- zebra/zebra_rib.c | 213 ++++++++++++++++++++++++++++--------------- zebra/zebra_snmp.c | 10 +- zebra/zebra_vty.c | 24 ++--- 6 files changed, 276 insertions(+), 98 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index bbf96929f..76dece298 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -82,6 +82,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_RIB_QUEUE, "RIB process work queue" }, { MTYPE_STATIC_IPV4, "Static IPv4 route" }, { MTYPE_STATIC_IPV6, "Static IPv6 route" }, + { MTYPE_RIB_DEST, "RIB destination" }, { -1, NULL }, }; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 4276f1d04..476582485 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -107,7 +107,7 @@ zebra_redistribute_default (struct zserv *client) rn = route_node_lookup (table, (struct prefix *)&p); if (rn) { - for (newrib = rn->info; newrib; newrib = newrib->next) + RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->distance != DISTANCE_INFINITY) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); @@ -127,7 +127,7 @@ zebra_redistribute_default (struct zserv *client) rn = route_node_lookup (table, (struct prefix *)&p6); if (rn) { - for (newrib = rn->info; newrib; newrib = newrib->next) + RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->distance != DISTANCE_INFINITY) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); @@ -148,7 +148,7 @@ zebra_redistribute (struct zserv *client, int type) table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - for (newrib = rn->info; newrib; newrib = newrib->next) + RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->type == type && newrib->distance != DISTANCE_INFINITY @@ -159,7 +159,7 @@ zebra_redistribute (struct zserv *client, int type) table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - for (newrib = rn->info; newrib; newrib = newrib->next) + RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->type == type && newrib->distance != DISTANCE_INFINITY diff --git a/zebra/rib.h b/zebra/rib.h index 1b85c81ed..084f35166 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -24,6 +24,7 @@ #define _ZEBRA_RIB_H #include "prefix.h" +#include "table.h" #define DISTANCE_INFINITY 255 @@ -38,10 +39,6 @@ union g_addr { struct rib { - /* Status Flags for the *route_node*, but kept in the head RIB.. */ - u_char rn_status; -#define RIB_ROUTE_QUEUED(x) (1 << (x)) - /* Link list. */ struct rib *next; struct rib *prev; @@ -97,6 +94,57 @@ struct meta_queue u_int32_t size; /* sum of lengths of all subqueues */ }; +/* + * Structure that represents a single destination (prefix). + */ +typedef struct rib_dest_t_ +{ + + /* + * Back pointer to the route node for this destination. This helps + * us get to the prefix that this structure is for. + */ + struct route_node *rnode; + + /* + * Doubly-linked list of routes for this prefix. + */ + struct rib *routes; + + /* + * Flags, see below. + */ + u_int32_t flags; + +} rib_dest_t; + +#define RIB_ROUTE_QUEUED(x) (1 << (x)) + +/* + * The maximum qindex that can be used. + */ +#define ZEBRA_MAX_QINDEX (MQ_SIZE - 1) + +/* + * Macro to iterate over each route for a destination (prefix). + */ +#define RIB_DEST_FOREACH_ROUTE(dest, rib) \ + for ((rib) = (dest) ? (dest)->routes : NULL; (rib); (rib) = (rib)->next) + +/* + * Same as above, but allows the current node to be unlinked. + */ +#define RIB_DEST_FOREACH_ROUTE_SAFE(dest, rib, next) \ + for ((rib) = (dest) ? (dest)->routes : NULL; \ + (rib) && ((next) = (rib)->next, 1); \ + (rib) = (next)) + +#define RNODE_FOREACH_RIB(rn, rib) \ + RIB_DEST_FOREACH_ROUTE (rib_dest_from_rnode (rn), rib) + +#define RNODE_FOREACH_RIB_SAFE(rn, rib, next) \ + RIB_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode (rn), rib, next) + /* Static route information. */ struct static_ipv4 { @@ -307,4 +355,66 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, #endif /* HAVE_IPV6 */ +extern int rib_gc_dest (struct route_node *rn); + +/* + * Inline functions. + */ + +/* + * rib_dest_from_rnode + */ +static inline rib_dest_t * +rib_dest_from_rnode (struct route_node *rn) +{ + return (rib_dest_t *) rn->info; +} + +/* + * rnode_to_ribs + * + * Returns a pointer to the list of routes corresponding to the given + * route_node. + */ +static inline struct rib * +rnode_to_ribs (struct route_node *rn) +{ + rib_dest_t *dest; + + dest = rib_dest_from_rnode (rn); + if (!dest) + return NULL; + + return dest->routes; +} + +/* + * rib_dest_prefix + */ +static inline struct prefix * +rib_dest_prefix (rib_dest_t *dest) +{ + return &dest->rnode->p; +} + +/* + * rib_dest_af + * + * Returns the address family that the destination is for. + */ +static inline u_char +rib_dest_af (rib_dest_t *dest) +{ + return dest->rnode->p.family; +} + +/* + * rib_dest_table + */ +static inline struct route_table * +rib_dest_table (rib_dest_t *dest) +{ + return dest->rnode->table; +} + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0e29e616a..f0d5c9d93 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -351,7 +351,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, return 0; /* Pick up selected route. */ - for (match = rn->info; match; match = match->next) + RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; @@ -452,7 +452,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, return 0; /* Pick up selected route. */ - for (match = rn->info; match; match = match->next) + RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; @@ -543,7 +543,7 @@ rib_match_ipv4 (struct in_addr addr) route_unlock_node (rn); /* Pick up selected route. */ - for (match = rn->info; match; match = match->next) + RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; @@ -601,7 +601,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) /* Unlock node. */ route_unlock_node (rn); - for (match = rn->info; match; match = match->next) + RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; @@ -658,7 +658,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) route_unlock_node (rn); /* Find out if a "selected" RR for the discovered RIB entry exists ever. */ - for (match = rn->info; match; match = match->next) + RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; @@ -725,7 +725,7 @@ rib_match_ipv6 (struct in6_addr *addr) route_unlock_node (rn); /* Pick up selected route. */ - for (match = rn->info; match; match = match->next) + RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; @@ -975,6 +975,61 @@ rib_uninstall (struct route_node *rn, struct rib *rib) static void rib_unlink (struct route_node *, struct rib *); +/* + * rib_can_delete_dest + * + * Returns TRUE if the given dest can be deleted from the table. + */ +static int +rib_can_delete_dest (rib_dest_t *dest) +{ + if (dest->routes) + { + return 0; + } + + return 1; +} + +/* + * rib_gc_dest + * + * Garbage collect the rib dest corresponding to the given route node + * if appropriate. + * + * Returns TRUE if the dest was deleted, FALSE otherwise. + */ +int +rib_gc_dest (struct route_node *rn) +{ + rib_dest_t *dest; + char buf[INET6_ADDRSTRLEN]; + + dest = rib_dest_from_rnode (rn); + if (!dest) + return 0; + + if (!rib_can_delete_dest (dest)) + return 0; + + if (IS_ZEBRA_DEBUG_RIB) + { + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); + zlog_debug ("%s: %s/%d: removing dest from table", __func__, + buf, rn->p.prefixlen); + } + + dest->rnode = NULL; + XFREE (MTYPE_RIB_DEST, dest); + rn->info = NULL; + + /* + * Release the one reference that we keep on the route node. + */ + route_unlock_node (rn); + return 1; +} + /* Core function for processing routing information base. */ static void rib_process (struct route_node *rn) @@ -993,13 +1048,8 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - for (rib = rn->info; rib; rib = next) + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - /* The next pointer is saved, because current pointer - * may be passed to rib_unlink() in the middle of iteration. - */ - next = rib->next; - /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { @@ -1017,7 +1067,7 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, buf, rn->p.prefixlen, rn, rib); - rib_unlink (rn, rib); + rib_unlink (rn, rib); } else del = rib; @@ -1074,7 +1124,7 @@ rib_process (struct route_node *rn) /* metric tie-breaks equal distance */ if (rib->metric <= select->metric) select = rib; - } /* for (rib = rn->info; rib; rib = next) */ + } /* RNODE_FOREACH_RIB_SAFE */ /* After the cycle is finished, the following pointers will be set: * select --- the winner RIB entry, if any was found, otherwise NULL @@ -1171,6 +1221,11 @@ rib_process (struct route_node *rn) end: if (IS_ZEBRA_DEBUG_RIB_Q) zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); + + /* + * Check if the dest can be deleted now. + */ + rib_gc_dest (rn); } /* Take a list of route_node structs and return 1, if there was a record @@ -1189,8 +1244,9 @@ process_subq (struct list * subq, u_char qindex) rnode = listgetdata (lnode); rib_process (rnode); - if (rnode->info) /* The first RIB record is holding the flags bitmask. */ - UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); + if (rnode->info) + UNSET_FLAG (rib_dest_from_rnode (rnode)->flags, RIB_ROUTE_QUEUED (qindex)); + #if 0 else { @@ -1223,7 +1279,9 @@ meta_queue_process (struct work_queue *dummy, void *data) return mq->size ? WQ_REQUEUE : WQ_SUCCESS; } -/* Map from rib types to queue type (priority) in meta queue */ +/* + * Map from rib types to queue type (priority) in meta queue + */ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = { [ZEBRA_ROUTE_SYSTEM] = 4, [ZEBRA_ROUTE_KERNEL] = 0, @@ -1251,12 +1309,13 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_Q) inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { u_char qindex = meta_queue_map[rib->type]; /* Invariant: at this point we always have rn->info set. */ - if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex))) + if (CHECK_FLAG (rib_dest_from_rnode (rn)->flags, + RIB_ROUTE_QUEUED (qindex))) { if (IS_ZEBRA_DEBUG_RIB_Q) zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", @@ -1264,7 +1323,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) continue; } - SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); + SET_FLAG (rib_dest_from_rnode (rn)->flags, RIB_ROUTE_QUEUED (qindex)); listnode_add (mq->subq[qindex], rn); route_lock_node (rn); mq->size++; @@ -1286,7 +1345,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); /* Pointless to queue a route_node with no RIB entries to add or remove */ - if (!rn->info) + if (!rnode_to_ribs (rn)) { zlog_debug ("%s: called for route_node (%p, %d) with no ribs", __func__, rn, rn->lock); @@ -1395,17 +1454,16 @@ rib_queue_init (struct zebra_t *zebra) * |-> set RIB_ENTRY_REMOVE | * rib_delnode (RIB freed) * - * - * Queueing state for a route_node is kept in the head RIB entry, this - * state must be preserved as and when the head RIB entry of a - * route_node is changed by rib_unlink / rib_link. A small complication, - * but saves having to allocate a dedicated object for this. + * The 'info' pointer of a route_node points to a rib_dest_t + * ('dest'). Queueing state for a route_node is kept on the dest. The + * dest is created on-demand by rib_link() and is kept around at least + * as long as there are ribs hanging off it (@see rib_gc_dest()). * * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): * * - route_nodes: refcounted by: - * - RIBs attached to route_node: - * - managed by: rib_link/unlink + * - dest attached to route_node: + * - managed by: rib_link/rib_gc_dest * - route_node processing queue * - managed by: rib_addqueue, rib_process. * @@ -1416,12 +1474,11 @@ static void rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; + rib_dest_t *dest; char buf[INET6_ADDRSTRLEN]; - + assert (rib && rn); - route_lock_node (rn); /* rn route table reference */ - if (IS_ZEBRA_DEBUG_RIB) { inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); @@ -1429,18 +1486,28 @@ rib_link (struct route_node *rn, struct rib *rib) buf, rn->p.prefixlen, rn, rib); } - head = rn->info; - if (head) + dest = rib_dest_from_rnode (rn); + if (!dest) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: new head, rn_status copied over", __func__, - buf, rn->p.prefixlen); + { + zlog_debug ("%s: %s/%d: adding dest to table", __func__, + buf, rn->p.prefixlen); + } + + dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t)); + route_lock_node (rn); /* rn route table reference */ + rn->info = dest; + dest->rnode = rn; + } + + head = dest->routes; + if (head) + { head->prev = rib; - /* Transfer the rn status flags to the new head RIB */ - rib->rn_status = head->rn_status; } rib->next = head; - rn->info = rib; + dest->routes = rib; rib_queue_add (&zebrad, rn); } @@ -1465,11 +1532,21 @@ rib_addnode (struct route_node *rn, struct rib *rib) rib_link (rn, rib); } +/* + * rib_unlink + * + * Detach a rib structure from a route_node. + * + * Note that a call to rib_unlink() should be followed by a call to + * rib_gc_dest() at some point. This allows a rib_dest_t that is no + * longer required to be deleted. + */ static void rib_unlink (struct route_node *rn, struct rib *rib) { struct nexthop *nexthop, *next; char buf[INET6_ADDRSTRLEN]; + rib_dest_t *dest; assert (rn && rib); @@ -1480,6 +1557,8 @@ rib_unlink (struct route_node *rn, struct rib *rib) __func__, buf, rn->p.prefixlen, rn, rib); } + dest = rib_dest_from_rnode (rn); + if (rib->next) rib->next->prev = rib->prev; @@ -1487,15 +1566,7 @@ rib_unlink (struct route_node *rn, struct rib *rib) rib->prev->next = rib->next; else { - rn->info = rib->next; - - if (rn->info) - { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: rn %p, rib %p, new head copy", - __func__, buf, rn->p.prefixlen, rn, rib); - rib->next->rn_status = rib->rn_status; - } + dest->routes = rib->next; } /* free RIB and nexthops */ @@ -1506,7 +1577,6 @@ rib_unlink (struct route_node *rn, struct rib *rib) } XFREE (MTYPE_RIB, rib); - route_unlock_node (rn); /* rn route table reference */ } static void @@ -1561,7 +1631,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* If same type of route are installed, treat it as a implicit withdraw. */ - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -1717,7 +1787,7 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) route_unlock_node (rn); /* let's go */ - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { zlog_debug ( @@ -1764,7 +1834,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) * RIBQ record already on head. This is necessary for proper revalidation * of the rest of the RIB. */ - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && ! RIB_SYSTEM_ROUTE (rib)) @@ -1816,7 +1886,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* If same type of route are installed, treat it as a implicit withdraw. */ - for (same = rn->info; same; same = same->next) + RNODE_FOREACH_RIB (rn, same) { if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) continue; @@ -1907,7 +1977,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, } /* Lookup same type route. */ - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2000,7 +2070,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) /* Lookup existing route */ rn = route_node_get (table, p); - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2096,7 +2166,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) if (! rn) return; - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2355,7 +2425,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* If same type of route are installed, treat it as a implicit withdraw. */ - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2458,7 +2528,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, } /* Lookup same type route. */ - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2551,7 +2621,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) /* Lookup existing route */ rn = route_node_get (table, p); - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2648,7 +2718,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) if (! rn) return; - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2844,13 +2914,13 @@ rib_update (void) table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - if (rn->info) + if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - if (rn->info) + if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); } @@ -2865,10 +2935,8 @@ rib_weed_table (struct route_table *table) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = next) + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - next = rib->next; - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2897,10 +2965,8 @@ rib_sweep_table (struct route_table *table) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = next) + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - next = rib->next; - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; @@ -2933,9 +2999,8 @@ rib_score_proto_table (u_char proto, struct route_table *table) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = next) + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - next = rib->next; if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type == proto) @@ -2965,11 +3030,13 @@ rib_close_table (struct route_table *table) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { - if (! RIB_SYSTEM_ROUTE (rib) - && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - rib_uninstall_kernel (rn, rib); + if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + continue; + + if (! RIB_SYSTEM_ROUTE (rib)) + rib_uninstall_kernel (rn, rib); } } diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index f52bbcb8d..e06e1443d 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -150,7 +150,7 @@ ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) result++; return (u_char *)&result; @@ -175,7 +175,7 @@ ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len, /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) result++; return (u_char *)&result; @@ -369,7 +369,7 @@ get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, { if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest)) { - for (*rib = (*np)->info; *rib; *rib = (*rib)->next) + RNODE_FOREACH_RIB (*np, *rib) { if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, (u_char *)&nexthop)) @@ -388,12 +388,12 @@ get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, /* Check destination first */ if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0) - for (rib2 = np2->info; rib2; rib2 = rib2->next) + RNODE_FOREACH_RIB (np2, rib2) check_replace(np2, rib2, np, rib); if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0) { /* have to look at each rib individually */ - for (rib2 = np2->info; rib2; rib2 = rib2->next) + RNODE_FOREACH_RIB (np2, rib2) { int proto2, policy2; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 743c13fe7..d07b09c8e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -535,7 +535,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) struct rib *rib; struct nexthop *nexthop; - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { vty_out (vty, "Routing entry for %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, @@ -822,7 +822,7 @@ DEFUN (show_ip_route, /* Show all IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (first) { @@ -863,7 +863,7 @@ DEFUN (show_ip_route_prefix_longer, /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) @@ -896,7 +896,7 @@ DEFUN (show_ip_route_supernets, /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { addr = ntohl (rn->p.u.prefix4.s_addr); @@ -942,7 +942,7 @@ DEFUN (show_ip_route_protocol, /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) @@ -1046,7 +1046,7 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table) memset (&rib_cnt, 0, sizeof(rib_cnt)); memset (&fib_cnt, 0, sizeof(fib_cnt)); for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { rib_cnt[ZEBRA_ROUTE_TOTAL]++; @@ -1219,7 +1219,7 @@ DEFUN (show_ip_mroute, /* Show all IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (first) { @@ -1546,7 +1546,7 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) struct nexthop *nexthop; char buf[BUFSIZ]; - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { vty_out (vty, "Routing entry for %s/%d%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), @@ -1795,7 +1795,7 @@ DEFUN (show_ipv6_route, /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (first) { @@ -1836,7 +1836,7 @@ DEFUN (show_ipv6_route_prefix_longer, /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) @@ -1876,7 +1876,7 @@ DEFUN (show_ipv6_route_protocol, /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) @@ -2008,7 +2008,7 @@ DEFUN (show_ipv6_mroute, /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) - for (rib = rn->info; rib; rib = rib->next) + RNODE_FOREACH_RIB (rn, rib) { if (first) { From 1b5ed1b054b955275bb7cf0f80fb7767094bc28b Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:54 +0000 Subject: [PATCH 0157/1342] zebra: add way to determine VRF/AFI/SAFI of table Add some code that allows us to determine which VRF and AFI/SAFI a given RIB table corresponds to. * zebra/rib.h Add rib_table_info_t structure, which contains information about the VRF, AFI and SAFI that a table is for. * zebra/zebra_rib.c - Add the vrf_table_create() function, which creates a table and sets its 'info' pointer to a newly created rib_table_info_t. The 'info' pointer allows us to go from a route_node or a table to the associated vrf. - vrf_alloc(): Use vrf_create_table() to create tables. * lib/memtypes.c Add memory type for rib_table_info_t. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/memtypes.c | 1 + zebra/rib.h | 36 ++++++++++++++++++++++++++++++++++++ zebra/zebra_rib.c | 29 +++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index 76dece298..50b6fa427 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -83,6 +83,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_STATIC_IPV4, "Static IPv4 route" }, { MTYPE_STATIC_IPV6, "Static IPv6 route" }, { MTYPE_RIB_DEST, "RIB destination" }, + { MTYPE_RIB_TABLE_INFO, "RIB table info" }, { -1, NULL }, }; diff --git a/zebra/rib.h b/zebra/rib.h index 084f35166..c98d99a4d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -268,6 +268,24 @@ struct vrf struct route_table *stable[AFI_MAX][SAFI_MAX]; }; +/* + * rib_table_info_t + * + * Structure that is hung off of a route_table that holds information about + * the table. + */ +typedef struct rib_table_info_t_ +{ + + /* + * Back pointer to vrf. + */ + struct vrf *vrf; + afi_t afi; + safi_t safi; + +} rib_table_info_t; + extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); @@ -361,6 +379,15 @@ extern int rib_gc_dest (struct route_node *rn); * Inline functions. */ +/* + * rib_table_info + */ +static inline rib_table_info_t * +rib_table_info (struct route_table *table) +{ + return (rib_table_info_t *) table->info; +} + /* * rib_dest_from_rnode */ @@ -417,4 +444,13 @@ rib_dest_table (rib_dest_t *dest) return dest->rnode->table; } +/* + * rib_dest_vrf + */ +static inline struct vrf * +rib_dest_vrf (rib_dest_t *dest) +{ + return rib_table_info (rib_dest_table (dest))->vrf; +} + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f0d5c9d93..2cbee9355 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -74,6 +74,27 @@ static const struct /* Vector for routing table. */ static vector vrf_vector; +/* + * vrf_table_create + */ +static void +vrf_table_create (struct vrf *vrf, afi_t afi, safi_t safi) +{ + rib_table_info_t *info; + struct route_table *table; + + assert (!vrf->table[afi][safi]); + + table = route_table_init (); + vrf->table[afi][safi] = table; + + info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); + info->vrf = vrf; + info->afi = afi; + info->safi = safi; + table->info = info; +} + /* Allocate new VRF. */ static struct vrf * vrf_alloc (const char *name) @@ -87,12 +108,12 @@ vrf_alloc (const char *name) vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); /* Allocate routing table and static table. */ - vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init (); - vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); + vrf_table_create (vrf, AFI_IP, SAFI_UNICAST); + vrf_table_create (vrf, AFI_IP6, SAFI_UNICAST); vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); - vrf->table[AFI_IP][SAFI_MULTICAST] = route_table_init (); - vrf->table[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + vrf_table_create (vrf, AFI_IP, SAFI_MULTICAST); + vrf_table_create (vrf, AFI_IP6, SAFI_MULTICAST); vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); From 0915bb0ce2ca6b5fee2cd214be4499eeeaf1c9af Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:55 +0000 Subject: [PATCH 0158/1342] zebra: add iterator for walking all tables in RIB * lib/zebra.h Add macro ZEBRA_NUM_OF, which returns the number of elements in a static array. * zebra/rib.h Add the rib_tables_iter_t structure and associated functions, which allow one to walk all tables in the rib. * zebra/zebra_rib.c - Add vrf_id_get_next() to retrieve the first VRF id (if any) that is greater than a given VRF id. - Add rib_tables_iter_next(). Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/zebra.h | 2 + zebra/rib.h | 52 +++++++++++++++++++++++ zebra/zebra_rib.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) diff --git a/lib/zebra.h b/lib/zebra.h index f8a6be306..404b832b0 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -387,6 +387,8 @@ struct in_pktinfo #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif +#define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0])) + /* For old definition. */ #ifndef IN6_ARE_ADDR_EQUAL #define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL diff --git a/zebra/rib.h b/zebra/rib.h index c98d99a4d..4f99d714a 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -286,6 +286,25 @@ typedef struct rib_table_info_t_ } rib_table_info_t; +typedef enum +{ + RIB_TABLES_ITER_S_INIT, + RIB_TABLES_ITER_S_ITERATING, + RIB_TABLES_ITER_S_DONE +} rib_tables_iter_state_t; + +/* + * Structure that holds state for iterating over all tables in the + * Routing Information Base. + */ +typedef struct rib_tables_iter_t_ +{ + uint32_t vrf_id; + int afi_safi_ix; + + rib_tables_iter_state_t state; +} rib_tables_iter_t; + extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); @@ -374,6 +393,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, #endif /* HAVE_IPV6 */ extern int rib_gc_dest (struct route_node *rn); +extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); /* * Inline functions. @@ -453,4 +473,36 @@ rib_dest_vrf (rib_dest_t *dest) return rib_table_info (rib_dest_table (dest))->vrf; } +/* + * rib_tables_iter_init + */ +static inline void +rib_tables_iter_init (rib_tables_iter_t *iter) + +{ + memset (iter, 0, sizeof (*iter)); + iter->state = RIB_TABLES_ITER_S_INIT; +} + +/* + * rib_tables_iter_started + * + * Returns TRUE if this iterator has started iterating over the set of + * tables. + */ +static inline int +rib_tables_iter_started (rib_tables_iter_t *iter) +{ + return iter->state != RIB_TABLES_ITER_S_INIT; +} + +/* + * rib_tables_iter_cleanup + */ +static inline void +rib_tables_iter_cleanup (rib_tables_iter_t *iter) +{ + iter->state = RIB_TABLES_ITER_S_DONE; +} + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 2cbee9355..5c75b9091 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3077,3 +3077,106 @@ rib_init (void) /* VRF initialization. */ vrf_init (); } + +/* + * vrf_id_get_next + * + * Get the first vrf id that is greater than the given vrf id if any. + * + * Returns TRUE if a vrf id was found, FALSE otherwise. + */ +static inline int +vrf_id_get_next (uint32_t id, uint32_t *next_id_p) +{ + while (++id < vector_active (vrf_vector)) + { + if (vrf_lookup (id)) + { + *next_id_p = id; + return 1; + } + } + + return 0; +} + +/* + * rib_tables_iter_next + * + * Returns the next table in the iteration. + */ +struct route_table * +rib_tables_iter_next (rib_tables_iter_t *iter) +{ + struct route_table *table; + + /* + * Array that helps us go over all AFI/SAFI combinations via one + * index. + */ + static struct { + afi_t afi; + safi_t safi; + } afi_safis[] = { + { AFI_IP, SAFI_UNICAST }, + { AFI_IP, SAFI_MULTICAST }, + { AFI_IP6, SAFI_UNICAST }, + { AFI_IP6, SAFI_MULTICAST }, + }; + + table = NULL; + + switch (iter->state) + { + + case RIB_TABLES_ITER_S_INIT: + iter->vrf_id = 0; + iter->afi_safi_ix = -1; + + /* Fall through */ + + case RIB_TABLES_ITER_S_ITERATING: + iter->afi_safi_ix++; + while (1) + { + + while (iter->afi_safi_ix < (int) ZEBRA_NUM_OF (afi_safis)) + { + table = vrf_table (afi_safis[iter->afi_safi_ix].afi, + afi_safis[iter->afi_safi_ix].safi, + iter->vrf_id); + if (table) + break; + + iter->afi_safi_ix++; + } + + /* + * Found another table in this vrf. + */ + if (table) + break; + + /* + * Done with all tables in the current vrf, go to the next + * one. + */ + if (!vrf_id_get_next (iter->vrf_id, &iter->vrf_id)) + break; + + iter->afi_safi_ix = 0; + } + + break; + + case RIB_TABLES_ITER_S_DONE: + return NULL; + } + + if (table) + iter->state = RIB_TABLES_ITER_S_ITERATING; + else + iter->state = RIB_TABLES_ITER_S_DONE; + + return table; +} From 78deec450cfa5ddcad290c13b36dd1d187da213e Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:56 +0000 Subject: [PATCH 0159/1342] zebra: extern/extract some functions from rt_netlink.c * zebra/{rib.h,zebra_rib.c} Add nexthop_type_to_str(), which returns a human-readable string corresponding to a nexthop type. * zebra/rt_netlink.[hc] - Add new header file that exposes some existing and new netlink-related functions from rt_netlink.c to the rest of zebra. addattr32 addattr_l rta_addattr_l nl_msg_type_to_str (new) nl_rtproto_to_str (new) - Use nexthop_type_to_str() instead of the static array 'nexthop_types_desc'. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- zebra/rib.h | 1 + zebra/rt_netlink.c | 48 +++++++++++++++++++++++++--------------------- zebra/rt_netlink.h | 46 ++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_rib.c | 25 ++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 zebra/rt_netlink.h diff --git a/zebra/rib.h b/zebra/rib.h index 4f99d714a..4ecfaa0d8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -305,6 +305,7 @@ typedef struct rib_tables_iter_t_ rib_tables_iter_state_t state; } rib_tables_iter_t; +extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ab28ad271..fa446a56f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -43,7 +43,7 @@ #include "zebra/interface.h" #include "zebra/debug.h" -#define NL_PKT_BUF_SIZE 4096 +#include "rt_netlink.h" /* Socket interface to kernel */ struct nlsock @@ -68,20 +68,6 @@ static const struct message nlmsg_str[] = { {0, NULL} }; -static const char *nexthop_types_desc[] = -{ - "none", - "Directly connected", - "Interface route", - "IPv4 nexthop", - "IPv4 nexthop with ifindex", - "IPv4 nexthop with ifname", - "IPv6 nexthop", - "IPv6 nexthop with ifindex", - "IPv6 nexthop with ifname", - "Null0 nexthop", -}; - extern struct zebra_t zebrad; extern struct zebra_privs_t zserv_privs; @@ -1236,7 +1222,7 @@ netlink_route_read (void) /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ -static int +int addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { int len; @@ -1256,7 +1242,7 @@ addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) return 0; } -static int +int rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) { int len; @@ -1278,7 +1264,7 @@ rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ -static int +int addattr32 (struct nlmsghdr *n, int maxlen, int type, int data) { int len; @@ -1515,7 +1501,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ - p->prefixlen, nexthop_types_desc[nexthop->rtype]); + p->prefixlen, nexthop_type_to_str (nexthop->rtype)); } if (nexthop->rtype == NEXTHOP_TYPE_IPV4 @@ -1580,7 +1566,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ - p->prefixlen, nexthop_types_desc[nexthop->type]); + p->prefixlen, nexthop_type_to_str (nexthop->type)); } if (nexthop->type == NEXTHOP_TYPE_IPV4 @@ -1687,7 +1673,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ - p->prefixlen, nexthop_types_desc[nexthop->rtype]); + p->prefixlen, nexthop_type_to_str (nexthop->rtype)); } if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) @@ -1761,7 +1747,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ - p->prefixlen, nexthop_types_desc[nexthop->type]); + p->prefixlen, nexthop_type_to_str (nexthop->type)); } if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) @@ -2023,3 +2009,21 @@ kernel_init (void) thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); } } + +/* + * nl_msg_type_to_str + */ +const char * +nl_msg_type_to_str (uint16_t msg_type) +{ + return lookup (nlmsg_str, msg_type); +} + +/* + * nl_rtproto_to_str + */ +const char * +nl_rtproto_to_str (u_char rtproto) +{ + return lookup (rtproto_str, rtproto); +} diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h new file mode 100644 index 000000000..529fa517a --- /dev/null +++ b/zebra/rt_netlink.h @@ -0,0 +1,46 @@ +/* Header file exported by rt_netlink.c to zebra. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RT_NETLINK_H +#define _ZEBRA_RT_NETLINK_H + +#ifdef HAVE_NETLINK + +#define NL_PKT_BUF_SIZE 4096 + +extern int +addattr32 (struct nlmsghdr *n, int maxlen, int type, int data); +extern int +addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen); + +extern int +rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen); + +extern const char * +nl_msg_type_to_str (uint16_t msg_type); + +extern const char * +nl_rtproto_to_str (u_char rtproto); + + +#endif /* HAVE_NETLINK */ + +#endif /* _ZEBRA_RT_NETLINK_H */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5c75b9091..299771234 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -170,6 +170,31 @@ vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) return vrf->stable[afi][safi]; } +/* + * nexthop_type_to_str + */ +const char * +nexthop_type_to_str (enum nexthop_types_t nh_type) +{ + static const char *desc[] = { + "none", + "Directly connected", + "Interface route", + "IPv4 nexthop", + "IPv4 nexthop with ifindex", + "IPv4 nexthop with ifname", + "IPv6 nexthop", + "IPv6 nexthop with ifindex", + "IPv6 nexthop with ifname", + "Null0 nexthop", + }; + + if (nh_type >= ZEBRA_NUM_OF (desc)) + return ""; + + return desc[nh_type]; +} + /* Add nexthop to the end of the list. */ static void nexthop_add (struct rib *rib, struct nexthop *nexthop) From 04f7dd64dfa0f339208f0d4833276b7684ee3343 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:57 +0000 Subject: [PATCH 0160/1342] lib: bring in sys/queue.h from FreeBSD tree Bring in sys/queue.h from the FreeBSD tree as lib/queue.h. This header implements lists of various flavors using inline linkages. The imported file corresponds to SVN revision 221843 (url below) and is available under the terms of the New BSD license (3-clause). http://svnweb.freebsd.org/base/head/sys/sys/queue.h?revision=221843 Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- lib/queue.h | 637 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 lib/queue.h diff --git a/lib/queue.h b/lib/queue.h new file mode 100644 index 000000000..70cffab1b --- /dev/null +++ b/lib/queue.h @@ -0,0 +1,637 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ From 443b993777e3e86fceb988f647d1c5b57661a182 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:58 +0000 Subject: [PATCH 0161/1342] fpm: Add public header for Forwarding Plane Manager The Forwarding Plane Manager (FPM) is an optional component that may be used in scenarios where the router has a forwarding path that is distinct from the kernel, commonly a hardware-based fast path. It is responsible for programming forwarding information (such as routes and nexthops) in the fast path. In Quagga, the Routing Information Base is maintained in the 'zebra' infrastructure daemon. Routing protocols communicate their best routes to zebra, and zebra computes the best route across protocols for each prefix. This latter information comprises the bulk of the Forwarding Information Base. The new header file added by this patch, 'fpm/fpm.h', defines a point-to-point interface using which zebra can update the FPM about changes in routes. The communication takes place over a stream socket. The FPM listens on a well-known TCP port, and zebra initiates the connection. All messages sent over the connection start with a short 'FPM header'. In the case of route add/delete messages, the header is followed by a netlink message. Zebra should send a complete copy of the forwarding table(s) to the FPM, including routes that it may have picked up from the kernel. The FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, the information in the second message is complete by itself, and replaces the information sent in the first message. If the connection to the FPM goes down for some reason, the client (zebra) should send the FPM a complete copy of the forwarding table(s) when it reconnects. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- fpm/fpm.h | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 fpm/fpm.h diff --git a/fpm/fpm.h b/fpm/fpm.h new file mode 100644 index 000000000..96f05f486 --- /dev/null +++ b/fpm/fpm.h @@ -0,0 +1,273 @@ +/* + * Public definitions pertaining to the Forwarding Plane Manager component. + * + * Permission is granted to use, copy, modify and/or distribute this + * software under either one of the licenses below. + * + * Note that if you use other files from the Quagga tree directly or + * indirectly, then the licenses in those files still apply. + * + * Please retain both licenses below when modifying this code in the + * Quagga tree. + * + * Copyright (C) 2012 by Open Source Routing. + * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") + */ + +/* + * License Option 1: GPL + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * License Option 2: ISC License + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FPM_H +#define _FPM_H + +/* + * The Forwarding Plane Manager (FPM) is an optional component that + * may be used in scenarios where the router has a forwarding path + * that is distinct from the kernel, commonly a hardware-based fast + * path. It is responsible for programming forwarding information + * (such as routes and nexthops) in the fast path. + * + * In Quagga, the Routing Information Base is maintained in the + * 'zebra' infrastructure daemon. Routing protocols communicate their + * best routes to zebra, and zebra computes the best route across + * protocols for each prefix. This latter information comprises the + * bulk of the Forwarding Information Base. + * + * This header file defines a point-to-point interface using which + * zebra can update the FPM about changes in routes. The communication + * takes place over a stream socket. The FPM listens on a well-known + * TCP port, and zebra initiates the connection. + * + * All messages sent over the connection start with a short FPM + * header, fpm_msg_hdr_t. In the case of route add/delete messages, + * the header is followed by a netlink message. Zebra should send a + * complete copy of the forwarding table(s) to the FPM, including + * routes that it may have picked up from the kernel. + * + * The FPM interface uses replace semantics. That is, if a 'route add' + * message for a prefix is followed by another 'route add' message, the + * information in the second message is complete by itself, and replaces + * the information sent in the first message. + * + * If the connection to the FPM goes down for some reason, the client + * (zebra) should send the FPM a complete copy of the forwarding + * table(s) when it reconnects. + */ + +#define FPM_DEFAULT_PORT 2620 + +/* + * Largest message that can be sent to or received from the FPM. + */ +#define FPM_MAX_MSG_LEN 4096 + +/* + * Header that precedes each fpm message to/from the FPM. + */ +typedef struct fpm_msg_hdr_t_ +{ + /* + * Protocol version. + */ + uint8_t version; + + /* + * Type of message, see below. + */ + uint8_t msg_type; + + /* + * Length of entire message, including the header, in network byte + * order. + * + * Note that msg_len is rounded up to make sure that message is at + * the desired alignment. This means that some payloads may need + * padding at the end. + */ + uint16_t msg_len; +} fpm_msg_hdr_t; + +/* + * The current version of the FPM protocol is 1. + */ +#define FPM_PROTO_VERSION 1 + +typedef enum fpm_msg_type_e_ { + FPM_MSG_TYPE_NONE = 0, + + /* + * Indicates that the payload is a completely formed netlink + * message. + */ + FPM_MSG_TYPE_NETLINK = 1, +} fpm_msg_type_e; + +/* + * The FPM message header is aligned to the same boundary as netlink + * messages (4). This means that a netlink message does not need + * padding when encapsulated in an FPM message. + */ +#define FPM_MSG_ALIGNTO 4 + +/* + * fpm_msg_align + * + * Round up the given length to the desired alignment. + */ +static inline size_t +fpm_msg_align (size_t len) +{ + return (len + FPM_MSG_ALIGNTO - 1) & ~(FPM_MSG_ALIGNTO - 1); +} + +/* + * The (rounded up) size of the FPM message header. This ensures that + * the message payload always starts at an aligned address. + */ +#define FPM_MSG_HDR_LEN (fpm_msg_align (sizeof (fpm_msg_hdr_t))) + +/* + * fpm_data_len_to_msg_len + * + * The length value that should be placed in the msg_len field of the + * header for a *payload* of size 'data_len'. + */ +static inline size_t +fpm_data_len_to_msg_len (size_t data_len) +{ + return fpm_msg_align (data_len) + FPM_MSG_HDR_LEN; +} + +/* + * fpm_msg_data + * + * Pointer to the payload of the given fpm header. + */ +static inline void * +fpm_msg_data (fpm_msg_hdr_t *hdr) +{ + return ((char*) hdr) + FPM_MSG_HDR_LEN; +} + +/* + * fpm_msg_len + */ +static inline size_t +fpm_msg_len (const fpm_msg_hdr_t *hdr) +{ + return ntohs (hdr->msg_len); +} + +/* + * fpm_msg_data_len + */ +static inline size_t +fpm_msg_data_len (const fpm_msg_hdr_t *hdr) +{ + return (fpm_msg_len (hdr) - FPM_MSG_HDR_LEN); +} + +/* + * fpm_msg_next + * + * Move to the next message in a buffer. + */ +static inline fpm_msg_hdr_t * +fpm_msg_next (fpm_msg_hdr_t *hdr, size_t *len) +{ + size_t msg_len; + + msg_len = fpm_msg_len (hdr); + + if (len) { + if (*len < msg_len) + { + assert(0); + return NULL; + } + *len -= msg_len; + } + + return (fpm_msg_hdr_t *) (((char*) hdr) + msg_len); +} + +/* + * fpm_msg_hdr_ok + * + * Returns TRUE if a message header looks well-formed. + */ +static inline int +fpm_msg_hdr_ok (const fpm_msg_hdr_t *hdr) +{ + size_t msg_len; + + if (hdr->msg_type == FPM_MSG_TYPE_NONE) + return 0; + + msg_len = fpm_msg_len (hdr); + + if (msg_len < FPM_MSG_HDR_LEN || msg_len > FPM_MAX_MSG_LEN) + return 0; + + if (fpm_msg_align (msg_len) != msg_len) + return 0; + + return 1; +} + +/* + * fpm_msg_ok + * + * Returns TRUE if a message looks well-formed. + * + * @param len The length in bytes from 'hdr' to the end of the buffer. + */ +static inline int +fpm_msg_ok (const fpm_msg_hdr_t *hdr, size_t len) +{ + if (len < FPM_MSG_HDR_LEN) + return 0; + + if (!fpm_msg_hdr_ok (hdr)) + return 0; + + if (fpm_msg_len (hdr) > len) + return 0; + + return 1; +} + +#endif /* _FPM_H */ From 5adc2528d386f037cc39e8029616295c3fec2db4 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:48:59 +0000 Subject: [PATCH 0162/1342] zebra: add module to communicate routes to FPM Enhance zebra to send routes to the (optional) Forwarding Path Manager component using the interface defined by fpm/fpm.h. * configure.ac - Add --enable-fpm flag. The FPM-related code in zebra is activated only if the build is configured with '--enable-fpm'. - Add HAVE_NETLINK automake conditional. This allows us to conditionally build netlink-dependent C code. * zebra/{rib.h,zebra_rib.c} - Add the 'fpm_q_entries' field to the rib_dest_t structure. This allows dests to be placed on the fpm queue. - Define a couple new rib_dest_t flags that hold FPM-related state. - Invoke the zfpm_trigger_update() function for a route_node whenever the information to be sent to the FPM changes. - rib_can_delete_dest(): Return FALSE if we have to update the FPM about the given dest. This ensures that the dest is not deleted even if there are no ribs hanging off of it. * zebra/zebra_fpm.c This file holds most of the code for interacting with the FPM. - If quagga was configured with '--enable-fpm', periodically try to connect to the FPM. - When the connection comes up, enqueue all relevent dests to the FPM queue. - When the FPM socket is readable, dequeue the next rib_dest_t from the FPM queue, encode it in to a message and send the message to the FPM. - When the connection to the FPM goes down, remove all dests from the FPM queue, and then start trying to connect to the FPM again. - Expose the following new operational commands: show zebra fpm stats clear zebra fpm stats * zebra/zebra_fpm_netlink.c - zfpm_netlink_encode_route(): Function to encode information about a rib_dest_t in netlink format. * zebra/zebra_fpm_private.h Private header file for the zebra FPM module. * zebra/zebra_fpm.h Header file exported by zebra FPM module to the rest of zebra. * zebra/debug.c Add the 'debug zebra fpm' command. * zebra/main.c Initialize the zebra-FPM code on startup. * zebra/misc_null.c Add stub for zfpm_trigger_update(). * zebra/Makefile.am - Include new file zebra_fpm.c in build. - Include zebra_fpm_netlink.c in build if HAVE_NETLINK is defined. * vtysh/Makefile.am Include zebra_fpm.c in list of files that define cli commands. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- configure.ac | 7 + vtysh/Makefile.am | 3 +- zebra/Makefile.am | 7 +- zebra/debug.c | 37 + zebra/debug.h | 5 + zebra/main.c | 7 + zebra/misc_null.c | 7 + zebra/rib.h | 18 + zebra/zebra_fpm.c | 1581 +++++++++++++++++++++++++++++++++++++ zebra/zebra_fpm.h | 34 + zebra/zebra_fpm_netlink.c | 552 +++++++++++++ zebra/zebra_fpm_private.h | 56 ++ zebra/zebra_rib.c | 32 + 13 files changed, 2344 insertions(+), 2 deletions(-) create mode 100644 zebra/zebra_fpm.c create mode 100644 zebra/zebra_fpm.h create mode 100644 zebra/zebra_fpm_netlink.c create mode 100644 zebra/zebra_fpm_private.h diff --git a/configure.ac b/configure.ac index 425fe2737..9bbe89f37 100755 --- a/configure.ac +++ b/configure.ac @@ -272,6 +272,8 @@ AC_ARG_ENABLE(time-check, [ --disable-time-check disable slow thread warning messages]) AC_ARG_ENABLE(pcreposix, [ --enable-pcreposix enable using PCRE Posix libs for regex functions]) +AC_ARG_ENABLE(fpm, +[ --enable-fpm enable Forwarding Plane Manager support]) if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" @@ -292,6 +294,10 @@ if test x"${enable_time_check}" != x"no" ; then fi fi +if test "${enable_fpm}" = "yes"; then + AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) +fi + if test "${enable_broken_aliases}" = "yes"; then if test "${enable_netlink}" = "yes" then @@ -828,6 +834,7 @@ fi AC_SUBST(RT_METHOD) AC_SUBST(KERNEL_METHOD) AC_SUBST(OTHER_METHOD) +AM_CONDITIONAL([HAVE_NETLINK], [test "x$netlink" = "xyes"]) dnl -------------------------- dnl Determine IS-IS I/O method diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 7550173c5..5c325ec26 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -33,7 +33,8 @@ vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/zebra/irdp_interface.c \ $(top_srcdir)/zebra/rtadv.c $(top_srcdir)/zebra/zebra_vty.c \ $(top_srcdir)/zebra/zserv.c $(top_srcdir)/zebra/router-id.c \ - $(top_srcdir)/zebra/zebra_routemap.c + $(top_srcdir)/zebra/zebra_routemap.c \ + $(top_srcdir)/zebra/zebra_fpm.c vtysh_cmd.c: $(vtysh_cmd_FILES) ./$(EXTRA_DIST) $(vtysh_cmd_FILES) > vtysh_cmd.c diff --git a/zebra/Makefile.am b/zebra/Makefile.am index ea962bf4e..266812f83 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -19,6 +19,10 @@ ioctl_method = @IOCTL_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) $(if_proc) \ $(rt_method) $(rtread_method) $(kernel_method) $(other_method) +if HAVE_NETLINK +othersrc = zebra_fpm_netlink.c +endif + AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) @@ -29,7 +33,8 @@ noinst_PROGRAMS = testzebra zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ - irdp_main.c irdp_interface.c irdp_packet.c router-id.c + irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ + $(othersrc) testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c \ diff --git a/zebra/debug.c b/zebra/debug.c index 175029b8a..7bfdb77d9 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -29,6 +29,7 @@ unsigned long zebra_debug_event; unsigned long zebra_debug_packet; unsigned long zebra_debug_kernel; unsigned long zebra_debug_rib; +unsigned long zebra_debug_fpm; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, @@ -71,6 +72,9 @@ DEFUN (show_debugging_zebra, if (IS_ZEBRA_DEBUG_RIB_Q) vty_out (vty, " Zebra RIB queue debugging is on%s", VTY_NEWLINE); + if (IS_ZEBRA_DEBUG_FPM) + vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -169,6 +173,17 @@ DEFUN (debug_zebra_rib_q, return CMD_SUCCESS; } +DEFUN (debug_zebra_fpm, + debug_zebra_fpm_cmd, + "debug zebra fpm", + DEBUG_STR + "Zebra configuration\n" + "Debug zebra FPM events\n") +{ + SET_FLAG (zebra_debug_fpm, ZEBRA_DEBUG_FPM); + return CMD_SUCCESS; +} + DEFUN (no_debug_zebra_events, no_debug_zebra_events_cmd, "no debug zebra events", @@ -247,6 +262,18 @@ DEFUN (no_debug_zebra_rib_q, return CMD_SUCCESS; } +DEFUN (no_debug_zebra_fpm, + no_debug_zebra_fpm_cmd, + "no debug zebra fpm", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug zebra FPM events\n") +{ + zebra_debug_fpm = 0; + return CMD_SUCCESS; +} + /* Debug node. */ struct cmd_node debug_node = { @@ -302,6 +329,11 @@ config_write_debug (struct vty *vty) vty_out (vty, "debug zebra rib queue%s", VTY_NEWLINE); write++; } + if (IS_ZEBRA_DEBUG_FPM) + { + vty_out (vty, "debug zebra fpm%s", VTY_NEWLINE); + write++; + } return write; } @@ -312,6 +344,7 @@ zebra_debug_init (void) zebra_debug_packet = 0; zebra_debug_kernel = 0; zebra_debug_rib = 0; + zebra_debug_fpm = 0; install_node (&debug_node, config_write_debug); @@ -325,11 +358,13 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &debug_zebra_rib_cmd); install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd); + install_element (ENABLE_NODE, &debug_zebra_fpm_cmd); install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd); install_element (ENABLE_NODE, &no_debug_zebra_rib_q_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &debug_zebra_events_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_cmd); @@ -338,9 +373,11 @@ zebra_debug_init (void) install_element (CONFIG_NODE, &debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &debug_zebra_rib_cmd); install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd); + install_element (CONFIG_NODE, &debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd); install_element (CONFIG_NODE, &no_debug_zebra_rib_q_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_fpm_cmd); } diff --git a/zebra/debug.h b/zebra/debug.h index 9d9412bca..d9231a22b 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -36,6 +36,8 @@ #define ZEBRA_DEBUG_RIB 0x01 #define ZEBRA_DEBUG_RIB_Q 0x02 +#define ZEBRA_DEBUG_FPM 0x01 + /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -49,10 +51,13 @@ #define IS_ZEBRA_DEBUG_RIB (zebra_debug_rib & ZEBRA_DEBUG_RIB) #define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q) +#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM) + extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; extern unsigned long zebra_debug_kernel; extern unsigned long zebra_debug_rib; +extern unsigned long zebra_debug_fpm; extern void zebra_debug_init (void); diff --git a/zebra/main.c b/zebra/main.c index 50ac224e2..742e02928 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -39,6 +39,7 @@ #include "zebra/router-id.h" #include "zebra/irdp.h" #include "zebra/rtadv.h" +#include "zebra/zebra_fpm.h" /* Zebra instance */ struct zebra_t zebrad = @@ -349,6 +350,12 @@ main (int argc, char **argv) zebra_snmp_init (); #endif /* HAVE_SNMP */ +#ifdef HAVE_FPM + zfpm_init (zebrad.master, 1, 0); +#else + zfpm_init (zebrad.master, 0, 0); +#endif + /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in diff --git a/zebra/misc_null.c b/zebra/misc_null.c index 735943015..c8cc47d1d 100644 --- a/zebra/misc_null.c +++ b/zebra/misc_null.c @@ -4,8 +4,15 @@ #include "zebra/rtadv.h" #include "zebra/irdp.h" #include "zebra/interface.h" +#include "zebra/zebra_fpm.h" void ifstat_update_proc (void) { return; } #pragma weak rtadv_config_write = ifstat_update_proc #pragma weak irdp_config_write = ifstat_update_proc #pragma weak ifstat_update_sysctl = ifstat_update_proc + +void +zfpm_trigger_update (struct route_node *rn, const char *reason) +{ + return; +} diff --git a/zebra/rib.h b/zebra/rib.h index 4ecfaa0d8..e16ce68a1 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -25,6 +25,7 @@ #include "prefix.h" #include "table.h" +#include "queue.h" #define DISTANCE_INFINITY 255 @@ -116,6 +117,11 @@ typedef struct rib_dest_t_ */ u_int32_t flags; + /* + * Linkage to put dest on the FPM processing queue. + */ + TAILQ_ENTRY(rib_dest_t_) fpm_q_entries; + } rib_dest_t; #define RIB_ROUTE_QUEUED(x) (1 << (x)) @@ -125,6 +131,18 @@ typedef struct rib_dest_t_ */ #define ZEBRA_MAX_QINDEX (MQ_SIZE - 1) +/* + * This flag indicates that a given prefix has been 'advertised' to + * the FPM to be installed in the forwarding plane. + */ +#define RIB_DEST_SENT_TO_FPM (1 << (ZEBRA_MAX_QINDEX + 1)) + +/* + * This flag is set when we need to send an update to the FPM about a + * dest. + */ +#define RIB_DEST_UPDATE_FPM (1 << (ZEBRA_MAX_QINDEX + 2)) + /* * Macro to iterate over each route for a destination (prefix). */ diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c new file mode 100644 index 000000000..e02d17455 --- /dev/null +++ b/zebra/zebra_fpm.c @@ -0,0 +1,1581 @@ +/* + * Main implementation file for interface to Forwarding Plane Manager. + * + * Copyright (C) 2012 by Open Source Routing. + * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "stream.h" +#include "thread.h" +#include "network.h" +#include "command.h" + +#include "zebra/rib.h" + +#include "fpm/fpm.h" +#include "zebra_fpm.h" +#include "zebra_fpm_private.h" + +/* + * Interval at which we attempt to connect to the FPM. + */ +#define ZFPM_CONNECT_RETRY_IVL 5 + +/* + * Sizes of outgoing and incoming stream buffers for writing/reading + * FPM messages. + */ +#define ZFPM_OBUF_SIZE (2 * FPM_MAX_MSG_LEN) +#define ZFPM_IBUF_SIZE (FPM_MAX_MSG_LEN) + +/* + * The maximum number of times the FPM socket write callback can call + * 'write' before it yields. + */ +#define ZFPM_MAX_WRITES_PER_RUN 10 + +/* + * Interval over which we collect statistics. + */ +#define ZFPM_STATS_IVL_SECS 10 + +/* + * Structure that holds state for iterating over all route_node + * structures that are candidates for being communicated to the FPM. + */ +typedef struct zfpm_rnodes_iter_t_ +{ + rib_tables_iter_t tables_iter; + route_table_iter_t iter; +} zfpm_rnodes_iter_t; + +/* + * Statistics. + */ +typedef struct zfpm_stats_t_ { + unsigned long connect_calls; + unsigned long connect_no_sock; + + unsigned long read_cb_calls; + + unsigned long write_cb_calls; + unsigned long write_calls; + unsigned long partial_writes; + unsigned long max_writes_hit; + unsigned long t_write_yields; + + unsigned long nop_deletes_skipped; + unsigned long route_adds; + unsigned long route_dels; + + unsigned long updates_triggered; + unsigned long redundant_triggers; + unsigned long non_fpm_table_triggers; + + unsigned long dests_del_after_update; + + unsigned long t_conn_down_starts; + unsigned long t_conn_down_dests_processed; + unsigned long t_conn_down_yields; + unsigned long t_conn_down_finishes; + + unsigned long t_conn_up_starts; + unsigned long t_conn_up_dests_processed; + unsigned long t_conn_up_yields; + unsigned long t_conn_up_aborts; + unsigned long t_conn_up_finishes; + +} zfpm_stats_t; + +/* + * States for the FPM state machine. + */ +typedef enum { + + /* + * In this state we are not yet ready to connect to the FPM. This + * can happen when this module is disabled, or if we're cleaning up + * after a connection has gone down. + */ + ZFPM_STATE_IDLE, + + /* + * Ready to talk to the FPM and periodically trying to connect to + * it. + */ + ZFPM_STATE_ACTIVE, + + /* + * In the middle of bringing up a TCP connection. Specifically, + * waiting for a connect() call to complete asynchronously. + */ + ZFPM_STATE_CONNECTING, + + /* + * TCP connection to the FPM is up. + */ + ZFPM_STATE_ESTABLISHED + +} zfpm_state_t; + +/* + * Globals. + */ +typedef struct zfpm_glob_t_ +{ + + /* + * True if the FPM module has been enabled. + */ + int enabled; + + struct thread_master *master; + + zfpm_state_t state; + + /* + * Port on which the FPM is running. + */ + int fpm_port; + + /* + * List of rib_dest_t structures to be processed + */ + TAILQ_HEAD (zfpm_dest_q, rib_dest_t_) dest_q; + + /* + * Stream socket to the FPM. + */ + int sock; + + /* + * Buffers for messages to/from the FPM. + */ + struct stream *obuf; + struct stream *ibuf; + + /* + * Threads for I/O. + */ + struct thread *t_connect; + struct thread *t_write; + struct thread *t_read; + + /* + * Thread to clean up after the TCP connection to the FPM goes down + * and the state that belongs to it. + */ + struct thread *t_conn_down; + + struct { + zfpm_rnodes_iter_t iter; + } t_conn_down_state; + + /* + * Thread to take actions once the TCP conn to the FPM comes up, and + * the state that belongs to it. + */ + struct thread *t_conn_up; + + struct { + zfpm_rnodes_iter_t iter; + } t_conn_up_state; + + unsigned long connect_calls; + time_t last_connect_call_time; + + /* + * Stats from the start of the current statistics interval up to + * now. These are the counters we typically update in the code. + */ + zfpm_stats_t stats; + + /* + * Statistics that were gathered in the last collection interval. + */ + zfpm_stats_t last_ivl_stats; + + /* + * Cumulative stats from the last clear to the start of the current + * statistics interval. + */ + zfpm_stats_t cumulative_stats; + + /* + * Stats interval timer. + */ + struct thread *t_stats; + + /* + * If non-zero, the last time when statistics were cleared. + */ + time_t last_stats_clear_time; + +} zfpm_glob_t; + +static zfpm_glob_t zfpm_glob_space; +static zfpm_glob_t *zfpm_g = &zfpm_glob_space; + +static int zfpm_read_cb (struct thread *thread); +static int zfpm_write_cb (struct thread *thread); + +static void zfpm_set_state (zfpm_state_t state, const char *reason); +static void zfpm_start_connect_timer (const char *reason); +static void zfpm_start_stats_timer (void); + +/* + * zfpm_thread_should_yield + */ +static inline int +zfpm_thread_should_yield (struct thread *t) +{ + return thread_should_yield (t); +} + +/* + * zfpm_state_to_str + */ +static const char * +zfpm_state_to_str (zfpm_state_t state) +{ + switch (state) + { + + case ZFPM_STATE_IDLE: + return "idle"; + + case ZFPM_STATE_ACTIVE: + return "active"; + + case ZFPM_STATE_CONNECTING: + return "connecting"; + + case ZFPM_STATE_ESTABLISHED: + return "established"; + + default: + return "unknown"; + } +} + +/* + * zfpm_get_time + */ +static time_t +zfpm_get_time (void) +{ + struct timeval tv; + + if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0) + zlog_warn ("FPM: quagga_gettime failed!!"); + + return tv.tv_sec; +} + +/* + * zfpm_get_elapsed_time + * + * Returns the time elapsed (in seconds) since the given time. + */ +static time_t +zfpm_get_elapsed_time (time_t reference) +{ + time_t now; + + now = zfpm_get_time (); + + if (now < reference) + { + assert (0); + return 0; + } + + return now - reference; +} + +/* + * zfpm_is_table_for_fpm + * + * Returns TRUE if the the given table is to be communicated to the + * FPM. + */ +static inline int +zfpm_is_table_for_fpm (struct route_table *table) +{ + rib_table_info_t *info; + + info = rib_table_info (table); + + /* + * We only send the unicast tables in the main instance to the FPM + * at this point. + */ + if (info->vrf->id != 0) + return 0; + + if (info->safi != SAFI_UNICAST) + return 0; + + return 1; +} + +/* + * zfpm_rnodes_iter_init + */ +static inline void +zfpm_rnodes_iter_init (zfpm_rnodes_iter_t *iter) +{ + memset (iter, 0, sizeof (*iter)); + rib_tables_iter_init (&iter->tables_iter); + + /* + * This is a hack, but it makes implementing 'next' easier by + * ensuring that route_table_iter_next() will return NULL the first + * time we call it. + */ + route_table_iter_init (&iter->iter, NULL); + route_table_iter_cleanup (&iter->iter); +} + +/* + * zfpm_rnodes_iter_next + */ +static inline struct route_node * +zfpm_rnodes_iter_next (zfpm_rnodes_iter_t *iter) +{ + struct route_node *rn; + struct route_table *table; + + while (1) + { + rn = route_table_iter_next (&iter->iter); + if (rn) + return rn; + + /* + * We've made our way through this table, go to the next one. + */ + route_table_iter_cleanup (&iter->iter); + + while ((table = rib_tables_iter_next (&iter->tables_iter))) + { + if (zfpm_is_table_for_fpm (table)) + break; + } + + if (!table) + return NULL; + + route_table_iter_init (&iter->iter, table); + } + + return NULL; +} + +/* + * zfpm_rnodes_iter_pause + */ +static inline void +zfpm_rnodes_iter_pause (zfpm_rnodes_iter_t *iter) +{ + route_table_iter_pause (&iter->iter); +} + +/* + * zfpm_rnodes_iter_cleanup + */ +static inline void +zfpm_rnodes_iter_cleanup (zfpm_rnodes_iter_t *iter) +{ + route_table_iter_cleanup (&iter->iter); + rib_tables_iter_cleanup (&iter->tables_iter); +} + +/* + * zfpm_stats_init + * + * Initialize a statistics block. + */ +static inline void +zfpm_stats_init (zfpm_stats_t *stats) +{ + memset (stats, 0, sizeof (*stats)); +} + +/* + * zfpm_stats_reset + */ +static inline void +zfpm_stats_reset (zfpm_stats_t *stats) +{ + zfpm_stats_init (stats); +} + +/* + * zfpm_stats_copy + */ +static inline void +zfpm_stats_copy (const zfpm_stats_t *src, zfpm_stats_t *dest) +{ + memcpy (dest, src, sizeof (*dest)); +} + +/* + * zfpm_stats_compose + * + * Total up the statistics in two stats structures ('s1 and 's2') and + * return the result in the third argument, 'result'. Note that the + * pointer 'result' may be the same as 's1' or 's2'. + * + * For simplicity, the implementation below assumes that the stats + * structure is composed entirely of counters. This can easily be + * changed when necessary. + */ +static void +zfpm_stats_compose (const zfpm_stats_t *s1, const zfpm_stats_t *s2, + zfpm_stats_t *result) +{ + const unsigned long *p1, *p2; + unsigned long *result_p; + int i, num_counters; + + p1 = (const unsigned long *) s1; + p2 = (const unsigned long *) s2; + result_p = (unsigned long *) result; + + num_counters = (sizeof (zfpm_stats_t) / sizeof (unsigned long)); + + for (i = 0; i < num_counters; i++) + { + result_p[i] = p1[i] + p2[i]; + } +} + +/* + * zfpm_read_on + */ +static inline void +zfpm_read_on (void) +{ + assert (!zfpm_g->t_read); + assert (zfpm_g->sock >= 0); + + THREAD_READ_ON (zfpm_g->master, zfpm_g->t_read, zfpm_read_cb, 0, + zfpm_g->sock); +} + +/* + * zfpm_write_on + */ +static inline void +zfpm_write_on (void) +{ + assert (!zfpm_g->t_write); + assert (zfpm_g->sock >= 0); + + THREAD_WRITE_ON (zfpm_g->master, zfpm_g->t_write, zfpm_write_cb, 0, + zfpm_g->sock); +} + +/* + * zfpm_read_off + */ +static inline void +zfpm_read_off (void) +{ + THREAD_READ_OFF (zfpm_g->t_read); +} + +/* + * zfpm_write_off + */ +static inline void +zfpm_write_off (void) +{ + THREAD_WRITE_OFF (zfpm_g->t_write); +} + +/* + * zfpm_conn_up_thread_cb + * + * Callback for actions to be taken when the connection to the FPM + * comes up. + */ +static int +zfpm_conn_up_thread_cb (struct thread *thread) +{ + struct route_node *rnode; + zfpm_rnodes_iter_t *iter; + rib_dest_t *dest; + + assert (zfpm_g->t_conn_up); + zfpm_g->t_conn_up = NULL; + + iter = &zfpm_g->t_conn_up_state.iter; + + if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) + { + zfpm_debug ("Connection not up anymore, conn_up thread aborting"); + zfpm_g->stats.t_conn_up_aborts++; + goto done; + } + + while ((rnode = zfpm_rnodes_iter_next (iter))) + { + dest = rib_dest_from_rnode (rnode); + + if (dest) + { + zfpm_g->stats.t_conn_up_dests_processed++; + zfpm_trigger_update (rnode, NULL); + } + + /* + * Yield if need be. + */ + if (!zfpm_thread_should_yield (thread)) + continue; + + zfpm_g->stats.t_conn_up_yields++; + zfpm_rnodes_iter_pause (iter); + zfpm_g->t_conn_up = thread_add_background (zfpm_g->master, + zfpm_conn_up_thread_cb, + 0, 0); + return 0; + } + + zfpm_g->stats.t_conn_up_finishes++; + + done: + zfpm_rnodes_iter_cleanup (iter); + return 0; +} + +/* + * zfpm_connection_up + * + * Called when the connection to the FPM comes up. + */ +static void +zfpm_connection_up (const char *detail) +{ + assert (zfpm_g->sock >= 0); + zfpm_read_on (); + zfpm_write_on (); + zfpm_set_state (ZFPM_STATE_ESTABLISHED, detail); + + /* + * Start thread to push existing routes to the FPM. + */ + assert (!zfpm_g->t_conn_up); + + zfpm_rnodes_iter_init (&zfpm_g->t_conn_up_state.iter); + + zfpm_debug ("Starting conn_up thread"); + zfpm_g->t_conn_up = thread_add_background (zfpm_g->master, + zfpm_conn_up_thread_cb, 0, 0); + zfpm_g->stats.t_conn_up_starts++; +} + +/* + * zfpm_connect_check + * + * Check if an asynchronous connect() to the FPM is complete. + */ +static void +zfpm_connect_check () +{ + int status; + socklen_t slen; + int ret; + + zfpm_read_off (); + zfpm_write_off (); + + slen = sizeof (status); + ret = getsockopt (zfpm_g->sock, SOL_SOCKET, SO_ERROR, (void *) &status, + &slen); + + if (ret >= 0 && status == 0) + { + zfpm_connection_up ("async connect complete"); + return; + } + + /* + * getsockopt() failed or indicated an error on the socket. + */ + close (zfpm_g->sock); + zfpm_g->sock = -1; + + zfpm_start_connect_timer ("getsockopt() after async connect failed"); + return; +} + +/* + * zfpm_conn_down_thread_cb + * + * Callback that is invoked to clean up state after the TCP connection + * to the FPM goes down. + */ +static int +zfpm_conn_down_thread_cb (struct thread *thread) +{ + struct route_node *rnode; + zfpm_rnodes_iter_t *iter; + rib_dest_t *dest; + + assert (zfpm_g->state == ZFPM_STATE_IDLE); + + assert (zfpm_g->t_conn_down); + zfpm_g->t_conn_down = NULL; + + iter = &zfpm_g->t_conn_down_state.iter; + + while ((rnode = zfpm_rnodes_iter_next (iter))) + { + dest = rib_dest_from_rnode (rnode); + + if (dest) + { + if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) + { + TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries); + } + + UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); + UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); + + zfpm_g->stats.t_conn_down_dests_processed++; + + /* + * Check if the dest should be deleted. + */ + rib_gc_dest(rnode); + } + + /* + * Yield if need be. + */ + if (!zfpm_thread_should_yield (thread)) + continue; + + zfpm_g->stats.t_conn_down_yields++; + zfpm_rnodes_iter_pause (iter); + zfpm_g->t_conn_down = thread_add_background (zfpm_g->master, + zfpm_conn_down_thread_cb, + 0, 0); + return 0; + } + + zfpm_g->stats.t_conn_down_finishes++; + zfpm_rnodes_iter_cleanup (iter); + + /* + * Start the process of connecting to the FPM again. + */ + zfpm_start_connect_timer ("cleanup complete"); + return 0; +} + +/* + * zfpm_connection_down + * + * Called when the connection to the FPM has gone down. + */ +static void +zfpm_connection_down (const char *detail) +{ + if (!detail) + detail = "unknown"; + + assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); + + zlog_info ("connection to the FPM has gone down: %s", detail); + + zfpm_read_off (); + zfpm_write_off (); + + stream_reset (zfpm_g->ibuf); + stream_reset (zfpm_g->obuf); + + if (zfpm_g->sock >= 0) { + close (zfpm_g->sock); + zfpm_g->sock = -1; + } + + /* + * Start thread to clean up state after the connection goes down. + */ + assert (!zfpm_g->t_conn_down); + zfpm_debug ("Starting conn_down thread"); + zfpm_rnodes_iter_init (&zfpm_g->t_conn_down_state.iter); + zfpm_g->t_conn_down = thread_add_background (zfpm_g->master, + zfpm_conn_down_thread_cb, 0, 0); + zfpm_g->stats.t_conn_down_starts++; + + zfpm_set_state (ZFPM_STATE_IDLE, detail); +} + +/* + * zfpm_read_cb + */ +static int +zfpm_read_cb (struct thread *thread) +{ + size_t already; + struct stream *ibuf; + uint16_t msg_len; + fpm_msg_hdr_t *hdr; + + zfpm_g->stats.read_cb_calls++; + assert (zfpm_g->t_read); + zfpm_g->t_read = NULL; + + /* + * Check if async connect is now done. + */ + if (zfpm_g->state == ZFPM_STATE_CONNECTING) + { + zfpm_connect_check(); + return 0; + } + + assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); + assert (zfpm_g->sock >= 0); + + ibuf = zfpm_g->ibuf; + + already = stream_get_endp (ibuf); + if (already < FPM_MSG_HDR_LEN) + { + ssize_t nbyte; + + nbyte = stream_read_try (ibuf, zfpm_g->sock, FPM_MSG_HDR_LEN - already); + if (nbyte == 0 || nbyte == -1) + { + zfpm_connection_down ("closed socket in read"); + return 0; + } + + if (nbyte != (ssize_t) (FPM_MSG_HDR_LEN - already)) + goto done; + + already = FPM_MSG_HDR_LEN; + } + + stream_set_getp (ibuf, 0); + + hdr = (fpm_msg_hdr_t *) stream_pnt (ibuf); + + if (!fpm_msg_hdr_ok (hdr)) + { + zfpm_connection_down ("invalid message header"); + return 0; + } + + msg_len = fpm_msg_len (hdr); + + /* + * Read out the rest of the packet. + */ + if (already < msg_len) + { + ssize_t nbyte; + + nbyte = stream_read_try (ibuf, zfpm_g->sock, msg_len - already); + + if (nbyte == 0 || nbyte == -1) + { + zfpm_connection_down ("failed to read message"); + return 0; + } + + if (nbyte != (ssize_t) (msg_len - already)) + goto done; + } + + zfpm_debug ("Read out a full fpm message"); + + /* + * Just throw it away for now. + */ + stream_reset (ibuf); + + done: + zfpm_read_on (); + return 0; +} + +/* + * zfpm_writes_pending + * + * Returns TRUE if we may have something to write to the FPM. + */ +static int +zfpm_writes_pending (void) +{ + + /* + * Check if there is any data in the outbound buffer that has not + * been written to the socket yet. + */ + if (stream_get_endp (zfpm_g->obuf) - stream_get_getp (zfpm_g->obuf)) + return 1; + + /* + * Check if there are any prefixes on the outbound queue. + */ + if (!TAILQ_EMPTY (&zfpm_g->dest_q)) + return 1; + + return 0; +} + +/* + * zfpm_encode_route + * + * Encode a message to the FPM with information about the given route. + * + * Returns the number of bytes written to the buffer. 0 or a negative + * value indicates an error. + */ +static inline int +zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf, + size_t in_buf_len) +{ +#ifndef HAVE_NETLINK + return 0; +#else + + int cmd; + + cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE; + + return zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len); + +#endif /* HAVE_NETLINK */ +} + +/* + * zfpm_route_for_update + * + * Returns the rib that is to be sent to the FPM for a given dest. + */ +static struct rib * +zfpm_route_for_update (rib_dest_t *dest) +{ + struct rib *rib; + + RIB_DEST_FOREACH_ROUTE (dest, rib) + { + if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + continue; + + return rib; + } + + /* + * We have no route for this destination. + */ + return NULL; +} + +/* + * zfpm_build_updates + * + * Process the outgoing queue and write messages to the outbound + * buffer. + */ +static void +zfpm_build_updates (void) +{ + struct stream *s; + rib_dest_t *dest; + unsigned char *buf, *data, *buf_end; + size_t msg_len; + size_t data_len; + fpm_msg_hdr_t *hdr; + struct rib *rib; + int is_add, write_msg; + + s = zfpm_g->obuf; + + assert (stream_empty (s)); + + do { + + /* + * Make sure there is enough space to write another message. + */ + if (STREAM_WRITEABLE (s) < FPM_MAX_MSG_LEN) + break; + + buf = STREAM_DATA (s) + stream_get_endp (s); + buf_end = buf + STREAM_WRITEABLE (s); + + dest = TAILQ_FIRST (&zfpm_g->dest_q); + if (!dest) + break; + + assert (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)); + + hdr = (fpm_msg_hdr_t *) buf; + hdr->version = FPM_PROTO_VERSION; + hdr->msg_type = FPM_MSG_TYPE_NETLINK; + + data = fpm_msg_data (hdr); + + rib = zfpm_route_for_update (dest); + is_add = rib ? 1 : 0; + + write_msg = 1; + + /* + * If this is a route deletion, and we have not sent the route to + * the FPM previously, skip it. + */ + if (!is_add && !CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM)) + { + write_msg = 0; + zfpm_g->stats.nop_deletes_skipped++; + } + + if (write_msg) { + data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data); + + assert (data_len); + if (data_len) + { + msg_len = fpm_data_len_to_msg_len (data_len); + hdr->msg_len = htons (msg_len); + stream_forward_endp (s, msg_len); + + if (is_add) + zfpm_g->stats.route_adds++; + else + zfpm_g->stats.route_dels++; + } + } + + /* + * Remove the dest from the queue, and reset the flag. + */ + UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); + TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries); + + if (is_add) + { + SET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); + } + else + { + UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); + } + + /* + * Delete the destination if necessary. + */ + if (rib_gc_dest (dest->rnode)) + zfpm_g->stats.dests_del_after_update++; + + } while (1); + +} + +/* + * zfpm_write_cb + */ +static int +zfpm_write_cb (struct thread *thread) +{ + struct stream *s; + int num_writes; + + zfpm_g->stats.write_cb_calls++; + assert (zfpm_g->t_write); + zfpm_g->t_write = NULL; + + /* + * Check if async connect is now done. + */ + if (zfpm_g->state == ZFPM_STATE_CONNECTING) + { + zfpm_connect_check (); + return 0; + } + + assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); + assert (zfpm_g->sock >= 0); + + num_writes = 0; + + do + { + int bytes_to_write, bytes_written; + + s = zfpm_g->obuf; + + /* + * If the stream is empty, try fill it up with data. + */ + if (stream_empty (s)) + { + zfpm_build_updates (); + } + + bytes_to_write = stream_get_endp (s) - stream_get_getp (s); + if (!bytes_to_write) + break; + + bytes_written = write (zfpm_g->sock, STREAM_PNT (s), bytes_to_write); + zfpm_g->stats.write_calls++; + num_writes++; + + if (bytes_written < 0) + { + if (ERRNO_IO_RETRY (errno)) + break; + + zfpm_connection_down ("failed to write to socket"); + return 0; + } + + if (bytes_written != bytes_to_write) + { + + /* + * Partial write. + */ + stream_forward_getp (s, bytes_written); + zfpm_g->stats.partial_writes++; + break; + } + + /* + * We've written out the entire contents of the stream. + */ + stream_reset (s); + + if (num_writes >= ZFPM_MAX_WRITES_PER_RUN) + { + zfpm_g->stats.max_writes_hit++; + break; + } + + if (zfpm_thread_should_yield (thread)) + { + zfpm_g->stats.t_write_yields++; + break; + } + } while (1); + + if (zfpm_writes_pending ()) + zfpm_write_on (); + + return 0; +} + +/* + * zfpm_connect_cb + */ +static int +zfpm_connect_cb (struct thread *t) +{ + int sock, ret; + struct sockaddr_in serv; + + assert (zfpm_g->t_connect); + zfpm_g->t_connect = NULL; + assert (zfpm_g->state == ZFPM_STATE_ACTIVE); + + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + zfpm_debug ("Failed to create socket for connect(): %s", strerror(errno)); + zfpm_g->stats.connect_no_sock++; + return 0; + } + + set_nonblocking(sock); + + /* Make server socket. */ + memset (&serv, 0, sizeof (serv)); + serv.sin_family = AF_INET; + serv.sin_port = htons (zfpm_g->fpm_port); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + serv.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* + * Connect to the FPM. + */ + zfpm_g->connect_calls++; + zfpm_g->stats.connect_calls++; + zfpm_g->last_connect_call_time = zfpm_get_time (); + + ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); + if (ret >= 0) + { + zfpm_g->sock = sock; + zfpm_connection_up ("connect succeeded"); + return 1; + } + + if (errno == EINPROGRESS) + { + zfpm_g->sock = sock; + zfpm_read_on (); + zfpm_write_on (); + zfpm_set_state (ZFPM_STATE_CONNECTING, "async connect in progress"); + return 0; + } + + zlog_info ("can't connect to FPM %d: %s", sock, safe_strerror (errno)); + close (sock); + + /* + * Restart timer for retrying connection. + */ + zfpm_start_connect_timer ("connect() failed"); + return 0; +} + +/* + * zfpm_set_state + * + * Move state machine into the given state. + */ +static void +zfpm_set_state (zfpm_state_t state, const char *reason) +{ + zfpm_state_t cur_state = zfpm_g->state; + + if (!reason) + reason = "Unknown"; + + if (state == cur_state) + return; + + zfpm_debug("beginning state transition %s -> %s. Reason: %s", + zfpm_state_to_str (cur_state), zfpm_state_to_str (state), + reason); + + switch (state) { + + case ZFPM_STATE_IDLE: + assert (cur_state == ZFPM_STATE_ESTABLISHED); + break; + + case ZFPM_STATE_ACTIVE: + assert (cur_state == ZFPM_STATE_IDLE || + cur_state == ZFPM_STATE_CONNECTING); + assert (zfpm_g->t_connect); + break; + + case ZFPM_STATE_CONNECTING: + assert (zfpm_g->sock); + assert (cur_state == ZFPM_STATE_ACTIVE); + assert (zfpm_g->t_read); + assert (zfpm_g->t_write); + break; + + case ZFPM_STATE_ESTABLISHED: + assert (cur_state == ZFPM_STATE_ACTIVE || + cur_state == ZFPM_STATE_CONNECTING); + assert (zfpm_g->sock); + assert (zfpm_g->t_read); + assert (zfpm_g->t_write); + break; + } + + zfpm_g->state = state; +} + +/* + * zfpm_calc_connect_delay + * + * Returns the number of seconds after which we should attempt to + * reconnect to the FPM. + */ +static long +zfpm_calc_connect_delay (void) +{ + time_t elapsed; + + /* + * Return 0 if this is our first attempt to connect. + */ + if (zfpm_g->connect_calls == 0) + { + return 0; + } + + elapsed = zfpm_get_elapsed_time (zfpm_g->last_connect_call_time); + + if (elapsed > ZFPM_CONNECT_RETRY_IVL) { + return 0; + } + + return ZFPM_CONNECT_RETRY_IVL - elapsed; +} + +/* + * zfpm_start_connect_timer + */ +static void +zfpm_start_connect_timer (const char *reason) +{ + long delay_secs; + + assert (!zfpm_g->t_connect); + assert (zfpm_g->sock < 0); + + assert(zfpm_g->state == ZFPM_STATE_IDLE || + zfpm_g->state == ZFPM_STATE_ACTIVE || + zfpm_g->state == ZFPM_STATE_CONNECTING); + + delay_secs = zfpm_calc_connect_delay(); + zfpm_debug ("scheduling connect in %ld seconds", delay_secs); + + THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_connect, zfpm_connect_cb, 0, + delay_secs); + zfpm_set_state (ZFPM_STATE_ACTIVE, reason); +} + +/* + * zfpm_is_enabled + * + * Returns TRUE if the zebra FPM module has been enabled. + */ +static inline int +zfpm_is_enabled (void) +{ + return zfpm_g->enabled; +} + +/* + * zfpm_conn_is_up + * + * Returns TRUE if the connection to the FPM is up. + */ +static inline int +zfpm_conn_is_up (void) +{ + if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) + return 0; + + assert (zfpm_g->sock >= 0); + + return 1; +} + +/* + * zfpm_trigger_update + * + * The zebra code invokes this function to indicate that we should + * send an update to the FPM about the given route_node. + */ +void +zfpm_trigger_update (struct route_node *rn, const char *reason) +{ + rib_dest_t *dest; + char buf[INET6_ADDRSTRLEN]; + + /* + * Ignore if the connection is down. We will update the FPM about + * all destinations once the connection comes up. + */ + if (!zfpm_conn_is_up ()) + return; + + dest = rib_dest_from_rnode (rn); + + /* + * Ignore the trigger if the dest is not in a table that we would + * send to the FPM. + */ + if (!zfpm_is_table_for_fpm (rib_dest_table (dest))) + { + zfpm_g->stats.non_fpm_table_triggers++; + return; + } + + if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { + zfpm_g->stats.redundant_triggers++; + return; + } + + if (reason) + { + zfpm_debug ("%s/%d triggering update to FPM - Reason: %s", + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)), + rn->p.prefixlen, reason); + } + + SET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); + TAILQ_INSERT_TAIL (&zfpm_g->dest_q, dest, fpm_q_entries); + zfpm_g->stats.updates_triggered++; + + /* + * Make sure that writes are enabled. + */ + if (zfpm_g->t_write) + return; + + zfpm_write_on (); +} + +/* + * zfpm_stats_timer_cb + */ +static int +zfpm_stats_timer_cb (struct thread *t) +{ + assert (zfpm_g->t_stats); + zfpm_g->t_stats = NULL; + + /* + * Remember the stats collected in the last interval for display + * purposes. + */ + zfpm_stats_copy (&zfpm_g->stats, &zfpm_g->last_ivl_stats); + + /* + * Add the current set of stats into the cumulative statistics. + */ + zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats, + &zfpm_g->cumulative_stats); + + /* + * Start collecting stats afresh over the next interval. + */ + zfpm_stats_reset (&zfpm_g->stats); + + zfpm_start_stats_timer (); + + return 0; +} + +/* + * zfpm_stop_stats_timer + */ +static void +zfpm_stop_stats_timer (void) +{ + if (!zfpm_g->t_stats) + return; + + zfpm_debug ("Stopping existing stats timer"); + THREAD_TIMER_OFF (zfpm_g->t_stats); +} + +/* + * zfpm_start_stats_timer + */ +void +zfpm_start_stats_timer (void) +{ + assert (!zfpm_g->t_stats); + + THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_stats, zfpm_stats_timer_cb, 0, + ZFPM_STATS_IVL_SECS); +} + +/* + * Helper macro for zfpm_show_stats() below. + */ +#define ZFPM_SHOW_STAT(counter) \ + do { \ + vty_out (vty, "%-40s %10lu %16lu%s", #counter, total_stats.counter, \ + zfpm_g->last_ivl_stats.counter, VTY_NEWLINE); \ + } while (0) + +/* + * zfpm_show_stats + */ +static void +zfpm_show_stats (struct vty *vty) +{ + zfpm_stats_t total_stats; + time_t elapsed; + + vty_out (vty, "%s%-40s %10s Last %2d secs%s%s", VTY_NEWLINE, "Counter", + "Total", ZFPM_STATS_IVL_SECS, VTY_NEWLINE, VTY_NEWLINE); + + /* + * Compute the total stats up to this instant. + */ + zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats, + &total_stats); + + ZFPM_SHOW_STAT (connect_calls); + ZFPM_SHOW_STAT (connect_no_sock); + ZFPM_SHOW_STAT (read_cb_calls); + ZFPM_SHOW_STAT (write_cb_calls); + ZFPM_SHOW_STAT (write_calls); + ZFPM_SHOW_STAT (partial_writes); + ZFPM_SHOW_STAT (max_writes_hit); + ZFPM_SHOW_STAT (t_write_yields); + ZFPM_SHOW_STAT (nop_deletes_skipped); + ZFPM_SHOW_STAT (route_adds); + ZFPM_SHOW_STAT (route_dels); + ZFPM_SHOW_STAT (updates_triggered); + ZFPM_SHOW_STAT (non_fpm_table_triggers); + ZFPM_SHOW_STAT (redundant_triggers); + ZFPM_SHOW_STAT (dests_del_after_update); + ZFPM_SHOW_STAT (t_conn_down_starts); + ZFPM_SHOW_STAT (t_conn_down_dests_processed); + ZFPM_SHOW_STAT (t_conn_down_yields); + ZFPM_SHOW_STAT (t_conn_down_finishes); + ZFPM_SHOW_STAT (t_conn_up_starts); + ZFPM_SHOW_STAT (t_conn_up_dests_processed); + ZFPM_SHOW_STAT (t_conn_up_yields); + ZFPM_SHOW_STAT (t_conn_up_aborts); + ZFPM_SHOW_STAT (t_conn_up_finishes); + + if (!zfpm_g->last_stats_clear_time) + return; + + elapsed = zfpm_get_elapsed_time (zfpm_g->last_stats_clear_time); + + vty_out (vty, "%sStats were cleared %lu seconds ago%s", VTY_NEWLINE, + (unsigned long) elapsed, VTY_NEWLINE); +} + +/* + * zfpm_clear_stats + */ +static void +zfpm_clear_stats (struct vty *vty) +{ + if (!zfpm_is_enabled ()) + { + vty_out (vty, "The FPM module is not enabled...%s", VTY_NEWLINE); + return; + } + + zfpm_stats_reset (&zfpm_g->stats); + zfpm_stats_reset (&zfpm_g->last_ivl_stats); + zfpm_stats_reset (&zfpm_g->cumulative_stats); + + zfpm_stop_stats_timer (); + zfpm_start_stats_timer (); + + zfpm_g->last_stats_clear_time = zfpm_get_time(); + + vty_out (vty, "Cleared FPM stats%s", VTY_NEWLINE); +} + +/* + * show_zebra_fpm_stats + */ +DEFUN (show_zebra_fpm_stats, + show_zebra_fpm_stats_cmd, + "show zebra fpm stats", + SHOW_STR + "Zebra information\n" + "Forwarding Path Manager information\n" + "Statistics\n") +{ + zfpm_show_stats (vty); + return CMD_SUCCESS; +} + +/* + * clear_zebra_fpm_stats + */ +DEFUN (clear_zebra_fpm_stats, + clear_zebra_fpm_stats_cmd, + "clear zebra fpm stats", + CLEAR_STR + "Zebra information\n" + "Clear Forwarding Path Manager information\n" + "Statistics\n") +{ + zfpm_clear_stats (vty); + return CMD_SUCCESS; +} + +/** + * zfpm_init + * + * One-time initialization of the Zebra FPM module. + * + * @param[in] port port at which FPM is running. + * @param[in] enable TRUE if the zebra FPM module should be enabled + * + * Returns TRUE on success. + */ +int +zfpm_init (struct thread_master *master, int enable, uint16_t port) +{ + static int initialized = 0; + + if (initialized) { + return 1; + } + + initialized = 1; + + memset (zfpm_g, 0, sizeof (*zfpm_g)); + zfpm_g->master = master; + TAILQ_INIT(&zfpm_g->dest_q); + zfpm_g->sock = -1; + zfpm_g->state = ZFPM_STATE_IDLE; + + /* + * Netlink must currently be available for the Zebra-FPM interface + * to be enabled. + */ +#ifndef HAVE_NETLINK + enable = 0; +#endif + + zfpm_g->enabled = enable; + + zfpm_stats_init (&zfpm_g->stats); + zfpm_stats_init (&zfpm_g->last_ivl_stats); + zfpm_stats_init (&zfpm_g->cumulative_stats); + + install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd); + install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd); + + if (!enable) { + return 1; + } + + if (!port) + port = FPM_DEFAULT_PORT; + + zfpm_g->fpm_port = port; + + zfpm_g->obuf = stream_new (ZFPM_OBUF_SIZE); + zfpm_g->ibuf = stream_new (ZFPM_IBUF_SIZE); + + zfpm_start_stats_timer (); + zfpm_start_connect_timer ("initialized"); + + return 1; +} diff --git a/zebra/zebra_fpm.h b/zebra/zebra_fpm.h new file mode 100644 index 000000000..44dec0286 --- /dev/null +++ b/zebra/zebra_fpm.h @@ -0,0 +1,34 @@ +/* + * Header file exported by the zebra FPM module to zebra. + * + * Copyright (C) 2012 by Open Source Routing. + * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_FPM_H +#define _ZEBRA_FPM_H + +/* + * Externs. + */ +extern int zfpm_init (struct thread_master *master, int enable, uint16_t port); +extern void zfpm_trigger_update (struct route_node *rn, const char *reason); + +#endif /* _ZEBRA_FPM_H */ diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c new file mode 100644 index 000000000..90d3afb2f --- /dev/null +++ b/zebra/zebra_fpm_netlink.c @@ -0,0 +1,552 @@ +/* + * Code for encoding/decoding FPM messages that are in netlink format. + * + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * Copyright (C) 2012 by Open Source Routing. + * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "rib.h" + +#include "rt_netlink.h" + +#include "zebra_fpm_private.h" + +/* + * addr_to_a + * + * Returns string representation of an address of the given AF. + */ +static inline const char * +addr_to_a (u_char af, void *addr) +{ + if (!addr) + return ""; + + switch (af) + { + + case AF_INET: + return inet_ntoa (*((struct in_addr *) addr)); + +#ifdef HAVE_IPV6 + case AF_INET6: + return inet6_ntoa (*((struct in6_addr *) addr)); +#endif + + default: + return ""; + } +} + +/* + * prefix_addr_to_a + * + * Convience wrapper that returns a human-readable string for the + * address in a prefix. + */ +static const char * +prefix_addr_to_a (struct prefix *prefix) +{ + if (!prefix) + return ""; + + return addr_to_a (prefix->family, &prefix->u.prefix); +} + +/* + * af_addr_size + * + * The size of an address in a given address family. + */ +static size_t +af_addr_size (u_char af) +{ + switch (af) + { + + case AF_INET: + return 4; + +#ifdef HAVE_IPV6 + case AF_INET6: + return 16; +#endif + + default: + assert(0); + return 16; + } +} + +/* + * netlink_nh_info_t + * + * Holds information about a single nexthop for netlink. These info + * structures are transient and may contain pointers into rib + * data structures for convenience. + */ +typedef struct netlink_nh_info_t_ +{ + uint32_t if_index; + union g_addr *gateway; + + /* + * Information from the struct nexthop from which this nh was + * derived. For debug purposes only. + */ + int recursive; + enum nexthop_types_t type; +} netlink_nh_info_t; + +/* + * netlink_route_info_t + * + * A structure for holding information for a netlink route message. + */ +typedef struct netlink_route_info_t_ +{ + uint16_t nlmsg_type; + u_char rtm_type; + uint32_t rtm_table; + u_char rtm_protocol; + u_char af; + struct prefix *prefix; + uint32_t *metric; + int num_nhs; + + /* + * Nexthop structures. We keep things simple for now by enforcing a + * maximum of 64 in case MULTIPATH_NUM is 0; + */ + netlink_nh_info_t nhs[MAX (MULTIPATH_NUM, 64)]; + union g_addr *pref_src; +} netlink_route_info_t; + +/* + * netlink_route_info_add_nh + * + * Add information about the given nexthop to the given route info + * structure. + * + * Returns TRUE if a nexthop was added, FALSE otherwise. + */ +static int +netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop) +{ + netlink_nh_info_t nhi; + union g_addr *src; + + memset (&nhi, 0, sizeof (nhi)); + src = NULL; + + if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs)) + return 0; + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + nhi.recursive = 1; + nhi.type = nexthop->rtype; + + 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 + || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) + { + nhi.if_index = nexthop->rifindex; + if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFINDEX) + && nexthop->src.ipv4.s_addr) + src = &nexthop->src; + } + + goto done; + } + + nhi.recursive = 0; + nhi.type = nexthop->type; + + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + { + nhi.gateway = &nexthop->gate; + if (nexthop->src.ipv4.s_addr) + src = &nexthop->src; + } + +#ifdef HAVE_IPV6 + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + { + nhi.gateway = &nexthop->gate; + } +#endif /* HAVE_IPV6 */ + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + { + nhi.if_index = nexthop->ifindex; + + if (nexthop->src.ipv4.s_addr) + src = &nexthop->src; + } + else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + { + nhi.if_index = nexthop->ifindex; + } + + /* + * Fall through... + */ + + done: + if (!nhi.gateway && nhi.if_index == 0) + return 0; + + /* + * We have a valid nhi. Copy the structure over to the route_info. + */ + ri->nhs[ri->num_nhs] = nhi; + ri->num_nhs++; + + if (src && !ri->pref_src) + ri->pref_src = src; + + return 1; +} + +/* + * netlink_proto_from_route_type + */ +static u_char +netlink_proto_from_route_type (int type) +{ + switch (type) + { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + return RTPROT_KERNEL; + + default: + return RTPROT_ZEBRA; + } +} + +/* + * netlink_route_info_fill + * + * Fill out the route information object from the given route. + * + * Returns TRUE on success and FALSE on failure. + */ +static int +netlink_route_info_fill (netlink_route_info_t *ri, int cmd, + rib_dest_t *dest, struct rib *rib) +{ + struct nexthop *nexthop = NULL; + int discard; + + memset (ri, 0, sizeof (*ri)); + + ri->prefix = rib_dest_prefix (dest); + ri->af = rib_dest_af (dest); + + ri->nlmsg_type = cmd; + ri->rtm_table = rib_dest_vrf (dest)->id; + ri->rtm_protocol = RTPROT_UNSPEC; + + /* + * An RTM_DELROUTE need not be accompanied by any nexthops, + * particularly in our communication with the FPM. + */ + if (cmd == RTM_DELROUTE && !rib) + goto skip; + + if (rib) + ri->rtm_protocol = netlink_proto_from_route_type (rib->type); + + if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) + discard = 1; + else + discard = 0; + + if (cmd == RTM_NEWROUTE) + { + if (discard) + { + if (rib->flags & ZEBRA_FLAG_BLACKHOLE) + ri->rtm_type = RTN_BLACKHOLE; + else if (rib->flags & ZEBRA_FLAG_REJECT) + ri->rtm_type = RTN_UNREACHABLE; + else + assert (0); + } + else + ri->rtm_type = RTN_UNICAST; + } + + ri->metric = &rib->metric; + + if (discard) + { + goto skip; + } + + /* Multipath case. */ + if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) + { + netlink_route_info_add_nh (ri, nexthop); + break; + } + } + } + else + { + for (nexthop = rib->nexthop; + nexthop && (MULTIPATH_NUM == 0 || ri->num_nhs < MULTIPATH_NUM); + nexthop = nexthop->next) + { + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) + { + netlink_route_info_add_nh (ri, nexthop); + } + } + } + + /* If there is no useful nexthop then return. */ + if (ri->num_nhs == 0) + { + zfpm_debug ("netlink_encode_route(): No useful nexthop."); + return 0; + } + + skip: + return 1; +} + +/* + * netlink_route_info_encode + * + * Returns the number of bytes written to the buffer. 0 or a negative + * value indicates an error. + */ +static int +netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf, + size_t in_buf_len) +{ + int bytelen; + int nexthop_num = 0; + size_t buf_offset; + netlink_nh_info_t *nhi; + + struct + { + struct nlmsghdr n; + struct rtmsg r; + char buf[1]; + } *req; + + req = (void *) in_buf; + + buf_offset = ((char *) req->buf) - ((char *) req); + + if (in_buf_len < buf_offset) { + assert(0); + return 0; + } + + memset (req, 0, buf_offset); + + bytelen = af_addr_size (ri->af); + + req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req->n.nlmsg_type = ri->nlmsg_type; + req->r.rtm_family = ri->af; + req->r.rtm_table = ri->rtm_table; + req->r.rtm_dst_len = ri->prefix->prefixlen; + req->r.rtm_protocol = ri->rtm_protocol; + req->r.rtm_scope = RT_SCOPE_UNIVERSE; + + addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen); + + req->r.rtm_type = ri->rtm_type; + + /* Metric. */ + if (ri->metric) + addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric); + + if (ri->num_nhs == 0) + goto done; + + if (ri->num_nhs == 1) + { + nhi = &ri->nhs[0]; + + if (nhi->gateway) + { + addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway, + bytelen); + } + + if (nhi->if_index) + { + addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index); + } + + goto done; + + } + + /* + * Multipath case. + */ + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *) buf; + struct rtnexthop *rtnh; + + rta->rta_type = RTA_MULTIPATH; + rta->rta_len = RTA_LENGTH (0); + rtnh = RTA_DATA (rta); + + for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++) + { + nhi = &ri->nhs[nexthop_num]; + + rtnh->rtnh_len = sizeof (*rtnh); + rtnh->rtnh_flags = 0; + rtnh->rtnh_hops = 0; + rtnh->rtnh_ifindex = 0; + rta->rta_len += rtnh->rtnh_len; + + if (nhi->gateway) + { + rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen); + rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; + } + + if (nhi->if_index) + { + rtnh->rtnh_ifindex = nhi->if_index; + } + + rtnh = RTNH_NEXT (rtnh); + } + + assert (rta->rta_len > RTA_LENGTH (0)); + addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta), + RTA_PAYLOAD (rta)); + +done: + + if (ri->pref_src) + { + addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen); + } + + assert (req->n.nlmsg_len < in_buf_len); + return req->n.nlmsg_len; +} + +/* + * zfpm_log_route_info + * + * Helper function to log the information in a route_info structure. + */ +static void +zfpm_log_route_info (netlink_route_info_t *ri, const char *label) +{ + netlink_nh_info_t *nhi; + int i; + + zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label, + nl_msg_type_to_str (ri->nlmsg_type), + prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen, + nl_rtproto_to_str (ri->rtm_protocol), + ri->metric ? *ri->metric : 0); + + for (i = 0; i < ri->num_nhs; i++) + { + nhi = &ri->nhs[i]; + zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s", + nhi->if_index, addr_to_a (ri->af, nhi->gateway), + nhi->recursive ? "yes" : "no", + nexthop_type_to_str (nhi->type)); + } +} + +/* + * zfpm_netlink_encode_route + * + * Create a netlink message corresponding to the given route in the + * given buffer space. + * + * Returns the number of bytes written to the buffer. 0 or a negative + * value indicates an error. + */ +int +zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib, + char *in_buf, size_t in_buf_len) +{ + netlink_route_info_t ri_space, *ri; + + ri = &ri_space; + + if (!netlink_route_info_fill (ri, cmd, dest, rib)) + return 0; + + zfpm_log_route_info (ri, __FUNCTION__); + + return netlink_route_info_encode (ri, in_buf, in_buf_len); +} diff --git a/zebra/zebra_fpm_private.h b/zebra/zebra_fpm_private.h new file mode 100644 index 000000000..809a70a44 --- /dev/null +++ b/zebra/zebra_fpm_private.h @@ -0,0 +1,56 @@ +/* + * Private header file for the zebra FPM module. + * + * Copyright (C) 2012 by Open Source Routing. + * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_FPM_PRIVATE_H +#define _ZEBRA_FPM_PRIVATE_H + +#include "zebra/debug.h" + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + +#define zfpm_debug(...) \ + do { \ + if (IS_ZEBRA_DEBUG_FPM) zlog_debug("FPM: " __VA_ARGS__); \ + } while(0) + +#elif defined __GNUC__ + +#define zfpm_debug(_args...) \ + do { \ + if (IS_ZEBRA_DEBUG_FPM) zlog_debug("FPM: " _args); \ + } while(0) + +#else +static inline void zfpm_debug(const char *format, ...) { return; } +#endif + + +/* + * Externs + */ +extern int +zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib, + char *in_buf, size_t in_buf_len); + +#endif /* _ZEBRA_FPM_PRIVATE_H */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 299771234..a75d72151 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -40,6 +40,7 @@ #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" +#include "zebra/zebra_fpm.h" /* Default rtm_table for all clients */ extern struct zebra_t zebrad; @@ -961,6 +962,11 @@ rib_install_kernel (struct route_node *rn, struct rib *rib) int ret = 0; struct nexthop *nexthop; + /* + * Make sure we update the FPM any time we send new information to + * the kernel. + */ + zfpm_trigger_update (rn, "installing in kernel"); switch (PREFIX_FAMILY (&rn->p)) { case AF_INET: @@ -988,6 +994,12 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) int ret = 0; struct nexthop *nexthop; + /* + * Make sure we update the FPM any time we send new information to + * the kernel. + */ + zfpm_trigger_update (rn, "uninstalling from kernel"); + switch (PREFIX_FAMILY (&rn->p)) { case AF_INET: @@ -1012,6 +1024,8 @@ rib_uninstall (struct route_node *rn, struct rib *rib) { if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { + zfpm_trigger_update (rn, "rib_uninstall"); + redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); @@ -1034,6 +1048,14 @@ rib_can_delete_dest (rib_dest_t *dest) return 0; } + /* + * Don't delete the dest if we have to update the FPM about this + * prefix. + */ + if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM) || + CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM)) + return 0; + return 1; } @@ -1187,6 +1209,8 @@ rib_process (struct route_node *rn) __func__, buf, rn->p.prefixlen, select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { + zfpm_trigger_update (rn, "updating existing route"); + redistribute_delete (&rn->p, select); if (! RIB_SYSTEM_ROUTE (select)) rib_uninstall_kernel (rn, select); @@ -1228,6 +1252,9 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, buf, rn->p.prefixlen, fib); + + zfpm_trigger_update (rn, "removing existing route"); + redistribute_delete (&rn->p, fib); if (! RIB_SYSTEM_ROUTE (fib)) rib_uninstall_kernel (rn, fib); @@ -1246,6 +1273,9 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, rn->p.prefixlen, select); + + zfpm_trigger_update (rn, "new route selected"); + /* Set real nexthop. */ nexthop_active_update (rn, select, 1); @@ -3081,6 +3111,8 @@ rib_close_table (struct route_table *table) if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) continue; + zfpm_trigger_update (rn, NULL); + if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); } From b9c24cd23091e817942d4eaab95712e84dbec8aa Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:49:00 +0000 Subject: [PATCH 0163/1342] doc: add blurbs on zebra FPM interface and commands Update documentation with some text on the zebra interface to the optional Forwarding Path Manager component, and the related cli commands. Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- doc/main.texi | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/doc/main.texi b/doc/main.texi index a57591377..a6bf0d1c9 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -11,6 +11,7 @@ different routing protocols. * Interface Commands:: Commands for zebra interfaces * Static Route Commands:: Commands for adding static routes * zebra Route Filtering:: Commands for zebra route filtering +* zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY @end menu @@ -227,6 +228,54 @@ ip protocol rip route-map RM1 @end group @end example +@node zebra FIB push interface +@section zebra FIB push interface + +Zebra supports a 'FIB push' interface that allows an external +component to learn the forwarding information computed by the Quagga +routing suite. + +In Quagga, the Routing Information Base (RIB) resides inside +zebra. Routing protocols communicate their best routes to zebra, and +zebra computes the best route across protocols for each prefix. This +latter information makes up the Forwarding Information Base +(FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in +the kernel to forward packets according to the routes computed by +Quagga. The kernel FIB is updated in an OS-specific way. For example, +the @code{netlink} interface is used on Linux, and route sockets are +used on FreeBSD. + +The FIB push interface aims to provide a cross-platform mechanism to +support scenarios where the router has a forwarding path that is +distinct from the kernel, commonly a hardware-based fast path. In +these cases, the FIB needs to be maintained reliably in the fast path +as well. We refer to the component that programs the forwarding plane +(directly or indirectly) as the Forwarding Plane Manager or FPM. + +The FIB push interface comprises of a TCP connection between zebra and +the FPM. The connection is initiated by zebra -- that is, the FPM acts +as the TCP server. + +The relevant zebra code kicks in when zebra is configured with the +@code{--enable-fpm} flag. Zebra periodically attempts to connect to +the well-known FPM port. Once the connection is up, zebra starts +sending messages containing routes over the socket to the FPM. Zebra +sends a complete copy of the forwarding table to the FPM, including +routes that it may have picked up from the kernel. The existing +interaction of zebra with the kernel remains unchanged -- that is, the +kernel continues to receive FIB updates as before. + +The format of the messages exchanged with the FPM is defined by the +file @file{fpm/fpm.h} in the quagga tree. + +The zebra FPM interface uses replace semantics. That is, if a 'route +add' message for a prefix is followed by another 'route add' message, +the information in the second message is complete by itself, and +replaces the information sent in the first message. + +If the connection to the FPM goes down for some reason, zebra sends +the FPM a complete copy of the forwarding table(s) when it reconnects. + @node zebra Terminal Mode Commands @section zebra Terminal Mode Commands @@ -271,3 +320,13 @@ If so, the box can't work as a router. @deffn Command {show ipv6forward} {} Display whether the host's IP v6 forwarding is enabled or not. @end deffn + +@deffn Command {show zebra fpm stats} {} +Display statistics related to the zebra code that interacts with the +optional Forwarding Plane Manager (FPM) component. +@end deffn + +@deffn Command {clear zebra fpm stats} {} +Reset statistics related to the zebra code that interacts with the +optional Forwarding Plane Manager (FPM) component. +@end deffn From 324ed1f87aedf30a45aea951edb2e717c5f9b7fb Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Tue, 13 Nov 2012 22:49:01 +0000 Subject: [PATCH 0164/1342] zebra: include intf when sending IPv4 nexthop to FPM * zebra/zebra_fpm_netlink.c Change the zebra FPM code to include an interface index when encoding a nexthop even if the protocol only provided a gateway address (e.g, NEXTHOP_TYPE_IPV4). Signed-off-by: Avneesh Sachdev Signed-off-by: David Lamparter --- zebra/zebra_fpm_netlink.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 90d3afb2f..67bcf0a15 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -167,6 +167,7 @@ netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop) { nhi.recursive = 1; nhi.type = nexthop->rtype; + nhi.if_index = nexthop->rifindex; if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) @@ -186,15 +187,9 @@ netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop) #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) + || nexthop->rtype == NEXTHOP_TYPE_IFNAME) { - nhi.if_index = nexthop->rifindex; - if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX - || nexthop->rtype == NEXTHOP_TYPE_IFINDEX) - && nexthop->src.ipv4.s_addr) + if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } @@ -203,6 +198,7 @@ netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop) nhi.recursive = 0; nhi.type = nexthop->type; + nhi.if_index = nexthop->ifindex; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) @@ -220,20 +216,13 @@ netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop) nhi.gateway = &nexthop->gate; } #endif /* HAVE_IPV6 */ + if (nexthop->type == NEXTHOP_TYPE_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IFNAME - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + || nexthop->type == NEXTHOP_TYPE_IFNAME) { - nhi.if_index = nexthop->ifindex; - if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } - else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) - { - nhi.if_index = nexthop->ifindex; - } /* * Fall through... From 0be793e674c8b076f0e8bf327257f15803480f49 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 01:34:56 +0000 Subject: [PATCH 0165/1342] build: include git info If enabled with --with-pkg-gitversion on ./configure, this will append git version strings and branch information at the following places: - overall version number: 0.99.21-g0123456 - login motd and show version: tag information + git id + branches Sample output: Hello, this is Quagga (version 0.99.21-g14b49ad-dirty). Copyright 1996-2005 Kunihiro Ishiguro, et al. This is a git build of quagga_0_99_21_release-106-g14b49ad-dirty Associated branch(es): local:master [v2]: fix build without gitinfo (add "else" branch) [v2]: fix for repos without any tags (different git describe output) Signed-off-by: David Lamparter --- configure.ac | 16 ++++++++++++---- lib/.gitignore | 2 ++ lib/Makefile.am | 24 +++++++++++++++++++++++- lib/command.c | 4 ++-- lib/gitversion.pl | 47 +++++++++++++++++++++++++++++++++++++++++++++++ lib/version.h.in | 13 ++++++++++++- 6 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 lib/gitversion.pl diff --git a/configure.ac b/configure.ac index 9bbe89f37..fb6efd7ea 100755 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,7 @@ AC_CANONICAL_TARGET() AM_INIT_AUTOMAKE(1.6) AM_CONFIG_HEADER(config.h) +AC_PATH_PROG(PERL, perl) AC_CHECK_PROG([GAWK],[gawk],[gawk],[not-in-PATH]) if test "x$GAWK" = "xnot-in-PATH" ; then AC_MSG_ERROR([GNU awk is required for lib/memtype.h made by memtypes.awk. @@ -192,6 +193,12 @@ dnl ---------------------- AC_ARG_WITH(pkg-extra-version, AS_HELP_STRING([--with-pkg-extra-version=VER], [add extra version field, for packagers/distributions]), [EXTRAVERSION=$withval],) +AC_ARG_WITH(pkg-git-version, + AS_HELP_STRING([--with-pkg-git-version], [add git information to MOTD and build version string]), + [ if test "x$withval" != "xno"; then + with_pkg_git_version="1" + AC_DEFINE(GIT_VERSION, [1], [include git version info]) + fi ],) AC_ARG_ENABLE(vtysh, [ --enable-vtysh include integrated vty shell for Quagga]) AC_ARG_ENABLE(ipv6, @@ -398,11 +405,13 @@ dnl Add extra version string to package dnl name, string and version fields. dnl ----------------------------------- if test "x${EXTRAVERSION}" != "x" ; then - VERSION=${VERSION}${EXTRAVERSION} - PACKAGE_VERSION=${PACKAGE_VERSION}${EXTRAVERSION} - PACKAGE_STRING=${PACKAGE_STRING}${EXTRAVERSION} + VERSION="${VERSION}${EXTRAVERSION}" + PACKAGE_VERSION="${PACKAGE_VERSION}${EXTRAVERSION}" + PACKAGE_STRING="${PACKAGE_STRING}${EXTRAVERSION}" fi +AM_CONDITIONAL([GIT_VERSION], [test "x$with_pkg_git_version" != "x"]) + dnl ------------------------------------ dnl Check C keywords and standard types dnl ------------------------------------ @@ -611,7 +620,6 @@ dnl --------------------- case "${enable_vtysh}" in "yes") VTYSH="vtysh"; AC_DEFINE(VTYSH,,VTY shell) - AC_PATH_PROG(PERL, perl) dnl Vtysh uses libreadline, which looks for termcap functions at dnl configure time. We follow readlines search order. dnl The required procedures are in libtermcap on NetBSD, in diff --git a/lib/.gitignore b/lib/.gitignore index 00af85a6e..02aa432ce 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -5,6 +5,8 @@ Makefile.in *.la version.c version.h +gitversion.h +gitversion.h.tmp .deps .nfs* .libs diff --git a/lib/Makefile.am b/lib/Makefile.am index e00ad54dc..690c18ff9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,7 +14,7 @@ libzebra_la_SOURCES = \ zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c -BUILT_SOURCES = memtypes.h route_types.h +BUILT_SOURCES = memtypes.h route_types.h gitversion.h libzebra_la_DEPENDENCIES = @LIB_REGEX@ @@ -36,3 +36,25 @@ memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@ + +if GIT_VERSION + +# bit of a trick here to always have up-to-date git stamps without triggering +# unneccessary rebuilds. .PHONY causes the .tmp file to be rebuilt always, +# but if we use that on gitversion.h it'll ripple through the .c file deps. +# (even if gitversion.h's file timestamp doesn't change, make will think it +# did, because of .PHONY...) + +.PHONY: gitversion.h.tmp +.SILENT: gitversion.h gitversion.h.tmp +GITH=gitversion.h +gitversion.h.tmp: $(srcdir)/../.git + @PERL@ $(srcdir)/gitversion.pl $(srcdir) > ${GITH}.tmp +gitversion.h: gitversion.h.tmp + { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp -v ${GITH}.tmp ${GITH} + +else +.PHONY: gitversion.h +gitversion.h: + /bin/true +endif diff --git a/lib/command.c b/lib/command.c index 64563b5d0..3b3fadac4 100644 --- a/lib/command.c +++ b/lib/command.c @@ -84,7 +84,7 @@ static const char *default_motd = "\r\n\ Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ " QUAGGA_COPYRIGHT "\r\n\ -\r\n"; +" GIT_INFO "\r\n"; static const struct facility_map { @@ -2409,7 +2409,7 @@ DEFUN (show_version, { vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"", VTY_NEWLINE); - vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE); + vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE); return CMD_SUCCESS; } diff --git a/lib/gitversion.pl b/lib/gitversion.pl new file mode 100644 index 000000000..448f13d67 --- /dev/null +++ b/lib/gitversion.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w +use strict; + +my $dir = shift; +chdir $dir || die "$dir: $!\n"; + +my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`; +chomp $gitdesc; +my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? $1 : "-gUNKNOWN"; + +printf STDERR "git suffix: %s\n", $gitsuffix; +printf "#define GIT_SUFFIX \"%s\"\n", $gitsuffix; + +my $gitcommit = `git log -1 --format=\"%H\" || echo DEADBEEF`; +chomp $gitcommit; +open(BRANCHES, "git branch -a -v --abbrev=40|") || die "git branch: $!\n"; +my @names = (); +while () { + chomp $_; + if (/\s+(.*?)\s+$gitcommit/) { + my $branch = $1; + if ($branch =~ /^remotes\/(.*?)(\/.*)$/) { + my $path = $2; + my $url = `git config --get "remote.$1.url"`; + chomp $url; + $url =~ s/^(git:|https?:|git@)\/\/github\.com/github/i; + $url =~ s/^(ssh|git):\/\/git\.sv\.gnu\.org\/srv\/git\//savannah:/i; + $url =~ s/^(ssh|git):\/\/git\.savannah\.nongnu\.org\//savannah:/i; + + push @names, $url.$path; + } else { + push @names, 'local:'.$branch; + } + } +} + +printf STDERR "git branches: %s\n", join(", ", @names); + +my $cr = "\\r\\n\\"; +printf < Date: Tue, 27 Nov 2012 01:10:24 +0000 Subject: [PATCH 0166/1342] isisd: do not add >63 IP addresses to hello RFC1195 s4.2 "Multiple IP Addresses per Interface" explicitly forbids us from adding multiple tuples of IP addresses, putting a hard cutoff at 63 IP addresses. * isisd/isis_tlv.c: cut off (and return success) at 63 addrs. Signed-off-by: David Lamparter Tested-by: Martin Winter --- isisd/isis_tlv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index f3b2c338f..ed3e0e81c 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -932,10 +932,9 @@ tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream) { if (pos - value + IPV4_MAX_BYTELEN > 255) { - retval = add_tlv (IPV4_ADDR, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; + /* RFC 1195 s4.2: only one tuple of 63 allowed. */ + zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses"); + break; } *(u_int32_t *) pos = ipv4->prefix.s_addr; pos += IPV4_MAX_BYTELEN; From 19f78cebd2ce50f0d1f367cd759cdcfb1a500f59 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 01:10:25 +0000 Subject: [PATCH 0167/1342] isisd: refuse adjacencies with our own system ID isisd would form an adjacency with another router despite the system IDs being identical. This would later cause an assertion failure like this: assertion=0x555555596db8 "isis_find_vertex (spftree->paths, id, vtype) == ((void *)0)", file=0x555555596c60 "isis_spf.c", line=515, function=0x555555597900 "isis_spf_add2tent") at log.c:619 which is caused by trying to add a path expected to not exist, but suddenly colliding due to the duplicate system ID. * isis_pdu.c: check for system ID collision on receiving Hello Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index bfa1e4e93..083ddc72b 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -988,6 +988,13 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) } } + if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) + { + zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s", + circuit->area->area_tag, circuit->interface->name); + return ISIS_WARNING; + } + /* * Accept the level 1 adjacency only if a match between local and * remote area addresses is found From b72f345d2e078d4cd0559234d051214f58eef542 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 01:10:26 +0000 Subject: [PATCH 0168/1342] isisd: drop hellos without supported protocol list isisd should not form adjacencies on receiving an IS-IS Hello without a list of supported protocols (cf. RFC 1195 s4.4 p32 "Maintaining Router Adjacencies") Also fixes memleaks in these error cases. * isisd/isis_pdu.c: improve TLVFLAG_NLPID handling Signed-off-by: David Lamparter Tested-by: Martin Winter --- isisd/isis_pdu.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 083ddc72b..8a92789ff 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -493,6 +493,13 @@ process_p2p_hello (struct isis_circuit *circuit) return ISIS_WARNING; } + if (!(found & TLVFLAG_NLPID)) + { + zlog_warn ("No supported protocols TLV in P2P IS to IS hello"); + free_tlvs (&tlvs); + return ISIS_WARNING; + } + /* 8.2.5.1 c) Authentication */ if (circuit->passwd.type) { @@ -550,9 +557,11 @@ process_p2p_hello (struct isis_circuit *circuit) tlvs_to_adj_area_addrs (&tlvs, adj); /* which protocol are spoken ??? */ - if (found & TLVFLAG_NLPID) - if (tlvs_to_adj_nlpids (&tlvs, adj)) - return ISIS_ERROR; + if (tlvs_to_adj_nlpids (&tlvs, adj)) + { + free_tlvs (&tlvs); + return ISIS_WARNING; + } /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) @@ -973,6 +982,14 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) goto out; } + if (!(found & TLVFLAG_NLPID)) + { + zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello", + level); + retval = ISIS_WARNING; + goto out; + } + /* Verify authentication, either cleartext of HMAC MD5 */ if (circuit->passwd.type) { @@ -1103,8 +1120,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) tlvs_to_adj_area_addrs (&tlvs, adj); /* which protocol are spoken ??? */ - if (found & TLVFLAG_NLPID) - tlvs_to_adj_nlpids (&tlvs, adj); + if (tlvs_to_adj_nlpids (&tlvs, adj)) + { + retval = ISIS_WARNING; + goto out; + } /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) From de543de3d7682eaeb8c9b657e9a3bb4bcd17993d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 01:10:27 +0000 Subject: [PATCH 0169/1342] isisd: fix spftree_area_del typo causing SEGV spftree_area_del didn't clear the IPv6 L2 spftree due to a simple typo, leading to a SEGV on shutdown when the still-armed timer would try to run an IPv6 L2 SPF calculation with its data free'd already. Signed-off-by: David Lamparter --- isisd/isis_spf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 07b855b40..1cb511381 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -365,7 +365,7 @@ spftree_area_del (struct isis_area *area) area->spftree[1] = NULL; } #ifdef HAVE_IPV6 - if (area->spftree[1] != NULL) + if (area->spftree6[1] != NULL) { isis_spftree_del (area->spftree6[1]); area->spftree6[1] = NULL; From f818c8f3fb9c98490df29e99aa9cddde8e0296d5 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 27 Nov 2012 01:10:28 +0000 Subject: [PATCH 0170/1342] isisd: save metric-style narrow isisd defaults to wide metric style. So if narrow metric style is configured, a matching setting should be written to the configuration, allowing a narrow metric-style setting to be saved. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- isisd/isisd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/isisd/isisd.c b/isisd/isisd.c index e8e3d9f0a..47675f0af 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2857,6 +2857,11 @@ isis_config_write (struct vty *vty) vty_out (vty, " metric-style transition%s", VTY_NEWLINE); write++; } + else + { + vty_out (vty, " metric-style narrow%s", VTY_NEWLINE); + write++; + } /* ISIS - overload-bit */ if (area->overload_bit) { From 318c8040abc1b8a737c941382e8aca82e546da09 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 01:10:29 +0000 Subject: [PATCH 0171/1342] isisd: always join all IS-IS multicast groups The socket is only created once when an interface is brought up, and the multicast groups were joined according to configuration at that point. This breaks when later switching an interface to another IS-IS level. Since, for a separate conformance issue (ANVL ISIS-6.4), we should be inspecting the destination address anyway, the simplest fix here is to just join all groups unconditionally. There shouldn't be much traffic on these anyway, worst case we might be picking up some unrelated multicast groups due to NIC filter aliasing though... Signed-off-by: David Lamparter Tested-by: Martin Winter --- isisd/isis_dlpi.c | 10 +++------- isisd/isis_pfpacket.c | 12 +++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index 73b6d3e7b..0a82718d3 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -442,13 +442,9 @@ open_dlpi_dev (struct isis_circuit *circuit) * 8.4.2 - Broadcast subnetwork IIH PDUs */ retval = 0; - if (circuit->is_type & IS_LEVEL_1) - { - retval |= dlpimcast (fd, ALL_L1_ISS); - retval |= dlpimcast (fd, ALL_ISS); - } - if (circuit->is_type & IS_LEVEL_2) - retval |= dlpimcast (fd, ALL_L2_ISS); + retval |= dlpimcast (fd, ALL_L1_ISS); + retval |= dlpimcast (fd, ALL_ISS); + retval |= dlpimcast (fd, ALL_L2_ISS); if (retval != 0) { diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 42947b22c..e5589aea4 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -142,16 +142,14 @@ open_packet_socket (struct isis_circuit *circuit) * 8.4.2 - Broadcast subnetwork IIH PDUs * FIXME: is there a case only one will fail?? */ - if (circuit->is_type & IS_LEVEL_1) - /* joining ALL_L1_ISS */ - retval = isis_multicast_join (circuit->fd, 1, + /* joining ALL_L1_ISS */ + retval |= isis_multicast_join (circuit->fd, 1, circuit->interface->ifindex); - if (circuit->is_type & IS_LEVEL_2) - /* joining ALL_L2_ISS */ - retval = isis_multicast_join (circuit->fd, 2, + /* joining ALL_L2_ISS */ + retval |= isis_multicast_join (circuit->fd, 2, circuit->interface->ifindex); /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */ - retval = isis_multicast_join (circuit->fd, 3, + retval |= isis_multicast_join (circuit->fd, 3, circuit->interface->ifindex); } else From e8aca32f312cbef1cb0b0dd9e87b7e59dc9fa251 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 01:10:30 +0000 Subject: [PATCH 0172/1342] isisd: address Coverity warnings this fixes a bunch of issues found by Coverity SCAN and flagged as "high" impact -- although, they're all rather minute issues. * isisd/isis_adjacency.c: one superfluous check, one possible NULL deref * isisd/isis_circuit.c: two prefix memory leaks * isisd/isis_csm.c: one missing break * isisd/isis_lsp.c: one possible NULL deref * isisd/isis_pfpacket.c: one error-case fd leak * isisd/isis_route.c: one isis_route_info memory leak * isisd/isis_routemap.c: one... fnord * isisd/isis_tlv.c: one infinite loop Reported-by: Coverity SCAN Signed-off-by: David Lamparter --- isisd/isis_adjacency.c | 4 ++-- isisd/isis_circuit.c | 4 ++++ isisd/isis_csm.c | 1 + isisd/isis_lsp.c | 4 +++- isisd/isis_pfpacket.c | 1 + isisd/isis_route.c | 6 +++++- isisd/isis_routemap.c | 3 +-- isisd/isis_spf.c | 2 +- isisd/isis_tlv.c | 1 + 9 files changed, 19 insertions(+), 7 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 468b0a69c..414885fc4 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -207,7 +207,7 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", adj_name, - adj->circuit ? adj->circuit->interface->name : "no circuit", + adj->circuit->interface->name, adj_state2string (old_state), adj_state2string (new_state), reason ? reason : "unspecified"); @@ -427,7 +427,7 @@ isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail) vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " SNPA: %s", snpa_print (adj->snpa)); - if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST) + if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { dyn = dynhn_find_by_id (adj->lanid); if (dyn) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index c09c3a282..3d9fb4739 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -327,6 +327,8 @@ isis_circuit_del_addr (struct isis_circuit *circuit, zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); } + + prefix_ipv4_free (ipv4); } #ifdef HAVE_IPV6 if (connected->address->family == AF_INET6) @@ -370,6 +372,8 @@ isis_circuit_del_addr (struct isis_circuit *circuit, } else if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + + prefix_ipv6_free (ipv6); } #endif /* HAVE_IPV6 */ return; diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index 5d74a71be..a58ba4907 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -101,6 +101,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); + break; case IF_DOWN_FROM_Z: zlog_warn ("circuit already disconnected"); break; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 082e9dcd1..f2a7923d5 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1631,7 +1631,7 @@ lsp_generate (struct isis_area *area, int level) static int lsp_regenerate (struct isis_area *area, int level) { - dict_t *lspdb = area->lspdb[level - 1]; + dict_t *lspdb; struct isis_lsp *lsp, *frag; struct listnode *node; u_char lspid[ISIS_SYS_ID_LEN + 2]; @@ -1640,6 +1640,8 @@ lsp_regenerate (struct isis_area *area, int level) if ((area == NULL) || (area->is_type & level) != level) return ISIS_ERROR; + lspdb = area->lspdb[level - 1]; + memset (lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index e5589aea4..4bc8717a9 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -129,6 +129,7 @@ open_packet_socket (struct isis_circuit *circuit) sizeof (struct sockaddr_ll)) < 0) { zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno)); + close (fd); return ISIS_WARNING; } diff --git a/isisd/isis_route.c b/isisd/isis_route.c index c99d95831..8ab470cef 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -438,7 +438,11 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, route_node = route_node_get (area->route_table6[level - 1], prefix); #endif /* HAVE_IPV6 */ else - return NULL; + { + isis_route_info_delete (rinfo_new); + return NULL; + } + rinfo_old = route_node->info; if (!rinfo_old) { diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index 558d39102..84a14ac57 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -69,8 +69,7 @@ isis_route_map_upd (const char *name) for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { if (isis->rmap[i].name) - isis->rmap[i].map = isis->rmap[i].map = - route_map_lookup_by_name (isis->rmap[i].name); + isis->rmap[i].map = route_map_lookup_by_name (isis->rmap[i].name); else isis->rmap[i].map = NULL; } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 1cb511381..e0a8d01cc 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1492,7 +1492,7 @@ isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid) struct listnode *anode; struct isis_vertex *vertex; struct isis_adjacency *adj; - u_char buff[255]; + u_char buff[BUFSIZ]; vty_out (vty, "Vertex Type Metric " "Next-Hop Interface Parent%s", VTY_NEWLINE); diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index ed3e0e81c..2c2415ae0 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -712,6 +712,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, Neighbor Extended Local Circuit ID (four octets, if Neighbor System ID is present) */ pnt += length; + value_len += length; } } else From 4fb7c84f1b5e282c7dc413a578d3f42353ac7fec Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 27 Nov 2012 19:51:59 +0000 Subject: [PATCH 0173/1342] isisd: fix metrics check for metric-style narrow When switching to narrow metric style, all configured circuits are verified to have a valid narrow style metric. Check te_metric instead of metric_default as the latter is only 8bit wide and may overflow for wide style metrics. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- isisd/isisd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/isisd/isisd.c b/isisd/isisd.c index 47675f0af..28cd05199 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2054,7 +2054,7 @@ validate_metric_style_narrow (struct vty *vty, struct isis_area *area) { if ((area->is_type & IS_LEVEL_1) && (circuit->is_type & IS_LEVEL_1) && - (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC)) + (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) { vty_out (vty, "ISIS circuit %s metric is invalid%s", circuit->interface->name, VTY_NEWLINE); @@ -2062,7 +2062,7 @@ validate_metric_style_narrow (struct vty *vty, struct isis_area *area) } if ((area->is_type & IS_LEVEL_2) && (circuit->is_type & IS_LEVEL_2) && - (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC)) + (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) { vty_out (vty, "ISIS circuit %s metric is invalid%s", circuit->interface->name, VTY_NEWLINE); From 478c1125cfcf92c3f2a574d6b76eea28126284dc Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 27 Nov 2012 19:52:00 +0000 Subject: [PATCH 0174/1342] isisd: verify metrics on metric-style transition When switching to metric-style transition, circuit metrics should also be verified to be in the narrow range 0..63. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- isisd/isisd.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/isisd/isisd.c b/isisd/isisd.c index 28cd05199..ce6a26214 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2092,19 +2092,22 @@ DEFUN (metric_style, area->newmetric = 1; area->oldmetric = 0; } - else if (strncmp (argv[0], "t", 1) == 0) - { - area->newmetric = 1; - area->oldmetric = 1; - } - else if (strncmp (argv[0], "n", 1) == 0) + else { ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; - area->newmetric = 0; - area->oldmetric = 1; + if (strncmp (argv[0], "t", 1) == 0) + { + area->newmetric = 1; + area->oldmetric = 1; + } + else if (strncmp (argv[0], "n", 1) == 0) + { + area->newmetric = 0; + area->oldmetric = 1; + } } return CMD_SUCCESS; From e1a555b67cc868f95ea2b53c278bd8d091333e5f Mon Sep 17 00:00:00 2001 From: Nick Hilliard Date: Wed, 28 Nov 2012 14:39:56 +0000 Subject: [PATCH 0175/1342] isisd: fix ipv6 metric endianness the isis ipv6 reachability metric is transmitted in big endian / network format, but isis_spf_process_lsp() does not convert this into host endian format when mucking around with local cost + received metric. This patch fixes this problem and makes received ipv6 metrics work properly on little-endian machines. Signed-off-by: David Lamparter --- isisd/isis_spf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index e0a8d01cc..fd93efa65 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -833,7 +833,7 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, { assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN); - dist = cost + ip6reach->metric; + dist = cost + ntohl(ip6reach->metric); vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; prefix.prefixlen = ip6reach->prefix_len; From fd76f41ac0267dc4cf5438ac8f5e23fae6810d31 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 13 Dec 2012 10:35:45 +0100 Subject: [PATCH 0176/1342] build: update ICC warning CFLAGS Intel's icc doesn't accept "-wd " anymore, it's "-wd" these days. But, anyhow, the warnings disabled in Quagga's configure.ac don't seem to appear anywhere at all, so let's just remove the option completely. Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fb6efd7ea..c1a4d8cdd 100755 --- a/configure.ac +++ b/configure.ac @@ -129,7 +129,7 @@ AC_MSG_CHECKING([whether to set a default CFLAGS]) if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in "ICC") - CFLAGS="-Os -g -Wall -wd 279,869,981" + CFLAGS="-Os -g -Wall" AC_MSG_RESULT([Intel default]) ;; "GCC") From 4209a88759c41aac54465b6d4389b7daaad6ac80 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 13 Dec 2012 10:59:00 +0100 Subject: [PATCH 0177/1342] build: fix dist tarball automake file lists haven't quite kept up with recent changes, time to fix them up so the dist tarball actually works... Signed-off-by: David Lamparter --- Makefile.am | 3 ++- lib/Makefile.am | 7 ++++++- zebra/Makefile.am | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 8371041ba..37fea43b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,8 @@ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ tools/mrlg.cgi tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ - tools/zebra.el tools/multiple-bgpd.sh + tools/zebra.el tools/multiple-bgpd.sh \ + fpm/fpm.h if HAVE_LATEX diff --git a/lib/Makefile.am b/lib/Makefile.am index 690c18ff9..0ec5b4c92 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -29,7 +29,12 @@ pkginclude_HEADERS = \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ workqueue.h route_types.h -EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.pl route_types.txt +EXTRA_DIST = \ + regex.c regex-gnu.h \ + queue.h \ + memtypes.awk \ + route_types.pl route_types.txt \ + gitversion.pl memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk ($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > $@) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 266812f83..96f7bef30 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -42,7 +42,8 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ - interface.h ipforward.h irdp.h router-id.h kernel_socket.h + interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ + rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) From a16dcf7c11d80775b07a0fa6f3ac5527190fb486 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 13 Dec 2012 11:20:50 +0100 Subject: [PATCH 0178/1342] build: check for .git in configure.ac Don't error out when someone tries using --with-pkg-git-version on something that isn't actually a git checkout (like a dist tarball). Signed-off-by: David Lamparter --- configure.ac | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index c1a4d8cdd..405693c9b 100755 --- a/configure.ac +++ b/configure.ac @@ -195,10 +195,7 @@ AC_ARG_WITH(pkg-extra-version, [EXTRAVERSION=$withval],) AC_ARG_WITH(pkg-git-version, AS_HELP_STRING([--with-pkg-git-version], [add git information to MOTD and build version string]), - [ if test "x$withval" != "xno"; then - with_pkg_git_version="1" - AC_DEFINE(GIT_VERSION, [1], [include git version info]) - fi ],) + [ test "x$withval" != "xno" && with_pkg_git_version="yes" ]) AC_ARG_ENABLE(vtysh, [ --enable-vtysh include integrated vty shell for Quagga]) AC_ARG_ENABLE(ipv6, @@ -410,7 +407,14 @@ if test "x${EXTRAVERSION}" != "x" ; then PACKAGE_STRING="${PACKAGE_STRING}${EXTRAVERSION}" fi -AM_CONDITIONAL([GIT_VERSION], [test "x$with_pkg_git_version" != "x"]) +if test "x$with_pkg_git_version" = "xyes"; then + if test -d "${srcdir}/.git"; then + AC_DEFINE(GIT_VERSION, [1], [include git version info]) + else with_pkg_git_version="no" + AC_MSG_WARN([--with-pkg-git-version given, but this is not a git checkout]) + fi +fi +AM_CONDITIONAL([GIT_VERSION], [test "x$with_pkg_git_version" = "xyes"]) dnl ------------------------------------ dnl Check C keywords and standard types From 16a86b3e2f82d3e19a722e2ab34c2c77f62ed926 Mon Sep 17 00:00:00 2001 From: Ayan Banerjee Date: Mon, 3 Dec 2012 10:48:46 -0800 Subject: [PATCH 0179/1342] ospf: suppress delete using replacement After a SPF run, OSPF deletes routes that have changed in terms of any metric, type, and/or next-hops and re-adds them. Given that the Zebra-RIB already support replacement semantics, we suppress deletes for routes that will be added back again. This has the following advantages. It reduces the number of IPC messages between OSPF/Zebra. Also, in the current flow, a batch of route deletes were followed by a batch of adds even for say a metric change. With the change, routes are sent as "add" when they are modified. Zebra already implicitly deletes older routes. Signed-off-by: Ayan Banerjee Reviewed-by: Scott Feldman Reviewed-by: Dinesh Dutt Signed-off-by: Scott Feldman --- ospfd/ospf_route.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index c3acba348..eb7829acd 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -126,6 +126,31 @@ ospf_route_table_free (struct route_table *rt) route_table_finish (rt); } +/* If a prefix exists in the new routing table, then return 1, + otherwise return 0. Since the ZEBRA-RIB does an implicit + withdraw, it is not necessary to send a delete, an add later + will act like an implicit delete. */ +static int +ospf_route_exist_new_table (struct route_table *rt, struct prefix_ipv4 *prefix) +{ + struct route_node *rn; + + assert (rt); + assert (prefix); + + rn = route_node_lookup (rt, (struct prefix *) prefix); + if (!rn) { + return 0; + } + route_unlock_node (rn); + + if (!rn->info) { + return 0; + } + + return 1; +} + /* If a prefix and a nexthop match any route in the routing table, then return 1, otherwise return 0. */ int @@ -223,13 +248,13 @@ ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt) { if (or->type == OSPF_DESTINATION_NETWORK) { - if (! ospf_route_match_same (cmprt, - (struct prefix_ipv4 *) &rn->p, or)) + if (! ospf_route_exist_new_table (cmprt, + (struct prefix_ipv4 *) &rn->p)) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); } else if (or->type == OSPF_DESTINATION_DISCARD) - if (! ospf_route_match_same (cmprt, - (struct prefix_ipv4 *) &rn->p, or)) + if (! ospf_route_exist_new_table (cmprt, + (struct prefix_ipv4 *) &rn->p)) ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); } } From 4ba4fc857685bfe31c7127826652012a750367c5 Mon Sep 17 00:00:00 2001 From: Ayan Banerjee Date: Mon, 3 Dec 2012 11:17:24 -0800 Subject: [PATCH 0180/1342] ospf: forward ref. of areas for "max-metric router-lsa administrative" cmd In the event areas are created at a later point of time with respect to the playback of the "max-metric router-lsa administrative" command, those areas do not get into indefinite max-metric mode. This patch is inteneded to store the configuration and apply it to all future areas that may be created. In the process, some other bugs that were there with respect to restart etc are fixed up. Tested locally to see that the fix works across multiple areas and across multiple restarts. Signed-off-by: Ayan Banerjee Reviewed-by: Scott Feldman Reviewed-by: JR Rivers Signed-off-by: Scott Feldman --- ospfd/ospf_vty.c | 5 +++++ ospfd/ospfd.c | 7 ++++++- ospfd/ospfd.h | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 97c8e8d62..a88071415 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -7020,6 +7020,10 @@ DEFUN (ospf_max_metric_router_lsa_admin, if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) ospf_router_lsa_update_area (area); } + + /* Allows for areas configured later to get the property */ + ospf->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_SET; + return CMD_SUCCESS; } @@ -7047,6 +7051,7 @@ DEFUN (no_ospf_max_metric_router_lsa_admin, ospf_router_lsa_update_area (area); } } + ospf->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET; return CMD_SUCCESS; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index e84051367..11a2dc5c1 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -182,7 +182,8 @@ ospf_new (void) new->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; new->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; - + new->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET; + /* Distribute parameter init. */ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { @@ -676,6 +677,10 @@ ospf_area_get (struct ospf *ospf, struct in_addr area_id, int format) area->format = format; listnode_add_sort (ospf->areas, area); ospf_check_abr_status (ospf); + if (ospf->stub_router_admin_set == OSPF_STUB_ROUTER_ADMINISTRATIVE_SET) + { + SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); + } } return area; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index bf825d177..dfaef1d42 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -195,6 +195,9 @@ struct ospf unsigned int stub_router_startup_time; /* seconds */ unsigned int stub_router_shutdown_time; /* seconds */ #define OSPF_STUB_ROUTER_UNCONFIGURED 0 + u_char stub_router_admin_set; +#define OSPF_STUB_ROUTER_ADMINISTRATIVE_SET 1 +#define OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET 0 #define OSPF_STUB_MAX_METRIC_SUMMARY_COST 0x00ff0000 From 91e6a0e5ca973c7183f638987b67aa370e9b484c Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Tue, 4 Dec 2012 10:46:37 -0800 Subject: [PATCH 0181/1342] ospf: Convert MAX_AGE LSA list to tree Store the MaxAge LSA list in a tree instead of a linked list for efficient access. Walking the list can be quite inefficient in some large systems and under certain tests. ospfd maintains the list of LSA's that have been MaxAge'd out in a separate linked list for removal by a remover/walker thread. When a new LSA is to be installed, the old LSA is ejected and when it is ejected, the MaxAge LSA list is traversed to ensure that the old LSA is also removed from this list if it exists on this list. When a large number (> 5K) MaxAge LSAs are bombarding the system, walking this list takes a significant time causing timers to fire and actions to be taken such as expiring neighbors due to expiry of DeadInterval (especially when timer is really low, <= 12s), creating a spiral of instability. By making this MaxAge LSA list be a tree, this problem is mitigated. Signed-off-by: Dinesh Dutt Reviewed-by: Ayan Banerjee Reviewed-by: Scott Feldman Reviewed-by: Shrijeet Mukherjee Signed-off-by: Scott Feldman --- ospfd/ospf_lsa.c | 52 +++++++++++++++++++++++++++++++++++++++-------- ospfd/ospf_lsdb.c | 21 +++++++++++-------- ospfd/ospf_lsdb.h | 1 + ospfd/ospf_vty.c | 23 +++++++++++++-------- ospfd/ospfd.c | 16 +++++++++++---- ospfd/ospfd.h | 2 +- 6 files changed, 83 insertions(+), 32 deletions(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index e778251ca..66c7e1c0c 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2828,7 +2828,7 @@ ospf_maxage_lsa_remover (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct ospf_lsa *lsa; - struct listnode *node, *nnode; + struct route_node *rn; int reschedule = 0; ospf->t_maxage = NULL; @@ -2839,8 +2839,13 @@ ospf_maxage_lsa_remover (struct thread *thread) reschedule = !ospf_check_nbr_status (ospf); if (!reschedule) - for (ALL_LIST_ELEMENTS (ospf->maxage_lsa, node, nnode, lsa)) + for (rn = route_top(ospf->maxage_lsa); rn; rn = route_next(rn)) { + if ((lsa = rn->info) == NULL) + { + continue; + } + if (lsa->retransmit_counter > 0) { reschedule = 1; @@ -2893,13 +2898,22 @@ ospf_maxage_lsa_remover (struct thread *thread) void ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) { - struct listnode *n; + struct route_node *rn; + struct prefix_ls lsa_prefix; - if ((n = listnode_lookup (ospf->maxage_lsa, lsa))) + ls_prefix_set (&lsa_prefix, lsa); + + if ((rn = route_node_lookup(ospf->maxage_lsa, + (struct prefix *)&lsa_prefix))) { - list_delete_node (ospf->maxage_lsa, n); - UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); - ospf_lsa_unlock (&lsa); /* maxage_lsa */ + if (rn->info == lsa) + { + UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); + ospf_lsa_unlock (&lsa); /* maxage_lsa */ + rn->info = NULL; + route_unlock_node (rn); /* route_node_lookup */ + } + route_unlock_node (rn); /* route_node_lookup */ } } @@ -2911,6 +2925,9 @@ ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) void ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) { + struct prefix_ls lsa_prefix; + struct route_node *rn; + /* When we saw a MaxAge LSA flooded to us, we put it on the list and schedule the MaxAge LSA remover. */ if (CHECK_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE)) @@ -2921,8 +2938,25 @@ ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) return; } - listnode_add (ospf->maxage_lsa, ospf_lsa_lock (lsa)); - SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); + ls_prefix_set (&lsa_prefix, lsa); + if ((rn = route_node_get (ospf->maxage_lsa, + (struct prefix *)&lsa_prefix)) != NULL) + { + if (rn->info != NULL) + { + route_unlock_node (rn); + } + else + { + rn->info = ospf_lsa_lock(lsa); + SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); + } + } + else + { + zlog_err("Unable to allocate memory for maxage lsa\n"); + assert(0); + } if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa)); diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index ea9a35284..aad979a74 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -72,13 +72,16 @@ ospf_lsdb_cleanup (struct ospf_lsdb *lsdb) route_table_finish (lsdb->type[i].db); } -static void -lsdb_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) +void +ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) { - lp->family = 0; - lp->prefixlen = 64; - lp->id = lsa->data->id; - lp->adv_router = lsa->data->adv_router; + if (lp && lsa && lsa->data) + { + lp->family = 0; + lp->prefixlen = 64; + lp->id = lsa->data->id; + lp->adv_router = lsa->data->adv_router; + } } static void @@ -115,7 +118,7 @@ ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) struct route_node *rn; table = lsdb->type[lsa->data->type].db; - lsdb_prefix_set (&lp, lsa); + ls_prefix_set (&lp, lsa); rn = route_node_get (table, (struct prefix *)&lp); /* nothing to do? */ @@ -167,7 +170,7 @@ ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) assert (lsa->data->type < OSPF_MAX_LSA); table = lsdb->type[lsa->data->type].db; - lsdb_prefix_set (&lp, lsa); + ls_prefix_set (&lp, lsa); if ((rn = route_node_lookup (table, (struct prefix *) &lp))) { if (rn->info == lsa) @@ -218,7 +221,7 @@ ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) struct ospf_lsa *find; table = lsdb->type[lsa->data->type].db; - lsdb_prefix_set (&lp, lsa); + ls_prefix_set (&lp, lsa); rn = route_node_lookup (table, (struct prefix *) &lp); if (rn) { diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h index 4157b6856..51ae45bf5 100644 --- a/ospfd/ospf_lsdb.h +++ b/ospfd/ospf_lsdb.h @@ -66,6 +66,7 @@ extern struct ospf_lsdb *ospf_lsdb_new (void); extern void ospf_lsdb_init (struct ospf_lsdb *); extern void ospf_lsdb_free (struct ospf_lsdb *); extern void ospf_lsdb_cleanup (struct ospf_lsdb *); +extern void ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa); extern void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *); extern void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *); extern void ospf_lsdb_delete_all (struct ospf_lsdb *); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a88071415..3655cfe18 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -4035,21 +4035,26 @@ show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) static void show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) { - struct listnode *node; + struct route_node *rn; struct ospf_lsa *lsa; vty_out (vty, "%s MaxAge Link States:%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - for (ALL_LIST_ELEMENTS_RO (ospf->maxage_lsa, node, lsa)) + for (rn = route_top (ospf->maxage_lsa); rn; rn = route_next (rn)) { - vty_out (vty, "Link type: %d%s", lsa->data->type, VTY_NEWLINE); - vty_out (vty, "Link State ID: %s%s", - inet_ntoa (lsa->data->id), VTY_NEWLINE); - vty_out (vty, "Advertising Router: %s%s", - inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); - vty_out (vty, "LSA lock count: %d%s", lsa->lock, VTY_NEWLINE); - vty_out (vty, "%s", VTY_NEWLINE); + struct ospf_lsa *lsa; + + if ((lsa = rn->info) != NULL) + { + vty_out (vty, "Link type: %d%s", lsa->data->type, VTY_NEWLINE); + vty_out (vty, "Link State ID: %s%s", + inet_ntoa (lsa->data->id), VTY_NEWLINE); + vty_out (vty, "Advertising Router: %s%s", + inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); + vty_out (vty, "LSA lock count: %d%s", lsa->lock, VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + } } } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 11a2dc5c1..d1de29d5e 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -201,7 +201,7 @@ ospf_new (void) /* MaxAge init. */ new->maxage_delay = OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT; - new->maxage_lsa = list_new (); + new->maxage_lsa = route_table_init(); new->t_maxage_walker = thread_add_timer (master, ospf_lsa_maxage_walker, new, OSPF_LSA_MAXAGE_CHECK_INTERVAL); @@ -502,10 +502,18 @@ ospf_finish_final (struct ospf *ospf) ospf_lsdb_delete_all (ospf->lsdb); ospf_lsdb_free (ospf->lsdb); - for (ALL_LIST_ELEMENTS (ospf->maxage_lsa, node, nnode, lsa)) - ospf_lsa_unlock (&lsa); /* maxage_lsa */ + for (rn = route_top (ospf->maxage_lsa); rn; rn = route_next (rn)) + { + struct ospf_lsa *lsa; - list_delete (ospf->maxage_lsa); + if ((lsa = rn->info) != NULL) + { + ospf_lsa_unlock (&lsa); + rn->info = NULL; + } + route_unlock_node (rn); + } + route_table_finish (ospf->maxage_lsa); if (ospf->old_table) ospf_route_table_free (ospf->old_table); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index dfaef1d42..cc27f66ed 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -248,7 +248,7 @@ struct ospf /* Time stamps. */ struct timeval ts_spf; /* SPF calculation time stamp. */ - struct list *maxage_lsa; /* List of MaxAge LSA for deletion. */ + struct route_table *maxage_lsa; /* List of MaxAge LSA for deletion. */ int redistribute; /* Num of redistributed protocols. */ /* Threads. */ From faf9875832539f00940904e1424f2e789fef52d4 Mon Sep 17 00:00:00 2001 From: Ayan Banerjee Date: Tue, 4 Dec 2012 10:49:12 -0800 Subject: [PATCH 0182/1342] ospf: Reduce MaxAge log level Reduce the log level for the MaxAge LSA reception when such an LSA does not exist in the database. Signed-off-by: Ayan Banerjee Reviewed-by: Scott Feldman Reviewed-by: Nolan Leake Signed-off-by: Scott Feldman --- ospfd/ospf_packet.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index ede59088c..d79df5354 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1834,8 +1834,11 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, ospf_ls_ack_send (nbr, lsa); /* Discard LSA. */ - zlog_info ("Link State Update[%s]: LS age is equal to MaxAge.", - dump_lsa_key(lsa)); + if (IS_DEBUG_OSPF (lsa, LSA)) + { + zlog_debug ("Link State Update[%s]: LS age is equal to MaxAge.", + dump_lsa_key(lsa)); + } DISCARD_LSA (lsa, 3); } From 2345a2221aa0a02b96846beab6088815f41e791b Mon Sep 17 00:00:00 2001 From: Leonard Tracy Date: Tue, 4 Dec 2012 11:02:35 -0800 Subject: [PATCH 0183/1342] ospf: Fix type-4 network mask to 0 per RFC The OSPF RFC (2328) states that the network mask field of a type 4 LSA "is not meaningful and must be zero". OSPFD has been setting the mask as /32. This patch changes OSPFD to set the mask to 0 per the RFC Signed-off-by: Scott Feldman --- ospfd/ospf_lsa.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 66c7e1c0c..fb55f7ff1 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1340,12 +1340,8 @@ static void ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, u_int32_t metric) { - struct in_addr mask; - - masklen2ip (p->prefixlen, &mask); - /* Put Network Mask. */ - stream_put_ipv4 (s, mask.s_addr); + stream_put_ipv4 (s, (u_int32_t) 0); /* Set # TOS. */ stream_putc (s, (u_char) 0); From 822d8f55199c0aee32c64f91532f637694d30e11 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 4 Dec 2012 11:11:41 -0800 Subject: [PATCH 0184/1342] ospf: fix apiserver enable The ospf_apiserver_enable flag was being cleared _after_ the "-a" command-line option set it to 1. Move up the initialisation, so enabling the OSPF API is actually possible. Reported-by: Rosario Mattera Signed-off-by: David Lamparter Signed-off-by: Scott Feldman --- ospfd/ospf_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 1448c7d8e..6d58b4ead 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -191,6 +191,11 @@ main (int argc, char **argv) /* Set umask before anything for security */ umask (0027); +#ifdef SUPPORT_OSPF_API + /* OSPF apiserver is disabled by default. */ + ospf_apiserver_enable = 0; +#endif /* SUPPORT_OSPF_API */ + /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); @@ -275,11 +280,6 @@ main (int argc, char **argv) /* OSPF master init. */ ospf_master_init (); -#ifdef SUPPORT_OSPF_API - /* OSPF apiserver is disabled by default. */ - ospf_apiserver_enable = 0; -#endif /* SUPPORT_OSPF_API */ - /* Initializations. */ master = om->master; From bda3c326a3fe843417726bfe1bc8d4bafbb51fa9 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 4 Dec 2012 11:31:16 -0800 Subject: [PATCH 0185/1342] ospfd: fix argument parsing for distribute-list Use the correct argument for the protocol lookup in ospf distribute-list commands. Signed-off-by: Christian Franke Signed-off-by: Scott Feldman --- ospfd/ospf_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 3655cfe18..862ef95a3 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -6042,7 +6042,7 @@ DEFUN (ospf_distribute_list_out, int source; /* Get distribute source. */ - source = proto_redistnum(AFI_IP, argv[0]); + source = proto_redistnum(AFI_IP, argv[1]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; @@ -6061,7 +6061,7 @@ DEFUN (no_ospf_distribute_list_out, struct ospf *ospf = vty->index; int source; - source = proto_redistnum(AFI_IP, argv[0]); + source = proto_redistnum(AFI_IP, argv[1]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; From 1a61ad1011c498c4ae66cc145db673e53ef02962 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 12:50:23 -0800 Subject: [PATCH 0186/1342] ospfd: Fixed typo bug in ospf_vty.h:ospf_neighbor Typo bug. ospf_nbr_nbma_poll_interval_set() was being sent priority instead of interval. Signed-off-by: Scott Feldman --- ospfd/ospf_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 862ef95a3..45ddc5c40 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2322,7 +2322,7 @@ DEFUN (ospf_neighbor, if (argc > 1) ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); if (argc > 2) - ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, priority); + ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, interval); return CMD_SUCCESS; } From fbc043a847149499436fe4083b6384bde43fe578 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 12:54:18 -0800 Subject: [PATCH 0187/1342] ospfd: Fixed signed/unsigned masking of negative metrics In the original code, negative metrics would be converted successfully by atoi() and then converted to an unsigned int that would always compare successfully against >= 0, leaving a large positive metric in the route map. Signed-off-by: Scott Feldman --- ospfd/ospf_routemap.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index adf815839..d0ebce66e 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -443,12 +443,16 @@ static void * route_set_metric_compile (const char *arg) { u_int32_t *metric; + int32_t ret; metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - *metric = atoi (arg); + ret = atoi (arg); - if (*metric >= 0) - return metric; + if (ret >= 0) + { + *metric = (u_int32_t)ret; + return metric; + } XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); return NULL; From f92c57f8ba4f1e856934ec1736be3cad62be4785 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 13:29:21 -0800 Subject: [PATCH 0188/1342] ospfd: Update comments to be more clear in packet processing Signed-off-by: Scott Feldman --- ospfd/ospf_packet.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index d79df5354..a51db246d 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1761,7 +1761,11 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, ospf_lsa_discard (L); \ continue; } - /* Process each LSA received in the one packet. */ + /* Process each LSA received in the one packet. + * + * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding + * text below are from the stepsin RFC 2328, Section 13. + */ for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa)) { struct ospf_lsa *ls_ret, *current; @@ -1785,11 +1789,11 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, listnode_delete (lsas, lsa); /* We don't need it in list anymore */ - /* Validate Checksum - Done above by ospf_ls_upd_list_lsa() */ + /* (1) Validate Checksum - Done above by ospf_ls_upd_list_lsa() */ - /* LSA Type - Done above by ospf_ls_upd_list_lsa() */ + /* (2) LSA Type - Done above by ospf_ls_upd_list_lsa() */ - /* Do not take in AS External LSAs if we are a stub or NSSA. */ + /* (3) Do not take in AS External LSAs if we are a stub or NSSA. */ /* Do not take in AS NSSA if this neighbor and we are not NSSA */ @@ -1821,19 +1825,19 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, current = ospf_lsa_lookup_by_header (oi->area, lsa->data); - /* If the LSA's LS age is equal to MaxAge, and there is currently + /* (4) If the LSA's LS age is equal to MaxAge, and there is currently no instance of the LSA in the router's link state database, and none of router's neighbors are in states Exchange or Loading, - then take the following actions. */ + then take the following actions: */ if (IS_LSA_MAXAGE (lsa) && !current && (ospf_nbr_count (oi, NSM_Exchange) + ospf_nbr_count (oi, NSM_Loading)) == 0) { - /* Response Link State Acknowledgment. */ + /* (4a) Response Link State Acknowledgment. */ ospf_ls_ack_send (nbr, lsa); - /* Discard LSA. */ + /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF (lsa, LSA)) { zlog_debug ("Link State Update[%s]: LS age is equal to MaxAge.", @@ -1893,7 +1897,7 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, #endif /* HAVE_OPAQUE_LSA */ /* It might be happen that received LSA is self-originated network LSA, but - * router ID is cahnged. So, we should check if LSA is a network-LSA whose + * router ID is changed. So, we should check if LSA is a network-LSA whose * Link State ID is one of the router's own IP interface addresses but whose * Advertising Router is not equal to the router's own Router ID * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed. @@ -1932,7 +1936,9 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, /* (5) Find the instance of this LSA that is currently contained in the router's link state database. If there is no database copy, or the received LSA is more recent than - the database copy the following steps must be performed. */ + the database copy the following steps must be performed. + (The sub steps from RFC 2328 section 13 step (5) will be performed in + ospf_flood() ) */ if (current == NULL || (ret = ospf_lsa_more_recent (current, lsa)) < 0) From 7798b6321cd0c6281b1a119ac894ff3749e88cc1 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 13:33:24 -0800 Subject: [PATCH 0189/1342] lib: Changes to VTY string-parsing macros to remove warnings The VTY_GET_INTEGER_RANGE macro was being used also just to check the range on a variable that wasn't used (for the "no" version of a VTY command), so I split the macro into two. Also, since the variable is unsigned, if MIN is zero, you get a warning about comparing an unsigned number against 0, giving rise to slightly convoluted logic. Note that the previous two patches were found by the -Wtype-limits and -Wunused-variables warnings. Without the changes to these macros, these warnings are triggered erroneously, making it harder to find the real problems. Signed-off-by: Scott Feldman --- lib/vty.h | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/lib/vty.h b/lib/vty.h index e5158687d..1798585ec 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -149,8 +149,8 @@ struct vty #define PRINTF_ATTRIBUTE(a,b) #endif /* __GNUC__ */ -/* Utility macros to convert VTY argument to unsigned long or integer. */ -#define VTY_GET_LONG(NAME,V,STR) \ +/* Utility macros to convert VTY argument to unsigned long */ +#define VTY_GET_ULONG(NAME,V,STR) \ do { \ char *endptr = NULL; \ errno = 0; \ @@ -162,20 +162,38 @@ do { \ } \ } while (0) -#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ -do { \ - unsigned long tmpl; \ - VTY_GET_LONG(NAME, tmpl, STR); \ - if ( (tmpl < (MIN)) || (tmpl > (MAX))) \ - { \ - vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ - return CMD_WARNING; \ - } \ - (V) = tmpl; \ +/* + * The logic below ((TMPL) <= ((MIN) && (TMPL) != (MIN)) is + * done to circumvent the compiler complaining about + * comparing unsigned numbers against zero, if MIN is zero. + * NB: The compiler isn't smart enough to supress the warning + * if you write (MIN) != 0 && tmpl < (MIN). + */ +#define VTY_GET_INTEGER_RANGE_HEART(NAME,TMPL,STR,MIN,MAX) \ +do { \ + VTY_GET_ULONG(NAME, (TMPL), STR); \ + if ( ((TMPL) <= (MIN) && (TMPL) != (MIN)) || (TMPL) > (MAX) ) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);\ + return CMD_WARNING; \ + } \ +} while (0) + +#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ +do { \ + unsigned long tmpl; \ + VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \ + (V) = tmpl; \ +} while (0) + +#define VTY_CHECK_INTEGER_RANGE(NAME,STR,MIN,MAX) \ +do { \ + unsigned long tmpl; \ + VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \ } while (0) -#define VTY_GET_INTEGER(NAME,V,STR) \ - VTY_GET_INTEGER_RANGE(NAME,V,STR,0U,UINT32_MAX) +#define VTY_GET_INTEGER(NAME,V,STR) \ + VTY_GET_INTEGER_RANGE(NAME,V,STR,0U,UINT32_MAX) #define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \ do { \ From 703819a9314692f3a3b7f888887b0cebc15c18ae Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 13:36:41 -0800 Subject: [PATCH 0190/1342] ospfd: Changed TE instance check to remove -Wtype-limits warning Since LEGAL_TE_INSTANCE_RANGE() was being passed an unsigned int, a warning was being thrown due to the compare against >= 0. Since this macro was used only in one place, I removed the macro for an explict compare against a constant for the MAX. Signed-off-by: Scott Feldman --- ospfd/ospf_te.c | 2 +- ospfd/ospf_te.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 24e81052f..587564a19 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -205,7 +205,7 @@ get_mpls_te_instance_value (void) { static u_int32_t seqno = 0; - if (LEGAL_TE_INSTANCE_RANGE (seqno + 1)) + if (seqno < MAX_LEGAL_TE_INSTANCE_NUM ) seqno += 1; else seqno = 1; /* Avoid zero. */ diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h index e8511cdfb..863d8ba8f 100644 --- a/ospfd/ospf_te.h +++ b/ospfd/ospf_te.h @@ -41,7 +41,7 @@ * */ -#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff) +#define MAX_LEGAL_TE_INSTANCE_NUM (0xffff) /* * 24 16 8 0 From de54b26caca7442af29656282e753b02aac6f093 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 13:40:58 -0800 Subject: [PATCH 0191/1342] ospfd: Update nsm_change_state to static scope, as it is not called from elsewhere Signed-off-by: Scott Feldman --- ospfd/ospf_nsm.c | 2 +- ospfd/ospf_nsm.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index cbc31716b..436896c20 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -643,7 +643,7 @@ nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event) #endif } -void +static void nsm_change_state (struct ospf_neighbor *nbr, int state) { struct ospf_interface *oi = nbr->oi; diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h index 4f2ae8083..9b7e14a4a 100644 --- a/ospfd/ospf_nsm.h +++ b/ospfd/ospf_nsm.h @@ -81,7 +81,6 @@ /* Prototypes. */ extern int ospf_nsm_event (struct thread *); -extern void nsm_change_state (struct ospf_neighbor *, int); extern void ospf_check_nbr_loading (struct ospf_neighbor *); extern int ospf_db_summary_isempty (struct ospf_neighbor *); extern int ospf_db_summary_count (struct ospf_neighbor *); From 0798cee34f5c436cd2a4b6e1d9a1ca90eee94292 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Tue, 4 Dec 2012 13:43:42 -0800 Subject: [PATCH 0192/1342] ospfd: compile warning cleanups A set of patches to clarify some comments as well as cleanup code that was causing warnings. After these patches, the code can be compiled with -Wall -Wsign-compare -Wpointer-arith -Wbad-function-cast -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wchar-subscripts -Wcast-qual -Wextra -Wno-unused-parameter -Wno-missing-field-initializers (what is current in trunk plus -Wextra -Wno-unused-parameter -Wno-missing-field-initializers). Signed-off-by: Scott Feldman --- ospfd/ospf_apiserver.c | 5 +---- ospfd/ospf_ism.c | 5 ++--- ospfd/ospf_lsa.c | 4 +++- ospfd/ospf_lsa.h | 1 + ospfd/ospf_network.c | 8 ++++---- ospfd/ospf_network.h | 2 +- ospfd/ospf_nsm.c | 5 ----- ospfd/ospf_opaque.c | 12 +++++++++--- ospfd/ospf_packet.c | 2 +- ospfd/ospf_vty.c | 10 +++------- ospfd/ospf_zebra.c | 9 +++------ ospfd/ospf_zebra.h | 2 +- ospfd/ospfd.c | 2 +- ospfd/ospfd.h | 2 +- 14 files changed, 31 insertions(+), 38 deletions(-) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 84d70ccc1..db1ccda72 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -299,13 +299,10 @@ void ospf_apiserver_event (enum event event, int fd, struct ospf_apiserver *apiserv) { - struct thread *apiserver_serv_thread; - switch (event) { case OSPF_APISERVER_ACCEPT: - apiserver_serv_thread = - thread_add_read (master, ospf_apiserver_accept, apiserv, fd); + (void)thread_add_read (master, ospf_apiserver_accept, apiserv, fd); break; case OSPF_APISERVER_SYNC_READ: apiserv->t_sync_read = diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index db53882d0..fa7d97f2f 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -203,7 +203,6 @@ ospf_dr_election (struct ospf_interface *oi) struct in_addr old_dr, old_bdr; int old_state, new_state; struct list *el_list; - struct ospf_neighbor *dr, *bdr; /* backup current values. */ old_dr = DR (oi); @@ -216,8 +215,8 @@ ospf_dr_election (struct ospf_interface *oi) ospf_dr_eligible_routers (oi->nbrs, el_list); /* First election of DR and BDR. */ - bdr = ospf_elect_bdr (oi, el_list); - dr = ospf_elect_dr (oi, el_list); + ospf_elect_bdr (oi, el_list); + ospf_elect_dr (oi, el_list); new_state = ospf_ism_state (oi); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index fb55f7ff1..4f7fb00aa 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2733,7 +2733,9 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, if (IS_LSA_SELF (lsa)) lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ else - ; /* Incoming "oi" for this LSA has set at LSUpd reception. */ + { + /* Incoming "oi" for this LSA has set at LSUpd reception. */ + } /* Fallthrough */ case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 6c95ff177..9ff2d9204 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -243,6 +243,7 @@ extern int tv_cmp (struct timeval, struct timeval); extern int get_age (struct ospf_lsa *); extern u_int16_t ospf_lsa_checksum (struct lsa_header *); +extern int ospf_lsa_checksum_valid (struct lsa_header *); extern int ospf_lsa_refresh_delay (struct ospf_lsa *); extern const char *dump_lsa_key (struct ospf_lsa *); diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 3e326a8c3..900a5667d 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -228,7 +228,7 @@ ospf_sock_init (void) } void -ospf_adjust_sndbuflen (struct ospf * ospf, int buflen) +ospf_adjust_sndbuflen (struct ospf * ospf, unsigned int buflen) { int ret, newbuflen; /* Check if any work has to be done at all. */ @@ -249,11 +249,11 @@ ospf_adjust_sndbuflen (struct ospf * ospf, int buflen) */ ret = setsockopt_so_sendbuf (ospf->fd, buflen); newbuflen = getsockopt_so_sendbuf (ospf->fd); - if (ret < 0 || newbuflen < buflen) - zlog_warn ("%s: tried to set SO_SNDBUF to %d, but got %d", + if (ret < 0 || newbuflen < 0 || newbuflen < (int) buflen) + zlog_warn ("%s: tried to set SO_SNDBUF to %u, but got %d", __func__, buflen, newbuflen); if (newbuflen >= 0) - ospf->maxsndbuflen = newbuflen; + ospf->maxsndbuflen = (unsigned int)newbuflen; else zlog_warn ("%s: failed to get SO_SNDBUF", __func__); if (ospfd_privs.change (ZPRIVS_LOWER)) diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h index f69099127..e0a5c69d5 100644 --- a/ospfd/ospf_network.h +++ b/ospfd/ospf_network.h @@ -34,6 +34,6 @@ extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); extern int ospf_sock_init (void); -extern void ospf_adjust_sndbuflen (struct ospf *, int); +extern void ospf_adjust_sndbuflen (struct ospf *, unsigned int); #endif /* _ZEBRA_OSPF_NETWORK_H */ diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 436896c20..fe4ddf5b2 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -72,14 +72,11 @@ ospf_inactivity_timer (struct thread *thread) static int ospf_db_desc_timer (struct thread *thread) { - struct ospf_interface *oi; struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_db_desc = NULL; - oi = nbr->oi; - if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)", IF_NAME (nbr->oi), inet_ntoa (nbr->src)); @@ -787,11 +784,9 @@ ospf_nsm_event (struct thread *thread) int event; int next_state; struct ospf_neighbor *nbr; - struct in_addr router_id; nbr = THREAD_ARG (thread); event = THREAD_VAL (thread); - router_id = nbr->router_id; if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi), diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index aa126e192..744952c96 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -223,9 +223,15 @@ ospf_opaque_type_name (u_char opaque_type) default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; - /* XXX warning: comparison is always true due to limited range of data type */ - else if (OPAQUE_TYPE_RANGE_RESERVED (opaque_type)) - name = "Private/Experimental"; + else + { + u_int32_t bigger_range = opaque_type; + /* + * Get around type-limits warning: comparison is always true due to limited range of data type + */ + if (OPAQUE_TYPE_RANGE_RESERVED (bigger_range)) + name = "Private/Experimental"; + } break; } return name; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index a51db246d..9a4587d96 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1764,7 +1764,7 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, /* Process each LSA received in the one packet. * * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding - * text below are from the stepsin RFC 2328, Section 13. + * text below are from the steps in RFC 2328, Section 13. */ for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa)) { diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 45ddc5c40..2ba8188c7 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -1742,12 +1742,11 @@ DEFUN (no_ospf_area_default_cost, struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; - u_int32_t cost; int format; struct prefix_ipv4 p; VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); - VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215); + VTY_CHECK_INTEGER_RANGE ("stub default cost", argv[1], 0, OSPF_LS_INFINITY); area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) @@ -1933,7 +1932,6 @@ DEFUN (no_ospf_area_filter_list, struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; - struct prefix_list *plist; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); @@ -1941,7 +1939,6 @@ DEFUN (no_ospf_area_filter_list, if ((area = ospf_area_lookup_by_area_id (ospf, area_id)) == NULL) return CMD_SUCCESS; - plist = prefix_list_lookup (AFI_IP, argv[1]); if (strncmp (argv[2], "in", 2) == 0) { if (PREFIX_NAME_IN (area)) @@ -2394,11 +2391,10 @@ DEFUN (no_ospf_neighbor, { struct ospf *ospf = vty->index; struct in_addr nbr_addr; - int ret; VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); - ret = ospf_nbr_nbma_unset (ospf, nbr_addr); + (void)ospf_nbr_nbma_unset (ospf, nbr_addr); return CMD_SUCCESS; } @@ -5408,7 +5404,7 @@ DEFUN (ip_ospf_priority, "Address of interface") { struct interface *ifp = vty->index; - u_int32_t priority; + long priority; struct route_node *rn; struct in_addr addr; int ret; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index f5f49f644..34a3b2a7f 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -133,8 +133,8 @@ ospf_interface_delete (int command, struct zclient *zclient, if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug - ("Zebra: interface delete %s index %d flags %lld metric %d mtu %d", - ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + ("Zebra: interface delete %s index %d flags %llx metric %d mtu %d", + ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); #ifdef HAVE_SNMP ospf_snmp_if_delete (ifp); @@ -1004,7 +1004,7 @@ ospf_distribute_list_update_timer (struct thread *thread) /* Update distribute-list and set timer to apply access-list. */ void -ospf_distribute_list_update (struct ospf *ospf, int type) +ospf_distribute_list_update (struct ospf *ospf, uintptr_t type) { struct route_table *rt; @@ -1217,7 +1217,6 @@ ospf_distance_unset (struct vty *vty, struct ospf *ospf, { int ret; struct prefix_ipv4 p; - u_char distance; struct route_node *rn; struct ospf_distance *odistance; @@ -1228,8 +1227,6 @@ ospf_distance_unset (struct vty *vty, struct ospf *ospf, return CMD_WARNING; } - distance = atoi (distance_str); - rn = route_node_lookup (ospf->distance_table, (struct prefix *) &p); if (!rn) { diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index fbb344424..148f6520f 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -54,7 +54,7 @@ extern int ospf_redistribute_check (struct ospf *, struct external_info *, int *); extern int ospf_distribute_check_connected (struct ospf *, struct external_info *); -extern void ospf_distribute_list_update (struct ospf *, int); +extern void ospf_distribute_list_update (struct ospf *, uintptr_t); extern int ospf_is_type_redistributed (int); extern void ospf_distance_reset (struct ospf *); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index d1de29d5e..3e2b23480 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -223,7 +223,7 @@ ospf_new (void) } new->maxsndbuflen = getsockopt_so_sendbuf (new->fd); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) - zlog_debug ("%s: starting with OSPF send buffer size %d", + zlog_debug ("%s: starting with OSPF send buffer size %u", __func__, new->maxsndbuflen); if ((new->ibuf = stream_new(OSPF_MAX_PACKET_SIZE+1)) == NULL) { diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index cc27f66ed..fb57bf514 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -273,7 +273,7 @@ struct ospf struct thread *t_write; struct thread *t_read; int fd; - int maxsndbuflen; + unsigned int maxsndbuflen; struct stream *ibuf; struct list *oi_write_q; From d265548ffb8da9ba3e1dd327efbff31c7cd15027 Mon Sep 17 00:00:00 2001 From: Vishal Kumar Date: Fri, 7 Dec 2012 14:47:58 -0800 Subject: [PATCH 0193/1342] ospfd: Corrected ospfd Type-4/Type-5 ls update handling This fix is for Type-4 LS updates handling at a ABR router where ospf daemon is not distributing Type-4 LS updates with correct LS-Age after learning about a ASBR router in a ospf network. Because of this Type-5 LS updates are not learnt in ospf network. Testing Scenario: This can be re-produced by restarting the ospfd daemon on DUT (mentioned in figure below)before the Hello time interval expires for area 0.0.0.1. ____ _______ ____ _________ | | area: 0.0.0.1 | | area: 0.0.0.0 | | area: 0.0.0.2 | | | R1 |---------------------|DUT/ABR|---------------------| R2 |------------------| R3/ASBR | |____| x.x.x.0/24 |_______| y.y.y.0/64 |____| z.z.z.0/24 |_________| In the above setup when ospfd is restarted (imp:before the Hello interval at R1 expires) and DUT learns about ASBR router R3 (Type-4) in the network from R2, but this ls-update is not propagates in area 0.0.0.1. So R1 never comes to know about the ASBR router in the network, so all the type-5 LS updates coming from R3 are not learnt by R1. Further if we again restart ospfd daemon it starts working fine. With the fix given this issue can be resolved. More Discussion on this is available at: http://www.gossamer-threads.com/lists/quagga/dev/23892 Signed-off-by: Scott Feldman --- ospfd/ospf_abr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index f5edc99e5..4770275d4 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1140,7 +1140,8 @@ ospf_abr_announce_rtr_to_area (struct prefix_ipv4 *p, u_int32_t cost, GET_METRIC (slsa->metric), cost); } - if (old && (GET_METRIC (slsa->metric) == cost)) + if (old && (GET_METRIC (slsa->metric) == cost) && + ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): old summary approved"); From e0630cb4d61557f956318a088f68f1fc4d261ef3 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Mon, 7 Jan 2013 10:12:52 -0800 Subject: [PATCH 0194/1342] ospfd: Remove dup MaxAge LSA flood Stop additional, unnecessary flooding of MaxAge LSAs. When a MaxAge LSA is installed, if the LSA is prematurely aged or the LSA is not self-originated, the LSA is flushed. This results in a the LSA being flooded a second time and in some cases flooded back to the receiver (unless the receiver is also the advertising router). A MaxAge'd LSA has already been flooded in ospf_flood() as part of the LSA receive processing (ospf_ls_upd). A self-originated LSA will be flooded from the originate/refresh routine. Thus, in the install routine, a MaxAge'd LSA only needs to be added to the MaxAge LSA list. Signed-off-by: Dinesh G Dutt Signed-off-by: Scott Feldman --- ospfd/ospf_lsa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 4f7fb00aa..dfd1a61e2 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2780,15 +2780,14 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, If received LSA' ls_age is MaxAge, or lsa is being prematurely aged (it's getting flushed out of the area), set LSA on MaxAge LSA list. */ - if ((lsa->flags & OSPF_LSA_PREMATURE_AGE) || - (IS_LSA_MAXAGE (new) && !IS_LSA_SELF (new))) + if (IS_LSA_MAXAGE (new)) { if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("LSA[Type%d:%s]: Install LSA 0x%p, MaxAge", new->data->type, inet_ntoa (new->data->id), lsa); - ospf_lsa_flush (ospf, lsa); + ospf_lsa_maxage (ospf, lsa); } return new; From 327c4cdf7578debcc140f04f03d02479771c9e11 Mon Sep 17 00:00:00 2001 From: Doug VanLeuven Date: Fri, 14 Dec 2012 14:58:30 +0200 Subject: [PATCH 0195/1342] testzebra: pragma weak: detect systems with weak alias and provide alternative LLVM clang does not support #pragma weak (bug 3679) on OS X. There are other systems where the #pragma weak has varying syntax. Added m4 file from the autoconf archives: http://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html Fix up zebra/*_null.c files to use #pragma weak alias or stub functions if not available. It's incomplete in that the different format #pragma enable easier fixes on need. Tested on 64bit OS X 10.7, FreeBSD 9.0 amd64 & i386 (32bit) using gcc & clang. Tested on linux 64bit. Signed-off-by: David Lamparter --- .gitignore | 1 + configure.ac | 16 ++ m4/ax_sys_weak_alias.m4 | 337 ++++++++++++++++++++++++++++++++++++++ zebra/ioctl_null.c | 13 ++ zebra/kernel_null.c | 14 ++ zebra/misc_null.c | 6 + zebra/redistribute_null.c | 29 ++++ 7 files changed, 416 insertions(+) create mode 100644 m4/ax_sys_weak_alias.m4 diff --git a/.gitignore b/.gitignore index 516ed611b..48e6b38b9 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ build *~ *.loT m4/*.m4 +!m4/ax_sys_weak_alias.m4 diff --git a/configure.ac b/configure.ac index 405693c9b..c51a0d3ee 100755 --- a/configure.ac +++ b/configure.ac @@ -1540,6 +1540,22 @@ if test "${enable_capabilities}" != "no"; then fi AC_SUBST(LIBCAP) +dnl --------------------------------------------------------------------------- +dnl http://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html +dnl Check for and set one of the following = 1 +dnl HAVE_SYS_WEAK_ALIAS_ATTRIBUTE +dnl HAVE_SYS_WEAK_ALIAS_PRAGMA +dnl HAVE_SYS_WEAK_ALIAS_HPSECONDARY +dnl HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE +dnl If any scheme is found, set +dnl HAVE_SYS_WEAK_ALIAS=1 +dnl The following variable is set to text value +dnl WEAK_ALIAS = "attribute" || "pragma" || "hpsecondary" || "criduplicate" || "no" +dnl If weak alias can cross object file boundaries +dnl WEAK_ALIAS_CROSSFILE = "yes" || "no" +dnl --------------------------------------------------------------------------- +AX_SYS_WEAK_ALIAS + dnl --------------------------- dnl check for glibc 'backtrace' dnl --------------------------- diff --git a/m4/ax_sys_weak_alias.m4 b/m4/ax_sys_weak_alias.m4 new file mode 100644 index 000000000..7c632a0ed --- /dev/null +++ b/m4/ax_sys_weak_alias.m4 @@ -0,0 +1,337 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_SYS_WEAK_ALIAS +# +# DESCRIPTION +# +# Determines whether weak aliases are supported on the system, and if so, +# what scheme is used to declare them. Also checks to see if aliases can +# cross object file boundaries, as some systems don't permit them to. +# +# Most systems permit something called a "weak alias" or "weak symbol." +# These aliases permit a library to provide a stub form of a routine +# defined in another library, thus allowing the first library to operate +# even if the other library is not linked. This macro will check for +# support of weak aliases, figure out what schemes are available, and +# determine some characteristics of the weak alias support -- primarily, +# whether a weak alias declared in one object file may be referenced from +# another object file. +# +# There are four known schemes of declaring weak symbols; each scheme is +# checked in turn, and the first one found is prefered. Note that only one +# of the mentioned preprocessor macros will be defined! +# +# 1. Function attributes +# +# This scheme was first introduced by the GNU C compiler, and attaches +# attributes to particular functions. It is among the easiest to use, and +# so is the first one checked. If this scheme is detected, the +# preprocessor macro HAVE_SYS_WEAK_ALIAS_ATTRIBUTE will be defined to 1. +# This scheme is used as in the following code fragment: +# +# void __weakf(int c) +# { +# /* Function definition... */ +# } +# +# void weakf(int c) __attribute__((weak, alias("__weakf"))); +# +# 2. #pragma weak +# +# This scheme is in use by many compilers other than the GNU C compiler. +# It is also particularly easy to use, and fairly portable -- well, as +# portable as these things get. If this scheme is detected first, the +# preprocessor macro HAVE_SYS_WEAK_ALIAS_PRAGMA will be defined to 1. This +# scheme is used as in the following code fragment: +# +# extern void weakf(int c); +# #pragma weak weakf = __weakf +# void __weakf(int c) +# { +# /* Function definition... */ +# } +# +# 3. #pragma _HP_SECONDARY_DEF +# +# This scheme appears to be in use by the HP compiler. As it is rather +# specialized, this is one of the last schemes checked. If it is the first +# one detected, the preprocessor macro HAVE_SYS_WEAK_ALIAS_HPSECONDARY +# will be defined to 1. This scheme is used as in the following code +# fragment: +# +# extern void weakf(int c); +# #pragma _HP_SECONDARY_DEF __weakf weakf +# void __weakf(int c) +# { +# /* Function definition... */ +# } +# +# 4. #pragma _CRI duplicate +# +# This scheme appears to be in use by the Cray compiler. As it is rather +# specialized, it too is one of the last schemes checked. If it is the +# first one detected, the preprocessor macro +# HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE will be defined to 1. This scheme is +# used as in the following code fragment: +# +# extern void weakf(int c); +# #pragma _CRI duplicate weakf as __weakf +# void __weakf(int c) +# { +# /* Function definition... */ +# } +# +# In addition to the preprocessor macros listed above, if any scheme is +# found, the preprocessor macro HAVE_SYS_WEAK_ALIAS will also be defined +# to 1. +# +# Once a weak aliasing scheme has been found, a check will be performed to +# see if weak aliases are honored across object file boundaries. If they +# are, the HAVE_SYS_WEAK_ALIAS_CROSSFILE preprocessor macro is defined to +# 1. +# +# This Autoconf macro also makes two substitutions. The first, WEAK_ALIAS, +# contains the name of the scheme found (one of "attribute", "pragma", +# "hpsecondary", or "criduplicate"), or "no" if no weak aliasing scheme +# was found. The second, WEAK_ALIAS_CROSSFILE, is set to "yes" or "no" +# depending on whether or not weak aliases may cross object file +# boundaries. +# +# LICENSE +# +# Copyright (c) 2008 Kevin L. Mitchell +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AU_ALIAS([KLM_SYS_WEAK_ALIAS], [AX_SYS_WEAK_ALIAS]) +AC_DEFUN([AX_SYS_WEAK_ALIAS], [ + # starting point: no aliasing scheme yet... + ax_sys_weak_alias=no + + # Figure out what kind of aliasing may be supported... + _AX_SYS_WEAK_ALIAS_ATTRIBUTE + _AX_SYS_WEAK_ALIAS_PRAGMA + _AX_SYS_WEAK_ALIAS_HPSECONDARY + _AX_SYS_WEAK_ALIAS_CRIDUPLICATE + + # Do we actually support aliasing? + AC_CACHE_CHECK([how to create weak aliases with $CC], + [ax_cv_sys_weak_alias], + [ax_cv_sys_weak_alias=$ax_sys_weak_alias]) + + # OK, set a #define + AS_IF([test $ax_cv_sys_weak_alias != no], [ + AC_DEFINE([HAVE_SYS_WEAK_ALIAS], 1, + [Define this if your system can create weak aliases]) + ]) + + # Can aliases cross object file boundaries? + _AX_SYS_WEAK_ALIAS_CROSSFILE + + # OK, remember the results + AC_SUBST([WEAK_ALIAS], [$ax_cv_sys_weak_alias]) + AC_SUBST([WEAK_ALIAS_CROSSFILE], [$ax_cv_sys_weak_alias_crossfile]) +]) + +AC_DEFUN([_AX_SYS_WEAK_ALIAS_ATTRIBUTE], +[ # Test whether compiler accepts __attribute__ form of weak aliasing + AC_CACHE_CHECK([whether $CC accepts function __attribute__((weak,alias()))], + [ax_cv_sys_weak_alias_attribute], [ + # We add -Werror if it's gcc to force an error exit if the weak attribute + # isn't understood + AS_IF([test $GCC = yes], [ + save_CFLAGS=$CFLAGS + CFLAGS=-Werror]) + + # Try linking with a weak alias... + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +void __weakf(int c) {} +void weakf(int c) __attribute__((weak, alias("__weakf")));], + [weakf(0)])], + [ax_cv_sys_weak_alias_attribute=yes], + [ax_cv_sys_weak_alias_attribute=no]) + + # Restore original CFLAGS + AS_IF([test $GCC = yes], [ + CFLAGS=$save_CFLAGS]) + ]) + + # What was the result of the test? + AS_IF([test $ax_sys_weak_alias = no && + test $ax_cv_sys_weak_alias_attribute = yes], [ + ax_sys_weak_alias=attribute + AC_DEFINE([HAVE_SYS_WEAK_ALIAS_ATTRIBUTE], 1, + [Define this if weak aliases may be created with __attribute__]) + ]) +]) + +AC_DEFUN([_AX_SYS_WEAK_ALIAS_PRAGMA], +[ # Test whether compiler accepts #pragma form of weak aliasing + AC_CACHE_CHECK([whether $CC supports @%:@pragma weak], + [ax_cv_sys_weak_alias_pragma], [ + + # Try linking with a weak alias... + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +extern void weakf(int c); +@%:@pragma weak weakf = __weakf +void __weakf(int c) {}], + [weakf(0)])], + [ax_cv_sys_weak_alias_pragma=yes], + [ax_cv_sys_weak_alias_pragma=no]) + ]) + + # What was the result of the test? + AS_IF([test $ax_sys_weak_alias = no && + test $ax_cv_sys_weak_alias_pragma = yes], [ + ax_sys_weak_alias=pragma + AC_DEFINE([HAVE_SYS_WEAK_ALIAS_PRAGMA], 1, + [Define this if weak aliases may be created with @%:@pragma weak]) + ]) +]) + +AC_DEFUN([_AX_SYS_WEAK_ALIAS_HPSECONDARY], +[ # Test whether compiler accepts _HP_SECONDARY_DEF pragma from HP... + AC_CACHE_CHECK([whether $CC supports @%:@pragma _HP_SECONDARY_DEF], + [ax_cv_sys_weak_alias_hpsecondary], [ + + # Try linking with a weak alias... + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +extern void weakf(int c); +@%:@pragma _HP_SECONDARY_DEF __weakf weakf +void __weakf(int c) {}], + [weakf(0)])], + [ax_cv_sys_weak_alias_hpsecondary=yes], + [ax_cv_sys_weak_alias_hpsecondary=no]) + ]) + + # What was the result of the test? + AS_IF([test $ax_sys_weak_alias = no && + test $ax_cv_sys_weak_alias_hpsecondary = yes], [ + ax_sys_weak_alias=hpsecondary + AC_DEFINE([HAVE_SYS_WEAK_ALIAS_HPSECONDARY], 1, + [Define this if weak aliases may be created with @%:@pragma _HP_SECONDARY_DEF]) + ]) +]) + +AC_DEFUN([_AX_SYS_WEAK_ALIAS_CRIDUPLICATE], +[ # Test whether compiler accepts "_CRI duplicate" pragma from Cray + AC_CACHE_CHECK([whether $CC supports @%:@pragma _CRI duplicate], + [ax_cv_sys_weak_alias_criduplicate], [ + + # Try linking with a weak alias... + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +extern void weakf(int c); +@%:@pragma _CRI duplicate weakf as __weakf +void __weakf(int c) {}], + [weakf(0)])], + [ax_cv_sys_weak_alias_criduplicate=yes], + [ax_cv_sys_weak_alias_criduplicate=no]) + ]) + + # What was the result of the test? + AS_IF([test $ax_sys_weak_alias = no && + test $ax_cv_sys_weak_alias_criduplicate = yes], [ + ax_sys_weak_alias=criduplicate + AC_DEFINE([HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE], 1, + [Define this if weak aliases may be created with @%:@pragma _CRI duplicate]) + ]) +]) + +dnl Note: This macro is modeled closely on AC_LINK_IFELSE, and in fact +dnl depends on some implementation details of that macro, particularly +dnl its use of _AC_MSG_LOG_CONFTEST to log the failed test program and +dnl its use of ac_link for running the linker. +AC_DEFUN([_AX_SYS_WEAK_ALIAS_CROSSFILE], +[ # Check to see if weak aliases can cross object file boundaries + AC_CACHE_CHECK([whether $CC supports weak aliases across object file boundaries], + [ax_cv_sys_weak_alias_crossfile], [ + AS_IF([test $ax_cv_sys_weak_alias = no], + [ax_cv_sys_weak_alias_crossfile=no], [ +dnl Must build our own test files... + # conftest1 contains our weak alias definition... + cat >conftest1.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF + cat confdefs.h >>conftest1.$ac_ext + cat >>conftest1.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +@%:@ifndef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE +extern void weakf(int c); +@%:@endif +@%:@if defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) +@%:@pragma weak weakf = __weakf +@%:@elif defined(HAVE_SYS_WEAK_ALIAS_HPSECONDARY) +@%:@pragma _HP_SECONDARY_DEF __weakf weakf +@%:@elif defined(HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE) +@%:@pragma _CRI duplicate weakf as __weakf +@%:@endif +void __weakf(int c) {} +@%:@ifdef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE +void weakf(int c) __attribute((weak, alias("__weakf"))); +@%:@endif +_ACEOF + # And conftest2 contains our main routine that calls it + cat >conftest2.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF + cat confdefs.h >> conftest2.$ac_ext + cat >>conftest2.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +extern void weakf(int c); +int +main () +{ + weakf(0); + return 0; +} +_ACEOF + # We must remove the object files (if any) ourselves... + rm -f conftest2.$ac_objext conftest$ac_exeext + + # Change ac_link to compile *2* files together + save_aclink=$ac_link + ac_link=`echo "$ac_link" | \ + sed -e 's/conftest\(\.\$ac_ext\)/conftest1\1 conftest2\1/'` +dnl Substitute our own routine for logging the conftest +m4_pushdef([_AC_MSG_LOG_CONFTEST], +[echo "$as_me: failed program was:" >&AS_MESSAGE_LOG_FD +echo ">>> conftest1.$ac_ext" >&AS_MESSAGE_LOG_FD +sed "s/^/| /" conftest1.$ac_ext >&AS_MESSAGE_LOG_FD +echo ">>> conftest2.$ac_ext" >&AS_MESSAGE_LOG_FD +sed "s/^/| /" conftest2.$ac_ext >&AS_MESSAGE_LOG_FD +])dnl + # Since we created the files ourselves, don't use SOURCE argument + AC_LINK_IFELSE(, [ax_cv_sys_weak_alias_crossfile=yes], + [ax_cv_sys_weak_alias_crossfile=no]) +dnl Restore _AC_MSG_LOG_CONFTEST +m4_popdef([_AC_MSG_LOG_CONFTEST])dnl + # Restore ac_link + ac_link=$save_aclink + + # We must remove the object files (if any) and C files ourselves... + rm -f conftest1.$ac_ext conftest2.$ac_ext \ + conftest1.$ac_objext conftest2.$ac_objext + ]) + ]) + + # What were the results of the test? + AS_IF([test $ax_cv_sys_weak_alias_crossfile = yes], [ + AC_DEFINE([HAVE_SYS_WEAK_ALIAS_CROSSFILE], 1, + [Define this if weak aliases in other files are honored]) + ]) +]) diff --git a/zebra/ioctl_null.c b/zebra/ioctl_null.c index 6d8e13a06..5d046d36d 100644 --- a/zebra/ioctl_null.c +++ b/zebra/ioctl_null.c @@ -19,16 +19,29 @@ int if_unset_prefix (struct interface *a, struct connected *b) } int if_prefix_add_ipv6 (struct interface *a, struct connected *b) { return 0; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak if_prefix_delete_ipv6 = if_prefix_add_ipv6 +#else +int if_prefix_delete_ipv6 (struct interface *a, struct connected *b) { return 0; } +#endif int if_ioctl (u_long a, caddr_t b) { return 0; } int if_set_flags (struct interface *a, uint64_t b) { return 0; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak if_unset_flags = if_set_flags +#else +int if_unset_flags (struct interface *a, uint64_t b) { return 0; } +#endif void if_get_flags (struct interface *a) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak if_get_metric = if_get_flags #pragma weak if_get_mtu = if_get_flags +#else +/* void if_get_metric (struct interface *a) { return; } */ +/* void if_get_mtu (struct interface *a) { return; } */ +#endif #ifdef SOLARIS_IPV6 #pragma weak if_ioctl_ipv6 = if_ioctl diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 6b96c6df1..ec994a6bf 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -9,9 +9,19 @@ #include "zebra/connected.h" int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak kernel_delete_ipv4 = kernel_add_ipv4 +#else +int kernel_delete_ipv4 (struct prefix *a, struct rib *b) { return 0; } +#endif + int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA_PRAGMA #pragma weak kernel_delete_ipv6 = kernel_add_ipv6 +#else +int kernel_delete_ipv6 (struct prefix *a, struct rib *b) { return 0; } +#endif + int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table) { return 0; } @@ -38,4 +48,8 @@ int kernel_address_delete_ipv4 (struct interface *a, struct connected *b) } void kernel_init (void) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak route_read = kernel_init +#else +void route_read (void) { return; } +#endif diff --git a/zebra/misc_null.c b/zebra/misc_null.c index c8cc47d1d..06807267e 100644 --- a/zebra/misc_null.c +++ b/zebra/misc_null.c @@ -7,9 +7,15 @@ #include "zebra/zebra_fpm.h" void ifstat_update_proc (void) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak rtadv_config_write = ifstat_update_proc #pragma weak irdp_config_write = ifstat_update_proc #pragma weak ifstat_update_sysctl = ifstat_update_proc +#else +void rtadv_config_write (struct vty *vty, struct interface *ifp) { return; } +void irdp_config_write (struct vty *vty, struct interface *ifp) { return; } +void ifstat_update_sysctl (void) { return; } +#endif void zfpm_trigger_update (struct route_node *rn, const char *reason) diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index e57a73b9c..54198c8e6 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -6,21 +6,50 @@ void zebra_redistribute_add (int a, struct zserv *b, int c) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_redistribute_delete = zebra_redistribute_add #pragma weak zebra_redistribute_default_add = zebra_redistribute_add #pragma weak zebra_redistribute_default_delete = zebra_redistribute_add +#else +void zebra_redistribute_delete (int a, struct zserv *b, int c) +{ return; } +void zebra_redistribute_default_add (int a, struct zserv *b, int c) +{ return; } +void zebra_redistribute_default_delete (int a, struct zserv *b, int c) +{ return; } +#endif void redistribute_add (struct prefix *a, struct rib *b) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak redistribute_delete = redistribute_add +#else +void redistribute_delete (struct prefix *a, struct rib *b) +{ return; } +#endif void zebra_interface_up_update (struct interface *a) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_interface_down_update = zebra_interface_up_update #pragma weak zebra_interface_add_update = zebra_interface_up_update #pragma weak zebra_interface_delete_update = zebra_interface_up_update +#else +void zebra_interface_down_update (struct interface *a) +{ return; } +void zebra_interface_add_update (struct interface *a) +{ return; } +void zebra_interface_delete_update (struct interface *a) +{ return; } +#endif void zebra_interface_address_add_update (struct interface *a, struct connected *b) { return; } +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_interface_address_delete_update = zebra_interface_address_add_update +#else +void zebra_interface_address_delete_update (struct interface *a, + struct connected *b) +{ return; } +#endif From 675769b1b17a068526d90786e1c35304656faba7 Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Fri, 14 Dec 2012 14:58:31 +0200 Subject: [PATCH 0196/1342] build: MacOSX needs BSD struct ip_mreq hack too Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c51a0d3ee..b69c99d54 100755 --- a/configure.ac +++ b/configure.ac @@ -978,7 +978,7 @@ AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES) AC_MSG_CHECKING([for BSD struct ip_mreq hack]) AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H #include -#endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) +#endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) return (0); #else #error No support for BSD struct ip_mreq hack detected From 61be0ee8824b30e94ddd2bfe8b51fcfd330c41dd Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Fri, 14 Dec 2012 14:58:32 +0200 Subject: [PATCH 0197/1342] build: Fix build for systems with no /bin/true There are systems with no /bin/true - it might have different path (/usr/bin/true) or even a shell builtin. Signed-off-by: David Lamparter --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index 0ec5b4c92..d7c31edb4 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -61,5 +61,5 @@ gitversion.h: gitversion.h.tmp else .PHONY: gitversion.h gitversion.h: - /bin/true + true endif From 913ff66ba30093d2fdc26af215f4bc0b3d359d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=B9=8F?= Date: Wed, 21 Nov 2012 18:15:43 +0800 Subject: [PATCH 0198/1342] zebra: fix netlink NL_PKT_BUF_SIZE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change default value of variable NL_PKT_BUF_SIZE to 8192UL. Cf. NLMSG_GOODSIZE definition of linux in include/linux/netlink.h for detail. Previously, on platforms with a page size greater than 8192, if you had added too many interfaces, zebra would not have enough buffer space to get the entire interface list. This resulted in an incomplete interface list. From: é«˜é¹ [updated to apply after FPM patches] Signed-off-by: David Lamparter --- zebra/rt_netlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 529fa517a..452b3974e 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -24,7 +24,7 @@ #ifdef HAVE_NETLINK -#define NL_PKT_BUF_SIZE 4096 +#define NL_PKT_BUF_SIZE 8192 extern int addattr32 (struct nlmsghdr *n, int maxlen, int type, int data); From a5c851c7ff41ef846e83d62394176ac1753ebf45 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Nov 2012 03:21:44 +0100 Subject: [PATCH 0199/1342] lib: remove ALL_LIST_ELEMENTS dead code branch ALL_LIST_ELEMENTS is checking node == NULL twice, which is causing a whole slew of false positives in Coverity. In this particular case, addressing this in the code is reasonable; being a macro, this appears all over the place without easy remedy. Acked-by: Scott Feldman Signed-off-by: David Lamparter --- lib/linklist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/linklist.h b/lib/linklist.h index f0ae36256..24a9e2069 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -90,7 +90,7 @@ extern void list_add_list (struct list *, struct list *); #define ALL_LIST_ELEMENTS(list,node,nextnode,data) \ (node) = listhead(list), ((data) = NULL); \ (node) != NULL && \ - ((data) = listgetdata(node),(nextnode) = listnextnode(node), 1); \ + ((data) = listgetdata(node),(nextnode) = node->next, 1); \ (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. From ebbb5fca5ca899a9a125aa2770d3fdf857186bac Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 15:17:33 +0000 Subject: [PATCH 0200/1342] bgpd: fix for leaked struct bgp_adj_[in|out] on peer shutdown If a peer with soft-reconfiguration configured is cleared, the function bgp_clear_route_table() doesn't free the bgp_adj_in and bgp_adj_out structures of route nodes that for some reason, ej. denied by a filter, don't have routes attached "rn->info == NULL". Signed-off-by: Jorge Boncompte [DTI2] Reviewed-by: Leonid Rosenboim Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2412503d3..9251d2c22 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2810,9 +2810,6 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_info *ri; struct bgp_adj_in *ain; struct bgp_adj_out *aout; - - if (rn->info == NULL) - continue; /* XXX:TODO: This is suboptimal, every non-empty route_node is * queued for every clearing peer, regardless of whether it is From 24e50f2013e64a73b1f7ecdbd5688360002d09f7 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Mon, 7 May 2012 15:17:33 +0000 Subject: [PATCH 0201/1342] bgpd: avoid heap fragmentation in bgp_clear_route_table In bgp_clear_route_table, moved cleanup code before the allocation of the work queue items. This returns the memory to the system allocator before allocating new and might therefore help avoiding heap fragmentation. * bgp_route.c: (bgp_clear_route_table) moved code blocks. Signed-off-by: Jorge Boncompte [DTI2] Reviewed-by: Leonid Rosenboim Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9251d2c22..6155bc165 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2842,6 +2842,21 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, * this may actually be achievable. It doesn't seem to be a huge * problem at this time, */ + for (ain = rn->adj_in; ain; ain = ain->next) + if (ain->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) + { + bgp_adj_in_remove (rn, ain); + bgp_unlock_node (rn); + break; + } + for (aout = rn->adj_out; aout; aout = aout->next) + if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) + { + bgp_adj_out_remove (rn, aout, peer, afi, safi); + bgp_unlock_node (rn); + break; + } + for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { @@ -2857,21 +2872,6 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, work_queue_add (peer->clear_node_queue, cnq); break; } - - for (ain = rn->adj_in; ain; ain = ain->next) - if (ain->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) - { - bgp_adj_in_remove (rn, ain); - bgp_unlock_node (rn); - break; - } - for (aout = rn->adj_out; aout; aout = aout->next) - if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) - { - bgp_adj_out_remove (rn, aout, peer, afi, safi); - bgp_unlock_node (rn); - break; - } } return; } From 15c713485699fd22dfa5b7ce3ca7c6be049f1033 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 19 Nov 2012 11:17:31 +0000 Subject: [PATCH 0202/1342] bgpd: store "no neighbor activate" for IPv4 unicast If a neighbor was in a peer group for any AFI/SAFI, bgpd would never write a "no neighbor activate" line for IPv4 unicast, so a valid setup like following could be configured, but not saved: router bgp 64600 bgp router-id 198.51.100.1 network 198.51.100.0/24 neighbor peers peer-group neighbor 2001:db8::2 remote-as 64601 no neighbor 2001:db8::2 activate ! address-family ipv6 network 2001:db8:1::/48 neighbor peers activate neighbor peers soft-reconfiguration inbound neighbor 2001:db8::2 peer-group peers exit-address-family ! Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 908bdd94f..0b3f0a8e9 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4915,7 +4915,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, vty_out (vty, " neighbor %s strict-capability-match%s", addr, VTY_NEWLINE); - if (! peer_group_active (peer)) + if (! peer->af_group[AFI_IP][SAFI_UNICAST]) { if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) { From 9499bf2bc6daf0a9b7170d3cf994daef2f1a8920 Mon Sep 17 00:00:00 2001 From: Leonid Rosenboim Date: Thu, 6 Dec 2012 20:17:41 +0000 Subject: [PATCH 0203/1342] zebra: don't overrun afi/safi array boundaries zebra was not checking afi/safi values. This was leading to crashes where these values were coming directly from some protocol's on-wire fields. Safeguarding them in zebra is a good start. Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a75d72151..4dd8551a2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -155,6 +155,9 @@ vrf_table (afi_t afi, safi_t safi, u_int32_t id) if (! vrf) return NULL; + if( afi >= AFI_MAX || safi >= SAFI_MAX ) + return NULL; + return vrf->table[afi][safi]; } @@ -168,6 +171,9 @@ vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) if (! vrf) return NULL; + if( afi >= AFI_MAX || safi >= SAFI_MAX ) + return NULL; + return vrf->stable[afi][safi]; } From b06b35f0754747f9f178be155a2903b360aa2b6c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 7 Dec 2012 14:26:09 +0000 Subject: [PATCH 0204/1342] bgpd: fix a memleak on "set community none" Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index f22040032..40f207653 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1347,6 +1347,9 @@ route_set_community (void *rule, struct prefix *prefix, { attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); attr->community = NULL; + /* See the longer comment down below. */ + if (old && old->refcnt == 0) + community_free(old); return RMAP_OKAY; } From a0de1d16cd00694b07b266d4a5dae5985e9072ff Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 7 Dec 2012 16:35:00 +0000 Subject: [PATCH 0205/1342] bgpd: fix a bug in bgp_attr_dup Commit 558d1fec11749d3257e improved bgp_attr_dup so it would be possible for the caller to provide attr_extra, allowing to use the stack instead of the heap for operations requiring only a short lived attr. However, this commit introduced a bug where bgp_attr_dup wouldn't copy attr_extra at all (but provide a reference to the original) if the caller provided attr_extra. Cc: Jorge Boncompte [DTI2] Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2cbd7bc35..1dce39bcc 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -321,11 +321,24 @@ bgp_attr_dup (struct attr *new, struct attr *orig) struct attr_extra *extra = new->extra; *new = *orig; - if (orig->extra) + /* if caller provided attr_extra space, use it in any case. + * + * This is neccesary even if orig->extra equals NULL, because otherwise + * memory may be later allocated on the heap by bgp_attr_extra_get. + * + * That memory would eventually be leaked, because the caller must not + * call bgp_attr_extra_free if he provided attr_extra on the stack. + */ + if (extra) + { + new->extra = extra; + memset(new->extra, 0, sizeof(struct attr_extra)); + if (orig->extra) + *new->extra = *orig->extra; + } + else if (orig->extra) { - /* if caller provided attr_extra space use it */ - if (! extra) - new->extra = bgp_attr_extra_new(); + new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; } } From a689e6a9f470d2a72493b907c94ef23516bbbda6 Mon Sep 17 00:00:00 2001 From: Leonid Rosenboim Date: Fri, 7 Dec 2012 21:25:00 +0000 Subject: [PATCH 0206/1342] bgpd: fix error response to invalid BGP version number BGP4-ANVL 20.1 ANVL tries to open BGP with version 5 and expects correct notification in response. Quagga sends notification, but with incorrect information in it. The data needs to be a 2-byte value, and for now we respond with 0004 for any peer version other than 4. Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2d62c8dac..968c8e4d8 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1411,14 +1411,16 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Peer BGP version check. */ if (version != BGP_VERSION_4) { - u_int8_t maxver = BGP_VERSION_4; + u_int16_t maxver = htons(BGP_VERSION_4); + /* XXX this reply may not be correct if version < 4 XXX */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); + /* Data must be in network byte order here */ bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, - &maxver, 1); + (u_int8_t *) &maxver, 2); return -1; } From 1e0ce7caa622f07c20bb74414a4a5b4cbd732c75 Mon Sep 17 00:00:00 2001 From: Leonid Rosenboim Date: Fri, 7 Dec 2012 21:31:07 +0000 Subject: [PATCH 0207/1342] bgpd: improve logging of invalid BGP Notifications Invalid BGP Notification messages should be logged locally, cf. RFC4271, Sect. 6.4, p 34, NOTIFICATION Message Error Handling Current notification for invalid Notification code: 2012/10/10 02:17:54 BGP: message index 10 not found in bgp_notify_msg (max is 8) 2012/10/10 02:17:54 BGP: 192.168.1.1 received NOTIFICATION 10/0 ((no item found)) 0 bytes the logging should be a bit more clear. The above logging really doesn't explain much and looks more like a programming error. [rewrote most of it to get in something I can call a shape -David] Signed-off-by: David Lamparter --- bgpd/bgp_debug.c | 28 ++++++++++++++++------------ lib/log.h | 5 +++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index e3e3ec86f..726dd862b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -243,31 +243,37 @@ bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, const char *direct) { const char *subcode_str; + const char *code_str; subcode_str = ""; + code_str = LOOKUP_DEF (bgp_notify_msg, bgp_notify->code, + "Unrecognized Error Code"); - switch (bgp_notify->code) + switch (bgp_notify->code) { case BGP_NOTIFY_HEADER_ERR: - subcode_str = LOOKUP (bgp_notify_head_msg, bgp_notify->subcode); + subcode_str = LOOKUP_DEF (bgp_notify_head_msg, bgp_notify->subcode, + "Unrecognized Error Subcode"); break; case BGP_NOTIFY_OPEN_ERR: - subcode_str = LOOKUP (bgp_notify_open_msg, bgp_notify->subcode); + subcode_str = LOOKUP_DEF (bgp_notify_open_msg, bgp_notify->subcode, + "Unrecognized Error Subcode"); break; case BGP_NOTIFY_UPDATE_ERR: - subcode_str = LOOKUP (bgp_notify_update_msg, bgp_notify->subcode); + subcode_str = LOOKUP_DEF (bgp_notify_update_msg, bgp_notify->subcode, + "Unrecognized Error Subcode"); break; case BGP_NOTIFY_HOLD_ERR: - subcode_str = ""; break; case BGP_NOTIFY_FSM_ERR: - subcode_str = ""; break; case BGP_NOTIFY_CEASE: - subcode_str = LOOKUP (bgp_notify_cease_msg, bgp_notify->subcode); + subcode_str = LOOKUP_DEF (bgp_notify_cease_msg, bgp_notify->subcode, + "Unrecognized Error Subcode"); break; case BGP_NOTIFY_CAPABILITY_ERR: - subcode_str = LOOKUP (bgp_notify_capability_msg, bgp_notify->subcode); + subcode_str = LOOKUP_DEF (bgp_notify_capability_msg, bgp_notify->subcode, + "Unrecognized Error Subcode"); break; } @@ -275,15 +281,13 @@ bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, zlog_info ("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s", strcmp (direct, "received") == 0 ? "received from" : "sent to", peer->host, bgp_notify->code, bgp_notify->subcode, - LOOKUP (bgp_notify_msg, bgp_notify->code), - subcode_str, bgp_notify->length, + code_str, subcode_str, bgp_notify->length, bgp_notify->data ? bgp_notify->data : ""); else if (BGP_DEBUG (normal, NORMAL)) plog_debug (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s", peer ? peer->host : "", direct, bgp_notify->code, bgp_notify->subcode, - LOOKUP (bgp_notify_msg, bgp_notify->code), - subcode_str, bgp_notify->length, + code_str, subcode_str, bgp_notify->length, bgp_notify->data ? bgp_notify->data : ""); } diff --git a/lib/log.h b/lib/log.h index 27f21b310..cf247a838 100644 --- a/lib/log.h +++ b/lib/log.h @@ -146,8 +146,9 @@ extern int zlog_reset_file (struct zlog *zl); /* Rotate log. */ extern int zlog_rotate (struct zlog *); -/* For hackey massage lookup and check */ -#define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)", #x) +/* For hackey message lookup and check */ +#define LOOKUP_DEF(x, y, def) mes_lookup(x, x ## _max, y, def, #x) +#define LOOKUP(x, y) LOOKUP_DEF(x, y, "(no item found)") extern const char *lookup (const struct message *, int); extern const char *mes_lookup (const struct message *meslist, From 07ff4dc4d29f6f8db77e0e73da5d59e864ae2e66 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 4 Jan 2013 22:29:20 +0000 Subject: [PATCH 0208/1342] bgpd: mark route nodes scheduled into work queue The flag bit BGP_NODE_PROCESS_SCHEDULED is checked but never set. This causes route node to be scheduled multiple times under load. Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6155bc165..06bd59916 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1695,6 +1695,7 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) break; } + SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return; } From 47f6aef02b85c604bbd556574e2c724b7304e9e8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 4 Jan 2013 22:29:22 +0000 Subject: [PATCH 0209/1342] configure: allow building without getrusage Measuring the resource usage of threads is moderately expensive since it requires doing an additional system call everytime a thread context switches. Make it possible to disable this with a configuration option. Signed-off-by: David Lamparter --- configure.ac | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index b69c99d54..ff34f03a7 100755 --- a/configure.ac +++ b/configure.ac @@ -266,6 +266,8 @@ AC_ARG_ENABLE(isis_topology, [ --enable-isis-topology enable IS-IS topology generator]) AC_ARG_ENABLE(capabilities, [ --disable-capabilities disable using POSIX capabilities]) +AC_ARG_ENABLE(rusage, +[ --disable-rusage disable using getrusage]) AC_ARG_ENABLE(gcc_ultra_verbose, [ --enable-gcc-ultra-verbose enable ultra verbose GCC warnings]) AC_ARG_ENABLE(linux24_tcp_md5, @@ -1486,12 +1488,13 @@ AC_CHECK_TYPES([struct in_pktinfo], dnl -------------------------------------- dnl checking for getrusage struct and call dnl -------------------------------------- -AC_MSG_CHECKING(whether getrusage is available) -AC_TRY_COMPILE([#include -],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);], -[AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_RUSAGE,,rusage)], - AC_MSG_RESULT(no)) +if test "${enable_rusage}" != "no"; then + AC_MSG_CHECKING(whether getrusage is available) + AC_TRY_COMPILE([#include ],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);], + [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RUSAGE,,rusage)], + AC_MSG_RESULT(no)) +fi dnl -------------------------------------- dnl checking for clock_time monotonic struct and call From d61c1bbd4bf6ddf717dda88350668a9f1e2da0ac Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 4 Jan 2013 22:29:23 +0000 Subject: [PATCH 0210/1342] bgpd: use recent monotonic time for readtime The readtime value is for diagnostic, and doesn't have to be highly accurate. This also fixes a problem where the readtime was being measured with system clock, but the peer_uptime() was comparing with bgp_clock. Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 968c8e4d8..02863d75e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2385,6 +2385,15 @@ bgp_marker_all_one (struct stream *s, int length) return 1; } +/* Recent thread time. + On same clock base as bgp_clock (MONOTONIC) + but can be time of last context switch to bgp_read thread. */ +static time_t +bgp_recent_clock (void) +{ + return recent_relative_time().tv_sec; +} + /* Starting point of packet process function. */ int bgp_read (struct thread *thread) @@ -2513,14 +2522,14 @@ bgp_read (struct thread *thread) bgp_open_receive (peer, size); /* XXX return value ignored! */ break; case BGP_MSG_UPDATE: - peer->readtime = time(NULL); /* Last read timer reset */ + peer->readtime = bgp_recent_clock (); bgp_update_receive (peer, size); break; case BGP_MSG_NOTIFY: bgp_notify_receive (peer, size); break; case BGP_MSG_KEEPALIVE: - peer->readtime = time(NULL); /* Last read timer reset */ + peer->readtime = bgp_recent_clock (); bgp_keepalive_receive (peer, size); break; case BGP_MSG_ROUTE_REFRESH_NEW: From 3a69f74a0a903659e8a5bb930b257d9d09a87626 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 11 Jan 2013 18:27:23 +0000 Subject: [PATCH 0211/1342] bgpd: uncork after each write Keep data flowing, uncork after each BGP_WRITE_PACKET_MAX. This makes TCP send data sooner, since thread may not be scheduled again for a a longish time because of new UPDATE's coming in. Signed-off-by: Stephen Hemminger Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 02863d75e..b0918fc52 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -677,7 +677,8 @@ bgp_write (struct thread *thread) /* Flush any existing events */ BGP_EVENT_ADD (peer, BGP_Stop); - return 0; + goto done; + case BGP_MSG_KEEPALIVE: peer->keepalive_out++; break; @@ -698,9 +699,9 @@ bgp_write (struct thread *thread) if (bgp_write_proceed (peer)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); - else - sockopt_cork (peer->fd, 0); - + + done: + sockopt_cork (peer->fd, 0); return 0; } From 303bb005889a843b0d7e07a9b67b68ee55653d8f Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Sun, 13 Jan 2013 17:45:28 +0000 Subject: [PATCH 0212/1342] build: Remove deprecated AM_CONFIG_HEADER AM_CONFIG_HEADER has been deprecated for many years and is removed completely from automake 1.13. Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ff34f03a7..51bc8bd78 100755 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ AC_CANONICAL_HOST() AC_CANONICAL_TARGET() AM_INIT_AUTOMAKE(1.6) -AM_CONFIG_HEADER(config.h) +AC_CONFIG_HEADERS(config.h) AC_PATH_PROG(PERL, perl) AC_CHECK_PROG([GAWK],[gawk],[gawk],[not-in-PATH]) From ea05767770d759d46f97d1dc33423de72ae20ccd Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Sun, 13 Jan 2013 17:45:29 +0000 Subject: [PATCH 0213/1342] build: Fix build on MacOSX 10.8 (Mountain Lion) Newer MacOSX versions have support for both IPv6 advanced socket API RFCs (2292 and 3542) switchable in compile time, but neither of these is default for some strange reason. RFC3542 will be default in future, but for now we have to declare that we want to use the RFC3542 API before including . Signed-off-by: David Lamparter --- configure.ac | 3 +++ lib/zebra.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/configure.ac b/configure.ac index 51bc8bd78..92c831ab4 100755 --- a/configure.ac +++ b/configure.ac @@ -472,6 +472,9 @@ m4_define([QUAGGA_INCLUDES], #if HAVE_SYS_SOCKET_H # include #endif +#ifdef __APPLE__ +# define __APPLE_USE_RFC_3542 +#endif #if HAVE_NETINET_IN_H # include #endif diff --git a/lib/zebra.h b/lib/zebra.h index 404b832b0..ffca7a8fb 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -142,6 +142,10 @@ typedef int socklen_t; #include #endif /* HAVE_SYS_SOCKIO_H */ +#ifdef __APPLE__ +#define __APPLE_USE_RFC_3542 +#endif + #ifdef HAVE_NETINET_IN_H #include #endif /* HAVE_NETINET_IN_H */ From f6295c29070631b24a391f79d4d37ab9c0807ecc Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Jan 2013 17:59:08 +0100 Subject: [PATCH 0214/1342] build: add buildtest.sh script This script compiles Quagga in a variety of configurations and optionally with LLVM and ICC (if those are installed). Signed-off-by: David Lamparter --- buildtest.sh | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100755 buildtest.sh diff --git a/buildtest.sh b/buildtest.sh new file mode 100755 index 000000000..c9dd323f8 --- /dev/null +++ b/buildtest.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# written 2012-2013 by David Lamparter, placed in Public Domain. +# +# builds some git commit of Quagga in some different configurations +# usage: buildtest.sh [commit [configurations...]] + +basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-ipv6 --enable-ripngd --enable-ospf6d --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld" + +configs_base="gcc|$basecfg" + +configs_nov6="gcc|$basecfg" +configs_nov6="${configs_nov6/enable-ipv6/disable-ipv6}" +configs_nov6="${configs_nov6/enable-ospf6d/disable-ospf6d}" +configs_nov6="${configs_nov6/enable-ripngd/disable-ripngd}" +configs_nov6="${configs_nov6/enable-babeld/disable-babeld}" + +configs_ext="gcc|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology" +configs_snmp="gcc|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology --enable-snmp" +configs_clang="clang|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology" +configs_icc="icc|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology" + +defconfigs="base nov6 ext" +net-snmp-config --version &> /dev/null && defconfigs="$defconfigs snmp" +clang --version &> /dev/null && defconfigs="$defconfigs clang" +icc --version &> /dev/null && defconfigs="$defconfigs icc" + +echo "enabled configurations: $defconfigs" + +cc_gcc="CC=gcc; export CC" +cc_clang="CC=clang; export CC" +cc_icc="CC=icc; export CC" + +############################### + +errfunc() { + echo "something went wrong! check $TEMP" + exit 1 +} + +set -e +trap errfunc ERR + +COMMITREF="$1" +COMMITISH="`git rev-list --max-count=1 ${COMMITREF:-HEAD}`" +TEMP="`mktemp -t -d quaggabuild.XXXXXX`" +BASE="`pwd`" +CONFIGS="$2" + +echo using temporary directory: $TEMP +echo git commit used: +git --no-pager log -n 1 --pretty=oneline "$COMMITISH" + +cd "$TEMP" +git clone "$BASE" "source" +cd "source" +git checkout -b build "$COMMITISH" +git clean -d -f -x +sh bootstrap.sh + +cd .. + +echo -e "\n\n\n\n\033[33;1mmaking dist tarball\033[m" + +mkdir build_dist +cd build_dist +../source/configure +make distdir=sdist dist-gzip +cd .. +tar zxvf build_dist/sdist.tar.gz + +for cfg in ${CONFIGS:-$defconfigs}; do + echo -e "\n\n\n\n\033[33;1mbuilding configuration $cfg\033[m" + config="\${configs_$cfg}" + eval "config=$config" + + cc="${config%%|*}" + args="${config#*|}" + + ccset="\${cc_$cc}" + eval "ccset=$ccset" + eval "$ccset" + + bdir="build_$cfg" + mkdir "$bdir" + cd "$bdir" + ../sdist/configure $args + make -j5 + make DESTDIR="$TEMP/inst_$cfg" install + cd .. +done + +echo -e "\n\n\n\neverything seems ok. you may now\n\trm -rf $TEMP" From 8d083b9ec5bb0375ebb6d8b2b05c848febd92cb5 Mon Sep 17 00:00:00 2001 From: Leonid Rosenboim Date: Tue, 6 Nov 2012 11:44:04 -0800 Subject: [PATCH 0215/1342] build: update .gitignore for all test programs --- tests/.gitignore | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index e6ab706c0..93e886c04 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,16 +5,25 @@ tags TAGS .deps .nfs* +*~ +*.loT *.lo *.la *.libs -tabletest -testsig .arch-inventory .arch-ids +aspathtest +ecommtest +heavy +heavythread +heavywq +tabletest +testbgpcap +testbgpmpath +testbgpmpattr testbuffer +testchecksum testmemory +testprivs testsig -*~ -*.loT - +teststream From ca3ccd8748434719e4670ce812d1310013fad518 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 26 Sep 2012 14:52:39 +0200 Subject: [PATCH 0216/1342] zebra: fix sockaddr_dl length assumptions (BZ#737) Quagga makes bad assumptions about sockaddr_dl (on NetBSD, but possibly on other systems as well). Particularly, sizeof(struct sockaddr_dl) returns a size that does not include the full sdl_data field, leading to not enough data being copied. This breaks IPv6 RAs in particular, as a broken mac address from sockaddr_dl will be included in the packets. From: Matthias-Christian Ott Tested-by: Uwe Toenjes <6bone@6bone.informatik.uni-leipzig.de> [further simplified + more comments] Signed-off-by: David Lamparter --- configure.ac | 1 + lib/if.h | 8 +++++++- lib/zclient.c | 2 +- zebra/kernel_socket.c | 15 ++++++++++++--- zebra/zserv.c | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 92c831ab4..937c79ce6 100755 --- a/configure.ac +++ b/configure.ac @@ -1469,6 +1469,7 @@ AC_CHECK_TYPES([struct sockaddr, struct sockaddr_in, AC_CHECK_MEMBERS([struct sockaddr.sa_len, struct sockaddr_in.sin_len, struct sockaddr_un.sun_len, struct sockaddr_in6.sin6_scope_id, + struct sockaddr_dl.sdl_len, struct if6_aliasreq.ifra_lifetime, struct nd_opt_adv_interval.nd_opt_ai_type], [], [], QUAGGA_INCLUDES) diff --git a/lib/if.h b/lib/if.h index 841ce51ec..2116e12eb 100644 --- a/lib/if.h +++ b/lib/if.h @@ -103,7 +103,13 @@ struct interface /* Hardware address. */ #ifdef HAVE_STRUCT_SOCKADDR_DL - struct sockaddr_dl sdl; + union { + /* note that sdl_storage is never accessed, it only exists to make space. + * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits + * best with C aliasing rules. */ + struct sockaddr_dl sdl; + struct sockaddr_storage sdl_storage; + }; #else unsigned short hw_type; u_char hw_addr[INTERFACE_HWADDR_MAX]; diff --git a/lib/zclient.c b/lib/zclient.c index 61c6f7300..d3165962d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -734,7 +734,7 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->mtu6 = stream_getl (s); ifp->bandwidth = stream_getl (s); #ifdef HAVE_STRUCT_SOCKADDR_DL - stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); + stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage)); #else ifp->hw_addr_len = stream_getl (s); if (ifp->hw_addr_len) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index cde36bd03..73fabd4c0 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -477,13 +477,22 @@ ifm_read (struct if_msghdr *ifm) /* * XXX sockaddr_dl contents can be larger than the structure - * definition, so the user of the stored structure must be - * careful not to read off the end. - * + * definition. There are 2 big families here: + * - BSD has sdl_len + sdl_data[16] + overruns sdl_data + * we MUST use sdl_len here or we'll truncate data. + * - Solaris has no sdl_len, but sdl_data[244] + * presumably, it's not going to run past that, so sizeof() + * is fine here. * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid */ if (ifnlen) + { +#ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN + memcpy (&ifp->sdl, sdl, sdl->sdl_len); +#else memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); +#endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */ + } if_add_update (ifp); } diff --git a/zebra/zserv.c b/zebra/zserv.c index 9e47f23fe..cb8dbcb3a 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -153,7 +153,7 @@ zserv_encode_interface (struct stream *s, struct interface *ifp) stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); #ifdef HAVE_STRUCT_SOCKADDR_DL - stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); + stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); #else stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) From a6694fe8a89b957216f548938cc31602df04d495 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Jan 2013 01:28:36 +0100 Subject: [PATCH 0217/1342] Revert "bgpd: flock() dump files (BZ#742)" This reverts commit b07458a055493dd37cb955ae90f11ae8bc334d3a. On second thought, the right way to do this is with rename(), not by introducing a lock that can potentially even stall bgpd. Reported-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_dump.c | 40 +++++----------------------------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 775486012..edb725a97 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -95,7 +95,6 @@ static FILE * bgp_dump_open_file (struct bgp_dump *bgp_dump) { int ret; - int fd; time_t clock; struct tm *tm; char fullpath[MAXPATHLEN]; @@ -132,16 +131,6 @@ bgp_dump_open_file (struct bgp_dump *bgp_dump) umask(oldumask); return NULL; } - else - { - fd = fileno(bgp_dump->fp); - ret = flock( fd, LOCK_EX ); - if (ret != 0) - { - zlog_warn ("bgp_dump_open_file: Unable to flock() file %s: %s", realpath, strerror (errno)); - } - } - umask(oldumask); return bgp_dump->fp; @@ -206,7 +195,6 @@ bgp_dump_set_size (struct stream *s, int type) static void bgp_dump_routes_index_table(struct bgp *bgp) { - int ret; struct peer *peer; struct listnode *node; uint16_t peerno = 0; @@ -278,11 +266,7 @@ bgp_dump_routes_index_table(struct bgp *bgp) bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); - ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); - if (ret != 1) - { - zlog_warn ("bgp_dump_routes_index_table: fwrite returned %d, expected 1: %s", ret, strerror (errno)); - } + fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); fflush (bgp_dump_routes.fp); } @@ -291,7 +275,6 @@ bgp_dump_routes_index_table(struct bgp *bgp) static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { - int ret; struct stream *obuf; struct bgp_info *info; struct bgp_node *rn; @@ -390,11 +373,8 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq) seq++; bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); - ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); - if (ret != 1) - { - zlog_warn ("bgp_dump_routes_func: fwrite returned %d, expected 1: %s", ret, strerror (errno)); - } + fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); + } fflush (bgp_dump_routes.fp); @@ -484,7 +464,6 @@ bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4) void bgp_dump_state (struct peer *peer, int status_old, int status_new) { - int ret; struct stream *obuf; /* If dump file pointer is disabled return immediately. */ @@ -505,11 +484,7 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new) bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); /* Write to the stream. */ - ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp); - if (ret != 1) - { - zlog_warn ("bgp_dump_state: fwrite returned %d, expected 1: %s", ret, strerror (errno)); - } + fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp); fflush (bgp_dump_all.fp); } @@ -517,7 +492,6 @@ static void bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, struct stream *packet) { - int ret; struct stream *obuf; /* If dump file pointer is disabled return immediately. */ @@ -546,11 +520,7 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); /* Write to the stream. */ - ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp); - if (ret != 1) - { - zlog_warn ("bgp_dump_packet_func: fwrite returned %d, expected 1: %s", ret, strerror (errno)); - } + fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp); fflush (bgp_dump->fp); } From 86998bc2bc9506841250c8d49dd2df2464660a18 Mon Sep 17 00:00:00 2001 From: Leonid Rosenboim Date: Fri, 14 Dec 2012 19:12:17 +0000 Subject: [PATCH 0218/1342] bgpd: uncork/nagle socket when sending BGP NOTIFY This pushes out the NOTIFY message before closing a connection. Previously, the TCP_CORK bandwidth optimization code caused NOTIFY messages to disappear prior to when the connection is closed. * bgpd/bgp_packet.c: unset CORK, set NODELAY, and replace writen() by more correct write() Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index b0918fc52..d115353f8 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -723,13 +723,21 @@ bgp_write_notify (struct peer *peer) val = fcntl (peer->fd, F_GETFL, 0); fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK); - ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); + /* Stop collecting data within the socket */ + sockopt_cork (peer->fd, 0); + + ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); if (ret <= 0) { BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } + /* Disable Nagle, make NOTIFY packet go out right away */ + val = 1; + (void) setsockopt (peer->fd, IPPROTO_TCP, TCP_NODELAY, + (char *) &val, sizeof (val)); + /* Retrieve BGP packet type. */ stream_set_getp (s, BGP_MARKER_SIZE + 2); type = stream_getc (s); From dcab1bb822161d55795aad59b14c5c5d79b71e1f Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 7 Dec 2012 16:45:52 +0000 Subject: [PATCH 0219/1342] bgpd: conditional default-originate using route-map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Incorporate a patch by Svetozar Mihailov which implements default-originate route-maps to behave as expected, i.e. allowing the default route to be advertised conditionally, depending on a criterion given by the route-map. I am aware that the performance attributes of the following implementation are far from optimal. However, this affects only code paths belonging to a feature that is broken without this patch, therefore, it seems reasonable to me to have this in the mainline for now. Cc: Svetozar Mihailov Reported-by: Sébastien Cramatte Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- NEWS | 5 +++++ bgpd/bgp_nexthop.c | 10 ++++++++++ bgpd/bgp_route.c | 48 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index d67d66469..fe0d5ad26 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ Note: this file lists major user-visible changes only. +- [bgpd] The semantics of default-originate route-map have changed. + The route-map is now used to advertise the default route conditionally. + The old behaviour which allowed to set attributes on the originated + default route is no longer supported. + * Changes in Quagga 0.99.21 - [bgpd] BGP multipath support has been merged diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 0e56d3686..d46923665 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -506,6 +506,16 @@ bgp_scan (afi_t afi, safi_t safi) else if (afi == AFI_IP6) zlog_debug ("scanning IPv6 Unicast routing tables"); } + + /* Reevaluate default-originate route-maps and announce/withdraw + * default route if neccesary. */ + for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) + { + if (peer->status == Established + && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) + && peer->default_rmap[afi][safi].name) + bgp_default_originate (peer, afi, safi, 0); + } } /* BGP scan thread. This thread check nexthop reachability. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 06bd59916..8bc72d7be 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2462,8 +2462,9 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) struct attr attr; struct aspath *aspath; struct prefix p; - struct bgp_info binfo; struct peer *from; + struct bgp_node *rn; + struct bgp_info *ri; int ret = RMAP_DENYMATCH; if (!(afi == AFI_IP || afi == AFI_IP6)) @@ -2505,21 +2506,37 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) if (peer->default_rmap[afi][safi].name) { - binfo.peer = bgp->peer_self; - binfo.attr = &attr; - SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); - - ret = route_map_apply (peer->default_rmap[afi][safi].map, &p, - RMAP_BGP, &binfo); - + for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) + { + for (ri = rn->info; ri; ri = ri->next) + { + struct attr dummy_attr; + struct attr_extra dummy_extra; + struct bgp_info info; + + /* Provide dummy so the route-map can't modify the attributes */ + dummy_attr.extra = &dummy_extra; + bgp_attr_dup(&dummy_attr, ri->attr); + info.peer = ri->peer; + info.attr = &dummy_attr; + + ret = route_map_apply(peer->default_rmap[afi][safi].map, &rn->p, + RMAP_BGP, &info); + + /* The route map might have set attributes. If we don't flush them + * here, they will be leaked. */ + bgp_attr_flush(&dummy_attr); + if (ret != RMAP_DENYMATCH) + break; + } + if (ret != RMAP_DENYMATCH) + break; + } bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) - { - bgp_attr_flush (&attr); - withdraw = 1; - } + withdraw = 1; } if (withdraw) @@ -2530,8 +2547,11 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) } else { - SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); - bgp_default_update_send (peer, &attr, afi, safi, from); + if (! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) + { + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); + bgp_default_update_send (peer, &attr, afi, safi, from); + } } bgp_attr_extra_free (&attr); From 955be06f8a647d1149d5547e1265fb66f55a9161 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Jan 2013 01:48:04 +0100 Subject: [PATCH 0220/1342] build: Quagga 0.99.22-rc1 this is not a full release version, so neither release notes nor documentation are updated yet. Also, signing the tag with my private GPG key instead of the Quagga one. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 937c79ce6..9b378e2d4 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.21, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.22-rc1, [https://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) From f47e5a18b5beb00d6b5b94965e305dadb5aa5bad Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 20 Jan 2013 18:29:28 +0100 Subject: [PATCH 0221/1342] bgpd: don't try to reconcile AS4_PATH with NULL bgp_attr_munge_as4_attrs would previously try to reintegrate an AS4_PATH with a NULL AS_PATH, leading to a rather nasty SEGV. Let's go by RFC6793 and treat missing AS_PATH as 0-length AS_PATH, which in turn means discarding the AS4_PATH. [NB: we don't actually stick to the actual rule, which is discarding AS4_PATH if it's longer than AS_PATH; indeed we should probably fix that too] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 1dce39bcc..cbf2902d6 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1360,6 +1360,9 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, /* need to reconcile NEW_AS_PATH and AS_PATH */ if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) { + if (!attr->aspath) + return BGP_ATTR_PARSE_PROCEED; + newpath = aspath_reconcile_as4 (attr->aspath, as4_path); aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (newpath); From 5e728e929942d39ce5a4ab3d01c33f7b688c4e3f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Jan 2013 05:50:24 +0100 Subject: [PATCH 0222/1342] bgpd: relax ORF capability length handling commit fe9bb64... "bgpd: CVE-2012-1820, DoS in bgp_capability_orf()" made the length test in bgp_capability_orf_entry() stricter and is now causing us to refuse (with CEASE) ORF capabilites carrying any excess data. This does not conform to the robustness principle as laid out by RFC1122 ("be liberal in what you accept"). Even worse, RFC5291 is quite unclear on how to use the ORF capability with multiple AFI/SAFIs. It can be interpreted as either "use one instance, stuff everything in" but also as "use multiple instances". So, if not for applying robustness, we end up clearing sessions from implementations going by the former interpretation. (or if anyone dares add a byte of padding...) Cc: Denis Ovsienko Signed-off-by: David Lamparter --- bgpd/bgp_open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index af711cc8c..7bf350165 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -230,7 +230,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) } /* validate number field */ - if (sizeof (struct capability_orf_entry) + (entry.num * 2) != hdr->length) + if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", From 1cb9cf062ec3ed7a3f13fb5465eb5fb917ce3329 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 22 Jan 2013 23:39:17 +0100 Subject: [PATCH 0223/1342] tests: update & extend AS_PATH tests NB: these tests test for current implementation state, not for RFC conformance. In particular, behaviour with confederations in AS4_PATH as well as reconcilation of short AS_PATH + AS4_PATH is currently NOT conforming to RFC 4893/6793. * tests/aspath_test.c: add capability to put both AS4_PATH & AS_PATH, add test for AS4_PATH w/o AS_PATH, update confederation test Signed-off-by: David Lamparter --- tests/aspath_test.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 9170455fb..7fdb5e221 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -443,6 +443,7 @@ static struct aspath_tests { const int cap; /* capabilities to set for peer */ const char attrheader [1024]; size_t len; + const struct test_segment *old_segment; } aspath_tests [] = { /* 0 */ @@ -590,10 +591,10 @@ static struct aspath_tests { }, /* 11 */ { - "4b AS_PATH: confed", + "4b AS4_PATH w/o AS_PATH", &test_segments[6], - "8466 3 52737 4096", - AS4_DATA, -1, + NULL, + AS4_DATA, 0, PEER_CAP_AS4_ADV, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, @@ -601,6 +602,20 @@ static struct aspath_tests { }, 3, }, + /* 12 */ + { + "4b AS4_PATH: confed", + &test_segments[6], + "8466 3 52737 4096 (123 456 789)", + AS4_DATA, 0, + PEER_CAP_AS4_ADV, + { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + BGP_ATTR_AS4_PATH, + 14, + }, + 3, + &test_segments[0], + }, { NULL, NULL, NULL, 0, 0, 0, { 0 }, 0 }, }; @@ -1212,6 +1227,14 @@ handle_attr_test (struct aspath_tests *t) stream_write (peer.ibuf, t->attrheader, t->len); datalen = aspath_put (peer.ibuf, asp, t->as4 == AS4_DATA); + if (t->old_segment) + { + char dummyaspath[] = { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, + t->old_segment->len }; + stream_write (peer.ibuf, dummyaspath, sizeof (dummyaspath)); + stream_write (peer.ibuf, t->old_segment->asdata, t->old_segment->len); + datalen += sizeof (dummyaspath) + t->old_segment->len; + } ret = bgp_attr_parse (&peer, &attr, t->len + datalen, NULL, NULL); @@ -1224,12 +1247,12 @@ handle_attr_test (struct aspath_tests *t) if (ret != 0) goto out; - if (attr.aspath == NULL) + if (t->shouldbe && attr.aspath == NULL) { - printf ("aspath is NULL!\n"); + printf ("aspath is NULL, but should be: %s\n", t->shouldbe); failed++; } - if (attr.aspath && strcmp (attr.aspath->str, t->shouldbe)) + if (t->shouldbe && attr.aspath && strcmp (attr.aspath->str, t->shouldbe)) { printf ("attr str and 'shouldbe' mismatched!\n" "attr str: %s\n" @@ -1237,6 +1260,11 @@ handle_attr_test (struct aspath_tests *t) attr.aspath->str, t->shouldbe); failed++; } + if (!t->shouldbe && attr.aspath) + { + printf ("aspath should be NULL, but is: %s\n", attr.aspath->str); + failed++; + } out: if (attr.aspath) From aeef13b0d5b50a90f293c93eb5a34c2a099d140b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Jan 2013 04:20:37 +0100 Subject: [PATCH 0224/1342] tests: fix missing init in bgp_mp_attr_test.c turns out, bgp_mp_reach_parse really doesn't like getting garbage attribute input. In particular, attr->extra better be NULL or we merrily go trample random places (like our stack). Signed-off-by: David Lamparter --- tests/bgp_mp_attr_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index f086740fd..177c1ad8d 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -436,8 +436,8 @@ parse_test (struct peer *peer, struct test_segment *t, int type) { int ret; int oldfailed = failed; - struct attr attr; - struct bgp_nlri nlri; + struct attr attr = { }; + struct bgp_nlri nlri = { }; struct bgp_attr_parser_args attr_args = { .peer = peer, .length = t->len, From d53d8fda42e1ce43852d3b4cff914ce79b5c6785 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 28 Jan 2013 07:14:43 +0100 Subject: [PATCH 0225/1342] bgpd: fix crash in soft-reconfiguration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8692c50652 introduced a bug where bgpd would crash on soft-reconfiguration. This happens e.g. when there are filtered unicast routes because rn->info is NULL in that case, which the code did not account for. Reported-by: PaweÅ‚ Staszewski Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8bc72d7be..fb35fab82 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2643,10 +2643,10 @@ bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, for (ain = rn->adj_in; ain; ain = ain->next) { struct bgp_info *ri = rn->info; + u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL; bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, - &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, - (bgp_info_extra_get (ri))->tag); + &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, tag); } } @@ -2690,10 +2690,11 @@ bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, if (ain->peer == peer) { struct bgp_info *ri = rn->info; + u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL; ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - prd, (bgp_info_extra_get (ri))->tag, 1); + prd, tag, 1); if (ret < 0) { From d3c74d218bfbd9b5b9c39ef7d286f1dd007f2a74 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 18 Jan 2013 18:56:39 +0100 Subject: [PATCH 0226/1342] doc: update NEWS for 0.99.22 changes --- NEWS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/NEWS b/NEWS index fe0d5ad26..59e237d67 100644 --- a/NEWS +++ b/NEWS @@ -1,9 +1,21 @@ Note: this file lists major user-visible changes only. +* Changes in Quagga 0.99.22 + - [bgpd] The semantics of default-originate route-map have changed. The route-map is now used to advertise the default route conditionally. The old behaviour which allowed to set attributes on the originated default route is no longer supported. +- [bgpd] There is now a replace-as option to neighbor ... local-as ... + no-prepend. For details, refer to the user documentation. +- [zebra] An FPM interface has been added. This provides an alternate + interface to routing information and is geared at OpenFlow & co. +- [snmp] AgentX is now supported; the old smux backend is considered + deprecated. ospf6d has also had OSPFV3-MIB added. +- [*] several issues with configuration save/load/apply have been fixed, + in particular on ospf "max-metric router-lsa administrative" and + "distribute-list", bgpd "no neighbor activate", isisd "metric-style", +- [*] a lot of bugs have been fixed, please refer to the git log * Changes in Quagga 0.99.21 From b0baf0740e3d6a01980cef7ea0af0a61c10b1bcd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 18 Jan 2013 19:11:59 +0100 Subject: [PATCH 0227/1342] doc: update some introduction paragraphs in particular, - add IS-IS to some listings - list Solaris & OSX as "some work required" - remove OS version numbers. We have no base to specify any of them. - list supported C compilers (gcc, clang, icc) - cut the Quagga 2.0 stuff that promises QoS and firewall functionality --- doc/overview.texi | 54 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/doc/overview.texi b/doc/overview.texi index 7acfc0e9e..2301c4b7f 100644 --- a/doc/overview.texi +++ b/doc/overview.texi @@ -4,7 +4,7 @@ @uref{http://www.quagga.net,,Quagga} is a routing software package that provides TCP/IP based routing services with routing protocols support such -as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, BGP-4, and BGP-4+ (@pxref{Supported +as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (@pxref{Supported RFCs}). Quagga also supports special BGP Route Reflector and Route Server behavior. In addition to traditional IPv4 routing protocols, Quagga also supports IPv6 routing protocols. With SNMP daemon which supports SMUX and AgentX @@ -52,7 +52,7 @@ software is very easy. The only thing you have to do is to set up the interfaces and put a few commands about static routes and/or default routes. If the network is rather large, or if the network structure changes frequently, you will want to take advantage of Quagga's dynamic routing -protocol support for protocols such as RIP, OSPF or BGP. +protocol support for protocols such as RIP, OSPF, IS-IS or BGP. Traditionally, UNIX based router configuration is done by @command{ifconfig} and @command{route} commands. Status of routing @@ -63,12 +63,13 @@ mode, the other is enable mode. Normal mode user can only view system status, enable mode user can change system configuration. This UNIX account independent feature will be great help to the router administrator. - Currently, Quagga supports common unicast routing protocols. Multicast -routing protocols such as BGMP, PIM-SM, PIM-DM may be supported in Quagga -2.0. MPLS support is going on. In the future, TCP/IP filtering control, -QoS control, diffserv configuration will be added to Quagga. Quagga -project's final goal is making a productive, quality, free TCP/IP routing -software. + Currently, Quagga supports common unicast routing protocols, that is BGP, +OSPF, RIP and IS-IS. Upcoming for MPLS support, an implementation of LDP is +currently being prepared for merging. Implementations of BFD and PIM-SSM +(IPv4) also exist, but are not actively being worked on. + + The ultimate goal of the Quagga project is making a productive, quality, free +TCP/IP routing software package. @node System Architecture @comment node-name, next, previous, up @@ -139,7 +140,7 @@ events. @cindex Compatibility with other systems @cindex Operating systems that support Quagga -Currently Quagga supports @sc{gnu}/Linux, BSD and Solaris. Porting Quagga +Currently Quagga supports @sc{gnu}/Linux and BSD. Porting Quagga to other platforms is not too difficult as platform dependent code should most be limited to the @command{zebra} daemon. Protocol daemons are mostly platform independent. Please let us know when you find out Quagga runs on a @@ -152,15 +153,40 @@ functionality on further platforms. @sp 1 @itemize @bullet @item -@sc{gnu}/Linux 2.4.x and higher +@sc{gnu}/Linux +@item +FreeBSD @item -FreeBSD 4.x and higher +NetBSD +@item +OpenBSD +@end itemize + +Versions of these platforms that are older than around 2 years from the point +of their original release (in case of @sc{gnu}/Linux, this is since the kernel's +release on kernel.org) may need some work. Similarly, the following platforms +may work with some effort: + +@sp 1 +@itemize @bullet +@item +Solaris +@item +Mac OSX +@end itemize + +Also note that, in particular regarding proprietary platforms, compiler +and C library choice will affect Quagga. Only recent versions of the +following C compilers are well-tested: + +@sp 1 +@itemize @bullet @item -NetBSD 1.6 and higher +@sc{gnu}'s GCC @item -OpenBSD 2.5 and higher +LLVM's clang @item -Solaris 8 and higher +Intel's ICC @end itemize @node Supported RFCs From b2baffe8d255890b85d93aee653bed2c18371128 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 27 Jan 2013 04:46:02 +0100 Subject: [PATCH 0228/1342] build: fix "pragma weak" mixups Not only was there a minor typo in the "pragma weak" preprocessor checks, but also were the tests not behaving as needed - they only indicated support for the /first/ method of implementing weak aliases, which on Linux is __attribute__ and not #pragma. * m4/ax_sys_weak_alias.m4: set defines for _all_ weak alias methods * zebra/kernel_null.c: fix typo Cc: Doug VanLeuven Signed-off-by: David Lamparter --- m4/ax_sys_weak_alias.m4 | 22 +++++++++------------- zebra/kernel_null.c | 2 +- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/m4/ax_sys_weak_alias.m4 b/m4/ax_sys_weak_alias.m4 index 7c632a0ed..27b0f0c4f 100644 --- a/m4/ax_sys_weak_alias.m4 +++ b/m4/ax_sys_weak_alias.m4 @@ -167,9 +167,8 @@ void weakf(int c) __attribute__((weak, alias("__weakf")));], ]) # What was the result of the test? - AS_IF([test $ax_sys_weak_alias = no && - test $ax_cv_sys_weak_alias_attribute = yes], [ - ax_sys_weak_alias=attribute + AS_IF([test $ax_cv_sys_weak_alias_attribute = yes], [ + test $ax_sys_weak_alias = no && ax_sys_weak_alias=attribute AC_DEFINE([HAVE_SYS_WEAK_ALIAS_ATTRIBUTE], 1, [Define this if weak aliases may be created with __attribute__]) ]) @@ -192,9 +191,8 @@ void __weakf(int c) {}], ]) # What was the result of the test? - AS_IF([test $ax_sys_weak_alias = no && - test $ax_cv_sys_weak_alias_pragma = yes], [ - ax_sys_weak_alias=pragma + AS_IF([test $ax_cv_sys_weak_alias_pragma = yes], [ + test $ax_sys_weak_alias = no && ax_sys_weak_alias=pragma AC_DEFINE([HAVE_SYS_WEAK_ALIAS_PRAGMA], 1, [Define this if weak aliases may be created with @%:@pragma weak]) ]) @@ -217,9 +215,8 @@ void __weakf(int c) {}], ]) # What was the result of the test? - AS_IF([test $ax_sys_weak_alias = no && - test $ax_cv_sys_weak_alias_hpsecondary = yes], [ - ax_sys_weak_alias=hpsecondary + AS_IF([test $ax_cv_sys_weak_alias_hpsecondary = yes], [ + test $ax_sys_weak_alias = no && ax_sys_weak_alias=hpsecondary AC_DEFINE([HAVE_SYS_WEAK_ALIAS_HPSECONDARY], 1, [Define this if weak aliases may be created with @%:@pragma _HP_SECONDARY_DEF]) ]) @@ -242,9 +239,8 @@ void __weakf(int c) {}], ]) # What was the result of the test? - AS_IF([test $ax_sys_weak_alias = no && - test $ax_cv_sys_weak_alias_criduplicate = yes], [ - ax_sys_weak_alias=criduplicate + AS_IF([test $ax_cv_sys_weak_alias_criduplicate = yes], [ + test $ax_sys_weak_alias = no && ax_sys_weak_alias=criduplicate AC_DEFINE([HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE], 1, [Define this if weak aliases may be created with @%:@pragma _CRI duplicate]) ]) @@ -271,7 +267,6 @@ _ACEOF @%:@ifndef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE extern void weakf(int c); -@%:@endif @%:@if defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) @%:@pragma weak weakf = __weakf @%:@elif defined(HAVE_SYS_WEAK_ALIAS_HPSECONDARY) @@ -279,6 +274,7 @@ extern void weakf(int c); @%:@elif defined(HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE) @%:@pragma _CRI duplicate weakf as __weakf @%:@endif +@%:@endif void __weakf(int c) {} @%:@ifdef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE void weakf(int c) __attribute((weak, alias("__weakf"))); diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index ec994a6bf..cdb6e23f0 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -16,7 +16,7 @@ int kernel_delete_ipv4 (struct prefix *a, struct rib *b) { return 0; } #endif int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } -#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA_PRAGMA +#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak kernel_delete_ipv6 = kernel_add_ipv6 #else int kernel_delete_ipv6 (struct prefix *a, struct rib *b) { return 0; } From 66b63aa036c75737c3a8cea9693eff4dec84f903 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 10 Feb 2013 03:08:33 +0100 Subject: [PATCH 0229/1342] release: 0.99.22 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9b378e2d4..6e59037ab 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.22-rc1, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.22, [https://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) From f1ef81b2476ea533ac3d2129aa0e89653c427323 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Tue, 22 Jan 2013 10:39:18 +0000 Subject: [PATCH 0230/1342] zebra: use SO_RCVBUFFORCE for netlink socket so net.core.rmem_max must not be adjusted. Requires linux kernel >= 2.6.14, falls back to SO_RCVBUF on error Signed-off-by: Ulrich Weber Signed-off-by: David Lamparter --- doc/zebra.8 | 2 +- zebra/rt_netlink.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/doc/zebra.8 b/doc/zebra.8 index 23703e727..a40909a69 100644 --- a/doc/zebra.8 +++ b/doc/zebra.8 @@ -80,7 +80,7 @@ handle flood of netlink messages from kernel. If you ever see "recvmsg overrun" messages in zebra log, you are in trouble. Solution is to increase receive buffer of netlink socket. Note that kernel -doesn't allow to increase it over maximum value defined in +< 2.6.14 doesn't allow to increase it over maximum value defined in \fI/proc/sys/net/core/rmem_max\fR. If you want to do it, you have to increase maximum before starting zebra. diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index fa446a56f..bab170371 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -101,6 +101,10 @@ set_ifindex(struct interface *ifp, unsigned int ifi_index) ifp->ifindex = ifi_index; } +#ifndef SO_RCVBUFFORCE +#define SO_RCVBUFFORCE (33) +#endif + static int netlink_recvbuf (struct nlsock *nl, uint32_t newsize) { @@ -117,8 +121,16 @@ netlink_recvbuf (struct nlsock *nl, uint32_t newsize) return -1; } - ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize, + /* Try force option (linux >= 2.6.14) and fall back to normal set */ + if ( zserv_privs.change (ZPRIVS_RAISE) ) + zlog_err ("routing_socket: Can't raise privileges"); + ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize, sizeof(nl_rcvbufsize)); + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("routing_socket: Can't lower privileges"); + if (ret < 0) + ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize, + sizeof(nl_rcvbufsize)); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name, From 0e4303d3173ecc264b3ec39a863174670bbe2900 Mon Sep 17 00:00:00 2001 From: Roman Hoog Antink Date: Fri, 18 Jan 2013 13:52:03 +0100 Subject: [PATCH 0231/1342] bgpd: fix lost passwords of grouped neighbors This patch resolves the significance of order of group and password statements. It prevents passwords from being lost in cases where all three conditions apply: 1. the peer is member of a group with or without group password 2. the peer has an individual password set 3. the peer is added to a group within an address-family ipv6 section In addition this patch prevents the same issue in cases, where an IPv4 peer's password is set first and the peer is added to a group afterwards. Adding a peer to a group cancels his individual password. Without ipv6 this is not a problem, because choosing the right order of config statements will do (set password only after adding peer to group). When adding the peer to a group within the address-family section, his password is definitely lost. The same workaround (ie. setting the password after the address-family section) can not be used, because "show run" will print the configuration statements in the wrong order. Signed-off-by: David Lamparter --- bgpd/bgpd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0b3f0a8e9..c9a04fff9 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1457,13 +1457,8 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* password apply */ - if (peer->password) - XFREE (MTYPE_PEER_PASSWORD, peer->password); - - if (conf->password) + if (conf->password && !peer->password) peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password); - else - peer->password = NULL; bgp_md5_set (peer); From 844ee10416c42debbfbc4d470eb2fe328e060977 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Sat, 23 Feb 2013 19:38:37 +0100 Subject: [PATCH 0232/1342] vtysh: fix false lib path matching in extract.pl.in The if ($file =~ /lib/) path matching logic is supposed to match Quagga's lib directory only but will match all path having lib in it such as /var/lib/jenkins/quagga/... Fix by matching both lib and file: lib/keychain.c etc. Signed-off-by: Joakim Tjernlund Signed-off-by: David Lamparter --- vtysh/extract.pl.in | 69 ++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 37763043a..d323cdb05 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -90,41 +90,40 @@ foreach (@ARGV) { $cmd =~ s/\s+$//g; # $protocol is VTYSH_PROTO format for redirection of user input - if ($file =~ /lib/) { - if ($file =~ /keychain.c/) { - $protocol = "VTYSH_RIPD"; - } - if ($file =~ /routemap.c/) { - $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; - } - if ($file =~ /filter.c/) { - $protocol = "VTYSH_ALL"; - } - if ($file =~ /plist.c/) { - if ($defun_array[1] =~ m/ipv6/) { - $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; - } else { - $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA"; - } - } - if ($file =~ /distribute.c/) { - if ($defun_array[1] =~ m/ipv6/) { - $protocol = "VTYSH_RIPNGD"; - } else { - $protocol = "VTYSH_RIPD"; - } - } - if ($file =~ /if_rmap.c/) { - if ($defun_array[1] =~ m/ipv6/) { - $protocol = "VTYSH_RIPNGD"; - } else { - $protocol = "VTYSH_RIPD"; - } - } - if ($file =~ /vty.c/) { - $protocol = "VTYSH_ALL"; - } - } else { + if ($file =~ /lib\/keychain\.c$/) { + $protocol = "VTYSH_RIPD"; + } + elsif ($file =~ /lib\/routemap\.c$/) { + $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; + } + elsif ($file =~ /lib\/filter\.c$/) { + $protocol = "VTYSH_ALL"; + } + elsif ($file =~ /lib\/plist\.c$/) { + if ($defun_array[1] =~ m/ipv6/) { + $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; + } else { + $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA"; + } + } + elsif ($file =~ /lib\/distribute\.c$/) { + if ($defun_array[1] =~ m/ipv6/) { + $protocol = "VTYSH_RIPNGD"; + } else { + $protocol = "VTYSH_RIPD"; + } + } + elsif ($file =~ /lib\/if_rmap\.c$/) { + if ($defun_array[1] =~ m/ipv6/) { + $protocol = "VTYSH_RIPNGD"; + } else { + $protocol = "VTYSH_RIPD"; + } + } + elsif ($file =~ /lib\/vty\.c$/) { + $protocol = "VTYSH_ALL"; + } + else { ($protocol) = ($file =~ /^.*\/([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/); $protocol = "VTYSH_" . uc $protocol; } From fa75585d3cac97616de4ea7c6805d91f709456eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti-Oskari=20Lepp=C3=A4nen?= Date: Fri, 15 Feb 2013 10:12:55 +0000 Subject: [PATCH 0233/1342] build: update quagga.spec.in both Quagga and RPM have moved a bit since this was last touched. Should now work again on CentOS 5 and 6. Signed-off-by: David Lamparter --- redhat/quagga.spec.in | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index a8c7fbf36..0ce25ca35 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -44,7 +44,7 @@ %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. -%define quagga_buildreqs texinfo tetex autoconf pam-devel +%define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. @@ -68,7 +68,7 @@ %define daemon_list zebra ripd ospfd bgpd %if %{with_ipv6} -%define daemonv6_list ripngd ospf6d +%define daemonv6_list ripngd babeld ospf6d %else %define daemonv6_list "" %endif @@ -97,17 +97,17 @@ Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz URL: http://www.quagga.net %if %{with_snmp} BuildRequires: net-snmp-devel -Prereq: net-snmp +Requires(pre): net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel -Prereq: ncurses +Requires(pre): ncurses %endif BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex # Initscripts > 5.60 is required for IPv6 support -Prereq: initscripts >= 5.60 -Prereq: ncurses pam -Prereq: /sbin/install-info +Requires(pre): initscripts >= 5.60 +Requires(pre): ncurses pam +Requires(pre): /sbin/install-info Provides: routingdaemon BuildRoot: %{_tmppath}/%{name}-%{version}-root Obsoletes: bird gated mrt zebra @@ -406,6 +406,7 @@ rm -rf $RPM_BUILD_ROOT %if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d +%{_sbindir}/babeld %endif %if %{with_isisd} %{_sbindir}/isisd From 44a86a0278c1678fd4b8dfa56c4f5f2feb6df3ad Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 25 Jan 2013 09:14:52 +0100 Subject: [PATCH 0234/1342] guile: remove --- doc/install.texi | 4 - guile/.gitignore | 10 -- guile/Makefile.am | 12 -- guile/Makefile.in | 299 ------------------------------------------ guile/README | 17 --- guile/guile-bgp.c | 117 ----------------- guile/zebra-guile.c | 71 ---------- guile/zebra-guile.h | 21 --- guile/zebra-support.c | 19 --- 9 files changed, 570 deletions(-) delete mode 100644 guile/.gitignore delete mode 100644 guile/Makefile.am delete mode 100644 guile/Makefile.in delete mode 100644 guile/README delete mode 100644 guile/guile-bgp.c delete mode 100644 guile/zebra-guile.c delete mode 100644 guile/zebra-guile.h delete mode 100644 guile/zebra-support.c diff --git a/doc/install.texi b/doc/install.texi index 1cc655742..0f8f65fab 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -49,10 +49,6 @@ use to turn off IPv6 support, to disable the compilation of specific daemons, and to enable SNMP support. @table @option -@item --enable-guile -Turn on compilation of the zebra-guile interpreter. You will need the -guile library to make this. zebra-guile implementation is not yet -finished. So this option is only useful for zebra-guile developers. @item --disable-ipv6 Turn off IPv6 related features and daemons. Quagga configure script automatically detects IPv6 stack. But sometimes you might want to diff --git a/guile/.gitignore b/guile/.gitignore deleted file mode 100644 index 5c2e06b67..000000000 --- a/guile/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -Makefile -*.o -zebra-guile -Makefile.in -.nfs* -.arch-inventory -.arch-ids -*~ -*.loT - diff --git a/guile/Makefile.am b/guile/Makefile.am deleted file mode 100644 index 8d7008e99..000000000 --- a/guile/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -## Process this file with Automake to create Makefile.in - -INCLUDES = @GUILE_CFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -I. -I$(srcdir) - -AM_CFLAGS = $(PICFLAGS) -AM_LDFLAGS = $(PILDFLAGS) - -bin_PROGRAMS = zebra-guile -zebra_guile_SOURCES = zebra-guile.c zebra-support.c guile-bgp.c -noinst_HEADERS = zebra-guile.h -zebra_guile_LDADD = @GUILE_LDFLAGS@ ../bgpd/libbgp.a ../lib/libzebra.la diff --git a/guile/Makefile.in b/guile/Makefile.in deleted file mode 100644 index 2773029b9..000000000 --- a/guile/Makefile.in +++ /dev/null @@ -1,299 +0,0 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am - -# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - -SHELL = @SHELL@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -sbindir = @sbindir@ -libexecdir = @libexecdir@ -datadir = @datadir@ -sysconfdir = @sysconfdir@ -sharedstatedir = @sharedstatedir@ -localstatedir = @localstatedir@ -libdir = @libdir@ -infodir = @infodir@ -mandir = @mandir@ -includedir = @includedir@ -oldincludedir = /usr/include - -DESTDIR = - -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ - -top_builddir = .. - -ACLOCAL = @ACLOCAL@ -AUTOCONF = @AUTOCONF@ -AUTOMAKE = @AUTOMAKE@ -AUTOHEADER = @AUTOHEADER@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -transform = @program_transform_name@ - -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -host_alias = @host_alias@ -host_triplet = @host@ -AR = @AR@ -BGPD = @BGPD@ -CC = @CC@ -CPP = @CPP@ -CURSES = @CURSES@ -IF_METHOD = @IF_METHOD@ -IF_PROC = @IF_PROC@ -IPFORWARD = @IPFORWARD@ -KERNEL_METHOD = @KERNEL_METHOD@ -LIBPAM = @LIBPAM@ -LIB_IPV6 = @LIB_IPV6@ -LIB_REGEX = @LIB_REGEX@ -MAKEINFO = @MAKEINFO@ -MULTIPATH_NUM = @MULTIPATH_NUM@ -OSPF6D = @OSPF6D@ -OSPFD = @OSPFD@ -OTHER_METHOD = @OTHER_METHOD@ -PACKAGE = @PACKAGE@ -RANLIB = @RANLIB@ -RIPD = @RIPD@ -RIPNGD = @RIPNGD@ -RTREAD_METHOD = @RTREAD_METHOD@ -RT_METHOD = @RT_METHOD@ -VERSION = @VERSION@ -VTYSH = @VTYSH@ -ZEBRA = @ZEBRA@ - -INCLUDES = @GUILE_CFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -DEFS = @DEFS@ -I. -I$(srcdir) - -bin_PROGRAMS = zebra-guile -zebra_guile_SOURCES = zebra-guile.c zebra-support.c guile-bgp.c -noinst_HEADERS = zebra-guile.h -zebra_guile_LDADD = @GUILE_LDFLAGS@ ../bgpd/libbgp.a ../lib/libzebra.a -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = ../config.h -CONFIG_CLEAN_FILES = -PROGRAMS = $(bin_PROGRAMS) - -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ -zebra_guile_OBJECTS = zebra-guile.o zebra-support.o guile-bgp.o -zebra_guile_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.a -zebra_guile_LDFLAGS = -CFLAGS = @CFLAGS@ -COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ -HEADERS = $(noinst_HEADERS) - -DIST_COMMON = README ChangeLog Makefile.am Makefile.in - - -DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) - -TAR = tar -GZIP_ENV = --best -SOURCES = $(zebra_guile_SOURCES) -OBJECTS = $(zebra_guile_OBJECTS) - -all: all-redirect -.SUFFIXES: -.SUFFIXES: .S .c .o .s -$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps guile/Makefile - -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - - -mostlyclean-binPROGRAMS: - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -distclean-binPROGRAMS: - -maintainer-clean-binPROGRAMS: - -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(bindir) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ - $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - list='$(bin_PROGRAMS)'; for p in $$list; do \ - rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ - done - -.c.o: - $(COMPILE) -c $< - -.s.o: - $(COMPILE) -c $< - -.S.o: - $(COMPILE) -c $< - -mostlyclean-compile: - -rm -f *.o core *.core - -clean-compile: - -distclean-compile: - -rm -f *.tab.c - -maintainer-clean-compile: - -zebra-guile: $(zebra_guile_OBJECTS) $(zebra_guile_DEPENDENCIES) - @rm -f zebra-guile - $(LINK) $(zebra_guile_LDFLAGS) $(zebra_guile_OBJECTS) $(zebra_guile_LDADD) $(LIBS) - -tags: TAGS - -ID: $(HEADERS) $(SOURCES) $(LISP) - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - here=`pwd` && cd $(srcdir) \ - && mkid -f$$here/ID $$unique $(LISP) - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ - || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) - -mostlyclean-tags: - -clean-tags: - -distclean-tags: - -rm -f TAGS ID - -maintainer-clean-tags: - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) - -subdir = guile - -distdir: $(DISTFILES) - @for file in $(DISTFILES); do \ - d=$(srcdir); \ - if test -d $$d/$$file; then \ - cp -pr $$/$$file $(distdir)/$$file; \ - else \ - test -f $(distdir)/$$file \ - || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ - || cp -p $$d/$$file $(distdir)/$$file || :; \ - fi; \ - done -info-am: -info: info-am -dvi-am: -dvi: dvi-am -check-am: all-am -check: check-am -installcheck-am: -installcheck: installcheck-am -install-exec-am: install-binPROGRAMS -install-exec: install-exec-am - -install-data-am: -install-data: install-data-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -install: install-am -uninstall-am: uninstall-binPROGRAMS -uninstall: uninstall-am -all-am: Makefile $(PROGRAMS) $(HEADERS) -all-redirect: all-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install -installdirs: - $(mkinstalldirs) $(DESTDIR)$(bindir) - - -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -rm -f Makefile $(CONFIG_CLEAN_FILES) - -rm -f config.cache config.log stamp-h stamp-h[0-9]* - -maintainer-clean-generic: -mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ - mostlyclean-tags mostlyclean-generic - -mostlyclean: mostlyclean-am - -clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \ - mostlyclean-am - -clean: clean-am - -distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ - distclean-generic clean-am - -distclean: distclean-am - -maintainer-clean-am: maintainer-clean-binPROGRAMS \ - maintainer-clean-compile maintainer-clean-tags \ - maintainer-clean-generic distclean-am - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - -maintainer-clean: maintainer-clean-am - -.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ -maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ -mostlyclean-compile distclean-compile clean-compile \ -maintainer-clean-compile tags mostlyclean-tags distclean-tags \ -clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ -check-am installcheck-am installcheck install-exec-am install-exec \ -install-data-am install-data install-am install uninstall-am uninstall \ -all-redirect all-am all installdirs mostlyclean-generic \ -distclean-generic clean-generic maintainer-clean-generic clean \ -mostlyclean distclean maintainer-clean - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/guile/README b/guile/README deleted file mode 100644 index 8e18fae56..000000000 --- a/guile/README +++ /dev/null @@ -1,17 +0,0 @@ - - zebra-guile - - Kunihiro Ishiguro - 1999 - -1. What is zebra-guile - -zebra-guile is GNU Zebra which linked with guile. Almost zebra's -command can be called from guile interpreter. So you can use guile as -a routing scripting language. - -2. How to use it. - -(define bgp (router-bgp 7675)) - -3. diff --git a/guile/guile-bgp.c b/guile/guile-bgp.c deleted file mode 100644 index fbd01ba0e..000000000 --- a/guile/guile-bgp.c +++ /dev/null @@ -1,117 +0,0 @@ -/* Guile bgp interface. - Copyright (C) 1999 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra 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. - -GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -#include -#include - -#include "log.h" -#include "bgpd/bgpd.h" - -/* static SCM scm_mark_bgp (SCM obj); */ -static size_t scm_free_bgp (SCM vect); -static int scm_print_bgp (SCM vect, SCM port, scm_print_state *pstate); -static SCM scm_equalp_bgp (SCM a, SCM b); - -/* Tag of scheme type of bgp. */ -long scm_tag_bgp; - -static scm_smobfuns bgp_funs = -{ - scm_mark0, scm_free_bgp, scm_print_bgp, scm_equalp_bgp -}; - -static int -scm_print_bgp (SCM vect, SCM port, scm_print_state *pstate) -{ - unsigned short num; - struct bgp *bgp; - - num = 0; - bgp = (struct bgp *) SCM_CDR (vect); - num = bgp->as; - scm_puts ("#', port); - return 1; -} - -static size_t -scm_free_bgp (SCM obj) -{ - /* dummy function. */ - return 10; -} - -static SCM -scm_equalp_bgp (SCM a, SCM b) -{ - - return SCM_BOOL_F; -} - -/* Make bgp instance. */ -SCM -scm_router_bgp (SCM as_number) -{ - SCM cell; - long num; - struct bgp *bgp; - struct bgp *bgp_create (); - - SCM_ASSERT (SCM_INUMP (as_number), as_number, SCM_ARG1, "router-bgp"); - - SCM_DEFER_INTS; - - num = gh_scm2long (as_number); - - /* Make new bgp object. */ - bgp = bgp_create (); - bgp->as = num; - - SCM_NEWCELL (cell); - SCM_SETCAR (cell, scm_tag_bgp); - SCM_SETCDR (cell, bgp); - - SCM_ALLOW_INTS; - - return cell; -} - -#if 0 -SCM -scm_router_bgp_list () -{ - return NULL; -} -#endif - -void -init_bgp () -{ - void bgp_init (); - - bgp_init (); - - /* Initi types. */ - scm_tag_bgp = scm_newsmob (&bgp_funs); - - gh_new_procedure ("router-bgp", scm_router_bgp, 1, 0, 0); - /* gh_new_procedure ("router-bgp-list", scm_router_bgp_list, 0, 0, 0); */ -} diff --git a/guile/zebra-guile.c b/guile/zebra-guile.c deleted file mode 100644 index f618dbc55..000000000 --- a/guile/zebra-guile.c +++ /dev/null @@ -1,71 +0,0 @@ -/* Zebra guile interface. - Copyright (C) 1998, 99 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra 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. - -GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -#include -#include "zebra-guile.h" - -#include "zebra.h" -#include "thread.h" - -struct thread *master; - -static void -init_libzebra () -{ - void cmd_init(); - void vty_init(); - void memory_init(); - - cmd_init (1); - vty_init (); - memory_init (); -} - -/* Install scheme procudures. */ -void -init_zebra_guile () -{ - init_libzebra (); - - init_bgp (); - -#if 0 - init_zebra (); - init_rip (); - init_ospf (); -#endif /* 0 */ -} - -static void -inner_main (void *closure, int argc, char **argv) -{ - /* Install zebra related scheme procedures. */ - init_zebra_guile (); - - /* Invoke interpreter. */ - scm_shell (argc, argv); -} - -int -main (int argc, char **argv) -{ - scm_boot_guile (argc, argv, inner_main, 0); - return 0; /* Not reached */ -} diff --git a/guile/zebra-guile.h b/guile/zebra-guile.h deleted file mode 100644 index f43e287d8..000000000 --- a/guile/zebra-guile.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Zebra guile header. - Copyright (C) 1999 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra 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. - -GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -void init_bgp (); diff --git a/guile/zebra-support.c b/guile/zebra-support.c deleted file mode 100644 index 9a6ef814a..000000000 --- a/guile/zebra-support.c +++ /dev/null @@ -1,19 +0,0 @@ -/* Zebra guile interface support. - Copyright (C) 1999 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra 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. - -GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ From 90645f5598ca8b25cd2692f2ac0d2778a3fd2755 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 4 Jan 2013 22:29:21 +0000 Subject: [PATCH 0235/1342] hash: force size to be a power of 2 By forcing the hash table size to be a power of 2, a potentially expensive divide can be replaced by a mask operation. Almost all usage of the hash table was using default size of 1024. Only places with different size was thread library (1011) and bgp aspath. Signed-off-by: David Lamparter --- bgpd/bgp_aspath.c | 2 +- lib/hash.c | 5 +++-- lib/hash.h | 2 +- lib/thread.c | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index c37a8897f..a8b078ff3 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1856,7 +1856,7 @@ aspath_cmp (const void *arg1, const void *arg2) void aspath_init (void) { - ashash = hash_create_size (32767, aspath_key_make, aspath_cmp); + ashash = hash_create_size (32768, aspath_key_make, aspath_cmp); } void diff --git a/lib/hash.c b/lib/hash.c index 6db79ea77..1e097f284 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -31,6 +31,7 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *), { struct hash *hash; + assert ((size & (size-1)) == 0); hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); hash->index = XCALLOC (MTYPE_HASH_INDEX, sizeof (struct hash_backet *) * size); @@ -71,7 +72,7 @@ hash_get (struct hash *hash, void *data, void * (*alloc_func) (void *)) struct hash_backet *backet; key = (*hash->hash_key) (data); - index = key % hash->size; + index = key & (hash->size - 1); for (backet = hash->index[index]; backet != NULL; backet = backet->next) if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) @@ -125,7 +126,7 @@ hash_release (struct hash *hash, void *data) struct hash_backet *pp; key = (*hash->hash_key) (data); - index = key % hash->size; + index = key & (hash->size - 1); for (backet = pp = hash->index[index]; backet; backet = backet->next) { diff --git a/lib/hash.h b/lib/hash.h index 4cb772e57..a6dd53190 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -41,7 +41,7 @@ struct hash /* Hash backet. */ struct hash_backet **index; - /* Hash table size. */ + /* Hash table size. Must be power of 2 */ unsigned int size; /* Key make function. */ diff --git a/lib/thread.c b/lib/thread.c index 16c92c246..27c29d6c8 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -531,8 +531,8 @@ thread_master_create () { if (cpu_record == NULL) cpu_record - = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key, - (int (*) (const void *, const void *))cpu_record_hash_cmp); + = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, + (int (*) (const void *, const void *))cpu_record_hash_cmp); return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); From 97c84db00c01b808337bedf69f696a1517e3d8c0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 11 Jan 2013 18:25:26 +0000 Subject: [PATCH 0236/1342] hash: dynamically grow hash table Dynamically grow the hash table index if the chains get too long. If expansion doesn't help keep chain length short, then stop expanding, to avoid bad behavior if there is a poor hash function. Not a new idea, based on concepts in uthash. Depends on my previous patch to restrict hash to power of 2. Signed-off-by: Stephen Hemminger [profiling results: sum of cycles spent in hash_get/jhash with RIPE RIS test data (single simple BGP peer) improved to 69% of previously spent] Signed-off-by: David Lamparter --- lib/hash.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++---- lib/hash.h | 6 ++++- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/lib/hash.c b/lib/hash.c index 1e097f284..987012a58 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -48,7 +48,7 @@ struct hash * hash_create (unsigned int (*hash_key) (void *), int (*hash_cmp) (const void *, const void *)) { - return hash_create_size (HASHTABSIZE, hash_key, hash_cmp); + return hash_create_size (HASH_INITIAL_SIZE, hash_key, hash_cmp); } /* Utility function for hash_get(). When this function is specified @@ -60,6 +60,52 @@ hash_alloc_intern (void *arg) return arg; } +/* Expand hash if the chain length exceeds the threshold. */ +static void hash_expand (struct hash *hash) +{ + unsigned int i, new_size, losers; + struct hash_backet *hb, *hbnext, **new_index; + + new_size = hash->size * 2; + new_index = XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * new_size); + if (new_index == NULL) + return; + + for (i = 0; i < hash->size; i++) + for (hb = hash->index[i]; hb; hb = hbnext) + { + unsigned int h = hb->key & (new_size - 1); + + hbnext = hb->next; + hb->next = new_index[h]; + new_index[h] = hb; + } + + /* Switch to new table */ + XFREE(MTYPE_HASH_INDEX, hash->index); + hash->size = new_size; + hash->index = new_index; + + /* Ideally, new index should have chains half as long as the original. + If expansion didn't help, then not worth expanding again, + the problem is the hash function. */ + losers = 0; + for (i = 0; i < hash->size; i++) + { + unsigned int len = 0; + for (hb = hash->index[i]; hb; hb = hb->next) + { + if (++len > HASH_THRESHOLD/2) + ++losers; + if (len >= HASH_THRESHOLD) + hash->no_expand = 1; + } + } + + if (losers > hash->count / 2) + hash->no_expand = 1; +} + /* Lookup and return hash backet in hash. If there is no corresponding hash backet and alloc_func is specified, create new hash backet. */ @@ -69,14 +115,19 @@ hash_get (struct hash *hash, void *data, void * (*alloc_func) (void *)) unsigned int key; unsigned int index; void *newdata; + unsigned int len; struct hash_backet *backet; key = (*hash->hash_key) (data); index = key & (hash->size - 1); + len = 0; - for (backet = hash->index[index]; backet != NULL; backet = backet->next) - if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) - return backet->data; + for (backet = hash->index[index]; backet != NULL; backet = backet->next) + { + if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) + return backet->data; + ++len; + } if (alloc_func) { @@ -84,6 +135,12 @@ hash_get (struct hash *hash, void *data, void * (*alloc_func) (void *)) if (newdata == NULL) return NULL; + if (len > HASH_THRESHOLD && !hash->no_expand) + { + hash_expand (hash); + index = key & (hash->size - 1); + } + backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); backet->data = newdata; backet->key = key; diff --git a/lib/hash.h b/lib/hash.h index a6dd53190..920c6685f 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -22,7 +22,8 @@ Boston, MA 02111-1307, USA. */ #define _ZEBRA_HASH_H /* Default hash table size. */ -#define HASHTABSIZE 1024 +#define HASH_INITIAL_SIZE 256 /* initial number of backets. */ +#define HASH_THRESHOLD 10 /* expand when backet. */ struct hash_backet { @@ -44,6 +45,9 @@ struct hash /* Hash table size. Must be power of 2 */ unsigned int size; + /* If expansion failed. */ + int no_expand; + /* Key make function. */ unsigned int (*hash_key) (void *); From f05a5595e6b4805bc1a6bd86fe7076c5ffbb7f00 Mon Sep 17 00:00:00 2001 From: Greg Troxel Date: Sun, 3 Mar 2013 11:38:17 -0500 Subject: [PATCH 0237/1342] build: Update supported versions. INSTALL.quagga.tex: Given the statement that it's viewed as a bug if quagga doesn't build on OS versions on the list, prune the list to the set for which there would be near-universal agreement that it's a bug. Clarify that the response to a system on the list not building might be dropping it from the list. (Time marches on, and these lists are not necessarily maintained. As an example, the comment saying FreeBSD4 support was iffy is now 6 years old.) Delete old discussion of ancient texinfo. Delete discussion of NetBSD versions before 4 (as no longer relevant). --- INSTALL.quagga.txt | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/INSTALL.quagga.txt b/INSTALL.quagga.txt index ec4e799d2..ae3d4ec61 100644 --- a/INSTALL.quagga.txt +++ b/INSTALL.quagga.txt @@ -16,23 +16,20 @@ workarounds for POSIX non-compliance are welcome. It is considered a bug if Quagga fails to build and run on any of the following systems (where .x indicates the most recent release), or -such systems "-current" versions. (Note that considering it a bug is +such systems "-current" versions. Or, it might be that this list is +out of date and will be updated. (Note that considering it a bug is not a guarantee of support, merely "we agree that it is broken".) Dragonfly ? - FreeBSD 4.x [In 2007, this is getting tenous.] - FreeBSD 5.x - FreeBSD 6.x + FreeBSD (stable branches currently supported, plus perhaps one) FreeBSD-current Linux [kernel/distribution information needed] - NetBSD 2.x [Note texinfo 4.6 in base system] - NetBSD 3.x NetBSD 4.x + NetBSD 5.x + NetBSD 6.x NetBSD-current OpenBSD ? [info needed on what should work] - Solaris 9 - Solaris 10 - + Solaris (modern/supported versions, including OpenSolaris forks) For further Quagga specific information on 'configure' and build-time configuration of the software, please read the Quagga info @@ -70,7 +67,8 @@ deficient is made. texinfo: 4.7 (released 2004-04-10; 4.8 is not yet common) GNU AWK: 3.1.5 (released 2005-08-12) -Becuase some systems provide texinfo 4.6 (4.7 is new), quagga.info is +[TODO: texinfo 4.6 is now ancient and this should be revisited/fixed] +Because some systems provide texinfo 4.6 (4.7 is new), quagga.info is checked in so that texinfo will generally not be invoked. When texinfo 4.7 is widespread, quagga.info will be removed from CVS and texinfo will become required again. (4.7 has figure support, needed @@ -91,11 +89,12 @@ instructions. Notes on required versions: The general goal is to use a modern baseline of tools, while not -imposing pain on those tracking stable distributions. The notes below -explain what versions are present in various environments. +imposing pain on those tracking supported (or almost supported) stable +distributions. The notes below explain what versions are present in +various environments. -NetBSD 1.6 and 2 provide texinfo 4.6. This is now considered old. -NetBSD 3 and 4 provide texinfo 4.7. +NetBSD 4 provides texinfo 4.7. +NetBSD 5 and 6 provides texinfo 4.8 Fedora Core ? provides autoconf 2.59. From 3d1e5791c53bf67ebd8ce45322779856974c687f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 29 Mar 2013 19:31:55 +0100 Subject: [PATCH 0238/1342] doc: update TODO the TODO was last touched in 2006. This is a first pass at cleaning it up, motivated primarily by the need for an up-to-date idea list for the Google Summer of Code 2013. Signed-off-by: David Lamparter --- TODO | 236 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 173 insertions(+), 63 deletions(-) diff --git a/TODO b/TODO index 24941de03..0da355336 100644 --- a/TODO +++ b/TODO @@ -1,78 +1,188 @@ Quagga TODO list - 2004/11/24 + 2013-03-29 -zebra: -o Pointopoint address configuration. -o Multiple (alias) address configuration for the interface when kernel - support it [just starting]. -o improve rtnetlink to handle sequence number tracking and reconciliation - and resyncs. -o Add support for valid and preferred lifetimes to IPv6 addresses -o proper support for (at least) 1-level recursive routes -o Ability to set src on routes, where systems support it. -o Ability to apply route-maps to daemon route updates. +This is the Quagga primary TODO list. It is on git because that way changes +pass through the usual process just like code does, therefore they will have +the same visibility. -bgpd: +If you are working on something beyond a simple fix, to avoid double work it +is a good idea to submit a patch to this TODO list when you are starting, +listing what you're doing. Also, as others may have done just that, check +the list before starting. -o BGP TCP MD5 authentication by password command. -o HUP signal support (reload configuration file). -o BGP multi-path extension -o move FSM state to be per-connection, not per-peer. -o Add support for internal and minimum-metric MED setting +Google Summer of Code 2013 note: this list double-serves as idea list for the +Summer of Code. Ideas considered suitable for students are marked with a star +after the number, like this: "[Q999*] achieve world peace". They will also +have extended descriptions. Nevertheless, if you'd like to do something else, +just write a mail to the mailing list: quagga-dev@lists.quagga.net -ripd: +"GSoC-Mentors:" listings are preliminary at this point. -o Multipath support. + +Overall +======= + +[Q000] improve unit test architecture + +[Q001] kick invalid runtime tests from configure.ac, use list of supported + OSes and their APIs instead. + Priority: low + State: patch half-done 2013-03-29 David Lamparter + +[Q002*] clean up zebra IPC, remove code duplication, align to common API + Priority: high + GSoC-Mentors: David Lamparter, Christian Franke + + Quagga posesses an IPC mechanism to exchange route information among + the different daemons and Zebra, the kernel-interface. This mechanism + is implemented in libzebra, but is currently used in all sorts of + different ways in the individual protocol daemons. Also, in the future + the entire protocol needs to be redone in an extensible way, so we're + able to support MPLS, BFD, Multi-Topology/Instance, VRFs, ... + + This TODO entry only refers to the first-step API cleanup. All the + daemons need to use a single, well-defined libzebra API. Only after + this has been addressed can we look upon changing the protocol itself, + since by then it will be encapsulated inside libzebra. + +[Q003] add multi-instance / multi-topology support to the individual protocols + +[Q004] MPLS support + State: work in progress 2013-03-29 Renato Westphal, Timo Teräs + +[Q005] BFD support + State: two old implementations exist, contact Hasso Tepper + + +library +======= + +[L000] improve route_table speed, eg strided lookups for common prefix depths. + +[L001] ipv6 addresses need concept of valid/preferred + +[L002] implement a generic daemon access/control protocol (eg D-Bus like? + simplified SNMP-a-like? NETCONF?) + +[L003] extend vty command definitions to allow them to be self-documenting + i18n command help strings + +[L004] create a common libspf (for ospfd, ospf6d and possibly isisd and more). + cf. TODO item [O000] for the ospfd/ospf6d specific variant + +[L005] stabilise the API (possibly including symbol/library versioning voodoo) + +[L006] Document the exported API (DocBook/Doxygen?) + +[LE00] incorporate library changes from Euro-IX branch, except threading + +[LE01] incorporate threading library support from Euro-IX branch + + +zebra +===== + +[Z000] Pointopoint address configuration. + Priority: low + State: patch done & tested 2013-03-29 David Lamparter + +[Z001] Add support for valid and preferred lifetimes to IPv6 addresses + +[Z002] proper support for (at least) 1-level recursive routes + Priority: high + +[Z003] Ability to set src on routes, where systems support it. + +[Z004] Ability to apply route-maps to daemon route updates. + + +bgpd +==== + +[B000] HUP signal support (reload configuration file). + +[B001] BGP multi-path extension, relaxed mode + Priority: medium + +[B002] move FSM state to be per-connection, not per-peer. + +[B003] Add support for internal and minimum-metric MED setting + + +ripd +==== + +[R000] Multipath support. + + +ospfd/ospf6d +============ + +[O000] move SPF to common code + +[O001] extend code sharing between ospfd and ospf6d beyond SPF + +[O002*] OSPF testing replay tool + Priority: medium + GSoC-Mentors: Martin Winter, Christian Franke, David Lamparter + + In order to extensively test OSPF implementations, a tool to fake an + OSPF neighbor is immensely useful. This tool needs to be capable of + forming an adjacency and pushing LSAs to the device to be tested. To + maintain the adjacency, some minimal state tracking is useful. + + In total, the tool needs to form an adjacency, read and push LSAs, and + output received LSAs. Additional tools to generate LSAs from + specifications as well as verify received LSA correctness can then be + built on top of that. + + The tool needs to support IPv4 and IPv6, possibly split into 2 tools + with some code sharing. ospfd: -o Rewrite the incremental RT update code. -o Demand circuits. -o Multiple instances. -o OSPF MIB [SNMP get is amost finished]. -o HUP signal treatment. -o Fragment Oversized LSAs -o move SPF to common code -o NSSA priority rules (RFC3101 2.4) -o Type-7 address ranges (RFC3101 2.2) -o Originating Type-7 default into area (RFC3101 2.7) +[O400] Demand circuits. + Priority: very low + +[O401] Multiple instances. + Priority: medium + +[O402] HUP signal treatment. + Priority: medium + State: patch on ML needs review 2012-06-04 Mattias Walström ospf6d: -o move SPF to common code -o add router-id lookups - -isisd: - -o finish SPF -o select nearest L2 when running SPF for L1 -o remove the routes when holding time for nexthop expires -o redistribution -o autosummary - -o Mesh groups (RFC2973) -o Crypto authentication (RFC3567) - -lib: -o improve route_table speed, eg strided lookups for common prefix depths. -o improve hash tables, eg auto-growing hash tables -o move performance sensitive users of hashes over to jhash -o clean up linked lists -o ipv6 addresses need concept of valid/preferred -o implement a generic daemon access/control protocol (eg D-Bus like? - simplified SNMP-a-like?) -o merge SPF code from ospfd and ospf6d into a common libspf -o depends-on(generic A/C protocol) move snmp to seperate daemon -o extend command definitions to allow them to be self-documenting -o i18n command help strings -o Document the exported API (DocBook/Doxygen?) - -vtysh: -o untangle readline specific bits -o add a vtyd with a vty (ie telnet) frontend (as opposed to readline) -o depends-on(generic A/C protocol) use such -o better AAA support than just PAM, eg krb5, SASL, LDAP.. - ----------------------------- +[O600] fix ospf6d in general + Priority: high + State: patches tickling in from Cumulus Networks 2013-03-29 Dinesh Dutt + +isisd +===== + +[I000] reassess isisd TODO + +[I001*] IS-IS testing replay tool + Priority: medium + GSoC-Mentors: Martin Winter, Christian Franke, David Lamparter + + see [O002*]. + +[I002] Mesh groups (RFC2973) + +[I003] Crypto authentication (RFC3567) + + +vtysh +===== + +[V000] untangle readline specific bits + +[V001] add a vtyd with a vty (ie telnet) frontend (as opposed to readline) + +[V002] (=> [L002]) use daemon control protocol + +[V003] better AAA support than just PAM, eg krb5, SASL, LDAP... From 24c6bb86f4d21c74149bc0a7e50f9b95da0b6fd3 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 29 Mar 2013 19:40:39 +0100 Subject: [PATCH 0239/1342] doc: add OSPFv3 homenet to TODO The homenet OSPFv3 extensions are not only relevant TODO items, but also suitable for GSoC students. Signed-off-by: David Lamparter --- TODO | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/TODO b/TODO index 0da355336..ccf4d03dd 100644 --- a/TODO +++ b/TODO @@ -159,6 +159,21 @@ ospf6d: Priority: high State: patches tickling in from Cumulus Networks 2013-03-29 Dinesh Dutt +[O601*] OSPFv3 autoconfiguration, prefix assignment and sourcedest routing + Priority: medium + State: work in progress 2013-03-29 Edward Seabrook + GSoC-Mentors: David Lamparter + + OSPFv3 application in the homenet is being designed to use several + extensions to the base protocol. In order of dependency, + autoconfiguration, prefix assignment and sourcedest routing should + be implemented. + + This task requires a good level of OSPF understanding plus proper + ability to follow IETF discussion about these points. Also, since work + has already started on this, improvements must obviously build on top + of that. + isisd ===== From b58c90807c9d0bfa9601704c7490a16070906004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 22 Mar 2013 08:54:44 +0000 Subject: [PATCH 0240/1342] doc: fix makeinfo errors and one warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4afa50b added few lines that are syntactically incorrect with leading plus sign. Cc: Denis Ovsienko Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- doc/ipv6.texi | 4 ++-- doc/quagga.texi | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ipv6.texi b/doc/ipv6.texi index b6cc43763..2482c1c0b 100644 --- a/doc/ipv6.texi +++ b/doc/ipv6.texi @@ -136,8 +136,8 @@ for the lowest preference possible. Default: 0 @end deffn -+@deffn {Interface Command} {ipv6 nd home-agent-lifetime <0-65520>} {} -+@deffnx {Interface Command} {no ipv6 nd home-agent-lifetime [<0-65520>]} {} +@deffn {Interface Command} {ipv6 nd home-agent-lifetime <0-65520>} {} +@deffnx {Interface Command} {no ipv6 nd home-agent-lifetime [<0-65520>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent Lifetime. The default value of 0 means to place the current Router Lifetime value. diff --git a/doc/quagga.texi b/doc/quagga.texi index ff913aa5f..b4105ac96 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -1,13 +1,13 @@ \input texinfo @c -*- texinfo -*- +@c Set variables - sourced from defines.texi +@include defines.texi + @c %**start of header @setchapternewpage odd @settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @setfilename quagga.info @c %**end of header -@c Set variables - sourced from defines.texi -@include defines.texi - @c automake will automatically generate version.texi @c and set EDITION, VERSION, UPDATED and UPDATED-MONTH @include version.texi From 4a014580ff85428aa41b28503554b2ce982805be Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 27 Feb 2013 11:24:24 +0100 Subject: [PATCH 0241/1342] build: fix minimal mixup in gitinfo suffix the original version of this had issues with tagless repositories; to fix that I removed the "-g" part from one of the regexes. I then failed to add those 2 characters back, leading to version numbers like "0.99.220123456" instead of "0.99.22-ga123456". Let's put the "-g" back... Signed-off-by: David Lamparter --- lib/gitversion.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitversion.pl b/lib/gitversion.pl index 448f13d67..8ddd9ffa5 100644 --- a/lib/gitversion.pl +++ b/lib/gitversion.pl @@ -6,7 +6,7 @@ my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`; chomp $gitdesc; -my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? $1 : "-gUNKNOWN"; +my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; printf STDERR "git suffix: %s\n", $gitsuffix; printf "#define GIT_SUFFIX \"%s\"\n", $gitsuffix; From c095185c26f72bff14238ca1209ef6b2d7a8b935 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 23 Feb 2013 22:17:21 +0100 Subject: [PATCH 0242/1342] tests: make --disable-bgpd kill bgpd tests too bgpd tests don't compile or run with --disable-bgpd, let's catch this in the Makefile. Reported-by: Joachim Nilsson Signed-off-by: David Lamparter --- tests/Makefile.am | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index cd6b2f1b4..7bc880b5f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,9 +4,15 @@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) +if BGPD +TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath +else +TESTS_BGPD = +endif + noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ - aspathtest testprivs teststream testbgpcap ecommtest \ - testbgpmpattr testchecksum testbgpmpath tabletest + testprivs teststream testchecksum tabletest \ + $(TESTS_BGPD) testsig_SOURCES = test-sig.c testbuffer_SOURCES = test-buffer.c From 58952492d2eedd4b7974274a578a1fa9707125bb Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 20 Feb 2013 10:00:53 +0000 Subject: [PATCH 0243/1342] ospfd: fix LSA initialization for build without opaque LSA If configured without opaque LSA support, the old code would incorrectly associate type 5 LSAs with an area. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospfd/ospf_packet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 9a4587d96..d3f1b5635 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1660,8 +1660,10 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ lsa->area = NULL; break; +#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ /* Fallthrough */ From 8df55970b64984e5071afd510caad5e778569bc1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 1 Mar 2013 12:03:58 +0100 Subject: [PATCH 0244/1342] build: reference libcap from libzebra (BZ#393,626) While the actual build failures have been fixed independently by d1d3ac9 "build: reorder libraries to address linker error", libzebra still does not reference libcap. This will lead to more build failures if someone else tries to use libzebra and doesn't add libcap. Let's just add libcap here and be done with it. I've not added libcap to the _DEPENDENCIES variable above since libcap is a system library. Actually, the whole _DEPENDENCIES thing is rather fishy; automake automatically sets _DEPENDENCIES from _LIBADD. For the sake of not breaking stuff that works (especially since most autotools stuff is arcane magic), I'm leaving it alone... Signed-off-by: David Lamparter --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index d7c31edb4..44d95bbee 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -18,7 +18,7 @@ BUILT_SOURCES = memtypes.h route_types.h gitversion.h libzebra_la_DEPENDENCIES = @LIB_REGEX@ -libzebra_la_LIBADD = @LIB_REGEX@ +libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@ pkginclude_HEADERS = \ buffer.h checksum.h command.h filter.h getopt.h hash.h \ From b68da446e977f8069fb72bce73402e2234ffc1d9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Feb 2013 22:17:00 +0100 Subject: [PATCH 0245/1342] ripd: correctly redistribute ifindex routes (BZ#664) ripd had a check to restrict metric 0 to only directly connected routes. This check was implemented by checking against Connected as route type. This is, however, incorrect -- all routes that directly use an interface without a nexthop should be treated as directly connected and passed off with metric 0. ripngd does not posess such a check and was not touched. Reported-by: Sean Fulton Signed-off-by: David Lamparter --- ripd/ripd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index db29d54a2..55a1a75f1 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -482,8 +482,9 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, new_dist = rip_distance_apply (&rinfotmp); new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT; old_dist = rinfo->distance; - /* Only connected routes may have a valid NULL distance */ - if (rinfo->type != ZEBRA_ROUTE_CONNECT) + /* Only routes directly connected to an interface (nexthop == 0) + * may have a valid NULL distance */ + if (rinfo->nexthop.s_addr != 0) old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; /* If imported route does not have STRICT precedence, mark it as a ghost */ From 677bcbbf153fe73e57cb44f668977cbd26661fd4 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Feb 2013 13:47:23 +0000 Subject: [PATCH 0246/1342] lib/vty: register vtysh socket in server socket vector (BZ#754) Register the vtysh socket in Vvty_serv_thread so it will be correctly closed on vty_reset instead of being leaked. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- lib/vty.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 70bf5645b..0d6345c83 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -71,7 +71,7 @@ static char *vty_accesslist_name = NULL; static char *vty_ipv6_accesslist_name = NULL; /* VTY server thread. */ -vector Vvty_serv_thread; +static vector Vvty_serv_thread; /* Current directory. */ char *vty_cwd = NULL; @@ -2509,7 +2509,8 @@ vty_event (enum event event, int sock, struct vty *vty) break; #ifdef VTYSH case VTYSH_SERV: - thread_add_read (master, vtysh_accept, vty, sock); + vty_serv_thread = thread_add_read (master, vtysh_accept, vty, sock); + vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; case VTYSH_READ: vty->t_read = thread_add_read (master, vtysh_read, vty, sock); From f2b53dac4c72811c06779c596c6162b994eb427a Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 20 Mar 2013 15:28:46 +0000 Subject: [PATCH 0247/1342] ospfd: restore nexthop IP for p2p interfaces commit c81ee5c... "ospfd: Optimize and improve SPF nexthop calculation" subtly changed semantics of routes calculated over pointopoint links by removing the nexthop IP address and instead using an ifindex route. This breaks calculation of AS-Ext routes with a forwarding address since in ospf_ase_complete_direct_routes() this will be hit: if (op->nexthop.s_addr == 0) op->nexthop.s_addr = nexthop.s_addr; thus turning the route unusable by having an invalid nexthop. Fix by restoring the nexthop IP on routes over PtP links. This also allows running multi-access (Ethernet) interfaces in PtP mode again. This bug is a regression against 0.99.21 and only present in 0.99.22. Signed-off-by: Christian Franke [patch description and code comments rewritten] Acked-by: Joakim Tjernlund Acked-by: James Li Signed-off-by: David Lamparter --- ospfd/ospf_spf.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index a5242b686..bd9564d9e 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -568,8 +568,22 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) { - added = 1; - nexthop.s_addr = 0; /* Nexthop not required */ + /* Having nexthop = 0 is tempting, but NOT acceptable. + It breaks AS-External routes with a forwarding address, + since ospf_ase_complete_direct_routes() will mistakenly + assume we've reached the last hop and should place the + forwarding address as nexthop. + Also, users may configure multi-access links in p2p mode, + so we need the IP to ARP the nexthop. + */ + struct ospf_neighbor *nbr_w; + + nbr_w = ospf_nbr_lookup_by_routerid (oi->nbrs, &l->link_id); + if (nbr_w != NULL) + { + added = 1; + nexthop = nbr_w->src; + } } else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { From f281ab9752393fcc7cbb54c50edb66f25c2a31fb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 26 Feb 2013 16:21:20 +0100 Subject: [PATCH 0248/1342] tests: add DejaGNU framework DejaGNU seems to be the 'standard' GNU test framework (which by itself doesn't say much), but it seems relatively usable and the "remote system" capabilities might come in handy for virtualisation-based tests for kernel interactions or something. Signed-off-by: David Lamparter --- buildtest.sh | 1 + configure.ac | 16 ++++++- tests/.gitignore | 5 ++ tests/Makefile.am | 11 +++++ tests/config/unix.exp | 104 ++++++++++++++++++++++++++++++++++++++++++ tests/global-conf.exp | 0 6 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 tests/config/unix.exp create mode 100644 tests/global-conf.exp diff --git a/buildtest.sh b/buildtest.sh index c9dd323f8..de638f562 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -85,6 +85,7 @@ for cfg in ${CONFIGS:-$defconfigs}; do cd "$bdir" ../sdist/configure $args make -j5 + make check make DESTDIR="$TEMP/inst_$cfg" install cd .. done diff --git a/configure.ac b/configure.ac index 6e59037ab..582f35728 100755 --- a/configure.ac +++ b/configure.ac @@ -1619,6 +1619,18 @@ fi AC_SUBST(PICFLAGS) AC_SUBST(PILDFLAGS) +dnl ------- +dnl DejaGNU +dnl ------- +if test x"$DEJAGNU" = x +then + DEJAGNU="\$(top_srcdir)/tests/global-conf.exp" +fi +RUNTESTDEFAULTFLAGS="-x --tool \$\$tool" + +AC_SUBST(DEJAGNU) +AC_SUBST(RUNTESTDEFAULTFLAGS) + dnl ------------------------------ dnl set paths for state directory dnl ------------------------------ @@ -1691,8 +1703,8 @@ AC_MSG_RESULT($ac_cv_htonl_works) AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile - doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile - redhat/Makefile + doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile + redhat/Makefile pkgsrc/Makefile redhat/quagga.spec lib/version.h diff --git a/tests/.gitignore b/tests/.gitignore index 93e886c04..8baea0a87 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -10,6 +10,10 @@ TAGS *.lo *.la *.libs +*.bak +*.log +*.sum +*.xml .arch-inventory .arch-ids aspathtest @@ -27,3 +31,4 @@ testmemory testprivs testsig teststream +site.exp diff --git a/tests/Makefile.am b/tests/Makefile.am index 7bc880b5f..14f7bef1a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,3 +1,14 @@ +AUTOMAKE_OPTIONS = dejagnu +export DEJAGNU + +SUBDIRS = + +EXTRA_DIST = \ + config/unix.exp \ + global-conf.exp + +DEJATOOL = + INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" diff --git a/tests/config/unix.exp b/tests/config/unix.exp new file mode 100644 index 000000000..25ea97f4c --- /dev/null +++ b/tests/config/unix.exp @@ -0,0 +1,104 @@ + +# every test should always be run and always return some status. +# so, if we lose sync with a multi-test program, aborted will be used +# to flag the remainder of the tests as untested. +#set aborted 0 + +# only match with color codes since "failed" / "OK" might otherwise +# be part of the output... +#set color 1 + +set config_h [open "../config.h" "r"] +set config_h_text [read $config_h] +close $config_h +set i [string first "#define HAVE_IPV6" $config_h_text] +if { $i >= 0 } { + set have_ipv6 1 +} else { + set have_ipv6 0 +} +send_user "IPv6 enabled: $have_ipv6\n" +set xfail 0 + +proc onetest { test_name note start } { + global aborted + global testprefix + global verbose + global color + global xfail + + if { $aborted > 0 } { + untested "$testprefix$test_name" + return + } + + if { $verbose > 0 } { + send_user "$testprefix$test_name$note\n" + } + expect { + "$start" { } + + eof { unresolved "$testprefix$test_name"; set aborted 1; } + timeout { unresolved "$testprefix$test_name"; set aborted 1; } + } + + if { $aborted > 0 } { + send_user "sync failed: $testprefix$test_name$note -- $testprefix aborted!\n" + return + } + + if { $color } { + set pat "(32mOK|31mfailed)" + } else { + set pat "(OK|failed)" + } + expect { + # need this because otherwise expect will skip over a "failed" and + # grab the next "OK" (or the other way around) + -re "$pat" { + if { "$expect_out(0,string)" == "32mOK" || "$expect_out(0,string)" == "OK" } { + pass "$testprefix$test_name" + } else { + if { $xfail } { + xfail "$testprefix$test_name" + } else { + fail "$testprefix$test_name" + } + } + return + } + + eof { unresolved "$testprefix$test_name"; set aborted 1; } + timeout { unresolved "$testprefix$test_name"; set aborted 1; } + } + + if { $aborted > 0 } { + send_user "failed: $testprefix$test_name$note -- $testprefix aborted!\n" + return + } +} + +proc headerline { line } { + global aborted + if { $aborted > 0 } { return; } + expect { + $line { return; } + eof { send_user "numbering mismatch!\n"; set aborted 1; } + timeout { send_user "numbering mismatch!\n"; set aborted 1; } + } +} + +proc simpletest { start } { + onetest "$start" "" "$start" +} + +proc simpletest_nov6 { start } { + global have_ipv6 + global xfail + + set xfail [expr 1-$have_ipv6] + onetest "$start" "" "$start" + set xfail 0 +} + + diff --git a/tests/global-conf.exp b/tests/global-conf.exp new file mode 100644 index 000000000..e69de29bb From 5bb7e4d12b3a3015208fad5ee0f3c055b704c8c4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 26 Feb 2013 17:53:30 +0100 Subject: [PATCH 0249/1342] tests: DejaGNU bgpd this just wraps the existing test programs in expect wrappers that make their results usable to DejaGNU. Signed-off-by: David Lamparter --- configure.ac | 1 + tests/Makefile.am | 7 +-- tests/bgpd.tests/Makefile.am | 7 +++ tests/bgpd.tests/aspathtest.exp | 76 ++++++++++++++++++++++++++++++ tests/bgpd.tests/ecommtest.exp | 13 +++++ tests/bgpd.tests/testbgpcap.exp | 51 ++++++++++++++++++++ tests/bgpd.tests/testbgpmpath.exp | 12 +++++ tests/bgpd.tests/testbgpmpattr.exp | 31 ++++++++++++ tests/lib/bgpd.exp | 0 9 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 tests/bgpd.tests/Makefile.am create mode 100644 tests/bgpd.tests/aspathtest.exp create mode 100644 tests/bgpd.tests/ecommtest.exp create mode 100644 tests/bgpd.tests/testbgpcap.exp create mode 100644 tests/bgpd.tests/testbgpmpath.exp create mode 100644 tests/bgpd.tests/testbgpmpattr.exp create mode 100644 tests/lib/bgpd.exp diff --git a/configure.ac b/configure.ac index 582f35728..32a59d97e 100755 --- a/configure.ac +++ b/configure.ac @@ -1704,6 +1704,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile + tests/bgpd.tests/Makefile redhat/Makefile pkgsrc/Makefile redhat/quagga.spec diff --git a/tests/Makefile.am b/tests/Makefile.am index 14f7bef1a..153922b9f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,14 +1,14 @@ AUTOMAKE_OPTIONS = dejagnu export DEJAGNU +DEJATOOL = -SUBDIRS = +SUBDIRS = bgpd.tests EXTRA_DIST = \ config/unix.exp \ + lib/bgpd.exp \ global-conf.exp -DEJATOOL = - INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" @@ -17,6 +17,7 @@ AM_LDFLAGS = $(PILDFLAGS) if BGPD TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath +DEJATOOL += bgpd else TESTS_BGPD = endif diff --git a/tests/bgpd.tests/Makefile.am b/tests/bgpd.tests/Makefile.am new file mode 100644 index 000000000..5900186cf --- /dev/null +++ b/tests/bgpd.tests/Makefile.am @@ -0,0 +1,7 @@ +EXTRA_DIST = \ + aspathtest.exp \ + ecommtest.exp \ + testbgpcap.exp \ + testbgpmpath.exp \ + testbgpmpattr.exp + diff --git a/tests/bgpd.tests/aspathtest.exp b/tests/bgpd.tests/aspathtest.exp new file mode 100644 index 000000000..dfecec780 --- /dev/null +++ b/tests/bgpd.tests/aspathtest.exp @@ -0,0 +1,76 @@ +set timeout 10 +set testprefix "aspathtest " +set aborted 0 +set color 1 + +spawn "./aspathtest" + +# proc onetest { test_name note start } { +# proc headerline { line } { + +set parserno 0 +proc parsertest { test_name } { + global parserno + headerline "test $parserno" + onetest "parse $test_name" " ($parserno)" "$test_name:" + onetest "parse $test_name +empty_prepend" " (#$parserno)" "empty prepend $test_name:" + incr parserno 1 +} +set attrno 0 +proc attrtest { test_name } { + global attrno + headerline "aspath_attr test $attrno" + onetest "attr $test_name" " (#$attrno)" "$test_name" + incr attrno 1 +} + + +parsertest "seq1" +parsertest "seq2" +parsertest "seq3" +parsertest "seqset" +parsertest "seqset2" +parsertest "multi" +parsertest "confed" +parsertest "confed2" +parsertest "confset" +parsertest "confmulti" +parsertest "seq4" +parsertest "tripleseq1" +parsertest "someprivate" +parsertest "allprivate" +parsertest "long" +parsertest "seq1extra" +parsertest "empty" +parsertest "redundantset" +parsertest "reconcile_lead_asp" +parsertest "reconcile_new_asp" +parsertest "reconcile_confed" +parsertest "reconcile_start_trans" +parsertest "reconcile_start_trans4" +parsertest "reconcile_start_trans_error" +parsertest "redundantset2" +parsertest "zero-size overflow" +parsertest "zero-size overflow + valid segment" +parsertest "invalid segment type" + +for {set i 0} {$i < 10} {incr i 1} { onetest "prepend $i" "" "prepend test $i"; } +for {set i 0} {$i < 5} {incr i 1} { onetest "aggregate $i" "" "aggregate test $i"; } +for {set i 0} {$i < 5} {incr i 1} { onetest "reconcile $i" "" "reconcile test $i"; } +for {set i 0} {$i < 22} {incr i 1} { onetest "compare $i" "" "left cmp "; } + +onetest "empty_get" "" "empty_get_test" +attrtest "basic test" +attrtest "length too short" +attrtest "length too long" +attrtest "incorrect flag" +attrtest "as4_path, with as2 format data" +attrtest "as4, with incorrect attr length" +attrtest "basic 4-byte as-path" +attrtest "4b AS_PATH: too short" +attrtest "4b AS_PATH: too long" +attrtest "4b AS_PATH: too long2" +attrtest "4b AS_PATH: bad flags" +attrtest "4b AS4_PATH w/o AS_PATH" +attrtest "4b AS4_PATH: confed" + diff --git a/tests/bgpd.tests/ecommtest.exp b/tests/bgpd.tests/ecommtest.exp new file mode 100644 index 000000000..074952fab --- /dev/null +++ b/tests/bgpd.tests/ecommtest.exp @@ -0,0 +1,13 @@ +set timeout 10 +set testprefix "ecommtest " +set aborted 0 +set color 0 + +spawn "./ecommtest" + +# proc simpletest { start } { + +simpletest "ipaddr" +simpletest "ipaddr-so" +simpletest "asn" +simpletest "asn4" diff --git a/tests/bgpd.tests/testbgpcap.exp b/tests/bgpd.tests/testbgpcap.exp new file mode 100644 index 000000000..1bbdfd12f --- /dev/null +++ b/tests/bgpd.tests/testbgpcap.exp @@ -0,0 +1,51 @@ +set timeout 10 +set testprefix "testbgpcap " +set aborted 0 +set color 1 + +spawn "./testbgpcap" + +# proc simpletest { start } { + +simpletest "MP4: MP IP/Uni" +simpletest_nov6 "MPv6: MP IPv6/Uni" +simpletest "MP2: MP IP/Multicast" +simpletest_nov6 "MP3: MP IP6/MPLS-labeled VPN" +simpletest_nov6 "MP5: MP IP6/MPLS-VPN" +simpletest "MP6: MP IP4/MPLS-laveled VPN" +simpletest "MP8: MP unknown AFI/SAFI" +simpletest "MP-short: MP IP4/Unicast, length too short (< minimum)" +simpletest "MP-overflow: MP IP4/Unicast, length too long" +simpletest "caphdr: capability header, and no more" +simpletest "nodata: header, no data but length says there is" +simpletest "padded: valid, with padding" +simpletest "minsize: violates minsize requirement" +simpletest "ORF: ORF, simple, single entry, single tuple" +simpletest "ORF-many: ORF, multi entry/tuple" +simpletest "ORFlo: ORF, multi entry/tuple, hdr length too short" +simpletest "ORFlu: ORF, multi entry/tuple, length too long" +simpletest "ORFnu: ORF, multi entry/tuple, entry number too long" +simpletest "ORFno: ORF, multi entry/tuple, entry number too short" +simpletest "ORFpad: ORF, multi entry/tuple, padded to align" +simpletest "AS4: AS4 capability" +simpletest "GR: GR capability" +simpletest "GR-short: GR capability, but header length too short" +simpletest "GR-long: GR capability, but header length too long" +simpletest "GR-trunc: GR capability, but truncated" +simpletest "GR-empty: GR capability, but empty." +simpletest "MP-empty: MP capability, but empty." +simpletest "ORF-empty: ORF capability, but empty." +simpletest "AS4-empty: AS4 capability, but empty." +simpletest "dyn-empty: Dynamic capability, but empty." +simpletest "dyn-old: Dynamic capability (deprecated version)" +simpletest "Cap-singlets: One capability per Optional-Param" +simpletest "Cap-series: Series of capability, one Optional-Param" +simpletest "AS4more: AS4 capability after other caps (singlets)" +simpletest "AS4series: AS4 capability, in series of capabilities" +simpletest "AS4real: AS4 capability, in series of capabilities" +simpletest "AS4real2: AS4 capability, in series of capabilities" +simpletest "DynCap: Dynamic Capability Message, IP/Multicast" +simpletest "DynCapLong: Dynamic Capability Message, IP/Multicast, truncated" +simpletest "DynCapPadded: Dynamic Capability Message, IP/Multicast, padded" +simpletest "DynCapMPCpadded: Dynamic Capability Message, IP/Multicast, cap data padded" +simpletest "DynCapMPCoverflow: Dynamic Capability Message, IP/Multicast, cap data != length" diff --git a/tests/bgpd.tests/testbgpmpath.exp b/tests/bgpd.tests/testbgpmpath.exp new file mode 100644 index 000000000..96a51e390 --- /dev/null +++ b/tests/bgpd.tests/testbgpmpath.exp @@ -0,0 +1,12 @@ +set timeout 10 +set testprefix "testbgpmpath " +set aborted 0 +set color 1 + +spawn "./testbgpmpath" + +# proc simpletest { start } { + +simpletest "bgp maximum-paths config" +simpletest "bgp_mp_list" +simpletest "bgp_info_mpath_update" diff --git a/tests/bgpd.tests/testbgpmpattr.exp b/tests/bgpd.tests/testbgpmpattr.exp new file mode 100644 index 000000000..93355ad7a --- /dev/null +++ b/tests/bgpd.tests/testbgpmpattr.exp @@ -0,0 +1,31 @@ +set timeout 10 +set testprefix "testbgpmpattr " +set aborted 0 +set color 1 + +spawn "./testbgpmpattr" + +# proc simpletest { start } { + +simpletest_nov6 "IPv6: IPV6 MP Reach, global nexthop, 1 NLRI" +simpletest_nov6 "IPv6-2: IPV6 MP Reach, global nexthop, 2 NLRIs" +simpletest_nov6 "IPv6-default: IPV6 MP Reach, global nexthop, 2 NLRIs + default" +simpletest_nov6 "IPv6-lnh: IPV6 MP Reach, global+local nexthops, 2 NLRIs + default" +simpletest "IPv6-nhlen: IPV6 MP Reach, inappropriate nexthop length" +simpletest "IPv6-nhlen2: IPV6 MP Reach, invalid nexthop length" +simpletest "IPv6-nhlen3: IPV6 MP Reach, nexthop length overflow" +simpletest "IPv6-nhlen4: IPV6 MP Reach, nexthop length short" +simpletest "IPv6-nlri: IPV6 MP Reach, NLRI bitlen overflow" +simpletest "IPv4: IPv4 MP Reach, 2 NLRIs + default" +simpletest "IPv4-nhlen: IPv4 MP Reach, nexthop lenth overflow" +simpletest "IPv4-nlrilen: IPv4 MP Reach, nlri lenth overflow" +simpletest "IPv4-MLVPN: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs" +simpletest "IPv6-bug: IPv6, global nexthop, 1 default NLRI" +simpletest_nov6 "IPv6-unreach: IPV6 MP Unreach, 1 NLRI" +simpletest_nov6 "IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs" +simpletest_nov6 "IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default" +simpletest "IPv6-unreach-nlri: IPV6 MP Unreach, NLRI bitlen overflow" +simpletest "IPv4-unreach: IPv4 MP Unreach, 2 NLRIs + default" +simpletest "IPv4-unreach-nlrilen: IPv4 MP Unreach, nlri length overflow" +simpletest "IPv4-unreach-MLVPN: IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs" + diff --git a/tests/lib/bgpd.exp b/tests/lib/bgpd.exp new file mode 100644 index 000000000..e69de29bb From c69905b673812ce6ec2a12960727a27b9b8d6426 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 24 Jan 2013 01:39:14 +0100 Subject: [PATCH 0250/1342] tests: DejaGNU libzebra Wrap the few libzebra test programs we have up for DejaGNU. Signed-off-by: David Lamparter --- configure.ac | 1 + tests/Makefile.am | 7 +++++-- tests/config/unix.exp | 18 ++++++++++++++++++ tests/lib/libzebra.exp | 0 tests/libzebra.tests/Makefile.am | 2 ++ tests/libzebra.tests/tabletest.exp | 9 +++++++++ tests/libzebra.tests/teststream.exp | 28 ++++++++++++++++++++++++++++ 7 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/lib/libzebra.exp create mode 100644 tests/libzebra.tests/Makefile.am create mode 100644 tests/libzebra.tests/tabletest.exp create mode 100644 tests/libzebra.tests/teststream.exp diff --git a/configure.ac b/configure.ac index 32a59d97e..ff7a4d547 100755 --- a/configure.ac +++ b/configure.ac @@ -1705,6 +1705,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile tests/bgpd.tests/Makefile + tests/libzebra.tests/Makefile redhat/Makefile pkgsrc/Makefile redhat/quagga.spec diff --git a/tests/Makefile.am b/tests/Makefile.am index 153922b9f..93c06b031 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,12 +1,15 @@ AUTOMAKE_OPTIONS = dejagnu export DEJAGNU -DEJATOOL = +DEJATOOL = libzebra -SUBDIRS = bgpd.tests +SUBDIRS = \ + bgpd.tests \ + libzebra.tests EXTRA_DIST = \ config/unix.exp \ lib/bgpd.exp \ + lib/libzebra.exp \ global-conf.exp INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib diff --git a/tests/config/unix.exp b/tests/config/unix.exp index 25ea97f4c..b41f072cc 100644 --- a/tests/config/unix.exp +++ b/tests/config/unix.exp @@ -20,6 +20,24 @@ if { $i >= 0 } { send_user "IPv6 enabled: $have_ipv6\n" set xfail 0 +proc onesimple { test_name match } { + global verbose + global aborted + global testprefix + if { $aborted > 0 } { + untested "$testprefix$test_name" + return + } + if { $verbose > 0 } { + send_user "$testprefix$test_name$note\n" + } + expect { + "$match" { pass "$testprefix$test_name"; } + eof { fail "$testprefix$test_name"; set aborted 1; } + timeout { unresolved "$testprefix$test_name"; set aborted 1; } + } +} + proc onetest { test_name note start } { global aborted global testprefix diff --git a/tests/lib/libzebra.exp b/tests/lib/libzebra.exp new file mode 100644 index 000000000..e69de29bb diff --git a/tests/libzebra.tests/Makefile.am b/tests/libzebra.tests/Makefile.am new file mode 100644 index 000000000..0d29e287c --- /dev/null +++ b/tests/libzebra.tests/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = \ + tabletest.exp diff --git a/tests/libzebra.tests/tabletest.exp b/tests/libzebra.tests/tabletest.exp new file mode 100644 index 000000000..5838d4fc7 --- /dev/null +++ b/tests/libzebra.tests/tabletest.exp @@ -0,0 +1,9 @@ +set timeout 10 +set testprefix "tabletest " +set aborted 0 + +spawn "./tabletest" + +for {set i 0} {$i < 6} {incr i 1} { onesimple "cmp $i" "Verifying cmp"; } +for {set i 0} {$i < 11} {incr i 1} { onesimple "succ $i" "Verifying successor"; } +onesimple "pause" "Verified pausing" diff --git a/tests/libzebra.tests/teststream.exp b/tests/libzebra.tests/teststream.exp new file mode 100644 index 000000000..ca602e305 --- /dev/null +++ b/tests/libzebra.tests/teststream.exp @@ -0,0 +1,28 @@ +set timeout 10 +spawn "./teststream" + +expect { + "endp: 15, readable: 15, writeable: 1009" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "0xef 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "endp: 15, readable: 15, writeable: 0" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "0xef 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "c: 0xef" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "w: 0xbeef" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "l: 0xdeadbeef" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +expect { + "q: 0xdeadbeefdeadbeef" { } + eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } } +pass "teststream" From 77ef01392f82c27a9892840c61a5e7391fd82415 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Fri, 12 Apr 2013 01:37:15 +0000 Subject: [PATCH 0251/1342] doc: update TODO for ospf6d work & bgp multipath This is work in progress at Cumulus Networks. --- TODO | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index ccf4d03dd..246cc2572 100644 --- a/TODO +++ b/TODO @@ -103,8 +103,10 @@ bgpd [B000] HUP signal support (reload configuration file). -[B001] BGP multi-path extension, relaxed mode +[B001*] BGP multi-path extension, relaxed mode Priority: medium + Implemented, patch will be sent shortly + Pradosh Mohapatra, Cumulus Networks [B002] move FSM state to be per-connection, not per-peer. @@ -155,9 +157,13 @@ ospfd: ospf6d: -[O600] fix ospf6d in general +[O600*] fix ospf6d in general Priority: high State: patches tickling in from Cumulus Networks 2013-03-29 Dinesh Dutt + Implemented: p2p link support, ABR, Stub area/Totally Stubby area, + SPF throttling, Improving state machine to get performance/scale, + max-metric support, Improving ECMP to be > 4, Various other bug fixes + [O601*] OSPFv3 autoconfiguration, prefix assignment and sourcedest routing Priority: medium From 4de8bf001189d40e086764fd804e59657d2e21e6 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 20 Feb 2013 10:00:52 +0000 Subject: [PATCH 0252/1342] ospfd: make ospf_maxage_lsa_remover actually yield ospf_maxage_lsa_remover whould check whether to yield, but run on anyway. Signed-off-by: Christian Franke Signed-off-by: Joachim Nilsson Signed-off-by: David Lamparter --- ospfd/ospf_lsa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index dfd1a61e2..e0e05ab84 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2843,6 +2843,9 @@ ospf_maxage_lsa_remover (struct thread *thread) continue; } + /* There is at least one neighbor from which we still await an ack + * for that LSA, so we are not allowed to remove it from our lsdb yet + * as per RFC 2328 section 14 para 4 a) */ if (lsa->retransmit_counter > 0) { reschedule = 1; @@ -2851,7 +2854,10 @@ ospf_maxage_lsa_remover (struct thread *thread) /* TODO: maybe convert this function to a work-queue */ if (thread_should_yield (thread)) - OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); + { + OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); + return 0; + } /* Remove LSA from the LSDB */ if (IS_LSA_SELF (lsa)) From 4c14b7f684510592f2eb46fd84859d8bca57def9 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 20 Feb 2013 10:00:54 +0000 Subject: [PATCH 0253/1342] ospfd: fix flooding procedure An ospf router should accept a new maxage LSA into its lsdb if it has any neighbors in state Exchange or Loading. ospfd would however only account for neighbors on the same interface which does not seem to be a valid optimization. Signed-off-by: Christian Franke Signed-off-by: Joachim Nilsson Signed-off-by: David Lamparter --- ospfd/ospf_lsa.c | 2 +- ospfd/ospf_lsa.h | 1 + ospfd/ospf_packet.c | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index e0e05ab84..109a120b1 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2794,7 +2794,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, } -static int +int ospf_check_nbr_status (struct ospf *ospf) { struct listnode *node, *nnode; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 9ff2d9204..c71877da4 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -251,6 +251,7 @@ extern u_int32_t lsa_seqnum_increment (struct ospf_lsa *); extern void lsa_header_set (struct stream *, u_char, u_char, struct in_addr, struct in_addr); extern struct ospf_neighbor *ospf_nbr_lookup_ptop (struct ospf_interface *); +extern int ospf_check_nbr_status (struct ospf *); /* Prototype for LSA primitive. */ extern struct ospf_lsa *ospf_lsa_new (void); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index d3f1b5635..37223fbb7 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1833,8 +1833,7 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, then take the following actions: */ if (IS_LSA_MAXAGE (lsa) && !current && - (ospf_nbr_count (oi, NSM_Exchange) + - ospf_nbr_count (oi, NSM_Loading)) == 0) + ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ ospf_ls_ack_send (nbr, lsa); From 1bf0ca9a07358ff13b1390f4462669e9ea4915dc Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 18:30:56 +0200 Subject: [PATCH 0254/1342] tests: fix Makefile.am so it works with BSD make The export statement is specific to GNU make and breaks the build with BSD make. I couldn't observe any difference in behaviour between having the export present and absent, therefore, just remove it. Signed-off-by: Christian Franke --- tests/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 93c06b031..b7a7fe748 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,4 @@ AUTOMAKE_OPTIONS = dejagnu -export DEJAGNU DEJATOOL = libzebra SUBDIRS = \ From d77102025a30eef274e8d343bfec75f87899a417 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 18:30:57 +0200 Subject: [PATCH 0255/1342] tests: don't build tests unless make check is run Use check_PROGRAMS instead of noinst_PROGRAMS in tests/Makefile.am to build the tests only when make check is actually run. Signed-off-by: Christian Franke --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index b7a7fe748..2ed0e1c59 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,7 +24,7 @@ else TESTS_BGPD = endif -noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ +check_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest \ $(TESTS_BGPD) From 78116ab6e1524815910658898620776ae5fd4d18 Mon Sep 17 00:00:00 2001 From: Greg Troxel Date: Mon, 15 Jul 2013 10:15:49 -0400 Subject: [PATCH 0256/1342] doc: Modernize INSTALL.quagga.txt. Note that list of prereq versions is out of date. Add DejaGnu for testing. Change references to CVS to git. Signed-off-by: Greg Troxel --- INSTALL.quagga.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/INSTALL.quagga.txt b/INSTALL.quagga.txt index ae3d4ec61..0d465879f 100644 --- a/INSTALL.quagga.txt +++ b/INSTALL.quagga.txt @@ -46,9 +46,9 @@ The Quagga website (http://www.quagga.net) currently has the info files available in various formats. -------------------------------------------------------------------------- -Building Quagga from CVS checkouts: +Building Quagga from git checkouts: -In order to build from CVS, you will need recent versions of several GNU +In order to build from git, you will need recent versions of several GNU tools, particularly autoconf, automake, libtool, GNU awk and texinfo. Note that the CVS snapshots on the Quagga website should not require these tools; everything is already setup ready to run 'configure'. If you have trouble @@ -61,12 +61,17 @@ a bug. Required versions can be moved earlier if no problems, or later after a judgement that a system without a higher version is deficient is made. + [TODO: this list is out of date as of 2013-07] automake: 1.9.6 (released 2005-07-10) autoconf: 2.59 (2.60 on 2006-06-26 is too recent to require) libtool: 1.5.22 (released 2005-12-18) texinfo: 4.7 (released 2004-04-10; 4.8 is not yet common) GNU AWK: 3.1.5 (released 2005-08-12) +For running tests, one also needs: + + DejaGnu: + [TODO: texinfo 4.6 is now ancient and this should be revisited/fixed] Because some systems provide texinfo 4.6 (4.7 is new), quagga.info is checked in so that texinfo will generally not be invoked. When From c51443f4aa6b7f0b0d6ad5409ad7d4b215092443 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 8 Jul 2013 23:05:28 +0200 Subject: [PATCH 0257/1342] ospfd: CVE-2013-2236, stack overrun in apiserver the OSPF API-server (exporting the LSDB and allowing announcement of Opaque-LSAs) writes past the end of fixed on-stack buffers. This leads to an exploitable stack overflow. For this condition to occur, the following two conditions must be true: - Quagga is configured with --enable-opaque-lsa - ospfd is started with the "-a" command line option If either of these does not hold, the relevant code is not executed and the issue does not get triggered. Since the issue occurs on receiving large LSAs (larger than 1488 bytes), it is possible for this to happen during normal operation of a network. In particular, if there is an OSPF router with a large number of interfaces, the Router-LSA of that router may exceed 1488 bytes and trigger this, leading to an ospfd crash. For an attacker to exploit this, s/he must be able to inject valid LSAs into the OSPF domain. Any best-practice protection measure (using crypto authentication, restricting OSPF to internal interfaces, packet filtering protocol 89, etc.) will prevent exploitation. On top of that, remote (not on an OSPF-speaking network segment) attackers will have difficulties bringing up the adjacency needed to inject a LSA. This patch only performs minimal changes to remove the possibility of a stack overrun. The OSPF API in general is quite ugly and needs a rewrite. Reported-by: Ricky Charlet Cc: Florian Weimer Signed-off-by: David Lamparter --- ospfd/ospf_api.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 74a49e3be..fae942ec2 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -472,6 +472,9 @@ new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter) emsg->filter.typemask = htons (filter->typemask); emsg->filter.origin = filter->origin; emsg->filter.num_areas = filter->num_areas; + if (len > sizeof (buf)) + len = sizeof(buf); + /* API broken - missing memcpy to fill data */ return msg_new (MSG_REGISTER_EVENT, emsg, seqnum, len); } @@ -488,6 +491,9 @@ new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter) smsg->filter.typemask = htons (filter->typemask); smsg->filter.origin = filter->origin; smsg->filter.num_areas = filter->num_areas; + if (len > sizeof (buf)) + len = sizeof(buf); + /* API broken - missing memcpy to fill data */ return msg_new (MSG_SYNC_LSDB, smsg, seqnum, len); } @@ -501,13 +507,15 @@ new_msg_originate_request (u_int32_t seqnum, int omsglen; char buf[OSPF_API_MAX_MSG_SIZE]; - omsglen = sizeof (struct msg_originate_request) - sizeof (struct lsa_header) - + ntohs (data->length); - omsg = (struct msg_originate_request *) buf; omsg->ifaddr = ifaddr; omsg->area_id = area_id; - memcpy (&omsg->data, data, ntohs (data->length)); + + omsglen = ntohs (data->length); + if (omsglen > sizeof (buf) - offsetof (struct msg_originate_request, data)) + omsglen = sizeof (buf) - offsetof (struct msg_originate_request, data); + memcpy (&omsg->data, data, omsglen); + omsglen += sizeof (struct msg_originate_request) - sizeof (struct lsa_header); return msg_new (MSG_ORIGINATE_REQUEST, omsg, seqnum, omsglen); } @@ -627,13 +635,16 @@ new_msg_lsa_change_notify (u_char msgtype, assert (data); nmsg = (struct msg_lsa_change_notify *) buf; - len = ntohs (data->length) + sizeof (struct msg_lsa_change_notify) - - sizeof (struct lsa_header); nmsg->ifaddr = ifaddr; nmsg->area_id = area_id; nmsg->is_self_originated = is_self_originated; memset (&nmsg->pad, 0, sizeof (nmsg->pad)); - memcpy (&nmsg->data, data, ntohs (data->length)); + + len = ntohs (data->length); + if (len > sizeof (buf) - offsetof (struct msg_lsa_change_notify, data)) + len = sizeof (buf) - offsetof (struct msg_lsa_change_notify, data); + memcpy (&nmsg->data, data, len); + len += sizeof (struct msg_lsa_change_notify) - sizeof (struct lsa_header); return msg_new (msgtype, nmsg, seqnum, len); } From c423d413e464913ee88c1ee700e2c4037e6bdb24 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 30 Jul 2013 15:36:26 +0200 Subject: [PATCH 0258/1342] lib: unconditionally include stddef.h I've used offsetof() in the previous commit to paper over the security problems in ospf_api.c. This blows the build on FreeBSD 7.0, missing offsetof(). Let's add that to zebra's generally used includes. stddef.h (and offsetof) is defined in C89 section 4.1.5 (and not deprecated/removed by any later standard). If this causes problems, the bug report should go against the host OS/compiler... Signed-off-by: David Lamparter --- lib/zebra.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zebra.h b/lib/zebra.h index ffca7a8fb..780e12eb3 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -40,6 +40,7 @@ typedef int socklen_t; #include #include #include +#include #include #include #include @@ -175,7 +176,6 @@ typedef int socklen_t; #include #include #include -#include #else #define RT_TABLE_MAIN 0 #endif /* HAVE_NETLINK */ From 397b5bded5654a31b4bd3b904f091fd3859aecf7 Mon Sep 17 00:00:00 2001 From: Leonid Rosenboim Date: Tue, 30 Jul 2013 20:14:25 +0200 Subject: [PATCH 0259/1342] bgpd: stricter packet handling in OpenSent Keepalives and updates are not expected in OpenSent, prior to receiving the peer's open message. Terminate the session with the proper notification. From: Leonid Rosenboim [split off FSM changes, some reordering & cleanup. read handling needs to be separately addressed] Signed-off-by: David Lamparter --- bgpd/bgp_fsm.c | 59 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index d92004579..fba942769 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -592,6 +592,32 @@ bgp_stop_with_error (struct peer *peer) return 0; } + +/* something went wrong, send notify and tear down */ +static int +bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) +{ + /* Send notify to remote peer */ + bgp_notify_send (peer, code, sub_code); + + /* Sweep if it is temporary peer. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); + peer_delete (peer); + return -1; + } + + /* Clear start timer value to default. */ + peer->v_start = BGP_INIT_START_TIMER; + + /* bgp_stop needs to be invoked while in Established state */ + bgp_stop(peer); + + return 0; +} + + /* TCP connection open. Next we send open message to remote peer. And add read thread for reading open message. */ static int @@ -740,29 +766,26 @@ bgp_fsm_keepalive_expire (struct peer *peer) return 0; } +/* FSM error, unexpected event. This is error of BGP connection. So cut the + peer and change to Idle status. */ +static int +bgp_fsm_event_error (struct peer *peer) +{ + plog_err (peer->log, "%s [FSM] unexpected packet received in state %s", + peer->host, LOOKUP (bgp_status_msg, peer->status)); + + return bgp_stop_with_notify (peer, BGP_NOTIFY_FSM_ERR, 0); +} + /* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_holdtime_expire (struct peer *peer) { if (BGP_DEBUG (fsm, FSM)) - zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host); + plog_debug (peer->log, "%s [FSM] Hold timer expire", peer->host); - /* Send notify to remote peer. */ - bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0); - - /* Sweep if it is temporary peer. */ - if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - { - zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); - peer_delete (peer); - return -1; - } - - /* bgp_stop needs to be invoked while in Established state */ - bgp_stop(peer); - - return 0; + return bgp_stop_with_notify (peer, BGP_NOTIFY_HOLD_ERR, 0); } /* Status goes to Established. Send keepalive packet then make first @@ -977,8 +1000,8 @@ static const struct { {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ - {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ - {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, From 9e47abd862f71847a85f330435c7b3a9b1f76099 Mon Sep 17 00:00:00 2001 From: Rakesh Garimella Date: Mon, 11 Mar 2013 12:38:31 +0000 Subject: [PATCH 0260/1342] bgpd: prevent double address delete on shutdown bgp_interface_down() and bgp_exit() both proceed to delete the address from bgpd's interface representation, so the second call gets a NULL result from the hash lookup and subsequently crashes. Signed-off-by: Rakesh Garimella [reformatted] Signed-off-by: David Lamparter --- bgpd/bgp_nexthop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index d46923665..4076fe419 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -604,6 +604,10 @@ bgp_address_del (struct prefix *p) tmp.addr = p->u.prefix4; addr = hash_lookup (bgp_address_hash, &tmp); + /* may have been deleted earlier by bgp_interface_down() */ + if (addr == NULL) + return; + addr->refcnt--; if (addr->refcnt == 0) From 8ff202e2d3fa7ebbd6728fdd230f3ad1a20578cd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 31 Jul 2013 14:39:41 +0200 Subject: [PATCH 0261/1342] bgpd: write NOTIFY non-blockingly switching the socket to blocking may well block the entire bgpd process for some time if our peer is overloaded (which may well be the original reason for the NOTIFY) The error handling is slightly different from the previous ML discussion on this; buffer exhaustion isn't technically a fatal TCP error, and we should probably proceed with FSM actions according to a sent NOTIFY (adjusting timers) even if we didn't manage to get the NOTIFY onto the wire. Acked-by: Leonid Rosenboim Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d115353f8..d71df0823 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -719,14 +719,15 @@ bgp_write_notify (struct peer *peer) return 0; assert (stream_get_endp (s) >= BGP_HEADER_SIZE); - /* Put socket in blocking mode. */ - val = fcntl (peer->fd, F_GETFL, 0); - fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK); - /* Stop collecting data within the socket */ sockopt_cork (peer->fd, 0); + /* socket is in nonblocking mode, if we can't deliver the NOTIFY, well, + * we only care about getting a clean shutdown at this point. */ ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); + + /* only connection reset/close gets counted as TCP_fatal_error, failure + * to write the entire NOTIFY doesn't get different FSM treatment */ if (ret <= 0) { BGP_EVENT_ADD (peer, TCP_fatal_error); From 67e7a2127c05a8c7dfddd7ffc6378edf6b666d55 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 4 Mar 2013 09:23:30 +0000 Subject: [PATCH 0262/1342] vtysh: don't append superflous spaces (BZ#750) rl_completion_append_character is reset to space every time the completion function is entered. So we would have to set it to '\0' every time new_completion() is called. We can make this conditional and avoid using rl_pending_input. This code path is most relevant when there are multiple completion matches with the same prefix, e.g. in router bgp context: "neighbor 1.2.3.4 pa" would have been completed to "neighbor 1.2.3.4 pass " instead of "neighbor 1.2.3.4 pass". Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- vtysh/vtysh.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index e3709e07e..c575902cd 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -677,8 +677,9 @@ new_completion (char *text, int start, int end) if (matches) { rl_point = rl_end; - if (complete_status == CMD_COMPLETE_FULL_MATCH) - rl_pending_input = ' '; + if (complete_status != CMD_COMPLETE_FULL_MATCH) + /* only append a space on full match */ + rl_completion_append_character = '\0'; } return matches; @@ -2214,9 +2215,6 @@ vtysh_readline_init (void) rl_bind_key ('?', (Function *) vtysh_rl_describe); rl_completion_entry_function = vtysh_completion_entry_function; rl_attempted_completion_function = (CPPFunction *)new_completion; - /* do not append space after completion. It will be appended - * in new_completion() function explicitly. */ - rl_completion_append_character = '\0'; } char * From a52070899afed55ae44ed6a140ac090cdf07d141 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 11 Apr 2013 08:24:29 +0000 Subject: [PATCH 0263/1342] zebra: don't printf to stdout on ZEBRA_IPV6_NEXTHOP_LOOKUP Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/zserv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index cb8dbcb3a..8aaaea6f1 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1049,7 +1049,9 @@ zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) char buf[BUFSIZ]; stream_get (&addr, client->ibuf, 16); - printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ)); + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: looking up %s", __func__, + inet_ntop (AF_INET6, &addr, buf, BUFSIZ)); return zsend_ipv6_nexthop_lookup (client, &addr); } From 4ff3bcad8e81b643f3247317a3949d7867b36f75 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 20 Mar 2013 10:50:07 +0000 Subject: [PATCH 0264/1342] isisd, ospf6d: use bug-report information from autoconf Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- isisd/isis_main.c | 2 +- ospf6d/ospf6_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index dcbc3de96..96816ebb2 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -144,7 +144,7 @@ Daemon which manages IS-IS routing\n\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ -Report bugs to http://bugzilla.quagga.net\n", progname); +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 1bdf52fb4..17d7654e9 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -125,7 +125,7 @@ Daemon which manages OSPF version 3.\n\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ -Report bugs to zebra@zebra.org\n", progname); +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); From a0f6ce5b41dcfa059074d72c8fc61896d3e996a9 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 11 Apr 2013 08:24:30 +0000 Subject: [PATCH 0265/1342] bgpd: honor PEER_FLAG_DISABLE_CONNECTED_CHECK on bgp_scan When neighbor disable-connected-check was used, bgpd would accept routes with unconnected nexthop as indended, however those routes would be invalidated on the next bgp_scan run as that function did not know about disable-connected-check. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_nexthop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 4076fe419..17586bc81 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -453,7 +453,8 @@ bgp_scan (afi_t afi, safi_t safi) changed = 0; metricchanged = 0; - if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1) + if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1 + && !CHECK_FLAG(bi->peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) valid = bgp_nexthop_onlink (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, From 5b9f51828db732d56053500b1d257797f7f3401b Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 25 May 2013 14:01:34 +0000 Subject: [PATCH 0266/1342] zebra: improve display of NEXTHOP_IPV4_IFINDEX in show ip route Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index d07b09c8e..a672d4222 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -621,7 +621,11 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + 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: @@ -731,7 +735,10 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + 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: From bb97e4622ed6f48e2b8e07f1f94edd03162223a1 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 25 May 2013 14:01:35 +0000 Subject: [PATCH 0267/1342] bgpd, zebra: Support NEXTHOP_IPV4_IFINDEX in nexthop_lookup api Since commit ba281d3d040, ospfd uses NEXTHOP_IPV4_IFINDEX routes. The API between zebra and bgpd which is used to query nexthops for recursive routes did not support this nexthop type and therefore, ospf changes (or any other IGP changes which use NEXTHOP_IPV4_IFINDEX) would never trigger any recursive route update. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_nexthop.c | 13 +++++++++++++ zebra/zserv.c | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 17586bc81..7d8d86658 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -122,6 +122,11 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) return 0; break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4) + || next1->ifindex != next2->ifindex) + return 0; + break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: if (next1->ifindex != next2->ifindex) @@ -832,6 +837,10 @@ zlookup_read (void) case ZEBRA_NEXTHOP_IPV4: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); + nexthop->ifindex = stream_getl (s); + break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); @@ -1304,6 +1313,10 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) case NEXTHOP_TYPE_IPV4: vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " gate %s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN)); + vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); + break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; diff --git a/zebra/zserv.c b/zebra/zserv.c index 8aaaea6f1..f792c8388 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -548,6 +548,8 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) if (rib) { + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Matching rib entry found.", __func__); stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); @@ -561,6 +563,10 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) case ZEBRA_NEXTHOP_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: stream_putl (s, nexthop->ifindex); @@ -575,6 +581,8 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) } else { + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: No matching rib entry found.", __func__); stream_putl (s, 0); stream_putc (s, 0); } @@ -890,8 +898,12 @@ static int zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) { struct in_addr addr; + char buf[BUFSIZ]; addr.s_addr = stream_get_ipv4 (client->ibuf); + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: looking up %s", __func__, + inet_ntop (AF_INET, &addr, buf, BUFSIZ)); return zsend_ipv4_nexthop_lookup (client, addr); } From a12afd5e8e57c95505d4d0166af234c7f19e9fe1 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 25 May 2013 14:01:36 +0000 Subject: [PATCH 0268/1342] bgpd, zebra: support NEXTHOP_IPV4_IFINDEX in bgp import check Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_nexthop.c | 16 +++++++++++----- zebra/zserv.c | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 7d8d86658..e23155c7e 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1093,14 +1093,20 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, { nexthop.s_addr = 0; nexthop_type = stream_getc (s); - if (nexthop_type == ZEBRA_NEXTHOP_IPV4) + switch (nexthop_type) { + case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); - if (igpnexthop) - *igpnexthop = nexthop; + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + nexthop.s_addr = stream_get_ipv4 (s); + /* ifindex */ (void)stream_getl (s); + break; + default: + /* do nothing */ + break; } - else - *igpnexthop = nexthop; + *igpnexthop = nexthop; return 1; } diff --git a/zebra/zserv.c b/zebra/zserv.c index f792c8388..118293780 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -627,6 +627,10 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) case ZEBRA_NEXTHOP_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: stream_putl (s, nexthop->ifindex); From 23cd8fb7133befdb84b3a918f7b2f6147161ac6e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 2 Aug 2013 07:27:53 +0000 Subject: [PATCH 0269/1342] ospfd: protect vs. VU#229804 (malformed Router-LSA) VU#229804 reports that, by injecting Router LSAs with the Advertising Router ID different from the Link State ID, OSPF implementations can be tricked into retaining and using invalid information. Quagga is not vulnerable to this because it looks up Router LSAs by (Router-ID, LS-ID) pair. The relevant code is in ospf_lsa.c l.3140. Note the double "id" parameter at the end. Still, we can provide an improvement here by discarding such malformed LSAs and providing a warning to the administrator. While we cannot prevent such malformed LSAs from entering the OSPF domain, we can certainly try to limit their distribution. cf. http://www.kb.cert.org/vuls/id/229804 for the vulnerability report. This issue is a specification issue in the OSPF protocol that was discovered by Dr. Gabi Nakibly. Reported-by: CERT Coordination Center Signed-off-by: David Lamparter --- ospfd/ospf_packet.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 37223fbb7..ab68bf0b7 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1823,6 +1823,27 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, DISCARD_LSA (lsa,2); } + /* VU229804: Router-LSA Adv-ID must be equal to LS-ID */ + if (lsa->data->type == OSPF_ROUTER_LSA) + if (!IPV4_ADDR_SAME(&lsa->data->id, &lsa->data->adv_router)) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + char buf3[INET_ADDRSTRLEN]; + + zlog_err("Incoming Router-LSA from %s with " + "Adv-ID[%s] != LS-ID[%s]", + inet_ntop (AF_INET, &ospfh->router_id, + buf1, INET_ADDRSTRLEN), + inet_ntop (AF_INET, &lsa->data->id, + buf2, INET_ADDRSTRLEN), + inet_ntop (AF_INET, &lsa->data->adv_router, + buf3, INET_ADDRSTRLEN)); + zlog_err("OSPF domain compromised by attack or corruption. " + "Verify correct operation of -ALL- OSPF routers."); + DISCARD_LSA (lsa, 0); + } + /* Find the LSA in the current database. */ current = ospf_lsa_lookup_by_header (oi->area, lsa->data); From 599da95527ec8e09cd3d890dc3addc6f2e791a0c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:43 +0000 Subject: [PATCH 0270/1342] zebra: process information about new addresses (BZ#486) Because of a change of semantics in the Linux kernel, information about changes made by zebra itself was not considered for updates. This change should fix this by accounting for the new semantics. It is based on a patch by lich posted to the bugzilla #486 Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index bab170371..86e02efb8 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -381,8 +381,11 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, h->nlmsg_seq, h->nlmsg_pid); - /* skip unsolicited messages originating from command socket */ - if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid) + /* skip unsolicited messages originating from command socket + * linux sets the originators port-id for {NEW|DEL}ADDR messages, + * so this has to be checked here. */ + if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid + && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s packet comes from %s", From 9db047fcb1bedcf1a5a1962e49aa70f48f969b96 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:44 +0000 Subject: [PATCH 0271/1342] zebra: make if_subnet_delete a bit more strict Enhance if_subnet_delete so it will complain about improper use. Also, fix one occurence of improper use where it was called for IPv6 as well. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/connected.c | 5 +++-- zebra/interface.c | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/zebra/connected.c b/zebra/connected.c index 05538c5d4..3db1271d0 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -49,8 +49,9 @@ connected_withdraw (struct connected *ifc) { zebra_interface_address_delete_update (ifc->ifp, ifc); - if_subnet_delete (ifc->ifp, ifc); - + if (ifc->address->family == AF_INET) + if_subnet_delete (ifc->ifp, ifc); + if (ifc->address->family == AF_INET) connected_down_ipv4 (ifc->ifp, ifc); #ifdef HAVE_IPV6 diff --git a/zebra/interface.c b/zebra/interface.c index 3578b7900..baa7ab638 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -161,11 +161,26 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc) /* Get address derived subnet node. */ rn = route_node_lookup (zebra_if->ipv4_subnets, ifc->address); if (! (rn && rn->info)) - return -1; + { + zlog_warn("Trying to remove an address from an unknown subnet." + " (please report this bug)"); + return -1; + } route_unlock_node (rn); /* Untie address from subnet's address list. */ addr_list = rn->info; + + /* Deleting an address that is not registered is a bug. + * In any case, we shouldn't decrement the lock counter if the address + * is unknown. */ + if (!listnode_lookup(addr_list, ifc)) + { + zlog_warn("Trying to remove an address from a subnet where it is not" + " currently registered. (please report this bug)"); + return -1; + } + listnode_delete (addr_list, ifc); route_unlock_node (rn); From 676e1a0142ec8b181d4d7ea1038f461bc67c1ee1 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:45 +0000 Subject: [PATCH 0272/1342] zebra: clear ZEBRA_IFC_CONFIGURED on "no ipv6 addr" To match the semantics of IPv4, the ZEBRA_IFC_CONFIGURED flag should be cleared when an IPv6 connected is uninstalled via vty. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/interface.c b/zebra/interface.c index baa7ab638..cd78ebbcd 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1499,6 +1499,8 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp, if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) return CMD_WARNING; + UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); + /* This is not real address or interface is not active. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) From d7f5dad6d1ab3078fcabc79e15a88873940c074d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:46 +0000 Subject: [PATCH 0273/1342] zebra: consolidate connected_implicit_withdraw connected_implicit_withdraw is used at two places and followed by exactly the same code. Move that code into connected_implicit_withdraw and give that function a more descriptive name. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/connected.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/zebra/connected.c b/zebra/connected.c index 3db1271d0..38ab37d59 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -137,14 +137,10 @@ connected_same (struct connected *ifc1, struct connected *ifc2) return 1; } -/* Handle implicit withdrawals of addresses, where a system ADDs an address - * to an interface which already has the same address configured. - * - * Returns the struct connected which must be announced to clients, - * or NULL if nothing to do. - */ -static struct connected * -connected_implicit_withdraw (struct interface *ifp, struct connected *ifc) +/* Handle changes to addresses and send the neccesary announcements + * to clients. */ +static void +connected_update(struct interface *ifp, struct connected *ifc) { struct connected *current; @@ -161,13 +157,17 @@ connected_implicit_withdraw (struct interface *ifp, struct connected *ifc) { /* nothing to do */ connected_free (ifc); - return NULL; + return; } - + + /* Clear the configured flag on the old ifc, so it will be freed by + * connected withdraw. */ UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED); connected_withdraw (current); /* implicit withdraw - freebsd does this */ } - return ifc; + + /* If the connected is new or has changed, announce it */ + connected_announce(ifp, ifc); } /* Called from if_up(). */ @@ -273,11 +273,7 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); - /* nothing to do? */ - if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) - return; - - connected_announce (ifp, ifc); + connected_update(ifp, ifc); } void @@ -401,11 +397,8 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, /* Label of this address. */ if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); - - if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) - return; - - connected_announce (ifp, ifc); + + connected_update(ifp, ifc); } void From c7df92de2dc91d0a934cf892e543728cb1a10849 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:47 +0000 Subject: [PATCH 0274/1342] zebra: warn if advertising connected with _REAL unset The implementation in zebra and the zclient protocol allow to communicate addresses to clients which are not yet in the kernel. This is usually not done and most clients seem to expect an address to be configured in the kernel when they receive it. Therefore, it seems reasonable to issue a warning when advertising an address to the clients that is not yet in the kernel. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/redistribute.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 476582485..078c2ad0b 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -358,6 +358,9 @@ zebra_interface_address_add_update (struct interface *ifp, p->prefixlen, ifc->ifp->name); } + if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) + zlog_warn("WARNING: advertising address to clients that is not yet usable."); + router_id_add_address(ifc); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) From f7f740fe58fb838fc87e82dc7e1e2d4e5ccf085c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:48 +0000 Subject: [PATCH 0275/1342] zebra: add ZEBRA_IFC_QUEUED to keep track of kernel state As there are timeframes when we don't get a notification from the kernel about new addresses. (e.g. while Linux performs IPv6 DAD), we need to have some information whether an address has been sent to the kernel or not. One case where this is relevant would be a user adding an IPv6 address, but deleting it before DAD has been complete. With the next patch which removes some (ill assuming) synchronous parts in address setup, ipv6_address_uninstall would not know whether or not it has to actually delete the prefix from the kernel. Resolving these windows where we lack information is what the flag ZEBRA_IFC_QUEUED is intended for. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- lib/if.h | 7 ++++++- zebra/connected.c | 9 +++++++++ zebra/interface.c | 19 ++++++++++++++----- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/if.h b/lib/if.h index 2116e12eb..13cc254e2 100644 --- a/lib/if.h +++ b/lib/if.h @@ -151,11 +151,16 @@ struct connected u_char conf; #define ZEBRA_IFC_REAL (1 << 0) #define ZEBRA_IFC_CONFIGURED (1 << 1) +#define ZEBRA_IFC_QUEUED (1 << 2) /* The ZEBRA_IFC_REAL flag should be set if and only if this address - exists in the kernel. + exists in the kernel and is actually usable. (A case where it exists but + is not yet usable would be IPv6 with DAD) The ZEBRA_IFC_CONFIGURED flag should be set if and only if this address was configured by the user from inside quagga. + The ZEBRA_IFC_QUEUED flag should be set if and only if the address exists + in the kernel. It may and should be set although the address might not be + usable yet. (compare with ZEBRA_IFC_REAL) */ /* Flags for connected address. */ diff --git a/zebra/connected.c b/zebra/connected.c index 38ab37d59..d474560c8 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -62,6 +62,9 @@ connected_withdraw (struct connected *ifc) UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); } + /* The address is not in the kernel anymore, so clear the flag */ + UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); + if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { listnode_delete (ifc->ifp->connected, ifc); @@ -211,6 +214,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, ifc = connected_new (); ifc->ifp = ifp; ifc->flags = flags; + /* If we get a notification from the kernel, + * we can safely assume the address is known to the kernel */ + SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* Allocate new connected address. */ p = prefix_ipv4_new (); @@ -363,6 +369,9 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, ifc = connected_new (); ifc->ifp = ifp; ifc->flags = flags; + /* If we get a notification from the kernel, + * we can safely assume the address is known to the kernel */ + SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* Allocate new connected address. */ p = prefix_ipv6_new (); diff --git a/zebra/interface.c b/zebra/interface.c index cd78ebbcd..470df0cdd 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -289,7 +289,7 @@ if_addr_wakeup (struct interface *ifp) p = ifc->address; if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED) - && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)) { /* Address check. */ if (p->family == AF_INET) @@ -321,6 +321,7 @@ if_addr_wakeup (struct interface *ifp) /* Add to subnet chain list. */ if_subnet_add (ifp, ifc); + SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); zebra_interface_address_add_update (ifp, ifc); @@ -345,6 +346,7 @@ if_addr_wakeup (struct interface *ifp) safe_strerror(errno)); continue; } + SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); zebra_interface_address_add_update (ifp, ifc); @@ -454,6 +456,7 @@ if_delete_update (struct interface *ifp) zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* Remove from subnet chain. */ list_delete_node (addr_list, anode); @@ -482,6 +485,7 @@ if_delete_update (struct interface *ifp) zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) last = node; @@ -1229,7 +1233,7 @@ ip_address_install (struct vty *vty, struct interface *ifp, SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); /* In case of this route need to install kernel. */ - if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { /* Some system need to up the interface to set IP address. */ @@ -1251,6 +1255,7 @@ ip_address_install (struct vty *vty, struct interface *ifp, if_subnet_add (ifp, ifc); /* IP address propery set. */ + SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* Update interface address information to protocol daemon. */ @@ -1296,7 +1301,7 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp, UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ - if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { listnode_delete (ifp->connected, ifc); @@ -1321,6 +1326,7 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp, * through the route socket, and we don't want to touch that behaviour * for now. It should work without the #ifdef, but why take the risk... * -- equinox 2012-07-13 */ + UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); #ifdef HAVE_NETLINK /* Remove connected route. */ @@ -1437,7 +1443,7 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); /* In case of this route need to install kernel. */ - if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { /* Some system need to up the interface to set IP address. */ @@ -1457,6 +1463,7 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, } /* IP address propery set. */ + SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* Update interface address information to protocol daemon. */ @@ -1502,7 +1509,7 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp, UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ - if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { listnode_delete (ifp->connected, ifc); @@ -1519,6 +1526,8 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp, return CMD_WARNING; } + UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); + /* Redistribute this information. */ zebra_interface_address_delete_update (ifp, ifc); From 02b4805f3914ef6ba0242c6f4dd1b6759ef97bf2 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:49 +0000 Subject: [PATCH 0276/1342] zebra: don't change connected state from zebra/interface.c Try to avoid changing connected state from zebra/interface.c as this means making assumptions about kernel behaviour which may be or may become wrong. This state should rather be updated by events from the kernel. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/connected.c | 49 +++++++++++------- zebra/interface.c | 126 ++++++++++++++-------------------------------- 2 files changed, 69 insertions(+), 106 deletions(-) diff --git a/zebra/connected.c b/zebra/connected.c index d474560c8..4802f2ba0 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -37,7 +37,7 @@ #include "zebra/connected.h" extern struct zebra_t zebrad; -/* withdraw a connected address */ +/* communicate the withdrawal of a connected address */ static void connected_withdraw (struct connected *ifc) { @@ -81,24 +81,19 @@ connected_announce (struct interface *ifp, struct connected *ifc) listnode_add (ifp->connected, ifc); /* Update interface address information to protocol daemon. */ - if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) - { - if (ifc->address->family == AF_INET) - if_subnet_add (ifp, ifc); + if (ifc->address->family == AF_INET) + if_subnet_add (ifp, ifc); - SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + zebra_interface_address_add_update (ifp, ifc); - zebra_interface_address_add_update (ifp, ifc); - - if (if_is_operative(ifp)) - { - if (ifc->address->family == AF_INET) - connected_up_ipv4 (ifp, ifc); + if (if_is_operative(ifp)) + { + if (ifc->address->family == AF_INET) + connected_up_ipv4 (ifp, ifc); #ifdef HAVE_IPV6 - else - connected_up_ipv6 (ifp, ifc); + else + connected_up_ipv6 (ifp, ifc); #endif - } } } @@ -116,7 +111,7 @@ connected_check (struct interface *ifp, struct prefix *p) return NULL; } -/* Check if two ifc's describe the same address */ +/* Check if two ifc's describe the same address in the same state */ static int connected_same (struct connected *ifc1, struct connected *ifc2) { @@ -136,6 +131,9 @@ connected_same (struct connected *ifc1, struct connected *ifc2) if (ifc1->flags != ifc2->flags) return 0; + + if (ifc1->conf != ifc2->conf) + return 0; return 1; } @@ -156,7 +154,7 @@ connected_update(struct interface *ifp, struct connected *ifc) /* Avoid spurious withdraws, this might be just the kernel 'reflecting' * back an address we have already added. */ - if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL)) + if (connected_same (current, ifc)) { /* nothing to do */ connected_free (ifc); @@ -169,8 +167,9 @@ connected_update(struct interface *ifp, struct connected *ifc) connected_withdraw (current); /* implicit withdraw - freebsd does this */ } - /* If the connected is new or has changed, announce it */ - connected_announce(ifp, ifc); + /* If the connected is new or has changed, announce it, if it is usable */ + if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) + connected_announce(ifp, ifc); } /* Called from if_up(). */ @@ -279,6 +278,10 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); + /* For all that I know an IPv4 address is always ready when we receive + * the notification. So it should be safe to set the REAL flag here. */ + SET_FLAG(ifc->conf, ZEBRA_IFC_REAL); + connected_update(ifp, ifc); } @@ -407,6 +410,14 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); + /* On Linux, we only get here when DAD is complete, therefore we can set + * ZEBRA_IFC_REAL. + * + * On BSD, there currently doesn't seem to be a way to check for completion of + * DAD, so we replicate the old behaviour and set ZEBRA_IFC_REAL, although DAD + * might still be running. + */ + SET_FLAG(ifc->conf, ZEBRA_IFC_REAL); connected_update(ifp, ifc); } diff --git a/zebra/interface.c b/zebra/interface.c index 470df0cdd..51798ca6c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -193,6 +193,9 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc) ifc = listgetdata (listhead (addr_list)); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); + /* XXX: Linux kernel removes all the secondary addresses when the primary + * address is removed. We could try to work around that, though this is + * non-trivial. */ zebra_interface_address_add_update (ifp, ifc); } @@ -296,16 +299,23 @@ if_addr_wakeup (struct interface *ifp) { if (! if_is_up (ifp)) { - /* XXX: WTF is it trying to set flags here? - * caller has just gotten a new interface, has been - * handed the flags already. This code has no business - * trying to override administrative status of the interface. - * The only call path to here which doesn't originate from - * kernel event is irdp - what on earth is it trying to do? - * - * further RUNNING is not a settable flag on any system - * I (paulj) am aware of. - */ + /* Assume zebra is configured like following: + * + * interface gre0 + * ip addr 192.0.2.1/24 + * ! + * + * As soon as zebra becomes first aware that gre0 exists in the + * kernel, it will set gre0 up and configure its addresses. + * + * (This may happen at startup when the interface already exists + * or during runtime when the interface is added to the kernel) + * + * XXX: IRDP code is calling here via if_add_update - this seems + * somewhat weird. + * XXX: RUNNING is not a settable flag on any system + * I (paulj) am aware of. + */ if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } @@ -318,23 +328,17 @@ if_addr_wakeup (struct interface *ifp) continue; } - /* Add to subnet chain list. */ - if_subnet_add (ifp, ifc); - SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); - SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); - - zebra_interface_address_add_update (ifp, ifc); - - if (if_is_operative(ifp)) - connected_up_ipv4 (ifp, ifc); + /* The address will be advertised to zebra clients when the notification + * from the kernel has been received. + * It will also be added to the interface's subnet list then. */ } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { if (! if_is_up (ifp)) { - /* XXX: See long comment above */ + /* See long comment above */ if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } @@ -346,13 +350,10 @@ if_addr_wakeup (struct interface *ifp) safe_strerror(errno)); continue; } - SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); - SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); - - zebra_interface_address_add_update (ifp, ifc); - if (if_is_operative(ifp)) - connected_up_ipv6 (ifp, ifc); + SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); + /* The address will be advertised to zebra clients when the notification + * from the kernel has been received. */ } #endif /* HAVE_IPV6 */ } @@ -450,9 +451,11 @@ if_delete_update (struct interface *ifp) ifc = listgetdata (anode); p = ifc->address; - connected_down_ipv4 (ifp, ifc); + /* XXX: We have to send notifications here explicitly, because we destroy + * the ifc before receiving the notification about the address being deleted. + */ zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); @@ -1251,19 +1254,10 @@ ip_address_install (struct vty *vty, struct interface *ifp, return CMD_WARNING; } - /* Add to subnet chain list (while marking secondary attribute). */ - if_subnet_add (ifp, ifc); - - /* IP address propery set. */ SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); - SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); - - /* Update interface address information to protocol daemon. */ - zebra_interface_address_add_update (ifp, ifc); - - /* If interface is up register connected route. */ - if (if_is_operative(ifp)) - connected_up_ipv4 (ifp, ifc); + /* The address will be advertised to zebra clients when the notification + * from the kernel has been received. + * It will also be added to the subnet chain list, then. */ } return CMD_SUCCESS; @@ -1317,35 +1311,9 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } - /* success! call returned that the address deletion went through. - * this is a synchronous operation, so we know it succeeded and can - * now update all internal state. */ - - /* the HAVE_NETLINK check is only here because, on BSD, although the - * call above is still synchronous, we get a second confirmation later - * through the route socket, and we don't want to touch that behaviour - * for now. It should work without the #ifdef, but why take the risk... - * -- equinox 2012-07-13 */ UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); -#ifdef HAVE_NETLINK - - /* Remove connected route. */ - connected_down_ipv4 (ifp, ifc); - - /* Redistribute this information. */ - zebra_interface_address_delete_update (ifp, ifc); - - /* IP address propery set. */ - UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); - - /* remove from interface, remark secondaries */ - if_subnet_delete (ifp, ifc); - - /* Free address information. */ - listnode_delete (ifp->connected, ifc); - connected_free (ifc); -#endif - + /* we will receive a kernel notification about this route being removed. + * this will trigger its removal from the connected list. */ return CMD_SUCCESS; } @@ -1462,16 +1430,9 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, return CMD_WARNING; } - /* IP address propery set. */ SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); - SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); - - /* Update interface address information to protocol daemon. */ - zebra_interface_address_add_update (ifp, ifc); - - /* If interface is up register connected route. */ - if (if_is_operative(ifp)) - connected_up_ipv6 (ifp, ifc); + /* The address will be advertised to zebra clients when the notification + * from the kernel has been received. */ } return CMD_SUCCESS; @@ -1527,17 +1488,8 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp, } UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); - - /* Redistribute this information. */ - zebra_interface_address_delete_update (ifp, ifc); - - /* Remove connected route. */ - connected_down_ipv6 (ifp, ifc); - - /* Free address information. */ - listnode_delete (ifp->connected, ifc); - connected_free (ifc); - + /* This information will be propagated to the zclients when the + * kernel notification is received. */ return CMD_SUCCESS; } From bfac8dcd2fe7ed099a679b5c8245599c6d0312ed Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 24 Jan 2013 14:04:50 +0000 Subject: [PATCH 0277/1342] zebra: improve interface shutdown behaviour Linux removes IPv6 addresses when the interface is set down. Those addresses need to be readded when the interface is set up again. Also, an interface should not be reactivated from shutdown by configuring an ip address. Finally, remove the three-state logic for the shutdown setting as its sole current use may be mild confusion. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/interface.c | 64 +++++++++++++++++++++++++++++++++++------------ zebra/interface.h | 3 +-- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 51798ca6c..155ee0294 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -56,7 +56,7 @@ if_zebra_new_hook (struct interface *ifp) zebra_if = XCALLOC (MTYPE_TMP, sizeof (struct zebra_if)); zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; - zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC; + zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF; #ifdef RTADV { @@ -378,6 +378,14 @@ if_add_update (struct interface *ifp) { SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + if (if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("interface %s index %d is shutdown. Won't wake it up.", + ifp->name, ifp->ifindex); + return; + } + if_addr_wakeup (ifp); if (IS_ZEBRA_DEBUG_KERNEL) @@ -1095,13 +1103,16 @@ DEFUN (shutdown_if, struct zebra_if *if_data; ifp = (struct interface *) vty->index; - ret = if_unset_flags (ifp, IFF_UP); - if (ret < 0) + if (ifp->ifindex != IFINDEX_INTERNAL) { - vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE); - return CMD_WARNING; + ret = if_unset_flags (ifp, IFF_UP); + if (ret < 0) + { + vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); } - if_refresh (ifp); if_data = ifp->info; if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON; @@ -1119,13 +1130,23 @@ DEFUN (no_shutdown_if, struct zebra_if *if_data; ifp = (struct interface *) vty->index; - ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING); - if (ret < 0) + + if (ifp->ifindex != IFINDEX_INTERNAL) { - vty_out (vty, "Can't up interface%s", VTY_NEWLINE); - return CMD_WARNING; + ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if (ret < 0) + { + vty_out (vty, "Can't up interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + + /* Some addresses (in particular, IPv6 addresses on Linux) get + * removed when the interface goes down. They need to be readded. + */ + if_addr_wakeup(ifp); } - if_refresh (ifp); + if_data = ifp->info; if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF; @@ -1191,11 +1212,14 @@ ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label) { + struct zebra_if *if_data; struct prefix_ipv4 cp; struct connected *ifc; struct prefix_ipv4 *p; int ret; + if_data = ifp->info; + ret = str2prefix_ipv4 (addr_str, &cp); if (ret <= 0) { @@ -1237,7 +1261,8 @@ ip_address_install (struct vty *vty, struct interface *ifp, /* In case of this route need to install kernel. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) - && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE) + && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) { /* Some system need to up the interface to set IP address. */ if (! if_is_up (ifp)) @@ -1371,11 +1396,14 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label, int secondary) { + struct zebra_if *if_data; struct prefix_ipv6 cp; struct connected *ifc; struct prefix_ipv6 *p; int ret; + if_data = ifp->info; + ret = str2prefix_ipv6 (addr_str, &cp); if (ret <= 0) { @@ -1412,7 +1440,8 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, /* In case of this route need to install kernel. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) - && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE) + && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) { /* Some system need to up the interface to set IP address. */ if (! if_is_up (ifp)) @@ -1533,6 +1562,12 @@ if_config_write (struct vty *vty) vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); + if (if_data) + { + if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) + vty_out (vty, " shutdown%s", VTY_NEWLINE); + } + if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); @@ -1565,9 +1600,6 @@ if_config_write (struct vty *vty) if (if_data) { - if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) - vty_out (vty, " shutdown%s", VTY_NEWLINE); - if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC) vty_out (vty, " %smulticast%s", if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ", diff --git a/zebra/interface.h b/zebra/interface.h index 0777a2fa3..7a05348ca 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -34,9 +34,8 @@ #define IF_ZEBRA_MULTICAST_OFF 2 /* For interface shutdown configuration. */ -#define IF_ZEBRA_SHUTDOWN_UNSPEC 0 +#define IF_ZEBRA_SHUTDOWN_OFF 0 #define IF_ZEBRA_SHUTDOWN_ON 1 -#define IF_ZEBRA_SHUTDOWN_OFF 2 /* Router advertisement feature. */ #if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) From fa713d9ee5ed30dedd0a290be9aaff780a2896be Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 15:35:37 +0000 Subject: [PATCH 0278/1342] 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 Signed-off-by: David Lamparter --- tests/.gitignore | 1 + tests/Makefile.am | 4 +- tests/libzebra.tests/Makefile.am | 3 +- tests/libzebra.tests/testnexthopiter.exp | 8 + tests/prng.c | 82 ++++ tests/prng.h | 34 ++ tests/test-nexthop-iter.c | 291 ++++++++++++ zebra/rib.h | 62 ++- zebra/rt_ioctl.c | 122 ++--- zebra/rt_netlink.c | 548 +++++++++++------------ zebra/rt_socket.c | 98 ++-- zebra/zebra_fpm_netlink.c | 83 +--- zebra/zebra_rib.c | 264 +++++++---- zebra/zebra_routemap.c | 16 +- zebra/zebra_vty.c | 136 ++---- zebra/zserv.c | 12 +- 16 files changed, 1046 insertions(+), 718 deletions(-) create mode 100644 tests/libzebra.tests/testnexthopiter.exp create mode 100644 tests/prng.c create mode 100644 tests/prng.h create mode 100644 tests/test-nexthop-iter.c diff --git a/tests/.gitignore b/tests/.gitignore index 8baea0a87..31fb70a48 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -31,4 +31,5 @@ testmemory testprivs testsig teststream +testnexthopiter site.exp diff --git a/tests/Makefile.am b/tests/Makefile.am index 2ed0e1c59..e5c7fd79d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,7 +25,7 @@ TESTS_BGPD = endif check_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ - testprivs teststream testchecksum tabletest \ + testprivs teststream testchecksum tabletest testnexthopiter \ $(TESTS_BGPD) testsig_SOURCES = test-sig.c @@ -43,6 +43,7 @@ testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c +testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testsig_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@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm +testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/tests/libzebra.tests/Makefile.am b/tests/libzebra.tests/Makefile.am index 0d29e287c..14138a08e 100644 --- a/tests/libzebra.tests/Makefile.am +++ b/tests/libzebra.tests/Makefile.am @@ -1,2 +1,3 @@ EXTRA_DIST = \ - tabletest.exp + tabletest.exp \ + testnexthopiter.exp diff --git a/tests/libzebra.tests/testnexthopiter.exp b/tests/libzebra.tests/testnexthopiter.exp new file mode 100644 index 000000000..be35a0a2b --- /dev/null +++ b/tests/libzebra.tests/testnexthopiter.exp @@ -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." diff --git a/tests/prng.c b/tests/prng.c new file mode 100644 index 000000000..7b1b42821 --- /dev/null +++ b/tests/prng.c @@ -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 +#include + +#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); +} diff --git a/tests/prng.h b/tests/prng.h new file mode 100644 index 000000000..ed3649863 --- /dev/null +++ b/tests/prng.h @@ -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 diff --git a/tests/test-nexthop-iter.c b/tests/test-nexthop-iter.c new file mode 100644 index 000000000..250379329 --- /dev/null +++ b/tests/test-nexthop-iter.c @@ -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 +#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"); +} diff --git a/zebra/rib.h b/zebra/rib.h index e16ce68a1..4d98e0595 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -254,16 +254,65 @@ struct nexthop #define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ #define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ - /* Nexthop address or interface name. */ + /* Nexthop address */ union g_addr gate; - - /* Recursive lookup nexthop. */ - u_char rtype; - unsigned int rifindex; - union g_addr rgate; 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. */ struct vrf { @@ -333,6 +382,7 @@ extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, struct in_addr *, struct in_addr *, unsigned int); +extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (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 *); diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c index a5d588c7f..404a7c696 100644 --- a/zebra/rt_ioctl.c +++ b/zebra/rt_ioctl.c @@ -169,7 +169,8 @@ kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family) int sock; struct rtentry rtentry; struct sockaddr_in sin_dest, sin_mask, sin_gate; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; int nexthop_num = 0; 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); if (cmd == SIOCADDRT) - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + { + /* 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; } memset (&sin_gate, 0, sizeof (struct sockaddr_in)); /* 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 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == SIOCDELRT && 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 || - nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) - { - sin_gate.sin_family = AF_INET; + sin_gate.sin_family = AF_INET; #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 */ - sin_gate.sin_addr = nexthop->rgate.ipv4; - 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; - } + sin_gate.sin_addr = nexthop->gate.ipv4; + rtentry.rt_flags |= RTF_GATEWAY; } - else + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME) { - if (nexthop->type == NEXTHOP_TYPE_IPV4 || - nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - { - sin_gate.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - 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; - } + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp) + rtentry.rt_dev = ifp->name; + else + return -1; } if (cmd == SIOCADDRT) @@ -430,7 +415,8 @@ kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib, int ret; int sock; struct in6_rtmsg rtm; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; int nexthop_num = 0; 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; */ /* 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 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == SIOCDELRT && 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 - || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME - || 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; - + 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 - { - 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; - } + rtm.rtmsg_ifindex = 0; if (cmd == SIOCADDRT) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 86e02efb8..b0ade0588 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1426,6 +1426,207 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate, 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. */ static int 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; struct sockaddr_nl snl; - struct nexthop *nexthop = NULL; - int nexthop_num = 0; + struct nexthop *nexthop = NULL, *tnexthop; + int recursing; + int nexthop_num; int discard; + const char *routedesc; struct { @@ -1485,159 +1688,52 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, if (discard) { if (cmd == RTM_NEWROUTE) - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + { + /* 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; } - /* Multipath case. */ - if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) + /* Count overall nexthops so we can decide whether to use singlepath + * or multipath case. */ + 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 && !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) { - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + 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 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { + routedesc = recursing ? "recursive, 1 hop" : "single hop"; - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - { - if (IS_ZEBRA_DEBUG_KERNEL) - { - 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); - } - } + _netlink_route_debug(cmd, p, nexthop, routedesc, family); + _netlink_route_build_singlepath(routedesc, bytelen, + nexthop, &req.n, sizeof req); if (cmd == RTM_NEWROUTE) 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); nexthop_num = 0; - for (nexthop = rib->nexthop; - nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM); - nexthop = nexthop->next) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { + if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM) + break; + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { + routedesc = recursing ? "recursive, multihop" : "multihop"; nexthop_num++; - rtnh->rtnh_len = sizeof (*rtnh); - rtnh->rtnh_flags = 0; - rtnh->rtnh_hops = 0; - rta->rta_len += rtnh->rtnh_len; - - 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; - } - } + _netlink_route_debug(cmd, p, nexthop, + routedesc, family); + _netlink_route_build_multipath(routedesc, bytelen, + nexthop, rta, rtnh, &src); rtnh = RTNH_NEXT (rtnh); if (cmd == RTM_NEWROUTE) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 1b8ded7ee..5d175d849 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -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 sin_dest, sin_mask, sin_gate; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; int nexthop_num = 0; unsigned int ifindex = 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 */ /* 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; 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) )) { - 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 || - nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) - { - 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; + sin_gate.sin_addr = nexthop->gate.ipv4; + gate = 1; } - 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 || - nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - { - sin_gate.sin_addr = nexthop->gate.ipv4; - 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; - } + struct in_addr loopback; + loopback.s_addr = htonl (INADDR_LOOPBACK); + sin_gate.sin_addr = loopback; + gate = 1; } 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) zlog_debug ("%s: odd command %s for flags %d", __func__, lookup (rtm_type_str, cmd), nexthop->flags); - } /* for (nexthop = ... */ + } /* for (ALL_NEXTHOPS_RO(...))*/ /* If there was no useful nexthop, then complain. */ 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 sin_dest, sin_mask, sin_gate; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; int nexthop_num = 0; unsigned int ifindex = 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 */ /* 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; if ((cmd == RTM_ADD @@ -388,36 +380,18 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, #endif )) { - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - { - if (nexthop->rtype == NEXTHOP_TYPE_IPV6 - || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME - || 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) { - 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; + 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 (cmd == RTM_ADD) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 67bcf0a15..b5f2b7607 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -152,7 +152,8 @@ typedef struct netlink_route_info_t_ * Returns TRUE if a nexthop was added, FALSE otherwise. */ 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; 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)) return 0; - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_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.recursive = recursive; nhi.type = nexthop->type; 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; } - /* - * Fall through... - */ - - done: if (!nhi.gateway && nhi.if_index == 0) return 0; @@ -272,7 +235,8 @@ static int netlink_route_info_fill (netlink_route_info_t *ri, int cmd, rib_dest_t *dest, struct rib *rib) { - struct nexthop *nexthop = NULL; + struct nexthop *nexthop, *tnexthop; + int recursing; int discard; memset (ri, 0, sizeof (*ri)); @@ -321,35 +285,20 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd, goto skip; } - /* Multipath case. */ - if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - { + if (MULTIPATH_NUM != 0 && ri->num_nhs >= MULTIPATH_NUM) + break; - if ((cmd == RTM_NEWROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - || (cmd == RTM_DELROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) - { - netlink_route_info_add_nh (ri, nexthop); - break; - } - } - } - else - { - for (nexthop = rib->nexthop; - nexthop && (MULTIPATH_NUM == 0 || ri->num_nhs < MULTIPATH_NUM); - nexthop = nexthop->next) + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { - if ((cmd == RTM_NEWROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - || (cmd == RTM_DELROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) - { - netlink_route_info_add_nh (ri, nexthop); - } + netlink_route_info_add_nh (ri, nexthop, recursing); } } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 4dd8551a2..e39976ee5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -202,20 +202,26 @@ nexthop_type_to_str (enum nexthop_types_t 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 -nexthop_add (struct rib *rib, struct nexthop *nexthop) +_nexthop_add (struct nexthop **target, struct nexthop *nexthop) { struct nexthop *last; - for (last = rib->nexthop; last && last->next; last = last->next) + for (last = *target; last && last->next; last = last->next) ; if (last) last->next = nexthop; else - rib->nexthop = nexthop; + *target = nexthop; 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++; } @@ -232,15 +238,32 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop) rib->nexthop_num--; } +static void nexthops_free(struct nexthop *nexthop); + /* Free nexthop. */ static void nexthop_free (struct nexthop *nexthop) { if (nexthop->ifname) XFREE (0, nexthop->ifname); + if (nexthop->resolved) + nexthops_free(nexthop->resolved); 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 * nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) { @@ -365,6 +388,24 @@ nexthop_blackhole_add (struct rib *rib) 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 the route from FIB. */ static int @@ -375,13 +416,19 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, struct route_table *table; struct route_node *rn; struct rib *match; + int resolved; struct nexthop *newhop; + struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = 0; 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. */ 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)) { + resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -443,18 +491,25 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { 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 || 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 || newhop->type == NEXTHOP_TYPE_IFNAME || 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 { @@ -476,13 +531,19 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct route_table *table; struct route_node *rn; struct rib *match; + int resolved; struct nexthop *newhop; + struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = 0; 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. */ 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)) { + resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -545,20 +607,27 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { 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 || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || 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 || newhop->type == NEXTHOP_TYPE_IFNAME || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || 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 { @@ -577,7 +646,8 @@ rib_match_ipv4 (struct in_addr addr) struct route_table *table; struct route_node *rn; struct rib *match; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; + int recursing; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); @@ -622,7 +692,7 @@ rib_match_ipv4 (struct in_addr addr) return match; 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)) return match; return NULL; @@ -638,7 +708,8 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) struct route_table *table; struct route_node *rn; struct rib *match; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; /* Lookup table. */ 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) 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)) return match; @@ -693,7 +764,9 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) struct route_table *table; struct route_node *rn; struct rib *match; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; + int nexthops_active; /* Lookup table. */ 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; /* 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)) - { - /* 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) - { - char gate_buf[INET_ADDRSTRLEN], rgate_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->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); - inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN); - zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); - } - return ZEBRA_RIB_FOUND_NOGATE; + { + 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, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN); + zlog_debug ("%s: qgate == %s, %s == %s", __func__, + qgate_buf, recursing ? "rgate" : "gate", gate_buf); + } } - } + + if (nexthops_active) + return ZEBRA_RIB_FOUND_NOGATE; return ZEBRA_RIB_NOTFOUND; } @@ -759,7 +831,8 @@ rib_match_ipv6 (struct in6_addr *addr) struct route_table *table; struct route_node *rn; struct rib *match; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; + int recursing; /* Lookup table. */ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); @@ -804,7 +877,7 @@ rib_match_ipv6 (struct in6_addr *addr) return match; 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)) return match; return NULL; @@ -966,7 +1039,8 @@ static void rib_install_kernel (struct route_node *rn, struct rib *rib) { 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 @@ -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 */ 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); } } @@ -998,7 +1072,8 @@ static int rib_uninstall_kernel (struct route_node *rn, struct rib *rib) { 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 @@ -1018,7 +1093,7 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) #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); return ret; @@ -1114,7 +1189,8 @@ rib_process (struct route_node *rn) struct rib *select = NULL; struct rib *del = NULL; int installed = 0; - struct nexthop *nexthop = NULL; + struct nexthop *nexthop = NULL, *tnexthop; + int recursing; char buf[INET6_ADDRSTRLEN]; assert (rn); @@ -1237,7 +1313,7 @@ rib_process (struct route_node *rn) 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)) { installed = 1; @@ -1626,7 +1702,6 @@ rib_addnode (struct route_node *rn, struct rib *rib) static void rib_unlink (struct route_node *rn, struct rib *rib) { - struct nexthop *nexthop, *next; char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; @@ -1652,11 +1727,7 @@ rib_unlink (struct route_node *rn, struct rib *rib) } /* free RIB and nexthops */ - for (nexthop = rib->nexthop; nexthop; nexthop = next) - { - next = nexthop->next; - nexthop_free (nexthop); - } + nexthops_free(rib->nexthop); 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) { - char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN]; - struct nexthop *nexthop; + char straddr[INET_ADDRSTRLEN]; + struct nexthop *nexthop, *tnexthop; + int recursing; - inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN); - zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen); + inet_ntop (AF_INET, &p->prefix, straddr, INET_ADDRSTRLEN); + zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr, p->prefixlen); zlog_debug ( "%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_fib_num ); - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - { - inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN); - inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN); - zlog_debug - ( - "%s: NH %s (%s) with flags %s%s%s", - func, - straddr1, - straddr2, - (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), - (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), - (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") - ); - } + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + { + inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr, INET_ADDRSTRLEN); + zlog_debug + ( + "%s: %s %s with flags %s%s%s", + func, + (recursing ? " NH" : "NH"), + straddr, + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") + ); + } 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 *fib = NULL; struct rib *same = NULL; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; @@ -2085,16 +2157,23 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, break; } /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || - IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) + else { - same = rib; - break; - } + if (gate == NULL) + { + 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 kernel. */ if (! same) @@ -2576,7 +2655,8 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct rib *rib; struct rib *fib = NULL; struct rib *same = NULL; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -2636,14 +2716,22 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, break; } /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || - IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)))) - { - same = rib; - break; - } + else + { + if (gate == NULL) + { + same = rib; + 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 diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index b3111b8e6..39c7e1bff 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -422,14 +422,10 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix, switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: + /* Interface routes can't match ip next-hop */ + return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: 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: p.family = AF_INET; p.prefix = nexthop->gate.ipv4; @@ -488,14 +484,10 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: + /* Interface routes can't match ip next-hop */ + return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: 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: p.family = AF_INET; p.prefix = nexthop->gate.ipv4; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a672d4222..e1da7df83 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -533,7 +533,8 @@ static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) { struct rib *rib; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; 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); } - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { char addrstr[32]; - vty_out (vty, " %c", - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); + vty_out (vty, " %c%s", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', + recursing ? " " : ""); switch (nexthop->type) { @@ -614,28 +616,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_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; - } - } + vty_out (vty, " (recursive)"); + switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -672,12 +654,13 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) static void 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; char buf[BUFSIZ]; /* Nexthop information. */ - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { 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", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', - len - 3, ' '); + len - 3 + (2 * recursing), ' '); 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"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_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; - } - } + vty_out (vty, " (recursive)"); + switch (nexthop->type) { 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[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[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)) { 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]++; } } @@ -1550,7 +1516,8 @@ static void vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) { struct rib *rib; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; char buf[BUFSIZ]; 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); } - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { - vty_out (vty, " %c", - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); + vty_out (vty, " %c%s", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', + recursing ? " " : ""); switch (nexthop->type) { @@ -1633,29 +1601,8 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_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, " (recursive)"); + 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, struct rib *rib) { - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; int len = 0; char buf[BUFSIZ]; /* Nexthop information. */ - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (nexthop == rib->nexthop) { @@ -1695,7 +1643,7 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn, vty_out (vty, " %c%*c", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', - len - 3, ' '); + len - 3 + (2 * recursing), ' '); switch (nexthop->type) { @@ -1724,29 +1672,7 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn, vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_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, " (recursive)"); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, ", bh"); diff --git a/zebra/zserv.c b/zebra/zserv.c index 118293780..5df521b0d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -389,7 +389,8 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, 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_IFINDEX); @@ -488,6 +489,9 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) num = 0; nump = stream_get_endp(s); 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) 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; nump = stream_get_endp(s); 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) 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); stream_putc (s, 0); 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); switch (nexthop->type) From 48a53dc71cb422e619859b79d5069e02fcd867d0 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 15:35:38 +0000 Subject: [PATCH 0279/1342] zebra: handle blackholes encountered in recursive resolution Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index e39976ee5..301e0cc1d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -472,6 +472,12 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, } else { + /* If the longest prefix match for the nexthop yields + * a blackhole, mark it as inactive. */ + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE) + || CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT)) + return 0; + if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ @@ -587,6 +593,12 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } else { + /* If the longest prefix match for the nexthop yields + * a blackhole, mark it as inactive. */ + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE) + || CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT)) + return 0; + if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ From e8d3d2991f72613edb76dea244a8c8e4684873dd Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 15:35:39 +0000 Subject: [PATCH 0280/1342] zebra: implement NEXTHOP_FLAG_ONLINK On Linux, the kernel will only allow for a route to be installed when its gateway is directly attached according the kernel fib. There are cases when this restriction by the kernel is too strong, in those cases, we deploy the RTNH_F_ONLINK netlink flag. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/rib.h | 1 + zebra/rt_netlink.c | 9 ++++++++- zebra/zebra_vty.c | 9 +++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/zebra/rib.h b/zebra/rib.h index 4d98e0595..1c548795e 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -253,6 +253,7 @@ struct nexthop #define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ #define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ #define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ +#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */ /* Nexthop address */ union g_addr gate; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b0ade0588..7a820bfd1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1443,8 +1443,11 @@ _netlink_route_build_singlepath( int bytelen, struct nexthop *nexthop, struct nlmsghdr *nlmsg, + struct rtmsg *rtmsg, size_t req_size) { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + rtmsg->rtm_flags |= RTNH_F_ONLINK; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { @@ -1534,6 +1537,9 @@ _netlink_route_build_multipath( rtnh->rtnh_hops = 0; rta->rta_len += rtnh->rtnh_len; + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + rtnh->rtnh_flags |= RTNH_F_ONLINK; + if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { @@ -1733,7 +1739,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, _netlink_route_debug(cmd, p, nexthop, routedesc, family); _netlink_route_build_singlepath(routedesc, bytelen, - nexthop, &req.n, sizeof req); + nexthop, &req.n, &req.r, + sizeof req); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e1da7df83..45928e930 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -615,6 +615,9 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out (vty, " onlink"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out (vty, " (recursive)"); @@ -710,6 +713,9 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out (vty, " onlink"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out (vty, " (recursive)"); @@ -1600,6 +1606,9 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out (vty, " onlink"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out (vty, " (recursive)"); From c3e6b595160cd3aa601ae7e1887e695710cde15d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 15:35:40 +0000 Subject: [PATCH 0281/1342] zebra: fix recursive-routes via ifindex routes Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 65 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 301e0cc1d..3106523d0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -500,16 +500,37 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, 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 || - newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - resolved_hop->gate.ipv4 = newhop->gate.ipv4; - + /* If the resolving route specifies a gateway, use it */ + if (newhop->type == NEXTHOP_TYPE_IPV4 + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME) + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv4 = newhop->gate.ipv4; + + if (newhop->ifindex) + { + resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + resolved_hop->ifindex = newhop->ifindex; + } + } + + /* If the resolving route is an interface route, + * it means the gateway we are looking up is connected + * to that interface. (The actual network is _not_ onlink). + * Therefore, the resolved route should have the original + * gateway as nexthop as it is directly connected. + * + * On Linux, we have to set the onlink netlink flag because + * otherwise, the kernel won't accept the route. */ if (newhop->type == NEXTHOP_TYPE_IFINDEX - || newhop->type == NEXTHOP_TYPE_IFNAME - || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - resolved_hop->ifindex = newhop->ifindex; + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + resolved_hop->gate.ipv4 = nexthop->gate.ipv4; + resolved_hop->ifindex = newhop->ifindex; + } _nexthop_add(&nexthop->resolved, resolved_hop); } @@ -622,18 +643,30 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); - - resolved_hop->type = newhop->type; + /* See nexthop_active_ipv4 for a description how the + * resolved nexthop is constructed. */ if (newhop->type == NEXTHOP_TYPE_IPV6 || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) - resolved_hop->gate.ipv6 = newhop->gate.ipv6; + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv6 = newhop->gate.ipv6; + + if (newhop->ifindex) + { + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->ifindex = newhop->ifindex; + } + } if (newhop->type == NEXTHOP_TYPE_IFINDEX - || newhop->type == NEXTHOP_TYPE_IFNAME - || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX - || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) - resolved_hop->ifindex = newhop->ifindex; + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->gate.ipv6 = nexthop->gate.ipv6; + resolved_hop->ifindex = newhop->ifindex; + } _nexthop_add(&nexthop->resolved, resolved_hop); } From f3a1732eb3bb41c094ec558d2aeee2766878a91d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 5 Jul 2013 15:35:41 +0000 Subject: [PATCH 0282/1342] zebra: apply route-maps for interface routes Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 3106523d0..ace69cacb 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -950,6 +950,7 @@ static unsigned nexthop_active_check (struct route_node *rn, struct rib *rib, struct nexthop *nexthop, int set) { + rib_table_info_t *info = rn->table->info; struct interface *ifp; route_map_result_t ret = RMAP_MATCH; extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; @@ -1027,11 +1028,22 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) return 0; + /* XXX: What exactly do those checks do? Do we support + * e.g. IPv4 routes with IPv6 nexthops or vice versa? */ if (RIB_SYSTEM_ROUTE(rib) || (family == AFI_IP && rn->p.family != AF_INET) || (family == AFI_IP6 && rn->p.family != AF_INET6)) return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + /* The original code didn't determine the family correctly + * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi + * from the rib_table_info in those cases. + * Possibly it may be better to use only the rib_table_info + * in every case. + */ + if (!family) + family = info->afi; + rmap = 0; if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && proto_rm[family][rib->type]) From fed643f4093abc0ed5e796aab9047768f7036ed6 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 23 Oct 2012 16:00:42 +0000 Subject: [PATCH 0283/1342] zebra: make rib_dump() compatible with IPv6 RIB [DL: resolved conflicts in zebra_rib.c] [DL: fix usage with --disable-ipv6] Signed-off-by: David Lamparter --- zebra/rib.h | 2 +- zebra/zebra_rib.c | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 1c548795e..97a20af30 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -386,7 +386,7 @@ extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (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 *, const struct rib *); extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *); #define ZEBRA_RIB_LOOKUP_ERROR -1 #define ZEBRA_RIB_FOUND_EXACT 0 diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ace69cacb..77c0d8ca7 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1912,13 +1912,13 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, * question are passed as 1st and 2nd arguments. */ -void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib) +void rib_dump (const char * func, const struct prefix * p, const struct rib * rib) { - char straddr[INET_ADDRSTRLEN]; + char straddr[INET6_ADDRSTRLEN]; struct nexthop *nexthop, *tnexthop; int recursing; - inet_ntop (AF_INET, &p->prefix, straddr, INET_ADDRSTRLEN); + inet_ntop (p->family, &p->u.prefix, straddr, INET6_ADDRSTRLEN); zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr, p->prefixlen); zlog_debug ( @@ -1946,9 +1946,10 @@ void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib rib->nexthop_active_num, rib->nexthop_fib_num ); + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { - inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr, INET_ADDRSTRLEN); + inet_ntop (p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN); zlog_debug ( "%s: %s %s with flags %s%s%s", @@ -2008,7 +2009,7 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") ); - rib_dump (__func__, p, rib); + rib_dump (__func__, (struct prefix *) p, rib); } } @@ -2055,7 +2056,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) char buf[INET_ADDRSTRLEN]; inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); - rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib); + rib_dump (__func__, &rn->p, rib); } rib_uninstall (rn, rib); } @@ -2117,7 +2118,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", __func__, rn, rib); - rib_dump (__func__, p, rib); + rib_dump (__func__, (struct prefix *) p, rib); } /* Free implicit route.*/ @@ -2127,7 +2128,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", __func__, rn, same); - rib_dump (__func__, p, same); + rib_dump (__func__, (struct prefix *) p, same); } rib_delnode (rn, same); } @@ -2693,10 +2694,24 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* Link new rib to node.*/ rib_addnode (rn, rib); + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", + __func__, rn, rib); + rib_dump (__func__, (struct prefix *) p, rib); + } /* Free implicit route.*/ if (same) + { + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", + __func__, rn, same); + rib_dump (__func__, (struct prefix *) p, same); + } rib_delnode (rn, same); + } route_unlock_node (rn); return 0; From a83a1e9c2f035d3152451dcfc97ab13b4ac427b9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 22 Oct 2013 11:35:48 -0700 Subject: [PATCH 0284/1342] build: fix tests/prng.h missing from dist broken by fa713d9... "zebra: rework recursive route resolution", and I forgot to squash the fix into that. Signed-off-by: David Lamparter --- tests/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index e5c7fd79d..9260a900b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -28,6 +28,8 @@ check_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ $(TESTS_BGPD) +noinst_HEADERS = prng.h + testsig_SOURCES = test-sig.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c From 8551e6dadce41fb87a61767af723cb25ae611a04 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Tue, 22 Oct 2013 17:42:18 -0700 Subject: [PATCH 0285/1342] ospf6d/ospfd: refactor some common defines Rearranging common defs and structures for use betweeen OSPFv2 and OSPFv3. Created a new file called libospf.h under lib directory to hold defines that are common between OSPFv2 and OSPFv3 code bases. [DL: split of defines refactor from timer refactor] Signed-off-by: David Lamparter --- lib/Makefile.am | 2 +- lib/libospf.h | 82 ++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_abr.c | 6 +-- ospf6d/ospf6_area.c | 1 + ospf6d/ospf6_area.h | 2 - ospf6d/ospf6_asbr.c | 4 +- ospf6d/ospf6_flood.c | 8 ++-- ospf6d/ospf6_interface.c | 6 +-- ospf6d/ospf6_lsa.c | 32 ++++++++-------- ospf6d/ospf6_lsa.h | 2 +- ospf6d/ospf6_lsdb.c | 2 +- ospf6d/ospf6_message.c | 2 +- ospf6d/ospf6_network.c | 1 + ospf6d/ospf6_proto.h | 21 ---------- ospf6d/ospf6d.h | 3 ++ ospfd/ospfd.h | 53 +------------------------- 16 files changed, 120 insertions(+), 107 deletions(-) create mode 100644 lib/libospf.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 44d95bbee..bd2109292 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -27,7 +27,7 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h + workqueue.h route_types.h libospf.h EXTRA_DIST = \ regex.c regex-gnu.h \ diff --git a/lib/libospf.h b/lib/libospf.h new file mode 100644 index 000000000..2282c0729 --- /dev/null +++ b/lib/libospf.h @@ -0,0 +1,82 @@ +/* + * Defines and structures common to OSPFv2 and OSPFv3 + * Copyright (C) 1998, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _LIBOSPFD_H +#define _LIBOSPFD_H + +/* IP precedence. */ +#ifndef IPTOS_PREC_INTERNETCONTROL +#define IPTOS_PREC_INTERNETCONTROL 0xC0 +#endif /* IPTOS_PREC_INTERNETCONTROL */ + +/* Default protocol, port number. */ +#ifndef IPPROTO_OSPFIGP +#define IPPROTO_OSPFIGP 89 +#endif /* IPPROTO_OSPFIGP */ + +/* Architectual Constants */ +#ifdef DEBUG +#define OSPF_LS_REFRESH_TIME 60 +#else +#define OSPF_LS_REFRESH_TIME 1800 +#endif +#define OSPF_MIN_LS_INTERVAL 5 +#define OSPF_MIN_LS_ARRIVAL 1 +#define OSPF_LSA_INITIAL_AGE 0 /* useful for debug */ +#define OSPF_LSA_MAXAGE 3600 +#define OSPF_CHECK_AGE 300 +#define OSPF_LSA_MAXAGE_DIFF 900 +#define OSPF_LS_INFINITY 0xffffff +#define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */ +#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001 +#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff + +/* OSPF interface default values. */ +#define OSPF_OUTPUT_COST_DEFAULT 10 +#define OSPF_OUTPUT_COST_INFINITE UINT16_MAX +#define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT 40 +#define OSPF_ROUTER_DEAD_INTERVAL_MINIMAL 1 +#define OSPF_HELLO_INTERVAL_DEFAULT 10 +#define OSPF_ROUTER_PRIORITY_DEFAULT 1 +#define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_TRANSMIT_DELAY_DEFAULT 1 +#define OSPF_DEFAULT_BANDWIDTH 10000 /* Kbps */ + +#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ + +#define OSPF_POLL_INTERVAL_DEFAULT 60 +#define OSPF_NEIGHBOR_PRIORITY_DEFAULT 0 + +#define OSPF_MTU_IGNORE_DEFAULT 0 +#define OSPF_FAST_HELLO_DEFAULT 0 + +#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ + +/* SPF Throttling timer values. */ +#define OSPF_SPF_DELAY_DEFAULT 200 +#define OSPF_SPF_HOLDTIME_DEFAULT 1000 +#define OSPF_SPF_MAX_HOLDTIME_DEFAULT 10000 + +#define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 +#define OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 + +#endif /* _LIBOSPFD_H */ diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index c3a63fe60..3277e7d88 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -253,7 +253,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, } /* do not generate if the route cost is greater or equal to LSInfinity */ - if (route->path.cost >= LS_INFINITY) + if (route->path.cost >= OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("The cost exceeds LSInfinity, withdraw"); @@ -296,7 +296,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, /* ranges are ignored when originate backbone routes to transit area. Otherwise, if ranges are configured, the route is suppressed. */ if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) && - (route->path.area_id != BACKBONE_AREA_ID || + (route->path.area_id != OSPF_AREA_BACKBONE || ! IS_AREA_TRANSIT (area))) { if (is_debug) @@ -604,7 +604,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) } /* (1) if cost == LSInfinity or if the LSA is MaxAge */ - if (cost == LS_INFINITY) + if (cost == OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("cost is LS_INFINITY, ignore"); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 9934e6b9c..2d20e6251 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -401,6 +401,7 @@ DEFUN (no_area_range, } ospf6_route_remove (range, oa->range_table); + return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index e8a4fbd87..655967a9a 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -105,8 +105,6 @@ struct ospf6_area #define OSPF6_AREA_TRANSIT 0x04 /* TransitCapability */ #define OSPF6_AREA_STUB 0x08 -#define BACKBONE_AREA_ID (htonl (0)) -#define IS_AREA_BACKBONE(oa) ((oa)->area_id == BACKBONE_AREA_ID) #define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE)) #define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE)) #define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT)) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index ae0a286d5..1a0634ed2 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -174,7 +174,7 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) return; } - if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) + if (OSPF6_ASBR_METRIC (external) == OSPF_LS_INFINITY) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with LSInfinity Metric"); @@ -890,7 +890,7 @@ ospf6_routemap_rule_set_metric_compile (const char *arg) u_int32_t metric; char *endp; metric = strtoul (arg, &endp, 0); - if (metric > LS_INFINITY || *endp != '\0') + if (metric > OSPF_LS_INFINITY || *endp != '\0') return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index b81597290..3a9af01d9 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -113,7 +113,7 @@ ospf6_lsa_originate (struct ospf6_lsa *lsa) ospf6_lsdb_add (ospf6_lsa_copy (lsa), lsdb_self); lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa, - LS_REFRESH_TIME); + OSPF_LS_REFRESH_TIME); if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type)) @@ -228,7 +228,7 @@ ospf6_install_lsa (struct ospf6_lsa *lsa) quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (! OSPF6_LSA_IS_MAXAGE (lsa)) lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa, - MAXAGE + lsa->birth.tv_sec - now.tv_sec); + OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec); else lsa->expire = NULL; @@ -837,7 +837,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, struct timeval now, res; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &old->installed, &res); - if (res.tv_sec < MIN_LS_ARRIVAL) + if (res.tv_sec < OSPF_MIN_LS_ARRIVAL) { if (is_debug) zlog_debug ("LSA can't be updated within MinLSArrival, discard"); @@ -944,7 +944,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, /* If database copy is in 'Seqnumber Wrapping', simply discard the received LSA */ if (OSPF6_LSA_IS_MAXAGE (old) && - old->header->seqnum == htonl (MAX_SEQUENCE_NUMBER)) + old->header->seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER)) { if (is_debug) { diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 40cda2460..467479b1c 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -112,9 +112,9 @@ ospf6_interface_create (struct interface *ifp) oi->transdelay = OSPF6_INTERFACE_TRANSDELAY; oi->priority = OSPF6_INTERFACE_PRIORITY; - oi->hello_interval = OSPF6_INTERFACE_HELLO_INTERVAL; - oi->dead_interval = OSPF6_INTERFACE_DEAD_INTERVAL; - oi->rxmt_interval = OSPF6_INTERFACE_RXMT_INTERVAL; + oi->hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; + oi->dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + oi->rxmt_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; oi->cost = OSPF6_INTERFACE_COST; oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index ff061dfb1..7dbd303f6 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -139,11 +139,11 @@ ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, ospf6_lsa_age_current (lsa1); ospf6_lsa_age_current (lsa2); - if (ntohs (lsa1->header->age) == MAXAGE && - ntohs (lsa2->header->age) != MAXAGE) + if (ntohs (lsa1->header->age) == OSPF_LSA_MAXAGE && + ntohs (lsa2->header->age) != OSPF_LSA_MAXAGE) return 1; - if (ntohs (lsa1->header->age) != MAXAGE && - ntohs (lsa2->header->age) == MAXAGE) + if (ntohs (lsa1->header->age) != OSPF_LSA_MAXAGE && + ntohs (lsa2->header->age) == OSPF_LSA_MAXAGE) return 1; /* compare body */ @@ -218,19 +218,19 @@ ospf6_lsa_age_current (struct ospf6_lsa *lsa) zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", safe_strerror (errno)); - if (ntohs (lsa->header->age) >= MAXAGE) + if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE) { /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using relative time, we cannot compare against lsa birth time, so we catch this special case here. */ - lsa->header->age = htons (MAXAGE); - return MAXAGE; + lsa->header->age = htons (OSPF_LSA_MAXAGE); + return OSPF_LSA_MAXAGE; } /* calculate age */ ulage = now.tv_sec - lsa->birth.tv_sec; /* if over MAXAGE, set to it */ - age = (ulage > MAXAGE ? MAXAGE : ulage); + age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : ulage); lsa->header->age = htons (age); return age; @@ -243,8 +243,8 @@ ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) unsigned short age; age = ospf6_lsa_age_current (lsa) + transdelay; - if (age > MAXAGE) - age = MAXAGE; + if (age > OSPF_LSA_MAXAGE) + age = OSPF_LSA_MAXAGE; lsa->header->age = htons (age); } @@ -258,7 +258,7 @@ ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) THREAD_OFF (lsa->expire); THREAD_OFF (lsa->refresh); - lsa->header->age = htons (MAXAGE); + lsa->header->age = htons (OSPF_LSA_MAXAGE); thread_execute (master, ospf6_lsa_expire, lsa, 0); } @@ -297,15 +297,15 @@ ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) ageb = ospf6_lsa_age_current (b); /* MaxAge check */ - if (agea == MAXAGE && ageb != MAXAGE) + if (agea == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE) return -1; - else if (agea != MAXAGE && ageb == MAXAGE) + else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE) return 1; /* Age check */ - if (agea > ageb && agea - ageb >= MAX_AGE_DIFF) + if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF) return 1; - else if (agea < ageb && ageb - agea >= MAX_AGE_DIFF) + else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_DIFF) return -1; /* neither recent */ @@ -653,7 +653,7 @@ ospf6_lsa_refresh (struct thread *thread) new = ospf6_lsa_create (self->header); new->lsdb = old->lsdb; new->refresh = thread_add_timer (master, ospf6_lsa_refresh, new, - LS_REFRESH_TIME); + OSPF_LS_REFRESH_TIME); /* store it in the LSDB for self-originated LSAs */ ospf6_lsdb_add (ospf6_lsa_copy (new), lsdb_self); diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 263411fc7..f10ee671b 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -107,7 +107,7 @@ struct ospf6_lsa_header ((L)->header->adv_router == (a) && (L)->header->id == (i) && \ (L)->header->type == (t)) #define OSPF6_LSA_IS_DIFFER(L1, L2) ospf6_lsa_is_differ (L1, L2) -#define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == MAXAGE) +#define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == OSPF_LSA_MAXAGE) #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) struct ospf6_lsa diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 280bdf957..7455d8353 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -572,7 +572,7 @@ ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, /* if current database copy not found, return InitialSequenceNumber */ lsa = ospf6_lsdb_lookup (type, id, adv_router, lsdb); if (lsa == NULL) - seqnum = INITIAL_SEQUENCE_NUMBER; + seqnum = OSPF_INITIAL_SEQUENCE_NUMBER; else seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 5edb70ce6..b35aa1ac2 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1282,7 +1282,7 @@ ospf6_rxpacket_examin (struct ospf6_interface *oi, struct ospf6_header *oh, cons { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) { - if (oh->area_id == BACKBONE_AREA_ID) + if (oh->area_id == OSPF_AREA_BACKBONE) zlog_debug ("%s: Message may be via Virtual Link: not supported", __func__); else zlog_debug diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index e5a1436c6..eed7f9d66 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -27,6 +27,7 @@ #include "sockopt.h" #include "privs.h" +#include "libospf.h" #include "ospf6_proto.h" #include "ospf6_network.h" diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index 646250047..af60eb922 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -26,33 +26,12 @@ /* OSPF protocol version */ #define OSPFV3_VERSION 3 -/* OSPF protocol number. */ -#ifndef IPPROTO_OSPFIGP -#define IPPROTO_OSPFIGP 89 -#endif - /* TOS field normaly null */ #define DEFAULT_TOS_VALUE 0x0 -/* Architectural Constants */ -#define LS_REFRESH_TIME 1800 /* 30 min */ -#define MIN_LS_INTERVAL 5 -#define MIN_LS_ARRIVAL 1 -#define MAXAGE 3600 /* 1 hour */ -#define CHECK_AGE 300 /* 5 min */ -#define MAX_AGE_DIFF 900 /* 15 min */ -#define LS_INFINITY 0xffffff /* 24-bit binary value */ -#define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */ -#define MAX_SEQUENCE_NUMBER 0x7fffffff /* signed 32-bit integer */ - #define ALLSPFROUTERS6 "ff02::5" #define ALLDROUTERS6 "ff02::6" -/* Configurable Constants */ - -#define DEFAULT_HELLO_INTERVAL 10 -#define DEFAULT_ROUTER_DEAD_INTERVAL 40 - #define OSPF6_ROUTER_BIT_W (1 << 3) #define OSPF6_ROUTER_BIT_V (1 << 2) #define OSPF6_ROUTER_BIT_E (1 << 1) diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 2ac6300e5..13699d612 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -24,6 +24,9 @@ #define OSPF6_DAEMON_VERSION "0.9.7r" +#include "libospf.h" +#include "thread.h" + /* global variables */ extern struct thread_master *master; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index fb57bf514..fe9d77e9b 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -24,22 +24,13 @@ #define _ZEBRA_OSPFD_H #include +#include "libospf.h" #include "filter.h" #include "log.h" #define OSPF_VERSION 2 -/* Default protocol, port number. */ -#ifndef IPPROTO_OSPFIGP -#define IPPROTO_OSPFIGP 89 -#endif /* IPPROTO_OSPFIGP */ - -/* IP precedence. */ -#ifndef IPTOS_PREC_INTERNETCONTROL -#define IPTOS_PREC_INTERNETCONTROL 0xC0 -#endif /* IPTOS_PREC_INTERNETCONTROL */ - /* VTY port number. */ #define OSPF_VTY_PORT 2604 @@ -50,29 +41,11 @@ /* Default configuration file name for ospfd. */ #define OSPF_DEFAULT_CONFIG "ospfd.conf" -/* Architectual Constants */ -#ifdef DEBUG -#define OSPF_LS_REFRESH_TIME 60 -#else -#define OSPF_LS_REFRESH_TIME 1800 -#endif -#define OSPF_MIN_LS_INTERVAL 5 -#define OSPF_MIN_LS_ARRIVAL 1 -#define OSPF_LSA_INITIAL_AGE 0 /* useful for debug */ -#define OSPF_LSA_MAXAGE 3600 -#define OSPF_CHECK_AGE 300 -#define OSPF_LSA_MAXAGE_DIFF 900 -#define OSPF_LS_INFINITY 0xffffff -#define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */ -#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001 -#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff - #define OSPF_NSSA_TRANS_STABLE_DEFAULT 40 #define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ #define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ -#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ /* OSPF Authentication Type. */ #define OSPF_AUTH_NULL 0 @@ -85,30 +58,6 @@ been given or not in VLink command handlers */ #define OSPF_AUTH_CMD_NOTSEEN -2 -/* OSPF SPF timer values. */ -#define OSPF_SPF_DELAY_DEFAULT 200 -#define OSPF_SPF_HOLDTIME_DEFAULT 1000 -#define OSPF_SPF_MAX_HOLDTIME_DEFAULT 10000 - -/* OSPF interface default values. */ -#define OSPF_OUTPUT_COST_DEFAULT 10 -#define OSPF_OUTPUT_COST_INFINITE UINT16_MAX -#define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT 40 -#define OSPF_ROUTER_DEAD_INTERVAL_MINIMAL 1 -#define OSPF_HELLO_INTERVAL_DEFAULT 10 -#define OSPF_ROUTER_PRIORITY_DEFAULT 1 -#define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 -#define OSPF_TRANSMIT_DELAY_DEFAULT 1 -#define OSPF_DEFAULT_BANDWIDTH 10000 /* Kbps */ - -#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ - -#define OSPF_POLL_INTERVAL_DEFAULT 60 -#define OSPF_NEIGHBOR_PRIORITY_DEFAULT 0 - -#define OSPF_MTU_IGNORE_DEFAULT 0 -#define OSPF_FAST_HELLO_DEFAULT 0 - /* OSPF options. */ #define OSPF_OPTION_T 0x01 /* TOS. */ #define OSPF_OPTION_E 0x02 From 3810e06eebe14f75c66fb17a88574384573e95fa Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:54:09 +0000 Subject: [PATCH 0286/1342] ospf6d: schedule SPF to run on events rather than directly on each event. OSPV3 SPF triggers on every SPF-able event instead of using timers the way OSPFv2 does. This patch makes SPF be triggered/throttled similar to OSPFv2. It adds a command to quagga identical to the OSPFv2 equivalent to configure these timers. Summary: Signed-off-by: Dinesh Dutt Reviewed-by: Scott Feldman [DL: removed reference to oa->ts_spf for rebase] [DL: killed timeval_subtract] Signed-off-by: David Lamparter --- doc/ospf6d.texi | 38 ++++++++ ospf6d/ospf6_area.c | 4 +- ospf6d/ospf6_interface.c | 12 ++- ospf6d/ospf6_spf.c | 189 +++++++++++++++++++++++++++++++++++---- ospf6d/ospf6_spf.h | 5 +- ospf6d/ospf6_top.c | 7 ++ ospf6d/ospf6_top.h | 13 +++ 7 files changed, 245 insertions(+), 23 deletions(-) diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi index 6667221cf..c01c0510d 100644 --- a/doc/ospf6d.texi +++ b/doc/ospf6d.texi @@ -28,6 +28,44 @@ Bind interface to specified area, and start sending OSPF packets. @var{area} ca be specified as 0. @end deffn +@deffn {OSPF6 Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {} +@deffnx {OSPF6 Command} {no timers throttle spf} {} +This command sets the initial @var{delay}, the @var{initial-holdtime} +and the @var{maximum-holdtime} between when SPF is calculated and the +event which triggered the calculation. The times are specified in +milliseconds and must be in the range of 0 to 600000 milliseconds. + +The @var{delay} specifies the minimum amount of time to delay SPF +calculation (hence it affects how long SPF calculation is delayed after +an event which occurs outside of the holdtime of any previous SPF +calculation, and also serves as a minimum holdtime). + +Consecutive SPF calculations will always be seperated by at least +'hold-time' milliseconds. The hold-time is adaptive and initially is +set to the @var{initial-holdtime} configured with the above command. +Events which occur within the holdtime of the previous SPF calculation +will cause the holdtime to be increased by @var{initial-holdtime}, bounded +by the @var{maximum-holdtime} configured with this command. If the adaptive +hold-time elapses without any SPF-triggering event occuring then +the current holdtime is reset to the @var{initial-holdtime}. + +@example +@group +router ospf6 + timers throttle spf 200 400 10000 +@end group +@end example + +In this example, the @var{delay} is set to 200ms, the @var{initial +holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence +there will always be at least 200ms between an event which requires SPF +calculation and the actual SPF calculation. Further consecutive SPF +calculations will always be seperated by between 400ms to 10s, the +hold-time increasing by 400ms each time an SPF-triggering event occurs +within the hold-time of the previous SPF calculation. + +@end deffn + @node OSPF6 area @section OSPF6 area diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 2d20e6251..1e07d8579 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -67,7 +67,7 @@ ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa) zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } - ospf6_spf_schedule (OSPF6_AREA (lsa->lsdb->data)); + ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6)); break; case OSPF6_LSTYPE_INTRA_PREFIX: @@ -97,7 +97,7 @@ ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa) zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } - ospf6_spf_schedule (OSPF6_AREA (lsa->lsdb->data)); + ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6)); break; case OSPF6_LSTYPE_INTRA_PREFIX: diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 467479b1c..7c45fe46a 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -75,12 +75,18 @@ ospf6_interface_lookup_by_ifindex (int ifindex) static void ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) { + struct ospf6_interface *oi; + + if (lsa == NULL) + return; + + oi = lsa->lsdb->data; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_LINK: - if (OSPF6_INTERFACE (lsa->lsdb->data)->state == OSPF6_INTERFACE_DR) - OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (OSPF6_INTERFACE (lsa->lsdb->data)); - ospf6_spf_schedule (OSPF6_INTERFACE (lsa->lsdb->data)->area); + if (oi->state == OSPF6_INTERFACE_DR) + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + ospf6_spf_schedule (oi->area->ospf6); break; default: diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index da0ee131b..e4c424dbb 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -506,39 +506,128 @@ static int ospf6_spf_calculation_thread (struct thread *t) { struct ospf6_area *oa; + struct ospf6 *ospf6; struct timeval start, end, runtime; + struct listnode *node; + struct ospf6_route *route; - oa = (struct ospf6_area *) THREAD_ARG (t); - oa->thread_spf_calculation = NULL; - - if (IS_OSPF6_DEBUG_SPF (PROCESS)) - zlog_debug ("SPF calculation for Area %s", oa->name); - if (IS_OSPF6_DEBUG_SPF (DATABASE)) - ospf6_spf_log_database (oa); + ospf6 = (struct ospf6 *)THREAD_ARG (t); + ospf6->t_spf_calc = NULL; /* execute SPF calculation */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &start); - ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa); + + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) + { + + if (oa == ospf6->backbone) + continue; + + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_debug ("SPF calculation for Area %s", oa->name); + if (IS_OSPF6_DEBUG_SPF (DATABASE)) + ospf6_spf_log_database (oa); + + ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa); + ospf6_intra_route_calculation (oa); + ospf6_intra_brouter_calculation (oa); + } + + if (ospf6->backbone) + { + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_debug ("SPF calculation for Backbone area %s", + ospf6->backbone->name); + if (IS_OSPF6_DEBUG_SPF (DATABASE)) + ospf6_spf_log_database(ospf6->backbone); + + ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table, + ospf6->backbone); + ospf6_intra_route_calculation(ospf6->backbone); + ospf6_intra_brouter_calculation(ospf6->backbone); + } + + /* Redo summaries if required */ + for (route = ospf6_route_head (ospf6->route_table); route; + route = ospf6_route_next (route)) + ospf6_abr_originate_summary(route); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &end); timersub (&end, &start, &runtime); + ospf6->ts_spf_duration = runtime; + if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF runtime: %ld sec %ld usec", runtime.tv_sec, runtime.tv_usec); - ospf6_intra_route_calculation (oa); - ospf6_intra_brouter_calculation (oa); - return 0; } +/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we + set timer for SPF calc. */ void -ospf6_spf_schedule (struct ospf6_area *oa) +ospf6_spf_schedule (struct ospf6 *ospf6) { - if (oa->thread_spf_calculation) + unsigned long delay, elapsed, ht; + struct timeval now, result; + + if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) + zlog_debug ("SPF: calculation timer scheduled"); + + /* OSPF instance does not exist. */ + if (ospf6 == NULL) return; - oa->thread_spf_calculation = - thread_add_event (master, ospf6_spf_calculation_thread, oa, 0); + + /* SPF calculation timer is already scheduled. */ + if (ospf6->t_spf_calc) + { + if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) + zlog_debug ("SPF: calculation timer is already scheduled: %p", + ospf6->t_spf_calc); + return; + } + + /* XXX Monotic timers: we only care about relative time here. */ + now = recent_relative_time (); + timersub (&now, &ospf6->ts_spf, &result); + + elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000); + ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier; + + if (ht > ospf6->spf_max_holdtime) + ht = ospf6->spf_max_holdtime; + + /* Get SPF calculation delay time. */ + if (elapsed < ht) + { + /* Got an event within the hold time of last SPF. We need to + * increase the hold_multiplier, if it's not already at/past + * maximum value, and wasn't already increased.. + */ + if (ht < ospf6->spf_max_holdtime) + ospf6->spf_hold_multiplier++; + + /* always honour the SPF initial delay */ + if ( (ht - elapsed) < ospf6->spf_delay) + delay = ospf6->spf_delay; + else + delay = ht - elapsed; + } + else + { + /* Event is past required hold-time of last SPF */ + delay = ospf6->spf_delay; + ospf6->spf_hold_multiplier = 1; + } + + if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) + zlog_debug ("SPF: calculation timer delay = %ld", delay); + + zlog_info ("SPF: Scheduled in %ld msec", delay); + + ospf6->t_spf_calc = + thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay); } void @@ -666,6 +755,59 @@ DEFUN (no_debug_ospf6_spf_database, return CMD_SUCCESS; } +static int +ospf6_timers_spf_set (struct vty *vty, unsigned int delay, + unsigned int hold, + unsigned int max) +{ + struct ospf6 *ospf = vty->index; + + ospf->spf_delay = delay; + ospf->spf_holdtime = hold; + ospf->spf_max_holdtime = max; + + return CMD_SUCCESS; +} + +DEFUN (ospf6_timers_throttle_spf, + ospf6_timers_throttle_spf_cmd, + "timers throttle spf <0-600000> <0-600000> <0-600000>", + "Adjust routing timers\n" + "Throttling adaptive timer\n" + "OSPF6 SPF timers\n" + "Delay (msec) from first change received till SPF calculation\n" + "Initial hold time (msec) between consecutive SPF calculations\n" + "Maximum hold time (msec)\n") +{ + unsigned int delay, hold, max; + + if (argc != 3) + { + vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000); + VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000); + VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000); + + return ospf6_timers_spf_set (vty, delay, hold, max); +} + +DEFUN (no_ospf6_timers_throttle_spf, + no_ospf6_timers_throttle_spf_cmd, + "no timers throttle spf", + NO_STR + "Adjust routing timers\n" + "Throttling adaptive timer\n" + "OSPF6 SPF timers\n") +{ + return ospf6_timers_spf_set (vty, + OSPF_SPF_DELAY_DEFAULT, + OSPF_SPF_HOLDTIME_DEFAULT, + OSPF_SPF_MAX_HOLDTIME_DEFAULT); +} + int config_write_ospf6_debug_spf (struct vty *vty) { @@ -678,6 +820,19 @@ config_write_ospf6_debug_spf (struct vty *vty) return 0; } +void +ospf6_spf_config_write (struct vty *vty) +{ + + if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT || + ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || + ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT) + vty_out (vty, " timers throttle spf %d %d %d%s", + ospf6->spf_delay, ospf6->spf_holdtime, + ospf6->spf_max_holdtime, VTY_NEWLINE); + +} + void install_element_ospf6_debug_spf (void) { @@ -698,6 +853,6 @@ install_element_ospf6_debug_spf (void) void ospf6_spf_init (void) { + install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd); + install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd); } - - diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index c7069c258..6c40424fd 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -22,6 +22,8 @@ #ifndef OSPF6_SPF_H #define OSPF6_SPF_H +#include "ospf6_top.h" + /* Debug option */ extern unsigned char conf_debug_ospf6_spf; #define OSPF6_DEBUG_SPF_PROCESS 0x01 @@ -81,11 +83,12 @@ extern void ospf6_spf_table_finish (struct ospf6_route_table *result_table); extern void ospf6_spf_calculation (u_int32_t router_id, struct ospf6_route_table *result_table, struct ospf6_area *oa); -extern void ospf6_spf_schedule (struct ospf6_area *oa); +extern void ospf6_spf_schedule (struct ospf6 *ospf); extern void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v); +extern void ospf6_spf_config_write (struct vty *vty); extern int config_write_ospf6_debug_spf (struct vty *vty); extern void install_element_ospf6_debug_spf (void); extern void ospf6_spf_init (void); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index df856b4cf..540ef382e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -46,6 +46,7 @@ #include "ospf6_asbr.h" #include "ospf6_abr.h" #include "ospf6_intra.h" +#include "ospf6_spf.h" #include "ospf6d.h" /* global ospf6d variable */ @@ -127,6 +128,11 @@ ospf6_create (void) o->lsdb->hook_add = ospf6_top_lsdb_hook_add; o->lsdb->hook_remove = ospf6_top_lsdb_hook_remove; + o->spf_delay = OSPF_SPF_DELAY_DEFAULT; + o->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + o->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; + o->spf_hold_multiplier = 1; + o->route_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, ROUTES); o->route_table->scope = o; o->route_table->hook_add = ospf6_top_route_hook_add; @@ -650,6 +656,7 @@ config_write_ospf6 (struct vty *vty) ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); + ospf6_spf_config_write (vty); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, j, oa)) { diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 4b2d2c3ef..27eb18cdd 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -38,6 +38,7 @@ struct ospf6 /* list of areas */ struct list *area_list; + struct ospf6_area *backbone; /* AS scope link state database */ struct ospf6_lsdb *lsdb; @@ -59,6 +60,18 @@ struct ospf6 u_char flag; + /* SPF parameters */ + unsigned int spf_delay; /* SPF delay time. */ + unsigned int spf_holdtime; /* SPF hold time. */ + unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ + unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ + + struct timeval ts_spf; /* SPF calculation time stamp. */ + struct timeval ts_spf_duration; /* Execution time of last SPF */ + + /* Threads */ + struct thread *t_spf_calc; /* SPF calculation timer. */ + struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *maxage_remover; }; From 2449fcd64ae95d5fbfd95d93468fc57003def57d Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:54:17 +0000 Subject: [PATCH 0287/1342] ospf6d: reinvoke MaxAge remover thread if not all MaxAge LSAs were flushed. MaxAge LSAs are being flushed out only on an event, unlike OSPFv2 where they're flushed out periodically. This causes certain LSAs to hang around forever, never getting flushed out. This patch makes flushing out MaxAge LSAs periodic, retriggered after a certain period if not all MaxAge LSAs were flushed out. Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- lib/libospf.h | 2 +- ospf6d/ospf6_lsdb.c | 23 +++++++++++++++++++++++ ospf6d/ospf6_lsdb.h | 15 --------------- ospf6d/ospf6_top.c | 32 ++++++++++++++++++++++++++------ ospfd/ospfd.c | 2 +- ospfd/ospfd.h | 2 -- 6 files changed, 51 insertions(+), 25 deletions(-) diff --git a/lib/libospf.h b/lib/libospf.h index 2282c0729..9a60ce9eb 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -77,6 +77,6 @@ #define OSPF_SPF_MAX_HOLDTIME_DEFAULT 10000 #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 -#define OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 +#define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 #endif /* _LIBOSPFD_H */ diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 7455d8353..0edc7a34c 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -481,6 +481,29 @@ ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) ospf6_lsdb_remove (lsa, lsdb); } +int +ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) +{ + int reschedule = 0; + struct ospf6_lsa *lsa; + + for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) + { + if (! OSPF6_LSA_IS_MAXAGE (lsa)) + continue; + if (lsa->retrans_count != 0) + { + reschedule = 1; + continue; + } + if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) + zlog_debug ("Remove MaxAge %s", lsa->name); + ospf6_lsdb_remove (lsa, lsdb); + } + + return (reschedule); +} + void ospf6_lsdb_show (struct vty *vty, int level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 71297daec..2974ffb1c 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -34,21 +34,6 @@ struct ospf6_lsdb void (*hook_remove) (struct ospf6_lsa *); }; -#define OSPF6_LSDB_MAXAGE_REMOVER(lsdb) \ - do { \ - struct ospf6_lsa *lsa; \ - for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) \ - { \ - if (! OSPF6_LSA_IS_MAXAGE (lsa)) \ - continue; \ - if (lsa->retrans_count != 0) \ - continue; \ - if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) \ - zlog_debug ("Remove MaxAge %s", lsa->name); \ - ospf6_lsdb_remove (lsa, lsdb); \ - } \ - } while (0) - /* Function Prototypes */ extern struct ospf6_lsdb *ospf6_lsdb_create (void *data); extern void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 540ef382e..e9fe7a4e9 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -208,7 +208,7 @@ ospf6_disable (struct ospf6 *o) } } -static int +int ospf6_maxage_remover (struct thread *thread) { struct ospf6 *o = (struct ospf6 *) THREAD_ARG (thread); @@ -216,6 +216,7 @@ ospf6_maxage_remover (struct thread *thread) struct ospf6_interface *oi; struct ospf6_neighbor *on; struct listnode *i, *j, *k; + int reschedule = 0; o->maxage_remover = (struct thread *) NULL; @@ -227,8 +228,9 @@ ospf6_maxage_remover (struct thread *thread) { if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING) - continue; + continue; + ospf6_maxage_remove (o); return 0; } } @@ -237,11 +239,28 @@ ospf6_maxage_remover (struct thread *thread) for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) - OSPF6_LSDB_MAXAGE_REMOVER (oi->lsdb); + { + if (ospf6_lsdb_maxage_remover (oi->lsdb)) + { + reschedule = 1; + } + } - OSPF6_LSDB_MAXAGE_REMOVER (oa->lsdb); + if (ospf6_lsdb_maxage_remover (oa->lsdb)) + { + reschedule = 1; + } + } + + if (ospf6_lsdb_maxage_remover (o->lsdb)) + { + reschedule = 1; + } + + if (reschedule) + { + ospf6_maxage_remove (o); } - OSPF6_LSDB_MAXAGE_REMOVER (o->lsdb); return 0; } @@ -250,7 +269,8 @@ void ospf6_maxage_remove (struct ospf6 *o) { if (o && ! o->maxage_remover) - o->maxage_remover = thread_add_event (master, ospf6_maxage_remover, o, 0); + o->maxage_remover = thread_add_timer (master, ospf6_maxage_remover, o, + OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT); } /* start ospf6 */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 3e2b23480..538bc0940 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -200,7 +200,7 @@ ospf_new (void) new->spf_hold_multiplier = 1; /* MaxAge init. */ - new->maxage_delay = OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT; + new->maxage_delay = OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT; new->maxage_lsa = route_table_init(); new->t_maxage_walker = thread_add_timer (master, ospf_lsa_maxage_walker, diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index fe9d77e9b..4242aa01b 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -211,10 +211,8 @@ struct ospf struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ #endif /* HAVE_OPAQUE_LSA */ -#define OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ -#define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/ From ac58e143f7278d5faaad7a8672e48328b03cffa5 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:54:24 +0000 Subject: [PATCH 0288/1342] ospf6d: remove older version of LSA from neigbor retx list before prematurely aging it. See comment in code for very detailed issue and fix. Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_lsa.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 7dbd303f6..183988004 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -258,6 +258,29 @@ ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) THREAD_OFF (lsa->expire); THREAD_OFF (lsa->refresh); + /* + * We clear the LSA from the neighbor retx lists now because it + * will not get deleted later. Essentially, changing the age to + * MaxAge will prevent this LSA from being matched with its + * existing entries in the retx list thereby causing those entries + * to be silently replaced with its MaxAged version, but with ever + * increasing retx count causing this LSA to remain forever and + * for the MaxAge remover thread to be called forever too. + * + * The reason the previous entry silently disappears is that when + * entry is added to a neighbor's retx list, it replaces the existing + * entry. But since the ospf6_lsdb_add() routine is generic and not aware + * of the special semantics of retx count, the retx count is not + * decremented when its replaced. Attempting to add the incr and decr + * retx count routines as the hook_add and hook_remove for the retx lists + * have a problem because the hook_remove routine is called for MaxAge + * entries (as will be the case in a traditional LSDB, unlike in this case + * where an LSDB is used as an efficient tree structure to store all kinds + * of data) that are added instead of calling the hook_add routine. + */ + + ospf6_flood_clear (lsa); + lsa->header->age = htons (OSPF_LSA_MAXAGE); thread_execute (master, ospf6_lsa_expire, lsa, 0); } From 09df4574b95dbb5880eb2d3c3c3c900687a9a3ef Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:54:31 +0000 Subject: [PATCH 0289/1342] ospf6d: enable the commands to support detailed debugging of LSAs. The code for the commands exists, but it hasn't been defined in the definition of the command itself. This patch fixes that. Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_lsa.c | 177 ++++++++------------------------------------- 1 file changed, 31 insertions(+), 146 deletions(-) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 183988004..3be08ef61 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -74,7 +74,7 @@ ospf6_unknown_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) struct ospf6_lsa_handler unknown_handler = { OSPF6_LSTYPE_UNKNOWN, - "Unknown", + "unknown", ospf6_unknown_lsa_show, OSPF6_LSA_DEBUG, }; @@ -748,7 +748,7 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) unsigned int i; unsigned int size = strlen (h->name); - if (!strcmp(h->name, "Unknown") && + if (!strcmp(h->name, "unknown") && h->type != OSPF6_LSTYPE_UNKNOWN) { snprintf (buf, sizeof (buf), "%#04hx", h->type); @@ -768,7 +768,7 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, - "debug ospf6 lsa XXXX/0xXXXX", + "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" @@ -777,44 +777,21 @@ DEFUN (debug_ospf6_lsa_type, { unsigned int i; struct ospf6_lsa_handler *handler = NULL; - unsigned long val; - char *endptr = NULL; - u_int16_t type = 0; assert (argc); - if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) || - (strlen (argv[0]) == 4)) - { - val = strtoul (argv[0], &endptr, 16); - if (*endptr == '\0') - type = val; - } - for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; - if (type && handler->type == type) + if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) break; if (! strcasecmp (argv[0], handler->name)) break; handler = NULL; } - if (type && handler == NULL) - { - handler = (struct ospf6_lsa_handler *) - malloc (sizeof (struct ospf6_lsa_handler)); - memset (handler, 0, sizeof (struct ospf6_lsa_handler)); - handler->type = type; - handler->name = "Unknown"; - handler->show = ospf6_unknown_lsa_show; - vector_set_index (ospf6_lsa_handler_vector, - handler->type & OSPF6_LSTYPE_FCODE_MASK, handler); - } - if (handler == NULL) handler = &unknown_handler; @@ -822,7 +799,7 @@ DEFUN (debug_ospf6_lsa_type, { if (! strcmp (argv[1], "originate")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); - if (! strcmp (argv[1], "examin")) + if (! strcmp (argv[1], "examine")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); if (! strcmp (argv[1], "flooding")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); @@ -833,9 +810,18 @@ DEFUN (debug_ospf6_lsa_type, return CMD_SUCCESS; } +ALIAS (debug_ospf6_lsa_type, + debug_ospf6_lsa_hex_detail_cmd, + "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", + DEBUG_STR + OSPF6_STR + "Debug Link State Advertisements (LSAs)\n" + "Specify LS type as Hexadecimal\n" + ) + DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, - "no debug ospf6 lsa XXXX/0xXXXX", + "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", NO_STR DEBUG_STR OSPF6_STR @@ -845,26 +831,15 @@ DEFUN (no_debug_ospf6_lsa_type, { u_int i; struct ospf6_lsa_handler *handler = NULL; - unsigned long val; - char *endptr = NULL; - u_int16_t type = 0; assert (argc); - if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) || - (strlen (argv[0]) == 4)) - { - val = strtoul (argv[0], &endptr, 16); - if (*endptr == '\0') - type = val; - } - for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; - if (type && handler->type == type) + if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) break; if (! strcasecmp (argv[0], handler->name)) break; @@ -877,7 +852,7 @@ DEFUN (no_debug_ospf6_lsa_type, { if (! strcmp (argv[1], "originate")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); - if (! strcmp (argv[1], "examin")) + if (! strcmp (argv[1], "examine")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); if (! strcmp (argv[1], "flooding")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); @@ -885,120 +860,30 @@ DEFUN (no_debug_ospf6_lsa_type, else UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG); - if (handler->debug == 0 && - !strcmp(handler->name, "Unknown") && type != OSPF6_LSTYPE_UNKNOWN) - { - free (handler); - vector_slot (ospf6_lsa_handler_vector, i) = NULL; - } - return CMD_SUCCESS; } -struct cmd_element debug_ospf6_lsa_type_cmd; -struct cmd_element debug_ospf6_lsa_type_detail_cmd; -struct cmd_element no_debug_ospf6_lsa_type_cmd; -struct cmd_element no_debug_ospf6_lsa_type_detail_cmd; +ALIAS (no_debug_ospf6_lsa_type, + no_debug_ospf6_lsa_hex_detail_cmd, + "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug Link State Advertisements (LSAs)\n" + "Specify LS type as Hexadecimal\n" + ) void install_element_ospf6_debug_lsa (void) { - u_int i; - struct ospf6_lsa_handler *handler; -#define STRSIZE 256 -#define DOCSIZE 1024 - static char strbuf[STRSIZE]; - static char docbuf[DOCSIZE]; - static char detail_strbuf[STRSIZE]; - static char detail_docbuf[DOCSIZE]; - char *str, *no_str; - char *doc, *no_doc; - - strbuf[0] = '\0'; - no_str = &strbuf[strlen (strbuf)]; - strncat (strbuf, "no ", STRSIZE - strlen (strbuf)); - str = &strbuf[strlen (strbuf)]; - - strncat (strbuf, "debug ospf6 lsa (", STRSIZE - strlen (strbuf)); - for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) - { - handler = vector_slot (ospf6_lsa_handler_vector, i); - if (handler == NULL) - continue; - strncat (strbuf, ospf6_lsa_handler_name (handler), - STRSIZE - strlen (strbuf)); - strncat (strbuf, "|", STRSIZE - strlen (strbuf)); - } - strbuf[strlen (strbuf) - 1] = ')'; - strbuf[strlen (strbuf)] = '\0'; - - docbuf[0] = '\0'; - no_doc = &docbuf[strlen (docbuf)]; - strncat (docbuf, NO_STR, DOCSIZE - strlen (docbuf)); - doc = &docbuf[strlen (docbuf)]; - - strncat (docbuf, DEBUG_STR, DOCSIZE - strlen (docbuf)); - strncat (docbuf, OSPF6_STR, DOCSIZE - strlen (docbuf)); - strncat (docbuf, "Debug Link State Advertisements (LSAs)\n", - DOCSIZE - strlen (docbuf)); - - for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) - { - handler = vector_slot (ospf6_lsa_handler_vector, i); - if (handler == NULL) - continue; - strncat (docbuf, "Debug ", DOCSIZE - strlen (docbuf)); - strncat (docbuf, handler->name, DOCSIZE - strlen (docbuf)); - strncat (docbuf, "-LSA\n", DOCSIZE - strlen (docbuf)); - } - docbuf[strlen (docbuf)] = '\0'; - - debug_ospf6_lsa_type_cmd.string = str; - debug_ospf6_lsa_type_cmd.func = debug_ospf6_lsa_type; - debug_ospf6_lsa_type_cmd.doc = doc; - - no_debug_ospf6_lsa_type_cmd.string = no_str; - no_debug_ospf6_lsa_type_cmd.func = no_debug_ospf6_lsa_type; - no_debug_ospf6_lsa_type_cmd.doc = no_doc; - - strncpy (detail_strbuf, strbuf, STRSIZE); - strncat (detail_strbuf, " (originate|examin|flooding)", - STRSIZE - strlen (detail_strbuf)); - detail_strbuf[strlen (detail_strbuf)] = '\0'; - no_str = &detail_strbuf[0]; - str = &detail_strbuf[strlen ("no ")]; - - strncpy (detail_docbuf, docbuf, DOCSIZE); - strncat (detail_docbuf, "Debug Originating LSA\n", - DOCSIZE - strlen (detail_docbuf)); - strncat (detail_docbuf, "Debug Examining LSA\n", - DOCSIZE - strlen (detail_docbuf)); - strncat (detail_docbuf, "Debug Flooding LSA\n", - DOCSIZE - strlen (detail_docbuf)); - detail_docbuf[strlen (detail_docbuf)] = '\0'; - no_doc = &detail_docbuf[0]; - doc = &detail_docbuf[strlen (NO_STR)]; - - debug_ospf6_lsa_type_detail_cmd.string = str; - debug_ospf6_lsa_type_detail_cmd.func = debug_ospf6_lsa_type; - debug_ospf6_lsa_type_detail_cmd.doc = doc; - - no_debug_ospf6_lsa_type_detail_cmd.string = no_str; - no_debug_ospf6_lsa_type_detail_cmd.func = no_debug_ospf6_lsa_type; - no_debug_ospf6_lsa_type_detail_cmd.doc = no_doc; - install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); - install_element (ENABLE_NODE, &debug_ospf6_lsa_type_cmd); - install_element (ENABLE_NODE, &debug_ospf6_lsa_type_detail_cmd); + install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); - install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_cmd); - install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_detail_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); - install_element (CONFIG_NODE, &debug_ospf6_lsa_type_cmd); - install_element (CONFIG_NODE, &debug_ospf6_lsa_type_detail_cmd); + install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); - install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_cmd); - install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_detail_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); } int @@ -1019,7 +904,7 @@ config_write_ospf6_debug_lsa (struct vty *vty) vty_out (vty, "debug ospf6 lsa %s originate%s", ospf6_lsa_handler_name (handler), VNL); if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN)) - vty_out (vty, "debug ospf6 lsa %s examin%s", + vty_out (vty, "debug ospf6 lsa %s examine%s", ospf6_lsa_handler_name (handler), VNL); if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD)) vty_out (vty, "debug ospf6 lsa %s flooding%s", From 8ae454e779d5620576990f4bf5da3a35f913cc4d Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:54:41 +0000 Subject: [PATCH 0290/1342] ospf6d: add more details to show ipv6 ospf6 data Specifically, it displays the flags, lock and retransmission count fields. Signed-off-by: Dinesh G Dutt Reviewed-by: JR Rivers Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_lsa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 3be08ef61..64f929d92 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -452,6 +452,11 @@ ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) ntohs (lsa->header->length), VNL); vty_out (vty, " Prev: %p This: %p Next: %p%s", lsa->prev, lsa, lsa->next, VNL); + vty_out (vty, "Flag: %x %s", lsa->flag, VNL); + vty_out (vty, "Lock: %d %s", lsa->lock, VNL); + vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); + vty_out (vty, "Threads: Expire: %x, Refresh: %x %s", + lsa->expire, lsa->refresh, VNL); vty_out (vty, "%s", VNL); return; } From bf986da797e7d2a0aaae313fea626ba433581f03 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:54:50 +0000 Subject: [PATCH 0291/1342] ospf6d: fix various bugs in installing and flooding LSAs Signed-off-by: Dinesh G Dutt Reviewed-by: Pradosh Mohapatra Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_flood.c | 14 ++++++-------- ospf6d/ospf6_lsa.c | 9 ++++----- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 3a9af01d9..ba7700924 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -122,10 +122,8 @@ ospf6_lsa_originate (struct ospf6_lsa *lsa) ospf6_lsa_header_print (lsa); } - if (old) - ospf6_flood_clear (old); - ospf6_flood (NULL, lsa); ospf6_install_lsa (lsa); + ospf6_flood (NULL, lsa); } void @@ -849,7 +847,11 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received); if (is_debug) - zlog_debug ("Flood, Install, Possibly acknowledge the received LSA"); + zlog_debug ("Install, Flood, Possibly acknowledge the received LSA"); + + /* Remove older copies of this LSA from retx lists */ + if (old) + ospf6_flood_clear (old); /* (b) immediately flood and (c) remove from all retrans-list */ /* Prevent self-originated LSA to be flooded. this is to make @@ -858,10 +860,6 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, if (new->header->adv_router != from->ospf6_if->area->ospf6->router_id) ospf6_flood (from, new); - /* (c) Remove the current database copy from all neighbors' Link - state retransmission lists. */ - /* XXX, flood_clear ? */ - /* (d), installing lsdb, which may cause routing table calculation (replacing database copy) */ ospf6_install_lsa (new); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 64f929d92..db14731f4 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -636,12 +636,12 @@ ospf6_lsa_expire (struct thread *thread) if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) return 0; /* dbexchange will do something ... */ - /* reflood lsa */ - ospf6_flood (NULL, lsa); - /* reinstall lsa */ ospf6_install_lsa (lsa); + /* reflood lsa */ + ospf6_flood (NULL, lsa); + /* schedule maxage remover */ ospf6_maxage_remove (ospf6); @@ -692,9 +692,8 @@ ospf6_lsa_refresh (struct thread *thread) ospf6_lsa_header_print (new); } - ospf6_flood_clear (old); - ospf6_flood (NULL, new); ospf6_install_lsa (new); + ospf6_flood (NULL, new); return 0; } From c5926a92235874574b20e426a3752c1451a90ec7 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:00 +0000 Subject: [PATCH 0292/1342] ospf6d: add p2p interface support Signed-off-by: Dinesh G Dutt Signed-off-by: Ayan Banerjee Reviewed-by: Scott Feldman Reviewed-by: James Li Signed-off-by: David Lamparter --- doc/ospf6d.texi | 4 + lib/libospf.h | 10 ++ ospf6d/ospf6_flood.c | 3 +- ospf6d/ospf6_interface.c | 105 +++++++++++++++++- ospf6d/ospf6_interface.h | 3 + ospf6d/ospf6_intra.c | 8 +- ospf6d/ospf6_message.c | 229 ++++++++++++++++++++++++--------------- ospfd/ospf_interface.h | 8 -- 8 files changed, 270 insertions(+), 100 deletions(-) diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi index c01c0510d..d981820c7 100644 --- a/doc/ospf6d.texi +++ b/doc/ospf6d.texi @@ -98,6 +98,10 @@ Sets interface's Router Priority. Default value is 1. Sets interface's Inf-Trans-Delay. Default value is 1. @end deffn +@deffn {Interface Command} {ipv6 ospf6 network (broadcast|point-to-point)} {} +Set explicitly network type for specifed interface. +@end deffn + @node Redistribute routes to OSPF6 @section Redistribute routes to OSPF6 diff --git a/lib/libospf.h b/lib/libospf.h index 9a60ce9eb..856c76df5 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -50,6 +50,16 @@ #define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001 #define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff +/* OSPF Interface Types */ +#define OSPF_IFTYPE_NONE 0 +#define OSPF_IFTYPE_POINTOPOINT 1 +#define OSPF_IFTYPE_BROADCAST 2 +#define OSPF_IFTYPE_NBMA 3 +#define OSPF_IFTYPE_POINTOMULTIPOINT 4 +#define OSPF_IFTYPE_VIRTUALLINK 5 +#define OSPF_IFTYPE_LOOPBACK 6 +#define OSPF_IFTYPE_MAX 7 + /* OSPF interface default values. */ #define OSPF_OUTPUT_COST_DEFAULT 10 #define OSPF_OUTPUT_COST_INFINITE UINT16_MAX diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index ba7700924..beae69927 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -366,7 +366,8 @@ ospf6_flood_interface (struct ospf6_neighbor *from, /* (5) flood the LSA out the interface. */ if (is_debug) zlog_debug ("Schedule flooding for the interface"); - if (if_is_broadcast (oi->interface)) + if ((oi->type == OSPF_IFTYPE_BROADCAST) || + (oi->type == OSPF_IFTYPE_POINTOPOINT)) { ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list); if (oi->thread_send_lsupdate == NULL) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 7c45fe46a..94b599be5 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -94,6 +94,17 @@ ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) } } +static u_char +ospf6_default_iftype(struct interface *ifp) +{ + if (if_is_pointopoint (ifp)) + return OSPF_IFTYPE_POINTOPOINT; + else if (if_is_loopback (ifp)) + return OSPF_IFTYPE_LOOPBACK; + else + return OSPF_IFTYPE_BROADCAST; +} + /* Create new ospf6 interface structure */ struct ospf6_interface * ospf6_interface_create (struct interface *ifp) @@ -122,6 +133,7 @@ ospf6_interface_create (struct interface *ifp) oi->dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; oi->rxmt_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; oi->cost = OSPF6_INTERFACE_COST; + oi->type = ospf6_default_iftype (ifp); oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; oi->mtu_ignore = 0; @@ -407,6 +419,7 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) (next_state != OSPF6_INTERFACE_DR && next_state != OSPF6_INTERFACE_BDR)) ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_LEAVE_GROUP); + if ((prev_state != OSPF6_INTERFACE_DR && prev_state != OSPF6_INTERFACE_BDR) && (next_state == OSPF6_INTERFACE_DR || @@ -640,8 +653,10 @@ interface_up (struct thread *thread) thread_add_event (master, ospf6_hello_send, oi, 0); /* decide next interface state */ - if (if_is_pointopoint (oi->interface)) + if ((if_is_pointopoint (oi->interface)) || + (oi->type == OSPF_IFTYPE_POINTOPOINT)) { ospf6_interface_state_change (OSPF6_INTERFACE_POINTTOPOINT, oi); + } else if (oi->priority == 0) ospf6_interface_state_change (OSPF6_INTERFACE_DROTHER, oi); else @@ -1522,6 +1537,86 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_list, return CMD_SUCCESS; } +DEFUN (ipv6_ospf6_network, + ipv6_ospf6_network_cmd, + "ipv6 ospf6 network (broadcast|point-to-point)", + IP6_STR + OSPF6_STR + "Network Type\n" + "Specify OSPFv6 broadcast network\n" + "Specify OSPF6 point-to-point network\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) { + oi = ospf6_interface_create (ifp); + } + assert (oi); + + if (strncmp (argv[0], "b", 1) == 0) + { + if (oi->type == OSPF_IFTYPE_BROADCAST) + return CMD_SUCCESS; + + oi->type = OSPF_IFTYPE_BROADCAST; + } + else if (strncmp (argv[0], "point-to-p", 10) == 0) + { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + return CMD_SUCCESS; + } + oi->type = OSPF_IFTYPE_POINTOPOINT; + } + + /* Reset the interface */ + thread_add_event (master, interface_down, oi, 0); + thread_add_event (master, interface_up, oi, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_network, + no_ipv6_ospf6_network_cmd, + "no ipv6 ospf6 network", + NO_STR + IP6_STR + OSPF6_STR + "Network Type\n" + "Default to whatever interface type system specifies" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + int type; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) { + return CMD_SUCCESS; + } + + type = ospf6_default_iftype (ifp); + if (oi->type == type) + { + return CMD_SUCCESS; + } + oi->type = type; + + /* Reset the interface */ + thread_add_event (master, interface_down, oi, 0); + thread_add_event (master, interface_up, oi, 0); + + return CMD_SUCCESS; +} + static int config_write_ospf6_interface (struct vty *vty) { @@ -1581,6 +1676,11 @@ config_write_ospf6_interface (struct vty *vty) if (oi->mtu_ignore) vty_out (vty, " ipv6 ospf6 mtu-ignore%s", VNL); + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + vty_out (vty, " ipv6 ospf6 network point-to-point%s", VNL); + else if (oi->type == OSPF_IFTYPE_BROADCAST) + vty_out (vty, " ipv6 ospf6 network broadcast%s", VNL); + vty_out (vty, "!%s", VNL); } return 0; @@ -1638,6 +1738,9 @@ ospf6_interface_init (void) install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd); + + install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd); } DEFUN (debug_ospf6_interface, diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index d80b07303..808f09688 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -56,6 +56,9 @@ struct ospf6_interface /* I/F transmission delay */ u_int32_t transdelay; + /* Network Type */ + u_char type; + /* Router Priority */ u_char priority; diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 9bc603b30..86f414606 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -215,7 +215,7 @@ ospf6_router_lsa_originate (struct thread *thread) } /* Point-to-Point interfaces */ - if (if_is_pointopoint (oi->interface)) + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) { @@ -233,7 +233,7 @@ ospf6_router_lsa_originate (struct thread *thread) } /* Broadcast and NBMA interfaces */ - if (if_is_broadcast (oi->interface)) + else if (oi->type == OSPF_IFTYPE_BROADCAST) { /* If this router is not DR, and If this router not fully adjacent with DR, @@ -261,6 +261,10 @@ ospf6_router_lsa_originate (struct thread *thread) lsdesc++; } + else + { + assert (0); /* Unknown interface type */ + } /* Virtual links */ /* xxx */ diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index b35aa1ac2..31db9a4ba 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1785,6 +1785,7 @@ ospf6_dbdesc_send (struct thread *thread) struct ospf6_dbdesc *dbdesc; u_char *p; struct ospf6_lsa *lsa; + struct in6_addr *dst; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_dbdesc = (struct thread *) NULL; @@ -1848,8 +1849,14 @@ ospf6_dbdesc_send (struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_DBDESC; oh->length = htons (p - sendbuf); - ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, - on->ospf6_if, oh); + + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) + dst = &allspfrouters6; + else + dst = &on->linklocal_addr; + + ospf6_send (on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh); + return 0; } @@ -1952,8 +1959,13 @@ ospf6_lsreq_send (struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSREQ; oh->length = htons (p - sendbuf); - ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) + ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); + else + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + return 0; } @@ -1964,7 +1976,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; - int num; + int lsa_cnt; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); @@ -1981,22 +1993,13 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) return 0; } - /* if we have nothing to send, return */ - if (on->lsupdate_list->count == 0 && - on->retrans_list->count == 0) - { - if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) - zlog_debug ("Quit to send (nothing to send)"); - return 0; - } - memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); - num = 0; + lsa_cnt = 0; /* lsupdate_list lists those LSA which doesn't need to be retransmitted. remove those from the list */ @@ -2005,58 +2008,85 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) - > ospf6_packet_max(on->ospf6_if)) - { - ospf6_lsa_unlock (lsa); - break; - } + > ospf6_packet_max(on->ospf6_if)) + { + ospf6_lsa_unlock (lsa); + break; + } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); - num++; + lsa_cnt++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsupdate_list); } + if (lsa_cnt) + { + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); + lsupdate->lsa_number = htonl (lsa_cnt); + + if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) || + (on->ospf6_if->state == OSPF6_INTERFACE_DR) || + (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) + ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, + on->ospf6_if, oh); + else + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + } + + /* The addresses used for retransmissions are different from those sent the + first time and so we need to separate them here. + */ + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + lsa_cnt = 0; + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) - > ospf6_packet_max(on->ospf6_if)) - { - ospf6_lsa_unlock (lsa); - break; - } + > ospf6_packet_max(on->ospf6_if)) + { + ospf6_lsa_unlock (lsa); + break; + } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); - num++; + lsa_cnt++; } - lsupdate->lsa_number = htonl (num); - - oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; - oh->length = htons (p - sendbuf); - - ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, - on->ospf6_if, oh); - - if (on->lsupdate_list->count != 0 || - on->retrans_list->count != 0) + if (lsa_cnt) { - if (on->lsupdate_list->count != 0) - on->thread_send_lsupdate = - thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); + lsupdate->lsa_number = htonl (lsa_cnt); + + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) + ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, + on->ospf6_if, oh); else - on->thread_send_lsupdate = - thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, - on->ospf6_if->rxmt_interval); + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); } + if (on->lsupdate_list->count != 0) + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); + else if (on->retrans_list->count != 0) + on->thread_send_lsupdate = + thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, + on->ospf6_if->rxmt_interval); return 0; } @@ -2067,7 +2097,7 @@ ospf6_lsupdate_send_interface (struct thread *thread) struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; - int num; + int lsa_cnt; struct ospf6_lsa *lsa; oi = (struct ospf6_interface *) THREAD_ARG (thread); @@ -2088,41 +2118,46 @@ ospf6_lsupdate_send_interface (struct thread *thread) memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *)((caddr_t) oh + - sizeof (struct ospf6_header)); + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); - num = 0; + lsa_cnt = 0; for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE (lsa->header))) - > ospf6_packet_max(oi)) - { - ospf6_lsa_unlock (lsa); - break; - } + > ospf6_packet_max(oi)) + { + ospf6_lsa_unlock (lsa); + break; + } ospf6_lsa_age_update_to_send (lsa, oi->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); - num++; + lsa_cnt++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsupdate_list); } - lsupdate->lsa_number = htonl (num); + if (lsa_cnt) + { + lsupdate->lsa_number = htonl (lsa_cnt); - oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; - oh->length = htons (p - sendbuf); + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); - if (oi->state == OSPF6_INTERFACE_DR || - oi->state == OSPF6_INTERFACE_BDR) - ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); - else - ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || + (oi->state == OSPF6_INTERFACE_DR) || + (oi->state == OSPF6_INTERFACE_BDR)) + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + else + ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); + + } if (oi->lsupdate_list->count > 0) { @@ -2140,6 +2175,7 @@ ospf6_lsack_send_neighbor (struct thread *thread) struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; + int lsa_cnt = 0; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsack = (struct thread *) NULL; @@ -2166,16 +2202,16 @@ ospf6_lsack_send_neighbor (struct thread *thread) { /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) - { - /* if we run out of packet size/space here, - better to try again soon. */ - THREAD_OFF (on->thread_send_lsack); - on->thread_send_lsack = - thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); + { + /* if we run out of packet size/space here, + better to try again soon. */ + THREAD_OFF (on->thread_send_lsack); + on->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); - ospf6_lsa_unlock (lsa); - break; - } + ospf6_lsa_unlock (lsa); + break; + } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); @@ -2183,13 +2219,24 @@ ospf6_lsack_send_neighbor (struct thread *thread) assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsack_list); + lsa_cnt++; } - oh->type = OSPF6_MESSAGE_TYPE_LSACK; - oh->length = htons (p - sendbuf); + if (lsa_cnt) + { + oh->type = OSPF6_MESSAGE_TYPE_LSACK; + oh->length = htons (p - sendbuf); + + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + } + + if (on->thread_send_lsack == NULL && on->lsack_list->count > 0) + { + on->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); + } - ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, - on->ospf6_if, oh); return 0; } @@ -2200,6 +2247,7 @@ ospf6_lsack_send_interface (struct thread *thread) struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; + int lsa_cnt = 0; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_send_lsack = (struct thread *) NULL; @@ -2226,16 +2274,16 @@ ospf6_lsack_send_interface (struct thread *thread) { /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(oi)) - { - /* if we run out of packet size/space here, - better to try again soon. */ - THREAD_OFF (oi->thread_send_lsack); - oi->thread_send_lsack = - thread_add_event (master, ospf6_lsack_send_interface, oi, 0); + { + /* if we run out of packet size/space here, + better to try again soon. */ + THREAD_OFF (oi->thread_send_lsack); + oi->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_interface, oi, 0); - ospf6_lsa_unlock (lsa); - break; - } + ospf6_lsa_unlock (lsa); + break; + } ospf6_lsa_age_update_to_send (lsa, oi->transdelay); memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); @@ -2243,16 +2291,21 @@ ospf6_lsack_send_interface (struct thread *thread) assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsack_list); + lsa_cnt++; } - oh->type = OSPF6_MESSAGE_TYPE_LSACK; - oh->length = htons (p - sendbuf); + if (lsa_cnt) + { + oh->type = OSPF6_MESSAGE_TYPE_LSACK; + oh->length = htons (p - sendbuf); - if (oi->state == OSPF6_INTERFACE_DR || - oi->state == OSPF6_INTERFACE_BDR) - ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); - else - ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || + (oi->state == OSPF6_INTERFACE_DR) || + (oi->state == OSPF6_INTERFACE_BDR)) + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + else + ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); + } if (oi->thread_send_lsack == NULL && oi->lsack_list->count > 0) { diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 9de655076..ed698c87e 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -140,14 +140,6 @@ struct ospf_interface /* OSPF Network Type. */ u_char type; -#define OSPF_IFTYPE_NONE 0 -#define OSPF_IFTYPE_POINTOPOINT 1 -#define OSPF_IFTYPE_BROADCAST 2 -#define OSPF_IFTYPE_NBMA 3 -#define OSPF_IFTYPE_POINTOMULTIPOINT 4 -#define OSPF_IFTYPE_VIRTUALLINK 5 -#define OSPF_IFTYPE_LOOPBACK 6 -#define OSPF_IFTYPE_MAX 7 /* State of Interface State Machine. */ u_char state; From eb82e9ee81792f86548d4937486b5dcbbd411a98 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:07 +0000 Subject: [PATCH 0293/1342] ospf6d: fix neighbor state machine (faster lsdb sync, RFC compliance) The OSPFv3 code doesn't do the following things right as part of an adjacency bringup: - Transmit DbDesc frames appropriately to ensure faster state transition to Loading state - Transmit LsReq frames when switching to exchange state and on receipt of an LS update in Loading state - Requesting LSAs multiple times in LsReq. It currently uses retransmit timer expiry to send the LsReq and DbDesc frames which significantly slows down large lsdb syncs. Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_flood.c | 34 +++++++++++++++++-------- ospf6d/ospf6_message.c | 56 +++++++++++++++++++++-------------------- ospf6d/ospf6_neighbor.c | 39 +++++++++++++++++++++++----- ospf6d/ospf6_neighbor.h | 3 +++ 4 files changed, 88 insertions(+), 44 deletions(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index beae69927..e02a432f9 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -206,8 +206,8 @@ ospf6_decrement_retrans_count (struct ospf6_lsa *lsa) void ospf6_install_lsa (struct ospf6_lsa *lsa) { - struct ospf6_lsa *old; struct timeval now; + struct ospf6_lsa *old; if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) @@ -290,7 +290,7 @@ ospf6_flood_interface (struct ospf6_neighbor *from, if (ospf6_lsa_compare (lsa, req) > 0) { if (is_debug) - zlog_debug ("Requesting is newer, next neighbor"); + zlog_debug ("Requesting is older, next neighbor"); continue; } @@ -298,18 +298,30 @@ ospf6_flood_interface (struct ospf6_neighbor *from, examin next neighbor */ if (ospf6_lsa_compare (lsa, req) == 0) { - if (is_debug) - zlog_debug ("Requesting the same, remove it, next neighbor"); + if (is_debug) + zlog_debug ("Requesting the same, remove it, next neighbor"); + if (req == on->last_ls_req) + { + ospf6_lsa_unlock (req); + on->last_ls_req = NULL; + } ospf6_lsdb_remove (req, on->request_list); + ospf6_check_nbr_loading (on); continue; } /* If the new LSA is more recent, delete from request-list */ if (ospf6_lsa_compare (lsa, req) < 0) { - if (is_debug) - zlog_debug ("Received is newer, remove requesting"); + if (is_debug) + zlog_debug ("Received is newer, remove requesting"); + if (req == on->last_ls_req) + { + ospf6_lsa_unlock (req); + on->last_ls_req = NULL; + } ospf6_lsdb_remove (req, on->request_list); + ospf6_check_nbr_loading (on); /* fall through */ } } @@ -796,7 +808,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, { /* log */ if (is_debug) - zlog_debug ("Drop MaxAge LSA with direct acknowledgement."); + zlog_debug ("Drop MaxAge LSA with direct acknowledgement."); /* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */ ospf6_lsdb_add (ospf6_lsa_copy (new), from->lsack_list); @@ -950,8 +962,8 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, zlog_debug ("The LSA is in Seqnumber Wrapping"); zlog_debug ("MaxAge & MaxSeqNum, discard"); } - ospf6_lsa_delete (new); - return; + ospf6_lsa_delete (new); + return; } /* Otherwise, Send database copy of this LSA to this neighbor */ @@ -968,8 +980,8 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, if (from->thread_send_lsupdate == NULL) from->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, from, 0); - ospf6_lsa_delete (new); - return; + ospf6_lsa_delete (new); + return; } return; } diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 31db9a4ba..dcbb36bf5 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -517,20 +517,20 @@ ospf6_dbdesc_recv_master (struct ospf6_header *oh, { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request (No database copy)"); - ospf6_lsdb_add (his, on->request_list); + ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } else if (ospf6_lsa_compare (his, mine) < 0) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request (Received MoreRecent)"); - ospf6_lsdb_add (his, on->request_list); + ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } else { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Discard (Existing MoreRecent)"); - ospf6_lsa_delete (his); } + ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); @@ -539,7 +539,7 @@ ospf6_dbdesc_recv_master (struct ospf6_header *oh, on->dbdesc_seqnum ++; /* schedule send lsreq */ - if (on->thread_send_lsreq == NULL) + if (on->request_list->count && (on->thread_send_lsreq == NULL)) on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); @@ -735,10 +735,9 @@ ospf6_dbdesc_recv_slave (struct ospf6_header *oh, { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request-list: %s", his->name); - ospf6_lsdb_add (his, on->request_list); + ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } - else - ospf6_lsa_delete (his); + ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); @@ -747,7 +746,8 @@ ospf6_dbdesc_recv_slave (struct ospf6_header *oh, on->dbdesc_seqnum = ntohl (dbdesc->seqnum); /* schedule send lsreq */ - if (on->thread_send_lsreq == NULL) + if ((on->thread_send_lsreq == NULL) && + (on->request_list->count)) on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); @@ -1351,19 +1351,6 @@ ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst, assert (p == OSPF6_MESSAGE_END (oh)); - /* RFC2328 Section 10.9: When the neighbor responds to these requests - with the proper Link State Update packet(s), the Link state request - list is truncated and a new Link State Request packet is sent. */ - /* send new Link State Request packet if this LS Update packet - can be recognized as a response to our previous LS Request */ - if (! IN6_IS_ADDR_MULTICAST (dst) && - (on->state == OSPF6_NEIGHBOR_EXCHANGE || - on->state == OSPF6_NEIGHBOR_LOADING)) - { - THREAD_OFF (on->thread_send_lsreq); - on->thread_send_lsreq = - thread_add_event (master, ospf6_lsreq_send, on, 0); - } } static void @@ -1907,7 +1894,7 @@ ospf6_lsreq_send (struct thread *thread) struct ospf6_header *oh; struct ospf6_lsreq_entry *e; u_char *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *last_req; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsreq = (struct thread *) NULL; @@ -1929,13 +1916,9 @@ ospf6_lsreq_send (struct thread *thread) return 0; } - /* set next thread */ - on->thread_send_lsreq = - thread_add_timer (master, ospf6_lsreq_send, on, - on->ospf6_if->rxmt_interval); - memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; + last_req = NULL; /* set Request entries in lsreq */ p = (u_char *)((caddr_t) oh + sizeof (struct ospf6_header)); @@ -1954,6 +1937,17 @@ ospf6_lsreq_send (struct thread *thread) e->id = lsa->header->id; e->adv_router = lsa->header->adv_router; p += sizeof (struct ospf6_lsreq_entry); + last_req = lsa; + } + + if (last_req != NULL) + { + if (on->last_ls_req != NULL) + { + ospf6_lsa_unlock (on->last_ls_req); + } + ospf6_lsa_lock (last_req); + on->last_ls_req = last_req; } oh->type = OSPF6_MESSAGE_TYPE_LSREQ; @@ -1966,6 +1960,14 @@ ospf6_lsreq_send (struct thread *thread) ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); + /* set next thread */ + if (on->request_list->count != 0) + { + on->thread_send_lsreq = + thread_add_timer (master, ospf6_lsreq_send, on, + on->ospf6_if->rxmt_interval); + } + return 0; } diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 806767dd5..84f0b002c 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -98,7 +98,6 @@ ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi) on->retrans_list = ospf6_lsdb_create (on); on->dbdesc_list = ospf6_lsdb_create (on); - on->lsreq_list = ospf6_lsdb_create (on); on->lsupdate_list = ospf6_lsdb_create (on); on->lsack_list = ospf6_lsdb_create (on); @@ -121,7 +120,6 @@ ospf6_neighbor_delete (struct ospf6_neighbor *on) } ospf6_lsdb_remove_all (on->dbdesc_list); - ospf6_lsdb_remove_all (on->lsreq_list); ospf6_lsdb_remove_all (on->lsupdate_list); ospf6_lsdb_remove_all (on->lsack_list); @@ -130,7 +128,6 @@ ospf6_neighbor_delete (struct ospf6_neighbor *on) ospf6_lsdb_delete (on->retrans_list); ospf6_lsdb_delete (on->dbdesc_list); - ospf6_lsdb_delete (on->lsreq_list); ospf6_lsdb_delete (on->lsupdate_list); ospf6_lsdb_delete (on->lsack_list); @@ -360,11 +357,41 @@ exchange_done (struct thread *thread) if (on->request_list->count == 0) ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on); else - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on); + { + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on); + + if (on->thread_send_lsreq == NULL) + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); + } return 0; } +/* Check loading state. */ +void +ospf6_check_nbr_loading (struct ospf6_neighbor *on) +{ + + /* RFC2328 Section 10.9: When the neighbor responds to these requests + with the proper Link State Update packet(s), the Link state request + list is truncated and a new Link State Request packet is sent. + */ + if ((on->state == OSPF6_NEIGHBOR_LOADING) || + (on->state == OSPF6_NEIGHBOR_EXCHANGE)) + { + if (on->request_list->count == 0) + thread_add_event (master, loading_done, on, 0); + else if (on->last_ls_req == NULL) + { + if (on->thread_send_lsreq != NULL) + THREAD_OFF (on->thread_send_lsreq); + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); + } + } +} + int loading_done (struct thread *thread) { @@ -727,10 +754,10 @@ ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on) timersub (&on->thread_send_lsreq->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSReq in Time %s [thread %s]%s", - on->lsreq_list->count, duration, + on->request_list->count, duration, (on->thread_send_lsreq ? "on" : "off"), VNL); - for (lsa = ospf6_lsdb_head (on->lsreq_list); lsa; + for (lsa = ospf6_lsdb_head (on->request_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 5f46c6f38..750e1b242 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -86,6 +86,8 @@ struct ospf6_neighbor struct ospf6_lsdb *lsupdate_list; struct ospf6_lsdb *lsack_list; + struct ospf6_lsa *last_ls_req; + /* Inactivity timer */ struct thread *inactivity_timer; @@ -130,6 +132,7 @@ extern int seqnumber_mismatch (struct thread *); extern int bad_lsreq (struct thread *); extern int oneway_received (struct thread *); extern int inactivity_timer (struct thread *); +extern void ospf6_check_nbr_loading (struct ospf6_neighbor *); extern void ospf6_neighbor_init (void); extern int config_write_ospf6_debug_neighbor (struct vty *vty); From a765eb9383c53c68523a67b36cea92eadf6f3439 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:14 +0000 Subject: [PATCH 0294/1342] ospf6d: convert LSDB to use route_node, improve performance the performance in the presence of a large number of LSAs. I also verified that the performance improvements stayed in the presence of a large number of peers (I tested upto 128). Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman Summary: Reviewed-by: James Li Signed-off-by: David Lamparter --- ospf6d/ospf6_lsa.c | 3 +- ospf6d/ospf6_lsa.h | 3 +- ospf6d/ospf6_lsdb.c | 165 +++++++++++++++++------------------------ ospf6d/ospf6_lsdb.h | 2 + ospf6d/ospf6_message.c | 16 ++-- 5 files changed, 78 insertions(+), 111 deletions(-) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index db14731f4..592aad9bc 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -450,8 +450,6 @@ ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) vty_out (vty, "CheckSum: %#06hx Length: %hu%s", ntohs (lsa->header->checksum), ntohs (lsa->header->length), VNL); - vty_out (vty, " Prev: %p This: %p Next: %p%s", - lsa->prev, lsa, lsa->next, VNL); vty_out (vty, "Flag: %x %s", lsa->flag, VNL); vty_out (vty, "Lock: %d %s", lsa->lock, VNL); vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); @@ -586,6 +584,7 @@ ospf6_lsa_copy (struct ospf6_lsa *lsa) copy->received = lsa->received; copy->installed = lsa->installed; copy->lsdb = lsa->lsdb; + copy->rn = NULL; return copy; } diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index f10ee671b..998599ba4 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -114,8 +114,7 @@ struct ospf6_lsa { char name[64]; /* dump string */ - struct ospf6_lsa *prev; - struct ospf6_lsa *next; + struct route_node *rn; unsigned char lock; /* reference counter */ unsigned char flag; /* special meaning (e.g. floodback) */ diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 0edc7a34c..657a57990 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -54,9 +54,12 @@ ospf6_lsdb_create (void *data) void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb) { - ospf6_lsdb_remove_all (lsdb); - route_table_finish (lsdb->table); - XFREE (MTYPE_OSPF6_LSDB, lsdb); + if (lsdb != NULL) + { + ospf6_lsdb_remove_all (lsdb); + route_table_finish (lsdb->table); + XFREE (MTYPE_OSPF6_LSDB, lsdb); + } } static void @@ -102,8 +105,8 @@ void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct prefix_ipv6 key; - struct route_node *current, *nextnode, *prevnode; - struct ospf6_lsa *next, *prev, *old = NULL; + struct route_node *current; + struct ospf6_lsa *old = NULL; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type)); @@ -114,55 +117,25 @@ ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) current = route_node_get (lsdb->table, (struct prefix *) &key); old = current->info; current->info = lsa; + lsa->rn = current; ospf6_lsa_lock (lsa); - if (old) - { - if (old->prev) - old->prev->next = lsa; - if (old->next) - old->next->prev = lsa; - lsa->next = old->next; - lsa->prev = old->prev; - } - else + if (!old) { - /* next link */ - nextnode = current; - route_lock_node (nextnode); - do { - nextnode = route_next (nextnode); - } while (nextnode && nextnode->info == NULL); - if (nextnode == NULL) - lsa->next = NULL; - else - { - next = nextnode->info; - lsa->next = next; - next->prev = lsa; - route_unlock_node (nextnode); - } + lsdb->count++; - /* prev link */ - prevnode = current; - route_lock_node (prevnode); - do { - prevnode = route_prev (prevnode); - } while (prevnode && prevnode->info == NULL); - if (prevnode == NULL) - lsa->prev = NULL; + if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + if (lsdb->hook_remove) + (*lsdb->hook_remove) (lsa); + } else - { - prev = prevnode->info; - lsa->prev = prev; - prev->next = lsa; - route_unlock_node (prevnode); - } - - lsdb->count++; + { + if (lsdb->hook_add) + (*lsdb->hook_add) (lsa); + } } - - if (old) + else { if (OSPF6_LSA_IS_CHANGED (old, lsa)) { @@ -187,20 +160,8 @@ ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) (*lsdb->hook_add) (lsa); } } + ospf6_lsa_unlock (old); } - else if (OSPF6_LSA_IS_MAXAGE (lsa)) - { - if (lsdb->hook_remove) - (*lsdb->hook_remove) (lsa); - } - else - { - if (lsdb->hook_add) - (*lsdb->hook_add) (lsa); - } - - if (old) - ospf6_lsa_unlock (old); ospf6_lsdb_count_assert (lsdb); } @@ -220,19 +181,15 @@ ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) node = route_node_lookup (lsdb->table, (struct prefix *) &key); assert (node && node->info == lsa); - if (lsa->prev) - lsa->prev->next = lsa->next; - if (lsa->next) - lsa->next->prev = lsa->prev; - node->info = NULL; lsdb->count--; if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); + route_unlock_node (node); /* to free the lookup lock */ + route_unlock_node (node); /* to free the original lock */ ospf6_lsa_unlock (lsa); - route_unlock_node (node); ospf6_lsdb_count_assert (lsdb); } @@ -255,6 +212,8 @@ ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, node = route_node_lookup (lsdb->table, (struct prefix *) &key); if (node == NULL || node->info == NULL) return NULL; + + route_unlock_node (node); return (struct ospf6_lsa *) node->info; } @@ -306,21 +265,9 @@ ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, u_int32_t adv_router, if (prefix_same (&node->p, p)) { - struct route_node *prev = node; - struct ospf6_lsa *lsa_prev; - struct ospf6_lsa *lsa_next; - node = route_next (node); while (node && node->info == NULL) node = route_next (node); - - lsa_prev = prev->info; - lsa_next = (node ? node->info : NULL); - assert (lsa_prev); - assert (lsa_prev->next == lsa_next); - if (lsa_next) - assert (lsa_next->prev == lsa_prev); - zlog_debug ("lsdb_lookup_next: assert OK with previous LSA"); } if (! node) @@ -346,7 +293,6 @@ ospf6_lsdb_head (struct ospf6_lsdb *lsdb) if (node == NULL) return NULL; - route_unlock_node (node); if (node->info) ospf6_lsa_lock ((struct ospf6_lsa *) node->info); return (struct ospf6_lsa *) node->info; @@ -355,12 +301,20 @@ ospf6_lsdb_head (struct ospf6_lsdb *lsdb) struct ospf6_lsa * ospf6_lsdb_next (struct ospf6_lsa *lsa) { - struct ospf6_lsa *next = lsa->next; + struct route_node *node = lsa->rn; + struct ospf6_lsa *next = NULL; - ospf6_lsa_unlock (lsa); - if (next) - ospf6_lsa_lock (next); + do { + node = route_next (node); + } while (node && node->info == NULL); + + if ((node != NULL) && (node->info != NULL)) + { + next = node->info; + ospf6_lsa_lock (next); + } + ospf6_lsa_unlock (lsa); return next; } @@ -390,8 +344,6 @@ ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router, if (node == NULL) return NULL; - else - route_unlock_node (node); if (! prefix_match ((struct prefix *) &key, &node->p)) return NULL; @@ -406,18 +358,19 @@ struct ospf6_lsa * ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router, struct ospf6_lsa *lsa) { - struct ospf6_lsa *next = lsa->next; + struct ospf6_lsa *next = ospf6_lsdb_next(lsa); if (next) { if (next->header->type != type || next->header->adv_router != adv_router) - next = NULL; + { + route_unlock_node (next->rn); + ospf6_lsa_unlock (next); + next = NULL; + } } - if (next) - ospf6_lsa_lock (next); - ospf6_lsa_unlock (lsa); return next; } @@ -444,8 +397,6 @@ ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb) if (node == NULL) return NULL; - else - route_unlock_node (node); if (! prefix_match ((struct prefix *) &key, &node->p)) return NULL; @@ -459,17 +410,18 @@ ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb) struct ospf6_lsa * ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa) { - struct ospf6_lsa *next = lsa->next; + struct ospf6_lsa *next = ospf6_lsdb_next (lsa); if (next) { if (next->header->type != type) - next = NULL; + { + route_unlock_node (next->rn); + ospf6_lsa_unlock (next); + next = NULL; + } } - if (next) - ospf6_lsa_lock (next); - ospf6_lsa_unlock (lsa); return next; } @@ -477,10 +429,25 @@ void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; + + if (lsdb == NULL) + return; + for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) ospf6_lsdb_remove (lsa, lsdb); } +void +ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa) +{ + if (lsa != NULL) + { + if (lsa->rn != NULL) + route_unlock_node (lsa->rn); + ospf6_lsa_unlock (lsa); + } +} + int ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) { @@ -574,7 +541,7 @@ ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, continue; if (ntohl (lsa->header->id) > id) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } id++; diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 2974ffb1c..a124adbf0 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -64,6 +64,7 @@ extern struct ospf6_lsa *ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa); extern void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb); +extern void ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa); #define OSPF6_LSDB_SHOW_LEVEL_NORMAL 0 #define OSPF6_LSDB_SHOW_LEVEL_DETAIL 1 @@ -79,5 +80,6 @@ extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); +extern int ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb); #endif /* OSPF6_LSDB_H */ diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index dcbb36bf5..82d2d340b 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1825,7 +1825,7 @@ ospf6_dbdesc_send (struct thread *thread) if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); @@ -1865,7 +1865,7 @@ ospf6_dbdesc_send_newone (struct thread *thread) { if (size + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } @@ -1928,7 +1928,7 @@ ospf6_lsreq_send (struct thread *thread) /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } @@ -2012,7 +2012,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } @@ -2058,7 +2058,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } @@ -2132,7 +2132,7 @@ ospf6_lsupdate_send_interface (struct thread *thread) if ( (p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE (lsa->header))) > ospf6_packet_max(oi)) { - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } @@ -2211,7 +2211,7 @@ ospf6_lsack_send_neighbor (struct thread *thread) on->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } @@ -2283,7 +2283,7 @@ ospf6_lsack_send_interface (struct thread *thread) oi->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_interface, oi, 0); - ospf6_lsa_unlock (lsa); + ospf6_lsdb_lsa_unlock (lsa); break; } From e39d05384d4563f04edf339bbd67a117dd18e533 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:36 +0000 Subject: [PATCH 0295/1342] ospf6d: turn off expensive debugging OSPF6 has very expensive LSDB and route debug on by default. This needs to be turned off for scaled performance. Signed-off-by: James Li Reviewed-by: Dinesh G Dutt Summary: Signed-off-by: David Lamparter --- ospf6d/ospf6_lsdb.c | 6 +++--- ospf6d/ospf6_route.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 657a57990..b13ae9b1f 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -73,7 +73,7 @@ ospf6_lsdb_set_key (struct prefix_ipv6 *key, void *value, int len) key->prefixlen += len * 8; } -#ifndef NDEBUG +#ifdef DEBUG static void _lsdb_count_assert (struct ospf6_lsdb *lsdb) { @@ -97,9 +97,9 @@ _lsdb_count_assert (struct ospf6_lsdb *lsdb) assert (num == lsdb->count); } #define ospf6_lsdb_count_assert(t) (_lsdb_count_assert (t)) -#else /*NDEBUG*/ +#else /*DEBUG*/ #define ospf6_lsdb_count_assert(t) ((void) 0) -#endif /*NDEBUG*/ +#endif /*DEBUG*/ void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 398acfa80..5f1869ac0 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -304,7 +304,7 @@ ospf6_route_lookup_bestmatch (struct prefix *prefix, return route; } -#ifndef NDEBUG +#ifdef DEBUG static void route_table_assert (struct ospf6_route_table *table) { @@ -350,7 +350,7 @@ route_table_assert (struct ospf6_route_table *table) #define ospf6_route_table_assert(t) (route_table_assert (t)) #else #define ospf6_route_table_assert(t) ((void) 0) -#endif /*NDEBUG*/ +#endif /*DEBUG*/ struct ospf6_route * ospf6_route_add (struct ospf6_route *route, From 17d003da963d6294e5ab95c690de285eccf0bac0 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:43 +0000 Subject: [PATCH 0296/1342] ospf6d: don't suppress empty router LSA Currently in OSPFv3 implementation, if all the interfaces are down/loopback or are without any full adjacencies, the router LSA is suppressed. So for a router with only stub networks, no router LSA is generated. However, intra-prefix LSAs are generated for the stub networks and these intra-prefix LSAs will reference the router LSA. So the router LSA really should not be suppressed. It needs to be generated to be the starting vertex for SPF w.r.t the stub networks. Signed-off-by: James Li Reviewed-by: Dinesh G Dutt Signed-off-by: David Lamparter --- ospf6d/ospf6_intra.c | 49 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 86f414606..4cb751f01 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -272,35 +272,26 @@ ospf6_router_lsa_originate (struct thread *thread) /* xxx */ } - if ((caddr_t) lsdesc != (caddr_t) router_lsa + - sizeof (struct ospf6_router_lsa)) - { - /* Fill LSA Header */ - lsa_header->age = 0; - lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); - lsa_header->id = htonl (link_state_id); - lsa_header->adv_router = oa->ospf6->router_id; - lsa_header->seqnum = - ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, - lsa_header->adv_router, oa->lsdb); - lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); - - /* LSA checksum */ - ospf6_lsa_checksum (lsa_header); - - /* create LSA */ - lsa = ospf6_lsa_create (lsa_header); - - /* Originate */ - ospf6_lsa_originate_area (lsa, oa); - - link_state_id ++; - } - else - { - if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) - zlog_debug ("Nothing to describe in Router-LSA, suppress"); - } + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); + lsa_header->id = htonl (link_state_id); + lsa_header->adv_router = oa->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oa->lsdb); + lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, oa); + + link_state_id ++; /* Do premature-aging of rest, undesired Router-LSAs */ type = ntohs (OSPF6_LSTYPE_ROUTER); From b81e97a8a7f85ecc7489dc8a7c7b9d403d9c4bc6 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:50 +0000 Subject: [PATCH 0297/1342] ospf6d: correct nexthop through directly connected networks This is implementing this part of RFC 2328: This is the "first case", see below, 16.1.1. The next hop calculation ... If there is at least one intervening router in the current shortest path between the destination and the root, the destination simply inherits the set of next hops from the parent. Otherwise, there are two cases. In the first case, the parent vertex is the root (the calculating router itself). This means that the destination is either a directly connected network or directly connected router. The outgoing interface in this case is simply the OSPF interface connecting to the destination network/router. ... The current Quagga code always tries to inherit the nexthop from a parent vertex, but does not cover the case that the destination is directly connected to the root vertex. This patch adds support for that case. Signed-off-by: James Li Reviewed-by: Dinesh G Dutt Signed-off-by: David Lamparter --- lib/if.c | 24 ++++++++++++++++++++++++ lib/if.h | 1 + ospf6d/ospf6_intra.c | 23 ++++++++++++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/if.c b/lib/if.c index e26aa046f..6348403b6 100644 --- a/lib/if.c +++ b/lib/if.c @@ -304,6 +304,30 @@ if_lookup_address (struct in_addr src) return match; } +/* Lookup interface by prefix */ +struct interface * +if_lookup_prefix (struct prefix *prefix) +{ + struct listnode *node; + struct prefix addr; + int bestlen = 0; + struct listnode *cnode; + struct interface *ifp; + struct connected *c; + + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + { + for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) + { + if (prefix_cmp(c->address, prefix) == 0) + { + return ifp; + } + } + } + return NULL; +} + /* Get interface by name if given name interface doesn't exist create one. */ struct interface * diff --git a/lib/if.h b/lib/if.h index 13cc254e2..8081be87d 100644 --- a/lib/if.h +++ b/lib/if.h @@ -245,6 +245,7 @@ extern struct interface *if_create (const char *name, int namelen); extern struct interface *if_lookup_by_index (unsigned int); extern struct interface *if_lookup_exact_address (struct in_addr); extern struct interface *if_lookup_address (struct in_addr); +extern struct interface *if_lookup_prefix (struct prefix *prefix); /* These 2 functions are to be used when the ifname argument is terminated by a '\0' character: */ diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 4cb751f01..c08a6ae64 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1024,6 +1024,8 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) struct ospf6_prefix *op; char *start, *current, *end; char buf[64]; + struct interface *ifp; + int direct_connect = 0; if (OSPF6_LSA_IS_MAXAGE (lsa)) return; @@ -1060,6 +1062,12 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) return; } + if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) + { + /* the intra-prefix are directly connected */ + direct_connect = 1; + } + prefix_num = ntohs (intra_prefix_lsa->prefix_num); start = (caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); @@ -1090,9 +1098,18 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) route->path.cost = ls_entry->path.cost + ntohs (op->prefix_metric); - for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) - ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); + if (direct_connect) + { + ifp = if_lookup_prefix(&route->prefix); + if (ifp) + route->nexthop[0].ifindex = ifp->ifindex; + } + else + { + for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); + } if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { From e7ad6b20d7a7c63ed7c640ab9f61c853e77508c5 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 07:55:57 +0000 Subject: [PATCH 0298/1342] ospf6d: fix linkdown handling Ensure OSPFv3 handles link down even correctly. OSPFv3 checks only the administrative status of a link instead of its operative status. This prevents it up from detecting a real link down event and reacting appropriately. Only protocol timer timeouts make it detect a link down eventually. This patch makes it look for the operative status of a link instead of admin status. Signed-off-by: Dinesh G Dutt Reviewed-by: James Li Signed-off-by: David Lamparter --- ospf6d/ospf6_interface.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 94b599be5..d1f5cba1c 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -316,7 +316,7 @@ ospf6_interface_state_update (struct interface *ifp) if (oi->area == NULL) return; - if (if_is_up (ifp)) + if (if_is_operative (ifp)) thread_add_event (master, interface_up, oi, 0); else thread_add_event (master, interface_down, oi, 0); @@ -625,7 +625,7 @@ interface_up (struct thread *thread) oi->interface->name); /* check physical interface is up */ - if (! if_is_up (oi->interface)) + if (! if_is_operative (oi->interface)) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s is down, can't execute [InterfaceUp]", @@ -779,7 +779,7 @@ ospf6_interface_show (struct vty *vty, struct interface *ifp) type = "UNKNOWN"; vty_out (vty, "%s is %s, type %s%s", - ifp->name, updown[if_is_up (ifp)], type, + ifp->name, updown[if_is_operative (ifp)], type, VNL); vty_out (vty, " Interface ID: %d%s", ifp->ifindex, VNL); From f41b4a021659dd48d62b1a7aac4b28e3663dbdaa Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 08:00:37 +0000 Subject: [PATCH 0299/1342] ospf6d: add overload support OSPFv3: Support setting/clearing overload bit on router It is sometimes necessary for a router to gracefully remove itself from the SPF tree i.e. it cannot act as a transit router. It does this by setting the overload bit in the router LSA. This patch adds support for enabling/disabling the overload bit. Signed-off-by: Dinesh G Dutt Reviewed-by: Pradosh Mohapatra [DL: patch applied with fuzz] Signed-off-by: David Lamparter --- ospf6d/ospf6_area.c | 13 ++++- ospf6d/ospf6_intra.c | 23 +++++++++ ospf6d/ospf6_intra.h | 8 +++ ospf6d/ospf6_spf.c | 5 ++ ospf6d/ospf6_top.c | 117 +++++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_top.h | 1 + 6 files changed, 165 insertions(+), 2 deletions(-) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 1e07d8579..37e5c0045 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -164,9 +164,18 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o) oa->summary_router->scope = oa; /* set default options */ - OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); + if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) + { + OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6); + OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R); + } + else + { + OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); + } + OSPF6_OPT_SET (oa->options, OSPF6_OPT_E); - OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); oa->ospf6 = o; listnode_add_sort (o->area_list, oa); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index c08a6ae64..025a77104 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -104,6 +104,29 @@ ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) return 0; } +int +ospf6_router_is_stub_router (struct ospf6_lsa *lsa) +{ + struct ospf6_router_lsa *rtr_lsa; + + if (lsa != NULL && OSPF6_LSA_IS_TYPE (ROUTER, lsa)) + { + rtr_lsa = (struct ospf6_router_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_R)) + { + return (OSPF6_IS_STUB_ROUTER); + } + else if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_V6)) + { + return (OSPF6_IS_STUB_ROUTER_V6); + } + } + + return (OSPF6_NOT_STUB_ROUTER); +} + int ospf6_router_lsa_originate (struct thread *thread) { diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h index 3810174ea..a25efa12c 100644 --- a/ospf6d/ospf6_intra.h +++ b/ospf6d/ospf6_intra.h @@ -94,6 +94,13 @@ struct ospf6_router_lsdesc #define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3 #define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4 +enum stub_router_mode + { + OSPF6_NOT_STUB_ROUTER, + OSPF6_IS_STUB_ROUTER, + OSPF6_IS_STUB_ROUTER_V6, + }; + #define ROUTER_LSDESC_IS_TYPE(t,x) \ ((((struct ospf6_router_lsdesc *)(x))->type == \ OSPF6_ROUTER_LSDESC_ ## t) ? 1 : 0) @@ -200,6 +207,7 @@ extern char *ospf6_router_lsdesc_lookup (u_char type, u_int32_t interface_id, extern char *ospf6_network_lsdesc_lookup (u_int32_t router_id, struct ospf6_lsa *lsa); +extern int ospf6_router_is_stub_router (struct ospf6_lsa *lsa); extern int ospf6_router_lsa_originate (struct thread *); extern int ospf6_network_lsa_originate (struct thread *); extern int ospf6_link_lsa_originate (struct thread *); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index e4c424dbb..845e206c4 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -424,6 +424,11 @@ ospf6_spf_calculation (u_int32_t router_id, if (ospf6_spf_install (v, result_table) < 0) continue; + /* Skip overloaded routers */ + if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) && + ospf6_router_is_stub_router (v->lsa))) + continue; + /* For each LS description in the just-added vertex V's LSA */ size = (VERTEX_IS_TYPE (ROUTER, v) ? sizeof (struct ospf6_router_lsdesc) : diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index e9fe7a4e9..dec7096cf 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -464,6 +464,101 @@ DEFUN (no_ospf6_interface_area, return CMD_SUCCESS; } +DEFUN (ospf6_stub_router_admin, + ospf6_stub_router_admin_cmd, + "stub-router administrative", + "Make router a stub router\n" + "Advertise inability to be a transit router\n" + "Administratively applied, for an indefinite period\n") +{ + struct listnode *node; + struct ospf6_area *oa; + + if (!CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) + { + for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) + { + OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6); + OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R); + OSPF6_ROUTER_LSA_SCHEDULE (oa); + } + SET_FLAG (ospf6->flag, OSPF6_STUB_ROUTER); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_stub_router_admin, + no_ospf6_stub_router_admin_cmd, + "no stub-router administrative", + NO_STR + "Make router a stub router\n" + "Advertise ability to be a transit router\n" + "Administratively applied, for an indefinite period\n") +{ + struct listnode *node; + struct ospf6_area *oa; + + if (CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) + { + for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) + { + OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); + OSPF6_ROUTER_LSA_SCHEDULE (oa); + } + UNSET_FLAG (ospf6->flag, OSPF6_STUB_ROUTER); + } + + return CMD_SUCCESS; +} + +DEFUN (ospf6_stub_router_startup, + ospf6_stub_router_startup_cmd, + "stub-router on-startup <5-86400>", + "Make router a stub router\n" + "Advertise inability to be a transit router\n" + "Automatically advertise as stub-router on startup of OSPF6\n" + "Time (seconds) to advertise self as stub-router\n") +{ + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_stub_router_startup, + no_ospf6_stub_router_startup_cmd, + "no stub-router on-startup", + NO_STR + "Make router a stub router\n" + "Advertise inability to be a transit router\n" + "Automatically advertise as stub-router on startup of OSPF6\n" + "Time (seconds) to advertise self as stub-router\n") +{ + return CMD_SUCCESS; +} + +DEFUN (ospf6_stub_router_shutdown, + ospf6_stub_router_shutdown_cmd, + "stub-router on-shutdown <5-86400>", + "Make router a stub router\n" + "Advertise inability to be a transit router\n" + "Automatically advertise as stub-router before shutdown\n" + "Time (seconds) to advertise self as stub-router\n") +{ + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_stub_router_shutdown, + no_ospf6_stub_router_shutdown_cmd, + "no stub-router on-shutdown", + NO_STR + "Make router a stub router\n" + "Advertise inability to be a transit router\n" + "Automatically advertise as stub-router before shutdown\n" + "Time (seconds) to advertise self as stub-router\n") +{ + return CMD_SUCCESS; +} + static void ospf6_show (struct vty *vty, struct ospf6 *o) { @@ -486,6 +581,9 @@ ospf6_show (struct vty *vty, struct ospf6 *o) /* Redistribute configuration */ /* XXX */ + if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) + vty_out (vty, " Router Is Stub Router%s", VNL); + /* LSAs */ vty_out (vty, " Number of AS scoped LSAs is %u%s", o->lsdb->count, VNL); @@ -654,6 +752,16 @@ DEFUN (show_ipv6_ospf6_route_type_detail, return CMD_SUCCESS; } +static void +ospf6_stub_router_config_write (struct vty *vty) +{ + if (CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) + { + vty_out (vty, " stub-router administrative%s", VNL); + } + return; +} + /* OSPF configuration write function. */ static int config_write_ospf6 (struct vty *vty) @@ -674,6 +782,7 @@ config_write_ospf6 (struct vty *vty) if (ospf6->router_id_static != 0) vty_out (vty, " router-id %s%s", router_id, VNL); + ospf6_stub_router_config_write (vty); ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); ospf6_spf_config_write (vty); @@ -729,6 +838,14 @@ ospf6_top_init (void) install_element (OSPF6_NODE, &ospf6_router_id_cmd); install_element (OSPF6_NODE, &ospf6_interface_area_cmd); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd); + install_element (OSPF6_NODE, &ospf6_stub_router_admin_cmd); + install_element (OSPF6_NODE, &no_ospf6_stub_router_admin_cmd); + /* For a later time + install_element (OSPF6_NODE, &ospf6_stub_router_startup_cmd); + install_element (OSPF6_NODE, &no_ospf6_stub_router_startup_cmd); + install_element (OSPF6_NODE, &ospf6_stub_router_shutdown_cmd); + install_element (OSPF6_NODE, &no_ospf6_stub_router_shutdown_cmd); + */ } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 27eb18cdd..02eb91547 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -76,6 +76,7 @@ struct ospf6 }; #define OSPF6_DISABLED 0x01 +#define OSPF6_STUB_ROUTER 0x02 /* global pointer for OSPF top data structure */ extern struct ospf6 *ospf6; From 3b220289a4d0da4539d965ca71e9479d68c87b11 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sat, 24 Aug 2013 08:00:44 +0000 Subject: [PATCH 0300/1342] ospf6d: handle seqnum wrapping Signed-off-by: Shrijeet Mukherjee Reviewed-by: Dinesh G Dutt [DL: mechanical adjust to rebase] [DL: adjust to removal of timerwheel code] Signed-off-by: David Lamparter --- ospf6d/ospf6_flood.c | 19 +++++++++++++++++++ ospf6d/ospf6_lsa.h | 3 +++ ospf6d/ospf6_lsdb.c | 13 ++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index e02a432f9..7f6b2850c 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -230,6 +230,25 @@ ospf6_install_lsa (struct ospf6_lsa *lsa) else lsa->expire = NULL; + if (OSPF6_LSA_IS_SEQWRAP(lsa) && + ! (CHECK_FLAG(lsa->flag,OSPF6_LSA_SEQWRAPPED) && + lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))) + { + if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) + zlog_debug("lsa install wrapping: sequence 0x%x", + ntohl(lsa->header->seqnum)); + SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); + /* in lieu of premature_aging, since we do not want to recreate this lsa + * and/or mess with timers etc, we just want to wrap the sequence number + * and reflood the lsa before continuing. + * NOTE: Flood needs to be called right after this function call, by the + * caller + */ + lsa->header->seqnum = htonl (OSPF_MAX_SEQUENCE_NUMBER); + lsa->header->age = htons (OSPF_LSA_MAXAGE); + ospf6_lsa_checksum (lsa->header); + } + /* actually install */ lsa->installed = now; ospf6_lsdb_add (lsa, lsa->lsdb); diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 998599ba4..ffd6ae0aa 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -109,6 +109,8 @@ struct ospf6_lsa_header #define OSPF6_LSA_IS_DIFFER(L1, L2) ospf6_lsa_is_differ (L1, L2) #define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == OSPF_LSA_MAXAGE) #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) +#define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1)) + struct ospf6_lsa { @@ -139,6 +141,7 @@ struct ospf6_lsa #define OSPF6_LSA_FLOODBACK 0x02 #define OSPF6_LSA_DUPLICATE 0x04 #define OSPF6_LSA_IMPLIEDACK 0x08 +#define OSPF6_LSA_SEQWRAPPED 0x20 struct ospf6_lsa_handler { diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index b13ae9b1f..5138d1c1c 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -465,7 +465,18 @@ ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) } if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) zlog_debug ("Remove MaxAge %s", lsa->name); - ospf6_lsdb_remove (lsa, lsdb); + if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)) + { + UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); + /* + * lsa->header->age = 0; + */ + lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER + 1); + ospf6_lsa_checksum (lsa->header); + thread_execute (master, ospf6_lsa_refresh, lsa, 0); + } else { + ospf6_lsdb_remove (lsa, lsdb); + } } return (reschedule); From 7a10a359e9740710c1e39c8be0f761f506795480 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sun, 25 Aug 2013 03:03:07 +0000 Subject: [PATCH 0301/1342] ospf6d: don't change SeqNum on initial DbDesc message The code was setting the DbDesc seqnum to the current seconds value of time if this was the initial DbDesc. However, the same code was getting invoked if the initial DbDesc was retransmitted. Caused ANVL test XX.XX to fail. Signed-off-by: Dinesh G Dutt Signed-off-by: David Lamparter --- ospf6d/ospf6_message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 82d2d340b..caebf5d6b 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1797,7 +1797,8 @@ ospf6_dbdesc_send (struct thread *thread) sizeof (struct ospf6_header)); /* if this is initial one, initialize sequence number for DbDesc */ - if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT)) + if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) && + (on->dbdesc_seqnum == 0)) { struct timeval tv; if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0) From 931b1b8c9a612665391ed43653c970fcb38bbbf0 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sun, 25 Aug 2013 03:03:15 +0000 Subject: [PATCH 0302/1342] ospf6d: increment dbdesc seqnum on SeqNumberMismatch/BadLsReq event As per RFC 2328, section 10.3, if the neighbor state machine reaches SeqNumberMismatch state when the NSM is in state Exchange or greater, "router increments the DD sequence number in the neighbor data structure, declares itself master (sets the master/slave bit to master), and starts sending Database Description Packets, with the initialize (I), more (M) and master (MS) bits set.". The existing code doesn't increment the DD SeqNum. This patch fixes that. Signed-off-by: Dinesh G Dutt Signed-off-by: David Lamparter --- ospf6d/ospf6_neighbor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 84f0b002c..b7d2e40db 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -484,6 +484,8 @@ seqnumber_mismatch (struct thread *thread) } THREAD_OFF (on->thread_send_dbdesc); + on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ + on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); @@ -520,6 +522,8 @@ bad_lsreq (struct thread *thread) } THREAD_OFF (on->thread_send_dbdesc); + on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ + on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); From e68a67672ccfabefadac36c66e88af997fb572b2 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sun, 25 Aug 2013 03:03:23 +0000 Subject: [PATCH 0303/1342] ospf6d: add LSA payload to show summary output Unlike OSPFv2, the LSID of an LSA isn't sufficient to know what the contents of the LSA are. Its useful for debugging and basic eyeball tests to see the contents of the LSA in the simple tabular format of "show ipv6 ospf6 database". This patch adds that output to the command. It replaces the existing fields of "duration, Chksum and Length" with a single field called Payload which is dependent on the LSA type. For Inter-Area Prefix, Intra-Area Prefix and AS-External LSAs, this will be the advertised prefix/prefix length, for Router LSAs, it is RtrID/IfID etc. Signed-off-by: Dinesh G Dutt Reviewed-by: Pradosh Mohapatra Reviewed-by: Scott Feldman [DL: rebase fix, line disappeared in ospf6_abr_originate_summary_to_area] Signed-off-by: David Lamparter --- ospf6d/ospf6_abr.c | 61 +++++++++++-- ospf6d/ospf6_asbr.c | 52 ++++++++--- ospf6d/ospf6_intra.c | 201 ++++++++++++++++++++++++++++++++++++++++++- ospf6d/ospf6_lsa.c | 77 +++++++++++++---- ospf6d/ospf6_lsa.h | 3 + 5 files changed, 356 insertions(+), 38 deletions(-) diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 3277e7d88..379a62ed0 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -764,12 +764,34 @@ ospf6_abr_reimport (struct ospf6_area *oa) /* Display functions */ +static char * +ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, + int buflen, int pos) +{ + struct ospf6_inter_prefix_lsa *prefix_lsa; + struct in6_addr in6; + + if (lsa != NULL) + { + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); + if (buf) + { + inet_ntop (AF_INET6, &in6, buf, buflen); + sprintf (&buf[strlen(buf)], "/%d", prefix_lsa->prefix.prefix_length); + } + } + + return (buf); +} + static int ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_prefix_lsa *prefix_lsa; - struct in6_addr in6; - char buf[64]; + char buf[INET6_ADDRSTRLEN]; prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); @@ -781,14 +803,32 @@ ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); - ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); - inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); - vty_out (vty, " Prefix: %s/%d%s", buf, - prefix_lsa->prefix.prefix_length, VNL); + vty_out (vty, " Prefix: %s%s", + ospf6_inter_area_prefix_lsa_get_prefix_str (lsa, buf, sizeof(buf), + 0), VNL); return 0; } +static char * +ospf6_inter_area_router_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, + int buflen, int pos) +{ + struct ospf6_inter_router_lsa *router_lsa; + + if (lsa != NULL) + { + router_lsa = (struct ospf6_inter_router_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + + if (buf) + inet_ntop (AF_INET, &router_lsa->router_id, buf, buflen); + } + + return (buf); +} + static int ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { @@ -802,6 +842,7 @@ ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) vty_out (vty, " Options: %s%s", buf, VNL); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (router_lsa), VNL); + inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); vty_out (vty, " Destination Router ID: %s%s", buf, VNL); @@ -855,14 +896,18 @@ struct ospf6_lsa_handler inter_prefix_handler = { OSPF6_LSTYPE_INTER_PREFIX, "Inter-Prefix", - ospf6_inter_area_prefix_lsa_show + "IAP", + ospf6_inter_area_prefix_lsa_show, + ospf6_inter_area_prefix_lsa_get_prefix_str, }; struct ospf6_lsa_handler inter_router_handler = { OSPF6_LSTYPE_INTER_ROUTER, "Inter-Router", - ospf6_inter_area_router_lsa_show + "IAR", + ospf6_inter_area_router_lsa_show, + ospf6_inter_area_router_lsa_get_prefix_str, }; void diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 1a0634ed2..27726c672 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1161,12 +1161,44 @@ ospf6_routemap_init (void) /* Display functions */ +static char * +ospf6_as_external_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, + int buflen, int pos) +{ + struct ospf6_as_external_lsa *external; + struct in6_addr in6; + int prefix_length = 0; + + if (lsa) + { + external = (struct ospf6_as_external_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + if (pos == 0) + { + ospf6_prefix_in6_addr (&in6, &external->prefix); + prefix_length = external->prefix.prefix_length; + } + else { + in6 = *((struct in6_addr *) + ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + + OSPF6_PREFIX_SPACE (external->prefix.prefix_length))); + } + if (buf) + { + inet_ntop (AF_INET6, &in6, buf, buflen); + if (prefix_length) + sprintf (&buf[strlen(buf)], "/%d", prefix_length); + } + } + return (buf); +} + static int ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; char buf[64]; - struct in6_addr in6, *forwarding; assert (lsa->header); external = (struct ospf6_as_external_lsa *) @@ -1191,19 +1223,15 @@ ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) ntohs (external->prefix.prefix_refer_lstype), VNL); - ospf6_prefix_in6_addr (&in6, &external->prefix); - inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); - vty_out (vty, " Prefix: %s/%d%s", buf, - external->prefix.prefix_length, VNL); + vty_out (vty, " Prefix: %s%s", + ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL); /* Forwarding-Address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { - forwarding = (struct in6_addr *) - ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + - OSPF6_PREFIX_SPACE (external->prefix.prefix_length)); - inet_ntop (AF_INET6, forwarding, buf, sizeof (buf)); - vty_out (vty, " Forwarding-Address: %s%s", buf, VNL); + vty_out (vty, " Forwarding-Address: %s%s", + ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 1), + VNL); } return 0; @@ -1257,7 +1285,9 @@ struct ospf6_lsa_handler as_external_handler = { OSPF6_LSTYPE_AS_EXTERNAL, "AS-External", - ospf6_as_external_lsa_show + "ASE", + ospf6_as_external_lsa_show, + ospf6_as_external_lsa_get_prefix_str }; void diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 025a77104..9c84e6574 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -56,6 +56,42 @@ u_int32_t conf_debug_ospf6_brouter_specific_area_id; /* RFC2740 3.4.3.1 Router-LSA */ /******************************/ +static char * +ospf6_router_lsa_get_nbr_id (struct ospf6_lsa *lsa, char *buf, int buflen, + int pos) +{ + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsdesc *lsdesc; + char *start, *end; + char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN]; + + if (lsa) + { + router_lsa = (struct ospf6_router_lsa *) + ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); + start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + + lsdesc = (struct ospf6_router_lsdesc *) + (start + pos*(sizeof (struct ospf6_router_lsdesc))); + if ((char *)lsdesc < end) + { + if (buf && (buflen > INET_ADDRSTRLEN*2)) + { + inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, + buf1, sizeof(buf1)); + inet_ntop (AF_INET, &lsdesc->neighbor_router_id, + buf2, sizeof(buf2)); + sprintf (buf, "%s/%s", buf2, buf1); + } + } + else + return NULL; + } + + return buf; +} + static int ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { @@ -334,6 +370,36 @@ ospf6_router_lsa_originate (struct thread *thread) /* RFC2740 3.4.3.2 Network-LSA */ /*******************************/ +static char * +ospf6_network_lsa_get_ar_id (struct ospf6_lsa *lsa, char *buf, int buflen, + int pos) +{ + char *start, *end, *current; + struct ospf6_network_lsa *network_lsa; + struct ospf6_network_lsdesc *lsdesc; + + if (lsa) + { + network_lsa = (struct ospf6_network_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + start = (char *) network_lsa + sizeof (struct ospf6_network_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + current = start + pos*(sizeof (struct ospf6_network_lsdesc)); + + if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) + { + lsdesc = (struct ospf6_network_lsdesc *)current; + if (buf) + inet_ntop (AF_INET, &lsdesc->router_id, buf, buflen); + } + else + return NULL; + } + + return (buf); +} + static int ospf6_network_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { @@ -480,6 +546,61 @@ ospf6_network_lsa_originate (struct thread *thread) /* RFC2740 3.4.3.6 Link-LSA */ /****************************/ +static char * +ospf6_link_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, + int pos) +{ + char *start, *end, *current; + struct ospf6_link_lsa *link_lsa; + struct in6_addr in6; + struct ospf6_prefix *prefix; + int cnt = 0, prefixnum; + + if (lsa) + { + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + if (pos == 0) { + inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, buflen); + return (buf); + } + + prefixnum = ntohl (link_lsa->prefix_num); + if (pos > prefixnum) + return (NULL); + + start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + current = start; + + do + { + prefix = (struct ospf6_prefix *) current; + if (prefix->prefix_length == 0 || + current + OSPF6_PREFIX_SIZE (prefix) > end) + { + return (NULL); + } + + if (cnt < pos) + { + current = start + pos*OSPF6_PREFIX_SIZE(prefix); + cnt++; + } + else + { + memset (&in6, 0, sizeof (in6)); + memcpy (&in6, OSPF6_PREFIX_BODY (prefix), + OSPF6_PREFIX_SPACE (prefix->prefix_length)); + inet_ntop (AF_INET6, &in6, buf, buflen); + return (buf); + } + } while (current <= end); + } + return (NULL); +} + static int ospf6_link_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { @@ -632,6 +753,56 @@ ospf6_link_lsa_originate (struct thread *thread) /*****************************************/ /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */ /*****************************************/ +static char * +ospf6_intra_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, + int buflen, int pos) +{ + char *start, *end, *current; + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + struct in6_addr in6; + int prefixnum, cnt = 0; + struct ospf6_prefix *prefix; + + if (lsa) + { + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + prefixnum = ntohs (intra_prefix_lsa->prefix_num); + if (pos > prefixnum) + return (NULL); + + start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + current = start; + + do + { + prefix = (struct ospf6_prefix *) current; + if (prefix->prefix_length == 0 || + current + OSPF6_PREFIX_SIZE (prefix) > end) + { + return NULL; + } + + if (cnt < pos) + { + current = start + pos*OSPF6_PREFIX_SIZE(prefix); + cnt++; + } + else + { + memset (&in6, 0, sizeof (in6)); + memcpy (&in6, OSPF6_PREFIX_BODY (prefix), + OSPF6_PREFIX_SPACE (prefix->prefix_length)); + inet_ntop (AF_INET6, &in6, buf, buflen); + sprintf(&buf[strlen(buf)], "/%d", prefix->prefix_length); + return (buf); + } + } while (current <= end); + } + return (buf); +} static int ospf6_intra_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) @@ -1103,6 +1274,20 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) if (end < current + OSPF6_PREFIX_SIZE (op)) break; + /* Appendix A.4.1.1 */ + if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) || + CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA)) + { + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + { + ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op), + buf, sizeof (buf)); + zlog_debug ("%s: Skipping Prefix %s has NU/LA option set", + __func__, buf); + } + continue; + } + route = ospf6_route_create (); memset (&route->prefix, 0, sizeof (struct prefix)); @@ -1454,28 +1639,36 @@ struct ospf6_lsa_handler router_handler = { OSPF6_LSTYPE_ROUTER, "Router", - ospf6_router_lsa_show + "Rtr", + ospf6_router_lsa_show, + ospf6_router_lsa_get_nbr_id }; struct ospf6_lsa_handler network_handler = { OSPF6_LSTYPE_NETWORK, "Network", - ospf6_network_lsa_show + "Net", + ospf6_network_lsa_show, + ospf6_network_lsa_get_ar_id }; struct ospf6_lsa_handler link_handler = { OSPF6_LSTYPE_LINK, "Link", - ospf6_link_lsa_show + "Lnk", + ospf6_link_lsa_show, + ospf6_link_lsa_get_prefix_str }; struct ospf6_lsa_handler intra_prefix_handler = { OSPF6_LSTYPE_INTRA_PREFIX, "Intra-Prefix", - ospf6_intra_prefix_lsa_show + "INP", + ospf6_intra_prefix_lsa_show, + ospf6_intra_prefix_lsa_get_prefix_str }; void diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 592aad9bc..4aa2b12ff 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -74,8 +74,10 @@ ospf6_unknown_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) struct ospf6_lsa_handler unknown_handler = { OSPF6_LSTYPE_UNKNOWN, - "unknown", + "Unknown", + "Unk", ospf6_unknown_lsa_show, + NULL, OSPF6_LSA_DEBUG, }; @@ -118,6 +120,20 @@ ospf6_lstype_name (u_int16_t type) return buf; } +const char * +ospf6_lstype_short_name (u_int16_t type) +{ + static char buf[8]; + struct ospf6_lsa_handler *handler; + + handler = ospf6_get_lsa_handler (type); + if (handler && handler != &unknown_handler) + return handler->short_name; + + snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type)); + return buf; +} + u_char ospf6_lstype_debug (u_int16_t type) { @@ -371,17 +387,19 @@ ospf6_lsa_header_print (struct ospf6_lsa *lsa) void ospf6_lsa_show_summary_header (struct vty *vty) { - vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s", + vty_out (vty, "%-4s %-15s%-15s%4s %8s %30s%s", "Type", "LSId", "AdvRouter", "Age", "SeqNum", - "Cksm", "Len", "Duration", VNL); + "Payload", VNL); } void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[16], id[16]; - struct timeval now, res; - char duration[16]; + int type; + struct ospf6_lsa_handler *handler; + char buf[64], tmpbuf[80]; + int cnt = 0; assert (lsa); assert (lsa->header); @@ -390,16 +408,38 @@ ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); - quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); - timersub (&now, &lsa->installed, &res); - timerstring (&res, duration, sizeof (duration)); - - vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s", - ospf6_lstype_name (lsa->header->type), - id, adv_router, ospf6_lsa_age_current (lsa), - (u_long) ntohl (lsa->header->seqnum), - ntohs (lsa->header->checksum), ntohs (lsa->header->length), - duration, VNL); + type = ntohs(lsa->header->type); + handler = ospf6_get_lsa_handler (lsa->header->type); + if ((type == OSPF6_LSTYPE_INTER_PREFIX) || + (type == OSPF6_LSTYPE_INTER_ROUTER) || + (type == OSPF6_LSTYPE_AS_EXTERNAL)) + { + vty_out (vty, "%-4s %-15s%-15s%4hu %8lx %30s%s", + ospf6_lstype_short_name (lsa->header->type), + id, adv_router, ospf6_lsa_age_current (lsa), + (u_long) ntohl (lsa->header->seqnum), + handler->get_prefix_str(lsa, buf, sizeof(buf), 0), VNL); + } + else if (type != OSPF6_LSTYPE_UNKNOWN) + { + sprintf (tmpbuf, "%-4s %-15s%-15s%4hu %8lx", + ospf6_lstype_short_name (lsa->header->type), + id, adv_router, ospf6_lsa_age_current (lsa), + (u_long) ntohl (lsa->header->seqnum)); + + while (handler->get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL) + { + vty_out (vty, "%s %30s%s", tmpbuf, buf, VNL); + cnt++; + } + } + else + { + vty_out (vty, "%-4s %-15s%-15s%4hu %8lx%s", + ospf6_lstype_short_name (lsa->header->type), + id, adv_router, ospf6_lsa_age_current (lsa), + (u_long) ntohl (lsa->header->seqnum), VNL); + } } void @@ -464,6 +504,8 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[64], id[64]; struct ospf6_lsa_handler *handler; + struct timeval now, res; + char duration[16]; assert (lsa && lsa->header); @@ -471,6 +513,10 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); + timersub (&now, &lsa->installed, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), ospf6_lstype_name (lsa->header->type), VNL); vty_out (vty, "Link State ID: %s%s", id, VNL); @@ -480,6 +526,7 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) vty_out (vty, "CheckSum: %#06hx Length: %hu%s", ntohs (lsa->header->checksum), ntohs (lsa->header->length), VNL); + vty_out (vty, "Duration: %s%s", duration, VNL); handler = ospf6_get_lsa_handler (lsa->header->type); if (handler->show == NULL) diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index ffd6ae0aa..aed89df29 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -147,7 +147,9 @@ struct ospf6_lsa_handler { u_int16_t type; /* host byte order */ const char *name; + const char *short_name; int (*show) (struct vty *, struct ospf6_lsa *); + char *(*get_prefix_str) (struct ospf6_lsa *, char *buf, int buflen, int pos); u_char debug; }; @@ -210,6 +212,7 @@ extern struct ospf6_lsa_handler unknown_handler; /* Function Prototypes */ extern const char *ospf6_lstype_name (u_int16_t type); +extern const char *ospf6_lstype_short_name (u_int16_t type); extern u_char ospf6_lstype_debug (u_int16_t type); extern int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); From 01879114f73adaf1cd4c9f5e7ae1550b72ff9ca9 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sun, 25 Aug 2013 03:03:31 +0000 Subject: [PATCH 0304/1342] ospf6d: handle Prefix and Router Options bits correctly Ensure that prefixes with the NU/LA bit set do not get added to the routing table. Ensure that routers with the V6/R bit set do not get added as transit routes. Signed-off-by: Dinesh Dutt [DL: adjust to rebase] Signed-off-by: David Lamparter --- ospf6d/ospf6_abr.c | 33 +++++++++++++++++++++++++++++---- ospf6d/ospf6_asbr.c | 7 +++++++ ospf6d/ospf6_intra.c | 4 ++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 379a62ed0..54404ab87 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -537,13 +537,13 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) int i; char buf[64]; int is_debug = 0; + struct ospf6_inter_prefix_lsa *prefix_lsa = NULL; + struct ospf6_inter_router_lsa *router_lsa = NULL; memset (&prefix, 0, sizeof (prefix)); if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { - struct ospf6_inter_prefix_lsa *prefix_lsa; - if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) { is_debug++; @@ -564,8 +564,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) } else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) { - struct ospf6_inter_router_lsa *router_lsa; - if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER)) { is_debug++; @@ -632,6 +630,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) } /* (3) if the prefix is equal to an active configured address range */ + /* or if the NU bit is set in the prefix */ if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { range = ospf6_route_lookup (&prefix, oa->range_table); @@ -643,6 +642,32 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_route_remove (old, table); return; } + + if (CHECK_FLAG (prefix_lsa->prefix.prefix_options, + OSPF6_PREFIX_OPTION_NU) || + CHECK_FLAG (prefix_lsa->prefix.prefix_options, + OSPF6_PREFIX_OPTION_LA)) + { + if (is_debug) + zlog_debug ("Prefix has NU/LA bit set, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } + } + + if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) + { + /* To pass test suites */ + if (! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_R) || + ! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_V6)) + { + if (is_debug) + zlog_debug ("Prefix has NU/LA bit set, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } } /* (4) if the routing table entry for the ABR does not exist */ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 27726c672..60df6e6c9 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -181,6 +181,13 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) return; } + if (CHECK_FLAG(external->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU)) + { + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + zlog_debug ("Ignore LSA with NU bit set Metric"); + return; + } + ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id); asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table); if (asbr_entry == NULL || diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 9c84e6574..e86e46bf7 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1562,6 +1562,10 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) ! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_B)) continue; + if (! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_V6) || + ! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_R)) + continue; + copy = ospf6_route_copy (brouter); copy->type = OSPF6_DEST_TYPE_ROUTER; copy->path.area_id = oa->area_id; From 7cf997226e86d98839f1e7872ca98b023ffea98e Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Sun, 25 Aug 2013 03:03:39 +0000 Subject: [PATCH 0305/1342] ospf6d: don't send LSAck on an interface if we've flooded the LSU out that i/f If we flood an LSA back out the same interface we received it from, don't send an LSAck out that interface for that LSA. This is as per RFC 2328, section 13.5 Signed-off-by: Dinesh G Dutt Reviewed-by: Pradosh Mohapatra Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_flood.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 7f6b2850c..dc9ecbfb0 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -387,11 +387,15 @@ ospf6_flood_interface (struct ospf6_neighbor *from, /* (4) If the new LSA was received on this interface, and the interface state is BDR, examin next interface */ - if (from && from->ospf6_if == oi && oi->state == OSPF6_INTERFACE_BDR) + if (from && from->ospf6_if == oi) { - if (is_debug) - zlog_debug ("Received is from the I/F, itself BDR, next interface"); - return; + if (oi->state == OSPF6_INTERFACE_BDR) + { + if (is_debug) + zlog_debug ("Received is from the I/F, itself BDR, next interface"); + return; + } + SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK); } /* (5) flood the LSA out the interface. */ @@ -560,15 +564,6 @@ ospf6_acknowledge_lsa_bdrouter (struct ospf6_lsa *lsa, int ismore_recent, assert (from && from->ospf6_if); oi = from->ospf6_if; - /* LSA has been flood back out receiving interface. - No acknowledgement sent. */ - if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK)) - { - if (is_debug) - zlog_debug ("No acknowledgement (BDR & FloodBack)"); - return; - } - /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgement sent if advertisement received from Designated Router, From 3d35ca482babab4267570143b8327fc894df0ff8 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Mon, 26 Aug 2013 03:40:16 +0000 Subject: [PATCH 0306/1342] ospf6d: add 'log-adjacency-changes [detail]' Similar to OSPFv2, add support for 'log-adjacency-changes [detail]' to log changes in adjacency state of ospfv3 neighbors. Signed-off-by: Pradosh Mohapatra Reviewed-by: Dinesh G Dutt Reviewed-by: Scott Feldman Reviewed-by: Shrijeet Mukherjee Signed-off-by: David Lamparter --- ospf6d/ospf6_neighbor.c | 57 +++++++++++++++++++++++--------- ospf6d/ospf6_neighbor.h | 38 +++++++++++++++++++++ ospf6d/ospf6_top.c | 73 +++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_top.h | 5 +++ 4 files changed, 157 insertions(+), 16 deletions(-) diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index b7d2e40db..fb209fdfa 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -142,7 +142,7 @@ ospf6_neighbor_delete (struct ospf6_neighbor *on) } static void -ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on) +ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int event) { u_char prev_state; @@ -158,11 +158,23 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on) /* log */ if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) { - zlog_debug ("Neighbor state change %s: [%s]->[%s]", on->name, + zlog_debug ("Neighbor state change %s: [%s]->[%s] (%s)", on->name, ospf6_neighbor_state_str[prev_state], - ospf6_neighbor_state_str[next_state]); + ospf6_neighbor_state_str[next_state], + ospf6_neighbor_event_string(event)); } + /* Optionally notify about adjacency changes */ + if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, + OSPF6_LOG_ADJACENCY_CHANGES) && + (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, + OSPF6_LOG_ADJACENCY_DETAIL) || + (next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state))) + zlog_notice("AdjChg: Nbr %s: %s -> %s (%s)", on->name, + ospf6_neighbor_state_str[prev_state], + ospf6_neighbor_state_str[next_state], + ospf6_neighbor_event_string(event)); + if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL) { OSPF6_ROUTER_LSA_SCHEDULE (on->ospf6_if->area); @@ -223,7 +235,8 @@ hello_received (struct thread *thread) on->ospf6_if->dead_interval); if (on->state <= OSPF6_NEIGHBOR_DOWN) - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on, + OSPF6_NEIGHBOR_EVENT_HELLO_RCVD); return 0; } @@ -246,11 +259,13 @@ twoway_received (struct thread *thread) if (! need_adjacency (on)) { - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on, + OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); return 0; } - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, + OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); @@ -327,7 +342,8 @@ negotiation_done (struct thread *thread) } UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXCHANGE, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXCHANGE, on, + OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE); return 0; } @@ -355,10 +371,12 @@ exchange_done (struct thread *thread) */ if (on->request_list->count == 0) - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on, + OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); else { - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on, + OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); if (on->thread_send_lsreq == NULL) on->thread_send_lsreq = @@ -408,7 +426,8 @@ loading_done (struct thread *thread) assert (on->request_list->count == 0); - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on, + OSPF6_NEIGHBOR_EVENT_LOADING_DONE); return 0; } @@ -427,7 +446,8 @@ adj_ok (struct thread *thread) if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency (on)) { - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, + OSPF6_NEIGHBOR_EVENT_ADJ_OK); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); @@ -440,7 +460,8 @@ adj_ok (struct thread *thread) else if (on->state >= OSPF6_NEIGHBOR_EXSTART && ! need_adjacency (on)) { - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on, + OSPF6_NEIGHBOR_EVENT_ADJ_OK); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; @@ -469,7 +490,8 @@ seqnumber_mismatch (struct thread *thread) if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *SeqNumberMismatch*", on->name); - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, + OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); @@ -507,7 +529,8 @@ bad_lsreq (struct thread *thread) if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *BadLSReq*", on->name); - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, + OSPF6_NEIGHBOR_EVENT_BAD_LSREQ); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); @@ -545,7 +568,8 @@ oneway_received (struct thread *thread) if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *1Way-Received*", on->name); - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on, + OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD); thread_add_event (master, neighbor_change, on->ospf6_if, 0); ospf6_lsdb_remove_all (on->summary_list); @@ -580,7 +604,8 @@ inactivity_timer (struct thread *thread) on->drouter = on->prev_drouter = 0; on->bdrouter = on->prev_bdrouter = 0; - ospf6_neighbor_state_change (OSPF6_NEIGHBOR_DOWN, on); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_DOWN, on, + OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); thread_add_event (master, neighbor_change, on->ospf6_if, 0); listnode_delete (on->ospf6_if->neighbor_list, on); diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 750e1b242..888218980 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -108,6 +108,44 @@ struct ospf6_neighbor #define OSPF6_NEIGHBOR_LOADING 7 #define OSPF6_NEIGHBOR_FULL 8 +/* Neighbor Events */ +#define OSPF6_NEIGHBOR_EVENT_NO_EVENT 0 +#define OSPF6_NEIGHBOR_EVENT_HELLO_RCVD 1 +#define OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD 2 +#define OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE 3 +#define OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE 4 +#define OSPF6_NEIGHBOR_EVENT_LOADING_DONE 5 +#define OSPF6_NEIGHBOR_EVENT_ADJ_OK 6 +#define OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH 7 +#define OSPF6_NEIGHBOR_EVENT_BAD_LSREQ 8 +#define OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD 9 +#define OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER 10 +#define OSPF6_NEIGHBOR_EVENT_MAX_EVENT 11 + +static const char *ospf6_neighbor_event_str[] = + { + "NoEvent", + "HelloReceived", + "2-WayReceived", + "NegotiationDone", + "ExchangeDone", + "LoadingDone", + "AdjOK?", + "SeqNumberMismatch", + "BadLSReq", + "1-WayReceived", + "InactivityTimer", + }; + +static const char *ospf6_neighbor_event_string (int event) +{ + #define OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING "UnknownEvent" + + if (event < OSPF6_NEIGHBOR_EVENT_MAX_EVENT) + return ospf6_neighbor_event_str[event]; + return OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING; +} + extern const char *ospf6_neighbor_state_str[]; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index dec7096cf..1f7cdc854 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -338,6 +338,56 @@ DEFUN (ospf6_router_id, return CMD_SUCCESS; } +DEFUN (ospf6_log_adjacency_changes, + ospf6_log_adjacency_changes_cmd, + "log-adjacency-changes", + "Log changes in adjacency state\n") +{ + struct ospf6 *ospf6 = vty->index; + + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + return CMD_SUCCESS; +} + +DEFUN (ospf6_log_adjacency_changes_detail, + ospf6_log_adjacency_changes_detail_cmd, + "log-adjacency-changes detail", + "Log changes in adjacency state\n" + "Log all state changes\n") +{ + struct ospf6 *ospf6 = vty->index; + + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_log_adjacency_changes, + no_ospf6_log_adjacency_changes_cmd, + "no log-adjacency-changes", + NO_STR + "Log changes in adjacency state\n") +{ + struct ospf6 *ospf6 = vty->index; + + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_log_adjacency_changes_detail, + no_ospf6_log_adjacency_changes_detail_cmd, + "no log-adjacency-changes detail", + NO_STR + "Log changes in adjacency state\n" + "Log all state changes\n") +{ + struct ospf6 *ospf6 = vty->index; + + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + return CMD_SUCCESS; +} + DEFUN (ospf6_interface_area, ospf6_interface_area_cmd, "interface IFNAME area A.B.C.D", @@ -592,6 +642,16 @@ ospf6_show (struct vty *vty, struct ospf6 *o) vty_out (vty, " Number of areas in this router is %u%s", listcount (o->area_list), VNL); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) + { + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) + vty_out(vty, " All adjacency changes are logged%s",VTY_NEWLINE); + else + vty_out(vty, " Adjacency changes are logged%s",VTY_NEWLINE); + } + + vty_out (vty, "%s",VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (o->area_list, n, oa)) ospf6_area_show (vty, oa); } @@ -782,6 +842,15 @@ config_write_ospf6 (struct vty *vty) if (ospf6->router_id_static != 0) vty_out (vty, " router-id %s%s", router_id, VNL); + /* log-adjacency-changes flag print. */ + if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) + { + vty_out(vty, " log-adjacency-changes"); + if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) + vty_out(vty, " detail"); + vty_out(vty, "%s", VTY_NEWLINE); + } + ospf6_stub_router_config_write (vty); ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); @@ -836,6 +905,10 @@ ospf6_top_init (void) install_default (OSPF6_NODE); install_element (OSPF6_NODE, &ospf6_router_id_cmd); + install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_cmd); + install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd); + install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd); + install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_detail_cmd); install_element (OSPF6_NODE, &ospf6_interface_area_cmd); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd); install_element (OSPF6_NODE, &ospf6_stub_router_admin_cmd); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 02eb91547..9d7cfd919 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -60,6 +60,11 @@ struct ospf6 u_char flag; + /* Configured flags */ + u_char config_flags; +#define OSPF6_LOG_ADJACENCY_CHANGES (1 << 0) +#define OSPF6_LOG_ADJACENCY_DETAIL (1 << 1) + /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ From a0edf6740e8203abec1ee3efa344a417c16fec7b Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Mon, 26 Aug 2013 03:40:23 +0000 Subject: [PATCH 0307/1342] ospf6d: add SPF logs, statistics, and display of SPF parameters Signed-off-by: Pradosh Mohapatra Reviewed-by: Scott Feldman [DL: adapted to rebase / readded randomly lost line] [DL: killed timeval_subtract] Signed-off-by: David Lamparter --- ospf6d/ospf6_area.c | 6 ++-- ospf6d/ospf6_interface.c | 20 +++++++++--- ospf6d/ospf6_intra.c | 2 +- ospf6d/ospf6_spf.c | 52 ++++++++++++++++++++++++++++-- ospf6d/ospf6_spf.h | 69 +++++++++++++++++++++++++++++++++++++++- ospf6d/ospf6_top.c | 29 ++++++++++++++++- ospf6d/ospf6_top.h | 2 ++ ospf6d/ospf6d.h | 11 +++++++ 8 files changed, 180 insertions(+), 11 deletions(-) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 37e5c0045..b09d9613c 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -67,7 +67,8 @@ ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa) zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } - ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6)); + ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6), + ospf6_lsadd_to_spf_reason(lsa)); break; case OSPF6_LSTYPE_INTRA_PREFIX: @@ -97,7 +98,8 @@ ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa) zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } - ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6)); + ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6), + ospf6_lsremove_to_spf_reason(lsa)); break; case OSPF6_LSTYPE_INTRA_PREFIX: diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index d1f5cba1c..fee1632a1 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -73,7 +73,7 @@ ospf6_interface_lookup_by_ifindex (int ifindex) /* schedule routing table recalculation */ static void -ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) +ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa, unsigned int reason) { struct ospf6_interface *oi; @@ -86,7 +86,7 @@ ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) case OSPF6_LSTYPE_LINK: if (oi->state == OSPF6_INTERFACE_DR) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); - ospf6_spf_schedule (oi->area->ospf6); + ospf6_spf_schedule (oi->area->ospf6, reason); break; default: @@ -94,6 +94,18 @@ ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) } } +static void +ospf6_interface_lsdb_hook_add (struct ospf6_lsa *lsa) +{ + ospf6_interface_lsdb_hook(lsa, ospf6_lsadd_to_spf_reason(lsa)); +} + +static void +ospf6_interface_lsdb_hook_remove (struct ospf6_lsa *lsa) +{ + ospf6_interface_lsdb_hook(lsa, ospf6_lsremove_to_spf_reason(lsa)); +} + static u_char ospf6_default_iftype(struct interface *ifp) { @@ -152,8 +164,8 @@ ospf6_interface_create (struct interface *ifp) oi->lsupdate_list = ospf6_lsdb_create (oi); oi->lsack_list = ospf6_lsdb_create (oi); oi->lsdb = ospf6_lsdb_create (oi); - oi->lsdb->hook_add = ospf6_interface_lsdb_hook; - oi->lsdb->hook_remove = ospf6_interface_lsdb_hook; + oi->lsdb->hook_add = ospf6_interface_lsdb_hook_add; + oi->lsdb->hook_remove = ospf6_interface_lsdb_hook_remove; oi->lsdb_self = ospf6_lsdb_create (oi); oi->route_connected = OSPF6_ROUTE_TABLE_CREATE (INTERFACE, CONNECTED_ROUTES); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index e86e46bf7..4ad7521e9 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -46,7 +46,7 @@ #include "ospf6_abr.h" #include "ospf6_flood.h" #include "ospf6d.h" - +#include "ospf6_spf.h" unsigned char conf_debug_ospf6_brouter = 0; u_int32_t conf_debug_ospf6_brouter_specific_router_id; diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 845e206c4..3ef5485fd 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -377,6 +377,36 @@ ospf6_spf_table_finish (struct ospf6_route_table *result_table) } } +static const char *ospf6_spf_reason_str[] = + { + "R+", + "R-", + "N+", + "N-", + "L+", + "L-", + "R*", + "N*", + }; + +void ospf6_spf_reason_string (unsigned int reason, char *buf, int size) +{ + int bit; + int len = 0; + + if (!buf) + return; + + for (bit = 0; bit <= (sizeof(ospf6_spf_reason_str) / sizeof(char *)); bit++) + { + if ((reason & (1 << bit)) && (len < size)) + { + len += snprintf((buf + len), (size - len), "%s%s", + (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]); + } + } +} + /* RFC2328 16.1. Calculating the shortest-path tree for an area */ /* RFC2740 3.8.1. Calculating the shortest path tree for an area */ void @@ -515,6 +545,8 @@ ospf6_spf_calculation_thread (struct thread *t) struct timeval start, end, runtime; struct listnode *node; struct ospf6_route *route; + int areas_processed = 0; + char rbuf[32]; ospf6 = (struct ospf6 *)THREAD_ARG (t); ospf6->t_spf_calc = NULL; @@ -536,6 +568,8 @@ ospf6_spf_calculation_thread (struct thread *t) ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa); ospf6_intra_route_calculation (oa); ospf6_intra_brouter_calculation (oa); + + areas_processed++; } if (ospf6->backbone) @@ -550,6 +584,7 @@ ospf6_spf_calculation_thread (struct thread *t) ospf6->backbone); ospf6_intra_route_calculation(ospf6->backbone); ospf6_intra_brouter_calculation(ospf6->backbone); + areas_processed++; } /* Redo summaries if required */ @@ -562,23 +597,36 @@ ospf6_spf_calculation_thread (struct thread *t) ospf6->ts_spf_duration = runtime; + ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf)); + if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF runtime: %ld sec %ld usec", runtime.tv_sec, runtime.tv_usec); + zlog_info("SPF processing: # Areas: %d, SPF runtime: %ld sec %ld usec, " + "Reason: %s\n", areas_processed, runtime.tv_sec, runtime.tv_usec, + rbuf); + ospf6->last_spf_reason = ospf6->spf_reason; + ospf6_reset_spf_reason(ospf6); return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ void -ospf6_spf_schedule (struct ospf6 *ospf6) +ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason) { unsigned long delay, elapsed, ht; struct timeval now, result; + ospf6_set_spf_reason(ospf6, reason); + if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) - zlog_debug ("SPF: calculation timer scheduled"); + { + char rbuf[32]; + ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf)); + zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf); + } /* OSPF instance does not exist. */ if (ospf6 == NULL) diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index 6c40424fd..b3481dc37 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -79,11 +79,77 @@ struct ospf6_vertex #define VERTEX_IS_TYPE(t, v) \ ((v)->type == OSPF6_VERTEX_TYPE_ ## t ? 1 : 0) +/* What triggered the SPF? */ +#define OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED (1 << 0) +#define OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED (1 << 1) +#define OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED (1 << 2) +#define OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED (1 << 3) +#define OSPF6_SPF_FLAGS_LINK_LSA_ADDED (1 << 4) +#define OSPF6_SPF_FLAGS_LINK_LSA_REMOVED (1 << 5) +#define OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED (1 << 6) +#define OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED (1 << 7) + +static inline void +ospf6_set_spf_reason (struct ospf6* ospf, unsigned int reason) +{ + ospf->spf_reason |= reason; +} + +static inline void +ospf6_reset_spf_reason (struct ospf6 *ospf) +{ + ospf->spf_reason = 0; +} + +static inline unsigned int +ospf6_lsadd_to_spf_reason (struct ospf6_lsa *lsa) +{ + unsigned int reason = 0; + + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_ROUTER: + reason = OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED; + break; + case OSPF6_LSTYPE_NETWORK: + reason = OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED; + break; + case OSPF6_LSTYPE_LINK: + reason = OSPF6_SPF_FLAGS_LINK_LSA_ADDED; + break; + default: + break; + } + return (reason); +} + +static inline unsigned int +ospf6_lsremove_to_spf_reason (struct ospf6_lsa *lsa) +{ + unsigned int reason = 0; + + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_ROUTER: + reason = OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED; + break; + case OSPF6_LSTYPE_NETWORK: + reason = OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED; + break; + case OSPF6_LSTYPE_LINK: + reason = OSPF6_SPF_FLAGS_LINK_LSA_REMOVED; + break; + default: + break; + } + return (reason); +} + extern void ospf6_spf_table_finish (struct ospf6_route_table *result_table); extern void ospf6_spf_calculation (u_int32_t router_id, struct ospf6_route_table *result_table, struct ospf6_area *oa); -extern void ospf6_spf_schedule (struct ospf6 *ospf); +extern void ospf6_spf_schedule (struct ospf6 *ospf, unsigned int reason); extern void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v); @@ -92,6 +158,7 @@ extern void ospf6_spf_config_write (struct vty *vty); extern int config_write_ospf6_debug_spf (struct vty *vty); extern void install_element_ospf6_debug_spf (void); extern void ospf6_spf_init (void); +extern void ospf6_spf_reason_string (unsigned int reason, char *buf, int size); #endif /* OSPF6_SPF_H */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 1f7cdc854..f83e6ab5e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -615,7 +615,8 @@ ospf6_show (struct vty *vty, struct ospf6 *o) struct listnode *n; struct ospf6_area *oa; char router_id[16], duration[32]; - struct timeval now, running; + struct timeval now, running, result; + char buf[32], rbuf[32]; /* process id, router id */ inet_ntop (AF_INET, &o->router_id, router_id, sizeof (router_id)); @@ -631,6 +632,32 @@ ospf6_show (struct vty *vty, struct ospf6 *o) /* Redistribute configuration */ /* XXX */ + /* Show SPF parameters */ + vty_out(vty, " Initial SPF scheduling delay %d millisec(s)%s" + " Minimum hold time between consecutive SPFs %d millsecond(s)%s" + " Maximum hold time between consecutive SPFs %d millsecond(s)%s" + " Hold time multiplier is currently %d%s", + o->spf_delay, VNL, + o->spf_holdtime, VNL, + o->spf_max_holdtime, VNL, + o->spf_hold_multiplier, VNL); + + vty_out(vty, " SPF algorithm "); + if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) + { + timersub(&now, &o->ts_spf, &result); + timerstring(&result, buf, sizeof(buf)); + ospf6_spf_reason_string(o->last_spf_reason, rbuf, sizeof(rbuf)); + vty_out(vty, "last executed %s ago, reason %s%s", buf, rbuf, VNL); + vty_out (vty, " Last SPF duration %ld sec %ld usec%s", + o->ts_spf_duration.tv_sec, o->ts_spf_duration.tv_usec, VNL); + } + else + vty_out(vty, "has not been run$%s", VNL); + threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf)); + vty_out (vty, " SPF timer %s%s%s", + (o->t_spf_calc ? "due in " : "is "), buf, VNL); + if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) vty_out (vty, " Router Is Stub Router%s", VNL); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 9d7cfd919..866f92f98 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -70,9 +70,11 @@ struct ospf6 unsigned int spf_holdtime; /* SPF hold time. */ unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ + unsigned int spf_reason; /* reason bits while scheduling SPF */ struct timeval ts_spf; /* SPF calculation time stamp. */ struct timeval ts_spf_duration; /* Execution time of last SPF */ + unsigned int last_spf_reason; /* Last SPF reason */ /* Threads */ struct thread *t_spf_calc; /* SPF calculation timer. */ diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 13699d612..0c86386a7 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -101,6 +101,17 @@ extern struct thread_master *master; zlog_warn ("strftime error"); \ } while (0) +#define threadtimer_string(now, t, buf, size) \ + do { \ + struct timeval result; \ + if (!t) \ + snprintf(buf, size, "inactive"); \ + else { \ + timersub(&t->u.sands, &now, &result); \ + timerstring(&result, buf, size); \ + } \ +} while (0) + /* for commands */ #define OSPF6_AREA_STR "Area information\n" #define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n" From ba960d5ae43e49991ed70fbe9ffa2e4567437a31 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Mon, 26 Aug 2013 03:40:37 +0000 Subject: [PATCH 0308/1342] ospf6d: fix integrated config With integrated config, the line defining an interface to be p2p is defined before assigning the interface to an area. When during the interface transition, there is an attempt to generate a router LSA, the process crashes. This fix addresses that. Signed-off-by: Dinesh G Dutt Reviewed-by: Pradosh Mohapatra Reviewed-by: Scott Feldman Signed-off-by: David Lamparter --- ospf6d/ospf6_interface.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index fee1632a1..111b929a5 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -654,6 +654,14 @@ interface_up (struct thread *thread) return 0; } + /* If no area assigned, return */ + if (oi->area == NULL) + { + zlog_debug ("%s: Not scheduleing Hello for %s as there is no area assigned yet", __func__, + oi->interface->name); + return 0; + } + /* Join AllSPFRouters */ ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP); From 7d4aa1d57d54a57aae78e6b12cf4524e2c43a514 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 13 Dec 2012 16:10:05 +0100 Subject: [PATCH 0309/1342] ospf6d: don't run DR election early on "ipv6 ospf6 priority" On changing the router priority, DR election should only be run when it was completed at least once before. Signed-off-by: Christian Franke --- ospf6d/ospf6_interface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 111b929a5..c692f2c7d 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1333,7 +1333,10 @@ DEFUN (ipv6_ospf6_priority, oi->priority = strtol (argv[0], NULL, 10); - if (oi->area) + if (oi->area && + (oi->state == OSPF6_INTERFACE_DROTHER || + oi->state == OSPF6_INTERFACE_BDR || + oi->state == OSPF6_INTERFACE_DR)) ospf6_interface_state_change (dr_election (oi), oi); return CMD_SUCCESS; From 1579a67f130ca34df9acefac14ebcdfdd8f6600a Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 8 Mar 2013 02:35:38 +0100 Subject: [PATCH 0310/1342] ospf6d: set cmsg size correctly On both Linux and FreeBSD, msg_controllen should be set to CMSG_LEN, not CMSG_SPACE. This avoids sending 4 bytes of trailing garbage to the kernel. Signed-off-by: Christian Franke --- ospf6d/ospf6_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index eed7f9d66..74cfbec7c 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -206,7 +206,7 @@ ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, smsghdr.msg_name = (caddr_t) &dst_sin6; smsghdr.msg_namelen = sizeof (struct sockaddr_in6); smsghdr.msg_control = (caddr_t) cmsgbuf; - smsghdr.msg_controllen = sizeof (cmsgbuf); + smsghdr.msg_controllen = scmsgp->cmsg_len; retval = sendmsg (ospf6_sock, &smsghdr, 0); if (retval != iov_totallen (message)) From 37531a7ec380554b18c004bcae9f5a070385d132 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 13 Dec 2012 13:50:28 +0100 Subject: [PATCH 0311/1342] ospf6d: clear DR info on interface_down This fixes an issue where ospf6d would send incorrect hellos and perform wrong DR election when an interface went down and up again. Signed-off-by: Christian Franke --- ospf6d/ospf6_interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index c692f2c7d..86c0bf688 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -769,6 +769,10 @@ interface_down (struct thread *thread) list_delete_all_node (oi->neighbor_list); + /* When interface state is reset, also reset information about + * DR election, as it is no longer valid. */ + oi->drouter = oi->prev_drouter = htonl(0); + oi->bdrouter = oi->prev_bdrouter = htonl(0); return 0; } From 6ee06fa9ed91412cb745668d462031cdbe2642e0 Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Sun, 12 Jan 2014 18:30:13 +0000 Subject: [PATCH 0312/1342] bgpd: bgpd-set-v4-nexthop-for-v6-peering.patch BGP: While advertising v4 prefixes over a v6 session, set the correct v4 nexthop. ISSUE: For an IPv6 peer, BGPd sets the local router-id as the next-hop's v4 address. This is incorrect as the router-id may not be a valid next-hop to be included in UPDATEs that contain v4 prefixes. PATCH: Set the v4 address in the next-hop field based on the interface that the peering is on (directly connected interface or loopback). Signed-off-by: Pradosh Mohapatra Reviewed-by: Scott Feldman Acked-by: Feng Lu --- bgpd/bgp_zebra.c | 24 ++++++++++++++++++++++-- lib/prefix.h | 10 ++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 604438304..26b97c2c4 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -534,6 +534,25 @@ if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) } #endif /* HAVE_IPV6 */ +static int +if_get_ipv4_address (struct interface *ifp, struct in_addr *addr) +{ + struct listnode *cnode; + struct connected *connected; + struct prefix *cp; + + for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) + { + cp = connected->address; + if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4))) + { + *addr = cp->u.prefix4; + return 1; + } + } + return 0; +} + int bgp_nexthop_set (union sockunion *local, union sockunion *remote, struct bgp_nexthop *nexthop, struct peer *peer) @@ -592,8 +611,9 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, { struct interface *direct = NULL; - /* IPv4 nexthop. I don't care about it. */ - if (peer->local_id.s_addr) + /* IPv4 nexthop. */ + ret = if_get_ipv4_address(ifp, &nexthop->v4); + if (!ret && peer->local_id.s_addr) nexthop->v4 = peer->local_id; /* Global address*/ diff --git a/lib/prefix.h b/lib/prefix.h index 7f0d36070..8c8992e8c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -196,4 +196,14 @@ extern const char *inet6_ntoa (struct in6_addr); extern int all_digit (const char *); +static inline int ipv4_martian (struct in_addr *addr) +{ + in_addr_t ip = addr->s_addr; + + if (IPV4_NET0(ip) || IPV4_NET127(ip) || IPV4_CLASS_DE(ip)) { + return 1; + } + return 0; +} + #endif /* _ZEBRA_PREFIX_H */ From a25a1264a5615a90e9ca9f60ccc1f397ca55bc56 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Nov 2013 14:36:05 +0000 Subject: [PATCH 0313/1342] ospfd: fixup log message in ospf_zebra_delete Signed-off-by: Christian Franke Acked-by: Feng Lu --- ospfd/ospf_zebra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 34a3b2a7f..b5268a3bd 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -482,7 +482,7 @@ ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) { char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra: Route add %s/%d nexthop %s", + zlog_debug("Zebra: Route delete %s/%d nexthop %s", inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), p->prefixlen, From 23f5f7c3dd805b7d6a46d86d23aaa5c71273a84a Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Nov 2013 17:06:14 +0000 Subject: [PATCH 0314/1342] zebra: match gateway when deleting NEXTHOP_IPV4_IFINDEX routes Signed-off-by: Christian Franke Acked-by: Feng Lu --- zebra/zserv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zserv.c b/zebra/zserv.c index 5df521b0d..55ac6e4fb 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -879,6 +879,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); + nexthop_p = &nexthop; ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IPV6: From b52aef18a9f3acc8b24ab5c2631dc574b8e2ec70 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Nov 2013 17:06:15 +0000 Subject: [PATCH 0315/1342] zebra: log routes w/o gateway in rib_delete_ipv4 Signed-off-by: Christian Franke Acked-by: Feng Lu Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 77c0d8ca7..6616f9a10 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2160,12 +2160,20 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Apply mask. */ apply_mask_ipv4 (p); - if (IS_ZEBRA_DEBUG_KERNEL && gate) - zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, - inet_ntoa (*gate), - ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), + p->prefixlen, + inet_ntoa (*gate), + ifindex); + else + zlog_debug ("rib_delete_ipv4(): route delete %s/%d ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), + p->prefixlen, + ifindex); + } /* Lookup route node. */ rn = route_node_lookup (table, (struct prefix *) p); From a11e012e8661629d665e992e765741a5eaa7d017 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Sun, 8 Sep 2013 13:48:34 +0000 Subject: [PATCH 0316/1342] security: Fix some typos and potential NULL-deref This patch against the git tree fixes minor typos, some of them possibily leading to NULL-pointer dereference in rare conditions. Signed-off-by: Remi Gacogne Signed-off-by: Joachim Nilsson Acked-by: Feng Lu --- lib/vty.c | 2 ++ ospf6d/ospf6_snmp.c | 2 +- ospfd/ospf_asbr.c | 3 ++- ospfd/ospf_te.c | 3 ++- zebra/irdp_packet.c | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 0d6345c83..96cb1e4b5 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1856,9 +1856,11 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) { case AF_INET: naddr=&su.sin.sin_addr; + break; #ifdef HAVE_IPV6 case AF_INET6: naddr=&su.sin6.sin6_addr; + break; #endif } diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index f8a3b9204..466039277 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -528,7 +528,7 @@ ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, return NULL; len = *length - v->namelen; - len = (len >= 1 ? sizeof 1 : 0); + len = (len >= 1 ? 1 : 0); if (exact && len != 1) return NULL; if (len) diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index a23b4f2be..7e7c84fd4 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -164,7 +164,8 @@ ospf_external_info_add (u_char type, struct prefix_ipv4 p, new->nexthop = nexthop; new->tag = 0; - rn->info = new; + if (rn) + rn->info = new; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("Redistribute[%s]: %s/%d external info created.", diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 587564a19..c605ce68d 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1036,7 +1036,8 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE (lsa)) { - lp->flags &= ~LPFLG_LSA_ENGAGED; + if (lp) + lp->flags &= ~LPFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (lsa); goto out; } diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 28dc171ed..50525043d 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -287,7 +287,7 @@ send_packet(struct interface *ifp, if (!(ifp->flags & IFF_UP)) return; - if (!p) + if (p) src = ntohl(p->u.prefix4.s_addr); else src = 0; /* Is filled in */ From d9628728e0924ae13ef6e8f8a67a2c9802745184 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 8 Mar 2013 21:47:35 +0100 Subject: [PATCH 0317/1342] ospf6d: improve ordered shutdown Improve the _disable/_enable infrastructure so it gets into a more usable shape and make 'no router ospf6' actually work. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospf6d/ospf6_area.c | 29 +++++++++++++++++++++++------ ospf6d/ospf6_asbr.c | 18 ++++++++++++++++-- ospf6d/ospf6_asbr.h | 1 + ospf6d/ospf6_interface.c | 22 ++++++++++++---------- ospf6d/ospf6_intra.h | 15 ++++++++++----- ospf6d/ospf6_main.c | 10 ++++++++-- ospf6d/ospf6_message.c | 2 +- ospf6d/ospf6_top.c | 28 ++++++++++++++++++++-------- ospf6d/ospf6_zebra.c | 4 +++- 9 files changed, 94 insertions(+), 35 deletions(-) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index b09d9613c..9a4e30e14 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -193,18 +193,21 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o) void ospf6_area_delete (struct ospf6_area *oa) { - struct listnode *n, *nnode; + struct listnode *n; struct ospf6_interface *oi; ospf6_route_table_delete (oa->range_table); ospf6_route_table_delete (oa->summary_prefix); ospf6_route_table_delete (oa->summary_router); - /* ospf6 interface list */ - for (ALL_LIST_ELEMENTS (oa->if_list, n, nnode, oi)) - { - ospf6_interface_delete (oi); - } + /* The ospf6_interface structs store configuration + * information which should not be lost/reset when + * deleting an area. + * So just detach the interface from the area and + * keep it around. */ + for (ALL_LIST_ELEMENTS_RO (oa->if_list, n, oi)) + oi->area = NULL; + list_delete (oa->if_list); ospf6_lsdb_delete (oa->lsdb); @@ -257,6 +260,7 @@ ospf6_area_enable (struct ospf6_area *oa) for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) ospf6_interface_enable (oi); + ospf6_abr_enable_area (oa); } void @@ -269,6 +273,19 @@ ospf6_area_disable (struct ospf6_area *oa) for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) ospf6_interface_disable (oi); + + ospf6_abr_disable_area (oa); + ospf6_lsdb_remove_all (oa->lsdb); + ospf6_lsdb_remove_all (oa->lsdb_self); + + ospf6_spf_table_finish(oa->spf_table); + ospf6_route_remove_all(oa->route_table); + + THREAD_OFF (oa->thread_spf_calculation); + THREAD_OFF (oa->thread_route_calculation); + + THREAD_OFF (oa->thread_router_lsa); + THREAD_OFF (oa->thread_intra_prefix_lsa); } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 60df6e6c9..3605e3f87 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -409,6 +409,8 @@ ospf6_asbr_redistribute_unset (int type) ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex, &route->prefix); } + + ospf6_asbr_routemap_unset (type); } void @@ -636,7 +638,6 @@ DEFUN (ospf6_redistribute, return CMD_WARNING; ospf6_asbr_redistribute_unset (type); - ospf6_asbr_routemap_unset (type); ospf6_asbr_redistribute_set (type); return CMD_SUCCESS; } @@ -677,7 +678,6 @@ DEFUN (no_ospf6_redistribute, return CMD_WARNING; ospf6_asbr_redistribute_unset (type); - ospf6_asbr_routemap_unset (type); return CMD_SUCCESS; } @@ -1312,6 +1312,20 @@ ospf6_asbr_init (void) install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); } +void +ospf6_asbr_redistribute_reset (void) +{ + int type; + + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (type == ZEBRA_ROUTE_OSPF6) + continue; + if (ospf6_zebra_is_redistribute (type)) + ospf6_asbr_redistribute_unset(type); + } +} + void ospf6_asbr_terminate (void) { diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 72e491432..73770cc00 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -89,6 +89,7 @@ extern void ospf6_asbr_redistribute_remove (int type, int ifindex, extern int ospf6_redistribute_config_write (struct vty *vty); extern void ospf6_asbr_init (void); +extern void ospf6_asbr_redistribute_reset (void); extern void ospf6_asbr_terminate (void); extern int config_write_ospf6_debug_asbr (struct vty *vty); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 86c0bf688..d9d2d03b0 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -219,31 +219,28 @@ void ospf6_interface_enable (struct ospf6_interface *oi) { UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); - - oi->thread_send_hello = - thread_add_event (master, ospf6_hello_send, oi, 0); + ospf6_interface_state_update (oi->interface); } void ospf6_interface_disable (struct ospf6_interface *oi) { - struct listnode *node, *nnode; - struct ospf6_neighbor *on; - SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); - for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) - ospf6_neighbor_delete (on); - - list_delete_all_node (oi->neighbor_list); + thread_execute (master, interface_down, oi, 0); ospf6_lsdb_remove_all (oi->lsdb); + ospf6_lsdb_remove_all (oi->lsdb_self); ospf6_lsdb_remove_all (oi->lsupdate_list); ospf6_lsdb_remove_all (oi->lsack_list); THREAD_OFF (oi->thread_send_hello); THREAD_OFF (oi->thread_send_lsupdate); THREAD_OFF (oi->thread_send_lsack); + + THREAD_OFF (oi->thread_network_lsa); + THREAD_OFF (oi->thread_link_lsa); + THREAD_OFF (oi->thread_intra_prefix_lsa); } static struct in6_addr * @@ -327,6 +324,8 @@ ospf6_interface_state_update (struct interface *ifp) return; if (oi->area == NULL) return; + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) + return; if (if_is_operative (ifp)) thread_add_event (master, interface_up, oi, 0); @@ -355,6 +354,9 @@ ospf6_interface_connected_route_update (struct interface *ifp) if (oi->area == NULL) return; + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) + return; + /* update "route to advertise" interface route table */ ospf6_route_remove_all (oi->route_connected); diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h index a25efa12c..e909da23d 100644 --- a/ospf6d/ospf6_intra.h +++ b/ospf6d/ospf6_intra.h @@ -156,32 +156,37 @@ struct ospf6_intra_prefix_lsa #define OSPF6_ROUTER_LSA_SCHEDULE(oa) \ do { \ - if (! (oa)->thread_router_lsa) \ + if (! (oa)->thread_router_lsa \ + && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ (oa)->thread_router_lsa = \ thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \ } while (0) #define OSPF6_NETWORK_LSA_SCHEDULE(oi) \ do { \ - if (! (oi)->thread_network_lsa) \ + if (! (oi)->thread_network_lsa \ + && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (oi)->thread_network_lsa = \ thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \ } while (0) #define OSPF6_LINK_LSA_SCHEDULE(oi) \ do { \ - if (! (oi)->thread_link_lsa) \ + if (! (oi)->thread_link_lsa \ + && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (oi)->thread_link_lsa = \ thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \ do { \ - if (! (oa)->thread_intra_prefix_lsa) \ + if (! (oa)->thread_intra_prefix_lsa \ + && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ (oa)->thread_intra_prefix_lsa = \ thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \ oa, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \ do { \ - if (! (oi)->thread_intra_prefix_lsa) \ + if (! (oi)->thread_intra_prefix_lsa \ + && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (oi)->thread_intra_prefix_lsa = \ thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \ oi, 0); \ diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 17d7654e9..e9919713b 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -41,6 +41,8 @@ #include "ospf6_message.h" #include "ospf6_asbr.h" #include "ospf6_lsa.h" +#include "ospf6_interface.h" +#include "ospf6_zebra.h" /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" @@ -134,12 +136,16 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); static void __attribute__ ((noreturn)) ospf6_exit (int status) { - extern struct ospf6 *ospf6; - extern struct zclient *zclient; + struct listnode *node; + struct interface *ifp; if (ospf6) ospf6_delete (ospf6); + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) + if (ifp->info != NULL) + ospf6_interface_delete(ifp->info); + ospf6_message_terminate (); ospf6_asbr_terminate (); ospf6_lsa_terminate (); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index caebf5d6b..5fb5a2164 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1543,7 +1543,7 @@ ospf6_receive (struct thread *thread) } oi = ospf6_interface_lookup_by_ifindex (ifindex); - if (oi == NULL || oi->area == NULL) + if (oi == NULL || oi->area == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { zlog_debug ("Message received on disabled interface"); return 0; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index f83e6ab5e..7c0922a6f 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -161,6 +161,8 @@ ospf6_delete (struct ospf6 *o) for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_delete (oa); + + list_delete (o->area_list); ospf6_lsdb_delete (o->lsdb); @@ -202,9 +204,16 @@ ospf6_disable (struct ospf6 *o) for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_disable (oa); + /* XXX: This also changes persistent settings */ + ospf6_asbr_redistribute_reset(); + ospf6_lsdb_remove_all (o->lsdb); ospf6_route_remove_all (o->route_table); ospf6_route_remove_all (o->brouter_table); + + THREAD_OFF(o->maxage_remover); + THREAD_OFF(o->t_spf_calc); + THREAD_OFF(o->t_ase_calc); } } @@ -282,8 +291,6 @@ DEFUN (router_ospf6, { if (ospf6 == NULL) ospf6 = ospf6_create (); - if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) - ospf6_enable (ospf6); /* set current ospf point. */ vty->node = OSPF6_NODE; @@ -299,10 +306,13 @@ DEFUN (no_router_ospf6, NO_STR OSPF6_ROUTER_STR) { - if (ospf6 == NULL || CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) - vty_out (vty, "OSPFv3 is not running%s", VNL); + if (ospf6 == NULL) + vty_out (vty, "OSPFv3 is not configured%s", VNL); else - ospf6_disable (ospf6); + { + ospf6_delete (ospf6); + ospf6 = NULL; + } /* return to config node . */ vty->node = CONFIG_NODE; @@ -435,8 +445,12 @@ DEFUN (ospf6_interface_area, SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); + /* ospf6 process is currently disabled, not much more to do */ + if (CHECK_FLAG (o->flag, OSPF6_DISABLED)) + return CMD_SUCCESS; + /* start up */ - thread_add_event (master, interface_up, oi, 0); + ospf6_interface_enable (oi); /* If the router is ABR, originate summary routes */ if (ospf6_is_router_abr (o)) @@ -861,8 +875,6 @@ config_write_ospf6 (struct vty *vty) /* OSPFv6 configuration. */ if (ospf6 == NULL) return CMD_SUCCESS; - if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) - return CMD_SUCCESS; inet_ntop (AF_INET, &ospf6->router_id_static, router_id, sizeof (router_id)); vty_out (vty, "router ospf6%s", VNL); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index f09e9d22c..50ecc1700 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -117,7 +117,9 @@ ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) ifp->name, ifp->ifindex, ifp->mtu6); #if 0 - /* Why is this commented out? */ + /* XXX: ospf6_interface_if_del is not the right way to handle this, + * because among other thinkable issues, it will also clear all + * settings as they are contained in the struct ospf6_interface. */ ospf6_interface_if_del (ifp); #endif /*0*/ From b13c1d9299d6426f48f074545f3e403e5a9b8a61 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 13 Dec 2012 16:11:16 +0100 Subject: [PATCH 0318/1342] ospf6d: handle missing link local address more gracefully ospf6 can't run on an interface without a link local address. Don't start the state machine when an interface comes up without such an ip and bring it up later, when a usable link local address is added. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospf6d/ospf6_interface.c | 17 ++++++++++++++--- ospf6d/ospf6_zebra.c | 11 ++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index d9d2d03b0..8d4276458 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -287,8 +287,7 @@ ospf6_interface_if_add (struct interface *ifp) } /* interface start */ - if (oi->area) - thread_add_event (master, interface_up, oi, 0); + ospf6_interface_state_update(oi->interface); } void @@ -327,7 +326,9 @@ ospf6_interface_state_update (struct interface *ifp) if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) return; - if (if_is_operative (ifp)) + if (if_is_operative (ifp) + && (ospf6_interface_get_linklocal_address(oi->interface) + || if_is_loopback(oi->interface))) thread_add_event (master, interface_up, oi, 0); else thread_add_event (master, interface_down, oi, 0); @@ -647,6 +648,16 @@ interface_up (struct thread *thread) return 0; } + /* check interface has a link-local address */ + if (! (ospf6_interface_get_linklocal_address(oi->interface) + || if_is_loopback(oi->interface))) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_debug ("Interface %s has no link local address, can't execute [InterfaceUp]", + oi->interface->name); + return 0; + } + /* if already enabled, do nothing */ if (oi->state > OSPF6_INTERFACE_DOWN) { diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 50ecc1700..cffd7675f 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -165,8 +165,10 @@ ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, buf, sizeof (buf)), c->address->prefixlen); if (c->address->family == AF_INET6) - ospf6_interface_connected_route_update (c->ifp); - + { + ospf6_interface_state_update (c->ifp); + ospf6_interface_connected_route_update (c->ifp); + } return 0; } @@ -188,7 +190,10 @@ ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, buf, sizeof (buf)), c->address->prefixlen); if (c->address->family == AF_INET6) - ospf6_interface_connected_route_update (c->ifp); + { + ospf6_interface_connected_route_update (c->ifp); + ospf6_interface_state_update (c->ifp); + } return 0; } From 11b4f01355703d34099d4da145c7d92e32d98636 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 9 Dec 2013 16:48:55 +0100 Subject: [PATCH 0319/1342] ospf6d: clear lsa->refresh before clearing LSAs This fixes a SEGV when we receive a higher-SeqNum copy of a LSA that we originated ourselves, before a reboot of ospf6d. We create a new copy of the LSA to resync the SeqNum, but then half an hour later the old refresh thread ends up trying to refresh the free()'d old LSA. The SEGV is triggered by this chain: ospf6_lsdb_maxage_remover -> thread_execute(ospf6_lsa_refresh) -> old->refresh = NULL Which assumes that old->refresh is no longer scheduled to run, as it is being run right there. But the thread_execute() doesn't know about old->refresh and therefore didn't remove it. (Found by ANVL OSPFV3-16.17) Signed-off-by: David Lamparter --- ospf6d/ospf6_flood.c | 1 + ospf6d/ospf6_lsdb.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index dc9ecbfb0..49ed6e265 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -220,6 +220,7 @@ ospf6_install_lsa (struct ospf6_lsa *lsa) if (old) { THREAD_OFF (old->expire); + THREAD_OFF (old->refresh); ospf6_flood_clear (old); } diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 5138d1c1c..707afc67e 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -473,6 +473,8 @@ ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) */ lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER + 1); ospf6_lsa_checksum (lsa->header); + + THREAD_OFF(lsa->refresh); thread_execute (master, ospf6_lsa_refresh, lsa, 0); } else { ospf6_lsdb_remove (lsa, lsdb); From 424cc3bd48da0f417c9056c5c2ade697a3386cd4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 23 Nov 2013 16:55:36 +0100 Subject: [PATCH 0320/1342] ospf6d: fix interface_down() stopping hellos interface_down() - which also handles some nonobvious cases like the last linklocal address disappearing - was previously not cancelling the hello timer. This had the effect of multiple such threads ending up scheduled after a quick down-up cycle. Signed-off-by: David Lamparter --- ospf6d/ospf6_interface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 8d4276458..b0f11194a 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -683,7 +683,7 @@ interface_up (struct thread *thread) /* Schedule Hello */ if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) - thread_add_event (master, ospf6_hello_send, oi, 0); + oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0); /* decide next interface state */ if ((if_is_pointopoint (oi->interface)) || @@ -771,6 +771,9 @@ interface_down (struct thread *thread) zlog_debug ("Interface Event %s: [InterfaceDown]", oi->interface->name); + /* Stop Hellos */ + THREAD_OFF (oi->thread_send_hello); + /* Leave AllSPFRouters */ if (oi->state > OSPF6_INTERFACE_DOWN) ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_LEAVE_GROUP); From 1db65fadf627637621c342b789b9a3604ca5fab5 Mon Sep 17 00:00:00 2001 From: Ingo Flaschberger Date: Sun, 17 Apr 2011 18:28:20 +0000 Subject: [PATCH 0321/1342] ospf6d: solve segfaults with ospf6d on FreeBSD Do not send ospf6d hellos on fresh created interfaces without configuration (ie. no vlan configured). Ospf6d use ip6_mtu, if it's not initalised, Ospf6d tries to alloc indefinite size of memory. Signed-off-by: David Lamparter --- ospf6d/ospf6_message.c | 7 +++++++ zebra/kernel_socket.c | 1 + 2 files changed, 8 insertions(+) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 5fb5a2164..0756ef34c 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1721,6 +1721,13 @@ ospf6_hello_send (struct thread *thread) return 0; } + if (iobuflen == 0) + { + zlog_debug ("Unable to send Hello on interface %s iobuflen is 0", + oi->interface->name); + return 0; + } + /* set next thread */ oi->thread_send_hello = thread_add_timer (master, ospf6_hello_send, oi, oi->hello_interval); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 73fabd4c0..37b2ae231 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -299,6 +299,7 @@ ifan_read (struct if_announcemsghdr *ifan) sizeof(ifan->ifan_name))); ifp->ifindex = ifan->ifan_index; + if_get_metric (ifp); if_add_update (ifp); } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) From c19543b223d3b8463c048f346b8044589e0cce39 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Wed, 24 Oct 2012 14:45:53 +0000 Subject: [PATCH 0322/1342] ospf6d: compute interface cost from its bandwidth Previously, the interface cost was a fixed default value that a user was allowed to change with "ipv6 ospf6 cost XX". As what is done with OSPFv2, we change this behaviour to compute the default interface cost from the interface bandwidth. The user can still force a cost with "ipv6 ospf6 cost XX". He can get the default value with "no ipv6 ospf6 cost". Moreover, the default cost value was 1. The cost is now computed from the bandwidth and a default reference bandwidth of 100 MBps (as for OSPFv2). Since the default bandwidth for an interface is 10 MBps, the "default" cost becomes 10 instead of 1. [DL: resolved conflict in ospf6d/ospf6_interface.c] Signed-off-by: David Lamparter --- doc/ospf6d.texi | 2 +- ospf6d/README | 2 +- ospf6d/ospf6_interface.c | 98 ++++++++++++++++++++++++++++++++++------ ospf6d/ospf6_interface.h | 4 ++ ospf6d/ospf6_zebra.c | 4 +- 5 files changed, 92 insertions(+), 18 deletions(-) diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi index d981820c7..d9bf06ddd 100644 --- a/doc/ospf6d.texi +++ b/doc/ospf6d.texi @@ -75,7 +75,7 @@ Area support for OSPFv3 is not yet implemented. @section OSPF6 interface @deffn {Interface Command} {ipv6 ospf6 cost COST} {} -Sets interface's output cost. Default value is 1. +Sets interface's output cost. Default value depends on the interface bandwidth. @end deffn @deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {} diff --git a/ospf6d/README b/ospf6d/README index 883486fa0..6db347f9b 100644 --- a/ospf6d/README +++ b/ospf6d/README @@ -60,7 +60,7 @@ CONFIG NODE: INTERFACE NODE: ipv6 ospf6 cost COST - Sets the interface's output cost. default 1 + Sets the interface's output cost. Depends on interface bandwidth by default. ipv6 ospf6 hello-interval HELLOINTERVAL Sets the interface's Hello Interval. default 10 diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index b0f11194a..e69889307 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -117,6 +117,52 @@ ospf6_default_iftype(struct interface *ifp) return OSPF_IFTYPE_BROADCAST; } +static u_int32_t +ospf6_interface_get_cost (struct ospf6_interface *oi) +{ + /* If all else fails, use default OSPF cost */ + u_int32_t cost; + u_int32_t bw, refbw; + + bw = oi->interface->bandwidth ? oi->interface->bandwidth : OSPF6_INTERFACE_BANDWIDTH; + refbw = OSPF6_REFERENCE_BANDWIDTH; + + /* A specifed ip ospf cost overrides a calculated one. */ + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) + cost = oi->cost; + else + { + cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5); + if (cost < 1) cost = 1; + else if (cost > UINT32_MAX) cost = UINT32_MAX; + } + + return cost; +} + +static void +ospf6_interface_recalculate_cost (struct ospf6_interface *oi) +{ + u_int32_t newcost; + + newcost = ospf6_interface_get_cost (oi); + if (newcost == oi->cost) return; + oi->cost = newcost; + + /* update cost held in route_connected list in ospf6_interface */ + ospf6_interface_connected_route_update (oi->interface); + + /* execute LSA hooks */ + if (oi->area) + { + OSPF6_LINK_LSA_SCHEDULE (oi); + OSPF6_ROUTER_LSA_SCHEDULE (oi->area); + OSPF6_NETWORK_LSA_SCHEDULE (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); + } +} + /* Create new ospf6 interface structure */ struct ospf6_interface * ospf6_interface_create (struct interface *ifp) @@ -144,7 +190,6 @@ ospf6_interface_create (struct interface *ifp) oi->hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; oi->dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; oi->rxmt_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; - oi->cost = OSPF6_INTERFACE_COST; oi->type = ospf6_default_iftype (ifp); oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; @@ -175,6 +220,9 @@ ospf6_interface_create (struct interface *ifp) oi->interface = ifp; ifp->info = oi; + /* Compute cost. */ + oi->cost = ospf6_interface_get_cost(oi); + return oi; } @@ -658,6 +706,9 @@ interface_up (struct thread *thread) return 0; } + /* Recompute cost */ + ospf6_interface_recalculate_cost (oi); + /* if already enabled, do nothing */ if (oi->state > OSPF6_INTERFACE_DOWN) { @@ -1214,19 +1265,37 @@ DEFUN (ipv6_ospf6_cost, return CMD_SUCCESS; oi->cost = lcost; - - /* update cost held in route_connected list in ospf6_interface */ - ospf6_interface_connected_route_update (oi->interface); + SET_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST); - /* execute LSA hooks */ - if (oi->area) - { - OSPF6_LINK_LSA_SCHEDULE (oi); - OSPF6_ROUTER_LSA_SCHEDULE (oi->area); - OSPF6_NETWORK_LSA_SCHEDULE (oi); - OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); - OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); - } + ospf6_interface_recalculate_cost(oi); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_cost, + no_ipv6_ospf6_cost_cmd, + "no ipv6 ospf6 cost", + NO_STR + IP6_STR + OSPF6_STR + "Calculate interface cost from bandwidth\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + unsigned long int lcost; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + UNSET_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST); + + ospf6_interface_recalculate_cost(oi); return CMD_SUCCESS; } @@ -1681,7 +1750,7 @@ config_write_ospf6_interface (struct vty *vty) if (ifp->mtu6 != oi->ifmtu) vty_out (vty, " ipv6 ospf6 ifmtu %d%s", oi->ifmtu, VNL); - if (oi->cost != OSPF6_INTERFACE_COST) + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) vty_out (vty, " ipv6 ospf6 cost %d%s", oi->cost, VNL); @@ -1764,6 +1833,7 @@ ospf6_interface_init (void) install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 808f09688..34f752330 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -128,6 +128,7 @@ extern const char *ospf6_interface_state_str[]; /* flags */ #define OSPF6_INTERFACE_DISABLE 0x01 #define OSPF6_INTERFACE_PASSIVE 0x02 +#define OSPF6_INTERFACE_NOAUTOCOST 0x04 /* default values */ #define OSPF6_INTERFACE_HELLO_INTERVAL 10 @@ -137,6 +138,9 @@ extern const char *ospf6_interface_state_str[]; #define OSPF6_INTERFACE_PRIORITY 1 #define OSPF6_INTERFACE_TRANSDELAY 1 #define OSPF6_INTERFACE_INSTANCE_ID 0 +#define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */ +#define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ + /* Function Prototypes */ diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index cffd7675f..8ee63fe6a 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -139,9 +139,9 @@ ospf6_zebra_if_state_update (int command, struct zclient *zclient, if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface state change: " - "%s index %d flags %llx metric %d mtu %d", + "%s index %d flags %llx metric %d mtu %d bandwidth %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6); + ifp->metric, ifp->mtu6, ifp->bandwidth); ospf6_interface_state_update (ifp); return 0; From fd5006896fce2816244c1ef4cabc736279548538 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Wed, 24 Oct 2012 14:45:54 +0000 Subject: [PATCH 0323/1342] ospf6d: add "auto-cost reference-bandwidth" command This command allows the user to change to default reference bandwidth for cost calculations. The default value is 100 Mbps. With a default bandwidth of 10 MBps, the default cost becomes 10. Those values are consistent with OSPFv2. [DL: resolved conflicts in vty command additions & docs] Signed-off-by: David Lamparter --- doc/ospf6d.texi | 15 +++++++++- ospf6d/README | 9 ++++++ ospf6d/ospf6_interface.c | 61 +++++++++++++++++++++++++++++++++++++++- ospf6d/ospf6_snmp.c | 4 ++- ospf6d/ospf6_top.c | 6 ++++ ospf6d/ospf6_top.h | 2 ++ 6 files changed, 94 insertions(+), 3 deletions(-) diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi index d9bf06ddd..31f4db0cc 100644 --- a/doc/ospf6d.texi +++ b/doc/ospf6d.texi @@ -66,6 +66,18 @@ within the hold-time of the previous SPF calculation. @end deffn +@deffn {OSPF6 Command} {auto-cost reference-bandwidth @var{cost}} {} +@deffnx {OSPF6 Command} {no auto-cost reference-bandwidth} {} +This sets the reference bandwidth for cost calculations, where this +bandwidth is considered equivalent to an OSPF cost of 1, specified in +Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s +or higher will have a cost of 1. Cost of lower bandwidth links will be +scaled with reference to this cost). + +This configuration setting MUST be consistent across all routers +within the OSPF domain. +@end deffn + @node OSPF6 area @section OSPF6 area @@ -75,7 +87,8 @@ Area support for OSPFv3 is not yet implemented. @section OSPF6 interface @deffn {Interface Command} {ipv6 ospf6 cost COST} {} -Sets interface's output cost. Default value depends on the interface bandwidth. +Sets interface's output cost. Default value depends on the interface +bandwidth and on the auto-cost reference bandwidth. @end deffn @deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {} diff --git a/ospf6d/README b/ospf6d/README index 6db347f9b..f5a004646 100644 --- a/ospf6d/README +++ b/ospf6d/README @@ -85,6 +85,15 @@ OSPF6 NODE: Binds interface to specified Area, and start sending OSPFv3 packets. + auto-cost reference-bandwidth COST + Sets the reference bandwidth for cost calculations, where this + bandwidth is considered equivalent to an OSPF cost of 1, specified + in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth + 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth + links will be scaled with reference to this cost). This + configuration setting MUST be consistent across all routers within + the OSPF domain. + Sample configuration is in ospf6d.conf.sample. -- diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index e69889307..4bc615518 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -125,7 +125,7 @@ ospf6_interface_get_cost (struct ospf6_interface *oi) u_int32_t bw, refbw; bw = oi->interface->bandwidth ? oi->interface->bandwidth : OSPF6_INTERFACE_BANDWIDTH; - refbw = OSPF6_REFERENCE_BANDWIDTH; + refbw = ospf6 ? ospf6->ref_bandwidth : OSPF6_REFERENCE_BANDWIDTH; /* A specifed ip ospf cost overrides a calculated one. */ if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) @@ -1300,6 +1300,61 @@ DEFUN (no_ipv6_ospf6_cost, return CMD_SUCCESS; } +DEFUN (auto_cost_reference_bandwidth, + auto_cost_reference_bandwidth_cmd, + "auto-cost reference-bandwidth <1-4294967>", + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n" + "The reference bandwidth in terms of Mbits per second\n") +{ + struct ospf6 *o = vty->index; + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct listnode *i, *j; + u_int32_t refbw; + + refbw = strtol (argv[0], NULL, 10); + if (refbw < 1 || refbw > 4294967) + { + vty_out (vty, "reference-bandwidth value is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* If reference bandwidth is changed. */ + if ((refbw * 1000) == o->ref_bandwidth) + return CMD_SUCCESS; + + o->ref_bandwidth = refbw * 1000; + for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) + ospf6_interface_recalculate_cost (oi); + + return CMD_SUCCESS; +} + +DEFUN (no_auto_cost_reference_bandwidth, + no_auto_cost_reference_bandwidth_cmd, + "no auto-cost reference-bandwidth", + NO_STR + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n") +{ + struct ospf6 *o = vty->index; + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct listnode *i, *j; + + if (o->ref_bandwidth == OSPF6_REFERENCE_BANDWIDTH) + return CMD_SUCCESS; + + o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; + for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) + ospf6_interface_recalculate_cost (oi); + + return CMD_SUCCESS; +} + DEFUN (ipv6_ospf6_hellointerval, ipv6_ospf6_hellointerval_cmd, "ipv6 ospf6 hello-interval <1-65535>", @@ -1854,6 +1909,10 @@ ospf6_interface_init (void) install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd); + + /* reference bandwidth commands */ + install_element (OSPF6_NODE, &auto_cost_reference_bandwidth_cmd); + install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); } DEFUN (debug_ospf6_interface, diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 466039277..4be8be04b 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -488,7 +488,9 @@ ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, case OSPFv3DEMANDEXTENSIONS: return SNMP_INTEGER (0); /* Not supported */ case OSPFv3REFERENCEBANDWIDTH: - return SNMP_INTEGER (100000); + if (ospf6) + return SNMP_INTEGER (ospf6->ref_bandwidth); + /* Otherwise, like for "not implemented". */ case OSPFv3RESTARTSUPPORT: case OSPFv3RESTARTINTERVAL: case OSPFv3RESTARTSTRICTLSACHECKING: diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 7c0922a6f..719127014 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -148,6 +148,8 @@ ospf6_create (void) o->external_id_table = route_table_init (); + o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; + return o; } @@ -890,6 +892,10 @@ config_write_ospf6 (struct vty *vty) vty_out(vty, "%s", VTY_NEWLINE); } + if (ospf6->ref_bandwidth != OSPF6_REFERENCE_BANDWIDTH) + vty_out (vty, " auto-cost reference-bandwidth %d%s", ospf6->ref_bandwidth / 1000, + VNL); + ospf6_stub_router_config_write (vty); ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 866f92f98..d6f4bf0f3 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -80,6 +80,8 @@ struct ospf6 struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *maxage_remover; + + u_int32_t ref_bandwidth; }; #define OSPF6_DISABLED 0x01 From c78a46c27f6dfdd42fe0800cebabc1e49cb0a4bf Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 20 Mar 2013 10:50:09 +0000 Subject: [PATCH 0324/1342] ospf6d: fix refcounting in ospf6_asbr_lsa_remove When iterating over a list, also the last node should be unlocked again. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospf6d/ospf6_asbr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 3605e3f87..c414970b8 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -297,6 +297,8 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) } ospf6_route_remove (route, ospf6->route_table); } + if (route != NULL) + ospf6_route_unlock (route); } void From 4d474fa3297c0d5d632e2c0bff6ccb0edbedaa5d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 19 Nov 2013 15:00:06 +0100 Subject: [PATCH 0325/1342] lib: fix backtraces broken by 837d16c... 837d16c ("*: use array_size() helper macro") accidentally changed one of the expressions in the backtrace code, which afterwards read: zlog_backtrace_sigsafe(): if (((size = backtrace(array,array_size(array)) <= 0) || which boils down to: (size = backtrace(...) <= 0). The braces were intended to go: (size = backtrace(...)) <= 0. All in all, this makes a nice textbook example of the original author being too clever (trying to save a single line by pulling the assignment into the condition) and the next person touching the code tripping over it... This code occurs another time in zlog_backtrace() where it is actually correct. Pulling out the assignment nonetheless. Also, new test program. Cc: Andrew J. Schorr Cc: Balaji.G Cc: Scott Feldman Signed-off-by: David Lamparter --- lib/log.c | 8 +++---- tests/.gitignore | 1 + tests/Makefile.am | 4 +++- tests/test-segv.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 tests/test-segv.c diff --git a/lib/log.c b/lib/log.c index e4ec7c228..55a3b052d 100644 --- a/lib/log.c +++ b/lib/log.c @@ -443,8 +443,8 @@ zlog_backtrace_sigsafe(int priority, void *program_counter) #define LOC s,buf+sizeof(buf)-s #ifdef HAVE_GLIBC_BACKTRACE - if (((size = backtrace(array,array_size(array)) <= 0) || - ((size_t)size > array_size(array)))) + size = backtrace(array, array_size(array)); + if (size <= 0 || (size_t)size > array_size(array)) return; #define DUMP(FD) { \ @@ -526,8 +526,8 @@ zlog_backtrace(int priority) int size, i; char **strings; - if (((size = backtrace(array,array_size(array))) <= 0) || - ((size_t)size > array_size(array))) + size = backtrace(array, array_size(array)); + if (size <= 0 || (size_t)size > array_size(array)) { zlog_err("Cannot get backtrace, returned invalid # of frames %d " "(valid range is between 1 and %lu)", diff --git a/tests/.gitignore b/tests/.gitignore index 31fb70a48..8d00a3df7 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -29,6 +29,7 @@ testbuffer testchecksum testmemory testprivs +testsegv testsig teststream testnexthopiter diff --git a/tests/Makefile.am b/tests/Makefile.am index 9260a900b..5e631d6a8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,13 +24,14 @@ else TESTS_BGPD = endif -check_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ +check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ $(TESTS_BGPD) noinst_HEADERS = prng.h testsig_SOURCES = test-sig.c +testsegv_SOURCES = test-segv.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c testprivs_SOURCES = test-privs.c @@ -48,6 +49,7 @@ tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ +testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ testmemory_LDADD = ../lib/libzebra.la @LIBCAP@ testprivs_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/tests/test-segv.c b/tests/test-segv.c new file mode 100644 index 000000000..55bd25a59 --- /dev/null +++ b/tests/test-segv.c @@ -0,0 +1,61 @@ +/* + * SEGV / backtrace handling test. + * + * copied from test-sig.c + * + * Copyright (C) 2013 by David Lamparter, Open Source Routing. + * Copyright (C) 2013 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 +#include +#include "lib/log.h" +#include "lib/memory.h" + +struct quagga_signal_t sigs[] = +{ +}; + +struct thread_master *master; + +int +threadfunc (struct thread *thread) +{ + int *null = NULL; + *null += 1; + return 0; +} + +int +main (void) +{ + master = thread_master_create (); + signal_init (master, array_size(sigs), sigs); + + zlog_default = openzlog("testsegv", ZLOG_NONE, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); + zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG); + zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); + + thread_execute (master, threadfunc, 0, 0); + + exit (0); +} From 6d729eeac91578dca29961e0e46f246f33c37f0c Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Wed, 31 Jul 2013 15:01:18 +0000 Subject: [PATCH 0326/1342] lib: fix for dynamically grown hashes Fixes commit 97c84db00c (hash: dynamically grow hash table). The no_expand field it's not initialized and could make the hashes to never grow the table index. Signed-off-by: Jorge Boncompte [DTI2] Acked-by: Feng Lu Signed-off-by: David Lamparter --- lib/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/hash.c b/lib/hash.c index 987012a58..56e41fa82 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -36,6 +36,7 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *), hash->index = XCALLOC (MTYPE_HASH_INDEX, sizeof (struct hash_backet *) * size); hash->size = size; + hash->no_expand = 0; hash->hash_key = hash_key; hash->hash_cmp = hash_cmp; hash->count = 0; From af514777f4327932a3e84f83d79e941967503e15 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Wed, 31 Jul 2013 16:16:05 +0000 Subject: [PATCH 0327/1342] lib: fix possible off-by-one in stream_put_prefix() The STREAM_WRITEABLE() call only checks if there is space for the prefix in the stream but does not account for the prefixlen. The stream_putc() call reduces available space by 1 and we can end copying one byte too much and with "endp" off by one if we are near the buffer end. Instead of moving the stream_putc() call before STREAM_WRITEABLE(), we check before hand for the required space, and open-code it. This avoids a function call and verifying again the stream buffer. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: David Lamparter --- lib/stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/stream.c b/lib/stream.c index ee2920e64..ccd4623ff 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -700,13 +700,13 @@ stream_put_prefix (struct stream *s, struct prefix *p) psize = PSIZE (p->prefixlen); - if (STREAM_WRITEABLE (s) < psize) + if (STREAM_WRITEABLE (s) < (psize + sizeof (u_char))) { STREAM_BOUND_WARN (s, "put"); return 0; } - stream_putc (s, p->prefixlen); + s->data[s->endp++] = p->prefixlen; memcpy (s->data + s->endp, &p->u.prefix, psize); s->endp += psize; From 8c99b4c11e69e4cf0ac03c551764cccc0a3fe35a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 1 Aug 2013 07:43:36 +0000 Subject: [PATCH 0328/1342] build: improve backtrace support/detection libexecinfo is used to provide backtrace() on *BSD. The API is compatible with glibc's, so this is a "free" improvement. To improve configure behaviour, the following configure options are modified/introduced: * --enable-gcc-rdynamic now defaults to "on" if the compiler is gcc. (I sadly wasn't able to find any documentation on the availability of this option for llvm, even though at least the version I have installed does support it) * --enable-backtrace has been added. This behaves as off/auto/on switch, i.e. giving either {dis,en}able will result in the requested behaviour (or an error if support wasn't found) Signed-off-by: David Lamparter --- INSTALL.quagga.txt | 3 +++ configure.ac | 29 +++++++++++++++++++++-------- doc/install.texi | 10 ++++++++++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/INSTALL.quagga.txt b/INSTALL.quagga.txt index 0d465879f..11c85b1a3 100644 --- a/INSTALL.quagga.txt +++ b/INSTALL.quagga.txt @@ -31,6 +31,9 @@ not a guarantee of support, merely "we agree that it is broken".) OpenBSD ? [info needed on what should work] Solaris (modern/supported versions, including OpenSolaris forks) +On BSD systems, installing libexecinfo is strongly recommended in order +to get backtrace support. + For further Quagga specific information on 'configure' and build-time configuration of the software, please read the Quagga info documentation, (doc/quagga.info). To read the info page included with diff --git a/configure.ac b/configure.ac index ff7a4d547..8964006a8 100755 --- a/configure.ac +++ b/configure.ac @@ -273,7 +273,9 @@ AC_ARG_ENABLE(gcc_ultra_verbose, AC_ARG_ENABLE(linux24_tcp_md5, [ --enable-linux24-tcp-md5 enable support for old, Linux-2.4 RFC2385 patch]) AC_ARG_ENABLE(gcc-rdynamic, -[ --enable-gcc-rdynamic enable gcc linking with -rdynamic for better backtraces]) +[ --enable-gcc-rdynamic enable linking with -rdynamic for better backtraces (default if gcc)]) +AC_ARG_ENABLE(backtrace, +[ --disable-backtrace, disable crash backtraces (default autodetect)]) AC_ARG_ENABLE(time-check, [ --disable-time-check disable slow thread warning messages]) AC_ARG_ENABLE(pcreposix, @@ -288,8 +290,10 @@ if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -Wpacked -Wpadded" fi -if test x"${enable_gcc_rdynamic}" = x"yes" ; then - LDFLAGS="${LDFLAGS} -rdynamic" +if test x"${enable_gcc_rdynamic}" != x"no" ; then + if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then + LDFLAGS="${LDFLAGS} -rdynamic" + fi fi if test x"${enable_time_check}" != x"no" ; then @@ -1566,12 +1570,21 @@ AX_SYS_WEAK_ALIAS dnl --------------------------- dnl check for glibc 'backtrace' dnl --------------------------- -AC_CHECK_HEADER([execinfo.h], - [AC_CHECK_FUNC([backtrace], - [AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) - AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) +if test x"${enable_backtrace}" != x"no" ; then + backtrace_ok=no + AC_CHECK_HEADER([execinfo.h], [ + AC_SEARCH_LIBS([backtrace], [execinfo], [ + AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) + AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) + backtrace_ok=yes + ],, [-lm]) ]) -]) + + if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then + dnl user explicitly requested backtrace but we failed to find support + AC_MSG_FAILURE([failed to find backtrace support]) + fi +fi dnl ----------------------------------------- dnl check for malloc mallinfo struct and call diff --git a/doc/install.texi b/doc/install.texi index 0f8f65fab..1e8d965bc 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -96,6 +96,16 @@ installed. They can be excluded from build with this option, which will minimally decrease compile time and overhead. They can always be built and executed at a later time by running @command{make check} in the @file{tests/} subdirectory, even if they're excluded from build. +@item --enable-gcc-rdynamic +Pass the @command{-rdynamic} option to the linker driver. This is in most +cases neccessary for getting usable backtraces. This option defaults to on +if the compiler is detected as gcc, but giving an explicit enable/disable is +suggested. +@item --enable-backtrace +Controls backtrace support for the crash handlers. This is autodetected by +default. Using the switch will enforce the requested behaviour, failing with +an error if support is requested but not available. On BSD systems, this +needs libexecinfo, while on glibc support for this is part of libc itself. @end table You may specify any combination of the above options to the configure From 98a59492d9152df8c93612d2d12f170b5c034189 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 1 Aug 2013 08:12:25 +0000 Subject: [PATCH 0329/1342] build: remove now-useless --{en, dis}able-tests commit d771020 "don't build tests unless make check is run" has made the --{en,dis}able-tests switch completely useless. The differentiation is now made by running "make check" or not doing so. The only effect of the switch is an "empty" excursion of make into the tests/ directory. (well, and it turns "make check" useless from the main directory if --disable-tests is given, which I don't think makes sense either) Acked-by: Greg Troxel Signed-off-by: David Lamparter --- Makefile.am | 2 +- configure.ac | 10 ---------- doc/install.texi | 6 ------ 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/Makefile.am b/Makefile.am index 37fea43b7..6916470bd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \ @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ - redhat @SOLARIS@ @BUILD_TESTS@ + redhat @SOLARIS@ tests DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ diff --git a/configure.ac b/configure.ac index 8964006a8..f9b176350 100755 --- a/configure.ac +++ b/configure.ac @@ -202,8 +202,6 @@ AC_ARG_ENABLE(ipv6, [ --disable-ipv6 turn off IPv6 related features and daemons]) AC_ARG_ENABLE(doc, [ --disable-doc do not build docs]) -AC_ARG_ENABLE(tests, -[ --disable-tests do not build tests]) AC_ARG_ENABLE(zebra, [ --disable-zebra do not build zebra daemon]) AC_ARG_ENABLE(bgpd, @@ -1272,13 +1270,6 @@ else DOC="doc" fi -dnl can't use TESTS as name, that's special with automake -if test "${enable_tests}" = "no";then - BUILD_TESTS="" -else - BUILD_TESTS="tests" -fi - dnl -------------------- dnl Daemon disable check dnl -------------------- @@ -1372,7 +1363,6 @@ else fi AC_SUBST(DOC) -AC_SUBST(BUILD_TESTS) AC_SUBST(ZEBRA) AC_SUBST(BGPD) AC_SUBST(RIPD) diff --git a/doc/install.texi b/doc/install.texi index 1e8d965bc..e958d845f 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -90,12 +90,6 @@ Enable support for Equal Cost Multipath. @var{ARG} is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. @item --disable-rtadv Disable support IPV6 router advertisement in zebra. -@item --disable-tests -Do not build tests. Test programs are built by default, but not ran or -installed. They can be excluded from build with this option, which will -minimally decrease compile time and overhead. They can always be built and -executed at a later time by running @command{make check} in the @file{tests/} -subdirectory, even if they're excluded from build. @item --enable-gcc-rdynamic Pass the @command{-rdynamic} option to the linker driver. This is in most cases neccessary for getting usable backtraces. This option defaults to on From db19c85679b08668c3dce73a655c21753042cf06 Mon Sep 17 00:00:00 2001 From: Brett Ciphery Date: Thu, 3 Oct 2013 13:48:54 +0000 Subject: [PATCH 0330/1342] zebra: set metric for directly connected routes via netlink to 0 a value of 1 is hard coded for the metric field, much like the ifconfig utility it may have roots in. in order to be in line with the metric used in the linux kernel itself, we switch this to 0. Signed-off-by: Brett Ciphery Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7a820bfd1..ba0b0d7de 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -504,7 +504,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); - ifp->metric = 1; + ifp->metric = 0; /* Hardware type and address. */ ifp->hw_type = ifi->ifi_type; @@ -1084,7 +1084,7 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); - ifp->metric = 1; + ifp->metric = 0; netlink_interface_update_hw_addr (tb, ifp); @@ -1096,7 +1096,7 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Interface status change. */ set_ifindex(ifp, ifi->ifi_index); ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); - ifp->metric = 1; + ifp->metric = 0; netlink_interface_update_hw_addr (tb, ifp); From f7bf41534e885c7bc077529c591a1bce24a5f1e9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 22 Oct 2013 17:10:21 +0000 Subject: [PATCH 0331/1342] zebra: apply syntactic sugar to rib_dump() strip the explicit __func__ present on all calls and make the prefix argument a transparent union. Signed-off-by: David Lamparter --- lib/prefix.h | 19 +++++++++++++++++++ zebra/rib.h | 4 +++- zebra/rt_socket.c | 2 +- zebra/zebra_rib.c | 16 +++++++++------- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/prefix.h b/lib/prefix.h index 8c8992e8c..9ef70ff50 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -89,6 +89,25 @@ struct prefix_rd u_char val[8] __attribute__ ((aligned (8))); }; +/* helper to get type safety/avoid casts on calls + * (w/o this, functions accepting all prefix types need casts on the caller + * side, which strips type safety since the cast will accept any pointer + * type.) + */ +union prefix46ptr +{ + struct prefix *p; + struct prefix_ipv4 *p4; + struct prefix_ipv6 *p6; +} __attribute__ ((transparent_union)); + +union prefix46constptr +{ + const struct prefix *p; + const struct prefix_ipv4 *p4; + const struct prefix_ipv6 *p6; +} __attribute__ ((transparent_union)); + #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif /* INET_ADDRSTRLEN */ diff --git a/zebra/rib.h b/zebra/rib.h index 97a20af30..d3a83c68a 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -386,7 +386,9 @@ extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); extern void rib_lookup_and_pushup (struct prefix_ipv4 *); -extern void rib_dump (const char *, const struct prefix *, const struct rib *); +#define rib_dump(prefix ,rib) _rib_dump(__func__, prefix, rib) +extern void _rib_dump (const char *, + union prefix46constptr, const struct rib *); extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *); #define ZEBRA_RIB_LOOKUP_ERROR -1 #define ZEBRA_RIB_FOUND_EXACT 0 diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 5d175d849..90ed73d0b 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -160,7 +160,7 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) { zlog_debug ("%s: %s/%d: attention! gate not found for rib %p", __func__, prefix_buf, p->prefixlen, rib); - rib_dump (__func__, (struct prefix_ipv4 *)p, rib); + rib_dump (p, rib); } else inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6616f9a10..8835ef37f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1912,8 +1912,10 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, * question are passed as 1st and 2nd arguments. */ -void rib_dump (const char * func, const struct prefix * p, const struct rib * rib) +void _rib_dump (const char * func, + union prefix46constptr pp, const struct rib * rib) { + const struct prefix *p = pp.p; char straddr[INET6_ADDRSTRLEN]; struct nexthop *nexthop, *tnexthop; int recursing; @@ -2009,7 +2011,7 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") ); - rib_dump (__func__, (struct prefix *) p, rib); + rib_dump (p, rib); } } @@ -2056,7 +2058,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) char buf[INET_ADDRSTRLEN]; inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); - rib_dump (__func__, &rn->p, rib); + rib_dump (&rn->p, rib); } rib_uninstall (rn, rib); } @@ -2118,7 +2120,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", __func__, rn, rib); - rib_dump (__func__, (struct prefix *) p, rib); + rib_dump (p, rib); } /* Free implicit route.*/ @@ -2128,7 +2130,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", __func__, rn, same); - rib_dump (__func__, (struct prefix *) p, same); + rib_dump (p, same); } rib_delnode (rn, same); } @@ -2706,7 +2708,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", __func__, rn, rib); - rib_dump (__func__, (struct prefix *) p, rib); + rib_dump (p, rib); } /* Free implicit route.*/ @@ -2716,7 +2718,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", __func__, rn, same); - rib_dump (__func__, (struct prefix *) p, same); + rib_dump (p, same); } rib_delnode (rn, same); } From 2b00515a9b639fd1e057f3ebf10ded2dde920764 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 30 Sep 2013 12:27:49 +0000 Subject: [PATCH 0332/1342] bgpd, ospfd, zebra: fix some DEFUN definitions Fixup some DEFUNS with incorrect command strings or mixed up helpstrings. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 58 +++++++++++++++++++++++------------------------ ospfd/ospf_vty.c | 2 ++ zebra/debug.c | 6 ++--- zebra/rtadv.c | 2 +- zebra/zebra_vty.c | 8 +++---- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fb35fab82..335543e08 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4375,7 +4375,7 @@ ALIAS_DEPRECATED (bgp_network_mask_natural, "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_natural_backdoor, bgp_network_mask_natural_backdoor_ttl_cmd, - "network A.B.C.D backdoor pathlimit (1-255>", + "network A.B.C.D backdoor pathlimit <1-255>", "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n" @@ -6796,7 +6796,7 @@ DEFUN (show_ip_bgp_view, IP_STR BGP_STR "BGP view\n" - "BGP view name\n") + "View name\n") { struct bgp *bgp; @@ -6818,7 +6818,7 @@ DEFUN (show_ip_bgp_view_route, IP_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); @@ -6831,7 +6831,7 @@ DEFUN (show_ip_bgp_view_prefix, IP_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); @@ -7904,14 +7904,14 @@ DEFUN (show_bgp_view_afi_safi_community_all, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address Family modifier\n" "Address Family modifier\n" - "Display routes containing communities\n") + "Display routes matching the communities\n") { int afi; int safi; @@ -7945,7 +7945,7 @@ DEFUN (show_bgp_view_afi_safi_community, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" @@ -7982,7 +7982,7 @@ ALIAS (show_bgp_view_afi_safi_community, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" @@ -8009,7 +8009,7 @@ ALIAS (show_bgp_view_afi_safi_community, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" @@ -8040,7 +8040,7 @@ ALIAS (show_bgp_view_afi_safi_community, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" @@ -10198,7 +10198,7 @@ DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" @@ -10613,7 +10613,7 @@ DEFUN (show_ip_bgp_view_rsclient, IP_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { @@ -10663,7 +10663,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" @@ -10723,7 +10723,7 @@ DEFUN (show_ip_bgp_view_rsclient_route, IP_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") @@ -10795,7 +10795,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_route, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" @@ -10877,7 +10877,7 @@ DEFUN (show_ip_bgp_view_rsclient_prefix, IP_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") @@ -10949,7 +10949,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" @@ -11031,7 +11031,7 @@ DEFUN (show_bgp_view_neighbor_routes, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -11057,7 +11057,7 @@ ALIAS (show_bgp_view_neighbor_routes, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" @@ -11070,7 +11070,7 @@ DEFUN (show_bgp_view_neighbor_damp, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -11096,7 +11096,7 @@ ALIAS (show_bgp_view_neighbor_damp, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" @@ -11109,7 +11109,7 @@ DEFUN (show_bgp_view_neighbor_flap, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -11135,7 +11135,7 @@ ALIAS (show_bgp_view_neighbor_flap, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" @@ -11246,7 +11246,7 @@ DEFUN (show_bgp_view_rsclient, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { @@ -11295,7 +11295,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" @@ -11354,7 +11354,7 @@ DEFUN (show_bgp_view_rsclient_route, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") @@ -11425,7 +11425,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_route, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" @@ -11506,7 +11506,7 @@ DEFUN (show_bgp_view_rsclient_prefix, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") @@ -11577,7 +11577,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix, SHOW_STR BGP_STR "BGP view\n" - "BGP view name\n" + "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 2ba8188c7..5e5a0b0d5 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -1976,6 +1976,8 @@ DEFUN (ospf_area_authentication_message_digest, ospf_area_authentication_message_digest_cmd, "area (A.B.C.D|<0-4294967295>) authentication message-digest", "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" "Enable authentication\n" "Use message-digest authentication\n") { diff --git a/zebra/debug.c b/zebra/debug.c index 7bfdb77d9..c3b00e0fa 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -35,8 +35,8 @@ DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, "show debugging zebra", SHOW_STR - "Zebra configuration\n" - "Debugging information\n") + "Debugging information\n" + "Zebra configuration\n") { vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); @@ -128,7 +128,7 @@ DEFUN (debug_zebra_packet_detail, "Debug option set for zebra packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n" - "Debug option set detaied information\n") + "Debug option set detailed information\n") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index ae5c5a1cc..91d7b3241 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -1483,7 +1483,7 @@ DEFUN (no_ipv6_nd_router_preference, ALIAS (no_ipv6_nd_router_preference, no_ipv6_nd_router_preference_val_cmd, - "no ipv6 nd router-preference (high|medium|low", + "no ipv6 nd router-preference (high|medium|low)", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 45928e930..f4946f461 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -280,9 +280,9 @@ DEFUN (ip_route_mask_flags_distance, "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" - "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n") + "Silently discard pkts when matched\n" + "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]); } @@ -294,9 +294,9 @@ DEFUN (ip_route_mask_flags_distance2, "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" - "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n") + "Silently discard pkts when matched\n" + "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); } From 8f399b0e4fff2344d75ebf709e1ce55f15269db2 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 30 Sep 2013 12:27:50 +0000 Subject: [PATCH 0333/1342] tests: add a test program for lib/command.c Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- tests/.gitignore | 2 + tests/Makefile.am | 18 +- tests/libzebra.tests/Makefile.am | 1 + tests/libzebra.tests/testcommands.exp | 23 + tests/prng.c | 48 ++ tests/prng.h | 4 + tests/test-commands.c | 417 ++++++++++++ tests/testcommands.in | 201 ++++++ tests/testcommands.out | 900 ++++++++++++++++++++++++++ 9 files changed, 1613 insertions(+), 1 deletion(-) create mode 100644 tests/libzebra.tests/testcommands.exp create mode 100644 tests/test-commands.c create mode 100644 tests/testcommands.in create mode 100644 tests/testcommands.out diff --git a/tests/.gitignore b/tests/.gitignore index 8d00a3df7..0ace3656d 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -33,4 +33,6 @@ testsegv testsig teststream testnexthopiter +testcommands +test-commands-defun.c site.exp diff --git a/tests/Makefile.am b/tests/Makefile.am index 5e631d6a8..ceca606a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,7 +9,9 @@ EXTRA_DIST = \ config/unix.exp \ lib/bgpd.exp \ lib/libzebra.exp \ - global-conf.exp + global-conf.exp \ + testcommands.in \ + testcommands.out INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" @@ -26,8 +28,20 @@ endif check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ + testcommands \ $(TESTS_BGPD) +../vtysh/vtysh_cmd.c: + $(MAKE) -C ../vtysh vtysh_cmd.c + +test-commands-defun.c: ../vtysh/vtysh_cmd.c + sed \ + -e '/"vtysh.h"/d' \ + -e 's/vtysh_init_cmd/test_init_cmd/' \ + -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ + < ../vtysh/vtysh_cmd.c \ + > test-commands-defun.c + noinst_HEADERS = prng.h testsig_SOURCES = test-sig.c @@ -47,6 +61,7 @@ testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c +testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ @@ -65,3 +80,4 @@ testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ +testcommands_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/tests/libzebra.tests/Makefile.am b/tests/libzebra.tests/Makefile.am index 14138a08e..a1ffea3de 100644 --- a/tests/libzebra.tests/Makefile.am +++ b/tests/libzebra.tests/Makefile.am @@ -1,3 +1,4 @@ EXTRA_DIST = \ tabletest.exp \ + testcommands.exp \ testnexthopiter.exp diff --git a/tests/libzebra.tests/testcommands.exp b/tests/libzebra.tests/testcommands.exp new file mode 100644 index 000000000..f760c6d7f --- /dev/null +++ b/tests/libzebra.tests/testcommands.exp @@ -0,0 +1,23 @@ +set timeout 30 +set test_name "testcommands" + +spawn sh -c "./testcommands -e 0 < testcommands.in | diff -au - testcommands.out" + +expect { + eof { + } + timeout { + exp_close + fail "$test_name: timeout" + } +} + +catch wait result +set os_error [lindex $result 2] +set exit_status [lindex $result 3] + +if { $os_error == 0 && $exit_status == 0 } { + pass "$test_name" +} else { + fail "$test_name" +} diff --git a/tests/prng.c b/tests/prng.c index 7b1b42821..8d78ea523 100644 --- a/tests/prng.c +++ b/tests/prng.c @@ -25,6 +25,7 @@ #include #include +#include #include "prng.h" @@ -75,6 +76,53 @@ prng_rand(struct prng *prng) return rv; } +const char * +prng_fuzz(struct prng *prng, + const char *string, + const char *charset, + unsigned int operations) +{ + static char buf[256]; + unsigned int charset_len; + unsigned int i; + unsigned int offset; + unsigned int op; + unsigned int character; + + assert(strlen(string) < sizeof(buf)); + + strncpy(buf, string, sizeof(buf)); + charset_len = strlen(charset); + + for (i = 0; i < operations; i++) + { + offset = prng_rand(prng) % strlen(buf); + op = prng_rand(prng) % 3; + + switch (op) + { + case 0: + /* replace */ + character = prng_rand(prng) % charset_len; + buf[offset] = charset[character]; + break; + case 1: + /* remove */ + memmove(buf + offset, buf + offset + 1, strlen(buf) - offset); + break; + case 2: + /* insert */ + assert(strlen(buf) + 1 < sizeof(buf)); + + memmove(buf + offset + 1, buf + offset, strlen(buf) + 1 - offset); + character = prng_rand(prng) % charset_len; + buf[offset] = charset[character]; + break; + } + } + return buf; +} + void prng_free(struct prng *prng) { diff --git a/tests/prng.h b/tests/prng.h index ed3649863..cf0bacc5f 100644 --- a/tests/prng.h +++ b/tests/prng.h @@ -29,6 +29,10 @@ struct prng; struct prng* prng_new(unsigned long long seed); unsigned int prng_rand(struct prng*); +const char * prng_fuzz(struct prng*, + const char *string, + const char *charset, + unsigned int operations); void prng_free(struct prng *); #endif diff --git a/tests/test-commands.c b/tests/test-commands.c new file mode 100644 index 000000000..e2f40c6a9 --- /dev/null +++ b/tests/test-commands.c @@ -0,0 +1,417 @@ +/* + * Test code for lib/command.c + * + * Copyright (C) 2013 by Open Source Routing. + * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") + * + * This program reads in a list of commandlines from stdin + * and calls all the public functions of lib/command.c for + * both the given command lines and fuzzed versions thereof. + * + * The output is currently not validated but only logged. It can + * be diffed to find regressions between versions. + * + * 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. + */ + +#define REALLY_NEED_PLAIN_GETOPT 1 + +#include + +#include +#include +#include + +#include "command.h" +#include "memory.h" +#include "vector.h" +#include "prng.h" + +extern vector cmdvec; +extern struct cmd_node vty_node; +extern void test_init_cmd(void); /* provided in test-commands-defun.c */ + +struct thread_master *master; /* dummy for libzebra*/ + +static vector test_cmds; +static char test_buf[32768]; + +static struct cmd_node bgp_node = +{ + BGP_NODE, + "%s(config-router)# ", +}; + +static struct cmd_node rip_node = +{ + RIP_NODE, + "%s(config-router)# ", +}; + +static struct cmd_node isis_node = +{ + ISIS_NODE, + "%s(config-router)# ", +}; + +static struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +static struct cmd_node rmap_node = +{ + RMAP_NODE, + "%s(config-route-map)# " +}; + +static struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# " +}; + +static struct cmd_node bgp_vpnv4_node = +{ + BGP_VPNV4_NODE, + "%s(config-router-af)# " +}; + +static struct cmd_node bgp_ipv4_node = +{ + BGP_IPV4_NODE, + "%s(config-router-af)# " +}; + +static struct cmd_node bgp_ipv4m_node = +{ + BGP_IPV4M_NODE, + "%s(config-router-af)# " +}; + +static struct cmd_node bgp_ipv6_node = +{ + BGP_IPV6_NODE, + "%s(config-router-af)# " +}; + +static struct cmd_node bgp_ipv6m_node = +{ + BGP_IPV6M_NODE, + "%s(config-router-af)# " +}; + +static struct cmd_node ospf_node = +{ + OSPF_NODE, + "%s(config-router)# " +}; + +static struct cmd_node ripng_node = +{ + RIPNG_NODE, + "%s(config-router)# " +}; + +static struct cmd_node ospf6_node = +{ + OSPF6_NODE, + "%s(config-ospf6)# " +}; + +static struct cmd_node babel_node = +{ + BABEL_NODE, + "%s(config-babel)# " +}; + +static struct cmd_node keychain_node = +{ + KEYCHAIN_NODE, + "%s(config-keychain)# " +}; + +static struct cmd_node keychain_key_node = +{ + KEYCHAIN_KEY_NODE, + "%s(config-keychain-key)# " +}; + +static int +test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[]) +{ + int offset; + int rv; + int i; + + offset = 0; + rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string); + if (rv < 0) + abort(); + + offset += rv; + + for (i = 0; i < argc; i++) + { + rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'", + (i == 0) ? ": " : ", ", argv[i]); + if (rv < 0) + abort(); + offset += rv; + } + + return CMD_SUCCESS; +} + +static void +test_load(void) +{ + char line[4096]; + + test_cmds = vector_init(VECTOR_MIN_SIZE); + + while (fgets(line, sizeof(line), stdin) != NULL) + { + if (strlen(line)) + line[strlen(line) - 1] = '\0'; + if (line[0] == '#') + continue; + vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line)); + } +} + +static void +test_init(void) +{ + unsigned int node; + unsigned int i; + struct cmd_node *cnode; + struct cmd_element *cmd; + + cmd_init(1); + + install_node (&bgp_node, NULL); + install_node (&rip_node, NULL); + install_node (&interface_node, NULL); + install_node (&rmap_node, NULL); + install_node (&zebra_node, NULL); + install_node (&bgp_vpnv4_node, NULL); + install_node (&bgp_ipv4_node, NULL); + install_node (&bgp_ipv4m_node, NULL); + install_node (&bgp_ipv6_node, NULL); + install_node (&bgp_ipv6m_node, NULL); + install_node (&ospf_node, NULL); + install_node (&ripng_node, NULL); + install_node (&ospf6_node, NULL); + install_node (&babel_node, NULL); + install_node (&keychain_node, NULL); + install_node (&keychain_key_node, NULL); + install_node (&isis_node, NULL); + install_node (&vty_node, NULL); + + test_init_cmd(); + + for (node = 0; node < vector_active(cmdvec); node++) + if ((cnode = vector_slot(cmdvec, node)) != NULL) + for (i = 0; i < vector_active(cnode->cmd_vector); i++) + if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL) + { + cmd->daemon = 0; + cmd->func = test_callback; + } + sort_node(); + + test_load(); + vty_init_vtysh(); +} + +static void +test_terminate(void) +{ + unsigned int i; + + vty_terminate(); + for (i = 0; i < vector_active(test_cmds); i++) + XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i)); + vector_free(test_cmds); + cmd_terminate(); +} + +static void +test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose) +{ + const char *test_str; + vector vline; + int ret; + unsigned int i; + char **completions; + unsigned int j; + struct cmd_node *cnode; + vector descriptions; + int appended_null; + int no_match; + + test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist); + vline = cmd_make_strvec(test_str); + + if (vline == NULL) + return; + + appended_null = 0; + for (i = 0; i < vector_active(cmdvec); i++) + if ((cnode = vector_slot(cmdvec, i)) != NULL) + { + if (node_index != (unsigned int)-1 && i != node_index) + continue; + + if (appended_null) + { + vector_unset(vline, vector_active(vline) - 1); + appended_null = 0; + } + vty->node = cnode->node; + test_buf[0] = '\0'; + ret = cmd_execute_command(vline, vty, NULL, 0); + no_match = (ret == CMD_ERR_NO_MATCH); + if (verbose || !no_match) + printf("execute relaxed '%s'@%d: rv==%d%s%s\n", + test_str, + cnode->node, + ret, + (test_buf[0] != '\0') ? ", " : "", + test_buf); + + vty->node = cnode->node; + test_buf[0] = '\0'; + ret = cmd_execute_command_strict(vline, vty, NULL); + if (verbose || !no_match) + printf("execute strict '%s'@%d: rv==%d%s%s\n", + test_str, + cnode->node, + ret, + (test_buf[0] != '\0') ? ", " : "", + test_buf); + + if (isspace((int) test_str[strlen(test_str) - 1])) + { + vector_set (vline, NULL); + appended_null = 1; + } + + vty->node = cnode->node; + completions = cmd_complete_command(vline, vty, &ret); + if (verbose || !no_match) + printf("complete '%s'@%d: rv==%d\n", + test_str, + cnode->node, + ret); + if (completions != NULL) + { + for (j = 0; completions[j] != NULL; j++) + { + printf(" '%s'\n", completions[j]); + XFREE(MTYPE_TMP, completions[j]); + } + XFREE(MTYPE_VECTOR_INDEX, completions); + } + + vty->node = cnode->node; + descriptions = cmd_describe_command(vline, vty, &ret); + if (verbose || !no_match) + printf("describe '%s'@%d: rv==%d\n", + test_str, + cnode->node, + ret); + if (descriptions != NULL) + { + for (j = 0; j < vector_active(descriptions); j++) + { + struct desc *cmd = vector_slot(descriptions, j); + printf(" '%s' '%s'\n", cmd->cmd, cmd->str); + } + vector_free(descriptions); + } + } + cmd_free_strvec(vline); +} + +int +main(int argc, char **argv) +{ + int opt; + struct prng *prng; + struct vty *vty; + unsigned int edit_distance; + unsigned int max_edit_distance; + unsigned int node_index; + int verbose; + unsigned int test_cmd; + unsigned int iteration; + unsigned int num_iterations; + + max_edit_distance = 3; + node_index = -1; + verbose = 0; + + while ((opt = getopt(argc, argv, "e:n:v")) != -1) + { + switch (opt) + { + case 'e': + max_edit_distance = atoi(optarg); + break; + case 'n': + node_index = atoi(optarg); + break; + case 'v': + verbose++; + break; + default: + fprintf(stderr, "Usage: %s [-e ] [-n ] [-v]\n", argv[0]); + exit(1); + break; + } + } + + test_init(); + prng = prng_new(0); + + vty = vty_new(); + vty->type = VTY_TERM; + + fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds)); + for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++) + { + for (edit_distance = 0; + edit_distance <= max_edit_distance; + edit_distance++) + { + num_iterations = 1 << edit_distance; + num_iterations *= num_iterations * num_iterations; + + for (iteration = 0; iteration < num_iterations; iteration++) + test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose); + } + fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds)); + } + fprintf(stderr, "\nDone.\n"); + + vty_close(vty); + prng_free(prng); + test_terminate(); + return 0; +} diff --git a/tests/testcommands.in b/tests/testcommands.in new file mode 100644 index 000000000..70c57052f --- /dev/null +++ b/tests/testcommands.in @@ -0,0 +1,201 @@ +# +# +# Some randomly chosen valid commands +# +# +area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE +area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1 +area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1 +area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1 +area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1 +clear bgp 1 out +clear bgp ipv6 2001:db8::1 out +clear bgp view VARIABLE * soft +clear ip bgp 1.2.3.4 ipv4 multicast out +ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig +ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1 +network 1.0.0.0/8 area 0 +no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay +no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay +no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval +no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval +no bgp graceful-restart +no ipv6 nd mtu 1 +no neighbor 1.2.3.4 distribute-list 1 in +no neighbor 2001:db8::1 send-community both +no neighbor VARIABLE maximum-prefix +redistribute isis route-map VARIABLE metric 0 metric-type 2 +redistribute rip metric 0 route-map VARIABLE metric-type 1 +show bgp community VARIABLE local-AS no-export VARIABLE exact-match +show bgp ipv6 community no-advertise no-export no-export no-export +show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match +show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match +show bgp view VARIABLE +show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE +show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS +show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise +show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE +show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS +show ip bgp community no-advertise local-AS no-advertise VARIABLE +show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match +show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match +show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match +show ipv6 bgp community no-export no-export VARIABLE VARIABLE +show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match +show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match +show ipv6 mbgp community local-AS local-AS no-export no-export exact-match +show ipv6 mbgp community no-export no-export local-AS no-export exact-match +show ipv6 ospf6 database as-external dump +show ipv6 ospf6 database inter-prefix 1.2.3.4 detail +show ipv6 ospf6 database intra-prefix 1.2.3.4 internal +# +# +# Slightly Fuzzed commands +# +# +a8ra 0 range 1.0.0.0/8 adverOise +accept-lifetime VARIABE 1 VA6IABLE 19I3 VARIABLE 1 VARIABLE 1993 +arAea 1.2.M.4 virtual-link 1.2.3.4 dead-interval 1 dead-interval 1 dead-inter6val 1 transmit-delay 1 +area 0 virtu0al-link 1.2.3.i hello-interval 1 ello-interval 1 transmit-delay 1 retransmit-interval 1 +area 0 virtual-lin 1.2.3.4 retransmit-interval 1 tranwmit-delay 1 retransmit-interval 1 retransmit-interval 1 +area 0 virtual-link 1.2.3.4 retransmit-interal 1 trasmit-dely 1 +area 1.2.3.4 virtual-link 1.2.3.4 deadCinterval 1 dead-intervalK 1 retransmit-interval 1 dead-interval 1 +area 1.2.3.4 virtual-link 1.2.3.4 dead-intervalo I1 dead-interval 1 retransmit-interval1 dead-interval 1 +area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1 +area 1.2.3.4 virtuyl-link 1.2.3.4 dead-interval 1 dead-inervalI 1 retransmit-interval 1 dead-interval 1 +area 1.2.3.4 virual-link 1.2.34 retransmit-interval 1 dead-interval 1 dead-interva 1 +area1.2.83.4 virtual-link 1.2.3.4 retra0smit-interval 1 dead-interval 1 dead-interval 1 +clear bgAp 2001g:dbK::1 +clear ip bgp 1.2.3.4 pv4 mlticat out +cleau bg i2001:db8::1 rsclient +de:ug ospf6 messag2 lsreq :recv +how ip bgp communiQy no-advertise no-adve:tise no-advertise +ip route 1.0Q0.0/8 1.2.3.s4 reGject +ipv6 nd prefix 2O01:db8::/32 0 infinEite off-link +ipv6 nwd prefix 2001:db8::/32 0 infinite oUUff-link +ipv6 route 2001:db8::/32q2001:db8:k: blackhole 1 +kshow ip rIute bgp +matcch peer .2.30.4 +mcogin +mhow ipv6 mbgp community o-advertise yocal-AS no-advertise +neighbor1.2..4 attribute-unchnged next-hop +neihbcr 2001:d b8::1 distribute-list 1 in +nko key-tqring +no area 0 viertual-link 1.2.3k.4 retransmit-iterval retransmit-interval retransmit-interval hello-interval +no area 0 virtual-link 1.2.3.4 dead-intaerval dead-intervIl hello-interval retransmit-interval +no area 0 virtual-link 1.2.3.4 retransmit-interval retransmit-intervIl dead-interval tranImit-deqlay +no area 0 virtual-link S1.2.3.4 d-ead-interval hello-interval transmit-deay transmit-delay +no area 1.2.3.4 virtua -link 1.2.3.4 transmit-delay hello-interval hello-interval retransmt-interval +no area 1.2.3.4 virtual-link 1.2.3.4 dea-iterval retransmit-interva- dead-interval hello-interval +no area 1.2.3.4 virtual-link 1.2.3.4 hello-interSval dead-interval retransmit-interval transmitdelay +no a:rea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interSvalW dead-interval retransmit-interval hello-interval +noarea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval trynsmit-delay hello-interval +no area 1.2.3.4 virtual-link 1.2.3.4 transmt:delay retransmit-interval retransmit-interval dead-Mnterval +no ares 1.2.3.4 virtual-link 1.2.3.4 dead-interval retransmit-interval dead-inesval retransmit-interval +no ayrea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval transmi-delay hello-interval +no bg2 grace2fuy-restart +no debug ospk6 nter2face +noimatch ipv6 addrMss VARIABLE +nomStch iA next-hop prefix-list +no neighbCr 200 :db8::1oroute-map VARIABLE export +no neighbor VARIABLE attributeaw8changed next-hop +no orea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval ead-interval retransmit-inteSval hello-interval +no ospcdead-inkerval +no redistribute kernelrote-map VARIABLE metric 0 +no redistribute s4taik metric 0 +nos Ceighbor 1.2.3.4 route-mapEVARIABLE in +o :neighbor VAIABLE attribute-unchanged next-hop +ooa router ip +redistribute isis meGtric-type2 Q route-map VARIABLE +redistribute static metric-type 1 metri 0 rowute-map VARIABLE +set-Koveroadbit +sh2w ipv6 mbgp comAunity VARIABLE +shgw bgp ipv6 community no-export VARIABLE no-xport no-expmrt +shiow Wgp neighbors +shoAw ip bgpipv4 unicast com6munity no-export no-export no-advertise no-export exact-match +sho bgp view gARIABLE nyeighbors 2001:db8::1 received-routes +shoow bgp ommunity local-AS no--export +show6 bgp community no-advertise local4-AS no-advertise VARIABLE exact-math +show8 bgp view VARIABLE ipv4 multicast community ARIABLE VARIABLE local-S +show bgp cCommunity VARIABLE VOARIABL no-advertise +show bgp cimAunity loal-AS local-AS no-export local-AS +show bgp cmmunity n-advertise no-export local-S no-advertise +show bgp communi0y no-export no-Cexport no-0xport no-export +show bgp communityOlocal-A no-advertise local-WAS +show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match +show bgp communiy no-export no-adsvertise VARIABLOE local-AS +show bgp communiYty no-export VARIABLE VARIABLE locali-AS exact-math +show bgp commuUityW no-advertis local-AS no-advertise no-advertise +show bgp commuWnity VAIABLE local-AS no-advertise n-export +show bgp com:unity no-exportqno-export VARIABLE no-expoIrt exact-match +show bgp ipv6 community local-AS no-expor no-xport VARIABCLE +show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE +show bgp ipv6 community no-advertise no6-export lcal-AS local-AS +show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math +show bgp ipv6 comm-unity no-advertise no-export local-AS local-kS exact-match +show bgp ipv6 community no-export local-AS no-adertise no-adve-tie +show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE +show bgp naighbors 201:db8::1 rUeceived-routes +show bgp viewVAIABLE ipv4 multicast community VARIABLE4no-export no-advertise local-AS +show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS +show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export +show bgp view VARIABLE ipv4 multicast omsunity local-AS VARIABLE no-advertise nUo-export +show bgp view VARIABLE ipv4 mutiast community no-export no-export VARIBLE no-export +show bgp view VARIABLE ipv4 unicast 0community VARIABqLE local-AS no-export VARIABwE +show bgp view VARIABLE ipv4 unicast communeity no-export AcRIABLE no-advertise local-AS +show bgp view VARIABLE ipv4 unicasU comunity no-export VARIABL no-advertise +show bgp view VARIABLE ipv6 unicast cocmmunity VARIABLE no-advet6ise VARIABLE +show bgp view VARIABLE ipvk4 unicast communty no-advertie local-AS local-AS no-export +show bgp view VARIALE ipv4 multicast cyommunity no-xport local-AS local-AS +show i6 bge community no-export VARIABLE no-advegtise VARIABLE exact-match +show iI bgp community no-advertise no-ad2vertsse VARIABLE exact-match +show ip6osp6 database dump +show ipA6 bgp community local-AS local-AS no-advertse lo:cal-AS +show ip bg comunity VARIABLE lcal-AS no-advertise +show ip bgp communityno-export2no-export no-advertise locaE-AS +Show ip bgp community no-export loqcal-AS no-adverise no-export +show ip bgp community no-expor VARIABLEono-export VARIAuBLE +show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match +show ip bgp cWmmunity no-expoWrt VARIABLE no-advertise VARIABLEexact-match +show ip bgp ip4 nicast community no-advertise no-expoIt local-AS local-AS exact-match +show ip bgp ipAv4 multicast community no-export no-export no-export no-advertiqe exact-mach +show ip bgp ipv4 Aulticast community no-advertise VARIABLE no-advertisKe no-exort +show ip bgp ipv4 meuqlticast community VARIABLE VARIABLE no-export n-export +show ip bgp ipv4 mlticast coQmmunity localg-AS local-AS no-advertise local-AS +show ip bgp ipv4 multicast communiy VARIABLE no-export VARIABLE no-advertise yxact-atch +show ip bgp ipv4 unicast commu0nity local-AS no-export no-exrt VARIABLE exact-match +show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match +showip bgp ipv4 unicast community no-export VARIABLE no-exp-ort VAR6IABLE exact-match +show ip bgp ipv4 unicat community no-exportlocal-AS VARIABLE no-export exa0t-match +show ip bgp ipv4 unicst community no-advertiseG local-AS no-advertise +show ip bgp i:v4 multicast community VARIABLE VARIABLE VARIABLE no-export eMxact-match +show ip bgp Mv4 unicast community no-export VARIABLE VARIABLE VAoRIABLE +show ipgexecommunity-list 1 +show ipkv6 bgp community no-export no-export VARIABL VARIBLE +show ipv6 bgp commu2nity local-AS local-AS noEadvertise local-AS +show ipv6 bgp communitK VARIABLE lcocal-AS no-advertie no-advertise exact-match +show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match +show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE +show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match +show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE +show ipv6 bgp comu-ity VARIABLE local-AS no-advertise no-export exact-match +show ipv6 bgp comunity no- export local-AS no-advertisge VARIABLE +show ipv6 bgp ommunity sno-advcrtise VARIABLE no-export no-advertise exact-match +show ipv6 igp community no-advertise no-advertise no-ecxpo0rt no-export +show ipv6 mb communyty VARIABLE +show ipv6 osp8f6 database nQtwork adv-ruter 1.2.3.4 detail +show ipv6 ospf6 dataase type-7 adv-router 1.2.3.4 inernal +show ipv6 ospf6 Edatabase intuer8-prefix 1.2.3.4 detail +show ipvq6 ospf6 database as-externa detil +show ip Wbgp ipv4 unicast community no-advertise no-exprt no-export VARIABLEK exact-match +show ip Ybgp attribute-in ufo +showMbgp ipv6 community ARIABLE local-AS local-AS no8advertise exact-match +show p bgp community no-dvertise no-export no-advertiseIno-export exact-match +show uipv6 mbgp coqmmunKty VARIABLE +shQw ipv6 mbgp community no-advetise local-AS no-export no-export ex8ct-match +shuw ipv6 mbgp community VARIABLyUE no-export no-export no-advertise +shw bgp view VARIABLE ipv4 un0icast Gcommunity no-export VARIABLE no-advertise +sow ip bgp ipv4 mulicast community no-export no-adertise no-export no-advertise +sow ipv6 ospf6 databIase as-external adv-router 1.2.3.4 +Whow bgp view VARIAeBLE ipv4 unicast community local-AS no-advrtise no-advertise local-AS +Wneighbor 1.2.3.4 dot-capabiliy-negotiate diff --git a/tests/testcommands.out b/tests/testcommands.out new file mode 100644 index 000000000..1422aefcc --- /dev/null +++ b/tests/testcommands.out @@ -0,0 +1,900 @@ +execute relaxed 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (authentication|) (message-digest|null) (message-digest-key|) <1-255> md5 KEY': '0', '1.2.3.4', 'authentication', 'null', 'message-digest-key', '1', 'VARIABLE' +execute strict 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (authentication|) (message-digest|null) (message-digest-key|) <1-255> md5 KEY': '0', '1.2.3.4', 'authentication', 'null', 'message-digest-key', '1', 'VARIABLE' +complete 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==2 +describe 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0 + 'KEY' 'The OSPF password (key)' +execute relaxed 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'dead-interval', '1', 'hello-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1' +execute strict 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'dead-interval', '1', 'hello-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1' +complete 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 +describe 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0 + '<1-65535>' 'Seconds' +execute relaxed 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'dead-interval', '1', 'retransmit-interval', '1' +execute strict 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'dead-interval', '1', 'retransmit-interval', '1' +complete 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==2 +describe 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0 + '<1-65535>' 'Seconds' +execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'hello-interval', '1', 'dead-interval', '1' +execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'hello-interval', '1', 'dead-interval', '1' +complete 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==2 +describe 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0 + '<1-65535>' 'Seconds' +execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1', 'dead-interval', '1' +execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1', 'dead-interval', '1' +complete 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==2 +describe 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0 + '<1-65535>' 'Seconds' +execute relaxed 'clear bgp 1 out'@4: rv==0, 'clear bgp <1-4294967295> out': '1' +execute strict 'clear bgp 1 out'@4: rv==0, 'clear bgp <1-4294967295> out': '1' +complete 'clear bgp 1 out'@4: rv==7 + 'out' +describe 'clear bgp 1 out'@4: rv==0 + 'out' 'Soft reconfig outbound update' +execute relaxed 'clear bgp ipv6 2001:db8::1 out'@4: rv==0, 'clear bgp ipv6 (A.B.C.D|X:X::X:X) out': '2001:db8::1' +execute strict 'clear bgp ipv6 2001:db8::1 out'@4: rv==0, 'clear bgp ipv6 (A.B.C.D|X:X::X:X) out': '2001:db8::1' +complete 'clear bgp ipv6 2001:db8::1 out'@4: rv==7 + 'out' +describe 'clear bgp ipv6 2001:db8::1 out'@4: rv==0 + 'out' 'Soft reconfig outbound update' +execute relaxed 'clear bgp view VARIABLE * soft'@4: rv==0, 'clear bgp view WORD * soft': 'VARIABLE' +execute strict 'clear bgp view VARIABLE * soft'@4: rv==0, 'clear bgp view WORD * soft': 'VARIABLE' +complete 'clear bgp view VARIABLE * soft'@4: rv==7 + 'soft' +describe 'clear bgp view VARIABLE * soft'@4: rv==0 + 'soft' 'Soft reconfig' +execute relaxed 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0, 'clear ip bgp A.B.C.D ipv4 (unicast|multicast) out': '1.2.3.4', 'multicast' +execute strict 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0, 'clear ip bgp A.B.C.D ipv4 (unicast|multicast) out': '1.2.3.4', 'multicast' +complete 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==7 + 'out' +describe 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0 + 'out' 'Soft reconfig outbound update' +execute relaxed 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0, 'ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) (<0-4294967295>|infinite) (no-autoconfig|)': '2001:db8::/32', 'infinite', 'infinite', 'no-autoconfig' +execute strict 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0, 'ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) (<0-4294967295>|infinite) (no-autoconfig|)': '2001:db8::/32', 'infinite', 'infinite', 'no-autoconfig' +complete 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==7 + 'no-autoconfig' +describe 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0 + 'no-autoconfig' 'Do not use prefix for autoconfiguration' +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0 + '<1-255>' 'Distance value for this prefix' +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 +execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' +execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 +complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 +describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 +execute relaxed 'network 1.0.0.0/8 area 0'@23: rv==0, 'network A.B.C.D/M area (A.B.C.D|<0-4294967295>)': '1.0.0.0/8', '0' +execute strict 'network 1.0.0.0/8 area 0'@23: rv==0, 'network A.B.C.D/M area (A.B.C.D|<0-4294967295>)': '1.0.0.0/8', '0' +complete 'network 1.0.0.0/8 area 0'@23: rv==2 +describe 'network 1.0.0.0/8 area 0'@23: rv==0 + '<0-4294967295>' 'OSPF area ID as a decimal value' + 'A.B.C.D' 'OSPF area ID in IP address format' +execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'hello-interval', 'transmit-delay' +execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'hello-interval', 'transmit-delay' +complete 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==7 + 'transmit-delay' +describe 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0 + 'transmit-delay' 'Seconds' +execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'retransmit-interval', 'transmit-delay' +execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'retransmit-interval', 'transmit-delay' +complete 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==7 + 'transmit-delay' +describe 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0 + 'transmit-delay' 'Seconds' +execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'retransmit-interval', 'dead-interval', 'retransmit-interval', 'hello-interval' +execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'retransmit-interval', 'dead-interval', 'retransmit-interval', 'hello-interval' +complete 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==7 + 'hello-interval' +describe 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0 + 'hello-interval' 'Link state transmit delay' +execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'transmit-delay', 'retransmit-interval', 'retransmit-interval', 'hello-interval' +execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'transmit-delay', 'retransmit-interval', 'retransmit-interval', 'hello-interval' +complete 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==7 + 'hello-interval' +describe 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0 + 'hello-interval' 'Link state transmit delay' +execute relaxed 'no bgp graceful-restart'@17: rv==0, 'no bgp graceful-restart' +execute strict 'no bgp graceful-restart'@17: rv==0, 'no bgp graceful-restart' +complete 'no bgp graceful-restart'@17: rv==7 + 'graceful-restart' +describe 'no bgp graceful-restart'@17: rv==0 + 'graceful-restart' 'Graceful restart capability parameters' +execute relaxed 'no bgp graceful-restart'@18: rv==0, 'no bgp graceful-restart' +execute strict 'no bgp graceful-restart'@18: rv==2 +complete 'no bgp graceful-restart'@18: rv==2 +describe 'no bgp graceful-restart'@18: rv==2 +execute relaxed 'no bgp graceful-restart'@19: rv==0, 'no bgp graceful-restart' +execute strict 'no bgp graceful-restart'@19: rv==2 +complete 'no bgp graceful-restart'@19: rv==2 +describe 'no bgp graceful-restart'@19: rv==2 +execute relaxed 'no bgp graceful-restart'@20: rv==0, 'no bgp graceful-restart' +execute strict 'no bgp graceful-restart'@20: rv==2 +complete 'no bgp graceful-restart'@20: rv==2 +describe 'no bgp graceful-restart'@20: rv==2 +execute relaxed 'no bgp graceful-restart'@21: rv==0, 'no bgp graceful-restart' +execute strict 'no bgp graceful-restart'@21: rv==2 +complete 'no bgp graceful-restart'@21: rv==2 +describe 'no bgp graceful-restart'@21: rv==2 +execute relaxed 'no bgp graceful-restart'@22: rv==0, 'no bgp graceful-restart' +execute strict 'no bgp graceful-restart'@22: rv==2 +complete 'no bgp graceful-restart'@22: rv==2 +describe 'no bgp graceful-restart'@22: rv==2 +execute relaxed 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' +execute strict 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' +complete 'no ipv6 nd mtu 1'@11: rv==2 +describe 'no ipv6 nd mtu 1'@11: rv==0 + '<1-65535>' 'MTU in bytes' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +complete 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==7 + 'in' +describe 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0 + 'in' 'Filter incoming updates' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +complete 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==7 + 'in' +describe 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0 + 'in' 'Filter incoming updates' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +complete 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==7 + 'in' +describe 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0 + 'in' 'Filter incoming updates' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +complete 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==7 + 'in' +describe 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0 + 'in' 'Filter incoming updates' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +complete 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==7 + 'in' +describe 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0 + 'in' 'Filter incoming updates' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +complete 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==7 + 'in' +describe 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0 + 'in' 'Filter incoming updates' +execute relaxed 'no neighbor 2001:db8::1 send-community both'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +execute strict 'no neighbor 2001:db8::1 send-community both'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +complete 'no neighbor 2001:db8::1 send-community both'@17: rv==7 + 'both' +describe 'no neighbor 2001:db8::1 send-community both'@17: rv==0 + 'both' 'Send Standard and Extended Community attributes' +execute relaxed 'no neighbor 2001:db8::1 send-community both'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +execute strict 'no neighbor 2001:db8::1 send-community both'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +complete 'no neighbor 2001:db8::1 send-community both'@18: rv==7 + 'both' +describe 'no neighbor 2001:db8::1 send-community both'@18: rv==0 + 'both' 'Send Standard and Extended Community attributes' +execute relaxed 'no neighbor 2001:db8::1 send-community both'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +execute strict 'no neighbor 2001:db8::1 send-community both'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +complete 'no neighbor 2001:db8::1 send-community both'@19: rv==7 + 'both' +describe 'no neighbor 2001:db8::1 send-community both'@19: rv==0 + 'both' 'Send Standard and Extended Community attributes' +execute relaxed 'no neighbor 2001:db8::1 send-community both'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +execute strict 'no neighbor 2001:db8::1 send-community both'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +complete 'no neighbor 2001:db8::1 send-community both'@20: rv==7 + 'both' +describe 'no neighbor 2001:db8::1 send-community both'@20: rv==0 + 'both' 'Send Standard and Extended Community attributes' +execute relaxed 'no neighbor 2001:db8::1 send-community both'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +execute strict 'no neighbor 2001:db8::1 send-community both'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +complete 'no neighbor 2001:db8::1 send-community both'@21: rv==7 + 'both' +describe 'no neighbor 2001:db8::1 send-community both'@21: rv==0 + 'both' 'Send Standard and Extended Community attributes' +execute relaxed 'no neighbor 2001:db8::1 send-community both'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +execute strict 'no neighbor 2001:db8::1 send-community both'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' +complete 'no neighbor 2001:db8::1 send-community both'@22: rv==7 + 'both' +describe 'no neighbor 2001:db8::1 send-community both'@22: rv==0 + 'both' 'Send Standard and Extended Community attributes' +execute relaxed 'no neighbor VARIABLE maximum-prefix'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +execute strict 'no neighbor VARIABLE maximum-prefix'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +complete 'no neighbor VARIABLE maximum-prefix'@17: rv==7 + 'maximum-prefix' +describe 'no neighbor VARIABLE maximum-prefix'@17: rv==0 + 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'no neighbor VARIABLE maximum-prefix'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +execute strict 'no neighbor VARIABLE maximum-prefix'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +complete 'no neighbor VARIABLE maximum-prefix'@18: rv==7 + 'maximum-prefix' +describe 'no neighbor VARIABLE maximum-prefix'@18: rv==0 + 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'no neighbor VARIABLE maximum-prefix'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +execute strict 'no neighbor VARIABLE maximum-prefix'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +complete 'no neighbor VARIABLE maximum-prefix'@19: rv==7 + 'maximum-prefix' +describe 'no neighbor VARIABLE maximum-prefix'@19: rv==0 + 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'no neighbor VARIABLE maximum-prefix'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +execute strict 'no neighbor VARIABLE maximum-prefix'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +complete 'no neighbor VARIABLE maximum-prefix'@20: rv==7 + 'maximum-prefix' +describe 'no neighbor VARIABLE maximum-prefix'@20: rv==0 + 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'no neighbor VARIABLE maximum-prefix'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +execute strict 'no neighbor VARIABLE maximum-prefix'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +complete 'no neighbor VARIABLE maximum-prefix'@21: rv==7 + 'maximum-prefix' +describe 'no neighbor VARIABLE maximum-prefix'@21: rv==0 + 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'no neighbor VARIABLE maximum-prefix'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +execute strict 'no neighbor VARIABLE maximum-prefix'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' +complete 'no neighbor VARIABLE maximum-prefix'@22: rv==7 + 'maximum-prefix' +describe 'no neighbor VARIABLE maximum-prefix'@22: rv==0 + 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==7 + 'exact-match' +describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==7 + 'exact-match' +describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==7 + 'exact-match' +describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' +execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' +complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==7 + 'no-export' +describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0 + 'AA:NN' 'community number' + 'no-export' 'Do not export to next AS (well-known community)' +execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' +execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' +complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==7 + 'no-export' +describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0 + 'AA:NN' 'community number' + 'no-export' 'Do not export to next AS (well-known community)' +execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' +execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' +complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==7 + 'no-export' +describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0 + 'AA:NN' 'community number' + 'no-export' 'Do not export to next AS (well-known community)' +execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' +execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' +complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==7 + 'exact-match' +describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' +execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' +complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==7 + 'exact-match' +describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' +execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' +complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==7 + 'exact-match' +describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' +execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' +complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==7 + 'exact-match' +describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' +execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' +complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==7 + 'exact-match' +describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' +execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' +complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==7 + 'exact-match' +describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp view VARIABLE'@1: rv==4 +execute strict 'show bgp view VARIABLE'@1: rv==4 +complete 'show bgp view VARIABLE'@1: rv==2 +describe 'show bgp view VARIABLE'@1: rv==0 + 'WORD' 'View name' +execute relaxed 'show bgp view VARIABLE'@2: rv==0, 'show bgp view WORD': 'VARIABLE' +execute strict 'show bgp view VARIABLE'@2: rv==0, 'show bgp view WORD': 'VARIABLE' +complete 'show bgp view VARIABLE'@2: rv==2 +describe 'show bgp view VARIABLE'@2: rv==0 + 'WORD' 'View name' +execute relaxed 'show bgp view VARIABLE'@4: rv==0, 'show bgp view WORD': 'VARIABLE' +execute strict 'show bgp view VARIABLE'@4: rv==0, 'show bgp view WORD': 'VARIABLE' +complete 'show bgp view VARIABLE'@4: rv==2 +describe 'show bgp view VARIABLE'@4: rv==0 + 'WORD' 'View name' +execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' +execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' +complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==2 +describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' +execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' +complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==2 +describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' +execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' +complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==2 +describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' +execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' +complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==7 + 'local-AS' +describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' +execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' +complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==7 + 'local-AS' +describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' +execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' +complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==7 + 'local-AS' +describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' +execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' +complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==7 + 'no-advertise' +describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0 + 'AA:NN' 'community number' + 'no-advertise' 'Do not advertise to any peer (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' +execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' +complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==7 + 'no-advertise' +describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0 + 'AA:NN' 'community number' + 'no-advertise' 'Do not advertise to any peer (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' +execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' +complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==7 + 'no-advertise' +describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0 + 'AA:NN' 'community number' + 'no-advertise' 'Do not advertise to any peer (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==2 +describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==2 +describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' +complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==2 +describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==7 + 'local-AS' +describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==7 + 'local-AS' +describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==7 + 'local-AS' +describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' +execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' +complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==2 +describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' +execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' +complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==2 +describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' +execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' +complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==2 +describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' +complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' +execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' +complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' +execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' +complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' +execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' +complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' +execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' +complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' +execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' +complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' +execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' +complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' +execute strict 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' +complete 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==2 +describe 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' +execute strict 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' +complete 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==2 +describe 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' +execute strict 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' +complete 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==7 + 'exact-match' +describe 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' +execute strict 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' +complete 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==7 + 'exact-match' +describe 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' +execute strict 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' +complete 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==7 + 'exact-match' +describe 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' +execute strict 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' +complete 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==7 + 'exact-match' +describe 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' +execute strict 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' +complete 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==7 + 'exact-match' +describe 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' +execute strict 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' +complete 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==7 + 'exact-match' +describe 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' +execute strict 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' +complete 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==7 + 'exact-match' +describe 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' +execute strict 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' +complete 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==7 + 'exact-match' +describe 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 ospf6 database as-external dump'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' +execute strict 'show ipv6 ospf6 database as-external dump'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' +complete 'show ipv6 ospf6 database as-external dump'@2: rv==7 + 'dump' +describe 'show ipv6 ospf6 database as-external dump'@2: rv==0 + 'dump' 'Dump LSAs' +execute relaxed 'show ipv6 ospf6 database as-external dump'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' +execute strict 'show ipv6 ospf6 database as-external dump'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' +complete 'show ipv6 ospf6 database as-external dump'@4: rv==7 + 'dump' +describe 'show ipv6 ospf6 database as-external dump'@4: rv==0 + 'dump' 'Dump LSAs' +execute relaxed 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' +execute strict 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' +complete 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==7 + 'detail' +describe 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0 + 'detail' 'Display details of LSAs' +execute relaxed 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' +execute strict 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' +complete 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==7 + 'detail' +describe 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0 + 'detail' 'Display details of LSAs' +execute relaxed 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' +execute strict 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' +complete 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==7 + 'internal' +describe 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0 + 'internal' 'Display LSA's internal information' +execute relaxed 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' +execute strict 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' +complete 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==7 + 'internal' +describe 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0 + 'internal' 'Display LSA's internal information' +execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'dead-interva', '1', 'retransmit-interval', '1', 'transmit-delay', '1' +execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 +complete 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 +describe 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==0 + '<1-65535>' 'Seconds' +execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' +execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' +complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==7 + 'exact-match' +describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' +execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' +complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==7 + 'exact-match' +describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' +execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' +complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==7 + 'exact-match' +describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' +execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' +complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==2 +describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' +execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' +complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==2 +describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' +execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' +complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==2 +describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' +execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' +complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==2 +describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' +execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' +complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==2 +describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' +execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' +complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==2 +describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' +execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' +complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==7 + 'local-AS' +describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' +execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' +complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==7 + 'local-AS' +describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' +execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' +complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==7 + 'local-AS' +describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' +execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' +complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==2 +describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' +execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' +complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==2 +describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' +execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' +complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==2 +describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' +execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' +complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==2 +describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' +execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' +complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==2 +describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' +execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' +complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==2 +describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' +execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' +complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==2 +describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' +execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' +complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==2 +describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' +execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' +complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==2 +describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' +execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' +complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==7 + 'local-AS' +describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' +execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' +complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==7 + 'local-AS' +describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' +execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' +complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==7 + 'local-AS' +describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0 + 'AA:NN' 'community number' + 'local-AS' 'Do not send outside local AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' +execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' +complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==7 + 'no-export' +describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0 + 'AA:NN' 'community number' + 'no-export' 'Do not export to next AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' +execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' +complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==7 + 'no-export' +describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0 + 'AA:NN' 'community number' + 'no-export' 'Do not export to next AS (well-known community)' +execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' +execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' +complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==7 + 'no-export' +describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0 + 'AA:NN' 'community number' + 'no-export' 'Do not export to next AS (well-known community)' +execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' +execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' +complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==2 +describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' +execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' +complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==2 +describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' +execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' +complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==2 +describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' +execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' +complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==2 +describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' +execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' +complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==2 +describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' +execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' +complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==2 +describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' +execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' +complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' +execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' +complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' +execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' +complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==7 + 'exact-match' +describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' +execute strict 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' +complete 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==7 + 'exact-match' +describe 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' +execute strict 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' +complete 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==7 + 'exact-match' +describe 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' +execute strict 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' +complete 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==2 +describe 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' +execute strict 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' +complete 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==2 +describe 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' +execute strict 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' +complete 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==7 + 'exact-match' +describe 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' +execute strict 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' +complete 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==7 + 'exact-match' +describe 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0 + 'exact-match' 'Exact match of the communities' +execute relaxed 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' +execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' +complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==2 +describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0 + 'AA:NN' 'community number' +execute relaxed 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' +execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' +complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==2 +describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0 + 'AA:NN' 'community number' From e712d0e3667ffad8109ef8bce3ce01927ee95bb7 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 1 Apr 2014 19:34:55 +0200 Subject: [PATCH 0334/1342] tests: fix build & disable testcommands The perils of having tests, the test wasn't tested thoroughly enough... Fixup various automake problems, and then disable it since it depends on configure parameters in its current version. For 0.99.24 we can ship a static copy of vtysh_cmd.c and have it reenabled. Signed-off-by: David Lamparter --- tests/Makefile.am | 3 ++- tests/libzebra.tests/testcommands.exp | 10 +++++++++- tests/{testcommands.out => testcommands.refout} | 0 3 files changed, 11 insertions(+), 2 deletions(-) rename tests/{testcommands.out => testcommands.refout} (100%) diff --git a/tests/Makefile.am b/tests/Makefile.am index ceca606a5..8707fe7d9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,7 +11,7 @@ EXTRA_DIST = \ lib/libzebra.exp \ global-conf.exp \ testcommands.in \ - testcommands.out + testcommands.refout INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" @@ -42,6 +42,7 @@ test-commands-defun.c: ../vtysh/vtysh_cmd.c < ../vtysh/vtysh_cmd.c \ > test-commands-defun.c +BUILT_SOURCES = test-commands-defun.c noinst_HEADERS = prng.h testsig_SOURCES = test-sig.c diff --git a/tests/libzebra.tests/testcommands.exp b/tests/libzebra.tests/testcommands.exp index f760c6d7f..d4bfc8231 100644 --- a/tests/libzebra.tests/testcommands.exp +++ b/tests/libzebra.tests/testcommands.exp @@ -1,7 +1,15 @@ set timeout 30 set test_name "testcommands" -spawn sh -c "./testcommands -e 0 < testcommands.in | diff -au - testcommands.out" +if {![info exists env(QUAGGA_TEST_COMMANDS)]} { + # sadly, the test randomly fails when configure parameters differ from + # what was used to create testcommands.refout. this can be fixed by + # shipping a matching vtysh_cmd.c, which we'll add after 0.99.23 + unresolved "$test_name" + exit 0 +} + +spawn sh -c "./testcommands -e 0 < $env(srcdir)/testcommands.in | diff -au - $env(srcdir)/testcommands.refout" expect { eof { diff --git a/tests/testcommands.out b/tests/testcommands.refout similarity index 100% rename from tests/testcommands.out rename to tests/testcommands.refout From cd40b329a2e4da882bcad0431c048c876bbeafbd Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 30 Sep 2013 12:27:51 +0000 Subject: [PATCH 0335/1342] lib/command.c: rewrite command matching/parsing Add support for keyword commands. Includes new documentation for DEFUN() in lib/command.h, for preexisting features as well as new keyword specification. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- babeld/babel_main.c | 3 - bgpd/bgp_main.c | 3 - isisd/isis_main.c | 2 - lib/command.c | 1977 ++++++++++++++++++++++++++--------------- lib/command.h | 193 +++- lib/memtypes.c | 2 +- lib/vty.c | 54 +- ospf6d/ospf6_main.c | 3 - ospfd/ospf_main.c | 2 - ripd/rip_main.c | 3 - ripngd/ripng_main.c | 3 - tests/main.c | 2 - tests/test-commands.c | 6 +- vtysh/vtysh.c | 22 +- vtysh/vtysh_main.c | 2 - zebra/main.c | 3 - zebra/test_main.c | 3 - 17 files changed, 1495 insertions(+), 788 deletions(-) diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 7b1d87996..529c3f295 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -277,9 +277,6 @@ babel_init(int argc, char **argv) /* this replace kernel_setup && kernel_setup_socket */ babelz_zebra_init (); - /* Sort all installed commands. */ - sort_node (); - /* Get zebra configuration file. */ zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); vty_read_config (babel_config_file, babel_config_default); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1ff1ac952..1be65043b 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -431,9 +431,6 @@ main (int argc, char **argv) /* BGP related initialization. */ bgp_init (); - /* Sort CLI commands. */ - sort_node (); - /* Parse config file. */ vty_read_config (config_file, config_default); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 96816ebb2..283b7eaae 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -339,8 +339,6 @@ main (int argc, char **argv, char **envp) isis_zebra_init (); - sort_node (); - /* parse config file */ /* this is needed three times! because we have interfaces before the areas */ vty_read_config (config_file, config_default); diff --git a/lib/command.c b/lib/command.c index 3b3fadac4..a23736441 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1,6 +1,8 @@ /* Command interpreter routine for virtual terminal [aka TeletYpe] Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + Copyright (C) 2013 by Open Source Routing. + Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") This file is part of GNU Zebra. @@ -35,9 +37,32 @@ Boston, MA 02111-1307, USA. */ each daemon maintains each own cmdvec. */ vector cmdvec = NULL; -struct desc desc_cr; +struct cmd_token token_cr; char *command_cr = NULL; +enum filter_type +{ + FILTER_RELAXED, + FILTER_STRICT +}; + +enum matcher_rv +{ + MATCHER_OK, + MATCHER_COMPLETE, + MATCHER_INCOMPLETE, + MATCHER_NO_MATCH, + MATCHER_AMBIGUOUS, + MATCHER_EXCEED_ARGC_MAX +}; + +#define MATCHER_ERROR(matcher_rv) \ + ( (matcher_rv) == MATCHER_INCOMPLETE \ + || (matcher_rv) == MATCHER_NO_MATCH \ + || (matcher_rv) == MATCHER_AMBIGUOUS \ + || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \ + ) + /* Host information structure. */ struct host host; @@ -196,53 +221,6 @@ install_node (struct cmd_node *node, node->cmd_vector = vector_init (VECTOR_MIN_SIZE); } -/* Compare two command's string. Used in sort_node (). */ -static int -cmp_node (const void *p, const void *q) -{ - const struct cmd_element *a = *(struct cmd_element * const *)p; - const struct cmd_element *b = *(struct cmd_element * const *)q; - - return strcmp (a->string, b->string); -} - -static int -cmp_desc (const void *p, const void *q) -{ - const struct desc *a = *(struct desc * const *)p; - const struct desc *b = *(struct desc * const *)q; - - return strcmp (a->cmd, b->cmd); -} - -/* Sort each node's command element according to command string. */ -void -sort_node () -{ - unsigned int i, j; - struct cmd_node *cnode; - vector descvec; - struct cmd_element *cmd_element; - - for (i = 0; i < vector_active (cmdvec); i++) - if ((cnode = vector_slot (cmdvec, i)) != NULL) - { - vector cmd_vector = cnode->cmd_vector; - qsort (cmd_vector->index, vector_active (cmd_vector), - sizeof (void *), cmp_node); - - for (j = 0; j < vector_active (cmd_vector); j++) - if ((cmd_element = vector_slot (cmd_vector, j)) != NULL - && vector_active (cmd_element->strvec)) - { - descvec = vector_slot (cmd_element->strvec, - vector_active (cmd_element->strvec) - 1); - qsort (descvec->index, vector_active (descvec), - sizeof (void *), cmp_desc); - } - } -} - /* Breaking up string into each command piece. I assume given character is separated by a space character. Return value is a vector which includes char ** data element. */ @@ -312,15 +290,46 @@ cmd_free_strvec (vector v) vector_free (v); } -/* Fetch next description. Used in cmd_make_descvec(). */ +struct format_parser_state +{ + vector topvect; /* Top level vector */ + vector intvect; /* Intermediate level vector, used when there's + * a multiple in a keyword. */ + vector curvect; /* current vector where read tokens should be + appended. */ + + const char *string; /* pointer to command string, not modified */ + const char *cp; /* pointer in command string, moved along while + parsing */ + const char *dp; /* pointer in description string, moved along while + parsing */ + + int in_keyword; /* flag to remember if we are in a keyword group */ + int in_multiple; /* flag to remember if we are in a multiple group */ + int just_read_word; /* flag to remember if the last thing we red was a + * real word and not some abstract token */ +}; + +static void +format_parser_error(struct format_parser_state *state, const char *message) +{ + int offset = state->cp - state->string + 1; + + fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string); + fprintf(stderr, " %*c\n", offset, '^'); + fprintf(stderr, "%s at offset %d.\n", message, offset); + fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n"); + exit(1); +} + static char * -cmd_desc_str (const char **string) +format_parser_desc_str(struct format_parser_state *state) { const char *cp, *start; char *token; int strlen; - - cp = *string; + + cp = state->dp; if (cp == NULL) return NULL; @@ -339,132 +348,226 @@ cmd_desc_str (const char **string) cp++; strlen = cp - start; - token = XMALLOC (MTYPE_STRVEC, strlen + 1); + token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1); memcpy (token, start, strlen); *(token + strlen) = '\0'; - *string = cp; + state->dp = cp; return token; } -/* New string vector. */ -static vector -cmd_make_descvec (const char *string, const char *descstr) +static void +format_parser_begin_keyword(struct format_parser_state *state) { - int multiple = 0; - const char *sp; - char *token; - int len; - const char *cp; - const char *dp; - vector allvec; - vector strvec = NULL; - struct desc *desc; + struct cmd_token *token; + vector keyword_vect; - cp = string; - dp = descstr; + if (state->in_keyword + || state->in_multiple) + format_parser_error(state, "Unexpected '{'"); - if (cp == NULL) - return NULL; + state->cp++; + state->in_keyword = 1; - allvec = vector_init (VECTOR_MIN_SIZE); + token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); + token->type = TOKEN_KEYWORD; + token->keyword = vector_init(VECTOR_MIN_SIZE); - while (1) - { - while (isspace ((int) *cp) && *cp != '\0') - cp++; + keyword_vect = vector_init(VECTOR_MIN_SIZE); + vector_set(token->keyword, keyword_vect); - if (*cp == '(') - { - multiple = 1; - cp++; - } - if (*cp == ')') - { - multiple = 0; - cp++; - } - if (*cp == '|') - { - if (! multiple) - { - fprintf (stderr, "Command parse error!: %s\n", string); - exit (1); - } - cp++; - } - - while (isspace ((int) *cp) && *cp != '\0') - cp++; + vector_set(state->curvect, token); + state->curvect = keyword_vect; +} - if (*cp == '(') - { - multiple = 1; - cp++; - } +static void +format_parser_begin_multiple(struct format_parser_state *state) +{ + struct cmd_token *token; - if (*cp == '\0') - return allvec; + if (state->in_keyword == 1) + format_parser_error(state, "Keyword starting with '('"); - sp = cp; + if (state->in_multiple) + format_parser_error(state, "Nested group"); - while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0') - cp++; + state->cp++; + state->in_multiple = 1; + state->just_read_word = 0; + + token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); + token->type = TOKEN_MULTIPLE; + token->multiple = vector_init(VECTOR_MIN_SIZE); - len = cp - sp; + vector_set(state->curvect, token); + if (state->curvect != state->topvect) + state->intvect = state->curvect; + state->curvect = token->multiple; +} - token = XMALLOC (MTYPE_STRVEC, len + 1); - memcpy (token, sp, len); - *(token + len) = '\0'; +static void +format_parser_end_keyword(struct format_parser_state *state) +{ + if (state->in_multiple + || !state->in_keyword) + format_parser_error(state, "Unexpected '}'"); - desc = XCALLOC (MTYPE_DESC, sizeof (struct desc)); - desc->cmd = token; - desc->str = cmd_desc_str (&dp); + if (state->in_keyword == 1) + format_parser_error(state, "Empty keyword group"); - if (multiple) - { - if (multiple == 1) - { - strvec = vector_init (VECTOR_MIN_SIZE); - vector_set (allvec, strvec); - } - multiple++; - } - else - { - strvec = vector_init (VECTOR_MIN_SIZE); - vector_set (allvec, strvec); - } - vector_set (strvec, desc); + state->cp++; + state->in_keyword = 0; + state->curvect = state->topvect; +} + +static void +format_parser_end_multiple(struct format_parser_state *state) +{ + char *dummy; + + if (!state->in_multiple) + format_parser_error(state, "Unepexted ')'"); + + if (vector_active(state->curvect) == 0) + format_parser_error(state, "Empty multiple section"); + + if (!state->just_read_word) + { + /* There are constructions like + * 'show ip ospf database ... (self-originate|)' + * in use. + * The old parser reads a description string for the + * word '' between |) which will never match. + * Simulate this behvaior by dropping the next desc + * string in such a case. */ + + dummy = format_parser_desc_str(state); + XFREE(MTYPE_CMD_TOKENS, dummy); } + + state->cp++; + state->in_multiple = 0; + + if (state->intvect) + state->curvect = state->intvect; + else + state->curvect = state->topvect; } -/* Count mandantory string vector size. This is to determine inputed - command has enough command length. */ -static int -cmd_cmdsize (vector strvec) +static void +format_parser_handle_pipe(struct format_parser_state *state) { - unsigned int i; - int size = 0; - vector descvec; - struct desc *desc; + struct cmd_token *keyword_token; + vector keyword_vect; - for (i = 0; i < vector_active (strvec); i++) - if ((descvec = vector_slot (strvec, i)) != NULL) + if (state->in_multiple) { - if ((vector_active (descvec)) == 1 - && (desc = vector_slot (descvec, 0)) != NULL) - { - if (desc->cmd == NULL || CMD_OPTION (desc->cmd)) - return size; - else - size++; - } - else - size++; + state->just_read_word = 0; + state->cp++; + } + else if (state->in_keyword) + { + state->in_keyword = 1; + state->cp++; + + keyword_token = vector_slot(state->topvect, + vector_active(state->topvect) - 1); + keyword_vect = vector_init(VECTOR_MIN_SIZE); + vector_set(keyword_token->keyword, keyword_vect); + state->curvect = keyword_vect; + } + else + { + format_parser_error(state, "Unexpected '|'"); + } +} + +static void +format_parser_read_word(struct format_parser_state *state) +{ + const char *start; + int len; + char *cmd; + struct cmd_token *token; + + start = state->cp; + + while (state->cp[0] != '\0' + && !strchr("\r\n(){}|", state->cp[0]) + && !isspace((int)state->cp[0])) + state->cp++; + + len = state->cp - start; + cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1); + memcpy(cmd, start, len); + cmd[len] = '\0'; + + token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); + token->type = TOKEN_TERMINAL; + token->cmd = cmd; + token->desc = format_parser_desc_str(state); + vector_set(state->curvect, token); + + if (state->in_keyword == 1) + state->in_keyword = 2; + + state->just_read_word = 1; +} + +/** + * Parse a given command format string and build a tree of tokens from + * it that is suitable to be used by the command subsystem. + * + * @param string Command format string. + * @param descstr Description string. + * @return A vector of struct cmd_token representing the given command, + * or NULL on error. + */ +static vector +cmd_parse_format(const char *string, const char *descstr) +{ + struct format_parser_state state; + + if (string == NULL) + return NULL; + + memset(&state, 0, sizeof(state)); + state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE); + state.cp = state.string = string; + state.dp = descstr; + + while (1) + { + while (isspace((int)state.cp[0]) && state.cp[0] != '\0') + state.cp++; + + switch (state.cp[0]) + { + case '\0': + if (state.in_keyword + || state.in_multiple) + format_parser_error(&state, "Unclosed group/keyword"); + return state.topvect; + case '{': + format_parser_begin_keyword(&state); + break; + case '(': + format_parser_begin_multiple(&state); + break; + case '}': + format_parser_end_keyword(&state); + break; + case ')': + format_parser_end_multiple(&state); + break; + case '|': + format_parser_handle_pipe(&state); + break; + default: + format_parser_read_word(&state); + } } - return size; } /* Return prompt character of specified node. */ @@ -497,11 +600,8 @@ install_element (enum node_type ntype, struct cmd_element *cmd) } vector_set (cnode->cmd_vector, cmd); - - if (cmd->strvec == NULL) - cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc); - - cmd->cmdsize = cmd_cmdsize (cmd->strvec); + if (cmd->tokens == NULL) + cmd->tokens = cmd_parse_format(cmd->string, cmd->doc); } static const unsigned char itoa64[] = @@ -847,9 +947,6 @@ cmd_ipv4_prefix_match (const char *str) static enum match_type cmd_ipv6_match (const char *str) { - int state = STATE_START; - int colons = 0, nums = 0, double_colon = 0; - const char *sp = NULL; struct sockaddr_in6 sin6_dummy; int ret; @@ -1056,254 +1153,700 @@ cmd_range_match (const char *range, const char *str) return 1; } -/* Make completion match and return match type flag. */ static enum match_type -cmd_filter_by_completion (char *command, vector v, unsigned int index) +cmd_word_match(struct cmd_token *token, + enum filter_type filter, + const char *word) { - unsigned int i; const char *str; - struct cmd_element *cmd_element; enum match_type match_type; - vector descvec; - struct desc *desc; - match_type = no_match; + str = token->cmd; - /* If command and cmd_element string does not match set NULL to vector */ - for (i = 0; i < vector_active (v); i++) - if ((cmd_element = vector_slot (v, i)) != NULL) - { - if (index >= vector_active (cmd_element->strvec)) - vector_slot (v, i) = NULL; - else - { - unsigned int j; - int matched = 0; + if (filter == FILTER_RELAXED) + if (!word || !strlen(word)) + return partly_match; - descvec = vector_slot (cmd_element->strvec, index); - - for (j = 0; j < vector_active (descvec); j++) - if ((desc = vector_slot (descvec, j))) - { - str = desc->cmd; - - if (CMD_VARARG (str)) - { - if (match_type < vararg_match) - match_type = vararg_match; - matched++; - } - else if (CMD_RANGE (str)) - { - if (cmd_range_match (str, command)) - { - if (match_type < range_match) - match_type = range_match; + if (!word) + return no_match; - matched++; - } - } + if (CMD_VARARG(str)) + { + return vararg_match; + } + else if (CMD_RANGE(str)) + { + if (cmd_range_match(str, word)) + return range_match; + } #ifdef HAVE_IPV6 - else if (CMD_IPV6 (str)) - { - if (cmd_ipv6_match (command)) - { - if (match_type < ipv6_match) - match_type = ipv6_match; + else if (CMD_IPV6(str)) + { + match_type = cmd_ipv6_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv6_match; + } + else if (CMD_IPV6_PREFIX(str)) + { + match_type = cmd_ipv6_prefix_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv6_prefix_match; + } +#endif /* HAVE_IPV6 */ + else if (CMD_IPV4(str)) + { + match_type = cmd_ipv4_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv4_match; + } + else if (CMD_IPV4_PREFIX(str)) + { + match_type = cmd_ipv4_prefix_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv4_prefix_match; + } + else if (CMD_OPTION(str) || CMD_VARIABLE(str)) + { + return extend_match; + } + else + { + if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word))) + { + if (!strcmp(str, word)) + return exact_match; + return partly_match; + } + if (filter == FILTER_STRICT && !strcmp(str, word)) + return exact_match; + } - matched++; - } - } - else if (CMD_IPV6_PREFIX (str)) - { - if (cmd_ipv6_prefix_match (command)) - { - if (match_type < ipv6_prefix_match) - match_type = ipv6_prefix_match; + return no_match; +} - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4 (str)) - { - if (cmd_ipv4_match (command)) - { - if (match_type < ipv4_match) - match_type = ipv4_match; +struct cmd_matcher +{ + struct cmd_element *cmd; /* The command element the matcher is using */ + enum filter_type filter; /* Whether to use strict or relaxed matching */ + vector vline; /* The tokenized commandline which is to be matched */ + unsigned int index; /* The index up to which matching should be done */ - matched++; - } - } - else if (CMD_IPV4_PREFIX (str)) - { - if (cmd_ipv4_prefix_match (command)) - { - if (match_type < ipv4_prefix_match) - match_type = ipv4_prefix_match; - matched++; - } - } - else - /* Check is this point's argument optional ? */ - if (CMD_OPTION (str) || CMD_VARIABLE (str)) - { - if (match_type < extend_match) - match_type = extend_match; - matched++; - } - else if (strncmp (command, str, strlen (command)) == 0) - { - if (strcmp (command, str) == 0) - match_type = exact_match; - else - { - if (match_type < partly_match) - match_type = partly_match; - } - matched++; - } - } - if (!matched) - vector_slot (v, i) = NULL; - } + /* If set, construct a list of matches at the position given by index */ + enum match_type *match_type; + vector *match; + + unsigned int word_index; /* iterating over vline */ +}; + +static int +push_argument(int *argc, const char **argv, const char *arg) +{ + if (!arg || !strlen(arg)) + arg = NULL; + + if (!argc || !argv) + return 0; + + if (*argc >= CMD_ARGC_MAX) + return -1; + + argv[(*argc)++] = arg; + return 0; +} + +static void +cmd_matcher_record_match(struct cmd_matcher *matcher, + enum match_type match_type, + struct cmd_token *token) +{ + if (matcher->word_index != matcher->index) + return; + + if (matcher->match) + { + if (!*matcher->match) + *matcher->match = vector_init(VECTOR_MIN_SIZE); + vector_set(*matcher->match, token); + } + + if (matcher->match_type) + { + if (match_type > *matcher->match_type) + *matcher->match_type = match_type; + } +} + +static int +cmd_matcher_words_left(struct cmd_matcher *matcher) +{ + return matcher->word_index < vector_active(matcher->vline); +} + +static const char* +cmd_matcher_get_word(struct cmd_matcher *matcher) +{ + assert(cmd_matcher_words_left(matcher)); + + return vector_slot(matcher->vline, matcher->word_index); +} + +static enum matcher_rv +cmd_matcher_match_terminal(struct cmd_matcher *matcher, + struct cmd_token *token, + int *argc, const char **argv) +{ + const char *word; + enum match_type word_match; + + assert(token->type == TOKEN_TERMINAL); + + if (!cmd_matcher_words_left(matcher)) + { + if (CMD_OPTION(token->cmd)) + return MATCHER_OK; /* missing optional args are NOT pushed as NULL */ + else + return MATCHER_INCOMPLETE; + } + + word = cmd_matcher_get_word(matcher); + word_match = cmd_word_match(token, matcher->filter, word); + if (word_match == no_match) + return MATCHER_NO_MATCH; + + /* We have to record the input word as argument if it matched + * against a variable. */ + if (CMD_VARARG(token->cmd) + || CMD_VARIABLE(token->cmd) + || CMD_OPTION(token->cmd)) + { + if (push_argument(argc, argv, word)) + return MATCHER_EXCEED_ARGC_MAX; + } + + cmd_matcher_record_match(matcher, word_match, token); + + matcher->word_index++; + + /* A vararg token should consume all left over words as arguments */ + if (CMD_VARARG(token->cmd)) + while (cmd_matcher_words_left(matcher)) + { + word = cmd_matcher_get_word(matcher); + if (word && strlen(word)) + push_argument(argc, argv, word); + matcher->word_index++; } - return match_type; + + return MATCHER_OK; } -/* Filter vector by command character with index. */ -static enum match_type -cmd_filter_by_string (char *command, vector v, unsigned int index) +static enum matcher_rv +cmd_matcher_match_multiple(struct cmd_matcher *matcher, + struct cmd_token *token, + int *argc, const char **argv) +{ + enum match_type multiple_match; + unsigned int multiple_index; + const char *word; + const char *arg; + struct cmd_token *word_token; + enum match_type word_match; + + assert(token->type == TOKEN_MULTIPLE); + + multiple_match = no_match; + + if (!cmd_matcher_words_left(matcher)) + return MATCHER_INCOMPLETE; + + word = cmd_matcher_get_word(matcher); + for (multiple_index = 0; + multiple_index < vector_active(token->multiple); + multiple_index++) + { + word_token = vector_slot(token->multiple, multiple_index); + + word_match = cmd_word_match(word_token, matcher->filter, word); + if (word_match == no_match) + continue; + + cmd_matcher_record_match(matcher, word_match, word_token); + + if (word_match > multiple_match) + { + multiple_match = word_match; + arg = word; + } + /* To mimic the behavior of the old command implementation, we + * tolerate any ambiguities here :/ */ + } + + matcher->word_index++; + + if (multiple_match == no_match) + return MATCHER_NO_MATCH; + + if (push_argument(argc, argv, arg)) + return MATCHER_EXCEED_ARGC_MAX; + + return MATCHER_OK; +} + +static enum matcher_rv +cmd_matcher_read_keywords(struct cmd_matcher *matcher, + struct cmd_token *token, + vector args_vector) { unsigned int i; - const char *str; - struct cmd_element *cmd_element; - enum match_type match_type; - vector descvec; - struct desc *desc; + unsigned long keyword_mask; + unsigned int keyword_found; + enum match_type keyword_match; + enum match_type word_match; + vector keyword_vector; + struct cmd_token *word_token; + const char *word; + int keyword_argc; + const char **keyword_argv; + enum matcher_rv rv; + + keyword_mask = 0; + while (1) + { + if (!cmd_matcher_words_left(matcher)) + return MATCHER_OK; - match_type = no_match; + word = cmd_matcher_get_word(matcher); - /* If command and cmd_element string does not match set NULL to vector */ - for (i = 0; i < vector_active (v); i++) - if ((cmd_element = vector_slot (v, i)) != NULL) - { - /* If given index is bigger than max string vector of command, - set NULL */ - if (index >= vector_active (cmd_element->strvec)) - vector_slot (v, i) = NULL; - else - { - unsigned int j; - int matched = 0; + keyword_found = -1; + keyword_match = no_match; + for (i = 0; i < vector_active(token->keyword); i++) + { + if (keyword_mask & (1 << i)) + continue; + + keyword_vector = vector_slot(token->keyword, i); + word_token = vector_slot(keyword_vector, 0); + + word_match = cmd_word_match(word_token, matcher->filter, word); + if (word_match == no_match) + continue; + + cmd_matcher_record_match(matcher, word_match, word_token); + + if (word_match > keyword_match) + { + keyword_match = word_match; + keyword_found = i; + } + else if (word_match == keyword_match) + { + if (matcher->word_index != matcher->index || args_vector) + return MATCHER_AMBIGUOUS; + } + } - descvec = vector_slot (cmd_element->strvec, index); + if (keyword_found == (unsigned int)-1) + return MATCHER_NO_MATCH; - for (j = 0; j < vector_active (descvec); j++) - if ((desc = vector_slot (descvec, j))) - { - str = desc->cmd; + matcher->word_index++; - if (CMD_VARARG (str)) - { - if (match_type < vararg_match) - match_type = vararg_match; - matched++; - } - else if (CMD_RANGE (str)) - { - if (cmd_range_match (str, command)) - { - if (match_type < range_match) - match_type = range_match; - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6 (str)) - { - if (cmd_ipv6_match (command) == exact_match) - { - if (match_type < ipv6_match) - match_type = ipv6_match; - matched++; - } - } - else if (CMD_IPV6_PREFIX (str)) - { - if (cmd_ipv6_prefix_match (command) == exact_match) - { - if (match_type < ipv6_prefix_match) - match_type = ipv6_prefix_match; - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4 (str)) - { - if (cmd_ipv4_match (command) == exact_match) - { - if (match_type < ipv4_match) - match_type = ipv4_match; - matched++; - } - } - else if (CMD_IPV4_PREFIX (str)) - { - if (cmd_ipv4_prefix_match (command) == exact_match) - { - if (match_type < ipv4_prefix_match) - match_type = ipv4_prefix_match; - matched++; - } - } - else if (CMD_OPTION (str) || CMD_VARIABLE (str)) - { - if (match_type < extend_match) - match_type = extend_match; - matched++; - } - else - { - if (strcmp (command, str) == 0) - { - match_type = exact_match; - matched++; - } - } - } - if (!matched) - vector_slot (v, i) = NULL; - } + if (matcher->word_index > matcher->index) + return MATCHER_OK; + + keyword_mask |= (1 << keyword_found); + + if (args_vector) + { + keyword_argc = 0; + keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*)); + /* We use -1 as a marker for unused fields as NULL might be a valid value */ + for (i = 0; i < CMD_ARGC_MAX + 1; i++) + keyword_argv[i] = (void*)-1; + vector_set_index(args_vector, keyword_found, keyword_argv); + } + else + { + keyword_argv = NULL; + } + + keyword_vector = vector_slot(token->keyword, keyword_found); + /* the keyword itself is at 0. We are only interested in the arguments, + * so start counting at 1. */ + for (i = 1; i < vector_active(keyword_vector); i++) + { + word_token = vector_slot(keyword_vector, i); + + switch (word_token->type) + { + case TOKEN_TERMINAL: + rv = cmd_matcher_match_terminal(matcher, word_token, + &keyword_argc, keyword_argv); + break; + case TOKEN_MULTIPLE: + rv = cmd_matcher_match_multiple(matcher, word_token, + &keyword_argc, keyword_argv); + break; + case TOKEN_KEYWORD: + assert(!"Keywords should never be nested."); + break; + } + + if (MATCHER_ERROR(rv)) + return rv; + + if (matcher->word_index > matcher->index) + return MATCHER_OK; + } + } + /* not reached */ +} + +static enum matcher_rv +cmd_matcher_build_keyword_args(struct cmd_matcher *matcher, + struct cmd_token *token, + int *argc, const char **argv, + vector keyword_args_vector) +{ + unsigned int i, j; + const char **keyword_args; + vector keyword_vector; + struct cmd_token *word_token; + const char *arg; + enum matcher_rv rv; + + rv = MATCHER_OK; + + if (keyword_args_vector == NULL) + return rv; + + for (i = 0; i < vector_active(token->keyword); i++) + { + keyword_vector = vector_slot(token->keyword, i); + keyword_args = vector_lookup(keyword_args_vector, i); + + if (vector_active(keyword_vector) == 1) + { + /* this is a keyword without arguments */ + if (keyword_args) + { + word_token = vector_slot(keyword_vector, 0); + arg = word_token->cmd; + } + else + { + arg = NULL; + } + + if (push_argument(argc, argv, arg)) + rv = MATCHER_EXCEED_ARGC_MAX; + } + else + { + /* this is a keyword with arguments */ + if (keyword_args) + { + /* the keyword was present, so just fill in the arguments */ + for (j = 0; keyword_args[j] != (void*)-1; j++) + if (push_argument(argc, argv, keyword_args[j])) + rv = MATCHER_EXCEED_ARGC_MAX; + XFREE(MTYPE_TMP, keyword_args); + } + else + { + /* the keyword was not present, insert NULL for the arguments + * the keyword would have taken. */ + for (j = 1; j < vector_active(keyword_vector); j++) + { + word_token = vector_slot(keyword_vector, j); + if ((word_token->type == TOKEN_TERMINAL + && (CMD_VARARG(word_token->cmd) + || CMD_VARIABLE(word_token->cmd) + || CMD_OPTION(word_token->cmd))) + || word_token->type == TOKEN_MULTIPLE) + { + if (push_argument(argc, argv, NULL)) + rv = MATCHER_EXCEED_ARGC_MAX; + } + } + } + } + } + vector_free(keyword_args_vector); + return rv; +} + +static enum matcher_rv +cmd_matcher_match_keyword(struct cmd_matcher *matcher, + struct cmd_token *token, + int *argc, const char **argv) +{ + vector keyword_args_vector; + enum matcher_rv reader_rv; + enum matcher_rv builder_rv; + + assert(token->type == TOKEN_KEYWORD); + + if (argc && argv) + keyword_args_vector = vector_init(VECTOR_MIN_SIZE); + else + keyword_args_vector = NULL; + + reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector); + builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc, + argv, keyword_args_vector); + /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */ + + if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv)) + return builder_rv; + + return reader_rv; +} + +static void +cmd_matcher_init(struct cmd_matcher *matcher, + struct cmd_element *cmd, + enum filter_type filter, + vector vline, + unsigned int index, + enum match_type *match_type, + vector *match) +{ + memset(matcher, 0, sizeof(*matcher)); + + matcher->cmd = cmd; + matcher->filter = filter; + matcher->vline = vline; + matcher->index = index; + + matcher->match_type = match_type; + if (matcher->match_type) + *matcher->match_type = no_match; + matcher->match = match; + + matcher->word_index = 0; +} + +static enum matcher_rv +cmd_element_match(struct cmd_element *cmd_element, + enum filter_type filter, + vector vline, + unsigned int index, + enum match_type *match_type, + vector *match, + int *argc, + const char **argv) +{ + struct cmd_matcher matcher; + unsigned int token_index; + enum matcher_rv rv; + + cmd_matcher_init(&matcher, cmd_element, filter, + vline, index, match_type, match); + + if (argc != NULL) + *argc = 0; + + for (token_index = 0; + token_index < vector_active(cmd_element->tokens); + token_index++) + { + struct cmd_token *token = vector_slot(cmd_element->tokens, token_index); + + switch (token->type) + { + case TOKEN_TERMINAL: + rv = cmd_matcher_match_terminal(&matcher, token, argc, argv); + break; + case TOKEN_MULTIPLE: + rv = cmd_matcher_match_multiple(&matcher, token, argc, argv); + break; + case TOKEN_KEYWORD: + rv = cmd_matcher_match_keyword(&matcher, token, argc, argv); + } + + if (MATCHER_ERROR(rv)) + return rv; + + if (matcher.word_index > index) + return MATCHER_OK; + } + + /* return MATCHER_COMPLETE if all words were consumed */ + if (matcher.word_index >= vector_active(vline)) + return MATCHER_COMPLETE; + + /* return MATCHER_COMPLETE also if only an empty word is left. */ + if (matcher.word_index == vector_active(vline) - 1 + && (!vector_slot(vline, matcher.word_index) + || !strlen((char*)vector_slot(vline, matcher.word_index)))) + return MATCHER_COMPLETE; + + return MATCHER_NO_MATCH; /* command is too long to match */ +} + +/** + * Filter a given vector of commands against a given commandline and + * calculate possible completions. + * + * @param commands A vector of struct cmd_element*. Commands that don't + * match against the given command line will be overwritten + * with NULL in that vector. + * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically + * determines how incomplete commands are handled, compare with + * cmd_word_match for details. + * @param vline A vector of char* containing the tokenized commandline. + * @param index Only match up to the given token of the commandline. + * @param match_type Record the type of the best match here. + * @param matches Record the matches here. For each cmd_element in the commands + * vector, a match vector will be created in the matches vector. + * That vector will contain all struct command_token* of the + * cmd_element which matched against the given vline at the given + * index. + * @return A code specifying if an error occured. If all went right, it's + * CMD_SUCCESS. + */ +static int +cmd_vector_filter(vector commands, + enum filter_type filter, + vector vline, + unsigned int index, + enum match_type *match_type, + vector *matches) +{ + unsigned int i; + struct cmd_element *cmd_element; + enum match_type best_match; + enum match_type element_match; + enum matcher_rv matcher_rv; + + best_match = no_match; + *matches = vector_init(VECTOR_MIN_SIZE); + + for (i = 0; i < vector_active (commands); i++) + if ((cmd_element = vector_slot (commands, i)) != NULL) + { + vector_set_index(*matches, i, NULL); + matcher_rv = cmd_element_match(cmd_element, filter, + vline, index, + &element_match, + (vector*)&vector_slot(*matches, i), + NULL, NULL); + if (MATCHER_ERROR(matcher_rv)) + { + vector_slot(commands, i) = NULL; + if (matcher_rv == MATCHER_AMBIGUOUS) + return CMD_ERR_AMBIGUOUS; + if (matcher_rv == MATCHER_EXCEED_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + else if (element_match > best_match) + { + best_match = element_match; + } } - return match_type; + *match_type = best_match; + return CMD_SUCCESS; +} + +/** + * Check whether a given commandline is complete if used for a specific + * cmd_element. + * + * @param cmd_element A cmd_element against which the commandline should be + * checked. + * @param vline The tokenized commandline. + * @return 1 if the given commandline is complete, 0 otherwise. + */ +static int +cmd_is_complete(struct cmd_element *cmd_element, + vector vline) +{ + enum matcher_rv rv; + + rv = cmd_element_match(cmd_element, + FILTER_RELAXED, + vline, -1, + NULL, NULL, + NULL, NULL); + return (rv == MATCHER_COMPLETE); +} + +/** + * Parse a given commandline and construct a list of arguments for the + * given command_element. + * + * @param cmd_element The cmd_element for which we want to construct arguments. + * @param vline The tokenized commandline. + * @param argc Where to store the argument count. + * @param argv Where to store the argument list. Should be at least + * CMD_ARGC_MAX elements long. + * @return CMD_SUCCESS if everything went alright, an error otherwise. + */ +static int +cmd_parse(struct cmd_element *cmd_element, + vector vline, + int *argc, const char **argv) +{ + enum matcher_rv rv = cmd_element_match(cmd_element, + FILTER_RELAXED, + vline, -1, + NULL, NULL, + argc, argv); + switch (rv) + { + case MATCHER_COMPLETE: + return CMD_SUCCESS; + + case MATCHER_NO_MATCH: + return CMD_ERR_NO_MATCH; + + case MATCHER_AMBIGUOUS: + return CMD_ERR_AMBIGUOUS; + + case MATCHER_EXCEED_ARGC_MAX: + return CMD_ERR_EXEED_ARGC_MAX; + + default: + return CMD_ERR_INCOMPLETE; + } } /* Check ambiguous match */ static int -is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) +is_cmd_ambiguous (vector cmd_vector, + const char *command, + vector matches, + enum match_type type) { unsigned int i; unsigned int j; const char *str = NULL; - struct cmd_element *cmd_element; const char *matched = NULL; - vector descvec; - struct desc *desc; + vector match_vector; + struct cmd_token *cmd_token; - for (i = 0; i < vector_active (v); i++) - if ((cmd_element = vector_slot (v, i)) != NULL) + if (command == NULL) + command = ""; + + for (i = 0; i < vector_active (matches); i++) + if ((match_vector = vector_slot (matches, i)) != NULL) { int match = 0; - descvec = vector_slot (cmd_element->strvec, index); - - for (j = 0; j < vector_active (descvec); j++) - if ((desc = vector_slot (descvec, j))) + for (j = 0; j < vector_active (match_vector); j++) + if ((cmd_token = vector_slot (match_vector, j)) != NULL) { enum match_type ret; - - str = desc->cmd; + + assert(cmd_token->type == TOKEN_TERMINAL); + if (cmd_token->type != TOKEN_TERMINAL) + continue; + + str = cmd_token->cmd; switch (type) { @@ -1371,7 +1914,7 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) } } if (!match) - vector_slot (v, i) = NULL; + vector_slot (cmd_vector, i) = NULL; } return 0; } @@ -1461,8 +2004,12 @@ cmd_entry_function_desc (const char *src, const char *dst) return NULL; } -/* Check same string element existence. If it isn't there return - 1. */ +/** + * Check whether a string is already present in a vector of strings. + * @param v A vector of char*. + * @param str A char*. + * @return 0 if str is already present in the vector, 1 otherwise. + */ static int cmd_unique_string (vector v, const char *str) { @@ -1476,19 +2023,25 @@ cmd_unique_string (vector v, const char *str) return 1; } -/* Compare string to description vector. If there is same string - return 1 else return 0. */ +/** + * Check whether a struct cmd_token matching a given string is already + * present in a vector of struct cmd_token. + * @param v A vector of struct cmd_token*. + * @param str A char* which should be searched for. + * @return 0 if there is a struct cmd_token* with its cmd matching str, + * 1 otherwise. + */ static int desc_unique_string (vector v, const char *str) { unsigned int i; - struct desc *desc; + struct cmd_token *token; for (i = 0; i < vector_active (v); i++) - if ((desc = vector_slot (v, i)) != NULL) - if (strcmp (desc->cmd, str) == 0) - return 1; - return 0; + if ((token = vector_slot (v, i)) != NULL) + if (strcmp (token->cmd, str) == 0) + return 0; + return 1; } static int @@ -1504,6 +2057,35 @@ cmd_try_do_shortcut (enum node_type node, char* first_word) { return 0; } +static void +cmd_matches_free(vector *matches) +{ + unsigned int i; + vector cmd_matches; + + for (i = 0; i < vector_active(*matches); i++) + if ((cmd_matches = vector_slot(*matches, i)) != NULL) + vector_free(cmd_matches); + vector_free(*matches); + *matches = NULL; +} + +static int +cmd_describe_cmp(const void *a, const void *b) +{ + const struct cmd_token *first = *(struct cmd_token * const *)a; + const struct cmd_token *second = *(struct cmd_token * const *)b; + + return strcmp(first->cmd, second->cmd); +} + +static void +cmd_describe_sort(vector matchvec) +{ + qsort(matchvec->index, vector_active(matchvec), + sizeof(void*), cmd_describe_cmp); +} + /* '?' describe command support. */ static vector cmd_describe_command_real (vector vline, struct vty *vty, int *status) @@ -1517,6 +2099,8 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) int ret; enum match_type match; char *command; + vector matches = NULL; + vector match_vector; /* Set index. */ if (vector_active (vline) == 0) @@ -1524,111 +2108,121 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) *status = CMD_ERR_NO_MATCH; return NULL; } - else - index = vector_active (vline) - 1; - + + index = vector_active (vline) - 1; + /* Make copy vector of current node's command vector. */ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); /* Prepare match vector */ matchvec = vector_init (INIT_MATCHVEC_SIZE); - /* Filter commands. */ - /* Only words precedes current word will be checked in this loop. */ - for (i = 0; i < index; i++) - if ((command = vector_slot (vline, i))) - { - match = cmd_filter_by_completion (command, cmd_vector, i); - - if (match == vararg_match) - { - struct cmd_element *cmd_element; - vector descvec; - unsigned int j, k; + /* Filter commands and build a list how they could possibly continue. */ + for (i = 0; i <= index; i++) + { + command = vector_slot (vline, i); - for (j = 0; j < vector_active (cmd_vector); j++) - if ((cmd_element = vector_slot (cmd_vector, j)) != NULL - && (vector_active (cmd_element->strvec))) - { - descvec = vector_slot (cmd_element->strvec, - vector_active (cmd_element->strvec) - 1); - for (k = 0; k < vector_active (descvec); k++) - { - struct desc *desc = vector_slot (descvec, k); - vector_set (matchvec, desc); - } - } - - vector_set (matchvec, &desc_cr); - vector_free (cmd_vector); + if (matches) + cmd_matches_free(&matches); - return matchvec; - } + ret = cmd_vector_filter(cmd_vector, + FILTER_RELAXED, + vline, i, + &match, + &matches); - if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) - { - vector_free (cmd_vector); - vector_free (matchvec); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } - else if (ret == 2) - { - vector_free (cmd_vector); - vector_free (matchvec); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - } + if (ret != CMD_SUCCESS) + { + vector_free (cmd_vector); + vector_free (matchvec); + cmd_matches_free(&matches); + *status = ret; + return NULL; + } - /* Prepare match vector */ - /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ + /* The last match may well be ambigious, so break here */ + if (i == index) + break; + + if (match == vararg_match) + { + /* We found a vararg match - so we can throw out the current matches here + * and don't need to continue checking the command input */ + unsigned int j, k; + + for (j = 0; j < vector_active (matches); j++) + if ((match_vector = vector_slot (matches, j)) != NULL) + for (k = 0; k < vector_active (match_vector); k++) + { + struct cmd_token *token = vector_slot (match_vector, k); + vector_set (matchvec, token); + } + + *status = CMD_SUCCESS; + vector_set(matchvec, &token_cr); + vector_free (cmd_vector); + cmd_matches_free(&matches); + cmd_describe_sort(matchvec); + return matchvec; + } - /* Make sure that cmd_vector is filtered based on current word */ - command = vector_slot (vline, index); - if (command) - match = cmd_filter_by_completion (command, cmd_vector, index); + ret = is_cmd_ambiguous(cmd_vector, command, matches, match); + if (ret == 1) + { + vector_free (cmd_vector); + vector_free (matchvec); + cmd_matches_free(&matches); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + else if (ret == 2) + { + vector_free (cmd_vector); + vector_free (matchvec); + cmd_matches_free(&matches); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + } /* Make description vector. */ - for (i = 0; i < vector_active (cmd_vector); i++) + for (i = 0; i < vector_active (matches); i++) if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) { - vector strvec = cmd_element->strvec; + unsigned int j; + const char *last_word; + vector vline_trimmed; - /* if command is NULL, index may be equal to vector_active */ - if (command && index >= vector_active (strvec)) - vector_slot (cmd_vector, i) = NULL; - else - { - /* Check if command is completed. */ - if (command == NULL && index == vector_active (strvec)) - { - if (!desc_unique_string (matchvec, command_cr)) - vector_set (matchvec, &desc_cr); - } - else - { - unsigned int j; - vector descvec = vector_slot (strvec, index); - struct desc *desc; - - for (j = 0; j < vector_active (descvec); j++) - if ((desc = vector_slot (descvec, j))) - { - const char *string; - - string = cmd_entry_function_desc (command, desc->cmd); - if (string) - { - /* Uniqueness check */ - if (!desc_unique_string (matchvec, string)) - vector_set (matchvec, desc); - } - } - } - } + last_word = vector_slot(vline, vector_active(vline) - 1); + if (last_word == NULL || !strlen(last_word)) + { + vline_trimmed = vector_copy(vline); + vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1); + + if (cmd_is_complete(cmd_element, vline_trimmed) + && desc_unique_string(matchvec, command_cr)) + { + if (match != vararg_match) + vector_set(matchvec, &token_cr); + } + + vector_free(vline_trimmed); + } + + match_vector = vector_slot (matches, i); + if (match_vector) + for (j = 0; j < vector_active(match_vector); j++) + { + struct cmd_token *token = vector_slot(match_vector, j); + const char *string; + + string = cmd_entry_function_desc(command, token->cmd); + if (string && desc_unique_string(matchvec, string)) + vector_set(matchvec, token); + } } vector_free (cmd_vector); + cmd_matches_free(&matches); if (vector_slot (matchvec, 0) == NULL) { @@ -1638,6 +2232,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) } *status = CMD_SUCCESS; + cmd_describe_sort(matchvec); return matchvec; } @@ -1708,6 +2303,31 @@ cmd_lcd (char **matched) return lcd; } +static int +cmd_complete_cmp(const void *a, const void *b) +{ + const char *first = *(char * const *)a; + const char *second = *(char * const *)b; + + if (!first) + { + if (!second) + return 0; + return 1; + } + if (!second) + return -1; + + return strcmp(first, second); +} + +static void +cmd_complete_sort(vector matchvec) +{ + qsort(matchvec->index, vector_active(matchvec), + sizeof(void*), cmd_complete_cmp); +} + /* Command line completion support. */ static char ** cmd_complete_command_real (vector vline, struct vty *vty, int *status) @@ -1716,13 +2336,13 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); #define INIT_MATCHVEC_SIZE 10 vector matchvec; - struct cmd_element *cmd_element; unsigned int index; char **match_str; - struct desc *desc; - vector descvec; + struct cmd_token *token; char *command; int lcd; + vector matches = NULL; + vector match_vector; if (vector_active (vline) == 0) { @@ -1733,66 +2353,80 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) else index = vector_active (vline) - 1; - /* First, filter by preceeding command string */ - for (i = 0; i < index; i++) - if ((command = vector_slot (vline, i))) - { - enum match_type match; - int ret; + /* First, filter by command string */ + for (i = 0; i <= index; i++) + { + command = vector_slot (vline, i); + enum match_type match; + int ret; - /* First try completion match, if there is exactly match return 1 */ - match = cmd_filter_by_completion (command, cmd_vector, i); + if (matches) + cmd_matches_free(&matches); - /* If there is exact match then filter ambiguous match else check - ambiguousness. */ - if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) - { - vector_free (cmd_vector); - *status = CMD_ERR_AMBIGUOUS; - return NULL; - } - /* + /* First try completion match, if there is exactly match return 1 */ + ret = cmd_vector_filter(cmd_vector, + FILTER_RELAXED, + vline, i, + &match, + &matches); + + if (ret != CMD_SUCCESS) + { + vector_free(cmd_vector); + cmd_matches_free(&matches); + *status = ret; + return NULL; + } + + /* Break here - the completion mustn't be checked to be non-ambiguous */ + if (i == index) + break; + + /* If there is exact match then filter ambiguous match else check + ambiguousness. */ + ret = is_cmd_ambiguous (cmd_vector, command, matches, match); + if (ret == 1) + { + vector_free (cmd_vector); + cmd_matches_free(&matches); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + /* else if (ret == 2) { vector_free (cmd_vector); + cmd_matches_free(&matches); *status = CMD_ERR_NO_MATCH; return NULL; } */ - } + } /* Prepare match vector. */ matchvec = vector_init (INIT_MATCHVEC_SIZE); - /* Now we got into completion */ - for (i = 0; i < vector_active (cmd_vector); i++) - if ((cmd_element = vector_slot (cmd_vector, i))) + /* Build the possible list of continuations into a list of completions */ + for (i = 0; i < vector_active (matches); i++) + if ((match_vector = vector_slot (matches, i))) { const char *string; - vector strvec = cmd_element->strvec; - - /* Check field length */ - if (index >= vector_active (strvec)) - vector_slot (cmd_vector, i) = NULL; - else - { - unsigned int j; + unsigned int j; - descvec = vector_slot (strvec, index); - for (j = 0; j < vector_active (descvec); j++) - if ((desc = vector_slot (descvec, j))) + for (j = 0; j < vector_active (match_vector); j++) + if ((token = vector_slot (match_vector, j))) { if ((string = cmd_entry_function (vector_slot (vline, index), - desc->cmd))) + token->cmd))) if (cmd_unique_string (matchvec, string)) vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); } - } } /* We don't need cmd_vector any more. */ vector_free (cmd_vector); + cmd_matches_free(&matches); /* No matched command */ if (vector_slot (matchvec, 0) == NULL) @@ -1832,7 +2466,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) { char *lcdstr; - lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1); + lcdstr = XMALLOC (MTYPE_TMP, lcd + 1); memcpy (lcdstr, matchvec->index[0], lcd); lcdstr[lcd] = '\0'; @@ -1842,7 +2476,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) for (i = 0; i < vector_active (matchvec); i++) { if (vector_slot (matchvec, i)) - XFREE (MTYPE_STRVEC, vector_slot (matchvec, i)); + XFREE (MTYPE_TMP, vector_slot (matchvec, i)); } vector_free (matchvec); @@ -1859,6 +2493,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) } match_str = (char **) matchvec->index; + cmd_complete_sort(matchvec); vector_only_wrapper_free (matchvec); *status = CMD_COMPLETE_LIST_MATCH; return match_str; @@ -1927,7 +2562,9 @@ node_parent ( enum node_type node ) /* Execute command by argument vline vector. */ static int -cmd_execute_command_real (vector vline, struct vty *vty, +cmd_execute_command_real (vector vline, + enum filter_type filter, + struct vty *vty, struct cmd_element **cmd) { unsigned int i; @@ -1939,35 +2576,48 @@ cmd_execute_command_real (vector vline, struct vty *vty, int argc; const char *argv[CMD_ARGC_MAX]; enum match_type match = 0; - int varflag; char *command; + int ret; + vector matches; /* Make copy of command elements. */ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); for (index = 0; index < vector_active (vline); index++) - if ((command = vector_slot (vline, index))) - { - int ret; - - match = cmd_filter_by_completion (command, cmd_vector, index); + { + command = vector_slot (vline, index); + ret = cmd_vector_filter(cmd_vector, + filter, + vline, index, + &match, + &matches); + + if (ret != CMD_SUCCESS) + { + cmd_matches_free(&matches); + return ret; + } - if (match == vararg_match) + if (match == vararg_match) + { + cmd_matches_free(&matches); break; - - ret = is_cmd_ambiguous (command, cmd_vector, index, match); + } - if (ret == 1) - { - vector_free (cmd_vector); - return CMD_ERR_AMBIGUOUS; - } - else if (ret == 2) - { - vector_free (cmd_vector); - return CMD_ERR_NO_MATCH; - } - } + ret = is_cmd_ambiguous (cmd_vector, command, matches, match); + cmd_matches_free(&matches); + + if (ret == 1) + { + vector_free(cmd_vector); + return CMD_ERR_AMBIGUOUS; + } + else if (ret == 2) + { + vector_free(cmd_vector); + return CMD_ERR_NO_MATCH; + } + } /* Check matched count. */ matched_element = NULL; @@ -1977,12 +2627,9 @@ cmd_execute_command_real (vector vline, struct vty *vty, for (i = 0; i < vector_active (cmd_vector); i++) if ((cmd_element = vector_slot (cmd_vector, i))) { - if (match == vararg_match || index >= cmd_element->cmdsize) + if (cmd_is_complete(cmd_element, vline)) { matched_element = cmd_element; -#if 0 - printf ("DEBUG: %s\n", cmd_element->string); -#endif matched_count++; } else @@ -2006,35 +2653,9 @@ cmd_execute_command_real (vector vline, struct vty *vty, if (matched_count > 1) return CMD_ERR_AMBIGUOUS; - /* Argument treatment */ - varflag = 0; - argc = 0; - - for (i = 0; i < vector_active (vline); i++) - { - if (varflag) - argv[argc++] = vector_slot (vline, i); - else - { - vector descvec = vector_slot (matched_element->strvec, i); - - if (vector_active (descvec) == 1) - { - struct desc *desc = vector_slot (descvec, 0); - - if (CMD_VARARG (desc->cmd)) - varflag = 1; - - if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) - argv[argc++] = vector_slot (vline, i); - } - else - argv[argc++] = vector_slot (vline, i); - } - - if (argc >= CMD_ARGC_MAX) - return CMD_ERR_EXEED_ARGC_MAX; - } + ret = cmd_parse(matched_element, vline, &argc, argv); + if (ret != CMD_SUCCESS) + return ret; /* For vtysh execution. */ if (cmd) @@ -2047,6 +2668,21 @@ cmd_execute_command_real (vector vline, struct vty *vty, return (*matched_element->func) (matched_element, vty, argc, argv); } +/** + * Execute a given command, handling things like "do ..." and checking + * whether the given command might apply at a parent node if doesn't + * apply for the current node. + * + * @param vline Command line input, vector of char* where each element is + * one input token. + * @param vty The vty context in which the command should be executed. + * @param cmd Pointer where the struct cmd_element of the matched command + * will be stored, if any. May be set to NULL if this info is + * not needed. + * @param vtysh If set != 0, don't lookup the command at parent nodes. + * @return The status of the command that has been executed or an error code + * as to why no command could be executed. + */ int cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, int vtysh) { @@ -2070,7 +2706,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); } - ret = cmd_execute_command_real (shifted_vline, vty, cmd); + ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd); vector_free(shifted_vline); vty->node = onode; @@ -2078,7 +2714,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, } - saved_ret = ret = cmd_execute_command_real (vline, vty, cmd); + saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd); if (vtysh) return saved_ret; @@ -2089,7 +2725,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, { try_node = node_parent(try_node); vty->node = try_node; - ret = cmd_execute_command_real (vline, vty, cmd); + ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd); tried = 1; if (ret == CMD_SUCCESS || ret == CMD_WARNING) { @@ -2104,123 +2740,24 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, return saved_ret; } -/* Execute command by argument readline. */ +/** + * Execute a given command, matching it strictly against the current node. + * This mode is used when reading config files. + * + * @param vline Command line input, vector of char* where each element is + * one input token. + * @param vty The vty context in which the command should be executed. + * @param cmd Pointer where the struct cmd_element* of the matched command + * will be stored, if any. May be set to NULL if this info is + * not needed. + * @return The status of the command that has been executed or an error code + * as to why no command could be executed. + */ int cmd_execute_command_strict (vector vline, struct vty *vty, struct cmd_element **cmd) { - unsigned int i; - unsigned int index; - vector cmd_vector; - struct cmd_element *cmd_element; - struct cmd_element *matched_element; - unsigned int matched_count, incomplete_count; - int argc; - const char *argv[CMD_ARGC_MAX]; - int varflag; - enum match_type match = 0; - char *command; - - /* Make copy of command element */ - cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); - - for (index = 0; index < vector_active (vline); index++) - if ((command = vector_slot (vline, index))) - { - int ret; - - match = cmd_filter_by_string (vector_slot (vline, index), - cmd_vector, index); - - /* If command meets '.VARARG' then finish matching. */ - if (match == vararg_match) - break; - - ret = is_cmd_ambiguous (command, cmd_vector, index, match); - if (ret == 1) - { - vector_free (cmd_vector); - return CMD_ERR_AMBIGUOUS; - } - if (ret == 2) - { - vector_free (cmd_vector); - return CMD_ERR_NO_MATCH; - } - } - - /* Check matched count. */ - matched_element = NULL; - matched_count = 0; - incomplete_count = 0; - for (i = 0; i < vector_active (cmd_vector); i++) - if (vector_slot (cmd_vector, i) != NULL) - { - cmd_element = vector_slot (cmd_vector, i); - - if (match == vararg_match || index >= cmd_element->cmdsize) - { - matched_element = cmd_element; - matched_count++; - } - else - incomplete_count++; - } - - /* Finish of using cmd_vector. */ - vector_free (cmd_vector); - - /* To execute command, matched_count must be 1. */ - if (matched_count == 0) - { - if (incomplete_count) - return CMD_ERR_INCOMPLETE; - else - return CMD_ERR_NO_MATCH; - } - - if (matched_count > 1) - return CMD_ERR_AMBIGUOUS; - - /* Argument treatment */ - varflag = 0; - argc = 0; - - for (i = 0; i < vector_active (vline); i++) - { - if (varflag) - argv[argc++] = vector_slot (vline, i); - else - { - vector descvec = vector_slot (matched_element->strvec, i); - - if (vector_active (descvec) == 1) - { - struct desc *desc = vector_slot (descvec, 0); - - if (CMD_VARARG (desc->cmd)) - varflag = 1; - - if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) - argv[argc++] = vector_slot (vline, i); - } - else - argv[argc++] = vector_slot (vline, i); - } - - if (argc >= CMD_ARGC_MAX) - return CMD_ERR_EXEED_ARGC_MAX; - } - - /* For vtysh execution. */ - if (cmd) - *cmd = matched_element; - - if (matched_element->daemon) - return CMD_SUCCESS_DAEMON; - - /* Now execute matched command */ - return (*matched_element->func) (matched_element, vty, argc, argv); + return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd); } /* Configration make from file. */ @@ -3461,9 +3998,10 @@ install_default (enum node_type node) void cmd_init (int terminal) { - command_cr = XSTRDUP(MTYPE_STRVEC, ""); - desc_cr.cmd = command_cr; - desc_cr.str = XSTRDUP(MTYPE_STRVEC, ""); + command_cr = XSTRDUP(MTYPE_CMD_TOKENS, ""); + token_cr.type = TOKEN_TERMINAL; + token_cr.cmd = command_cr; + token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, ""); /* Allocate initial top vector of commands. */ cmdvec = vector_init (VECTOR_MIN_SIZE); @@ -3584,14 +4122,61 @@ cmd_init (int terminal) srand(time(NULL)); } +static void +cmd_terminate_token(struct cmd_token *token) +{ + unsigned int i, j; + vector keyword_vect; + + if (token->multiple) + { + for (i = 0; i < vector_active(token->multiple); i++) + cmd_terminate_token(vector_slot(token->multiple, i)); + vector_free(token->multiple); + token->multiple = NULL; + } + + if (token->keyword) + { + for (i = 0; i < vector_active(token->keyword); i++) + { + keyword_vect = vector_slot(token->keyword, i); + for (j = 0; j < vector_active(keyword_vect); j++) + cmd_terminate_token(vector_slot(keyword_vect, j)); + vector_free(keyword_vect); + } + vector_free(token->keyword); + token->keyword = NULL; + } + + XFREE(MTYPE_CMD_TOKENS, token->cmd); + XFREE(MTYPE_CMD_TOKENS, token->desc); + + XFREE(MTYPE_CMD_TOKENS, token); +} + +static void +cmd_terminate_element(struct cmd_element *cmd) +{ + unsigned int i; + + if (cmd->tokens == NULL) + return; + + for (i = 0; i < vector_active(cmd->tokens); i++) + cmd_terminate_token(vector_slot(cmd->tokens, i)); + + vector_free(cmd->tokens); + cmd->tokens = NULL; +} + void cmd_terminate () { - unsigned int i, j, k, l; + unsigned int i, j; struct cmd_node *cmd_node; struct cmd_element *cmd_element; - struct desc *desc; - vector cmd_node_v, cmd_element_v, desc_v; + vector cmd_node_v; if (cmdvec) { @@ -3601,30 +4186,8 @@ cmd_terminate () cmd_node_v = cmd_node->cmd_vector; for (j = 0; j < vector_active (cmd_node_v); j++) - if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL && - cmd_element->strvec != NULL) - { - cmd_element_v = cmd_element->strvec; - - for (k = 0; k < vector_active (cmd_element_v); k++) - if ((desc_v = vector_slot (cmd_element_v, k)) != NULL) - { - for (l = 0; l < vector_active (desc_v); l++) - if ((desc = vector_slot (desc_v, l)) != NULL) - { - if (desc->cmd) - XFREE (MTYPE_STRVEC, desc->cmd); - if (desc->str) - XFREE (MTYPE_STRVEC, desc->str); - - XFREE (MTYPE_DESC, desc); - } - vector_free (desc_v); - } - - cmd_element->strvec = NULL; - vector_free (cmd_element_v); - } + if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL) + cmd_terminate_element(cmd_element); vector_free (cmd_node_v); } @@ -3634,9 +4197,9 @@ cmd_terminate () } if (command_cr) - XFREE(MTYPE_STRVEC, command_cr); - if (desc_cr.str) - XFREE(MTYPE_STRVEC, desc_cr.str); + XFREE(MTYPE_CMD_TOKENS, command_cr); + if (token_cr.desc) + XFREE(MTYPE_CMD_TOKENS, token_cr.desc); if (host.name) XFREE (MTYPE_HOST, host.name); if (host.password) diff --git a/lib/command.h b/lib/command.h index 2d708d8ec..e47c42552 100644 --- a/lib/command.h +++ b/lib/command.h @@ -138,18 +138,32 @@ struct cmd_element int (*func) (struct cmd_element *, struct vty *, int, const char *[]); const char *doc; /* Documentation of this command. */ int daemon; /* Daemon to which this command belong. */ - vector strvec; /* Pointing out each description vector. */ - unsigned int cmdsize; /* Command index count. */ - char *config; /* Configuration string */ - vector subconfig; /* Sub configuration string */ + vector tokens; /* Vector of cmd_tokens */ u_char attr; /* Command attributes */ }; + +enum cmd_token_type +{ + TOKEN_TERMINAL = 0, + TOKEN_MULTIPLE, + TOKEN_KEYWORD, +}; + /* Command description structure. */ -struct desc +struct cmd_token { + enum cmd_token_type type; + + /* Used for type == MULTIPLE */ + vector multiple; /* vector of cmd_token, type == FINAL */ + + /* Used for type == KEYWORD */ + vector keyword; /* vector of vector of cmd_tokens */ + + /* Used for type == TERMINAL */ char *cmd; /* Command string. */ - char *str; /* Command's description. */ + char *desc; /* Command's description. */ }; /* Return value of the commands. */ @@ -192,7 +206,170 @@ struct desc int argc __attribute__ ((unused)), \ const char *argv[] __attribute__ ((unused)) ) -/* DEFUN for vty command interafce. Little bit hacky ;-). */ +/* DEFUN for vty command interafce. Little bit hacky ;-). + * + * DEFUN(funcname, cmdname, cmdstr, helpstr) + * + * funcname + * ======== + * + * Name of the function that will be defined. + * + * cmdname + * ======= + * + * Name of the struct that will be defined for the command. + * + * cmdstr + * ====== + * + * The cmdstr defines the command syntax. It is used by the vty subsystem + * and vtysh to perform matching and completion in the cli. So you have to take + * care to construct it adhering to the following grammar. The names used + * for the production rules losely represent the names used in lib/command.c + * + * cmdstr = cmd_token , { " " , cmd_token } ; + * + * cmd_token = cmd_terminal + * | cmd_multiple + * | cmd_keyword ; + * + * cmd_terminal_fixed = fixed_string + * | variable + * | range + * | ipv4 + * | ipv4_prefix + * | ipv6 + * | ipv6_prefix ; + * + * cmd_terminal = cmd_terminal_fixed + * | option + * | vararg ; + * + * multiple_part = cmd_terminal_fixed ; + * cmd_multiple = "(" , multiple_part , ( "|" | { "|" , multiple_part } ) , ")" ; + * + * keyword_part = fixed_string , { " " , ( cmd_terminal_fixed | cmd_multiple ) } ; + * cmd_keyword = "{" , keyword_part , { "|" , keyword_part } , "}" ; + * + * lowercase = "a" | ... | "z" ; + * uppercase = "A" | ... | "Z" ; + * digit = "0" | ... | "9" ; + * number = digit , { digit } ; + * + * fixed_string = (lowercase | digit) , { lowercase | digit | uppercase | "-" | "_" } ; + * variable = uppercase , { uppercase | "_" } ; + * range = "<" , number , "-" , number , ">" ; + * ipv4 = "A.B.C.D" ; + * ipv4_prefix = "A.B.C.D/M" ; + * ipv6 = "X:X::X:X" ; + * ipv6_prefix = "X:X::X:X/M" ; + * option = "[" , variable , "]" ; + * vararg = "." , variable ; + * + * To put that all in a textual description: A cmdstr is a sequence of tokens, + * separated by spaces. + * + * Terminal Tokens: + * + * A very simple cmdstring would be something like: "show ip bgp". It consists + * of three Terminal Tokens, each containing a fixed string. When this command + * is called, no arguments will be passed down to the function implementing it, + * as it only consists of fixed strings. + * + * Apart from fixed strings, Terminal Tokens can also contain variables: + * An example would be "show ip bgp A.B.C.D". This command expects an IPv4 + * as argument. As this is a variable, the IP address entered by the user will + * be passed down as an argument. Apart from two exceptions, the other options + * for Terminal Tokens behave exactly as we just discussed and only make a + * difference for the CLI. The two exceptions will be discussed in the next + * paragraphs. + * + * A Terminal Token can contain a so called option match. This is a simple + * string variable that the user may omit. An example would be: + * "show interface [IFNAME]". If the user calls this without an interface as + * argument, no arguments will be passed down to the function implementing + * this command. Otherwise, the interface name will be provided to the function + * as a regular argument. + + * Also, a Terminal Token can contain a so called vararg. This is used e.g. in + * "show ip bgp regexp .LINE". The last token is a vararg match and will + * consume all the arguments the user inputs on the command line and append + * those to the list of arguments passed down to the function implementing this + * command. (Therefore, it doesn't make much sense to have any tokens after a + * vararg because the vararg will already consume all the words the user entered + * in the CLI) + * + * Multiple Tokens: + * + * The Multiple Token type can be used if there are multiple possibilities what + * arguments may be used for a command, but it should map to the same function + * nonetheless. An example would be "ip route A.B.C.D/M (reject|blackhole)" + * In that case both "reject" and "blackhole" would be acceptable as last + * arguments. The words matched by Multiple Tokens are always added to the + * argument list, even if they are matched by fixed strings. Such a Multiple + * Token can contain almost any type of token that would also be acceptable + * for a Terminal Token, the exception are optional variables and varag. + * + * There is one special case that is used in some places of Quagga that should be + * pointed out here shortly. An example would be "password (8|) WORD". This + * construct is used to have fixed strings communicated as arguments. (The "8" + * will be passed down as an argument in this case) It does not mean that + * the "8" is optional. Another historic and possibly surprising property of + * this construct is that it consumes two parts of helpstr. (Help + * strings will be explained later) + * + * Keyword Tokens: + * + * There are commands that take a lot of different and possibly optional arguments. + * An example from ospf would be the "default-information originate" command. This + * command takes a lot of optional arguments that may be provided in any order. + * To accomodate such commands, the Keyword Token has been implemented. + * Using the keyword token, the "default-information originate" command and all + * its possible options can be represented using this single cmdstr: + * "default-information originate \ + * {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}" + * + * Keywords always start with a fixed string and may be followed by arguments. + * Except optional variables and vararg, everything is permitted here. + * + * For the special case of a keyword without arguments, either NULL or the + * keyword itself will be pushed as an argument, depending on whether the + * keyword is present. + * For the other keywords, arguments will be only pushed for + * variables/Multiple Tokens. If the keyword is not present, the arguments that + * would have been pushed will be substituted by NULL. + * + * A few examples: + * "default information originate metric-type 1 metric 1000" + * would yield the following arguments: + * { NULL, "1000", "1", NULL } + * + * "default information originate always route-map RMAP-DEFAULT" + * would yield the following arguments: + * { "always", NULL, NULL, "RMAP-DEFAULT" } + * + * helpstr + * ======= + * + * The helpstr is used to show a short explantion for the commands that + * are available when the user presses '?' on the CLI. It is the concatenation + * of the helpstrings for all the tokens that make up the command. + * + * There should be one helpstring for each token in the cmdstr except those + * containing other tokens, like Multiple or Keyword Tokens. For those, there + * will only be the helpstrings of the contained tokens. + * + * The individual helpstrings are expected to be in the same order as their + * respective Tokens appear in the cmdstr. They should each be terminated with + * a linefeed. The last helpstring should be terminated with a linefeed as well. + * + * Care should also be taken to avoid having similar tokens with different + * helpstrings. Imagine e.g. the commands "show ip ospf" and "show ip bgp". + * they both contain a helpstring for "show", but only one will be displayed + * when the user enters "sh?". If those two helpstrings differ, it is not + * defined which one will be shown and the behavior is therefore unpredictable. + */ #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ @@ -330,7 +507,6 @@ struct desc extern void install_node (struct cmd_node *, int (*) (struct vty *)); extern void install_default (enum node_type); extern void install_element (enum node_type, struct cmd_element *); -extern void sort_node (void); /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated string with a space between each element (allocated using @@ -346,7 +522,6 @@ extern int config_from_file (struct vty *, FILE *); extern enum node_type node_parent (enum node_type); extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int); extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); -extern void config_replace_string (struct cmd_element *, char *, ...); extern void cmd_init (int); extern void cmd_terminate (void); diff --git a/lib/memtypes.c b/lib/memtypes.c index 50b6fa427..47a343873 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -54,7 +54,7 @@ struct memory_list memory_list_lib[] = { MTYPE_ROUTE_MAP_RULE, "Route map rule" }, { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" }, { MTYPE_ROUTE_MAP_COMPILED, "Route map compiled" }, - { MTYPE_DESC, "Command desc" }, + { MTYPE_CMD_TOKENS, "Command desc" }, { MTYPE_KEY, "Key" }, { MTYPE_KEYCHAIN, "Key chain" }, { MTYPE_IF_RMAP, "Interface route map" }, diff --git a/lib/vty.c b/lib/vty.c index 96cb1e4b5..9908b0236 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -931,23 +931,23 @@ vty_complete_command (struct vty *vty) static void vty_describe_fold (struct vty *vty, int cmd_width, - unsigned int desc_width, struct desc *desc) + unsigned int desc_width, struct cmd_token *token) { char *buf; const char *cmd, *p; int pos; - cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; + cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd; if (desc_width <= 0) { - vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); + vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE); return; } - buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1); + buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1); - for (p = desc->str; strlen (p) > desc_width; p += pos + 1) + for (p = token->desc; strlen (p) > desc_width; p += pos + 1) { for (pos = desc_width; pos > 0; pos--) if (*(p + pos) == ' ') @@ -976,7 +976,7 @@ vty_describe_command (struct vty *vty) vector vline; vector describe; unsigned int i, width, desc_width; - struct desc *desc, *desc_cr = NULL; + struct cmd_token *token, *token_cr = NULL; vline = cmd_make_strvec (vty->buf); @@ -1010,15 +1010,15 @@ vty_describe_command (struct vty *vty) /* Get width of command string. */ width = 0; for (i = 0; i < vector_active (describe); i++) - if ((desc = vector_slot (describe, i)) != NULL) + if ((token = vector_slot (describe, i)) != NULL) { unsigned int len; - if (desc->cmd[0] == '\0') + if (token->cmd[0] == '\0') continue; - len = strlen (desc->cmd); - if (desc->cmd[0] == '.') + len = strlen (token->cmd); + if (token->cmd[0] == '.') len--; if (width < len) @@ -1030,27 +1030,27 @@ vty_describe_command (struct vty *vty) /* Print out description. */ for (i = 0; i < vector_active (describe); i++) - if ((desc = vector_slot (describe, i)) != NULL) + if ((token = vector_slot (describe, i)) != NULL) { - if (desc->cmd[0] == '\0') + if (token->cmd[0] == '\0') continue; - if (strcmp (desc->cmd, command_cr) == 0) + if (strcmp (token->cmd, command_cr) == 0) { - desc_cr = desc; + token_cr = token; continue; } - if (!desc->str) + if (!token->desc) vty_out (vty, " %-s%s", - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, VTY_NEWLINE); - else if (desc_width >= strlen (desc->str)) + else if (desc_width >= strlen (token->desc)) vty_out (vty, " %-*s %s%s", width, - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str, VTY_NEWLINE); + token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, + token->desc, VTY_NEWLINE); else - vty_describe_fold (vty, width, desc_width, desc); + vty_describe_fold (vty, width, desc_width, token); #if 0 vty_out (vty, " %-*s %s%s", width @@ -1059,18 +1059,18 @@ vty_describe_command (struct vty *vty) #endif /* 0 */ } - if ((desc = desc_cr)) + if ((token = token_cr)) { - if (!desc->str) + if (!token->desc) vty_out (vty, " %-s%s", - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, VTY_NEWLINE); - else if (desc_width >= strlen (desc->str)) + else if (desc_width >= strlen (token->desc)) vty_out (vty, " %-*s %s%s", width, - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str, VTY_NEWLINE); + token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, + token->desc, VTY_NEWLINE); else - vty_describe_fold (vty, width, desc_width, desc); + vty_describe_fold (vty, width, desc_width, token); } out: diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index e9919713b..4f6d9e514 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -325,9 +325,6 @@ main (int argc, char *argv[], char *envp[]) /* initialize ospf6 */ ospf6_init (); - /* sort command vector */ - sort_node (); - /* parse config file */ vty_read_config (config_file, config_default); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 6d58b4ead..c68aa4dd3 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -310,8 +310,6 @@ main (int argc, char **argv) ospf_opaque_init (); #endif /* HAVE_OPAQUE_LSA */ - sort_node (); - /* Get configuration file. */ vty_read_config (config_file, config_default); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 6a9fa71da..a512fbc2d 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -287,9 +287,6 @@ main (int argc, char **argv) rip_zclient_init (); rip_peer_init (); - /* Sort all installed commands. */ - sort_node (); - /* Get configuration file. */ vty_read_config (config_file, config_default); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 20225b7d5..7525a2676 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -282,9 +282,6 @@ main (int argc, char **argv) zebra_init (); ripng_peer_init (); - /* Sort all installed commands. */ - sort_node (); - /* Get configuration file. */ vty_read_config (config_file, config_default); diff --git a/tests/main.c b/tests/main.c index e0fbb4d51..2d8cb0c59 100644 --- a/tests/main.c +++ b/tests/main.c @@ -171,8 +171,6 @@ main (int argc, char **argv) /* OSPF vty inits. */ test_vty_init (); - sort_node (); - /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { diff --git a/tests/test-commands.c b/tests/test-commands.c index e2f40c6a9..18b3b50d7 100644 --- a/tests/test-commands.c +++ b/tests/test-commands.c @@ -233,8 +233,6 @@ test_init(void) cmd->daemon = 0; cmd->func = test_callback; } - sort_node(); - test_load(); vty_init_vtysh(); } @@ -340,8 +338,8 @@ test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_ { for (j = 0; j < vector_active(descriptions); j++) { - struct desc *cmd = vector_slot(descriptions, j); - printf(" '%s' '%s'\n", cmd->cmd, cmd->str); + struct cmd_token *cmd = vector_slot(descriptions, j); + printf(" '%s' '%s'\n", cmd->cmd, cmd->desc); } vector_free(descriptions); } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index c575902cd..34c3bd62a 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -554,7 +554,7 @@ vtysh_rl_describe (void) vector vline; vector describe; int width; - struct desc *desc; + struct cmd_token *token; vline = cmd_make_strvec (rl_line_buffer); @@ -592,15 +592,15 @@ vtysh_rl_describe (void) /* Get width of command string. */ width = 0; for (i = 0; i < vector_active (describe); i++) - if ((desc = vector_slot (describe, i)) != NULL) + if ((token = vector_slot (describe, i)) != NULL) { int len; - if (desc->cmd[0] == '\0') + if (token->cmd[0] == '\0') continue; - len = strlen (desc->cmd); - if (desc->cmd[0] == '.') + len = strlen (token->cmd); + if (token->cmd[0] == '.') len--; if (width < len) @@ -608,19 +608,19 @@ vtysh_rl_describe (void) } for (i = 0; i < vector_active (describe); i++) - if ((desc = vector_slot (describe, i)) != NULL) + if ((token = vector_slot (describe, i)) != NULL) { - if (desc->cmd[0] == '\0') + if (token->cmd[0] == '\0') continue; - if (! desc->str) + if (! token->desc) fprintf (stdout," %-s\n", - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd); + token->cmd[0] == '.' ? token->cmd + 1 : token->cmd); else fprintf (stdout," %-*s %s\n", width, - desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, - desc->str); + token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, + token->desc); } cmd_free_strvec (vline); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 4a315a5c8..48958f0f3 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -299,8 +299,6 @@ main (int argc, char **argv, char **env) vty_init_vtysh (); - sort_node (); - /* Read vtysh configuration file before connecting to daemons. */ vtysh_read_config (config_default); diff --git a/zebra/main.c b/zebra/main.c index 742e02928..523b1911c 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -343,9 +343,6 @@ main (int argc, char **argv) interface_list (); route_read (); - /* Sort VTY commands. */ - sort_node (); - #ifdef HAVE_SNMP zebra_snmp_init (); #endif /* HAVE_SNMP */ diff --git a/zebra/test_main.c b/zebra/test_main.c index a9518637d..c6951729f 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -298,9 +298,6 @@ main (int argc, char **argv) route_read (); zebra_vty_init(); - /* Sort VTY commands. */ - sort_node (); - /* Configuration file read*/ vty_read_config (config_file, config_default); From 6f2a67031cfb21362fc7ecd3251761799c8ffe27 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 30 Sep 2013 12:27:52 +0000 Subject: [PATCH 0336/1342] ospfd/ospf_vty.c: use keyword cmd style Use the new keyword command style for: - default-information originate - distance ospf - redistribute Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospfd/ospf_vty.c | 990 ++++---------------------------------- tests/testcommands.in | 15 + tests/testcommands.refout | 107 ++++ 3 files changed, 211 insertions(+), 901 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 5e5a0b0d5..1489b20a4 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -5787,11 +5787,10 @@ ALIAS (no_ip_ospf_transmit_delay, "OSPF interface commands\n" "Link state transmit delay\n") - -DEFUN (ospf_redistribute_source_metric_type, - ospf_redistribute_source_metric_type_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD - " metric <0-16777214> metric-type (1|2) route-map WORD", +DEFUN (ospf_redistribute_source, + ospf_redistribute_source_cmd, + "redistribute " QUAGGA_REDIST_STR_OSPFD + " {metric <0-16777214>|metric-type (1|2)|route-map WORD}", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" @@ -5807,84 +5806,25 @@ DEFUN (ospf_redistribute_source_metric_type, int type = -1; int metric = -1; + if (argc < 4) + return CMD_WARNING; /* should not happen */ + /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ - if (argc >= 2) + if (argv[1] != NULL) if (!str2metric (argv[1], &metric)) return CMD_WARNING; /* Get metric type. */ - if (argc >= 3) + if (argv[2] != NULL) if (!str2metric_type (argv[2], &type)) return CMD_WARNING; - if (argc == 4) - ospf_routemap_set (ospf, source, argv[3]); - else - ospf_routemap_unset (ospf, source); - - return ospf_redistribute_set (ospf, source, type, metric); -} - -ALIAS (ospf_redistribute_source_metric_type, - ospf_redistribute_source_metric_type_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD - " metric <0-16777214> metric-type (1|2)", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "Metric for redistributed routes\n" - "OSPF default metric\n" - "OSPF exterior metric type for redistributed routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n") - -ALIAS (ospf_redistribute_source_metric_type, - ospf_redistribute_source_metric_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD " metric <0-16777214>", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "Metric for redistributed routes\n" - "OSPF default metric\n") - -DEFUN (ospf_redistribute_source_type_metric, - ospf_redistribute_source_type_metric_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD - " metric-type (1|2) metric <0-16777214> route-map WORD", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "OSPF exterior metric type for redistributed routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Metric for redistributed routes\n" - "OSPF default metric\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int source; - int type = -1; - int metric = -1; - - /* Get distribute source. */ - source = proto_redistnum(AFI_IP, argv[0]); - if (source < 0 || source == ZEBRA_ROUTE_OSPF) - return CMD_WARNING; - - /* Get metric value. */ - if (argc >= 2) - if (!str2metric_type (argv[1], &type)) - return CMD_WARNING; - - /* Get metric type. */ - if (argc >= 3) - if (!str2metric (argv[2], &metric)) - return CMD_WARNING; - - if (argc == 4) + if (argv[3] != NULL) ospf_routemap_set (ospf, source, argv[3]); else ospf_routemap_unset (ospf, source); @@ -5892,124 +5832,6 @@ DEFUN (ospf_redistribute_source_type_metric, return ospf_redistribute_set (ospf, source, type, metric); } -ALIAS (ospf_redistribute_source_type_metric, - ospf_redistribute_source_type_metric_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD - " metric-type (1|2) metric <0-16777214>", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "OSPF exterior metric type for redistributed routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Metric for redistributed routes\n" - "OSPF default metric\n") - -ALIAS (ospf_redistribute_source_type_metric, - ospf_redistribute_source_type_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD " metric-type (1|2)", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "OSPF exterior metric type for redistributed routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n") - -ALIAS (ospf_redistribute_source_type_metric, - ospf_redistribute_source_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD, - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD) - -DEFUN (ospf_redistribute_source_metric_routemap, - ospf_redistribute_source_metric_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD - " metric <0-16777214> route-map WORD", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "Metric for redistributed routes\n" - "OSPF default metric\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int source; - int metric = -1; - - /* Get distribute source. */ - source = proto_redistnum(AFI_IP, argv[0]); - if (source < 0 || source == ZEBRA_ROUTE_OSPF) - return CMD_WARNING; - - /* Get metric value. */ - if (argc >= 2) - if (!str2metric (argv[1], &metric)) - return CMD_WARNING; - - if (argc == 3) - ospf_routemap_set (ospf, source, argv[2]); - else - ospf_routemap_unset (ospf, source); - - return ospf_redistribute_set (ospf, source, -1, metric); -} - -DEFUN (ospf_redistribute_source_type_routemap, - ospf_redistribute_source_type_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD - " metric-type (1|2) route-map WORD", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "OSPF exterior metric type for redistributed routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int source; - int type = -1; - - /* Get distribute source. */ - source = proto_redistnum(AFI_IP, argv[0]); - if (source < 0 || source == ZEBRA_ROUTE_OSPF) - return CMD_WARNING; - - /* Get metric value. */ - if (argc >= 2) - if (!str2metric_type (argv[1], &type)) - return CMD_WARNING; - - if (argc == 3) - ospf_routemap_set (ospf, source, argv[2]); - else - ospf_routemap_unset (ospf, source); - - return ospf_redistribute_set (ospf, source, type, -1); -} - -DEFUN (ospf_redistribute_source_routemap, - ospf_redistribute_source_routemap_cmd, - "redistribute " QUAGGA_REDIST_STR_OSPFD " route-map WORD", - REDIST_STR - QUAGGA_REDIST_HELP_STR_OSPFD - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int source; - - /* Get distribute source. */ - source = proto_redistnum(AFI_IP, argv[0]); - if (source < 0 || source == ZEBRA_ROUTE_OSPF) - return CMD_WARNING; - - if (argc == 2) - ospf_routemap_set (ospf, source, argv[1]); - else - ospf_routemap_unset (ospf, source); - - return ospf_redistribute_set (ospf, source, -1, -1); -} - DEFUN (no_ospf_redistribute_source, no_ospf_redistribute_source_cmd, "no redistribute " QUAGGA_REDIST_STR_OSPFD, @@ -6032,432 +5854,85 @@ DEFUN (ospf_distribute_list_out, ospf_distribute_list_out_cmd, "distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, "Filter networks in routing updates\n" - "Access-list name\n" - OUT_STR - QUAGGA_REDIST_HELP_STR_OSPFD) -{ - struct ospf *ospf = vty->index; - int source; - - /* Get distribute source. */ - source = proto_redistnum(AFI_IP, argv[1]); - if (source < 0 || source == ZEBRA_ROUTE_OSPF) - return CMD_WARNING; - - return ospf_distribute_list_out_set (ospf, source, argv[0]); -} - -DEFUN (no_ospf_distribute_list_out, - no_ospf_distribute_list_out_cmd, - "no distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, - NO_STR - "Filter networks in routing updates\n" - "Access-list name\n" - OUT_STR - QUAGGA_REDIST_HELP_STR_OSPFD) -{ - struct ospf *ospf = vty->index; - int source; - - source = proto_redistnum(AFI_IP, argv[1]); - if (source < 0 || source == ZEBRA_ROUTE_OSPF) - return CMD_WARNING; - - return ospf_distribute_list_out_unset (ospf, source, argv[0]); -} - -/* Default information originate. */ -DEFUN (ospf_default_information_originate_metric_type_routemap, - ospf_default_information_originate_metric_type_routemap_cmd, - "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int type = -1; - int metric = -1; - - /* Get metric value. */ - if (argc >= 1) - if (!str2metric (argv[0], &metric)) - return CMD_WARNING; - - /* Get metric type. */ - if (argc >= 2) - if (!str2metric_type (argv[1], &type)) - return CMD_WARNING; - - if (argc == 3) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, - type, metric); -} - -ALIAS (ospf_default_information_originate_metric_type_routemap, - ospf_default_information_originate_metric_type_cmd, - "default-information originate metric <0-16777214> metric-type (1|2)", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n") - -ALIAS (ospf_default_information_originate_metric_type_routemap, - ospf_default_information_originate_metric_cmd, - "default-information originate metric <0-16777214>", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF default metric\n" - "OSPF metric\n") - -ALIAS (ospf_default_information_originate_metric_type_routemap, - ospf_default_information_originate_cmd, - "default-information originate", - "Control distribution of default information\n" - "Distribute a default route\n") - -/* Default information originate. */ -DEFUN (ospf_default_information_originate_metric_routemap, - ospf_default_information_originate_metric_routemap_cmd, - "default-information originate metric <0-16777214> route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int metric = -1; - - /* Get metric value. */ - if (argc >= 1) - if (!str2metric (argv[0], &metric)) - return CMD_WARNING; - - if (argc == 2) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, - -1, metric); -} - -/* Default information originate. */ -DEFUN (ospf_default_information_originate_routemap, - ospf_default_information_originate_routemap_cmd, - "default-information originate route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - - if (argc == 1) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[0]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, -1, -1); -} - -DEFUN (ospf_default_information_originate_type_metric_routemap, - ospf_default_information_originate_type_metric_routemap_cmd, - "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "OSPF default metric\n" - "OSPF metric\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int type = -1; - int metric = -1; - - /* Get metric type. */ - if (argc >= 1) - if (!str2metric_type (argv[0], &type)) - return CMD_WARNING; - - /* Get metric value. */ - if (argc >= 2) - if (!str2metric (argv[1], &metric)) - return CMD_WARNING; - - if (argc == 3) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, - type, metric); -} - -ALIAS (ospf_default_information_originate_type_metric_routemap, - ospf_default_information_originate_type_metric_cmd, - "default-information originate metric-type (1|2) metric <0-16777214>", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "OSPF default metric\n" - "OSPF metric\n") - -ALIAS (ospf_default_information_originate_type_metric_routemap, - ospf_default_information_originate_type_cmd, - "default-information originate metric-type (1|2)", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n") - -DEFUN (ospf_default_information_originate_type_routemap, - ospf_default_information_originate_type_routemap_cmd, - "default-information originate metric-type (1|2) route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int type = -1; - - /* Get metric type. */ - if (argc >= 1) - if (!str2metric_type (argv[0], &type)) - return CMD_WARNING; - - if (argc == 2) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, - type, -1); -} - -DEFUN (ospf_default_information_originate_always_metric_type_routemap, - ospf_default_information_originate_always_metric_type_routemap_cmd, - "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int type = -1; - int metric = -1; - - /* Get metric value. */ - if (argc >= 1) - if (!str2metric (argv[0], &metric)) - return CMD_WARNING; - - /* Get metric type. */ - if (argc >= 2) - if (!str2metric_type (argv[1], &type)) - return CMD_WARNING; - - if (argc == 3) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, - type, metric); -} - -ALIAS (ospf_default_information_originate_always_metric_type_routemap, - ospf_default_information_originate_always_metric_type_cmd, - "default-information originate always metric <0-16777214> metric-type (1|2)", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n") - -ALIAS (ospf_default_information_originate_always_metric_type_routemap, - ospf_default_information_originate_always_metric_cmd, - "default-information originate always metric <0-16777214>", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "OSPF metric type for default routes\n") - -ALIAS (ospf_default_information_originate_always_metric_type_routemap, - ospf_default_information_originate_always_cmd, - "default-information originate always", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n") - -DEFUN (ospf_default_information_originate_always_metric_routemap, - ospf_default_information_originate_always_metric_routemap_cmd, - "default-information originate always metric <0-16777214> route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF default metric\n" - "OSPF metric\n" - "Route map reference\n" - "Pointer to route-map entries\n") + "Access-list name\n" + OUT_STR + QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; - int metric = -1; - - /* Get metric value. */ - if (argc >= 1) - if (!str2metric (argv[0], &metric)) - return CMD_WARNING; + int source; - if (argc == 2) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); + /* Get distribute source. */ + source = proto_redistnum(AFI_IP, argv[1]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) + return CMD_WARNING; - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, - -1, metric); + return ospf_distribute_list_out_set (ospf, source, argv[0]); } -DEFUN (ospf_default_information_originate_always_routemap, - ospf_default_information_originate_always_routemap_cmd, - "default-information originate always route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "Route map reference\n" - "Pointer to route-map entries\n") +DEFUN (no_ospf_distribute_list_out, + no_ospf_distribute_list_out_cmd, + "no distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + OUT_STR + QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; + int source; - if (argc == 1) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[0]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); + source = proto_redistnum(AFI_IP, argv[1]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) + return CMD_WARNING; - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, -1, -1); + return ospf_distribute_list_out_unset (ospf, source, argv[0]); } -DEFUN (ospf_default_information_originate_always_type_metric_routemap, - ospf_default_information_originate_always_type_metric_routemap_cmd, - "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD", +/* Default information originate. */ +DEFUN (ospf_default_information_originate, + ospf_default_information_originate_cmd, + "default-information originate " + "{always|metric <0-16777214>|metric-type (1|2)|route-map WORD}", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" - "OSPF default metric\n" - "OSPF metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; + int default_originate = DEFAULT_ORIGINATE_ZEBRA; int type = -1; int metric = -1; - /* Get metric type. */ - if (argc >= 1) - if (!str2metric_type (argv[0], &type)) - return CMD_WARNING; + if (argc < 4) + return CMD_WARNING; /* this should not happen */ + + /* Check whether "always" was specified */ + if (argv[0] != NULL) + default_originate = DEFAULT_ORIGINATE_ALWAYS; /* Get metric value. */ - if (argc >= 2) + if (argv[1] != NULL) if (!str2metric (argv[1], &metric)) return CMD_WARNING; - if (argc == 3) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); - else - ospf_routemap_unset (ospf, DEFAULT_ROUTE); - - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, - type, metric); -} - -ALIAS (ospf_default_information_originate_always_type_metric_routemap, - ospf_default_information_originate_always_type_metric_cmd, - "default-information originate always metric-type (1|2) metric <0-16777214>", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "OSPF default metric\n" - "OSPF metric\n") - -ALIAS (ospf_default_information_originate_always_type_metric_routemap, - ospf_default_information_originate_always_type_cmd, - "default-information originate always metric-type (1|2)", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n") - -DEFUN (ospf_default_information_originate_always_type_routemap, - ospf_default_information_originate_always_type_routemap_cmd, - "default-information originate always metric-type (1|2) route-map WORD", - "Control distribution of default information\n" - "Distribute a default route\n" - "Always advertise default route\n" - "OSPF metric type for default routes\n" - "Set OSPF External Type 1 metrics\n" - "Set OSPF External Type 2 metrics\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - struct ospf *ospf = vty->index; - int type = -1; - /* Get metric type. */ - if (argc >= 1) - if (!str2metric_type (argv[0], &type)) + if (argv[2] != NULL) + if (!str2metric_type (argv[2], &type)) return CMD_WARNING; - if (argc == 2) - ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); + if (argv[3] != NULL) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[3]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); - return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, - type, -1); + return ospf_redistribute_default_set (ospf, default_originate, + type, metric); } DEFUN (no_ospf_default_information_originate, @@ -6552,296 +6027,73 @@ DEFUN (no_ospf_distance, DEFUN (no_ospf_distance_ospf, no_ospf_distance_ospf_cmd, - "no distance ospf", + "no distance ospf {intra-area|inter-area|external}", NO_STR "Define an administrative distance\n" "OSPF Administrative distance\n" - "OSPF Distance\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_intra = 0; - ospf->distance_inter = 0; - ospf->distance_external = 0; - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_intra, - ospf_distance_ospf_intra_cmd, - "distance ospf intra-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "Intra-area routes\n" - "Distance for intra-area routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_intra = atoi (argv[0]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_intra_inter, - ospf_distance_ospf_intra_inter_cmd, - "distance ospf intra-area <1-255> inter-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "Intra-area routes\n" - "Distance for intra-area routes\n" - "Inter-area routes\n" - "Distance for inter-area routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_intra = atoi (argv[0]); - ospf->distance_inter = atoi (argv[1]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_intra_external, - ospf_distance_ospf_intra_external_cmd, - "distance ospf intra-area <1-255> external <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "Intra-area routes\n" - "Distance for intra-area routes\n" - "External routes\n" - "Distance for external routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_intra = atoi (argv[0]); - ospf->distance_external = atoi (argv[1]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_intra_inter_external, - ospf_distance_ospf_intra_inter_external_cmd, - "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "Intra-area routes\n" - "Distance for intra-area routes\n" - "Inter-area routes\n" - "Distance for inter-area routes\n" - "External routes\n" - "Distance for external routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_intra = atoi (argv[0]); - ospf->distance_inter = atoi (argv[1]); - ospf->distance_external = atoi (argv[2]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_intra_external_inter, - ospf_distance_ospf_intra_external_inter_cmd, - "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" + "OSPF Distance\n" "Intra-area routes\n" - "Distance for intra-area routes\n" - "External routes\n" - "Distance for external routes\n" - "Inter-area routes\n" - "Distance for inter-area routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_intra = atoi (argv[0]); - ospf->distance_external = atoi (argv[1]); - ospf->distance_inter = atoi (argv[2]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_inter, - ospf_distance_ospf_inter_cmd, - "distance ospf inter-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" "Inter-area routes\n" - "Distance for inter-area routes\n") + "External routes\n") { struct ospf *ospf = vty->index; - ospf->distance_inter = atoi (argv[0]); - - return CMD_SUCCESS; -} + if (argc < 3) + return CMD_WARNING; -DEFUN (ospf_distance_ospf_inter_intra, - ospf_distance_ospf_inter_intra_cmd, - "distance ospf inter-area <1-255> intra-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "Inter-area routes\n" - "Distance for inter-area routes\n" - "Intra-area routes\n" - "Distance for intra-area routes\n") -{ - struct ospf *ospf = vty->index; + if (argv[0] != NULL) + ospf->distance_intra = 0; - ospf->distance_inter = atoi (argv[0]); - ospf->distance_intra = atoi (argv[1]); + if (argv[1] != NULL) + ospf->distance_inter = 0; - return CMD_SUCCESS; -} + if (argv[2] != NULL) + ospf->distance_external = 0; -DEFUN (ospf_distance_ospf_inter_external, - ospf_distance_ospf_inter_external_cmd, - "distance ospf inter-area <1-255> external <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "Inter-area routes\n" - "Distance for inter-area routes\n" - "External routes\n" - "Distance for external routes\n") -{ - struct ospf *ospf = vty->index; + if (argv[0] || argv[1] || argv[2]) + return CMD_SUCCESS; - ospf->distance_inter = atoi (argv[0]); - ospf->distance_external = atoi (argv[1]); + /* If no arguments are given, clear all distance information */ + ospf->distance_intra = 0; + ospf->distance_inter = 0; + ospf->distance_external = 0; return CMD_SUCCESS; } -DEFUN (ospf_distance_ospf_inter_intra_external, - ospf_distance_ospf_inter_intra_external_cmd, - "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>", +DEFUN (ospf_distance_ospf, + ospf_distance_ospf_cmd, + "distance ospf " + "{intra-area <1-255>|inter-area <1-255>|external <1-255>}", "Define an administrative distance\n" "OSPF Administrative distance\n" - "Inter-area routes\n" - "Distance for inter-area routes\n" "Intra-area routes\n" "Distance for intra-area routes\n" - "External routes\n" - "Distance for external routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_inter = atoi (argv[0]); - ospf->distance_intra = atoi (argv[1]); - ospf->distance_external = atoi (argv[2]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_inter_external_intra, - ospf_distance_ospf_inter_external_intra_cmd, - "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" - "Distance for external routes\n" - "Intra-area routes\n" - "Distance for intra-area routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_inter = atoi (argv[0]); - ospf->distance_external = atoi (argv[1]); - ospf->distance_intra = atoi (argv[2]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_external, - ospf_distance_ospf_external_cmd, - "distance ospf external <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; - ospf->distance_external = atoi (argv[0]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_external_intra, - ospf_distance_ospf_external_intra_cmd, - "distance ospf external <1-255> intra-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "External routes\n" - "Distance for external routes\n" - "Intra-area routes\n" - "Distance for intra-area routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_external = atoi (argv[0]); - ospf->distance_intra = atoi (argv[1]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_external_inter, - ospf_distance_ospf_external_inter_cmd, - "distance ospf external <1-255> inter-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "External routes\n" - "Distance for external routes\n" - "Inter-area routes\n" - "Distance for inter-area routes\n") -{ - struct ospf *ospf = vty->index; - - ospf->distance_external = atoi (argv[0]); - ospf->distance_inter = atoi (argv[1]); - - return CMD_SUCCESS; -} - -DEFUN (ospf_distance_ospf_external_intra_inter, - ospf_distance_ospf_external_intra_inter_cmd, - "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "External routes\n" - "Distance for external routes\n" - "Intra-area routes\n" - "Distance for intra-area routes\n" - "Inter-area routes\n" - "Distance for inter-area routes\n") -{ - struct ospf *ospf = vty->index; + if (argc < 3) /* should not happen */ + return CMD_WARNING; - ospf->distance_external = atoi (argv[0]); - ospf->distance_intra = atoi (argv[1]); - ospf->distance_inter = atoi (argv[2]); + if (!argv[0] && !argv[1] && !argv[2]) + { + vty_out(vty, "%% Command incomplete. (Arguments required)%s", + VTY_NEWLINE); + return CMD_WARNING; + } - return CMD_SUCCESS; -} + if (argv[0] != NULL) + ospf->distance_intra = atoi(argv[0]); -DEFUN (ospf_distance_ospf_external_inter_intra, - ospf_distance_ospf_external_inter_intra_cmd, - "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>", - "Define an administrative distance\n" - "OSPF Administrative distance\n" - "External routes\n" - "Distance for external routes\n" - "Inter-area routes\n" - "Distance for inter-area routes\n" - "Intra-area routes\n" - "Distance for intra-area routes\n") -{ - struct ospf *ospf = vty->index; + if (argv[1] != NULL) + ospf->distance_inter = atoi(argv[1]); - ospf->distance_external = atoi (argv[0]); - ospf->distance_inter = atoi (argv[1]); - ospf->distance_intra = atoi (argv[2]); + if (argv[2] != NULL) + ospf->distance_external = atoi(argv[2]); return CMD_SUCCESS; } @@ -8268,63 +7520,13 @@ ospf_vty_if_init (void) static void ospf_vty_zebra_init (void) { - install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd); - install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd); - install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd); - install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_cmd); - install_element (OSPF_NODE, - &ospf_redistribute_source_metric_type_routemap_cmd); - install_element (OSPF_NODE, - &ospf_redistribute_source_type_metric_routemap_cmd); - install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd); - install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd); - install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd); - install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd); install_element (OSPF_NODE, &ospf_distribute_list_out_cmd); install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_metric_type_cmd); - install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_type_metric_cmd); - install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_metric_type_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_metric_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_type_metric_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_type_cmd); - - install_element (OSPF_NODE, - &ospf_default_information_originate_metric_type_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_metric_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_type_metric_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_type_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_metric_type_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_metric_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_type_metric_routemap_cmd); - install_element (OSPF_NODE, - &ospf_default_information_originate_always_type_routemap_cmd); - install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd); install_element (OSPF_NODE, &ospf_default_metric_cmd); @@ -8334,21 +7536,7 @@ ospf_vty_zebra_init (void) install_element (OSPF_NODE, &ospf_distance_cmd); install_element (OSPF_NODE, &no_ospf_distance_cmd); install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd); - install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_cmd); #if 0 install_element (OSPF_NODE, &ospf_distance_source_cmd); install_element (OSPF_NODE, &no_ospf_distance_source_cmd); diff --git a/tests/testcommands.in b/tests/testcommands.in index 70c57052f..7fe62799f 100644 --- a/tests/testcommands.in +++ b/tests/testcommands.in @@ -199,3 +199,18 @@ sow ip bgp ipv4 mulicast community no-export no-adertise no-export no-advertise sow ipv6 ospf6 databIase as-external adv-router 1.2.3.4 Whow bgp view VARIAeBLE ipv4 unicast community local-AS no-advrtise no-advertise local-AS Wneighbor 1.2.3.4 dot-capabiliy-negotiate +# +# +# Some teststrings explicitly used for keyword commands +# +# +redistribute bgp +redistribute bgp m 10 +redistribute bgp metric 10 metric-type 1 +redistribute bgp metric 10 metric 10 +redistribute bgp route-map RMAP_REDIST_BGP +default-information originate metric-type 1 metric 10 +default-information originate always metric-type 1 metric 10 +default-information originate route-map RMAP_DEFAULT +default-information originate route-map RMAP_DEFAULT metric 10 +default-information originate always metric-type 2 metric 23 diff --git a/tests/testcommands.refout b/tests/testcommands.refout index 1422aefcc..11483b84b 100644 --- a/tests/testcommands.refout +++ b/tests/testcommands.refout @@ -299,6 +299,18 @@ complete 'no neighbor VARIABLE maximum-prefix'@22: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@22: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' +execute relaxed 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'isis', '0', '2', 'VARIABLE' +execute strict 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'isis', '0', '2', 'VARIABLE' +complete 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==7 + '2' +describe 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0 + '2' 'Set OSPF External Type 2 metrics' +execute relaxed 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'rip', '0', '1', 'VARIABLE' +execute strict 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'rip', '0', '1', 'VARIABLE' +complete 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==7 + '1' +describe 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0 + '1' 'Set OSPF External Type 1 metrics' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==7 @@ -898,3 +910,98 @@ execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, 'sh complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==2 describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0 'AA:NN' 'community number' +execute relaxed 'redistribute bgp'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel)': 'bgp' +execute strict 'redistribute bgp'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel)': 'bgp' +complete 'redistribute bgp'@14: rv==7 + 'bgp' +describe 'redistribute bgp'@14: rv==0 + 'bgp' 'Border Gateway Protocol (BGP)' +execute relaxed 'redistribute bgp'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel)': 'bgp' +execute strict 'redistribute bgp'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel)': 'bgp' +complete 'redistribute bgp'@15: rv==7 + 'bgp' +describe 'redistribute bgp'@15: rv==0 + 'bgp' 'Border Gateway Protocol (BGP)' +execute relaxed 'redistribute bgp'@16: rv==0, 'redistribute (kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp)': 'bgp' +execute strict 'redistribute bgp'@16: rv==0, 'redistribute (kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp)': 'bgp' +complete 'redistribute bgp'@16: rv==7 + 'bgp' +describe 'redistribute bgp'@16: rv==0 + 'bgp' 'Border Gateway Protocol (BGP)' +execute relaxed 'redistribute bgp'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', '(null)' +execute strict 'redistribute bgp'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', '(null)' +complete 'redistribute bgp'@23: rv==7 + 'bgp' +describe 'redistribute bgp'@23: rv==0 + 'bgp' 'Border Gateway Protocol (BGP)' +execute relaxed 'redistribute bgp'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel)': 'bgp' +execute strict 'redistribute bgp'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel)': 'bgp' +complete 'redistribute bgp'@24: rv==7 + 'bgp' +describe 'redistribute bgp'@24: rv==0 + 'bgp' 'Border Gateway Protocol (BGP)' +execute relaxed 'redistribute bgp m 10'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) metric <0-16>': 'bgp', '10' +execute strict 'redistribute bgp m 10'@14: rv==2 +complete 'redistribute bgp m 10'@14: rv==2 +describe 'redistribute bgp m 10'@14: rv==0 + '<0-16>' 'Metric value' +execute relaxed 'redistribute bgp m 10'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) metric <0-16>': 'bgp', '10' +execute strict 'redistribute bgp m 10'@15: rv==2 +complete 'redistribute bgp m 10'@15: rv==2 +describe 'redistribute bgp m 10'@15: rv==0 + '<0-16>' 'Metric value' +execute relaxed 'redistribute bgp m 10'@23: rv==3 +execute strict 'redistribute bgp m 10'@23: rv==2 +complete 'redistribute bgp m 10'@23: rv==3 +describe 'redistribute bgp m 10'@23: rv==3 +execute relaxed 'redistribute bgp metric 10 metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '10', '1', '(null)' +execute strict 'redistribute bgp metric 10 metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '10', '1', '(null)' +complete 'redistribute bgp metric 10 metric-type 1'@23: rv==7 + '1' +describe 'redistribute bgp metric 10 metric-type 1'@23: rv==0 + '1' 'Set OSPF External Type 1 metrics' +execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' +execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' +complete 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==2 +describe 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0 + 'WORD' 'Pointer to route-map entries' +execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' +execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' +complete 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==2 +describe 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0 + 'WORD' 'Pointer to route-map entries' +execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', 'RMAP_REDIST_BGP' +execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', 'RMAP_REDIST_BGP' +complete 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==2 +describe 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0 + 'WORD' 'Pointer to route-map entries' +execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' +execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' +complete 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==2 +describe 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0 + 'WORD' 'Route map name' +execute relaxed 'default-information originate metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '1', '(null)' +execute strict 'default-information originate metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '1', '(null)' +complete 'default-information originate metric-type 1 metric 10'@23: rv==2 +describe 'default-information originate metric-type 1 metric 10'@23: rv==0 + '<0-16777214>' 'OSPF metric' +execute relaxed 'default-information originate always metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '10', '1', '(null)' +execute strict 'default-information originate always metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '10', '1', '(null)' +complete 'default-information originate always metric-type 1 metric 10'@23: rv==2 +describe 'default-information originate always metric-type 1 metric 10'@23: rv==0 + '<0-16777214>' 'OSPF metric' +execute relaxed 'default-information originate route-map RMAP_DEFAULT'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '(null)', '(null)', 'RMAP_DEFAULT' +execute strict 'default-information originate route-map RMAP_DEFAULT'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '(null)', '(null)', 'RMAP_DEFAULT' +complete 'default-information originate route-map RMAP_DEFAULT'@23: rv==2 +describe 'default-information originate route-map RMAP_DEFAULT'@23: rv==0 + 'WORD' 'Pointer to route-map entries' +execute relaxed 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '(null)', 'RMAP_DEFAULT' +execute strict 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '(null)', 'RMAP_DEFAULT' +complete 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==2 +describe 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0 + '<0-16777214>' 'OSPF metric' +execute relaxed 'default-information originate always metric-type 2 metric 23'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '23', '2', '(null)' +execute strict 'default-information originate always metric-type 2 metric 23'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '23', '2', '(null)' +complete 'default-information originate always metric-type 2 metric 23'@23: rv==2 +describe 'default-information originate always metric-type 2 metric 23'@23: rv==0 + '<0-16777214>' 'OSPF metric' From ba32db1e854ff2b26861a2d4e4193a9f1b3816cd Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 19 Nov 2013 14:11:40 +0000 Subject: [PATCH 0337/1342] tests: Add tests for timers Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- tests/.gitignore | 2 + tests/Makefile.am | 6 +- tests/libzebra.tests/Makefile.am | 1 + .../libzebra.tests/test-timer-correctness.exp | 7 + tests/test-timer-correctness.c | 194 ++++++++++++++++++ tests/test-timer-performance.c | 104 ++++++++++ 6 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 tests/libzebra.tests/test-timer-correctness.exp create mode 100644 tests/test-timer-correctness.c create mode 100644 tests/test-timer-performance.c diff --git a/tests/.gitignore b/tests/.gitignore index 0ace3656d..1cb28c9fd 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -22,6 +22,8 @@ heavy heavythread heavywq tabletest +test-timer-correctness +test-timer-performance testbgpcap testbgpmpath testbgpmpattr diff --git a/tests/Makefile.am b/tests/Makefile.am index 8707fe7d9..8a086d0b6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -28,7 +28,7 @@ endif check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ - testcommands \ + testcommands test-timer-correctness test-timer-performance \ $(TESTS_BGPD) ../vtysh/vtysh_cmd.c: @@ -63,6 +63,8 @@ testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c +test_timer_correctness_SOURCES = test-timer-correctness.c prng.c +test_timer_performance_SOURCES = test-timer-performance.c prng.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ @@ -82,3 +84,5 @@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ testcommands_LDADD = ../lib/libzebra.la @LIBCAP@ +test_timer_correctness_LDADD = ../lib/libzebra.la @LIBCAP@ +test_timer_performance_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/tests/libzebra.tests/Makefile.am b/tests/libzebra.tests/Makefile.am index a1ffea3de..819cce2fe 100644 --- a/tests/libzebra.tests/Makefile.am +++ b/tests/libzebra.tests/Makefile.am @@ -1,4 +1,5 @@ EXTRA_DIST = \ tabletest.exp \ + test-timer-correctness.exp \ testcommands.exp \ testnexthopiter.exp diff --git a/tests/libzebra.tests/test-timer-correctness.exp b/tests/libzebra.tests/test-timer-correctness.exp new file mode 100644 index 000000000..83531c7df --- /dev/null +++ b/tests/libzebra.tests/test-timer-correctness.exp @@ -0,0 +1,7 @@ +set timeout 10 +set testprefix "test-timer-correctness" +set aborted 0 + +spawn "./test-timer-correctness" + +onesimple "" "Expected output and actual output match." diff --git a/tests/test-timer-correctness.c b/tests/test-timer-correctness.c new file mode 100644 index 000000000..94c8f1df2 --- /dev/null +++ b/tests/test-timer-correctness.c @@ -0,0 +1,194 @@ +/* + * Test program to verify that scheduled timers are executed in the + * correct order. + * + * Copyright (C) 2013 by Open Source Routing. + * Copyright (C) 2013 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 +#include + +#include + +#include "memory.h" +#include "pqueue.h" +#include "prng.h" +#include "thread.h" + +#define SCHEDULE_TIMERS 800 +#define REMOVE_TIMERS 200 + +#define TIMESTR_LEN strlen("4294967296.999999") + +struct thread_master *master; + +static size_t log_buf_len; +static size_t log_buf_pos; +static char *log_buf; + +static size_t expected_buf_len; +static size_t expected_buf_pos; +static char *expected_buf; + +static struct prng *prng; + +static struct thread **timers; + +static int timers_pending; + +static void terminate_test(void) +{ + int exit_code; + + if (strcmp(log_buf, expected_buf)) + { + fprintf(stderr, "Expected output and received output differ.\n"); + fprintf(stderr, "---Expected output: ---\n%s", expected_buf); + fprintf(stderr, "---Actual output: ---\n%s", log_buf); + exit_code = 1; + } + else + { + printf("Expected output and actual output match.\n"); + exit_code = 0; + } + + thread_master_free(master); + XFREE(MTYPE_TMP, log_buf); + XFREE(MTYPE_TMP, expected_buf); + prng_free(prng); + XFREE(MTYPE_TMP, timers); + + exit(exit_code); +} + +static int timer_func(struct thread *thread) +{ + int rv; + + rv = snprintf(log_buf + log_buf_pos, log_buf_len - log_buf_pos, + "%s\n", (char*)thread->arg); + assert(rv >= 0); + log_buf_pos += rv; + assert(log_buf_pos < log_buf_len); + XFREE(MTYPE_TMP, thread->arg); + + timers_pending--; + if (!timers_pending) + terminate_test(); + + return 0; +} + +static int cmp_timeval(const void* a, const void *b) +{ + const struct timeval *ta = *(struct timeval * const *)a; + const struct timeval *tb = *(struct timeval * const *)b; + + if (timercmp(ta, tb, <)) + return -1; + if (timercmp(ta, tb, >)) + return 1; + return 0; +} + +int main(int argc, char **argv) +{ + int i, j; + struct thread t; + struct timeval **alarms; + + master = thread_master_create(); + + log_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1; + log_buf_pos = 0; + log_buf = XMALLOC(MTYPE_TMP, log_buf_len); + + expected_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1; + expected_buf_pos = 0; + expected_buf = XMALLOC(MTYPE_TMP, expected_buf_len); + + prng = prng_new(0); + + timers = XMALLOC(MTYPE_TMP, SCHEDULE_TIMERS * sizeof(*timers)); + + for (i = 0; i < SCHEDULE_TIMERS; i++) + { + long interval_msec; + int ret; + char *arg; + + /* Schedule timers to expire in 0..5 seconds */ + interval_msec = prng_rand(prng) % 5000; + arg = XMALLOC(MTYPE_TMP, TIMESTR_LEN + 1); + timers[i] = thread_add_timer_msec(master, timer_func, arg, interval_msec); + ret = snprintf(arg, TIMESTR_LEN + 1, "%ld.%06ld", + timers[i]->u.sands.tv_sec, timers[i]->u.sands.tv_usec); + assert(ret > 0); + assert((size_t)ret < TIMESTR_LEN + 1); + timers_pending++; + } + + for (i = 0; i < REMOVE_TIMERS; i++) + { + int index; + + index = prng_rand(prng) % SCHEDULE_TIMERS; + if (!timers[index]) + continue; + + XFREE(MTYPE_TMP, timers[index]->arg); + thread_cancel(timers[index]); + timers[index] = NULL; + timers_pending--; + } + + /* We create an array of pointers to the alarm times and sort + * that array. That sorted array is used to generate a string + * representing the expected "output" of the timers when they + * are run. */ + j = 0; + alarms = XMALLOC(MTYPE_TMP, timers_pending * sizeof(*alarms)); + for (i = 0; i < SCHEDULE_TIMERS; i++) + { + if (!timers[i]) + continue; + alarms[j++] = &timers[i]->u.sands; + } + qsort(alarms, j, sizeof(*alarms), cmp_timeval); + for (i = 0; i < j; i++) + { + int ret; + + ret = snprintf(expected_buf + expected_buf_pos, + expected_buf_len - expected_buf_pos, + "%ld.%06ld\n", alarms[i]->tv_sec, alarms[i]->tv_usec); + assert(ret > 0); + expected_buf_pos += ret; + assert(expected_buf_pos < expected_buf_len); + } + XFREE(MTYPE_TMP, alarms); + + while (thread_fetch(master, &t)) + thread_call(&t); + + return 0; +} diff --git a/tests/test-timer-performance.c b/tests/test-timer-performance.c new file mode 100644 index 000000000..a529a5ce0 --- /dev/null +++ b/tests/test-timer-performance.c @@ -0,0 +1,104 @@ +/* + * Test program which measures the time it takes to schedule and + * remove timers. + * + * Copyright (C) 2013 by Open Source Routing. + * Copyright (C) 2013 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 +#include + +#include + +#include "thread.h" +#include "pqueue.h" +#include "prng.h" + +#define SCHEDULE_TIMERS 1000000 +#define REMOVE_TIMERS 500000 + +struct thread_master *master; + +static int dummy_func(struct thread *thread) +{ + return 0; +} + +int main(int argc, char **argv) +{ + struct prng *prng; + int i; + struct thread **timers; + struct timeval tv_start, tv_lap, tv_stop; + unsigned long t_schedule, t_remove; + + master = thread_master_create(); + prng = prng_new(0); + timers = calloc(SCHEDULE_TIMERS, sizeof(*timers)); + + /* create thread structures so they won't be allocated during the + * time measurement */ + for (i = 0; i < SCHEDULE_TIMERS; i++) + timers[i] = thread_add_timer_msec(master, dummy_func, NULL, 0); + for (i = 0; i < SCHEDULE_TIMERS; i++) + thread_cancel(timers[i]); + + quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_start); + + for (i = 0; i < SCHEDULE_TIMERS; i++) + { + long interval_msec; + + interval_msec = prng_rand(prng) % (100 * SCHEDULE_TIMERS); + timers[i] = thread_add_timer_msec(master, dummy_func, + NULL, interval_msec); + } + + quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_lap); + + for (i = 0; i < REMOVE_TIMERS; i++) + { + int index; + + index = prng_rand(prng) % SCHEDULE_TIMERS; + if (timers[index]) + thread_cancel(timers[index]); + timers[index] = NULL; + } + + quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_stop); + + t_schedule = 1000 * (tv_lap.tv_sec - tv_start.tv_sec); + t_schedule += (tv_lap.tv_usec - tv_start.tv_usec) / 1000; + + t_remove = 1000 * (tv_stop.tv_sec - tv_lap.tv_sec); + t_remove += (tv_stop.tv_usec - tv_lap.tv_usec) / 1000; + + printf("Scheduling %d random timers took %ld.%03ld seconds.\n", + SCHEDULE_TIMERS, t_schedule/1000, t_schedule%1000); + printf("Removing %d random timers took %ld.%03ld seconds.\n", + REMOVE_TIMERS, t_remove/1000, t_remove%1000); + fflush(stdout); + + free(timers); + thread_master_free(master); + prng_free(prng); + return 0; +} From 514991c76366c2a9f4c644714ad0722df0eed532 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 19 Nov 2013 14:11:41 +0000 Subject: [PATCH 0338/1342] lib: remove unused thread_master_debug function Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- lib/thread.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 27c29d6c8..ddb95c015 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -496,35 +496,6 @@ DEFUN(clear_thread_cpu, return CMD_SUCCESS; } -/* List allocation and head/tail print out. */ -static void -thread_list_debug (struct thread_list *list) -{ - printf ("count [%d] head [%p] tail [%p]\n", - list->count, list->head, list->tail); -} - -/* Debug print for thread_master. */ -static void __attribute__ ((unused)) -thread_master_debug (struct thread_master *m) -{ - printf ("-----------\n"); - printf ("readlist : "); - thread_list_debug (&m->read); - printf ("writelist : "); - thread_list_debug (&m->write); - printf ("timerlist : "); - thread_list_debug (&m->timer); - printf ("eventlist : "); - thread_list_debug (&m->event); - printf ("unuselist : "); - thread_list_debug (&m->unuse); - printf ("bgndlist : "); - thread_list_debug (&m->background); - printf ("total alloc: [%ld]\n", m->alloc); - printf ("-----------\n"); -} - /* Allocate new thread master. */ struct thread_master * thread_master_create () From 4becea724ccd87e88f8454622ae227308b5fa3ce Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 19 Nov 2013 14:11:42 +0000 Subject: [PATCH 0339/1342] lib: use heap to manage timers Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- lib/pqueue.c | 17 +++++++ lib/pqueue.h | 1 + lib/thread.c | 138 ++++++++++++++++++++++++++++++++------------------- lib/thread.h | 7 ++- 4 files changed, 110 insertions(+), 53 deletions(-) diff --git a/lib/pqueue.c b/lib/pqueue.c index 12a779f2a..69ab8e65d 100644 --- a/lib/pqueue.c +++ b/lib/pqueue.c @@ -168,3 +168,20 @@ pqueue_dequeue (struct pqueue *queue) trickle_down (0, queue); return data; } + +void +pqueue_remove_at (int index, struct pqueue *queue) +{ + queue->array[index] = queue->array[--queue->size]; + + if (index > 0 + && (*queue->cmp) (queue->array[index], + queue->array[PARENT_OF(index)]) < 0) + { + trickle_up (index, queue); + } + else + { + trickle_down (index, queue); + } +} diff --git a/lib/pqueue.h b/lib/pqueue.h index be37f98da..8bb6961d8 100644 --- a/lib/pqueue.h +++ b/lib/pqueue.h @@ -38,6 +38,7 @@ extern void pqueue_delete (struct pqueue *queue); extern void pqueue_enqueue (void *data, struct pqueue *queue); extern void *pqueue_dequeue (struct pqueue *queue); +extern void pqueue_remove_at (int index, struct pqueue *queue); extern void trickle_down (int index, struct pqueue *queue); extern void trickle_up (int index, struct pqueue *queue); diff --git a/lib/thread.c b/lib/thread.c index ddb95c015..e2a37b149 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -27,6 +27,7 @@ #include "memory.h" #include "log.h" #include "hash.h" +#include "pqueue.h" #include "command.h" #include "sigevent.h" @@ -496,17 +497,49 @@ DEFUN(clear_thread_cpu, return CMD_SUCCESS; } +static int +thread_timer_cmp(void *a, void *b) +{ + struct thread *thread_a = a; + struct thread *thread_b = b; + + long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands); + + if (cmp < 0) + return -1; + if (cmp > 0) + return 1; + return 0; +} + +static void +thread_timer_update(void *node, int actual_position) +{ + struct thread *thread = node; + + thread->index = actual_position; +} + /* Allocate new thread master. */ struct thread_master * thread_master_create () { + struct thread_master *rv; + if (cpu_record == NULL) cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, (int (*) (const void *, const void *))cpu_record_hash_cmp); - - return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, - sizeof (struct thread_master)); + + rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); + + /* Initialize the timer queues */ + rv->timer = pqueue_create(); + rv->background = pqueue_create(); + rv->timer->cmp = rv->background->cmp = thread_timer_cmp; + rv->timer->update = rv->background->update = thread_timer_update; + + return rv; } /* Add a new thread to the list. */ @@ -523,22 +556,6 @@ thread_list_add (struct thread_list *list, struct thread *thread) list->count++; } -/* Add a new thread just before the point. */ -static void -thread_list_add_before (struct thread_list *list, - struct thread *point, - struct thread *thread) -{ - thread->next = point; - thread->prev = point->prev; - if (point->prev) - point->prev->next = thread; - else - list->head = thread; - point->prev = thread; - list->count++; -} - /* Delete a thread from the list. */ static struct thread * thread_list_delete (struct thread_list *list, struct thread *thread) @@ -584,17 +601,29 @@ thread_list_free (struct thread_master *m, struct thread_list *list) } } +static void +thread_queue_free (struct thread_master *m, struct pqueue *queue) +{ + int i; + + for (i = 0; i < queue->size; i++) + XFREE(MTYPE_THREAD, queue->array[i]); + + m->alloc -= queue->size; + pqueue_delete(queue); +} + /* Stop thread scheduler. */ void thread_master_free (struct thread_master *m) { thread_list_free (m, &m->read); thread_list_free (m, &m->write); - thread_list_free (m, &m->timer); + thread_queue_free (m, m->timer); thread_list_free (m, &m->event); thread_list_free (m, &m->ready); thread_list_free (m, &m->unuse); - thread_list_free (m, &m->background); + thread_queue_free (m, m->background); XFREE (MTYPE_THREAD_MASTER, m); @@ -676,7 +705,8 @@ thread_get (struct thread_master *m, u_char type, thread->master = m; thread->func = func; thread->arg = arg; - + thread->index = -1; + strip_funcname (thread->funcname, funcname); return thread; @@ -737,16 +767,15 @@ funcname_thread_add_timer_timeval (struct thread_master *m, const char* funcname) { struct thread *thread; - struct thread_list *list; + struct pqueue *queue; struct timeval alarm_time; - struct thread *tt; assert (m != NULL); assert (type == THREAD_TIMER || type == THREAD_BACKGROUND); assert (time_relative); - list = ((type == THREAD_TIMER) ? &m->timer : &m->background); + queue = ((type == THREAD_TIMER) ? m->timer : m->background); thread = thread_get (m, type, func, arg, funcname); /* Do we need jitter here? */ @@ -755,16 +784,7 @@ funcname_thread_add_timer_timeval (struct thread_master *m, alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec; thread->u.sands = timeval_adjust(alarm_time); - /* Sort by timeval. */ - for (tt = list->head; tt; tt = tt->next) - if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) - break; - - if (tt) - thread_list_add_before (list, tt, thread); - else - thread_list_add (list, thread); - + pqueue_enqueue(thread, queue); return thread; } @@ -849,7 +869,8 @@ funcname_thread_add_event (struct thread_master *m, void thread_cancel (struct thread *thread) { - struct thread_list *list; + struct thread_list *list = NULL; + struct pqueue *queue = NULL; switch (thread->type) { @@ -864,7 +885,7 @@ thread_cancel (struct thread *thread) list = &thread->master->write; break; case THREAD_TIMER: - list = &thread->master->timer; + queue = thread->master->timer; break; case THREAD_EVENT: list = &thread->master->event; @@ -873,13 +894,28 @@ thread_cancel (struct thread *thread) list = &thread->master->ready; break; case THREAD_BACKGROUND: - list = &thread->master->background; + queue = thread->master->background; break; default: return; break; } - thread_list_delete (list, thread); + + if (queue) + { + assert(thread->index >= 0); + assert(thread == queue->array[thread->index]); + pqueue_remove_at(thread->index, queue); + } + else if (list) + { + thread_list_delete (list, thread); + } + else + { + assert(!"Thread should be either in queue or list!"); + } + thread->type = THREAD_UNUSED; thread_add_unuse (thread->master, thread); } @@ -929,11 +965,12 @@ thread_cancel_event (struct thread_master *m, void *arg) } static struct timeval * -thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val) +thread_timer_wait (struct pqueue *queue, struct timeval *timer_val) { - if (!thread_empty (tlist)) + if (queue->size) { - *timer_val = timeval_subtract (tlist->head->u.sands, relative_time); + struct thread *next_timer = queue->array[0]; + *timer_val = timeval_subtract (next_timer->u.sands, relative_time); return timer_val; } return NULL; @@ -977,18 +1014,17 @@ thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset) /* Add all timers that have popped to the ready list. */ static unsigned int -thread_timer_process (struct thread_list *list, struct timeval *timenow) +thread_timer_process (struct pqueue *queue, struct timeval *timenow) { struct thread *thread; - struct thread *next; unsigned int ready = 0; - for (thread = list->head; thread; thread = next) + while (queue->size) { - next = thread->next; + thread = queue->array[0]; if (timeval_cmp (*timenow, thread->u.sands) < 0) return ready; - thread_list_delete (list, thread); + pqueue_dequeue(queue); thread->type = THREAD_READY; thread_list_add (&thread->master->ready, thread); ready++; @@ -1064,8 +1100,8 @@ thread_fetch (struct thread_master *m, struct thread *fetch) if (m->ready.count == 0) { quagga_get_relative (NULL); - timer_wait = thread_timer_wait (&m->timer, &timer_val); - timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg); + timer_wait = thread_timer_wait (m->timer, &timer_val); + timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg); if (timer_wait_bg && (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) @@ -1121,7 +1157,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ quagga_get_relative (NULL); - thread_timer_process (&m->timer, &relative_time); + thread_timer_process (m->timer, &relative_time); /* Got IO, process it */ if (num > 0) @@ -1142,7 +1178,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) #endif /* Background timer/events, lowest priority */ - thread_timer_process (&m->background, &relative_time); + thread_timer_process (m->background, &relative_time); if ((thread = thread_trim_head (&m->ready)) != NULL) return thread_run (m, thread, fetch); diff --git a/lib/thread.h b/lib/thread.h index 67902cf6c..dbf5f25b8 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -44,16 +44,18 @@ struct thread_list int count; }; +struct pqueue; + /* Master of the theads. */ struct thread_master { struct thread_list read; struct thread_list write; - struct thread_list timer; + struct pqueue *timer; struct thread_list event; struct thread_list ready; struct thread_list unuse; - struct thread_list background; + struct pqueue *background; fd_set readfd; fd_set writefd; fd_set exceptfd; @@ -80,6 +82,7 @@ struct thread int fd; /* file descriptor in case of read/write. */ struct timeval sands; /* rest of time sands value. */ } u; + int index; /* used for timers to store position in queue */ struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ char funcname[FUNCNAME_LEN]; From 24c84dbe806084552d7bb14b9f1d00514a048b9d Mon Sep 17 00:00:00 2001 From: Ken Williams Date: Tue, 15 Apr 2014 02:23:11 +0000 Subject: [PATCH 0340/1342] zebra: Change the mechanism for comparing route ID's. The current format uses subtraction of two ints. Unfortunately, the subtraction method does not work for all combinations of numbers. For example, the with numbers represented by 10.x.x.x and 192.x.x.x, 10.x.x.x - 192.x.x.x will yield a very large positive number indicating that 10.x.x.x is larger. Signed-off-by: Ken Williams Acked-by: Feng Lu Signed-off-by: David Lamparter --- zebra/router-id.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/zebra/router-id.c b/zebra/router-id.c index 3d6b511c5..b738027ec 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -230,10 +230,8 @@ router_id_cmp (void *a, void *b) { const struct connected *ifa = (const struct connected *)a; const struct connected *ifb = (const struct connected *)b; - unsigned int A = ntohl(ifa->address->u.prefix4.s_addr); - unsigned int B = ntohl(ifb->address->u.prefix4.s_addr); - return (int) (A - B); + return IPV4_ADDR_CMP(&ifa->address->u.prefix4.s_addr,&ifb->address->u.prefix4.s_addr); } void From 7a9d983e4f961c2103f2cf82a51d5d8321ad0e43 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 10 Jul 2013 11:56:18 +0000 Subject: [PATCH 0341/1342] ospfd: run DR election prior to LSA regeneration The results from DR election are used when constructing router-LSAs. E.g. they are used to determine whether a broadcast interface should be added with a link type of stub interface or transit interface. Therefore, we should run DR election prior before regenerating LSAs. Before commit c363d3861b5384a31465a72ddc3b0f6ff007a95a the DR election was called synchronously prior to router-LSA regeneration which was run asynchronously. This fixes bug #761 on the Quagga bugzilla. Signed-off-by: Christian Franke Acked-by: Feng Lu Signed-off-by: David Lamparter --- ospfd/ospf_nsm.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index fe4ddf5b2..bcabd5f70 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -661,6 +661,25 @@ nsm_change_state (struct ospf_neighbor *nbr, int state) if (oi->type == OSPF_IFTYPE_VIRTUALLINK) vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id); + /* Generate NeighborChange ISM event. + * + * In response to NeighborChange, DR election is rerun. The information + * from the election process is required by the router-lsa construction. + * + * Therefore, trigger the event prior to refreshing the LSAs. */ + switch (oi->state) { + case ISM_DROther: + case ISM_Backup: + case ISM_DR: + if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) || + (old_state >= NSM_TwoWay && state < NSM_TwoWay)) + OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange); + break; + default: + /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */ + break; + } + /* One of the neighboring routers changes to/from the FULL state. */ if ((old_state != NSM_Full && state == NSM_Full) || (old_state == NSM_Full && state != NSM_Full)) @@ -760,20 +779,6 @@ nsm_change_state (struct ospf_neighbor *nbr, int state) if (state == NSM_Down) nbr->crypt_seqnum = 0; - /* Generete NeighborChange ISM event. */ - switch (oi->state) { - case ISM_DROther: - case ISM_Backup: - case ISM_DR: - if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) || - (old_state >= NSM_TwoWay && state < NSM_TwoWay)) - OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange); - break; - default: - /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */ - break; - } - /* Preserve old status? */ } From 4b4bda9bb1913579bd54667f62fafe58e2746478 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 11 Jul 2013 07:56:29 +0000 Subject: [PATCH 0342/1342] ospfd: don't allow to set network type on loopback interfaces OSPFd only allocates some stub information for loopback interfaces. This causes a crash when the interface state machine is started on that interface by configuring a different network type. It doesn't make much sense to configure the network type of a loopback interface, therefore, just forbid it. See also bugzilla #670. Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospfd/ospf_vty.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 1489b20a4..ee8c90190 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -5309,7 +5309,13 @@ DEFUN (ip_ospf_network, struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; struct route_node *rn; - + + if (old_type == OSPF_IFTYPE_LOOPBACK) + { + vty_out (vty, "This is a loopback interface. Can't set network type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (strncmp (argv[0], "b", 1) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; else if (strncmp (argv[0], "n", 1) == 0) From 49d7af115177d05bd66d3115cbacd56a7591ec5e Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Fri, 21 Feb 2014 08:11:15 +0000 Subject: [PATCH 0343/1342] ospfd: check the LS-Ack's recentness instead of only comparing the #seq ISSUE: RTA(DR)-----(BackupDR)RTB RTA advertises a new LSA to RTB, and then flushes the LSA (with setting the age of the LSA to MaxAge) within 1 second. Then the LSA is deleted from RTA, while it still exists on RTB with non-MaxAge and can not be flushed any more. FIX: The reason can be explained in below: a) RTA -- new LSA, #seq=1 --> RTB (RTB will send the delayed Ack in 1s) b) RTA -- MaxAge LSA, #seq=1 --> RTB (RTB discards it for the MIN_LS_ARRIVAL) c) RTA <-- Ack for the new LSA, #seq=1 -- RTB (RTA accepts it) In the step c), ospf_ls_ack() compares the #seq of the entry in the LS-Ack with that of local MaxAge LSA. The #seq of the two entries are same. So the Ack is accepted and the LSA is removed from the retransmit-list (while it should not). In RFC2328, section 13.7. Receiving link state acknowledgments: o If the acknowledgment is for the same instance that is <== contained on the list, remove the item from the list and examine the next acknowledgment. Otherwise: where "same instance" does not mean the same #seq. We must call ospf_lsa_more_recent() to check whether the two instances are same. Signed-off-by: Feng Lu Signed-off-by: Christian Franke Signed-off-by: David Lamparter --- ospfd/ospf_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index ab68bf0b7..cce56fc62 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2120,7 +2120,7 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh, lsr = ospf_ls_retransmit_lookup (nbr, lsa); - if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) + if (lsr != NULL && ospf_lsa_more_recent (lsr, lsa) == 0) { #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsr->data->type)) From e387dfd18ded3ddfef4c0a9cb896f73831864579 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 28 Apr 2014 08:04:58 +0000 Subject: [PATCH 0344/1342] ospfd: fix a reference counting issue introduced by commit 4de8bf0011 Commit 4de8bf0011 added a return statement to a loop iterating over a route_table. That loop uses route_top/route_next. As commit 4de8bf0011 failed to add a route_node_unlock before the return statement, a reference is leaked when this codepath is taken. Signed-off-by: Christian Franke Acked-by: Feng Lu Signed-off-by: David Lamparter --- ospfd/ospf_lsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 109a120b1..270c1ea21 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2856,6 +2856,7 @@ ospf_maxage_lsa_remover (struct thread *thread) if (thread_should_yield (thread)) { OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); + route_unlock_node(rn); /* route_top/route_next */ return 0; } From 8afee5c1729e56f74d27ceb1766bea9f943f060c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 28 Apr 2014 08:04:59 +0000 Subject: [PATCH 0345/1342] ospfd: clarify indentation and comments in ospf_lsa_maxage_delete Signed-off-by: Christian Franke Acked-by: Feng Lu Signed-off-by: David Lamparter --- ospfd/ospf_lsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 270c1ea21..369655163 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2915,9 +2915,9 @@ ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); ospf_lsa_unlock (&lsa); /* maxage_lsa */ rn->info = NULL; - route_unlock_node (rn); /* route_node_lookup */ + route_unlock_node (rn); /* unlock node because lsa is deleted */ } - route_unlock_node (rn); /* route_node_lookup */ + route_unlock_node (rn); /* route_node_lookup */ } } From b4b359a265f1b6272b4eb17c11e9c6ef9817f34b Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Mon, 28 Apr 2014 10:58:06 +0000 Subject: [PATCH 0346/1342] ospfd: For an ABR, ensure the right LSID is MaxAge'd PROBLEM: Accurate garbage collection of maxage LSAs. The global OSPF structure has a maxage_lsa tree - the key to the tree is tuple. Suppose the ABR has multiple areas and has originated some intra-area LSAs. The key for all those LSAs is the same. The code then ends up in a state where all but the first LSA do not get cleaned up from the areas' LSDB. A subsequent event would readvertise those LSAs. PATCH: Since the LSA is going to stick around till it actually gets cleaned up by the maxage_walker, make the LSA pointer as the key. Each distinct LSA that gets maxage'd then gets added to the tree and will get cleaned up correctly. Signed-off-by: Pradosh Mohapatra [CF: Use CHAR_BIT; use uintptr_t; use sizeof(field) instead of sizeof(type)] Signed-off-by: Christian Franke [DL: this must remain a temporary fix! needs to be redone after 0.99.23] Signed-off-by: David Lamparter --- lib/prefix.h | 9 +++++++++ ospfd/ospf_lsa.c | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/prefix.h b/lib/prefix.h index 9ef70ff50..45889e086 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -52,6 +52,7 @@ struct prefix struct in_addr adv_router; } lp; u_char val[8]; + uintptr_t ptr; } u __attribute__ ((aligned (8))); }; @@ -89,6 +90,14 @@ struct prefix_rd u_char val[8] __attribute__ ((aligned (8))); }; +/* Prefix for a generic pointer */ +struct prefix_ptr +{ + u_char family; + u_char prefixlen; + uintptr_t prefix __attribute__ ((aligned (8))); +}; + /* helper to get type safety/avoid casts on calls * (w/o this, functions accepting all prefix types need casts on the caller * side, which strips type safety since the cast will accept any pointer diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 369655163..0a66b1d4c 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2903,9 +2903,11 @@ void ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) { struct route_node *rn; - struct prefix_ls lsa_prefix; + struct prefix_ptr lsa_prefix; - ls_prefix_set (&lsa_prefix, lsa); + lsa_prefix.family = 0; + lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; + lsa_prefix.prefix = (uintptr_t) lsa; if ((rn = route_node_lookup(ospf->maxage_lsa, (struct prefix *)&lsa_prefix))) @@ -2929,7 +2931,7 @@ ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) void ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) { - struct prefix_ls lsa_prefix; + struct prefix_ptr lsa_prefix; struct route_node *rn; /* When we saw a MaxAge LSA flooded to us, we put it on the list @@ -2942,12 +2944,18 @@ ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) return; } - ls_prefix_set (&lsa_prefix, lsa); + lsa_prefix.family = 0; + lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; + lsa_prefix.prefix = (uintptr_t) lsa; + if ((rn = route_node_get (ospf->maxage_lsa, (struct prefix *)&lsa_prefix)) != NULL) { if (rn->info != NULL) { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_debug ("LSA[%s]: found LSA (%p) in table for LSA %p %d", + dump_lsa_key (lsa), rn->info, lsa, lsa_prefix.prefixlen); route_unlock_node (rn); } else From cbf435cb72b937c9e5bfe38905e05de3755b1021 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 28 Apr 2014 11:42:20 +0000 Subject: [PATCH 0347/1342] ospfd: add debug messages for router lsa-generation Add log messages to lsa_link_broadcast_set so it becomes more apparent why a particular broadcast interface was added as transit or stub interface. Signed-off-by: Christian Franke Acked-by: Feng Lu Signed-off-by: David Lamparter --- ospfd/ospf_lsa.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 0a66b1d4c..967cdb580 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -568,6 +568,9 @@ lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) /* Describe Type 3 Link. */ if (oi->state == ISM_Waiting) { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_debug ("LSA[Type1]: Interface %s is in state Waiting. " + "Adding stub interface", oi->ifp->name); masklen2ip (oi->address->prefixlen, &mask); id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, @@ -580,12 +583,18 @@ lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) && ospf_nbr_count (oi, NSM_Full) > 0) { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_debug ("LSA[Type1]: Interface %s has a DR. " + "Adding transit interface", oi->ifp->name); return link_info_set (s, DR (oi), oi->address->u.prefix4, LSA_LINK_TYPE_TRANSIT, 0, cost); } /* Describe type 3 link. */ else { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_debug ("LSA[Type1]: Interface %s has no DR. " + "Adding stub interface", oi->ifp->name); masklen2ip (oi->address->prefixlen, &mask); id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, From d92a2f39b46f1990052d2db046b47edf7bb21ebb Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Wed, 31 Jul 2013 16:36:08 +0000 Subject: [PATCH 0348/1342] bgpd: use ATTR_FLAG_BIT() for BGP_ATTR_ values * bgp_attr.c: this UNSET_FLAG()s are bogus. I did a quick review and I think that they could not cause any bug anyway. Signed-off-by: Jorge Boncompte [DTI2] Acked-by: Feng Lu Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index cbf2902d6..feb073c66 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -645,21 +645,21 @@ bgp_attr_unintern_sub (struct attr *attr) /* aspath refcount shoud be decrement. */ if (attr->aspath) aspath_unintern (&attr->aspath); - UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)); if (attr->community) community_unintern (&attr->community); - UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); if (attr->extra) { if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); - UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); if (attr->extra->cluster) cluster_unintern (attr->extra->cluster); - UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); if (attr->extra->transit) transit_unintern (attr->extra->transit); From 2fdd455cfd1f758b7aa2e6c8e3d185098b93908c Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Sat, 7 Sep 2013 07:02:36 +0000 Subject: [PATCH 0349/1342] bgpd: add 'bgp bestpath as-path multipath-relax' Compute multipath in BGP based on AS_PATH hop count match. If the knob is turned on, it is not required to have an exact match of AS_PATHs (provided other multipath conditions are met, of course). Signed-off-by: Pradosh Mohapatra Reviewed-by: Dinesh G Dutt Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 15 ++++++++++++++- bgpd/bgp_vty.c | 36 ++++++++++++++++++++++++++++++++++++ bgpd/bgpd.c | 3 +++ bgpd/bgpd.h | 1 + doc/bgpd.texi | 6 ++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 335543e08..7f68b8d0a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -480,7 +480,20 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, /* 9. Maximum path check. */ if (newm == existm) { - if (new->peer->sort == BGP_PEER_IBGP) + if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) + { + + /* + * For the two paths, all comparison steps till IGP metric + * have succeeded - including AS_PATH hop count. Since 'bgp + * bestpath as-path multipath-relax' knob is on, we don't need + * an exact match of AS_PATH. Thus, mark the paths are equal. + * That will trigger both these paths to get into the multipath + * array. + */ + *paths_eq = 1; + } + else if (new->peer->sort == BGP_PEER_IBGP) { if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) *paths_eq = 1; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0f2889481..bfa1f2044 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1160,6 +1160,38 @@ DEFUN (no_bgp_bestpath_aspath_confed, return CMD_SUCCESS; } +/* "bgp bestpath as-path multipath-relax" configuration. */ +DEFUN (bgp_bestpath_aspath_multipath_relax, + bgp_bestpath_aspath_multipath_relax_cmd, + "bgp bestpath as-path multipath-relax", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Allow load sharing across routes that have different AS paths (but same length)\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_aspath_multipath_relax, + no_bgp_bestpath_aspath_multipath_relax_cmd, + "no bgp bestpath as-path multipath-relax", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Allow load sharing across routes that have different AS paths (but same length)\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); + return CMD_SUCCESS; +} + /* "bgp log-neighbor-changes" configuration. */ DEFUN (bgp_log_neighbor_changes, bgp_log_neighbor_changes_cmd, @@ -9172,6 +9204,10 @@ bgp_vty_init (void) install_element (BGP_NODE, &bgp_bestpath_aspath_confed_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_confed_cmd); + /* "bgp bestpath as-path multipath-relax" commands */ + install_element (BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd); + /* "bgp log-neighbor-changes" commands */ install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd); install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c9a04fff9..4b26993e7 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5276,6 +5276,9 @@ bgp_config_write (struct vty *vty) vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED)) vty_out (vty, " bgp bestpath as-path confed%s", VTY_NEWLINE); + if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { + vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE); + } if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)) vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0746f0dd7..024fedcf3 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -120,6 +120,7 @@ struct bgp #define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 11) #define BGP_FLAG_GRACEFUL_RESTART (1 << 12) #define BGP_FLAG_ASPATH_CONFED (1 << 13) +#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; diff --git a/doc/bgpd.texi b/doc/bgpd.texi index dd37d3ecd..24028d6f9 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -124,6 +124,12 @@ sequences should should be taken into account during the BGP best path decision process. @end deffn +@deffn {BGP} {bgp bestpath as-path multipath-relax} {} +This command specifies that BGP decision process should consider paths +of equal AS_PATH length candidates for multipath computation. Without +the knob, the entire AS_PATH must match for multipath computation. +@end deffn + @node BGP route flap dampening @subsection BGP route flap dampening From 689bb66c6a92d238bed1a8b0920438c5a2271966 Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Sat, 7 Sep 2013 07:13:37 +0000 Subject: [PATCH 0350/1342] bgpd: track correct originator-id in reflected routes ISSUE: Suppose route1 and route2 received from route-reflector-client1 and client2 respectively have identical attributes. The current logic of creating the adj-rib-out for a peer threads the 'adv' structures for both routes against the same attribute. This results in 'bgp_update_packet()' to pack those routes in the same UPDATE message with one attr structure formatted. The originator-id is thus set according to the first route's received router id. This is incorrect. PATCH: Fix bgp_announce_check() function to set the originator-id in the advertising attr structure. Also, fix the attribute hash function and compare function to consider originator-id. Otherwise attributes where all fields except the originator-id are identical get merged into one memory location. Signed-off-by: Pradosh Mohapatra Reviewed-by: Scott Feldman Reviewed-by: Ken Yin [DL: whitespace changes dropped] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 4 +++- bgpd/bgp_route.c | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index feb073c66..a0dfc65df 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -379,6 +379,7 @@ attrhash_key_make (void *p) MIX(extra->aggregator_addr.s_addr); MIX(extra->weight); MIX(extra->mp_nexthop_global_in.s_addr); + MIX(extra->originator_id.s_addr); } if (attr->aspath) @@ -434,7 +435,8 @@ attrhash_cmp (const void *p1, const void *p2) && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) && ae1->ecommunity == ae2->ecommunity && ae1->cluster == ae2->cluster - && ae1->transit == ae2->transit) + && ae1->transit == ae2->transit + && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) return 1; else if (ae1 || ae2) return 0; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7f68b8d0a..0428531f7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -965,6 +965,17 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, attr->local_pref = bgp->default_local_pref; } + /* If originator-id is not set and the route is to be reflected, + set the originator id */ + if (peer && from && peer->sort == BGP_PEER_IBGP && + from->sort == BGP_PEER_IBGP && + (! (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) + { + attr->extra = bgp_attr_extra_get(attr); + IPV4_ADDR_COPY(&(attr->extra->originator_id), &(from->remote_id)); + SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); + } + /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ if (peer->sort == BGP_PEER_EBGP && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) From b366b518401e0b0652cd70d297d3fb67b4803db0 Mon Sep 17 00:00:00 2001 From: Boian Bonev Date: Mon, 9 Sep 2013 16:41:35 +0000 Subject: [PATCH 0351/1342] bgpd: display multipath status in "show ip bgp" The output of "show ip bg" does not show whether and which routes are installed as multipath routes along the best route: BGP table version is 0, local router ID is 10.10.100.209 Status codes: s suppressed, d damped, h history, * valid, > best, i - internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *>i1.0.0.0/24 10.10.100.1 1 111 0 15169 i * i 10.10.100.2 1 111 0 15169 i * i 10.10.100.3 1 111 0 65100 15169 i This patch adds a new status code that is showing exactly which routes are used as multipath: BGP table version is 0, local router ID is 10.10.100.209 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *>i1.0.0.0/24 10.10.100.1 1 111 0 15169 i *=i 10.10.100.2 1 111 0 15169 i * i 10.10.100.3 1 111 0 65100 15169 i The inconsistency in the status code legend ("i - internal" vs. "i internal") inherent from old IOS was fixed. It had to be touched anyways. Signed-off-by: Boian Bonev [DL: rewrap long line, clean whitespace in same chunk] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0428531f7..29533c43e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5651,6 +5651,8 @@ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo) vty_out (vty, "d"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) vty_out (vty, ">"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_MULTIPATH)) + vty_out (vty, "="); else vty_out (vty, " "); @@ -6134,9 +6136,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, #endif /* HAVE_CLOCK_MONOTONIC */ } vty_out (vty, "%s", VTY_NEWLINE); -} - -#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s" +} + +#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\ + "h history, * valid, > best, = multipath,%s"\ + " i internal, r RIB-failure, S Stale, R Removed%s" #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" From 6aa136f1eaeb0dfc1e39e6c2cd6380a399ef126f Mon Sep 17 00:00:00 2001 From: Vitaliy Senchyshyn Date: Wed, 2 Oct 2013 10:40:20 +0000 Subject: [PATCH 0352/1342] bgpd: send notify in OpenSent when stopping manually The issue it fixes is that the notification message is not sent to a second peer when bgp is stopped manually. According to BGP RFC4271, section 8.2.2, regarding the FSM transitions, in OpenSent state: If a ManualStop event (Event 2) is issued in the OpenSent state, the local system: * sends the NOTIFICATION with a Cease, * sets the ConnectRetryTimer to zero, * releases all BGP resources, * drops the TCP connection, * sets the ConnectRetryCounter to zero, and * changes its state to Idle. I've added a check for OpenSent state when the notification is sent from the functions which are called from the CLI commands which directly/indirectly stop/restart BGP. Acked-by: Pradosh Mohapatra Signed-off-by: David Lamparter --- bgpd/bgpd.c | 80 ++++++++++++++++++++++++++++++++--------------------- bgpd/bgpd.h | 2 ++ 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4b26993e7..5e2a5e19f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -175,7 +175,7 @@ bgp_router_id_set (struct bgp *bgp, struct in_addr *id) { IPV4_ADDR_COPY (&peer->local_id, id); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -205,7 +205,7 @@ bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) if (peer->sort != BGP_PEER_IBGP) continue; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -233,7 +233,7 @@ bgp_cluster_id_unset (struct bgp *bgp) if (peer->sort != BGP_PEER_IBGP) continue; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -302,7 +302,7 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as) if (peer_sort (peer) == BGP_PEER_EBGP) { peer->local_as = as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -322,7 +322,7 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as) /* Reset the local_as to be our EBGP one */ if (peer_sort (peer) == BGP_PEER_EBGP) peer->local_as = as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -351,7 +351,7 @@ bgp_confederation_id_unset (struct bgp *bgp) if (peer_sort (peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -415,7 +415,7 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as) if (peer->as == as) { peer->local_as = bgp->as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -471,7 +471,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as) if (peer->as == as) { peer->local_as = bgp->confed_id; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -911,7 +911,7 @@ peer_as_change (struct peer *peer, as_t as) /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -1869,7 +1869,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, peer_group2peer_config_copy (group, peer, afi, safi); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_BIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -1912,7 +1912,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, peer_global_config_reset (peer); } - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_UNBIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2095,10 +2095,28 @@ bgp_delete (struct bgp *bgp) bgp_redistribute_unset (bgp, afi, i); for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) - peer_delete (peer); + { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + { + /* Send notify to remote peer. */ + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); + } + + peer_delete (peer); + } for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) - peer_group_delete (group); + { + for (ALL_LIST_ELEMENTS (group->peer, node, next, peer)) + { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + { + /* Send notify to remote peer. */ + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); + } + } + peer_group_delete (group); + } assert (listcount (bgp->rsclient) == 0); @@ -2406,7 +2424,7 @@ peer_flag_modify_action (struct peer *peer, u_int32_t flag) if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); else @@ -2418,7 +2436,7 @@ peer_flag_modify_action (struct peer *peer, u_int32_t flag) BGP_EVENT_ADD (peer, BGP_Stop); } } - else if (peer->status == Established) + else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; @@ -2821,7 +2839,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2853,7 +2871,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname) peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2890,7 +2908,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2921,7 +2939,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su) peer->update_source = sockunion_dup (su); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2972,7 +2990,7 @@ peer_update_source_unset (struct peer *peer) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3002,7 +3020,7 @@ peer_update_source_unset (struct peer *peer) peer->update_if = NULL; } - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3441,7 +3459,7 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3467,7 +3485,7 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as) else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3498,7 +3516,7 @@ peer_local_as_unset (struct peer *peer) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3517,7 +3535,7 @@ peer_local_as_unset (struct peer *peer) UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3551,8 +3569,8 @@ peer_password_set (struct peer *peer, const char *password) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) - bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); @@ -3569,7 +3587,7 @@ peer_password_set (struct peer *peer, const char *password) peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); @@ -3597,7 +3615,7 @@ peer_password_unset (struct peer *peer) && strcmp (peer->group->conf->password, peer->password) == 0) return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); @@ -3620,7 +3638,7 @@ peer_password_unset (struct peer *peer) if (!peer->password) continue; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); @@ -4543,7 +4561,7 @@ peer_clear (struct peer *peer) } peer->v_start = BGP_INIT_START_TIMER; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_RESET); else diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 024fedcf3..3d516d35a 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -778,6 +778,8 @@ enum bgp_clear_type /* Macros. */ #define BGP_INPUT(P) ((P)->ibuf) #define BGP_INPUT_PNT(P) (STREAM_PNT(BGP_INPUT(P))) +#define BGP_IS_VALID_STATE_FOR_NOTIF(S)\ + (((S) == OpenSent) || ((S) == OpenConfirm) || ((S) == Established)) /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) From 48fc05fb7e6ee44db9f73f3194bfd4738b7f9dc1 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Thu, 9 Jan 2014 00:31:22 +0000 Subject: [PATCH 0353/1342] bgpd: fix O_NONBLOCK on outgoing connects BGP was setting sockets to be non-blocking only for the accepted passive peers. As a fix, setting the BGP sockets to be non-blocking even for the active peers. Signed-off-by: Vipin Kumar Reviewed-by: Pradosh Mohapatra Reviewed-by: Dinesh Dutt [DL: patch split, this is item 1.] Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 79d5d27d0..bcaaba759 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -306,6 +306,8 @@ bgp_connect (struct peer *peer) if (peer->fd < 0) return -1; + set_nonblocking (peer->fd); + /* If we can get socket for the peer, adjest TTL and make connection. */ if (peer->sort == BGP_PEER_EBGP) { sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); From 3374bef0412ac11815779f54321cbc4bf96da909 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Thu, 9 Jan 2014 00:31:22 +0000 Subject: [PATCH 0354/1342] bgpd: increase TCP socket buffer size BGP does not respond fairly in high scale. As the number of BGP peers and prefixes increase, triggers like interface flaps which lead to BGP peer flaps, cause blockage in bgp_write. BGP does handle the cases of TCP socket buffer full by queuing a write event back, there is no functional issue there as such. Still, increasing the peer socket buffer size should help reduce event queueing in BGP. Signed-off-by: Vipin Kumar Reviewed-by: Pradosh Mohapatra Reviewed-by: Dinesh Dutt [DL: patch split, this is item 3.] Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 30 +++++++++++++++++++++++++++++- bgpd/bgp_network.h | 2 ++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index bcaaba759..d86db3c8a 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -122,7 +122,29 @@ bgp_md5_set (struct peer *peer) return ret; } - + +/* Update BGP socket send buffer size */ +static void +bgp_update_sock_send_buffer_size (int fd) +{ + int size = BGP_SOCKET_SNDBUF_SIZE; + int optval; + socklen_t optlen = sizeof(optval); + + if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) + { + zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno)); + return; + } + if (optval < size) + { + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) + { + zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno)); + } + } +} + /* Accept bgp connection. */ static int bgp_accept (struct thread *thread) @@ -153,6 +175,9 @@ bgp_accept (struct thread *thread) } set_nonblocking (bgp_sock); + /* Set socket send buffer size */ + bgp_update_sock_send_buffer_size(bgp_sock); + if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); @@ -308,6 +333,9 @@ bgp_connect (struct peer *peer) set_nonblocking (peer->fd); + /* Set socket send buffer size */ + bgp_update_sock_send_buffer_size(peer->fd); + /* If we can get socket for the peer, adjest TTL and make connection. */ if (peer->sort == BGP_PEER_EBGP) { sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 5bf2e5ff1..127684306 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_NETWORK_H #define _QUAGGA_BGP_NETWORK_H +#define BGP_SOCKET_SNDBUF_SIZE 65536 + extern int bgp_socket (unsigned short, const char *); extern void bgp_close (void); extern int bgp_connect (struct peer *); From 8da8689d91a6436c17aca5000b1426aaea47e23c Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Wed, 11 Sep 2013 03:33:55 +0000 Subject: [PATCH 0355/1342] bgpd: fix fast external fallover behavior ISSUES 1. When an interface goes down, the zclient callbacks are invoked in the following order: (a) address_delete() that removes the connected address list: ifp->connected, (b) interface_down() that performs "fast external fallover" operation. The operation relies on ifp->connected to look for peers that should be brought down. That's a cyclic dependency. 2. 'ttl-security' configuration handler sets peer->ttl to MAXTTL (so that BGP packets are sent with TTL=255, as per the requirement of ttl-security). This, however, is incompatible with 'fast external fallover' as the fallover operation checks for (ttl == 1) to determine directly connected peers. 3. The current fallover operation does not work for IPv6 address family. PATCH 1. The patch removes the dependency on 'ifp->connected' list for fast fallover. The peer already contains a nexthop structure that reflects the peering address. The nexthop structure has a pointer to the interface (ifp) that peering address resolves to. Everytime the TCP connection succeeds, the ifp is updated. The patch uses this ifp in the interface_down() callback for a match for the peers that should be brought down. 2. The evaluation for directly connected peering is enhanced as 'peer->ttl == 1' OR 'peer->gtsm_hops == 1'. Thus a ttl-security configuration on the peer with one hop is directly connected and should be brought down under 'fast external fallover'. 3. Because of fix (1), IPv6 address family works automatically. Signed-off-by: Pradosh Mohapatra Reviewed-by: Dinesh G Dutt Signed-off-by: David Lamparter --- bgpd/bgp_zebra.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 26b97c2c4..0f212321a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -147,12 +147,11 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_delete (c); - /* Fast external-failover (Currently IPv4 only) */ + /* Fast external-failover */ { struct listnode *mnode; struct bgp *bgp; struct peer *peer; - struct interface *peer_if; for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) { @@ -161,15 +160,10 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer->ttl != 1) + if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) continue; - if (peer->su.sa.sa_family == AF_INET) - peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr); - else - continue; - - if (ifp == peer_if) + if (ifp == peer->nexthop.ifp) BGP_EVENT_ADD (peer, BGP_Stop); } } From ef0b0c3e95a1f30d6f338100c689feef8ad5cd6e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 19 May 2014 22:52:04 +0200 Subject: [PATCH 0356/1342] bgpd: factor out TTL setting TTL/min TTL are set from both bgp_accept() and bgp_connect(). Factor them out so the following change to enable iBGP GTSM becomes more readable. [DL: originally by Dinesh G Dutt , split off from the next commit] Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index d86db3c8a..93bb1d9b5 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -145,6 +145,16 @@ bgp_update_sock_send_buffer_size (int fd) } } +static void +bgp_set_socket_ttl (struct peer *peer, int bgp_sock) +{ + if (peer->sort == BGP_PEER_EBGP) { + sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl); + if (peer->gtsm_hops) + sockopt_minttl (peer->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer->gtsm_hops); + } +} + /* Accept bgp connection. */ static int bgp_accept (struct thread *thread) @@ -198,12 +208,7 @@ bgp_accept (struct thread *thread) return -1; } - /* In case of peer is EBGP, we should set TTL for this connection. */ - if (peer1->sort == BGP_PEER_EBGP) { - sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); - if (peer1->gtsm_hops) - sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops); - } + bgp_set_socket_ttl (peer1, bgp_sock); /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) @@ -336,12 +341,7 @@ bgp_connect (struct peer *peer) /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(peer->fd); - /* If we can get socket for the peer, adjest TTL and make connection. */ - if (peer->sort == BGP_PEER_EBGP) { - sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); - if (peer->gtsm_hops) - sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); - } + bgp_set_socket_ttl (peer, peer->fd); sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); From 5f9adb5d26d3af31b00c02084468e9f92b461b01 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 19 May 2014 23:15:02 +0200 Subject: [PATCH 0357/1342] bgpd: factor out eBGP multihop check The check for an eBGP multihop configuration is unwieldy; factor it out into a separate function. [DL: originally by Dinesh G Dutt , split off from the next commit] Signed-off-by: David Lamparter --- bgpd/bgpd.c | 66 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5e2a5e19f..afd0dbd21 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4409,14 +4409,42 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) } return 0; } - + +static int is_ebgp_multihop_configured (struct peer *peer) +{ + struct peer_group *group; + struct listnode *node, *nnode; + struct peer *peer1; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + if (group->conf->ttl != 1) + return 1; + + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) + { + if (peer1->sort == BGP_PEER_IBGP) + continue; + + if (peer1->ttl != 1) + return 1; + } + } + else + { + if (peer->ttl != 1) + return 1; + } + return 0; +} + /* Set # of hops between us and BGP peer. */ int peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) { struct peer_group *group; struct listnode *node, *nnode; - struct peer *peer1; int ret; zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); @@ -4432,32 +4460,16 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) mess of this configuration parameter, and OpenBGPD got it right. */ - if (peer->gtsm_hops == 0) { - if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - group = peer->group; - if (group->conf->ttl != 1) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) - { - if (peer1->sort == BGP_PEER_IBGP) - continue; + if (peer->gtsm_hops == 0) + { + if (is_ebgp_multihop_configured (peer)) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - if (peer1->ttl != 1) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - } - } - else - { - if (peer->ttl != 1) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - } - /* specify MAXTTL on outgoing packets */ - ret = peer_ebgp_multihop_set (peer, MAXTTL); - if (ret != 0) - return ret; - } + /* specify MAXTTL on outgoing packets */ + ret = peer_ebgp_multihop_set (peer, MAXTTL); + if (ret != 0) + return ret; + } peer->gtsm_hops = gtsm_hops; From 5d804b439a4138c77f81de30c64f923e2b5c1340 Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Thu, 12 Sep 2013 03:37:07 +0000 Subject: [PATCH 0358/1342] bgpd: support TTL-security with iBGP Traditionally, ttl-security feature has been associated with EBGP sessions as those identify directly connected external peers. The GTSM RFC (rfc 5082) does not make any restrictions on type of peering. In fact, it is beneficial to support ttl-security for both EBGP and IBGP sessions. Specifically, in data centers, there are directly connected IBGP peerings that will benefit from the protection ttl-security provides. Signed-off-by: Dinesh G Dutt Reviewed-by: Pradosh Mohapatra [DL: function refactoring split out into previous 2 patches. changes: - bgp_set_socket_ttl(): ret type int -> void - is_ebgp_multihop_configured(): stripped peer == NULL check - comments/whitespace] Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 43 ++++++++++++++++++++++++++++++++++++++----- bgpd/bgp_vty.c | 6 ++++++ bgpd/bgpd.c | 31 ++++++++++--------------------- doc/bgpd.texi | 8 ++++++++ 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 93bb1d9b5..6c7cf54c0 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -148,11 +148,44 @@ bgp_update_sock_send_buffer_size (int fd) static void bgp_set_socket_ttl (struct peer *peer, int bgp_sock) { - if (peer->sort == BGP_PEER_EBGP) { - sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl); - if (peer->gtsm_hops) - sockopt_minttl (peer->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer->gtsm_hops); - } + char buf[INET_ADDRSTRLEN]; + int ret; + + /* In case of peer is EBGP, we should set TTL for this connection. */ + if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP)) + { + ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl); + if (ret) + { + zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", + __func__, + inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), + errno); + } + } + else if (peer->gtsm_hops) + { + /* On Linux, setting minttl without setting ttl seems to mess with the + outgoing ttl. Therefore setting both. + */ + ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, MAXTTL); + if (ret) + { + zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", + __func__, + inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), + errno); + } + ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock, + MAXTTL + 1 - peer->gtsm_hops); + if (ret) + { + zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", + __func__, + inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), + errno); + } + } } /* Accept bgp connection. */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bfa1f2044..b4d765afa 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7857,6 +7857,12 @@ bgp_show_peer (struct vty *vty, struct peer *p) vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", p->ttl, VTY_NEWLINE); } + else + { + if (p->gtsm_hops > 0) + vty_out (vty, " Internal BGP neighbor may be up to %d hops away.%s", + p->gtsm_hops, VTY_NEWLINE); + } /* Local address. */ if (p->su_local) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index afd0dbd21..88d13ed8c 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4419,21 +4419,21 @@ static int is_ebgp_multihop_configured (struct peer *peer) if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; - if (group->conf->ttl != 1) + if ((peer_sort(peer) != BGP_PEER_IBGP) && + (group->conf->ttl != 1)) return 1; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { - if (peer1->sort == BGP_PEER_IBGP) - continue; - - if (peer1->ttl != 1) + if ((peer_sort (peer1) != BGP_PEER_IBGP) && + (peer1->ttl != 1)) return 1; } } else { - if (peer->ttl != 1) + if ((peer_sort(peer) != BGP_PEER_IBGP) && + (peer->ttl != 1)) return 1; } return 0; @@ -4449,9 +4449,6 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); - if (peer->sort == BGP_PEER_IBGP) - return BGP_ERR_NO_IBGP_WITH_TTLHACK; - /* We cannot configure ttl-security hops when ebgp-multihop is already set. For non peer-groups, the check is simple. For peer-groups, it's slightly messy, because we need to check both the peer-group structure @@ -4466,6 +4463,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; /* specify MAXTTL on outgoing packets */ + /* Routine handles iBGP peers correctly */ ret = peer_ebgp_multihop_set (peer, MAXTTL); if (ret != 0) return ret; @@ -4475,7 +4473,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) + if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); } else @@ -4483,9 +4481,6 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer->sort == BGP_PEER_IBGP) - continue; - peer->gtsm_hops = group->conf->gtsm_hops; /* Change setting of existing peer @@ -4520,9 +4515,6 @@ peer_ttl_security_hops_unset (struct peer *peer) zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); - if (peer->sort == BGP_PEER_IBGP) - return 0; - /* if a peer-group member, then reset to peer-group default rather than 0 */ if (peer_group_active (peer)) peer->gtsm_hops = peer->group->conf->gtsm_hops; @@ -4532,7 +4524,7 @@ peer_ttl_security_hops_unset (struct peer *peer) opeer = peer; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) + if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } else @@ -4540,9 +4532,6 @@ peer_ttl_security_hops_unset (struct peer *peer) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer->sort == BGP_PEER_IBGP) - continue; - peer->gtsm_hops = 0; if (peer->fd >= 0) @@ -4865,7 +4854,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, VTY_NEWLINE); /* ttl-security hops */ - if (peer->sort != BGP_PEER_IBGP && peer->gtsm_hops != 0) + if (peer->gtsm_hops != 0) if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, peer->gtsm_hops, VTY_NEWLINE); diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 24028d6f9..cb9789bdb 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -366,6 +366,14 @@ Note that replace-as can only be specified if no-prepend is. This command is only allowed for eBGP peers. @end deffn +@deffn {BGP} {neighbor @var{peer} ttl-security hops @var{number}} {} +@deffnx {BGP} {no neighbor @var{peer} ttl-security hops @var{number}} {} +This command enforces Generalized TTL Security Mechanism (GTSM), as +specified in RFC 5082. With this command, only neighbors that are the +specified number of hops away will be allowed to become neighbors. This +command is mututally exclusive with @command{ebgp-multihop}. +@end deffn + @node Peer filtering @subsection Peer filtering From 000e157c852653288c5a1e6d0dee821c1765d315 Mon Sep 17 00:00:00 2001 From: Milan Kocian Date: Fri, 18 Oct 2013 07:59:38 +0000 Subject: [PATCH 0359/1342] bgpd: Fix condition allowas-in in rsclient code Currently when you set neighbour's 'allowas-in' option on route server side you get redistribution of the prefixes from this neighbour's table into all neighbour's tables which have the same AS number. I think that wanted behaviour is to allow import prefixes from neighbour's tables with the same AS num into neighbour which has 'allowas-in' option set. Signed-off-by: Milan Kocian Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 29533c43e..46c0c85f6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1881,7 +1881,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, break; /* AS path loop check. */ - if (aspath_loop_check (attr->aspath, rsclient->as) > peer->allowas_in[afi][safi]) + if (aspath_loop_check (attr->aspath, rsclient->as) > rsclient->allowas_in[afi][safi]) { reason = "as-path contains our own AS;"; goto filtered; From 8e998b1eb5fea53f2a2eddd9f7f2b8ab004406f3 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Fri, 16 May 2014 14:13:43 +0000 Subject: [PATCH 0360/1342] zebra: raise the privileges before calling socket() Because of recent changes when creating AF_NETLINK socket, kernel will cache capabilities of the caller and if file descriptor is used or otherwise handed to another process it will check that current user has necessary capabilities to use the socket. Hence we need to ensure we have necessary capabilities when creating the socket and at the time we use the socket. See: http://www.spinics.net/lists/netdev/msg280198.html Signed-off-by: Michal Sekletar Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ba0b0d7de..6a802f690 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -162,6 +162,12 @@ netlink_socket (struct nlsock *nl, unsigned long groups) int namelen; int save_errno; + if (zserv_privs.change (ZPRIVS_RAISE)) + { + zlog (NULL, LOG_ERR, "Can't raise privileges"); + return -1; + } + sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock < 0) { @@ -175,12 +181,6 @@ netlink_socket (struct nlsock *nl, unsigned long groups) snl.nl_groups = groups; /* Bind the socket to the netlink structure for anything. */ - if (zserv_privs.change (ZPRIVS_RAISE)) - { - zlog (NULL, LOG_ERR, "Can't raise privileges"); - return -1; - } - ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) From 66d2ead7df2db9144605c973fcd80b88df33f81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Luttringer?= Date: Tue, 27 May 2014 19:55:11 +0200 Subject: [PATCH 0361/1342] vtysh: fix build against readline 6.3 readline 6.3 removes some old deprecated funnily-named types. This updates vtysh to use the new types so it builds again. Reported-by: Joel Teichroeb References: https://bugs.archlinux.org/task/39495 Signed-off-by: David Lamparter --- vtysh/vtysh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 34c3bd62a..89b9b257e 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2212,9 +2212,9 @@ void vtysh_readline_init (void) { /* readline related settings. */ - rl_bind_key ('?', (Function *) vtysh_rl_describe); + rl_bind_key ('?', (rl_command_func_t *) vtysh_rl_describe); rl_completion_entry_function = vtysh_completion_entry_function; - rl_attempted_completion_function = (CPPFunction *)new_completion; + rl_attempted_completion_function = (rl_completion_func_t *)new_completion; } char * From 2c13299a05e5544a5e79c2a970256a21f488a3fa Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Sat, 7 Sep 2013 07:07:20 +0000 Subject: [PATCH 0362/1342] bgpd: don't compare next-hop to router-id While announcing a path to a peer, the code currently compares the path's next-hop with the peer's router-id. This can lead to problems as the router IDs are unique only within an AS. Suppose AS 1 sends route with next-hop 10.1.1.1. It is possible that the speaker has an established BGP peering with a router in AS 2 with router ID 10.1.1.1. The route will not be advertised to that peer in AS 2. The patch removes this check. Signed-off-by: Pradosh Mohapatra Reviewed-by: Dinesh G Dutt Reviewed-by: Shrijeet Mukherjee Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 46c0c85f6..a919b54e9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -823,16 +823,6 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, if (from == peer) return 0; - /* If peer's id and route's nexthop are same. draft-ietf-idr-bgp4-23 5.1.3 */ - if (p->family == AF_INET - && IPV4_ADDR_SAME(&peer->remote_id, &riattr->nexthop)) - return 0; -#ifdef HAVE_IPV6 - if (p->family == AF_INET6 - && IPV6_ADDR_SAME(&peer->remote_id, &riattr->nexthop)) - return 0; -#endif - /* Aggregate-address suppress check. */ if (ri->extra && ri->extra->suppress) if (! UNSUPPRESS_MAP_NAME (filter)) From 8c71e481dae11b7ae3f1ef561a989624b2ae84b6 Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Wed, 15 Jan 2014 06:57:57 +0000 Subject: [PATCH 0363/1342] bgpd: efficient NLRI packing for AFs != ipv4-unicast ISSUE: Currently, for non-ipv4-unicast address families where prefixes are encoded in MP_REACH/MP_UNREACH attributes, BGP ends up sending one prefix per UPDATE message. This is quite inefficient. The patch addresses the issue. PATCH: We introduce a scratch buffer in the peer structure that stores the MP_REACH/MP_UNREACH attributes for non-ipv4-unicast families. This enables us to encode multiple prefixes. In the end, the two buffers are merged to create the UPDATE packet. Signed-off-by: Pradosh Mohapatra Reviewed-by: Daniel Walton [DL: removed no longer existing bgp_packet_withdraw prototype] Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 249 ++++++++++++++++++++++++---------------------- bgpd/bgp_attr.h | 32 ++++-- bgpd/bgp_packet.c | 160 ++++++++++++++++++++--------- bgpd/bgpd.c | 5 +- bgpd/bgpd.h | 6 ++ lib/stream.c | 19 ++++ lib/stream.h | 11 ++ 7 files changed, 310 insertions(+), 172 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a0dfc65df..f284758ef 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2058,12 +2058,106 @@ bgp_attr_check (struct peer *peer, struct attr *attr) int stream_put_prefix (struct stream *, struct prefix *); +size_t +bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, + struct attr *attr) +{ + size_t sizep; + + /* Set extended bit always to encode the attribute length as 2 bytes */ + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_MP_REACH_NLRI); + sizep = stream_get_endp (s); + stream_putw (s, 0); /* Marker: Attribute length. */ + stream_putw (s, afi); /* AFI */ + stream_putc (s, safi); /* SAFI */ + + /* Nexthop */ + switch (afi) + { + case AFI_IP: + switch (safi) + { + case SAFI_UNICAST: + case SAFI_MULTICAST: + stream_putc (s, 4); + stream_put_ipv4 (s, attr->nexthop.s_addr); + break; + case SAFI_MPLS_VPN: + stream_putc (s, 12); + stream_putl (s, 0); + stream_putl (s, 0); + stream_put (s, &attr->extra->mp_nexthop_global_in, 4); + break; + default: + break; + } + break; +#ifdef HAVE_IPV6 + case AFI_IP6: + switch (safi) + { + case SAFI_UNICAST: + case SAFI_MULTICAST: + { + unsigned long sizep; + struct attr_extra *attre = attr->extra; + + assert (attr->extra); + stream_putc (s, attre->mp_nexthop_len); + stream_put (s, &attre->mp_nexthop_global, 16); + if (attre->mp_nexthop_len == 32) + stream_put (s, &attre->mp_nexthop_local, 16); + } + default: + break; + } + break; +#endif /*HAVE_IPV6*/ + default: + break; + } + + /* SNPA */ + stream_putc (s, 0); + return sizep; +} + +void +bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, + struct prefix *p, struct prefix_rd *prd, + u_char *tag) +{ + switch (safi) + { + case SAFI_MPLS_VPN: + /* Tag, RD, Prefix write. */ + stream_putc (s, p->prefixlen + 88); + stream_put (s, tag, 3); + stream_put (s, prd->val, 8); + stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); + break; + default: + /* Prefix write. */ + stream_put_prefix (s, p); + break; + } +} + +void +bgp_packet_mpattr_end (struct stream *s, size_t sizep) +{ + /* Set MP attribute length. Don't count the (2) bytes used to encode + the attr length */ + stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2); +} + /* Make attribute packet. */ bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *peer, - struct stream *s, struct attr *attr, struct prefix *p, - afi_t afi, safi_t safi, struct peer *from, - struct prefix_rd *prd, u_char *tag) + struct stream *s, struct attr *attr, + struct prefix *p, afi_t afi, safi_t safi, + struct peer *from, struct prefix_rd *prd, u_char *tag) { size_t cp; size_t aspath_sizep; @@ -2071,6 +2165,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, int send_as4_path = 0; int send_as4_aggregator = 0; int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; + size_t mpattrlen_pos = 0; if (! bgp) bgp = bgp_get_default (); @@ -2078,6 +2173,13 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, /* Remember current pointer. */ cp = stream_get_endp (s); + if (p && !(afi == AFI_IP && safi == SAFI_UNICAST)) + { + mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr); + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag); + bgp_packet_mpattr_end(s, mpattrlen_pos); + } + /* Origin attribute. */ stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_ORIGIN); @@ -2286,96 +2388,6 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } } -#ifdef HAVE_IPV6 - /* If p is IPv6 address put it into attribute. */ - if (p->family == AF_INET6) - { - unsigned long sizep; - struct attr_extra *attre = attr->extra; - - assert (attr->extra); - - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); - stream_putc (s, BGP_ATTR_MP_REACH_NLRI); - sizep = stream_get_endp (s); - stream_putc (s, 0); /* Marker: Attribute length. */ - stream_putw (s, AFI_IP6); /* AFI */ - stream_putc (s, safi); /* SAFI */ - - stream_putc (s, attre->mp_nexthop_len); - - if (attre->mp_nexthop_len == 16) - stream_put (s, &attre->mp_nexthop_global, 16); - else if (attre->mp_nexthop_len == 32) - { - stream_put (s, &attre->mp_nexthop_global, 16); - stream_put (s, &attre->mp_nexthop_local, 16); - } - - /* SNPA */ - stream_putc (s, 0); - - /* Prefix write. */ - stream_put_prefix (s, p); - - /* Set MP attribute length. */ - stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); - } -#endif /* HAVE_IPV6 */ - - if (p->family == AF_INET && safi == SAFI_MULTICAST) - { - unsigned long sizep; - - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); - stream_putc (s, BGP_ATTR_MP_REACH_NLRI); - sizep = stream_get_endp (s); - stream_putc (s, 0); /* Marker: Attribute Length. */ - stream_putw (s, AFI_IP); /* AFI */ - stream_putc (s, SAFI_MULTICAST); /* SAFI */ - - stream_putc (s, 4); - stream_put_ipv4 (s, attr->nexthop.s_addr); - - /* SNPA */ - stream_putc (s, 0); - - /* Prefix write. */ - stream_put_prefix (s, p); - - /* Set MP attribute length. */ - stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); - } - - if (p->family == AF_INET && safi == SAFI_MPLS_VPN) - { - unsigned long sizep; - - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); - stream_putc (s, BGP_ATTR_MP_REACH_NLRI); - sizep = stream_get_endp (s); - stream_putc (s, 0); /* Length of this attribute. */ - stream_putw (s, AFI_IP); /* AFI */ - stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */ - - stream_putc (s, 12); - stream_putl (s, 0); - stream_putl (s, 0); - stream_put (s, &attr->extra->mp_nexthop_global_in, 4); - - /* SNPA */ - stream_putc (s, 0); - - /* Tag, RD, Prefix write. */ - stream_putc (s, p->prefixlen + 88); - stream_put (s, tag, 3); - stream_put (s, prd->val, 8); - stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); - - /* Set MP attribute length. */ - stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); - } - /* Extended Communities attribute. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) @@ -2497,50 +2509,49 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, return stream_get_endp (s) - cp; } -bgp_size_t -bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, - afi_t afi, safi_t safi, struct prefix_rd *prd, - u_char *tag) +size_t +bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi) { - unsigned long cp; unsigned long attrlen_pnt; - bgp_size_t size; - cp = stream_get_endp (s); - - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + /* Set extended bit always to encode the attribute length as 2 bytes */ + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); attrlen_pnt = stream_get_endp (s); - stream_putc (s, 0); /* Length of this attribute. */ + stream_putw (s, 0); /* Length of this attribute. */ - stream_putw (s, family2afi (p->family)); + stream_putw (s, afi); + safi = (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi; + stream_putc (s, safi); + return attrlen_pnt; +} +void +bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, + afi_t afi, safi_t safi, struct prefix_rd *prd, + u_char *tag) +{ if (safi == SAFI_MPLS_VPN) { - /* SAFI */ - stream_putc (s, SAFI_MPLS_LABELED_VPN); - - /* prefix. */ stream_putc (s, p->prefixlen + 88); stream_put (s, tag, 3); stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); } else - { - /* SAFI */ - stream_putc (s, safi); - - /* prefix */ - stream_put_prefix (s, p); - } + stream_put_prefix (s, p); +} - /* Set MP attribute length. */ - size = stream_get_endp (s) - attrlen_pnt - 1; - stream_putc_at (s, attrlen_pnt, size); +void +bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt) +{ + bgp_size_t size; - return stream_get_endp (s) - cp; + /* Set MP attribute length. Don't count the (2) bytes used to encode + the attr length */ + size = stream_get_endp (s) - attrlen_pnt - 2; + stream_putw_at (s, attrlen_pnt, size); } /* Initialization of attribute. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index df87c8631..cdd54674b 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -157,13 +157,11 @@ extern struct attr *bgp_attr_default_intern (u_char); extern struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set); -extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, - struct stream *, struct attr *, - struct prefix *, afi_t, safi_t, - struct peer *, struct prefix_rd *, u_char *); -extern bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, - struct prefix *p, afi_t, safi_t, - struct prefix_rd *, u_char *); +extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, + struct stream *, struct attr *, + struct prefix *, afi_t, safi_t, + struct peer *, struct prefix_rd *, + u_char *); extern void bgp_dump_routes_attr (struct stream *, struct attr *, struct prefix *); extern int attrhash_cmp (const void *, const void *); @@ -194,4 +192,24 @@ extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); +/** + * Set of functions to encode MP_REACH_NLRI and MP_UNREACH_NLRI attributes. + * Typical call sequence is to call _start(), followed by multiple _prefix(), + * one for each NLRI that needs to be encoded into the UPDATE message, and + * finally the _end() function. + */ +extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi, + struct attr *attr); +extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, + struct prefix *p, struct prefix_rd *prd, + u_char *tag); +extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep); + +extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, + safi_t safi); +extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, + afi_t afi, safi_t safi, struct prefix_rd *prd, + u_char *tag); +extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt); + #endif /* _QUAGGA_BGP_ATTR_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d71df0823..d5f24170c 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -142,16 +142,21 @@ static struct stream * bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; + struct stream *snlri; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct stream *packet; struct bgp_node *rn = NULL; struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; - unsigned long pos; + unsigned long attrlen_pos = 0; + size_t mpattrlen_pos = 0; + size_t mpattr_pos = 0; s = peer->work; stream_reset (s); + snlri = peer->scratch; + stream_reset (snlri); adv = FIFO_HEAD (&peer->sync[afi][safi]->update); @@ -164,39 +169,61 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) binfo = adv->binfo; /* When remaining space can't include NLRI and it's length. */ - if (STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) + if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <= + (BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen))) break; /* If packet is empty, set attribute. */ if (stream_empty (s)) { - struct prefix_rd *prd = NULL; - u_char *tag = NULL; struct peer *from = NULL; - - if (rn->prn) - prd = (struct prefix_rd *) &rn->prn->p; + if (binfo) - { - from = binfo->peer; - if (binfo->extra) - tag = binfo->extra->tag; - } - + from = binfo->peer; + + /* 1: Write the BGP message header - 16 bytes marker, 2 bytes length, + * one byte message type. + */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); - stream_putw (s, 0); - pos = stream_get_endp (s); + + /* 2: withdrawn routes length */ + stream_putw (s, 0); + + /* 3: total attributes length - attrlen_pos stores the position */ + attrlen_pos = stream_get_endp (s); stream_putw (s, 0); - total_attr_len = bgp_packet_attribute (NULL, peer, s, + + /* 4: if there is MP_REACH_NLRI attribute, that should be the first + * attribute, according to draft-ietf-idr-error-handling. Save the + * position. + */ + mpattr_pos = stream_get_endp(s); + + /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ + total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, - &rn->p, afi, safi, - from, prd, tag); - stream_putw_at (s, pos, total_attr_len); + NULL, afi, safi, + from, NULL, NULL); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); - + else + { + /* Encode the prefix in MP_REACH_NLRI attribute */ + struct prefix_rd *prd = NULL; + u_char *tag = NULL; + + if (rn->prn) + prd = (struct prefix_rd *) &rn->prn->p; + if (binfo && binfo->extra) + tag = binfo->extra->tag; + + if (stream_empty(snlri)) + mpattrlen_pos = bgp_packet_mpattr_start(snlri, afi, safi, + adv->baa->attr); + bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag); + } if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; @@ -216,18 +243,28 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) adj->attr = bgp_attr_intern (adv->baa->attr); adv = bgp_advertise_clean (peer, adj, afi, safi); - - if (! (afi == AFI_IP && safi == SAFI_UNICAST)) - break; } - + if (! stream_empty (s)) { - bgp_packet_set_size (s); - packet = stream_dup (s); + if (!stream_empty(snlri)) + { + bgp_packet_mpattr_end(snlri, mpattrlen_pos); + total_attr_len += stream_get_endp(snlri); + } + + /* set the total attribute length correctly */ + stream_putw_at (s, attrlen_pos, total_attr_len); + + if (!stream_empty(snlri)) + packet = stream_dupcat(s, snlri, mpattr_pos); + else + packet = stream_dup (s); + bgp_packet_set_size (packet); bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); stream_reset (s); + stream_reset (snlri); return packet; } return NULL; @@ -277,6 +314,15 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) } /* Make BGP withdraw packet. */ +/* For ipv4 unicast: + 16-octet marker | 2-octet length | 1-octet type | + 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0) +*/ +/* For other afi/safis: + 16-octet marker | 2-octet length | 1-octet type | + 2-octet withdrawn route length (=0) | 2-octet attrlen | + mp_unreach attr type | attr len | afi | safi | withdrawn prefixes +*/ static struct stream * bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) { @@ -288,6 +334,10 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) unsigned long pos; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; + size_t mp_start = 0; + size_t attrlen_pos = 0; + size_t mplen_pos = 0; + u_char first_time = 1; s = peer->work; stream_reset (s); @@ -298,31 +348,38 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) adj = adv->adj; rn = adv->rn; - if (STREAM_REMAIN (s) + if (STREAM_REMAIN (s) < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) break; if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); - stream_putw (s, 0); + stream_putw (s, 0); /* unfeasible routes length */ } + else + first_time = 0; if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { struct prefix_rd *prd = NULL; - + if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; - pos = stream_get_endp (s); - stream_putw (s, 0); - total_attr_len - = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL); - - /* Set total path attribute length. */ - stream_putw_at (s, pos, total_attr_len); + + /* If first time, format the MP_UNREACH header */ + if (first_time) + { + attrlen_pos = stream_get_endp (s); + /* total attr length = 0 for now. reevaluate later */ + stream_putw (s, 0); + mp_start = stream_get_endp (s); + mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); + } + + bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL); } if (BGP_DEBUG (update, UPDATE_OUT)) @@ -339,20 +396,26 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) bgp_adj_out_remove (rn, adj, peer, afi, safi); bgp_unlock_node (rn); - - if (! (afi == AFI_IP && safi == SAFI_UNICAST)) - break; } if (! stream_empty (s)) { if (afi == AFI_IP && safi == SAFI_UNICAST) { - unfeasible_len + unfeasible_len = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); stream_putw (s, 0); } + else + { + /* Set the mp_unreach attr's length */ + bgp_packet_mpunreach_end(s, mplen_pos); + + /* Set total path attribute length. */ + total_attr_len = stream_get_endp(s) - mp_start; + stream_putw_at (s, attrlen_pos, total_attr_len); + } bgp_packet_set_size (s); packet = stream_dup (s); bgp_packet_add (peer, packet); @@ -439,10 +502,12 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) struct stream *s; struct stream *packet; struct prefix p; - unsigned long pos; + unsigned long attrlen_pos = 0; unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; + size_t mp_start = 0; + size_t mplen_pos = 0; if (DISABLE_BGP_ANNOUNCE) return; @@ -455,7 +520,6 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) #endif /* HAVE_IPV6 */ total_attr_len = 0; - pos = 0; if (BGP_DEBUG (update, UPDATE_OUT)) { @@ -490,12 +554,18 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) } else { - pos = stream_get_endp (s); + attrlen_pos = stream_get_endp (s); stream_putw (s, 0); - total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); + mp_start = stream_get_endp (s); + mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); + bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL); + + /* Set the mp_unreach attr's length */ + bgp_packet_mpunreach_end(s, mplen_pos); /* Set total path attribute length. */ - stream_putw_at (s, pos, total_attr_len); + total_attr_len = stream_get_endp(s) - mp_start; + stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 88d13ed8c..6a21b11ab 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -832,6 +832,7 @@ peer_new (struct bgp *bgp) peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer->obuf = stream_fifo_new (); peer->work = stream_new (BGP_MAX_PACKET_SIZE); + peer->scratch = stream_new (BGP_MAX_PACKET_SIZE); bgp_sync_init (peer); @@ -1272,8 +1273,10 @@ peer_delete (struct peer *peer) stream_fifo_free (peer->obuf); if (peer->work) stream_free (peer->work); + if (peer->scratch) + stream_free(peer->scratch); peer->obuf = NULL; - peer->work = peer->ibuf = NULL; + peer->work = peer->scratch = peer->ibuf = NULL; /* Local and remote addresses. */ if (peer->su_local) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3d516d35a..688f459f2 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -313,6 +313,12 @@ struct peer struct stream_fifo *obuf; struct stream *work; + /* We use a separate stream to encode MP_REACH_NLRI for efficient + * NLRI packing. peer->work stores all the other attributes. The + * actual packet is then constructed by concatenating the two. + */ + struct stream *scratch; + /* Status of the peer. */ int status; int ostatus; diff --git a/lib/stream.c b/lib/stream.c index ccd4623ff..9a6fcbcf2 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -154,6 +154,25 @@ stream_dup (struct stream *s) return (stream_copy (new, s)); } +struct stream * +stream_dupcat (struct stream *s1, struct stream *s2, size_t offset) +{ + struct stream *new; + + STREAM_VERIFY_SANE (s1); + STREAM_VERIFY_SANE (s2); + + if ( (new = stream_new (s1->endp + s2->endp)) == NULL) + return NULL; + + memcpy (new->data, s1->data, offset); + memcpy (new->data + offset, s2->data, s2->endp); + memcpy (new->data + offset + s2->endp, s1->data + offset, + (s1->endp - offset)); + new->endp = s1->endp + s2->endp; + return new; +} + size_t stream_resize (struct stream *s, size_t newsize) { diff --git a/lib/stream.h b/lib/stream.h index f10aa6d41..f0c742c05 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -122,6 +122,9 @@ struct stream_fifo /* number of bytes still to be read */ #define STREAM_READABLE(S) ((S)->endp - (S)->getp) +#define STREAM_CONCAT_REMAIN(S1, S2, size) \ + ((size) - (S1)->endp - (S2)->endp) + /* deprecated macros - do not use in new code */ #define STREAM_PNT(S) stream_pnt((S)) #define STREAM_DATA(S) ((S)->data) @@ -145,6 +148,14 @@ extern size_t stream_get_endp (struct stream *); extern size_t stream_get_size (struct stream *); extern u_char *stream_get_data (struct stream *); +/** + * Create a new stream structure; copy offset bytes from s1 to the new + * stream; copy s2 data to the new stream; copy rest of s1 data to the + * new stream. + */ +extern struct stream *stream_dupcat(struct stream *s1, struct stream *s2, + size_t offset); + extern void stream_set_getp (struct stream *, size_t); extern void stream_set_endp (struct stream *, size_t); extern void stream_forward_getp (struct stream *, size_t); From d9d4ae5157207b9b8bdb167983519a7ffb860f2c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 13 Jan 2010 00:32:39 +0000 Subject: [PATCH 0364/1342] bgpd: fix crash when allowas-in is done on inactive peer When allowas-in is changed on a peer that is not up, BGP would crash trying to do route_refresh. If peer is not up, there is no need to do notification or send. Signed-off-by: Stephen Hemminger Acked-by: Feng Lu Signed-off-by: David Lamparter --- bgpd/bgpd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6a21b11ab..2fe300c5a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2293,6 +2293,9 @@ peer_change_action (struct peer *peer, afi_t afi, safi_t safi, if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return; + if (peer->status != Established) + return; + if (type == peer_change_reset) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); From 224e7e515747b74dd6d3610570a64b9726a27722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 24 Apr 2014 06:40:33 +0000 Subject: [PATCH 0365/1342] lib: remove redundant and incorrect sys/fcntl.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POSIX defines , is the same thing. However, it should not be used as it's existence can depend on C-library implementation. E.g. musl gives warning if is used. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/zebra.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/zebra.h b/lib/zebra.h index 780e12eb3..3715b342e 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -51,7 +51,6 @@ typedef int socklen_t; #ifdef HAVE_STROPTS_H #include #endif /* HAVE_STROPTS_H */ -#include #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H */ From 7b3b98ae3ecdad20cf5cebd2a6532aee17184d95 Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Mon, 14 Apr 2014 08:09:29 +0000 Subject: [PATCH 0366/1342] ripd & ripngd: avoid the zero interface metric The interface metric is initialized to 0 in the commit db19c85: zebra: set metric for directly connected routes via netlink to 0 Ripd and ripngd must be aware of it and avoid increase the route metric by 0. Signed-off-by: Feng Lu Signed-off-by: David Lamparter --- ripd/ripd.c | 2 +- ripngd/ripngd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index 55a1a75f1..01bd69eca 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -433,7 +433,7 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, /* If offset-list does not modify the metric use interface's metric. */ if (!ret) - rte->metric += ifp->metric; + rte->metric += ifp->metric ? ifp->metric : 1; if (rte->metric > RIP_METRIC_INFINITY) rte->metric = RIP_METRIC_INFINITY; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 8e97c2f8b..318f600ef 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -717,7 +717,7 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, /* If offset-list does not modify the metric use interface's * one. */ if (! ret) - rte->metric += ifp->metric; + rte->metric += ifp->metric ? ifp->metric : 1; if (rte->metric > RIPNG_METRIC_INFINITY) rte->metric = RIPNG_METRIC_INFINITY; From 404fd2974fb53340be6d570b86f2f6f4c0a100c6 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 21 Aug 2013 09:39:33 +0000 Subject: [PATCH 0367/1342] ripd: fix "show ip rip status" documentation The command was mis-named in the documentation as "show ip protocols". Signed-off-by: Joachim Nilsson Signed-off-by: David Lamparter --- doc/ripd.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ripd.texi b/doc/ripd.texi index c6f804af2..78d63eed4 100644 --- a/doc/ripd.texi +++ b/doc/ripd.texi @@ -560,14 +560,14 @@ for routes redistributed into RIP. @c Exmaple here. -@deffn Command {show ip protocols} {} +@deffn Command {show ip rip status} {} The command displays current RIP status. It includes RIP timer, filtering, version, RIP enabled interface and RIP peer inforation. @end deffn @example @group -ripd> @b{show ip protocols} +ripd> @b{show ip rip status} Routing Protocol is "rip" Sending updates every 30 seconds with +/-50%, next due in 35 seconds Timeout after 180 seconds, garbage collect after 120 seconds From fd6f39a514093973bb0fb39484a0ed9615534c89 Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Wed, 19 Feb 2014 09:05:05 +0000 Subject: [PATCH 0368/1342] isisd: ignore the unrecognized TLVs When processing LSPDUs, the unrecognized TLVs/sub-TLVs should be silently ignored. In parse_tlvs(), ISIS_WARNING is returned once an unrecognized TLV exists. It breaks the processing in lsp_authentication_check() and lsp_update_data(). So remove it. Signed-off-by: Feng Lu Signed-off-by: David Lamparter --- isisd/isis_tlv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 2c2415ae0..bbfa5d812 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -742,7 +742,6 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d", areatag, type, length); - retval = ISIS_WARNING; pnt += length; break; } From fdb913aedb5a9807ad60715e8badb4f25d57acea Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Jun 2014 18:42:25 +0200 Subject: [PATCH 0369/1342] build: Quagga 0.99.23-rc1 this is not a full release version, so neither release notes nor documentation are updated yet. Also, signing the tag with my private GPG key instead of the Quagga one. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f9b176350..fa9e6e1f2 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.22, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.23-rc1, [https://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) From 6b0655a25194c7c0331154edaa6124cf783e5e5e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 06:53:35 +0200 Subject: [PATCH 0370/1342] *: nuke ^L (page feed) Quagga sources have inherited a slew of Page Feed (^L, \xC) characters from ancient history. Among other things, these break patchwork's XML-RPC API because \xC is not a valid character in XML documents. Nuke them from high orbit. Patches can be adapted simply by: sed -e 's%^L%%' -i filename.patch (you can type page feeds in some environments with Ctrl-V Ctrl-L) Signed-off-by: David Lamparter --- COPYING | 10 +-- COPYING.LIB | 18 ++--- NEWS | 84 ++++++++++---------- bgpd/bgp_advertise.c | 10 +-- bgpd/bgp_aspath.c | 12 +-- bgpd/bgp_attr.c | 10 +-- bgpd/bgp_clist.c | 8 +- bgpd/bgp_damp.c | 4 +- bgpd/bgp_debug.c | 2 +- bgpd/bgp_dump.c | 8 +- bgpd/bgp_ecommunity.c | 4 +- bgpd/bgp_filter.c | 6 +- bgpd/bgp_fsm.c | 4 +- bgpd/bgp_main.c | 4 +- bgpd/bgp_network.c | 2 +- bgpd/bgp_nexthop.c | 12 +-- bgpd/bgp_packet.c | 6 +- bgpd/bgp_route.c | 68 ++++++++-------- bgpd/bgp_routemap.c | 68 ++++++++-------- bgpd/bgp_snmp.c | 8 +- bgpd/bgp_vty.c | 168 +++++++++++++++++++-------------------- bgpd/bgp_zebra.c | 8 +- bgpd/bgpd.c | 74 ++++++++--------- bgpd/bgpd.h | 2 +- doc/mpls/opaque_lsa.txt | 8 +- lib/command.c | 2 +- lib/distribute.c | 4 +- lib/filter.c | 6 +- lib/getopt.c | 10 +-- lib/getopt1.c | 4 +- lib/if.c | 10 +-- lib/if_rmap.c | 6 +- lib/keychain.c | 8 +- lib/linklist.c | 8 +- lib/log.c | 8 +- lib/memory.c | 10 +-- lib/plist.c | 10 +-- lib/prefix.c | 6 +- lib/privs.c | 10 +-- lib/regex-gnu.h | 12 +-- lib/regex.c | 46 +++++------ lib/routemap.c | 8 +- lib/smux.c | 10 +-- lib/stream.c | 10 +-- lib/table.c | 2 +- lib/thread.c | 12 +-- lib/vty.c | 10 +-- lib/zclient.c | 8 +- ospf6d/ospf6_abr.c | 2 +- ospf6d/ospf6_area.c | 2 +- ospf6d/ospf6_asbr.c | 8 +- ospf6d/ospf6_interface.c | 6 +- ospf6d/ospf6_interface.h | 2 +- ospf6d/ospf6_intra.h | 2 +- ospf6d/ospf6_lsa.c | 6 +- ospf6d/ospf6_lsa.h | 2 +- ospf6d/ospf6_message.c | 4 +- ospf6d/ospf6_neighbor.c | 2 +- ospf6d/ospf6_neighbor.h | 2 +- ospf6d/ospf6_network.h | 2 +- ospf6d/ospf6_route.c | 2 +- ospf6d/ospf6_zebra.c | 4 +- ospf6d/ospf6d.c | 2 +- ospf6d/ospf6d.h | 2 +- ospfclient/COPYING | 10 +-- ospfd/ospf_abr.c | 2 +- ospfd/ospf_asbr.c | 6 +- ospfd/ospf_dump.c | 18 ++--- ospfd/ospf_flood.c | 8 +- ospfd/ospf_ia.c | 2 +- ospfd/ospf_interface.c | 12 +-- ospfd/ospf_ism.c | 4 +- ospfd/ospf_lsa.c | 34 ++++---- ospfd/ospf_lsdb.c | 2 +- ospfd/ospf_main.c | 4 +- ospfd/ospf_nsm.c | 6 +- ospfd/ospf_packet.c | 6 +- ospfd/ospf_snmp.c | 20 ++--- ospfd/ospf_spf.c | 12 +-- ospfd/ospf_vty.c | 50 ++++++------ ospfd/ospf_zebra.c | 2 +- ospfd/ospfd.c | 20 ++--- ripd/rip_debug.c | 2 +- ripd/rip_interface.c | 16 ++-- ripd/rip_main.c | 4 +- ripd/rip_peer.c | 2 +- ripd/rip_routemap.c | 14 ++-- ripd/rip_snmp.c | 6 +- ripd/rip_zebra.c | 8 +- ripd/ripd.c | 20 ++--- ripngd/ripng_debug.c | 2 +- ripngd/ripng_interface.c | 10 +-- ripngd/ripng_main.c | 4 +- ripngd/ripng_peer.c | 2 +- ripngd/ripng_routemap.c | 12 +-- ripngd/ripng_zebra.c | 4 +- ripngd/ripngd.c | 8 +- tests/main.c | 4 +- tests/test-checksum.c | 4 +- tests/test-privs.c | 2 +- zebra/connected.c | 4 +- zebra/if_proc.c | 2 +- zebra/interface.c | 2 +- zebra/irdp_packet.c | 6 +- zebra/kernel_socket.c | 8 +- zebra/main.c | 4 +- zebra/rt_ioctl.c | 2 +- zebra/rt_netlink.c | 2 +- zebra/rtadv.c | 6 +- zebra/test_main.c | 6 +- zebra/zebra_rib.c | 20 ++--- zebra/zebra_routemap.c | 10 +-- zebra/zebra_snmp.c | 6 +- zebra/zebra_vty.c | 2 +- zebra/zserv.c | 16 ++-- 115 files changed, 658 insertions(+), 658 deletions(-) diff --git a/COPYING b/COPYING index a43ea2126..b8cf3a1ab 100644 --- a/COPYING +++ b/COPYING @@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest diff --git a/COPYING.LIB b/COPYING.LIB index 161a3d1d4..2b4628e4a 100644 --- a/COPYING.LIB +++ b/COPYING.LIB @@ -51,7 +51,7 @@ library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. - + Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect @@ -98,7 +98,7 @@ works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. - + GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -145,7 +145,7 @@ Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - + 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 @@ -203,7 +203,7 @@ instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - + Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. @@ -254,7 +254,7 @@ Library will still fall under Section 6.) distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - + 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work @@ -308,7 +308,7 @@ restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - + 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined @@ -349,7 +349,7 @@ subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. - + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or @@ -401,7 +401,7 @@ conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - + 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is @@ -435,7 +435,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest diff --git a/NEWS b/NEWS index 59e237d67..d1529bc4d 100644 --- a/NEWS +++ b/NEWS @@ -198,7 +198,7 @@ which the PtP patch introduced. * Chages in ospf6d ** Many bugs are fixed. - + * Changes in zebra-0.92a * Changes in bgpd @@ -215,7 +215,7 @@ which the PtP patch introduced. * Changes in zebra ** Treat kernel type routes as EGP routes. - + * Changes in zebra-0.92 ** Overall security is improved. Default umask is 0077. @@ -272,7 +272,7 @@ router bgp 7675 multiple IP address for an interface. ** Redistribution of loopback interface's address works fine. - + * Changes in zebra-0.91 ** --enable-oldrib configure option is removed. @@ -324,7 +324,7 @@ only supported on GNU/Linux with netlink interface. ** Fix bug of LSA MaxAge flood. ** Fix bug of NSSA codes. - + * Changes in zebra-0.90 ** From this beta release, --enable-unixdomain and --enable-newrib @@ -660,7 +660,7 @@ zebrastart.sh /usr/local/sbin/ospfd -d /usr/local/sbin/bgpd -d /usr/local/bin/vtysh -b - + * Changes in zebra-0.89 * Changes in lib @@ -754,7 +754,7 @@ value. it is available. ** Reflect IPv6 interface's address change to protocol daemons. - + * Changes in zebra-0.88 * Changes in lib @@ -875,7 +875,7 @@ generating MRT compatible dump output. * Changes in vtysh ** VTY shell is now included into the distribution. - + * Changes in zebra-0.87 * Changes in lib @@ -968,7 +968,7 @@ bgp ASN. * Changes in zebra ** Better interface up/down event handle. - + * Changes in zebra-0.86 * Changes in lib @@ -1052,7 +1052,7 @@ fixed. ** Remove client structure when client dies. ** Take care static route when interface goes up/down. - + * Changes in zebra-0.85 * Changes in bgpd @@ -1075,7 +1075,7 @@ drastically improved. * Changes in ripd ** RIPv1 update is done by class-full manner. - + * Changes in zebra-0.84b * Changes in lib @@ -1094,14 +1094,14 @@ consume only one screen size memory. ** Fix debug output string. ** Add RIP peer handling. RIP peer are shown by "show ip protocols". - + * Changes in zebra-0.84a * Changes in bgpd ** Fix serious bug of BGP-4+ peering under IPv6 link-local address. Due to the bug BGP-4+ peering may not be established. - + * Changes in zebra-0.84 * Changes in lib @@ -1180,7 +1180,7 @@ consume only one screen size memory. this command, you have to configure neighbor with "neighbor A.B.C.D soft-reconfiguration inbound" beforehand. - + * Changes in zebra-0.83 * bgpd @@ -1192,7 +1192,7 @@ introduced in zebra-0.82. ** When bgpd send Notify message, don't use thread manager. It is now send to neighbor immediately. - + * Changes in zebra-0.82 ** Solaris 2.6 support is added by Michael Handler @@ -1243,7 +1243,7 @@ draft-ietf-idr-bgp4-cap-neg-04.txt. * Changes in ospf6d ** Many debug feature is added. - + * Changes in zebra-0.81 ** SNMP support is disabled in default.--enable-snmp option is added @@ -1252,7 +1252,7 @@ to configure script. * Changes in bgpd ** Fix FSM bug which introduced in zebra-0.80. - + * Changes in zebra-0.80 * access-list @@ -1515,7 +1515,7 @@ to configure script. From zebra-0.80, ripd will reload it's configuration file when ripd receives HUP signal. Other daemon such as bgpd, ospfd will support HUP signal treatment soon. - + * Changes in zebra-0.79 * Changes in zebra @@ -1551,7 +1551,7 @@ not work for NetBSD-currnet on SparcStation 10. * Changes in ospf6d ** Enclosed KAME specific part with #ifdef #endif - + * Changes in zebra-0.78 * Changes in lib @@ -1596,7 +1596,7 @@ RIP_METRIC_INFINITY with network byte order using htonl (). * Changes in ospf6d ** `ip6' statement in configuration is changed to `ipv6'. - + * Changes in zebra-0.77 * Changes in lib @@ -1667,7 +1667,7 @@ timeout, garbage timer. * Changes in ospf6d ** Redistribute route works. - + * Changes in zebra-0.76 * Changes in lib @@ -1677,7 +1677,7 @@ timeout, garbage timer. ** Include SERVICES file to the distribution ** Update zebra.texi to zebra-0.76. - + * Changes in zebra-0.75 * Changes in lib @@ -1724,7 +1724,7 @@ used when `next-hop-self'. ** Never include a neighbor in Hello packet, when the neighbor goes down. - + * Changes in zebra-0.74 * Changes in lib @@ -1785,7 +1785,7 @@ router. ** LSA data structure is changed. ** Call of log_rotate() is removed. - + * Changes in zebra-0.73 * Changes in lib @@ -1847,7 +1847,7 @@ DEFAULT_LOCAL_PREF(100). ** Clean up logging message. ** Reflect routing information to zebra daemon. - + * Changes in zebra-0.72 * Changes in lib @@ -1868,7 +1868,7 @@ set ipv6 nexthop local -> set ipv6 next-hop local * Changes in ospfd ** Fix bug of multiple `network area' directive crashes. - + * Changes in zebra-0.71 * Changes in lib @@ -1919,7 +1919,7 @@ NOTIFY Malformed AS path is send to the peer. * Chanegs in ospf6d ** Routing table code is rewritten. - + * Changes in zebra-0.70 * Changes in zebra @@ -1940,7 +1940,7 @@ nexthop is calculated by looking up IGP routing table. * Changes in ospfd ** DD null pointer bug is fixed. - + * Changes in zebra-0.69 * Changes in zebra @@ -1990,7 +1990,7 @@ peer. * Changes in ospfd ** LS request and LS update can be send and received. - + * Changes in zebra-0.68 * Changes in lib @@ -2023,7 +2023,7 @@ summary-only mode. * Changes in ospf6d ** router zebra related bug is fixed. - + * Changes in zebra-0.67 * Changes in lib @@ -2065,7 +2065,7 @@ it is fixed. * Changes in ospf6d ** `router zebra' is default behavior. - + * Changes in zebra-0.66 * Changes in zebra @@ -2109,7 +2109,7 @@ routes to the kernel, please configure like below: router zebra no redistribute ripng ! - + * Changes in zebra-0.65 * Changes in lib @@ -2161,7 +2161,7 @@ zebra. * Changes in ospf6d ** Bug fix about network vertex. - + * Changes in zebra-0.64.1. This is bug fix release. @@ -2199,7 +2199,7 @@ not work with previous version, sorry. ** Fix bug of no network IPV6_NETWORK. ** Important bug fix about intra-area-prefix-lsa. - + * Changes in zebra-0.64. * Changes in lib @@ -2238,7 +2238,7 @@ Barcenilla. ** There are many changes. If you have interested in ospf6d please visit ospf6d/README file. - + * Changes in zebra-0.63 first beta package. * Changes in lib @@ -2257,7 +2257,7 @@ visit ospf6d/README file. * Changes in ospf6d ** Now ospf6d can be compiled on both Linux and *BSD system. - + * Changes in zebra-19990420 snapshot ** `make dist' at top directory works now. @@ -2300,7 +2300,7 @@ router bgp ASN ** configure --enable-guile turns on zebra-guile build. ** (router-bgp ASN) allocates real bgp structre. - + * Changes in zebra-19990416 snapshot ** Set version to 0.60 for preparation of beta release. @@ -2331,7 +2331,7 @@ Bligh . * Changes in ospfd ** DR and BDR information is shown by `show ip ospf interface' command. - + * Changes in zebra-19990408 snapshot * Changes in bgpd @@ -2358,7 +2358,7 @@ kad@gibson.skif.net. ** With KAME stack, terminal interface is now bind AF_INET socket instead of AF_INET6 one. - + * Changes in zebra-19990403 snapshot * Changes in bgpd @@ -2377,7 +2377,7 @@ segment. This change is for announcement to gated under iBGP. ** Yasuhiro Ohara's ospf6d codes is imported. It is under development and can't be compiled on any platform. - + * Changes in zebra-19990327 snapshot * Changes in bgpd @@ -2422,7 +2422,7 @@ buffer when the address family is not supported and the length is big * Changes in ospfd ** Now ospfd receive OSPF packet. - + * Changes in zebra-19990319 snapshot * Changes in configuration and libraries @@ -2513,8 +2513,8 @@ several files are included in ospfd directory. ** ospf6d codes are merged from Yasuhiro Ohara 's ospfd work. Now codes are located in ospf6d directory. - + Local variables: mode: outline -paragraph-separate: "[ ]*$" +paragraph-separate: "[ ]*$" end: diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 666218fa8..e0fa58d46 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -35,7 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_packet.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_mplsvpn.h" - + /* BGP advertise attribute is used for pack same attribute update into one packet. To do that we maintain attribute hash in struct peer. */ @@ -79,7 +79,7 @@ baa_hash_cmp (const void *p1, const void *p2) return attrhash_cmp (baa1->attr, baa2->attr); } - + /* BGP update and withdraw information is stored in BGP advertise structure. This structure is referred from BGP adjacency information. */ @@ -151,7 +151,7 @@ bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) baa_free (baa); } } - + /* BGP adjacency keeps minimal advertisement information. */ static void bgp_adj_out_free (struct bgp_adj_out *adj) @@ -327,7 +327,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, BGP_ADJ_OUT_DEL (rn, adj); bgp_adj_out_free (adj); } - + void bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) { @@ -376,7 +376,7 @@ bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); } - + void bgp_sync_init (struct peer *peer) { diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index a8b078ff3..e8559bea6 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -34,7 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" - + /* Attr. Flags and Attr. Type Code. */ #define AS_HEADER_SIZE 2 @@ -90,7 +90,7 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; - + /* Callers are required to initialize the memory */ static as_t * assegment_data_new (int num) @@ -308,7 +308,7 @@ assegment_normalise (struct assegment *head) } return head; } - + static struct aspath * aspath_new (void) { @@ -1657,7 +1657,7 @@ aspath_count (void) { return ashash->count; } - + /* Theoretically, one as path can have: @@ -1811,7 +1811,7 @@ aspath_str2aspath (const char *str) return aspath; } - + /* Make hash value by raw aspath data. */ unsigned int aspath_key_make (void *p) @@ -1868,7 +1868,7 @@ aspath_finish (void) if (snmp_stream) stream_free (snmp_stream); } - + /* return and as path value */ const char * aspath_print (struct aspath *as) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f284758ef..a1fd16545 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -38,7 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" - + /* Attribute strings for logging. */ static const struct message attr_str [] = { @@ -73,7 +73,7 @@ static const struct message attr_flag_str[] = { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, }; static const size_t attr_flag_str_max = array_size(attr_flag_str); - + static struct hash *cluster_hash; static void * @@ -207,7 +207,7 @@ cluster_finish (void) hash_free (cluster_hash); cluster_hash = NULL; } - + /* Unknown transit attribute. */ static struct hash *transit_hash; @@ -283,7 +283,7 @@ transit_finish (void) hash_free (transit_hash); transit_hash = NULL; } - + /* Attribute hash routines. */ static struct hash *attrhash; @@ -2055,7 +2055,7 @@ bgp_attr_check (struct peer *peer, struct attr *attr) } return BGP_ATTR_PARSE_PROCEED; } - + int stream_put_prefix (struct stream *, struct prefix *); size_t diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 6c9976e3b..b91ab81fa 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -30,7 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" - + /* Lookup master structure for community-list or extcommunity-list. */ struct community_list_master * @@ -262,7 +262,7 @@ community_list_empty_p (struct community_list *list) { return (list->head == NULL && list->tail == NULL) ? 1 : 0; } - + /* Add community-list entry to the list. */ static void community_list_entry_add (struct community_list *list, @@ -329,7 +329,7 @@ community_list_entry_lookup (struct community_list *list, const void *arg, } return NULL; } - + /* Internal function to perform regular expression match for community attribute. */ static int @@ -590,7 +590,7 @@ community_list_dup_check (struct community_list *list, } return 0; } - + /* Set community-list. */ int community_list_set (struct community_list_handler *ch, diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 2820f17c7..0ffafb7a0 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -42,7 +42,7 @@ static struct bgp_damp_config *damp = &bgp_damp_cfg; used list. */ #define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list) #define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list) - + /* Calculate reuse list index by penalty value. */ static int bgp_reuse_index (int penalty) @@ -86,7 +86,7 @@ bgp_reuse_list_delete (struct bgp_damp_info *bdi) else damp->reuse_list[bdi->index] = bdi->next; } - + /* Return decayed penalty value. */ int bgp_damp_decay (time_t tdiff, int penalty) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 726dd862b..1d0976977 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -290,7 +290,7 @@ bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, code_str, subcode_str, bgp_notify->length, bgp_notify->data ? bgp_notify->data : ""); } - + /* Debug option setting interface. */ unsigned long bgp_debug_option = 0; diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index edb725a97..a3c9526fd 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -33,7 +33,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_dump.h" - + enum bgp_dump_type { BGP_DUMP_ALL, @@ -89,7 +89,7 @@ struct bgp_dump bgp_dump_routes; /* Dump whole BGP table is very heavy process. */ struct thread *t_bgp_dump_routes; - + /* Some define for BGP packet dump. */ static FILE * bgp_dump_open_file (struct bgp_dump *bgp_dump) @@ -535,7 +535,7 @@ bgp_dump_packet (struct peer *peer, int type, struct stream *packet) if (type == BGP_MSG_UPDATE) bgp_dump_packet_func (&bgp_dump_updates, peer, packet); } - + static unsigned int bgp_dump_parse_time (const char *str) { @@ -845,7 +845,7 @@ config_write_bgp_dump (struct vty *vty) } return 0; } - + /* Initialize BGP packet dump functionality. */ void bgp_dump_init (void) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 5722425e1..8a326a8bb 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -31,7 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Hash of community attribute. */ static struct hash *ecomhash; - + /* Allocate a new ecommunities. */ static struct ecommunity * ecommunity_new (void) @@ -277,7 +277,7 @@ ecommunity_finish (void) hash_free (ecomhash); ecomhash = NULL; } - + /* Extended Communities token enum. */ enum ecommunity_token { diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 8ee62b013..fd8ece659 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -84,7 +84,7 @@ struct as_list struct as_filter *head; struct as_filter *tail; }; - + /* ip as-path access-list 10 permit AS1. */ static struct as_list_master as_list_master = @@ -370,7 +370,7 @@ as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter) if (as_list_master.delete_hook) (*as_list_master.delete_hook) (); } - + static int as_filter_match (struct as_filter *asfilter, struct aspath *aspath) { @@ -412,7 +412,7 @@ as_list_delete_hook (void (*func) (void)) { as_list_master.delete_hook = func; } - + static int as_list_dup_check (struct as_list *aslist, struct as_filter *new) { diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index fba942769..112c34a19 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -43,7 +43,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ - + /* BGP FSM (finite state machine) has three types of functions. Type one is thread functions. Type two is event functions. Type three is FSM functions. Timer functions are set by bgp_timer_set @@ -928,7 +928,7 @@ bgp_ignore (struct peer *peer) zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host); return 0; } - + /* Finite State Machine structure */ static const struct { int (*func) (struct peer *); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1be65043b..5026b5eaa 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -171,7 +171,7 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); exit (status); } - + /* SIGHUP handler. */ void sighup (void) @@ -314,7 +314,7 @@ bgp_exit (int status) exit (status); } - + /* Main routine of bgpd. Treatment of argument and start bgp finite state machine is handled at here. */ int diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 6c7cf54c0..c0527447a 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -47,7 +47,7 @@ struct bgp_listener union sockunion su; struct thread *thread; }; - + /* * Set MD5 key for the socket, for the given IPv4 peer address. * If the password is NULL or zero-length, the option will be disabled. diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index e23155c7e..5b1d13ac8 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -45,7 +45,7 @@ struct bgp_nexthop_cache *zlookup_query (struct in_addr); #ifdef HAVE_IPV6 struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); #endif /* HAVE_IPV6 */ - + /* Only one BGP scan thread are activated at the same time. */ static struct thread *bgp_scan_thread = NULL; @@ -68,7 +68,7 @@ static struct bgp_table *bgp_connected_table[AFI_MAX]; /* BGP nexthop lookup query client. */ struct zclient *zlookup = NULL; - + /* Add nexthop to the end of the list. */ static void bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) @@ -109,7 +109,7 @@ bnc_free (struct bgp_nexthop_cache *bnc) bnc_nexthop_free (bnc); XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } - + static int bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) { @@ -623,7 +623,7 @@ bgp_address_del (struct prefix *p) } } - + struct bgp_connected_ref { unsigned int refcnt; @@ -781,7 +781,7 @@ bgp_nexthop_self (struct attr *attr) return 0; } - + static struct bgp_nexthop_cache * zlookup_read (void) { @@ -1243,7 +1243,7 @@ bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) return 0; } - + DEFUN (bgp_scan_time, bgp_scan_time_cmd, "bgp scan-time <5-60>", diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d5f24170c..80651f155 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -49,7 +49,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_vty.h" int stream_put_prefix (struct stream *, struct prefix *); - + /* Set up BGP packet marker and packet type. */ static int bgp_packet_set_marker (struct stream *s, u_char type) @@ -1166,7 +1166,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } - + /* RFC1771 6.8 Connection collision detection. */ static int bgp_collision_detect (struct peer *new, struct in_addr remote_id) @@ -2381,7 +2381,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size) /* Parse packet. */ return bgp_capability_msg_parse (peer, pnt, size); } - + /* BGP read utility function. */ static int bgp_read_packet (struct peer *peer) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a919b54e9..f421ca5eb 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -59,7 +59,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; - + static struct bgp_node * bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd) @@ -89,7 +89,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix return rn; } - + /* Allocate bgp_info_extra */ static struct bgp_info_extra * bgp_info_extra_new (void) @@ -683,7 +683,7 @@ bgp_cluster_filter (struct peer *peer, struct attr *attr) } return 0; } - + static int bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) @@ -721,7 +721,7 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, } return RMAP_PERMIT; } - + static int bgp_export_modifier (struct peer *rsclient, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) @@ -793,7 +793,7 @@ bgp_import_modifier (struct peer *rsclient, struct peer *peer, } return RMAP_PERMIT; } - + static int bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) @@ -2468,7 +2468,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, return 0; } - + void bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) { @@ -2571,7 +2571,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) bgp_attr_extra_free (&attr); aspath_unintern (&aspath); } - + static void bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, int rsclient) @@ -2642,7 +2642,7 @@ bgp_announce_route_all (struct peer *peer) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) bgp_announce_route (peer, afi, safi); } - + static void bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd) @@ -2686,7 +2686,7 @@ bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table, &prd); } } - + static void bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd) @@ -2744,7 +2744,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) bgp_soft_reconfig_table (peer, afi, safi, table, &prd); } } - + struct bgp_clear_node_queue { @@ -3038,7 +3038,7 @@ bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi) } } } - + /* Delete all kernel routes. */ void bgp_cleanup_routes (void) @@ -3079,7 +3079,7 @@ bgp_reset (void) access_list_reset (); prefix_list_reset (); } - + /* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr value. */ int @@ -3242,7 +3242,7 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, } return 0; } - + static struct bgp_static * bgp_static_new (void) { @@ -4009,7 +4009,7 @@ bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str, return CMD_SUCCESS; } - + DEFUN (bgp_network, bgp_network_cmd, "network A.B.C.D/M", @@ -4467,7 +4467,7 @@ ALIAS_DEPRECATED (no_ipv6_bgp_network, "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") #endif /* HAVE_IPV6 */ - + /* Aggreagete address: advertise-map Set condition to advertise attribute @@ -5378,7 +5378,7 @@ ALIAS (no_ipv6_aggregate_address_summary_only, "Aggregate prefix\n" "Filter more specific routes from updates\n") #endif /* HAVE_IPV6 */ - + /* Redistribute route treatment. */ void bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, @@ -5578,7 +5578,7 @@ bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type) } } } - + /* Static function to display route. */ static void route_vty_out_route (struct prefix *p, struct vty *vty) @@ -7103,7 +7103,7 @@ DEFUN (show_ipv6_mbgp_prefix, return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); } #endif - + static int bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi, @@ -7247,7 +7247,7 @@ DEFUN (show_ipv6_mbgp_regexp, bgp_show_type_regexp); } #endif /* HAVE_IPV6 */ - + static int bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -7362,7 +7362,7 @@ DEFUN (show_ipv6_mbgp_prefix_list, bgp_show_type_prefix_list); } #endif /* HAVE_IPV6 */ - + static int bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -7476,7 +7476,7 @@ DEFUN (show_ipv6_mbgp_filter_list, bgp_show_type_filter_list); } #endif /* HAVE_IPV6 */ - + static int bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -7561,7 +7561,7 @@ ALIAS (show_bgp_route_map, "Address family\n" "Display routes matching the route-map\n" "A route-map to match on\n") - + DEFUN (show_ip_bgp_cidr_only, show_ip_bgp_cidr_only_cmd, "show ip bgp cidr-only", @@ -7605,7 +7605,7 @@ DEFUN (show_ip_bgp_ipv4_cidr_only, return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } - + DEFUN (show_ip_bgp_community_all, show_ip_bgp_community_all_cmd, "show ip bgp community", @@ -7683,7 +7683,7 @@ DEFUN (show_ipv6_mbgp_community_all, bgp_show_type_community_all, NULL); } #endif /* HAVE_IPV6 */ - + static int bgp_show_community (struct vty *vty, const char *view_name, int argc, const char **argv, int exact, afi_t afi, safi_t safi) @@ -8875,7 +8875,7 @@ ALIAS (show_ipv6_mbgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") #endif /* HAVE_IPV6 */ - + static int bgp_show_community_list (struct vty *vty, const char *com, int exact, afi_t afi, safi_t safi) @@ -9062,7 +9062,7 @@ DEFUN (show_ipv6_mbgp_community_list_exact, return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ - + static int bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -9254,7 +9254,7 @@ peer_lookup_in_view (struct vty *vty, const char *view_name, return peer; } - + enum bgp_stats { BGP_STATS_MAXBITLEN = 0, @@ -9602,7 +9602,7 @@ ALIAS (show_bgp_statistics_view, "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") - + enum bgp_pcounts { PCOUNT_ADJ_IN = 0, @@ -10142,7 +10142,7 @@ DEFUN (ipv6_mbgp_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0); } #endif /* HAVE_IPV6 */ - + DEFUN (show_ip_bgp_view_neighbor_received_routes, show_ip_bgp_view_neighbor_received_routes_cmd, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", @@ -10519,7 +10519,7 @@ ALIAS (show_bgp_view_neighbor_received_prefix_filter, "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") #endif /* HAVE_IPV6 */ - + static int bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -11671,7 +11671,7 @@ ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix, "IP prefix /, e.g., 3ffe::/16\n") #endif /* HAVE_IPV6 */ - + struct bgp_table *bgp_distance_table; struct bgp_distance @@ -11948,7 +11948,7 @@ DEFUN (no_bgp_distance_source_access_list, bgp_distance_unset (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } - + DEFUN (bgp_damp_set, bgp_damp_set_cmd, "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", @@ -12043,7 +12043,7 @@ DEFUN (show_ip_bgp_flap_statistics, return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_statistics, NULL); } - + /* Display specified route of BGP table. */ static int bgp_clear_damp_route (struct vty *vty, const char *view_name, @@ -12207,7 +12207,7 @@ DEFUN (clear_ip_bgp_dampening_address_mask, return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 0); } - + static int bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 40f207653..6dc88b3aa 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -100,7 +100,7 @@ o Local extention set as-path exclude : Done */ - + /* 'match peer (A.B.C.D|X:X::X:X)' */ /* Compares the peer specified in the 'match peer' clause with the peer @@ -240,7 +240,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = route_match_ip_address_compile, route_match_ip_address_free }; - + /* `match ip next-hop IP_ADDRESS' */ /* Match function return 1 if match is success else return zero. */ @@ -292,7 +292,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; - + /* `match ip route-source ACCESS-LIST' */ /* Match function return 1 if match is success else return zero. */ @@ -350,7 +350,7 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = route_match_ip_route_source_compile, route_match_ip_route_source_free }; - + /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t @@ -390,7 +390,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; - + /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t @@ -437,7 +437,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; - + /* `match ip route-source prefix-list PREFIX_LIST' */ static route_map_result_t @@ -490,7 +490,7 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = route_match_ip_route_source_prefix_list_compile, route_match_ip_route_source_prefix_list_free }; - + /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ @@ -555,7 +555,7 @@ struct route_map_rule_cmd route_match_metric_cmd = route_match_metric_compile, route_match_metric_free }; - + /* `match as-path ASPATH' */ /* Match function for as-path match. I assume given object is */ @@ -603,7 +603,7 @@ struct route_map_rule_cmd route_match_aspath_cmd = route_match_aspath_compile, route_match_aspath_free }; - + /* `match community COMMUNIY' */ struct rmap_community { @@ -687,7 +687,7 @@ struct route_map_rule_cmd route_match_community_cmd = route_match_community_compile, route_match_community_free }; - + /* Match function for extcommunity match. */ static route_map_result_t route_match_ecommunity (void *rule, struct prefix *prefix, @@ -736,10 +736,10 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = route_match_ecommunity_compile, route_match_ecommunity_free }; - + /* `match nlri` and `set nlri` are replaced by `address-family ipv4` and `address-family vpnv4'. */ - + /* `match origin' */ static route_map_result_t route_match_origin (void *rule, struct prefix *prefix, @@ -964,7 +964,7 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = route_set_ip_nexthop_compile, route_set_ip_nexthop_free }; - + /* `set local-preference LOCAL_PREF' */ /* Set local preference. */ @@ -1031,7 +1031,7 @@ struct route_map_rule_cmd route_set_local_pref_cmd = route_set_local_pref_compile, route_set_local_pref_free, }; - + /* `set weight WEIGHT' */ /* Set weight. */ @@ -1100,7 +1100,7 @@ struct route_map_rule_cmd route_set_weight_cmd = route_set_weight_compile, route_set_weight_free, }; - + /* `set metric METRIC' */ /* Set metric to attribute. */ @@ -1200,7 +1200,7 @@ struct route_map_rule_cmd route_set_metric_cmd = route_set_metric_compile, route_set_metric_free, }; - + /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ @@ -1256,7 +1256,7 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = route_set_aspath_prepend_compile, route_set_aspath_prepend_free, }; - + /* `set as-path exclude ASn' */ /* For ASN exclude mechanism. @@ -1314,7 +1314,7 @@ struct route_map_rule_cmd route_set_aspath_exclude_cmd = route_set_aspath_exclude_compile, route_set_aspath_exclude_free, }; - + /* `set community COMMUNITY' */ struct rmap_com_set { @@ -1438,7 +1438,7 @@ struct route_map_rule_cmd route_set_community_cmd = route_set_community_compile, route_set_community_free, }; - + /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ @@ -1527,7 +1527,7 @@ struct route_map_rule_cmd route_set_community_delete_cmd = route_set_community_delete_compile, route_set_community_delete_free, }; - + /* `set extcommunity rt COMMUNITY' */ /* For community set mechanism. */ @@ -1659,7 +1659,7 @@ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = route_set_ecommunity_soo_compile, route_set_ecommunity_soo_free, }; - + /* `set origin ORIGIN' */ /* For origin set. */ @@ -1713,7 +1713,7 @@ struct route_map_rule_cmd route_set_origin_cmd = route_set_origin_compile, route_set_origin_free, }; - + /* `set atomic-aggregate' */ /* For atomic aggregate set. */ @@ -1754,7 +1754,7 @@ struct route_map_rule_cmd route_set_atomic_aggregate_cmd = route_set_atomic_aggregate_compile, route_set_atomic_aggregate_free, }; - + /* `set aggregator as AS A.B.C.D' */ struct aggregator { @@ -1813,7 +1813,7 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = route_set_aggregator_as_compile, route_set_aggregator_as_free, }; - + #ifdef HAVE_IPV6 /* `match ipv6 address IP_ACCESS_LIST' */ @@ -1855,7 +1855,7 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd = route_match_ipv6_address_compile, route_match_ipv6_address_free }; - + /* `match ipv6 next-hop IP_ADDRESS' */ static route_map_result_t @@ -1917,7 +1917,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = route_match_ipv6_next_hop_compile, route_match_ipv6_next_hop_free }; - + /* `match ipv6 address prefix-list PREFIX_LIST' */ static route_map_result_t @@ -1957,7 +1957,7 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = route_match_ipv6_address_prefix_list_compile, route_match_ipv6_address_prefix_list_free }; - + /* `set ipv6 nexthop global IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -2021,7 +2021,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = route_set_ipv6_nexthop_global_compile, route_set_ipv6_nexthop_global_free }; - + /* `set ipv6 nexthop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -2086,7 +2086,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = route_set_ipv6_nexthop_local_free }; #endif /* HAVE_IPV6 */ - + /* `set vpnv4 nexthop A.B.C.D' */ static route_map_result_t @@ -2142,7 +2142,7 @@ struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = route_set_vpnv4_nexthop_compile, route_set_vpnv4_nexthop_free }; - + /* `set originator-id' */ /* For origin set. */ @@ -2199,7 +2199,7 @@ struct route_map_rule_cmd route_set_originator_id_cmd = route_set_originator_id_compile, route_set_originator_id_free, }; - + /* Add bgp route map rule. */ static int bgp_route_match_add (struct vty *vty, struct route_map_index *index, @@ -2408,7 +2408,7 @@ bgp_route_map_update (const char *unused) } } } - + DEFUN (match_peer, match_peer_cmd, "match peer (A.B.C.D|X:X::X:X)", @@ -3562,7 +3562,7 @@ ALIAS (no_set_aggregator_as, "AS number\n" "IP address of aggregator\n") - + #ifdef HAVE_IPV6 DEFUN (match_ipv6_address, match_ipv6_address_cmd, @@ -3833,7 +3833,7 @@ ALIAS (no_match_pathlimit_as, "BGP AS-Pathlimit attribute\n" "Match Pathlimit ASN\n") - + /* Initialization of route map. */ void bgp_route_map_init (void) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index c8f2aa54b..79aaa03a6 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -38,7 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_route.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_snmp.h" - + /* BGP4-MIB described in RFC1657. */ #define BGP4MIB 1,3,6,1,2,1,15 @@ -112,7 +112,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define OCTET_STRING ASN_OCTET_STR #define IPADDRESS ASN_IPADDRESS #define GAUGE32 ASN_UNSIGNED - + /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES @@ -242,7 +242,7 @@ struct variable bgp_variables[] = 3, {6, 1, 14}}, }; - + static u_char * bgpVersion (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) @@ -835,7 +835,7 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, } return NULL; } - + /* BGP Traps. */ struct trap_object bgpTrapList[] = { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b4d765afa..3c6973b0b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -314,7 +314,7 @@ DEFUN_DEPRECATED (neighbor_version, { return CMD_SUCCESS; } - + /* "router bgp" commands. */ DEFUN (router_bgp, router_bgp_cmd, @@ -364,7 +364,7 @@ ALIAS (router_bgp, AS_STR "BGP view\n" "view name\n") - + /* "no router bgp" commands. */ DEFUN (no_router_bgp, no_router_bgp_cmd, @@ -405,7 +405,7 @@ ALIAS (no_router_bgp, AS_STR "BGP view\n" "view name\n") - + /* BGP router-id. */ DEFUN (bgp_router_id, @@ -476,7 +476,7 @@ ALIAS (no_bgp_router_id, BGP_STR "Override configured router identifier\n" "Manually configured router identifier\n") - + /* BGP Cluster ID. */ DEFUN (bgp_cluster_id, @@ -546,7 +546,7 @@ ALIAS (no_bgp_cluster_id, BGP_STR "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id in IP address format\n") - + DEFUN (bgp_confederation_identifier, bgp_confederation_identifier_cmd, "bgp confederation identifier " CMD_AS_RANGE, @@ -596,7 +596,7 @@ ALIAS (no_bgp_confederation_identifier, "AS confederation parameters\n" "AS number\n" "Set routing domain confederation AS\n") - + DEFUN (bgp_confederation_peers, bgp_confederation_peers_cmd, "bgp confederation peers ." CMD_AS_RANGE, @@ -650,7 +650,7 @@ DEFUN (no_bgp_confederation_peers, } return CMD_SUCCESS; } - + /* Maximum-paths configuration */ DEFUN (bgp_maxpaths, bgp_maxpaths_cmd, @@ -793,7 +793,7 @@ bgp_config_write_maxpaths (struct vty *vty, struct bgp *bgp, afi_t afi, return 0; } - + /* BGP timers. */ DEFUN (bgp_timers, @@ -849,7 +849,7 @@ ALIAS (no_bgp_timers, "BGP timers\n" "Keepalive interval\n" "Holdtime\n") - + DEFUN (bgp_client_to_client_reflection, bgp_client_to_client_reflection_cmd, "bgp client-to-client reflection", @@ -906,7 +906,7 @@ DEFUN (no_bgp_always_compare_med, bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); return CMD_SUCCESS; } - + /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, bgp_deterministic_med_cmd, @@ -1037,7 +1037,7 @@ DEFUN (no_bgp_fast_external_failover, bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); return CMD_SUCCESS; } - + /* "bgp enforce-first-as" configuration. */ DEFUN (bgp_enforce_first_as, bgp_enforce_first_as_cmd, @@ -1065,7 +1065,7 @@ DEFUN (no_bgp_enforce_first_as, bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS); return CMD_SUCCESS; } - + /* "bgp bestpath compare-routerid" configuration. */ DEFUN (bgp_bestpath_compare_router_id, bgp_bestpath_compare_router_id_cmd, @@ -1095,7 +1095,7 @@ DEFUN (no_bgp_bestpath_compare_router_id, bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID); return CMD_SUCCESS; } - + /* "bgp bestpath as-path ignore" configuration. */ DEFUN (bgp_bestpath_aspath_ignore, bgp_bestpath_aspath_ignore_cmd, @@ -1127,7 +1127,7 @@ DEFUN (no_bgp_bestpath_aspath_ignore, bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE); return CMD_SUCCESS; } - + /* "bgp bestpath as-path confed" configuration. */ DEFUN (bgp_bestpath_aspath_confed, bgp_bestpath_aspath_confed_cmd, @@ -1159,7 +1159,7 @@ DEFUN (no_bgp_bestpath_aspath_confed, bgp_flag_unset (bgp, BGP_FLAG_ASPATH_CONFED); return CMD_SUCCESS; } - + /* "bgp bestpath as-path multipath-relax" configuration. */ DEFUN (bgp_bestpath_aspath_multipath_relax, bgp_bestpath_aspath_multipath_relax_cmd, @@ -1191,7 +1191,7 @@ DEFUN (no_bgp_bestpath_aspath_multipath_relax, bgp_flag_unset (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); return CMD_SUCCESS; } - + /* "bgp log-neighbor-changes" configuration. */ DEFUN (bgp_log_neighbor_changes, bgp_log_neighbor_changes_cmd, @@ -1219,7 +1219,7 @@ DEFUN (no_bgp_log_neighbor_changes, bgp_flag_unset (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); return CMD_SUCCESS; } - + /* "bgp bestpath med" configuration. */ DEFUN (bgp_bestpath_med, bgp_bestpath_med_cmd, @@ -1317,7 +1317,7 @@ ALIAS (no_bgp_bestpath_med2, "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") - + /* "no bgp default ipv4-unicast". */ DEFUN (no_bgp_default_ipv4_unicast, no_bgp_default_ipv4_unicast_cmd, @@ -1347,7 +1347,7 @@ DEFUN (bgp_default_ipv4_unicast, bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4); return CMD_SUCCESS; } - + /* "bgp import-check" configuration. */ DEFUN (bgp_network_import_check, bgp_network_import_check_cmd, @@ -1377,7 +1377,7 @@ DEFUN (no_bgp_network_import_check, bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); return CMD_SUCCESS; } - + DEFUN (bgp_default_local_preference, bgp_default_local_preference_cmd, "bgp default local-preference <0-4294967295>", @@ -1421,7 +1421,7 @@ ALIAS (no_bgp_default_local_preference, "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") - + static int peer_remote_as_vty (struct vty *vty, const char *peer_str, const char *as_str, afi_t afi, safi_t safi) @@ -1481,7 +1481,7 @@ DEFUN (neighbor_remote_as, { return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST); } - + DEFUN (neighbor_peer_group, neighbor_peer_group_cmd, "neighbor WORD peer-group", @@ -1586,7 +1586,7 @@ DEFUN (no_neighbor_peer_group_remote_as, } return CMD_SUCCESS; } - + DEFUN (neighbor_local_as, neighbor_local_as_cmd, NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE, @@ -1696,7 +1696,7 @@ ALIAS (no_neighbor_local_as, "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" "Do not prepend local-as to updates from ibgp peers\n") - + DEFUN (neighbor_password, neighbor_password_cmd, NEIGHBOR_CMD2 "password LINE", @@ -1734,7 +1734,7 @@ DEFUN (no_neighbor_password, ret = peer_password_unset (peer); return bgp_vty_return (vty, ret); } - + DEFUN (neighbor_activate, neighbor_activate_cmd, NEIGHBOR_CMD2 "activate", @@ -1773,7 +1773,7 @@ DEFUN (no_neighbor_activate, return bgp_vty_return (vty, ret); } - + DEFUN (neighbor_set_peer_group, neighbor_set_peer_group_cmd, NEIGHBOR_CMD "peer-group WORD", @@ -1855,7 +1855,7 @@ DEFUN (no_neighbor_set_peer_group, return bgp_vty_return (vty, ret); } - + static int peer_flag_modify_vty (struct vty *vty, const char *ip_str, u_int16_t flag, int set) @@ -1908,7 +1908,7 @@ DEFUN (no_neighbor_passive, { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE); } - + /* neighbor shutdown. */ DEFUN (neighbor_shutdown, neighbor_shutdown_cmd, @@ -1930,7 +1930,7 @@ DEFUN (no_neighbor_shutdown, { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); } - + /* Deprecated neighbor capability route-refresh. */ DEFUN_DEPRECATED (neighbor_capability_route_refresh, neighbor_capability_route_refresh_cmd, @@ -1954,7 +1954,7 @@ DEFUN_DEPRECATED (no_neighbor_capability_route_refresh, { return CMD_SUCCESS; } - + /* neighbor capability dynamic. */ DEFUN (neighbor_capability_dynamic, neighbor_capability_dynamic_cmd, @@ -1978,7 +1978,7 @@ DEFUN (no_neighbor_capability_dynamic, { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); } - + /* neighbor dont-capability-negotiate */ DEFUN (neighbor_dont_capability_negotiate, neighbor_dont_capability_negotiate_cmd, @@ -2000,7 +2000,7 @@ DEFUN (no_neighbor_dont_capability_negotiate, { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); } - + static int peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_t flag, int set) @@ -2033,7 +2033,7 @@ peer_af_flag_unset_vty (struct vty *vty, const char *peer_str, afi_t afi, { return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0); } - + /* neighbor capability orf prefix-list. */ DEFUN (neighbor_capability_orf_prefix, neighbor_capability_orf_prefix_cmd, @@ -2089,7 +2089,7 @@ DEFUN (no_neighbor_capability_orf_prefix, return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flag); } - + /* neighbor next-hop-self. */ DEFUN (neighbor_nexthop_self, neighbor_nexthop_self_cmd, @@ -2113,7 +2113,7 @@ DEFUN (no_neighbor_nexthop_self, return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); } - + /* neighbor remove-private-AS. */ DEFUN (neighbor_remove_private_as, neighbor_remove_private_as_cmd, @@ -2139,7 +2139,7 @@ DEFUN (no_neighbor_remove_private_as, bgp_node_safi (vty), PEER_FLAG_REMOVE_PRIVATE_AS); } - + /* neighbor send-community. */ DEFUN (neighbor_send_community, neighbor_send_community_cmd, @@ -2165,7 +2165,7 @@ DEFUN (no_neighbor_send_community, bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); } - + /* neighbor send-community extended. */ DEFUN (neighbor_send_community_type, neighbor_send_community_type_cmd, @@ -2217,7 +2217,7 @@ DEFUN (no_neighbor_send_community_type, (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY)); } - + /* neighbor soft-reconfig. */ DEFUN (neighbor_soft_reconfiguration, neighbor_soft_reconfiguration_cmd, @@ -2245,7 +2245,7 @@ DEFUN (no_neighbor_soft_reconfiguration, bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SOFT_RECONFIG); } - + DEFUN (neighbor_route_reflector_client, neighbor_route_reflector_client_cmd, NEIGHBOR_CMD2 "route-reflector-client", @@ -2277,7 +2277,7 @@ DEFUN (no_neighbor_route_reflector_client, bgp_node_safi (vty), PEER_FLAG_REFLECTOR_CLIENT); } - + static int peer_rsclient_set_vty (struct vty *vty, const char *peer_str, int afi, int safi) @@ -2425,7 +2425,7 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str, return CMD_SUCCESS; } - + /* neighbor route-server-client. */ DEFUN (neighbor_route_server_client, neighbor_route_server_client_cmd, @@ -2449,7 +2449,7 @@ DEFUN (no_neighbor_route_server_client, return peer_rsclient_unset_vty (vty, argv[0], bgp_node_afi(vty), bgp_node_safi(vty)); } - + DEFUN (neighbor_nexthop_local_unchanged, neighbor_nexthop_local_unchanged_cmd, NEIGHBOR_CMD2 "nexthop-local unchanged", @@ -2462,7 +2462,7 @@ DEFUN (neighbor_nexthop_local_unchanged, bgp_node_safi (vty), PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } - + DEFUN (no_neighbor_nexthop_local_unchanged, no_neighbor_nexthop_local_unchanged_cmd, NO_NEIGHBOR_CMD2 "nexthop-local unchanged", @@ -2476,7 +2476,7 @@ DEFUN (no_neighbor_nexthop_local_unchanged, bgp_node_safi (vty), PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } - + DEFUN (neighbor_attr_unchanged, neighbor_attr_unchanged_cmd, NEIGHBOR_CMD2 "attribute-unchanged", @@ -2833,7 +2833,7 @@ DEFUN_DEPRECATED (neighbor_transparent_nexthop, bgp_node_safi (vty), PEER_FLAG_NEXTHOP_UNCHANGED); } - + /* EBGP multihop configuration. */ static int peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str, @@ -2907,7 +2907,7 @@ ALIAS (no_neighbor_ebgp_multihop, NEIGHBOR_ADDR_STR2 "Allow EBGP neighbors not on directly connected networks\n" "maximum hop count\n") - + /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, @@ -2946,7 +2946,7 @@ ALIAS (no_neighbor_disable_connected_check, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Enforce EBGP neighbors perform multihop\n") - + DEFUN (neighbor_description, neighbor_description_cmd, NEIGHBOR_CMD2 "description .LINE", @@ -3001,7 +3001,7 @@ ALIAS (no_neighbor_description, NEIGHBOR_ADDR_STR2 "Neighbor specific description\n" "Up to 80 characters describing this neighbor\n") - + /* Neighbor update-source. */ static int peer_update_source_vty (struct vty *vty, const char *peer_str, @@ -3056,7 +3056,7 @@ DEFUN (no_neighbor_update_source, { return peer_update_source_vty (vty, argv[0], NULL); } - + static int peer_default_originate_set_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, @@ -3123,7 +3123,7 @@ ALIAS (no_neighbor_default_originate, "Originate default route to this neighbor\n" "Route-map to specify criteria to originate default\n" "route-map name\n") - + /* Set neighbor's BGP port. */ static int peer_port_vty (struct vty *vty, const char *ip_str, int afi, @@ -3183,7 +3183,7 @@ ALIAS (no_neighbor_port, NEIGHBOR_ADDR_STR "Neighbor's BGP port\n" "TCP port number\n") - + /* neighbor weight. */ static int peer_weight_set_vty (struct vty *vty, const char *ip_str, @@ -3248,7 +3248,7 @@ ALIAS (no_neighbor_weight, NEIGHBOR_ADDR_STR2 "Set default weight for routes from this neighbor\n" "default weight\n") - + /* Override capability negotiation. */ DEFUN (neighbor_override_capability, neighbor_override_capability_cmd, @@ -3270,7 +3270,7 @@ DEFUN (no_neighbor_override_capability, { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); } - + DEFUN (neighbor_strict_capability, neighbor_strict_capability_cmd, NEIGHBOR_CMD "strict-capability-match", @@ -3291,7 +3291,7 @@ DEFUN (no_neighbor_strict_capability, { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); } - + static int peer_timers_set_vty (struct vty *vty, const char *ip_str, const char *keep_str, const char *hold_str) @@ -3312,7 +3312,7 @@ peer_timers_set_vty (struct vty *vty, const char *ip_str, return bgp_vty_return (vty, ret); } - + static int peer_timers_unset_vty (struct vty *vty, const char *ip_str) { @@ -3350,7 +3350,7 @@ DEFUN (no_neighbor_timers, { return peer_timers_unset_vty (vty, argv[0]); } - + static int peer_timers_connect_set_vty (struct vty *vty, const char *ip_str, const char *time_str) @@ -3418,7 +3418,7 @@ ALIAS (no_neighbor_timers_connect, "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") - + static int peer_advertise_interval_vty (struct vty *vty, const char *ip_str, const char *time_str, int set) @@ -3472,7 +3472,7 @@ ALIAS (no_neighbor_advertise_interval, NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n" "time in seconds\n") - + /* neighbor interface */ static int peer_interface_vty (struct vty *vty, const char *ip_str, const char *str) @@ -3514,7 +3514,7 @@ DEFUN (no_neighbor_interface, { return peer_interface_vty (vty, argv[0], NULL); } - + /* Set distribute list to the peer. */ static int peer_distribute_set_vty (struct vty *vty, const char *ip_str, @@ -3595,7 +3595,7 @@ DEFUN (no_neighbor_distribute_list, return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } - + /* Set prefix list to the peer. */ static int peer_prefix_list_set_vty (struct vty *vty, const char *ip_str, afi_t afi, @@ -3672,7 +3672,7 @@ DEFUN (no_neighbor_prefix_list, return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } - + static int peer_aslist_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, @@ -3749,7 +3749,7 @@ DEFUN (no_neighbor_filter_list, return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } - + /* Set route-map to the peer. */ static int peer_route_map_set_vty (struct vty *vty, const char *ip_str, @@ -3838,7 +3838,7 @@ DEFUN (no_neighbor_route_map, return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } - + /* Set unsuppress-map to the peer. */ static int peer_unsuppress_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi, @@ -3897,7 +3897,7 @@ DEFUN (no_neighbor_unsuppress_map, return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty)); } - + static int peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *num_str, @@ -4107,7 +4107,7 @@ ALIAS (no_neighbor_maximum_prefix, "Threshold value (%) at which to generate a warning msg\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") - + /* "neighbor allowas-in" */ DEFUN (neighbor_allowas_in, neighbor_allowas_in_cmd, @@ -4162,7 +4162,7 @@ DEFUN (no_neighbor_allowas_in, return bgp_vty_return (vty, ret); } - + DEFUN (neighbor_ttl_security, neighbor_ttl_security_cmd, NEIGHBOR_CMD2 "ttl-security hops <1-254>", @@ -4198,7 +4198,7 @@ DEFUN (no_neighbor_ttl_security, return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer)); } - + /* Address family configuration. */ DEFUN (address_family_ipv4, address_family_ipv4_cmd, @@ -4282,7 +4282,7 @@ DEFUN (exit_address_family, vty->node = BGP_NODE; return CMD_SUCCESS; } - + /* BGP clear sort. */ enum clear_sort { @@ -4636,7 +4636,7 @@ ALIAS (clear_ip_bgp_as, BGP_STR "Address family\n" "Clear peers with the AS number\n") - + /* Outbound soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft_out, clear_ip_bgp_all_soft_out_cmd, @@ -5263,7 +5263,7 @@ ALIAS (clear_bgp_as_soft_out, "Address family\n" "Clear peers with the AS number\n" "Soft reconfig outbound update\n") - + /* Inbound soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft_in, clear_ip_bgp_all_soft_in_cmd, @@ -6225,7 +6225,7 @@ ALIAS (clear_bgp_as_in_prefix_filter, "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") - + /* Both soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft, clear_ip_bgp_all_soft_cmd, @@ -6599,7 +6599,7 @@ ALIAS (clear_bgp_as_soft, "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n") - + /* RS-client soft reconfiguration. */ #ifdef HAVE_IPV6 DEFUN (clear_bgp_all_rsclient, @@ -7278,7 +7278,7 @@ DEFUN (show_ipv6_mbgp_summary, return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ - + const char * afi_safi_print (afi_t afi, safi_t safi) { @@ -8188,7 +8188,7 @@ ALIAS (show_ip_bgp_instance_neighbors_peer, "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") - + /* Show BGP's AS paths internal data. There are both `show ip bgp paths' and `show ip mbgp paths'. Those functions results are the same.*/ @@ -8221,7 +8221,7 @@ DEFUN (show_ip_bgp_ipv4_paths, return CMD_SUCCESS; } - + #include "hash.h" static void @@ -8264,7 +8264,7 @@ DEFUN (show_ip_bgp_attr_info, attr_show_all (vty); return CMD_SUCCESS; } - + static int bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient, afi_t afi, safi_t safi) @@ -8585,7 +8585,7 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, "Summary of all Route Server Clients\n") #endif /* HAVE IPV6 */ - + /* Redistribute VTY commands. */ DEFUN (bgp_redistribute_ipv4, @@ -8799,7 +8799,7 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric, "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") - + #ifdef HAVE_IPV6 DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, @@ -9014,7 +9014,7 @@ ALIAS (no_bgp_redistribute_ipv6_rmap_metric, "Route map reference\n" "Pointer to route-map entries\n") #endif /* HAVE_IPV6 */ - + int bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) @@ -9047,7 +9047,7 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, } return *write; } - + /* BGP node structure. */ static struct cmd_node bgp_node = { @@ -9090,7 +9090,7 @@ static struct cmd_node bgp_vpnv4_node = "%s(config-router-af)# ", 1 }; - + static void community_list_vty (void); void @@ -10231,7 +10231,7 @@ bgp_vty_init (void) /* Community-list. */ community_list_vty (); } - + #include "memory.h" #include "bgp_regex.h" #include "bgp_clist.h" @@ -10630,7 +10630,7 @@ DEFUN (show_ip_community_list_arg, return CMD_SUCCESS; } - + static int extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv, int style, int reject_all_digit_name) @@ -10980,7 +10980,7 @@ DEFUN (show_ip_extcommunity_list_arg, return CMD_SUCCESS; } - + /* Return configuration string of community-list entry. */ static const char * community_list_config_str (struct community_entry *entry) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 0f212321a..f18d916f1 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -38,7 +38,7 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_mpath.h" - + /* All information about zebra. */ struct zclient *zclient = NULL; struct in_addr router_id_zebra; @@ -381,7 +381,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) return 0; } #endif /* HAVE_IPV6 */ - + struct interface * if_lookup_by_ipv4 (struct in_addr *addr) { @@ -943,7 +943,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) } #endif /* HAVE_IPV6 */ } - + /* Other routes redistribution into BGP. */ int bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) @@ -1069,7 +1069,7 @@ bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) return 1; } - + void bgp_zclient_reset (void) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2fe300c5a..19b96fa93 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -61,7 +61,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ - + /* BGP process wide configuration. */ static struct bgp_master bgp_master; @@ -72,7 +72,7 @@ struct bgp_master *bm; /* BGP community-list. */ struct community_list_handler *bgp_clist; - + /* BGP global flag manipulation. */ int bgp_option_set (int flag) @@ -115,7 +115,7 @@ bgp_option_check (int flag) { return CHECK_FLAG (bm->options, flag); } - + /* BGP flag manipulation. */ int bgp_flag_set (struct bgp *bgp, int flag) @@ -136,7 +136,7 @@ bgp_flag_check (struct bgp *bgp, int flag) { return CHECK_FLAG (bgp->flags, flag); } - + /* Internal function to set BGP structure configureation flag. */ static void bgp_config_set (struct bgp *bgp, int config) @@ -155,7 +155,7 @@ bgp_config_check (struct bgp *bgp, int config) { return CHECK_FLAG (bgp->config, config); } - + /* Set BGP router identifier. */ int bgp_router_id_set (struct bgp *bgp, struct in_addr *id) @@ -242,7 +242,7 @@ bgp_cluster_id_unset (struct bgp *bgp) } return 0; } - + /* time_t value that is monotonicly increasing * and uneffected by adjustments to system clock */ @@ -273,7 +273,7 @@ bgp_timers_unset (struct bgp *bgp) return 0; } - + /* BGP confederation configuration. */ int bgp_confederation_id_set (struct bgp *bgp, as_t as) @@ -485,7 +485,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as) return 0; } - + /* Local preference configuration. */ int bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref) @@ -508,7 +508,7 @@ bgp_default_local_preference_unset (struct bgp *bgp) return 0; } - + /* If peer is RSERVER_CLIENT in at least one address family and is not member of a peer_group for that family, return 1. Used to check wether the peer is included in list bgp->rsclient. */ @@ -1325,7 +1325,7 @@ peer_delete (struct peer *peer) return 0; } - + static int peer_group_cmp (struct peer_group *g1, struct peer_group *g2) { @@ -1926,7 +1926,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, return 0; } - + /* BGP instance creation by `router bgp' commands. */ static struct bgp * bgp_create (as_t *as, const char *name) @@ -2181,7 +2181,7 @@ bgp_free (struct bgp *bgp) } XFREE (MTYPE_BGP, bgp); } - + struct peer * peer_lookup (struct bgp *bgp, union sockunion *su) { @@ -2250,7 +2250,7 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as, } return NULL; } - + /* If peer is configured at least one address family return 1. */ int peer_active (struct peer *peer) @@ -2276,7 +2276,7 @@ peer_active_nego (struct peer *peer) return 1; return 0; } - + /* peer_flag_change_type. */ enum peer_change_type { @@ -2695,7 +2695,7 @@ peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) { return peer_af_flag_modify (peer, afi, safi, flag, 0); } - + /* EBGP multihop configuration. */ int peer_ebgp_multihop_set (struct peer *peer, int ttl) @@ -2794,7 +2794,7 @@ peer_ebgp_multihop_unset (struct peer *peer) } return 0; } - + /* Neighbor description. */ int peer_description_set (struct peer *peer, char *desc) @@ -2817,7 +2817,7 @@ peer_description_unset (struct peer *peer) return 0; } - + /* Neighbor update-source. */ int peer_update_source_if_set (struct peer *peer, const char *ifname) @@ -3037,7 +3037,7 @@ peer_update_source_unset (struct peer *peer) } return 0; } - + int peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi, const char *rmap) @@ -3142,7 +3142,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi) } return 0; } - + int peer_port_set (struct peer *peer, u_int16_t port) { @@ -3156,7 +3156,7 @@ peer_port_unset (struct peer *peer) peer->port = BGP_PORT_DEFAULT; return 0; } - + /* neighbor weight. */ int peer_weight_set (struct peer *peer, u_int16_t weight) @@ -3204,7 +3204,7 @@ peer_weight_unset (struct peer *peer) } return 0; } - + int peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime) { @@ -3274,7 +3274,7 @@ peer_timers_unset (struct peer *peer) return 0; } - + int peer_timers_connect_set (struct peer *peer, u_int32_t connect) { @@ -3309,7 +3309,7 @@ peer_timers_connect_unset (struct peer *peer) return 0; } - + int peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) { @@ -3342,7 +3342,7 @@ peer_advertise_interval_unset (struct peer *peer) return 0; } - + /* neighbor interface */ int peer_interface_set (struct peer *peer, const char *str) @@ -3363,7 +3363,7 @@ peer_interface_unset (struct peer *peer) return 0; } - + /* Allow-as in. */ int peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num) @@ -3424,7 +3424,7 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi) } return 0; } - + int peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as) { @@ -3552,7 +3552,7 @@ peer_local_as_unset (struct peer *peer) } return 0; } - + /* Set password for authenticating with the peer. */ int peer_password_set (struct peer *peer, const char *password) @@ -3657,7 +3657,7 @@ peer_password_unset (struct peer *peer) return 0; } - + /* Set distribute list to the peer. */ int peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -3817,7 +3817,7 @@ peer_distribute_update (struct access_list *access) } } } - + /* Set prefix list to the peer. */ int peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -3976,7 +3976,7 @@ peer_prefix_list_update (struct prefix_list *plist) } } } - + int peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) @@ -4130,7 +4130,7 @@ peer_aslist_update (void) } } } - + /* Set route-map to the peer. */ int peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -4238,7 +4238,7 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) } return 0; } - + /* Set unsuppress-map to the peer. */ int peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi, @@ -4320,7 +4320,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi) } return 0; } - + int peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t max, u_char threshold, @@ -4547,7 +4547,7 @@ peer_ttl_security_hops_unset (struct peer *peer) return peer_ebgp_multihop_unset (opeer); } - + int peer_clear (struct peer *peer) { @@ -4652,7 +4652,7 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, } return 0; } - + /* Display peer uptime.*/ /* XXX: why does this function return char * when it takes buffer? */ char * @@ -4697,7 +4697,7 @@ peer_uptime (time_t uptime2, char *buf, size_t len) tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } - + static void bgp_config_write_filter (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) @@ -5394,7 +5394,7 @@ bgp_master_init (void) bm->start_time = bgp_clock (); } - + void bgp_init (void) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 688f459f2..a1b1273ba 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -854,7 +854,7 @@ extern struct peer *peer_create_accept (struct bgp *); extern char *peer_uptime (time_t, char *, size_t); extern int bgp_config_write (struct vty *); extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); - + extern void bgp_master_init (void); extern void bgp_init (void); diff --git a/doc/mpls/opaque_lsa.txt b/doc/mpls/opaque_lsa.txt index 7d5c7fed4..ae89ee34b 100644 --- a/doc/mpls/opaque_lsa.txt +++ b/doc/mpls/opaque_lsa.txt @@ -20,7 +20,7 @@ | (Callback functions) | +----------------------+ - + 2. Self-originated Opaque-LSAs per LSA-type. 2.1 Type-11 (AS-external) Opaque-LSAs @@ -110,7 +110,7 @@ : | +-------------+ : : --- : :..........................................................................: - + 2.2 Type-10 (area-local) Opaque-LSAs struct @@ -204,7 +204,7 @@ : | +-------------+ : : --- : :..........................................................................: - + 2.3 Type-9 (link-local) Opaque-LSAs struct @@ -300,7 +300,7 @@ : +-------------+ : :..........................................................................: - + 3. Internal structures for MPLS-TE parameter management. struct diff --git a/lib/command.c b/lib/command.c index a23736441..7249c6530 100644 --- a/lib/command.c +++ b/lib/command.c @@ -183,7 +183,7 @@ print_version (const char *progname) printf ("%s\n", QUAGGA_COPYRIGHT); } - + /* Utility function to concatenate argv argument into a single string with inserting ' ' character between each argument. */ char * diff --git a/lib/distribute.c b/lib/distribute.c index 8d6f63774..ba8043cf9 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -34,7 +34,7 @@ struct hash *disthash; /* Hook functions. */ void (*distribute_add_hook) (struct distribute *); void (*distribute_delete_hook) (struct distribute *); - + static struct distribute * distribute_new (void) { @@ -133,7 +133,7 @@ distribute_cmp (const struct distribute *dist1, const struct distribute *dist2) return 1; return 0; } - + /* Set access-list name to the distribute list. */ static struct distribute * distribute_list_set (const char *ifname, enum distribute_type type, diff --git a/lib/filter.c b/lib/filter.c index 693418242..96605c7d5 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -110,7 +110,7 @@ static struct access_master access_master_ipv6 = NULL, }; #endif /* HAVE_IPV6 */ - + static struct access_master * access_master_get (afi_t afi) { @@ -208,7 +208,7 @@ filter_match_zebra (struct filter *mfilter, struct prefix *p) else return 0; } - + /* Allocate new access list structure. */ static struct access_list * access_list_new (void) @@ -501,7 +501,7 @@ access_list_filter_delete (struct access_list *access, struct filter *filter) if (master->delete_hook) (*master->delete_hook) (access); } - + /* deny Specify packets to reject permit Specify packets to forward diff --git a/lib/getopt.c b/lib/getopt.c index c784fb6cc..064909d31 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -23,7 +23,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO @@ -193,7 +193,7 @@ static enum /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; - + #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. @@ -243,7 +243,7 @@ extern int strlen (const char *); #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ - + /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have @@ -456,7 +456,7 @@ _getopt_initialize (argc, argv, optstring) return optstring; } - + /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. @@ -986,7 +986,7 @@ getopt (argc, argv, optstring) #endif /* REALLY_NEED_PLAIN_GETOPT */ #endif /* Not ELIDE_CODE. */ - + #ifdef TEST /* Compile with -DTEST to make an executable for use in testing diff --git a/lib/getopt1.c b/lib/getopt1.c index 985f12c58..fa766747a 100644 --- a/lib/getopt1.c +++ b/lib/getopt1.c @@ -19,7 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #ifdef HAVE_CONFIG_H #include #endif @@ -95,7 +95,7 @@ getopt_long_only (argc, argv, options, long_options, opt_index) #endif /* Not ELIDE_CODE. */ - + #ifdef TEST #include diff --git a/lib/if.c b/lib/if.c index 6348403b6..18e2fb314 100644 --- a/lib/if.c +++ b/lib/if.c @@ -35,7 +35,7 @@ #include "buffer.h" #include "str.h" #include "log.h" - + /* Master list of interfaces. */ struct list *iflist; @@ -45,7 +45,7 @@ struct if_master int (*if_new_hook) (struct interface *); int (*if_delete_hook) (struct interface *); } if_master; - + /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the * relationship between ifp1 and ifp2. Interface names consist of an @@ -513,7 +513,7 @@ DEFUN (no_interface_desc, return CMD_SUCCESS; } - + #ifdef SUNOS_5 /* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created * a seperate struct interface for each logical interface, so config @@ -555,7 +555,7 @@ if_sunwzebra_get (const char *name, size_t nlen) return if_get_by_name_len (name, nlen); } #endif /* SUNOS_5 */ - + DEFUN (interface, interface_cmd, "interface IFNAME", @@ -806,7 +806,7 @@ if_indextoname (unsigned int ifindex, char *name) return ifp->name; } #endif - + #if 0 /* this route_table of struct connected's is unused * however, it would be good to use a route_table rather than * a list.. diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 7d049b872..e4a83de8b 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -32,7 +32,7 @@ struct hash *ifrmaphash; /* Hook functions. */ static void (*if_rmap_add_hook) (struct if_rmap *) = NULL; static void (*if_rmap_delete_hook) (struct if_rmap *) = NULL; - + static struct if_rmap * if_rmap_new (void) { @@ -122,7 +122,7 @@ if_rmap_hash_cmp (const void *arg1, const void* arg2) return strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0; } - + static struct if_rmap * if_rmap_set (const char *ifname, enum if_rmap_type type, const char *routemap_name) @@ -273,7 +273,7 @@ ALIAS (no_if_rmap, "Route map for input filtering\n" "Route map for output filtering\n" "Route map interface name\n") - + /* Configuration write function. */ int config_write_if_rmap (struct vty *vty) diff --git a/lib/keychain.c b/lib/keychain.c index 6719cebf7..762c46298 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -226,7 +226,7 @@ key_delete (struct keychain *keychain, struct key *key) free (key->string); key_free (key); } - + DEFUN (key_chain, key_chain_cmd, "key chain WORD", @@ -531,7 +531,7 @@ key_lifetime_infinite_set (struct vty *vty, struct key_range *krange, return CMD_SUCCESS; } - + DEFUN (accept_lifetime_day_month_day_month, accept_lifetime_day_month_day_month_cmd, "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", @@ -689,7 +689,7 @@ DEFUN (accept_lifetime_duration_month_day, return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[2], argv[1], argv[3], argv[4]); } - + DEFUN (send_lifetime_day_month_day_month, send_lifetime_day_month_day_month_cmd, "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", @@ -847,7 +847,7 @@ DEFUN (send_lifetime_duration_month_day, return key_lifetime_duration_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3], argv[4]); } - + static struct cmd_node keychain_node = { KEYCHAIN_NODE, diff --git a/lib/linklist.c b/lib/linklist.c index 485a80bee..370b2fa61 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -23,7 +23,7 @@ #include "linklist.h" #include "memory.h" - + /* Allocate new list. */ struct list * list_new (void) @@ -51,7 +51,7 @@ listnode_free (struct listnode *node) { XFREE (MTYPE_LINK_NODE, node); } - + /* Add new data to the list. */ void listnode_add (struct list *list, void *val) @@ -242,7 +242,7 @@ listnode_lookup (struct list *list, void *data) return node; return NULL; } - + /* Delete the node from list. For ospfd and ospf6d. */ void list_delete_node (struct list *list, struct listnode *node) @@ -258,7 +258,7 @@ list_delete_node (struct list *list, struct listnode *node) list->count--; listnode_free (node); } - + /* ospf_spf.c */ void list_add_node_prev (struct list *list, struct listnode *current, void *val) diff --git a/lib/log.c b/lib/log.c index 55a3b052d..1058844b7 100644 --- a/lib/log.c +++ b/lib/log.c @@ -69,7 +69,7 @@ const char *zlog_priority[] = }; - + /* For time string format. */ size_t @@ -145,7 +145,7 @@ time_print(FILE *fp, struct timestamp_control *ctl) fprintf(fp, "%s ", ctl->buf); } - + /* va_list version of zlog. */ static void vzlog (struct zlog *zl, int priority, const char *format, va_list args) @@ -619,7 +619,7 @@ _zlog_assert_failed (const char *assertion, const char *file, abort(); } - + /* Open log stream */ struct zlog * openzlog (const char *progname, zlog_proto_t protocol, @@ -756,7 +756,7 @@ zlog_rotate (struct zlog *zl) return 1; } - + /* Message lookup function. */ const char * lookup (const struct message *mes, int key) diff --git a/lib/memory.c b/lib/memory.c index 684ebcff5..620bdee51 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -32,7 +32,7 @@ static void alloc_inc (int); static void alloc_dec (int); static void log_memstats(int log_priority); - + static const struct message mstr [] = { { MTYPE_THREAD, "thread" }, @@ -42,7 +42,7 @@ static const struct message mstr [] = { MTYPE_IF, "interface" }, { 0, NULL }, }; - + /* Fatal memory allocation error occured. */ static void __attribute__ ((noreturn)) zerror (const char *fname, int type, size_t size) @@ -150,7 +150,7 @@ zstrdup (int type, const char *str) alloc_inc (type); return dup; } - + #ifdef MEMORY_LOG static struct { @@ -259,7 +259,7 @@ alloc_dec (int type) { mstat[type].alloc--; } - + /* Looking up memory status from vty interface. */ #include "vector.h" #include "vty.h" @@ -558,7 +558,7 @@ memory_init (void) install_element (ENABLE_NODE, &show_memory_ospf6_cmd); install_element (ENABLE_NODE, &show_memory_isis_cmd); } - + /* Stats querying from users */ /* Return a pointer to a human friendly string describing * the byte count passed in. E.g: diff --git a/lib/plist.c b/lib/plist.c index 0f802a83b..7416ebd2f 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -110,7 +110,7 @@ static struct prefix_master prefix_master_orf = NULL, NULL, }; - + static struct prefix_master * prefix_master_get (afi_t afi) { @@ -621,7 +621,7 @@ prefix_list_print (struct prefix_list *plist) } } } - + /* Retrun 1 when plist already include pentry policy. */ static struct prefix_list_entry * prefix_entry_dup_check (struct prefix_list *plist, @@ -1165,7 +1165,7 @@ vty_clear_prefix_list (struct vty *vty, afi_t afi, const char *name, } return CMD_SUCCESS; } - + DEFUN (ip_prefix_list, ip_prefix_list_cmd, "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", @@ -1759,7 +1759,7 @@ DEFUN (clear_ip_prefix_list_name_prefix, { return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]); } - + #ifdef HAVE_IPV6 DEFUN (ipv6_prefix_list, ipv6_prefix_list_cmd, @@ -2355,7 +2355,7 @@ DEFUN (clear_ipv6_prefix_list_name_prefix, return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]); } #endif /* HAVE_IPV6 */ - + /* Configuration write function. */ static int config_write_prefix_afi (afi_t afi, struct vty *vty) diff --git a/lib/prefix.c b/lib/prefix.c index a3b1adf8f..dbfdc8301 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -27,7 +27,7 @@ #include "sockunion.h" #include "memory.h" #include "log.h" - + /* Maskbit. */ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; @@ -186,7 +186,7 @@ prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen) { return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen); } - + /* Address Famiy Identifier to Address Family converter. */ int afi2family (afi_t afi) @@ -494,7 +494,7 @@ prefix_ipv4_any (const struct prefix_ipv4 *p) { return (p->prefix.s_addr == 0 && p->prefixlen == 0); } - + #ifdef HAVE_IPV6 /* Allocate a new ip version 6 route */ diff --git a/lib/privs.c b/lib/privs.c index 69606f57c..e182543a6 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -47,7 +47,7 @@ struct _pset { typedef cap_value_t pvalue_t; typedef struct _pset pset_t; typedef cap_t pstorage_t; - + #elif defined (HAVE_SOLARIS_CAPABILITIES) typedef priv_t pvalue_t; typedef priv_set_t pset_t; @@ -56,7 +56,7 @@ typedef priv_set_t *pstorage_t; #error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!" #endif /* HAVE_LCAPS */ #endif /* HAVE_CAPABILITIES */ - + /* the default NULL state we report is RAISED, but could be LOWERED if * zprivs_terminate is called and the NULL handler is installed. */ @@ -139,7 +139,7 @@ static struct [ZCAP_FOWNER] = { 1, (pvalue_t []) { PRIV_FILE_OWNER }, }, #endif /* HAVE_SOLARIS_CAPABILITIES */ }; - + #ifdef HAVE_LCAPS /* Linux forms of capabilities methods */ /* convert zebras privileges to system capabilities */ @@ -339,7 +339,7 @@ zprivs_caps_terminate (void) cap_free (zprivs_state.caps); } #elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */ - + /* Solaris specific capability/privilege methods * * Resources: @@ -556,7 +556,7 @@ zprivs_caps_terminate (void) #error "Neither Solaris nor Linux capabilities, dazed and confused..." #endif /* HAVE_LCAPS */ #endif /* HAVE_CAPABILITIES */ - + int zprivs_change_uid (zebra_privs_ops_t op) { diff --git a/lib/regex-gnu.h b/lib/regex-gnu.h index d88ab92bd..4cee464f2 100644 --- a/lib/regex-gnu.h +++ b/lib/regex-gnu.h @@ -165,7 +165,7 @@ typedef unsigned long int reg_syntax_t; stored in the pattern buffer, so changing this does not affect already-compiled regexps. */ extern reg_syntax_t re_syntax_options; - + /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so don't delete them!) */ @@ -234,7 +234,7 @@ extern reg_syntax_t re_syntax_options; | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ - + /* Maximum number of duplicates an interval can allow. Some systems (erroneously) define this in other header files, but we want our value, so remove any previous define. */ @@ -309,7 +309,7 @@ typedef enum REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ } reg_errcode_t; - + /* This data structure represents a compiled pattern. Before calling the pattern compiler, the fields `buffer', `allocated', `fastmap', `translate', and `no_sub' can be set. After the pattern has been @@ -389,7 +389,7 @@ struct re_pattern_buffer }; typedef struct re_pattern_buffer regex_t; - + /* Type for byte offsets within the string. POSIX mandates this. */ typedef int regoff_t; @@ -420,7 +420,7 @@ typedef struct regoff_t rm_so; /* Byte offset from string's start to substring's start. */ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ } regmatch_t; - + /* Declarations for routines. */ /* To avoid duplicating every routine declaration -- once with a @@ -532,7 +532,7 @@ extern void regfree _RE_ARGS ((regex_t *__preg)); #endif /* C++ */ #endif /* regex.h */ - + /* Local variables: make-backup-files: t diff --git a/lib/regex.c b/lib/regex.c index a22e03f6b..122f44764 100644 --- a/lib/regex.c +++ b/lib/regex.c @@ -209,7 +209,7 @@ init_syntax_once () # define SYNTAX(c) re_syntax_table[c] #endif /* not emacs */ - + /* Get the interface, including the syntax bits. */ #include @@ -279,7 +279,7 @@ init_syntax_once () /* As in Harbison and Steele. */ # define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) #endif - + /* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we use `alloca' instead of `malloc'. This is because using malloc in re_search* or re_match* could cause memory leaks when C-g is used in @@ -388,7 +388,7 @@ static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp, int pos, struct re_registers *regs, int stop)); - + /* These are the command codes that appear in compiled regular expressions. Some opcodes are followed by argument bytes. A command code can specify any interpretation whatsoever for its @@ -527,7 +527,7 @@ typedef enum notsyntaxspec #endif /* emacs */ } re_opcode_t; - + /* Common operations on the compiled pattern. */ /* Store NUMBER in two contiguous bytes starting at DESTINATION. */ @@ -604,7 +604,7 @@ extract_number_and_incr (destination, source) # endif /* not EXTRACT_MACROS */ #endif /* DEBUG */ - + /* If DEBUG is defined, Regex prints many voluminous messages about what it is doing (if the variable `debug' is nonzero). If linked with the main program in `iregex.c', you can enter patterns and strings @@ -977,7 +977,7 @@ printchar (c) # define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) #endif /* not DEBUG */ - + /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can also be assigned to arbitrarily: each pattern buffer stores its own syntax, so it can be changed between regex compilations. */ @@ -1011,7 +1011,7 @@ re_set_syntax (syntax) #ifdef _LIBC weak_alias (__re_set_syntax, re_set_syntax) #endif - + /* This table gives an error message for each of the error codes listed in regex.h. Obviously the order here has to be same as there. POSIX doesn't require that we do anything for REG_NOERROR, @@ -1091,7 +1091,7 @@ static const size_t re_error_msgid_idx[] = REG_ESIZE_IDX, REG_ERPAREN_IDX }; - + /* Avoiding alloca during matching, to placate r_alloc. */ /* Define MATCH_MAY_ALLOCATE unless we need to make sure that the @@ -1129,7 +1129,7 @@ static const size_t re_error_msgid_idx[] = # undef MATCH_MAY_ALLOCATE #endif - + /* Failure stack declarations and macros; both re_compile_fastmap and re_match_2 use a failure stack. These have to be macros because of REGEX_ALLOCATE_STACK. */ @@ -1495,7 +1495,7 @@ typedef struct } /* POP_FAILURE_POINT */ - + /* Structure for per-register (a.k.a. per-group) information. Other register information, such as the starting and ending positions (which are addresses), and the list of @@ -1555,7 +1555,7 @@ typedef union static char reg_unset_dummy; #define REG_UNSET_VALUE (®_unset_dummy) #define REG_UNSET(e) ((e) == REG_UNSET_VALUE) - + /* Subroutine declarations and macros for regex_compile. */ static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size, @@ -1809,7 +1809,7 @@ typedef struct || STREQ (string, "punct") || STREQ (string, "graph") \ || STREQ (string, "cntrl") || STREQ (string, "blank")) #endif - + #ifndef MATCH_MAY_ALLOCATE /* If we cannot allocate large objects within re_match_2_internal, @@ -1857,7 +1857,7 @@ regex_grow_registers (num_regs) } #endif /* not MATCH_MAY_ALLOCATE */ - + static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type compile_stack, regnum_t regnum)); @@ -2991,7 +2991,7 @@ regex_compile (pattern, size, syntax, bufp) return REG_NOERROR; } /* regex_compile */ - + /* Subroutines for `regex_compile'. */ /* Store OP at LOC followed by two-byte integer parameter ARG. */ @@ -3178,7 +3178,7 @@ compile_range (p_ptr, pend, translate, syntax, b) return REG_NOERROR; } - + /* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible characters can start a string that matches the pattern. This fastmap @@ -3484,7 +3484,7 @@ re_compile_fastmap (bufp) #ifdef _LIBC weak_alias (__re_compile_fastmap, re_compile_fastmap) #endif - + /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use this memory for recording register information. STARTS and ENDS @@ -3522,7 +3522,7 @@ re_set_registers (bufp, regs, num_regs, starts, ends) #ifdef _LIBC weak_alias (__re_set_registers, re_set_registers) #endif - + /* Searching routines. */ /* Like re_search_2, below, but only one string is specified, and @@ -3704,7 +3704,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) #ifdef _LIBC weak_alias (__re_search_2, re_search_2) #endif - + /* This converts PTR, a pointer into one of the search strings `string1' and `string2' into an offset from the beginning of that string. */ #define POINTER_TO_OFFSET(ptr) \ @@ -3783,7 +3783,7 @@ weak_alias (__re_search_2, re_search_2) to actually save any registers when none are active. */ #define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) #define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) - + /* Matching routines. */ #ifndef emacs /* Emacs never uses this. */ @@ -5248,7 +5248,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) return -1; /* Failure to match. */ } /* re_match_2 */ - + /* Subroutine definitions for re_match_2. */ @@ -5511,7 +5511,7 @@ bcmp_translate (s1, s2, len, translate) } return 0; } - + /* Entry points for GNU code. */ /* re_compile_pattern is the GNU regular expression compiler: it @@ -5552,7 +5552,7 @@ re_compile_pattern (pattern, length, bufp) #ifdef _LIBC weak_alias (__re_compile_pattern, re_compile_pattern) #endif - + /* Entry points compatible with 4.2 BSD regex library. We don't define them unless specifically requested. */ @@ -5623,7 +5623,7 @@ re_exec (s) } #endif /* _REGEX_RE_COMP */ - + /* POSIX.2 functions. Don't define these for Emacs. */ #ifndef emacs diff --git a/lib/routemap.c b/lib/routemap.c index 4f4e6d620..1e1510ebd 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -28,7 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "vty.h" #include "log.h" - + /* Vector for route match rules. */ static vector route_match_vec; @@ -72,7 +72,7 @@ route_map_rule_delete (struct route_map_rule_list *, static void route_map_index_delete (struct route_map_index *, int); - + /* New route map allocation. Please note route map's name must be specified. */ static struct route_map * @@ -420,7 +420,7 @@ route_map_rule_new (void) new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule)); return new; } - + /* Install rule command to the match list. */ void route_map_install_match (struct route_map_rule_cmd *cmd) @@ -898,7 +898,7 @@ route_map_finish (void) vector_free (route_set_vec); route_set_vec = NULL; } - + /* VTY related functions. */ DEFUN (route_map, route_map_cmd, diff --git a/lib/smux.c b/lib/smux.c index 074664001..70be49289 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -78,7 +78,7 @@ struct subtree enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ}; void smux_event (enum smux_event, int); - + /* SMUX socket. */ int smux_sock = -1; @@ -114,7 +114,7 @@ static struct cmd_node smux_node = /* thread master */ static struct thread_master *master; - + static int oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len) { @@ -132,7 +132,7 @@ oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len) return 0; } - + static void smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len) { @@ -1230,7 +1230,7 @@ smux_stop (void) smux_sock = -1; } } - + void @@ -1251,7 +1251,7 @@ smux_event (enum smux_event event, int sock) break; } } - + static int smux_str2oid (const char *str, oid *oid, size_t *oid_len) { diff --git a/lib/stream.c b/lib/stream.c index 9a6fcbcf2..0fc3c3b11 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -196,7 +196,7 @@ stream_resize (struct stream *s, size_t newsize) return s->size; } - + size_t stream_get_getp (struct stream *s) { @@ -285,7 +285,7 @@ stream_forward_endp (struct stream *s, size_t size) s->endp += size; } - + /* Copy from stream to destination. */ void stream_get (void *dst, struct stream *s, size_t size) @@ -492,7 +492,7 @@ stream_get_ipv4 (struct stream *s) return l; } - + /* Copy to source to stream. * * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap @@ -731,7 +731,7 @@ stream_put_prefix (struct stream *s, struct prefix *p) return psize; } - + /* Read size from fd. */ int stream_read (struct stream *s, int fd, size_t size) @@ -937,7 +937,7 @@ stream_flush (struct stream *s, int fd) return nbytes; } - + /* Stream first in first out queue. */ struct stream_fifo * diff --git a/lib/table.c b/lib/table.c index 19b5d1b18..220e9b81e 100644 --- a/lib/table.c +++ b/lib/table.c @@ -29,7 +29,7 @@ static void route_node_delete (struct route_node *); static void route_table_free (struct route_table *); - + /* * route_table_init_with_delegate diff --git a/lib/thread.c b/lib/thread.c index e2a37b149..468edd90c 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -45,7 +45,7 @@ extern int agentx_enabled; #include #endif - + /* Recent absolute time of day */ struct timeval recent_time; static struct timeval last_recent_time; @@ -54,9 +54,9 @@ static struct timeval relative_time; static struct timeval relative_time_base; /* init flag */ static unsigned short timers_inited; - + static struct hash *cpu_record = NULL; - + /* Struct timeval's tv_usec one second value. */ #define TIMER_SECOND_MICRO 1000000L @@ -108,7 +108,7 @@ timeval_elapsed (struct timeval a, struct timeval b) return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + (a.tv_usec - b.tv_usec)); } - + #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__) static void quagga_gettimeofday_relative_adjust (void) @@ -247,7 +247,7 @@ recent_relative_time (void) { return relative_time; } - + static unsigned int cpu_record_hash_key (struct cpu_thread_history *a) { @@ -496,7 +496,7 @@ DEFUN(clear_thread_cpu, cpu_record_clear (filter); return CMD_SUCCESS; } - + static int thread_timer_cmp(void *a, void *b) { diff --git a/lib/vty.c b/lib/vty.c index 9908b0236..114135760 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -57,7 +57,7 @@ static void vty_event (enum event, int, struct vty *); /* Extern host structure from command.c */ extern struct host host; - + /* Vector which store each vty structure. */ static vector vtyvec; @@ -89,7 +89,7 @@ static u_char restricted_mode = 0; /* Integrated configuration file path */ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; - + /* VTY standard output function. */ int vty_out (struct vty *vty, const char *format, ...) @@ -455,7 +455,7 @@ vty_command (struct vty *vty, char *buf) return ret; } - + static const char telnet_backward_char = 0x08; static const char telnet_space_char = ' '; @@ -2494,7 +2494,7 @@ vty_config_unlock (struct vty *vty) } return vty->config; } - + /* Master of the threads. */ static struct thread_master *master; @@ -2551,7 +2551,7 @@ vty_event (enum event event, int sock, struct vty *vty) break; } } - + DEFUN (config_who, config_who_cmd, "who", diff --git a/lib/zclient.c b/lib/zclient.c index d3165962d..20188f6ab 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -32,7 +32,7 @@ #include "zclient.h" #include "memory.h" #include "table.h" - + /* Zebra client events. */ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; @@ -45,7 +45,7 @@ char *zclient_serv_path = NULL; /* This file local debug flag. */ int zclient_debug = 0; - + /* Allocate zclient structure. */ struct zclient * zclient_new () @@ -413,7 +413,7 @@ zclient_connect (struct thread *t) return zclient_start (zclient); } - + /* * "xdr_encode"-like interface that allows daemon (client) to send * a message to zebra server for a route that needs to be @@ -816,7 +816,7 @@ zebra_interface_address_read (int type, struct stream *s) return ifc; } - + /* Zebra client message read function. */ static int zclient_read (struct thread *thread) diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 54404ab87..bb79900e5 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -787,7 +787,7 @@ ospf6_abr_reimport (struct ospf6_area *oa) } - + /* Display functions */ static char * ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 9a4e30e14..4b4ca1304 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -288,7 +288,7 @@ ospf6_area_disable (struct ospf6_area *oa) THREAD_OFF (oa->thread_intra_prefix_lsa); } - + void ospf6_area_show (struct vty *vty, struct ospf6_area *oa) { diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index c414970b8..6ba6cdf6b 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -151,7 +151,7 @@ ospf6_as_external_lsa_originate (struct ospf6_route *route) ospf6_lsa_originate_process (lsa, ospf6); } - + void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) { @@ -342,7 +342,7 @@ ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry) } - + /* redistribute function */ static void @@ -748,7 +748,7 @@ ospf6_redistribute_show_config (struct vty *vty) } - + /* Routemap Functions */ static route_map_result_t ospf6_routemap_rule_match_address_prefixlist (void *rule, @@ -1168,7 +1168,7 @@ ospf6_routemap_init (void) install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); } - + /* Display functions */ static char * ospf6_as_external_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 4bc615518..f0ef79093 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -516,7 +516,7 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) } - + /* DR Election, RFC2328 section 9.4 */ #define IS_ELIGIBLE(n) \ @@ -673,7 +673,7 @@ dr_election (struct ospf6_interface *oi) return next_state; } - + /* Interface State Machine */ int interface_up (struct thread *thread) @@ -843,7 +843,7 @@ interface_down (struct thread *thread) return 0; } - + /* show specified interface structure */ static int ospf6_interface_show (struct vty *vty, struct interface *ifp) diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 34f752330..95a377fbb 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -142,7 +142,7 @@ extern const char *ospf6_interface_state_str[]; #define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ - + /* Function Prototypes */ extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int); diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h index e909da23d..c9660b6a5 100644 --- a/ospf6d/ospf6_intra.h +++ b/ospf6d/ospf6_intra.h @@ -153,7 +153,7 @@ struct ospf6_intra_prefix_lsa /* followed by ospf6 prefix(es) */ }; - + #define OSPF6_ROUTER_LSA_SCHEDULE(oa) \ do { \ if (! (oa)->thread_router_lsa \ diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 4aa2b12ff..2e6153557 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -658,7 +658,7 @@ ospf6_lsa_unlock (struct ospf6_lsa *lsa) ospf6_lsa_delete (lsa); } - + /* ospf6 lsa expiry */ int ospf6_lsa_expire (struct thread *thread) @@ -744,7 +744,7 @@ ospf6_lsa_refresh (struct thread *thread) return 0; } - + /* Fletcher Checksum -- Refer to RFC1008. */ @@ -790,7 +790,7 @@ ospf6_lsa_terminate (void) { vector_free (ospf6_lsa_handler_vector); } - + static char * ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) { diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index aed89df29..a85ca66dc 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -209,7 +209,7 @@ extern struct ospf6_lsa_handler unknown_handler; continue; \ } - + /* Function Prototypes */ extern const char *ospf6_lstype_name (u_int16_t type); extern const char *ospf6_lstype_short_name (u_int16_t type); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 0756ef34c..ecc96f714 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -2326,7 +2326,7 @@ ospf6_lsack_send_interface (struct thread *thread) return 0; } - + /* Commands */ DEFUN (debug_ospf6_message, debug_ospf6_message_cmd, @@ -2400,7 +2400,7 @@ ALIAS (debug_ospf6_message, "Debug only receiving message\n" ) - + DEFUN (no_debug_ospf6_message, no_debug_ospf6_message_cmd, "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index fb209fdfa..7f6c6c5cd 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -615,7 +615,7 @@ inactivity_timer (struct thread *thread) } - + /* vty functions */ /* show neighbor structure */ static void diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 888218980..65c43fd2e 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -148,7 +148,7 @@ static const char *ospf6_neighbor_event_string (int event) extern const char *ospf6_neighbor_state_str[]; - + /* Function Prototypes */ int ospf6_neighbor_cmp (void *va, void *vb); void ospf6_neighbor_dbex_init (struct ospf6_neighbor *on); diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 0526b3e1c..947834d56 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -22,7 +22,7 @@ #ifndef OSPF6_NETWORK_H #define OSPF6_NETWORK_H - + extern int ospf6_sock; extern struct in6_addr allspfrouters6; diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 5f1869ac0..9e6b33e54 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -780,7 +780,7 @@ ospf6_route_table_delete (struct ospf6_route_table *table) XFREE (MTYPE_OSPF6_ROUTE, table); } - + /* VTY commands */ void ospf6_route_show (struct vty *vty, struct ospf6_route *route) diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 8ee63fe6a..85f70647f 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -274,7 +274,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, - + DEFUN (show_zebra, show_zebra_cmd, "show zebra", @@ -602,7 +602,7 @@ ospf6_zebra_init (void) } /* Debug */ - + DEFUN (debug_ospf6_zebra_sendrecv, debug_ospf6_zebra_sendrecv_cmd, "debug ospf6 zebra (send|recv)", diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 3fdbda18e..3cdd5c116 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -77,7 +77,7 @@ route_prev (struct route_node *node) return prev; } - + /* show database functions */ DEFUN (show_version_ospf6, show_version_ospf6_cmd, diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 0c86386a7..78ae1a14b 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -127,7 +127,7 @@ extern struct thread_master *master; return CMD_SUCCESS; \ } - + /* Function Prototypes */ extern struct route_node *route_prev (struct route_node *node); diff --git a/ospfclient/COPYING b/ospfclient/COPYING index a43ea2126..b8cf3a1ab 100644 --- a/ospfclient/COPYING +++ b/ospfclient/COPYING @@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 4770275d4..4bb70b6a9 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -50,7 +50,7 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" - + static struct ospf_area_range * ospf_area_range_new (struct prefix_ipv4 *p) { diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 7e7c84fd4..7e9412c88 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -44,7 +44,7 @@ #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" - + /* Remove external route. */ void ospf_external_route_remove (struct ospf *ospf, struct prefix_ipv4 *p) @@ -96,7 +96,7 @@ ospf_external_route_lookup (struct ospf *ospf, return NULL; } - + /* Add an External info for AS-external-LSA. */ struct external_info * ospf_external_info_new (u_char type) @@ -234,7 +234,7 @@ ospf_external_info_find_lsa (struct ospf *ospf, return lsa; } - + /* Update ASBR status. */ void ospf_asbr_status_update (struct ospf *ospf, u_char status) diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 7e11e2513..ef023366a 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -143,7 +143,7 @@ unsigned long term_debug_ospf_lsa = 0; unsigned long term_debug_ospf_zebra = 0; unsigned long term_debug_ospf_nssa = 0; - + const char * ospf_redist_string(u_int route_type) @@ -218,7 +218,7 @@ ospf_if_name_string (struct ospf_interface *oi) return buf; } - + void ospf_nbr_state_message (struct ospf_neighbor *nbr, char *buf, size_t size) { @@ -746,7 +746,7 @@ ospf_packet_dump (struct stream *s) stream_set_getp (s, gp); } - + /* [no] debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) [send|recv [detail]] @@ -956,7 +956,7 @@ ALIAS (no_debug_ospf_packet, "Packet received\n" "Detail Information\n") - + DEFUN (debug_ospf_ism, debug_ospf_ism_cmd, "debug ospf ism", @@ -1058,7 +1058,7 @@ ALIAS (no_debug_ospf_ism, "ISM Event Information\n" "ISM Timer Information\n") - + DEFUN (debug_ospf_nsm, debug_ospf_nsm_cmd, "debug ospf nsm", @@ -1161,7 +1161,7 @@ ALIAS (no_debug_ospf_nsm, "NSM Event Information\n" "NSM Timer Information\n") - + DEFUN (debug_ospf_lsa, debug_ospf_lsa_cmd, "debug ospf lsa", @@ -1274,7 +1274,7 @@ ALIAS (no_debug_ospf_lsa, "LSA Install/Delete\n" "LSA Refres\n") - + DEFUN (debug_ospf_zebra, debug_ospf_zebra_cmd, "debug ospf zebra", @@ -1366,7 +1366,7 @@ ALIAS (no_debug_ospf_zebra, "OSPF Zebra information\n" "Zebra interface\n" "Zebra redistribute\n") - + DEFUN (debug_ospf_event, debug_ospf_event_cmd, "debug ospf event", @@ -1421,7 +1421,7 @@ DEFUN (no_debug_ospf_nssa, return CMD_SUCCESS; } - + DEFUN (show_debugging_ospf, show_debugging_ospf_cmd, "show debugging ospf", diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 2ebae89ac..2c33b00ef 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -49,7 +49,7 @@ #include "ospfd/ospf_dump.h" extern struct zclient *zclient; - + /* Do the LSA acking specified in table 19, Section 13.5, row 2 * This get called from ospf_flood_out_interface. Declared inline * for speed. */ @@ -757,7 +757,7 @@ ospf_flood_through (struct ospf *ospf, return (lsa_ack_flag); } - + /* Management functions for neighbor's Link State Request list. */ void @@ -835,7 +835,7 @@ ospf_ls_request_new (struct lsa_header *lsah) return new; } - + /* Management functions for neighbor's ls-retransmit list. */ unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *nbr) @@ -973,7 +973,7 @@ ospf_ls_retransmit_delete_nbr_as (struct ospf *ospf, struct ospf_lsa *lsa) ospf_ls_retransmit_delete_nbr_if (oi, lsa); } - + /* Sets ls_age to MaxAge and floods throu the area. When we implement ASE routing, there will be anothe function flushing an LSA from the whole domain. */ diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c index 6a8c3c631..b2d0faeb7 100644 --- a/ospfd/ospf_ia.c +++ b/ospfd/ospf_ia.c @@ -193,7 +193,7 @@ ospf_ia_router_route (struct ospf *ospf, struct route_table *rtrs, listnode_add (rn->info, new_or); } - + static int process_summary_lsa (struct ospf_area *area, struct route_table *rt, struct route_table *rtrs, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index a37dde12e..0f02cc821 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -49,7 +49,7 @@ #include "ospfd/ospf_snmp.h" #endif /* HAVE_SNMP */ - + int ospf_if_get_output_cost (struct ospf_interface *oi) { @@ -334,7 +334,7 @@ ospf_if_free (struct ospf_interface *oi) XFREE (MTYPE_OSPF_IF, oi); } - + /* * check if interface with given address is configured and * return it if yes. special treatment for PtP networks. @@ -489,7 +489,7 @@ ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src, return match; } - + void ospf_if_stream_set (struct ospf_interface *oi) { @@ -518,7 +518,7 @@ ospf_if_stream_unset (struct ospf_interface *oi) } } - + static struct ospf_if_params * ospf_new_if_params (void) { @@ -825,7 +825,7 @@ ospf_if_down (struct ospf_interface *oi) return 1; } - + /* Virtual Link related functions. */ struct ospf_vl_data * @@ -1194,7 +1194,7 @@ ospf_vls_in_area (struct ospf_area *area) return c; } - + struct crypt_key * ospf_crypt_key_new () { diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index fa7d97f2f..9649df8dc 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -44,7 +44,7 @@ #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_snmp.h" - + /* elect DR and BDR. Refer to RFC2319 section 9.4 */ static struct ospf_neighbor * ospf_dr_election_sub (struct list *routers) @@ -245,7 +245,7 @@ ospf_dr_election (struct ospf_interface *oi) return new_state; } - + int ospf_hello_timer (struct thread *thread) { diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 967cdb580..fef6b162f 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -50,7 +50,7 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" - + u_int32_t get_metric (u_char *metric) { @@ -61,7 +61,7 @@ get_metric (u_char *metric) return m; } - + struct timeval tv_adjust (struct timeval a) { @@ -159,7 +159,7 @@ ospf_lsa_refresh_delay (struct ospf_lsa *lsa) return delay; } - + int get_age (struct ospf_lsa *lsa) { @@ -171,7 +171,7 @@ get_age (struct ospf_lsa *lsa) return age; } - + /* Fletcher Checksum -- Refer to RFC1008. */ /* All the offsets are zero-based. The offsets in the RFC1008 are @@ -205,7 +205,7 @@ ospf_lsa_checksum_valid (struct lsa_header *lsa) } - + /* Create OSPF LSA. */ struct ospf_lsa * ospf_lsa_new () @@ -341,7 +341,7 @@ ospf_lsa_data_free (struct lsa_header *lsah) XFREE (MTYPE_OSPF_LSA_DATA, lsah); } - + /* LSA general functions. */ const char * @@ -393,7 +393,7 @@ lsa_header_set (struct stream *s, u_char options, stream_forward_endp (s, OSPF_LSA_HEADER_SIZE); } - + /* router-LSA related functions. */ /* Get router-LSA flags. */ @@ -746,7 +746,7 @@ ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area) /* Set # of links here. */ stream_putw_at (s, putp, cnt); } - + static int ospf_stub_router_timer (struct thread *t) { @@ -803,7 +803,7 @@ ospf_stub_router_check (struct ospf_area *area) OSPF_AREA_TIMER_ON (area->t_stub_router, ospf_stub_router_timer, area->ospf->stub_router_startup_time); } - + /* Create new router-LSA. */ static struct ospf_lsa * ospf_router_lsa_new (struct ospf_area *area) @@ -1005,7 +1005,7 @@ ospf_router_lsa_update (struct ospf *ospf) return 0; } - + /* network-LSA related functions. */ /* Originate Network-LSA. */ static void @@ -1184,7 +1184,7 @@ ospf_network_lsa_refresh (struct ospf_lsa *lsa) return new; } - + static void stream_put_ospf_metric (struct stream *s, u_int32_t metric_value) { @@ -1343,7 +1343,7 @@ ospf_summary_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) return new; } - + /* summary-ASBR-LSA related functions. */ static void ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, @@ -2377,7 +2377,7 @@ ospf_external_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa, return new; } - + /* LSA installation functions. */ /* Install router-LSA to an area. */ @@ -2802,7 +2802,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, return new; } - + int ospf_check_nbr_status (struct ospf *ospf) { @@ -2827,7 +2827,7 @@ ospf_check_nbr_status (struct ospf *ospf) return 1; } - + static int ospf_maxage_lsa_remover (struct thread *thread) @@ -3539,7 +3539,7 @@ ospf_lsa_unique_id (struct ospf *ospf, return id; } - + #define LSA_ACTION_FLOOD_AREA 1 #define LSA_ACTION_FLUSH_AREA 2 @@ -3602,7 +3602,7 @@ ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa) thread_add_event (master, ospf_lsa_action, data, 0); } - + /* LSA Refreshment functions. */ struct ospf_lsa * ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index aad979a74..f7cf60fd0 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -31,7 +31,7 @@ #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" - + struct ospf_lsdb * ospf_lsdb_new () { diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index c68aa4dd3..82735b731 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -132,7 +132,7 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } - + /* SIGHUP handler. */ static void sighup (void) @@ -174,7 +174,7 @@ struct quagga_signal_t ospf_signals[] = .handler = &sigint, }, }; - + /* OSPFd main routine. */ int main (int argc, char **argv) diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index bcabd5f70..0e6814e22 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -50,7 +50,7 @@ #include "ospfd/ospf_snmp.h" static void nsm_clear_adj (struct ospf_neighbor *); - + /* OSPF NSM Timer functions. */ static int ospf_inactivity_timer (struct thread *thread) @@ -156,7 +156,7 @@ nsm_should_adj (struct ospf_neighbor *nbr) return 0; } - + /* OSPF NSM functions. */ static int nsm_packet_received (struct ospf_neighbor *nbr) @@ -258,7 +258,7 @@ ospf_db_summary_clear (struct ospf_neighbor *nbr) } } - + /* The area link state database consists of the router-LSAs, network-LSAs and summary-LSAs contained in the area structure, diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index cce56fc62..efdf8263b 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -323,7 +323,7 @@ ospf_packet_max (struct ospf_interface *oi) return max; } - + static int ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh) { @@ -438,7 +438,7 @@ ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) return OSPF_AUTH_MD5_SIZE; } - + static int ospf_ls_req_timer (struct thread *thread) { @@ -2136,7 +2136,7 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh, return; } - + static struct stream * ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) { diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 1daf0d6aa..7f7b15786 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -48,7 +48,7 @@ #include "ospfd/ospf_ism.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_snmp.h" - + /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 @@ -204,7 +204,7 @@ #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR - + /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES @@ -501,7 +501,7 @@ struct variable ospf_variables[] = {OSPFAREAAGGREGATEEFFECT, INTEGER, RWRITE, ospfAreaAggregateEntry, 3, {14, 1, 6}} }; - + /* The administrative status of OSPF. When OSPF is enbled on at least one interface return 1. */ static int @@ -1407,7 +1407,7 @@ ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact, } return NULL; } - + struct list *ospf_snmp_iflist; struct ospf_snmp_if @@ -1911,7 +1911,7 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, } return NULL; } - + struct route_table *ospf_snmp_vl_table; void @@ -2127,7 +2127,7 @@ ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, } return NULL; } - + static struct ospf_neighbor * ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, unsigned int *ifindex) @@ -2360,7 +2360,7 @@ ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, } return NULL; } - + static u_char * ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) @@ -2419,7 +2419,7 @@ ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact, } return NULL; } - + static struct ospf_lsa * ospfExtLsdbLookup (struct variable *v, oid *name, size_t *length, u_char *type, struct in_addr *ls_id, struct in_addr *router_id, int exact) @@ -2572,7 +2572,7 @@ ospfExtLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, } return NULL; } - + static u_char * ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) @@ -2608,7 +2608,7 @@ ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, } return NULL; } - + /* OSPF Traps. */ #define IFSTATECHANGE 16 #define VIRTIFSTATECHANGE 1 diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index bd9564d9e..c40fc33ef 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -52,7 +52,7 @@ static void ospf_vertex_free (void *); * dynamically allocated at begin of ospf_spf_calculate */ static struct list vertex_list = { .del = ospf_vertex_free }; - + /* Heap related functions, for the managment of the candidates, to * be used with pqueue. */ static int @@ -90,7 +90,7 @@ update_stat (void *node , int position) /* Set the status of the vertex, when its position changes. */ *(v->stat) = position; } - + static struct vertex_nexthop * vertex_nexthop_new (void) { @@ -134,7 +134,7 @@ ospf_canonical_nexthops_free (struct vertex *root) vertex_nexthop_free (vp->nexthop); } } - + /* TODO: Parent list should be excised, in favour of maintaining only * vertex_nexthop, with refcounts. */ @@ -159,7 +159,7 @@ vertex_parent_free (void *p) { XFREE (MTYPE_OSPF_VERTEX_PARENT, p); } - + static struct vertex * ospf_vertex_new (struct ospf_lsa *lsa) { @@ -276,7 +276,7 @@ ospf_vertex_add_parent (struct vertex *v) listnode_add (vp->parent->children, v); } } - + static void ospf_spf_init (struct ospf_area *area) { @@ -1254,7 +1254,7 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); } - + /* Timer for SPF calculation. */ static int ospf_spf_calculate_timer (struct thread *thread) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index ee8c90190..8bfcaa829 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -49,7 +49,7 @@ #include "ospfd/ospf_vty.h" #include "ospfd/ospf_dump.h" - + static const char *ospf_network_type_str[] = { "Null", @@ -61,7 +61,7 @@ static const char *ospf_network_type_str[] = "LOOPBACK" }; - + /* Utility functions. */ static int ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) @@ -94,7 +94,7 @@ ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) return 0; } - + static int str2metric (const char *str, int *metric) { @@ -142,7 +142,7 @@ ospf_oi_count (struct interface *ifp) return i; } - + DEFUN (router_ospf, router_ospf_cmd, "router ospf", @@ -490,7 +490,7 @@ DEFUN (no_ospf_network_area, return CMD_SUCCESS; } - + DEFUN (ospf_area_range, ospf_area_range_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", @@ -634,7 +634,7 @@ ALIAS (no_ospf_area_range, "Advertise this range (default)\n" "User specified metric for this range\n" "Advertised metric for this range\n") - + DEFUN (ospf_area_range_substitute, ospf_area_range_substitute_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", @@ -686,7 +686,7 @@ DEFUN (no_ospf_area_range_substitute, return CMD_SUCCESS; } - + /* Command Handler Logic in VLink stuff is delicate!! ALTER AT YOUR OWN RISK!!!! @@ -1382,7 +1382,7 @@ ALIAS (no_ospf_area_vlink, VLINK_HELPSTR_AUTHTYPE_SIMPLE VLINK_HELPSTR_AUTH_MD5) - + DEFUN (ospf_area_shortcut, ospf_area_shortcut_cmd, "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", @@ -1450,7 +1450,7 @@ DEFUN (no_ospf_area_shortcut, return CMD_SUCCESS; } - + DEFUN (ospf_area_stub, ospf_area_stub_cmd, "area (A.B.C.D|<0-4294967295>) stub", @@ -1971,7 +1971,7 @@ DEFUN (no_ospf_area_filter_list, return CMD_SUCCESS; } - + DEFUN (ospf_area_authentication_message_digest, ospf_area_authentication_message_digest_cmd, "area (A.B.C.D|<0-4294967295>) authentication message-digest", @@ -2042,7 +2042,7 @@ DEFUN (no_ospf_area_authentication, return CMD_SUCCESS; } - + DEFUN (ospf_abr_type, ospf_abr_type_cmd, "ospf abr-type (cisco|ibm|shortcut|standard)", @@ -2206,7 +2206,7 @@ ALIAS (no_ospf_compatible_rfc1583, NO_STR "OSPF specific commands\n" "Disable the RFC1583Compatibility flag\n") - + static int ospf_timers_spf_set (struct vty *vty, unsigned int delay, unsigned int hold, @@ -2297,7 +2297,7 @@ ALIAS_DEPRECATED (no_ospf_timers_throttle_spf, NO_STR "Adjust routing timers\n" "OSPF SPF timers\n") - + DEFUN (ospf_neighbor, ospf_neighbor_cmd, "neighbor A.B.C.D", @@ -2430,7 +2430,7 @@ ALIAS (no_ospf_neighbor, "Dead Neighbor Polling interval\n" "Seconds\n") - + DEFUN (ospf_refresh_timer, ospf_refresh_timer_cmd, "refresh timer <10-1800>", "Adjust refresh parameters\n" @@ -2548,7 +2548,7 @@ const char *ospf_shortcut_mode_descr_str[] = }; - + static void show_ip_ospf_area (struct vty *vty, struct ospf_area *area) { @@ -2800,7 +2800,7 @@ DEFUN (show_ip_ospf, return CMD_SUCCESS; } - + static void show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, struct interface *ifp) @@ -3429,7 +3429,7 @@ DEFUN (show_ip_ospf_neighbor_int_detail, return CMD_SUCCESS; } - + /* Show functions */ static int show_lsa_summary (struct vty *vty, struct ospf_lsa *lsa, int self) @@ -4302,7 +4302,7 @@ ALIAS (show_ip_ospf_database_type_adv_router, OSPF_LSA_TYPES_DESC "Self-originated link states\n") - + DEFUN (ip_ospf_authentication_args, ip_ospf_authentication_args_addr_cmd, "ip ospf authentication (null|message-digest) A.B.C.D", @@ -6262,7 +6262,7 @@ ALIAS (no_ip_ospf_mtu_ignore, "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") - + DEFUN (ospf_max_metric_router_lsa_admin, ospf_max_metric_router_lsa_admin_cmd, "max-metric router-lsa administrative", @@ -6431,7 +6431,7 @@ config_write_stub_router (struct vty *vty, struct ospf *ospf) } return; } - + static void show_ip_ospf_route_network (struct vty *vty, struct route_table *rt) { @@ -6650,7 +6650,7 @@ DEFUN (show_ip_ospf_route, return CMD_SUCCESS; } - + const char *ospf_abr_type_str[] = { "unknown", @@ -6679,7 +6679,7 @@ area_id2str (char *buf, int length, struct ospf_area *area) sprintf (buf, "%lu", (unsigned long) ntohl (area->area_id.s_addr)); } - + const char *ospf_int_type_str[] = { "unknown", /* should never be used. */ @@ -7113,7 +7113,7 @@ config_write_virtual_link (struct vty *vty, struct ospf *ospf) return 0; } - + static int config_write_ospf_redistribute (struct vty *vty, struct ospf *ospf) { @@ -7406,7 +7406,7 @@ ospf_vty_show_init (void) install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd); } - + /* ospfd's interface node. */ static struct cmd_node interface_node = { @@ -7558,7 +7558,7 @@ static struct cmd_node ospf_node = 1 }; - + /* Install OSPF related vty commands. */ void ospf_vty_init (void) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index b5268a3bd..b6d3260b4 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -918,7 +918,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, return 0; } - + int ospf_distribute_list_out_set (struct ospf *ospf, int type, const char *name) diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 538bc0940..dd57f645b 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -53,7 +53,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" - + /* OSPF process wide configuration. */ static struct ospf_master ospf_master; @@ -64,7 +64,7 @@ struct ospf_master *om; extern struct zclient *zclient; extern struct in_addr router_id_zebra; - + static void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); static void ospf_network_free (struct ospf *, struct ospf_network *); static void ospf_area_free (struct ospf_area *); @@ -76,7 +76,7 @@ static int ospf_network_match_iface (const struct connected *, static void ospf_finish_final (struct ospf *); #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 - + void ospf_router_id_update (struct ospf *ospf) { @@ -139,7 +139,7 @@ ospf_router_id_update (struct ospf *ospf) ospf_if_update (ospf, ifp); } } - + /* For OSPF area sort by area id. */ static int ospf_area_id_cmp (struct ospf_area *a1, struct ospf_area *a2) @@ -279,7 +279,7 @@ ospf_get () return ospf; } - + /* Handle the second half of deferred shutdown. This is called either * from the deferred-shutdown timer thread, or directly through * ospf_deferred_shutdown_check. @@ -354,7 +354,7 @@ ospf_deferred_shutdown_check (struct ospf *ospf) timeout); return; } - + /* Shut down the entire process */ void ospf_terminate (void) @@ -563,7 +563,7 @@ ospf_finish_final (struct ospf *ospf) XFREE (MTYPE_OSPF_TOP, ospf); } - + /* allocate new OSPF Area object */ static struct ospf_area * ospf_area_new (struct ospf *ospf, struct in_addr area_id) @@ -719,7 +719,7 @@ ospf_area_del_if (struct ospf_area *area, struct ospf_interface *oi) listnode_delete (area->oiflist, oi); } - + /* Config network statement related functions. */ static struct ospf_network * ospf_network_new (struct in_addr area_id, int format) @@ -987,7 +987,7 @@ ospf_remove_vls_through_area (struct ospf *ospf, struct ospf_area *area) ospf_vl_delete (ospf, vl_data); } - + static const struct message ospf_area_type_msg[] = { { OSPF_AREA_DEFAULT, "Default" }, @@ -1350,7 +1350,7 @@ ospf_timers_refresh_unset (struct ospf *ospf) return 1; } - + static struct ospf_nbr_nbma * ospf_nbr_nbma_new (void) { diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c index 662e5843a..a267874ad 100644 --- a/ripd/rip_debug.c +++ b/ripd/rip_debug.c @@ -27,7 +27,7 @@ unsigned long rip_debug_event = 0; unsigned long rip_debug_packet = 0; unsigned long rip_debug_zebra = 0; - + DEFUN (show_debugging_rip, show_debugging_rip_cmd, "show debugging rip", diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 810b71c0d..22cef4540 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -41,7 +41,7 @@ #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" - + /* static prototypes */ static void rip_enable_apply (struct interface *); static void rip_passive_interface_apply (struct interface *); @@ -49,7 +49,7 @@ static int rip_if_down(struct interface *ifp); static int rip_enable_if_lookup (const char *ifname); static int rip_enable_network_lookup2 (struct connected *connected); static void rip_enable_apply_all (void); - + struct message ri_version_msg[] = { {RI_RIP_VERSION_1, "1"}, @@ -68,7 +68,7 @@ struct route_table *rip_enable_network; /* Vector to store passive-interface name. */ static int passive_default; /* are we in passive-interface default mode? */ vector Vrip_passive_nondefault; - + /* Join to the RIP version 2 multicast group. */ static int ipv4_multicast_join (int sock, @@ -109,7 +109,7 @@ ipv4_multicast_leave (int sock, return ret; } - + /* Allocate new RIP's interface configuration. */ static struct rip_interface * rip_interface_new (void) @@ -754,7 +754,7 @@ rip_interface_address_delete (int command, struct zclient *zclient, return 0; } - + /* Check interface is enabled by network statement. */ /* Check wether the interface has at least a connected prefix that * is within the ripng_enable_network table. */ @@ -1142,7 +1142,7 @@ rip_clean_network () vector_slot (rip_enable_interface, i) = NULL; } } - + /* Utility function for looking up passive interface settings. */ static int rip_passive_nondefault_lookup (const char *ifname) @@ -1229,7 +1229,7 @@ rip_passive_nondefault_clean (void) } rip_passive_interface_apply_all (); } - + /* RIP enable network or interface configuration. */ DEFUN (rip_network, rip_network_cmd, @@ -1913,7 +1913,7 @@ DEFUN (no_rip_passive_interface, else return rip_passive_nondefault_unset (vty, ifname); } - + /* Write rip configuration of each interface. */ static int rip_interface_config_write (struct vty *vty) diff --git a/ripd/rip_main.c b/ripd/rip_main.c index a512fbc2d..e81e61b80 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -126,7 +126,7 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); exit (status); } - + /* SIGHUP handler. */ static void sighup (void) @@ -183,7 +183,7 @@ static struct quagga_signal_t ripd_signals[] = .handler = &sigint, }, }; - + /* Main routine of ripd. */ int main (int argc, char **argv) diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index fd912ebad..6a3add640 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -32,7 +32,7 @@ /* Linked list of RIP peer. */ struct list *peer_list; - + static struct rip_peer * rip_peer_new (void) { diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index cb87ea555..37a986c50 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -32,7 +32,7 @@ #include "plist.h" #include "ripd/ripd.h" - + struct rip_metric_modifier { enum @@ -160,7 +160,7 @@ rip_route_map_update (const char *notused) } } } - + /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t @@ -323,7 +323,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; - + /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t @@ -370,7 +370,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; - + /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return @@ -416,7 +416,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = route_match_ip_address_compile, route_match_ip_address_free }; - + /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t @@ -507,7 +507,7 @@ struct route_map_rule_cmd route_match_tag_cmd = route_match_tag_compile, route_match_tag_free }; - + /* `set metric METRIC' */ /* Set metric to attribute. */ @@ -718,7 +718,7 @@ static struct route_map_rule_cmd route_set_tag_cmd = route_set_tag_compile, route_set_tag_free }; - + #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 090ebfae2..2df815b03 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -33,7 +33,7 @@ #include "smux.h" #include "ripd/ripd.h" - + /* RIPv2-MIB. */ #define RIPV2MIB 1,3,6,1,2,1,23 @@ -76,7 +76,7 @@ #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR - + /* Define SNMP local variables. */ SNMP_LOCAL_VARIABLES @@ -149,7 +149,7 @@ struct variable rip_variables[] = }; extern struct thread_master *master; - + static u_char * rip2Globals (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 199e85e8c..1f6ef6120 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -33,7 +33,7 @@ /* All information about zebra. */ struct zclient *zclient = NULL; - + /* RIPd to zebra command interface. */ void rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, @@ -196,7 +196,7 @@ rip_routemap_unset (int type, const char *name) return 0; } - + /* Redistribution types */ static struct { int type; @@ -551,7 +551,7 @@ DEFUN (no_rip_redistribute_type_metric_routemap, return CMD_WARNING; } - + /* Default information originate. */ DEFUN (rip_default_information_originate, @@ -597,7 +597,7 @@ DEFUN (no_rip_default_information_originate, return CMD_SUCCESS; } - + /* RIP configuration write function. */ static int config_write_zebra (struct vty *vty) diff --git a/ripd/ripd.c b/ripd/ripd.c index 01bd69eca..dfeb951c5 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -61,20 +61,20 @@ long rip_global_route_changes = 0; /* RIP queries. */ long rip_global_queries = 0; - + /* Prototypes. */ static void rip_event (enum rip_event, int); static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char); static int rip_triggered_update (struct thread *); static int rip_update_jitter (unsigned long); - + /* RIP output routes type. */ enum { rip_all_route, rip_changed_route }; - + /* RIP command strings. */ static const struct message rip_msg[] = { @@ -86,7 +86,7 @@ static const struct message rip_msg[] = {RIP_POLL_ENTRY, "POLL ENTRY"}, {0, NULL}, }; - + /* Utility function to set boradcast option to the socket. */ static int sockopt_broadcast (int sock) @@ -2774,7 +2774,7 @@ rip_request_send (struct sockaddr_in *to, struct interface *ifp, } return sizeof (rip_packet); } - + static int rip_update_jitter (unsigned long time) { @@ -2828,7 +2828,7 @@ rip_event (enum rip_event event, int sock) break; } } - + DEFUN (router_rip, router_rip_cmd, "router rip", @@ -3104,7 +3104,7 @@ ALIAS (no_rip_timers, "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") - + struct route_table *rip_distance_table; struct rip_distance @@ -3372,7 +3372,7 @@ DEFUN (no_rip_distance_source_access_list, rip_distance_unset (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } - + /* Print out routes update time. */ static void rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) @@ -3696,7 +3696,7 @@ static struct cmd_node rip_node = "%s(config-router)# ", 1 }; - + /* Distribute-list update functions. */ static void rip_distribute_update (struct distribute *dist) @@ -3787,7 +3787,7 @@ rip_distribute_update_all_wrapper(struct access_list *notused) { rip_distribute_update_all(NULL); } - + /* Delete all added rip route. */ void rip_clean (void) diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c index 33a7cf69f..c1eb39ba2 100644 --- a/ripngd/ripng_debug.c +++ b/ripngd/ripng_debug.c @@ -28,7 +28,7 @@ unsigned long ripng_debug_event = 0; unsigned long ripng_debug_packet = 0; unsigned long ripng_debug_zebra = 0; - + DEFUN (show_debugging_ripng, show_debugging_ripng_cmd, "show debugging ripng", diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 6718fff21..8717bfb0e 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -38,7 +38,7 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" - + /* If RFC2133 definition is used. */ #ifndef IPV6_JOIN_GROUP #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP @@ -505,7 +505,7 @@ ripng_interface_address_delete (int command, struct zclient *zclient, return 0; } - + /* RIPng enable interface vector. */ vector ripng_enable_if; @@ -812,7 +812,7 @@ ripng_enable_apply_all (void) for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_enable_apply (ifp); } - + /* Clear all network and neighbor configuration */ void ripng_clean_network () @@ -835,7 +835,7 @@ ripng_clean_network () vector_slot (ripng_enable_if, i) = NULL; } } - + /* Vector to store passive-interface name. */ vector Vripng_passive_interface; @@ -1103,7 +1103,7 @@ DEFUN (no_ripng_passive_interface, { return ripng_passive_interface_unset (vty, argv[0]); } - + static struct ripng_interface * ri_new (void) { diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 7525a2676..acc980ded 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -127,7 +127,7 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } - + /* SIGHUP handler. */ static void sighup (void) @@ -182,7 +182,7 @@ struct quagga_signal_t ripng_signals[] = .handler = &sigint, }, }; - + /* RIPngd main routine. */ int main (int argc, char **argv) diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index c04456b8a..b12e14604 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -38,7 +38,7 @@ /* Linked list of RIPng peer. */ struct list *peer_list; - + static struct ripng_peer * ripng_peer_new (void) { diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index 0f5cca350..f4fadb67e 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -29,7 +29,7 @@ #include "sockunion.h" #include "ripngd/ripngd.h" - + struct rip_metric_modifier { enum @@ -42,7 +42,7 @@ struct rip_metric_modifier u_char metric; }; - + static int ripng_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) @@ -130,7 +130,7 @@ ripng_route_set_delete (struct vty *vty, struct route_map_index *index, } return CMD_SUCCESS; } - + /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t @@ -184,7 +184,7 @@ static struct route_map_rule_cmd route_match_metric_cmd = route_match_metric_compile, route_match_metric_free }; - + /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t @@ -284,7 +284,7 @@ static struct route_map_rule_cmd route_match_tag_cmd = route_match_tag_compile, route_match_tag_free }; - + /* `set metric METRIC' */ /* Set metric to attribute. */ @@ -496,7 +496,7 @@ static struct route_map_rule_cmd route_set_tag_cmd = route_set_tag_compile, route_set_tag_free }; - + #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 8e7660626..68f37be32 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -41,7 +41,7 @@ int ripng_interface_add (int, struct zclient *, zebra_size_t); int ripng_interface_delete (int, struct zclient *, zebra_size_t); int ripng_interface_address_add (int, struct zclient *, zebra_size_t); int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); - + void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex, u_char metric) @@ -206,7 +206,7 @@ ripng_redistribute_routemap_unset (int type) ripng->route_map[type].name = NULL; ripng->route_map[type].map = NULL; } - + /* Redistribution types */ static struct { int type; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 318f600ef..941c3a068 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -95,7 +95,7 @@ ripng_info_free (struct ripng_info *rinfo) { XFREE (MTYPE_RIPNG_ROUTE, rinfo); } - + /* Create ripng socket. */ static int ripng_make_socket (void) @@ -1886,7 +1886,7 @@ ripng_request (struct interface *ifp) NULL, ifp); } - + static int ripng_update_jitter (int time) { @@ -1928,7 +1928,7 @@ ripng_event (enum ripng_event event, int sock) break; } } - + /* Print out routes update time. */ static void @@ -2767,7 +2767,7 @@ ripng_distribute_update_all_wrapper (struct access_list *notused) { ripng_distribute_update_all(NULL); } - + /* delete all the added ripng routes. */ void ripng_clean() diff --git a/tests/main.c b/tests/main.c index 2d8cb0c59..5e7bdcb15 100644 --- a/tests/main.c +++ b/tests/main.c @@ -95,8 +95,8 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } - - + + /* main routine. */ int main (int argc, char **argv) diff --git a/tests/test-checksum.c b/tests/test-checksum.c index fc4eb02d0..921b58c40 100644 --- a/tests/test-checksum.c +++ b/tests/test-checksum.c @@ -24,7 +24,7 @@ typedef uint16_t testoff_t; /* Fletcher Checksum -- Refer to RFC1008. */ #define MODX 4102 - + /* Accumulator phase of checksum */ static struct acc_vals @@ -263,7 +263,7 @@ struct reductions_t { { .name = "isisd-mody", .f = reduce_isisd_mody }, { NULL, NULL }, }; - + /* The original ospfd checksum */ static u_int16_t ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off) diff --git a/tests/test-privs.c b/tests/test-privs.c index a888ea0fc..beae81f69 100644 --- a/tests/test-privs.c +++ b/tests/test-privs.c @@ -74,7 +74,7 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } - + struct thread_master *master; /* main routine. */ int diff --git a/zebra/connected.c b/zebra/connected.c index 4802f2ba0..c4f87f4cb 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -36,7 +36,7 @@ #include "zebra/interface.h" #include "zebra/connected.h" extern struct zebra_t zebrad; - + /* communicate the withdrawal of a connected address */ static void connected_withdraw (struct connected *ifc) @@ -96,7 +96,7 @@ connected_announce (struct interface *ifp, struct connected *ifc) #endif } } - + /* If same interface address is already exist... */ struct connected * connected_check (struct interface *ifp, struct prefix *p) diff --git a/zebra/if_proc.c b/zebra/if_proc.c index 3aec530bf..2dbc47261 100644 --- a/zebra/if_proc.c +++ b/zebra/if_proc.c @@ -198,7 +198,7 @@ interface_list_proc () fclose(fp); return 0; } - + #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) #ifndef _PATH_PROC_NET_IF_INET6 diff --git a/zebra/interface.c b/zebra/interface.c index 155ee0294..7e1d3dd86 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1206,7 +1206,7 @@ ALIAS (no_bandwidth_if, NO_STR "Set bandwidth informational parameter\n" "Bandwidth in kilobits\n") - + static int ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 50525043d..0d31050c5 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -184,7 +184,7 @@ parse_irdp_packet(char *p, inet_ntoa (src)); } } - + static int irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex) { @@ -222,7 +222,7 @@ irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex) return ret; } - + int irdp_read_raw(struct thread *r) { struct interface *ifp; @@ -264,7 +264,7 @@ int irdp_read_raw(struct thread *r) return ret; } - + void send_packet(struct interface *ifp, struct stream *s, diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 37b2ae231..3dbeb98bc 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -252,7 +252,7 @@ af_check (int family) #endif /* HAVE_IPV6 */ return 0; } - + /* Dump routing table flag for debug purpose. */ static void rtm_flag_dump (int flag) @@ -557,7 +557,7 @@ ifm_read (struct if_msghdr *ifm) return 0; } - + /* Address read from struct ifa_msghdr. */ static void ifam_read_mesg (struct ifa_msghdr *ifm, @@ -751,7 +751,7 @@ ifam_read (struct ifa_msghdr *ifam) return 0; } - + /* Interface function for reading kernel routing table information. */ static int rtm_read_mesg (struct rt_msghdr *rtm, @@ -1128,7 +1128,7 @@ rtm_write (int message, return ZEBRA_ERR_NOERROR; } - + #include "thread.h" #include "zebra/zserv.h" diff --git a/zebra/main.c b/zebra/main.c index 523b1911c..d7f2a108b 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -151,7 +151,7 @@ usage (char *progname, int status) exit (status); } - + /* SIGHUP handler. */ static void sighup (void) @@ -203,7 +203,7 @@ struct quagga_signal_t zebra_signals[] = .handler = &sigint, }, }; - + /* Main startup routine. */ int main (int argc, char **argv) diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c index 404a7c696..e175d1e27 100644 --- a/zebra/rt_ioctl.c +++ b/zebra/rt_ioctl.c @@ -332,7 +332,7 @@ kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET); } - + #ifdef HAVE_IPV6 /* Below is hack for GNU libc definition and Linux 2.1.X header. */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6a802f690..452ea6421 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1848,7 +1848,7 @@ kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, dest->prefixlen, gate, index, flags, table); } #endif /* HAVE_IPV6 */ - + /* Interface address modification. */ static int netlink_address (int cmd, int family, struct interface *ifp, diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 91d7b3241..21ca6da99 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -66,7 +66,7 @@ static void rtadv_event (enum rtadv_event, int); static int if_join_all_router (int, struct interface *); static int if_leave_all_router (int, struct interface *); - + /* Structure which hold status of router advertisement. */ struct rtadv { @@ -80,7 +80,7 @@ struct rtadv }; struct rtadv *rtadv = NULL; - + static struct rtadv * rtadv_new (void) { @@ -580,7 +580,7 @@ rtadv_make_socket (void) return sock; } - + static struct rtadv_prefix * rtadv_prefix_new (void) { diff --git a/zebra/test_main.c b/zebra/test_main.c index c6951729f..f98bb4199 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -103,7 +103,7 @@ usage (char *progname, int status) exit (status); } - + static unsigned int test_ifindex = 0; /* testrib commands */ @@ -149,7 +149,7 @@ test_cmd_init (void) { install_element (INTERFACE_NODE, &test_interface_state_cmd); } - + /* SIGHUP handler. */ static void sighup (void) @@ -195,7 +195,7 @@ struct quagga_signal_t zebra_signals[] = .handler = &sigint, }, }; - + /* Main startup routine. */ int main (int argc, char **argv) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8835ef37f..dc7e1ca19 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -71,7 +71,7 @@ static const struct [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, /* no entry/default: 150 */ }; - + /* Vector for routing table. */ static vector vrf_vector; @@ -176,7 +176,7 @@ vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) return vrf->stable[afi][safi]; } - + /* * nexthop_type_to_str */ @@ -1090,7 +1090,7 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) return rib->nexthop_active_num; } - + static void rib_install_kernel (struct route_node *rn, struct rib *rib) @@ -2283,7 +2283,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, route_unlock_node (rn); return 0; } - + /* Install static route into rib. */ static void static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) @@ -2596,7 +2596,7 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, return 1; } - + #ifdef HAVE_IPV6 static int rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, @@ -2857,7 +2857,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, route_unlock_node (rn); return 0; } - + /* Install static route into rib. */ static void static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) @@ -3155,7 +3155,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, return 1; } #endif /* HAVE_IPV6 */ - + /* RIB update function. */ void rib_update (void) @@ -3176,7 +3176,7 @@ rib_update (void) rib_queue_add (&zebrad, rn); } - + /* Remove all routes which comes from non main table. */ static void rib_weed_table (struct route_table *table) @@ -3205,7 +3205,7 @@ rib_weed_tables (void) rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } - + /* Delete self installed routes after zebra is relaunched. */ static void rib_sweep_table (struct route_table *table) @@ -3301,7 +3301,7 @@ rib_close (void) rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } - + /* Routing information base initialize. */ void rib_init (void) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 39c7e1bff..b0dca088b 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -123,7 +123,7 @@ zebra_route_set_delete (struct vty *vty, struct route_map_index *index, return CMD_SUCCESS; } - + /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t @@ -467,7 +467,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; - + /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t @@ -525,7 +525,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; - + /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return @@ -571,7 +571,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = route_match_ip_address_compile, route_match_ip_address_free }; - + /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t @@ -612,7 +612,7 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = route_match_ip_address_prefix_list_free }; - + /* `set src A.B.C.D' */ /* Set src. */ diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index e06e1443d..f0d3e7e58 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -34,7 +34,7 @@ #include "zebra/rib.h" #include "zebra/zserv.h" - + #define IPFWMIB 1,3,6,1,2,1,4,24 /* ipForwardTable */ @@ -78,7 +78,7 @@ #define ROWSTATUS ASN_INTEGER #define IPADDRESS ASN_IPADDRESS #define OBJECTIDENTIFIER ASN_OBJECT_ID - + extern struct zebra_t zebrad; oid ipfw_oid [] = { IPFWMIB }; @@ -130,7 +130,7 @@ struct variable zebra_variables[] = {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}} }; - + static u_char * ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index f4946f461..baa60db9a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1210,7 +1210,7 @@ DEFUN (show_ip_mroute, return CMD_SUCCESS; } - + #ifdef HAVE_IPV6 /* General fucntion for IPv6 static route. */ static int diff --git a/zebra/zserv.c b/zebra/zserv.c index 55ac6e4fb..ca17c2c6d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -42,7 +42,7 @@ #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" - + /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -51,7 +51,7 @@ extern struct zebra_t zebrad; static void zebra_event (enum event event, int sock, struct zserv *client); extern struct zebra_privs_t zserv_privs; - + static void zebra_client_close (struct zserv *client); static int @@ -661,7 +661,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) return zebra_server_send_message(client); } - + /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ int zsend_router_id_update (struct zserv *client, struct prefix *p) @@ -690,7 +690,7 @@ zsend_router_id_update (struct zserv *client, struct prefix *p) return zebra_server_send_message(client); } - + /* Register zebra server interface information. Send current all interface and address information. */ static int @@ -1539,7 +1539,7 @@ zebra_serv_un (const char *path) zebra_event (ZEBRA_SERV, sock, NULL); } - + static void zebra_event (enum event event, int sock, struct zserv *client) @@ -1558,7 +1558,7 @@ zebra_event (enum event event, int sock, struct zserv *client) break; } } - + /* Display default rtm_table for all clients. */ DEFUN (show_table, show_table_cmd, @@ -1658,7 +1658,7 @@ static struct cmd_node table_node = "", /* This node has no interface. */ 1 }; - + /* Only display ip forwarding is enabled or not. */ DEFUN (show_ip_forwarding, show_ip_forwarding_cmd, @@ -1779,7 +1779,7 @@ static struct cmd_node forwarding_node = 1 }; - + /* Initialisation of zebra and installation of commands. */ void zebra_init (void) From 2c32ee5f04191c6ffae9c19621548bc72b00e3ba Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 24 Jun 2014 07:12:01 +0200 Subject: [PATCH 0371/1342] doc: update NEWS for 0.99.23 changes --- NEWS | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/NEWS b/NEWS index d1529bc4d..57cc99f07 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,29 @@ Note: this file lists major user-visible changes only. +* Changes in Quagga 0.99.23 + +Known issues: +- [bgpd] setting an extcommunity in a route map on a route that already has + an extcommunity attribute will cause bgpd to crash. This issue will be + fixed in a followup minor release. + +User-visible changes: +- [lib] Performance enhancements on hashes and timers. +- [bgpd] New feature: iBGP TTL security. +- [bgpd] New feature: relaxed bestpath criteria for multipath and improved + display of multipath routes in "show ip bgp". Scripts parsing this output + may need to be updated. +- [bgpd] Multiprotocol peerings over IPv6 now try to find a more appropriate + IPv4 nexthop by looking at the interface. +- [ospf6d] A large amount of changes has been merged for ospf6d. Careful + evaluation prior to deployment is recommended. +- [zebra] Recursive route support has been overhauled. Scripts parsing + "show ip route" output may need adaptation. +- [zebra] IPv6 address management has been improved regarding tentative + addresses. This is visible in that a freshly configured address will not + immediately be marked as usable. +- [*] a lot of bugs have been fixed, please refer to the git log + * Changes in Quagga 0.99.22 - [bgpd] The semantics of default-originate route-map have changed. From a4b5665f76d9e907a547c85c9c4a7a656c568b9d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 24 Jun 2014 07:14:20 +0200 Subject: [PATCH 0372/1342] release: 0.99.23 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fa9e6e1f2..220124ab8 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.23-rc1, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.23, [https://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) From 2aa640bd78b64821bde9a53ecdd1e96e91b20ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 20 May 2014 08:57:26 +0300 Subject: [PATCH 0373/1342] bgpd: fix route-map comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Timo Teräs --- bgpd/bgp_routemap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 6dc88b3aa..cb5ccffd7 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -93,7 +93,7 @@ o Cisco route-map tag : (This will not be implemented by bgpd) weight : Done -o Local extention +o Local extensions set ipv6 next-hop global: Done set ipv6 next-hop local : Done @@ -1248,7 +1248,7 @@ route_set_aspath_prepend_free (void *rule) aspath_free (aspath); } -/* Set metric rule structure. */ +/* Set as-path prepend rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", @@ -1705,7 +1705,7 @@ route_set_origin_free (void *rule) XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } -/* Set metric rule structure. */ +/* Set origin rule structure. */ struct route_map_rule_cmd route_set_origin_cmd = { "origin", @@ -2191,7 +2191,7 @@ route_set_originator_id_free (void *rule) XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } -/* Set metric rule structure. */ +/* Set originator-id rule structure. */ struct route_map_rule_cmd route_set_originator_id_cmd = { "originator-id", From 9e7a53c179f6897128b24435452b5d3d0f8c715a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 24 Apr 2014 10:22:37 +0300 Subject: [PATCH 0374/1342] bgpd: implement "next-hop-self all" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As specified in: http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/iproute_bgp/command/irg-cr-book/bgp-m1.html#wp4972925610 This allows overriding next-hop for ibgp learned routes on an RR for reflected routes. Especially useful for using iBGP in DMVPN setups. See: http://blog.ipspace.net/2014/04/changes-in-ibgp-next-hop-processing.html Signed-off-by: Timo Teräs --- bgpd/bgp_route.c | 3 ++- bgpd/bgp_vty.c | 30 +++++++++++++++++++++++------- bgpd/bgpd.c | 5 ++++- bgpd/bgpd.h | 1 + doc/bgpd.texi | 8 +++++--- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f421ca5eb..232a6a1c3 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -976,7 +976,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } /* next-hop-set */ - if (transparent || reflect + if (transparent + || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL)) || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && ((p->family == AF_INET && attr->nexthop.s_addr) #ifdef HAVE_IPV6 diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3c6973b0b..a818fe7a8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2093,25 +2093,41 @@ DEFUN (no_neighbor_capability_orf_prefix, /* neighbor next-hop-self. */ DEFUN (neighbor_nexthop_self, neighbor_nexthop_self_cmd, - NEIGHBOR_CMD2 "next-hop-self", + NEIGHBOR_CMD2 "next-hop-self {all}", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 - "Disable the next hop calculation for this neighbor\n") + "Disable the next hop calculation for this neighbor\n" + "Apply also to ibgp-learned routes when acting as a route reflector\n") { - return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), - bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); + u_int32_t flags = PEER_FLAG_NEXTHOP_SELF, unset = 0; + int rc; + + /* Check if "all" is specified */ + if (argv[1] != NULL) + flags |= PEER_FLAG_NEXTHOP_SELF_ALL; + else + unset |= PEER_FLAG_NEXTHOP_SELF_ALL; + + rc = peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); + if ( rc == CMD_SUCCESS && unset ) + rc = peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), unset); + return rc; } DEFUN (no_neighbor_nexthop_self, no_neighbor_nexthop_self_cmd, - NO_NEIGHBOR_CMD2 "next-hop-self", + NO_NEIGHBOR_CMD2 "next-hop-self {all}", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 - "Disable the next hop calculation for this neighbor\n") + "Disable the next hop calculation for this neighbor\n" + "Apply also to ibgp-learned routes when acting as a route reflector\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), - bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); + bgp_node_safi (vty), + PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL); } /* neighbor remove-private-AS. */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 19b96fa93..4d374cc19 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2355,6 +2355,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset }, { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset }, { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out }, + { PEER_FLAG_NEXTHOP_SELF_ALL, 1, peer_change_reset_out }, { 0, 0, 0 } }; @@ -4990,7 +4991,9 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, /* Nexthop self. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF) && ! peer->af_group[afi][safi]) - vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE); + vty_out (vty, " neighbor %s next-hop-self%s%s", addr, + peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF_ALL) ? + " all" : "", VTY_NEWLINE); /* Remove private AS. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a1b1273ba..eae803de1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -412,6 +412,7 @@ struct peer #define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */ #define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */ #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */ +#define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */ /* MD5 password */ char *password; diff --git a/doc/bgpd.texi b/doc/bgpd.texi index cb9789bdb..de709707a 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -299,10 +299,12 @@ This command is deprecated and may be removed in a future release. Its use should be avoided. @end deffn -@deffn {BGP} {neighbor @var{peer} next-hop-self} {} -@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {} +@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {} +@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {} This command specifies an announced route's nexthop as being equivalent -to the address of the bgp router. +to the address of the bgp router if it is learned via eBGP. +If the optional keyword @code{all} is specified the modifiation is done +also for routes learned via iBGP. @end deffn @deffn {BGP} {neighbor @var{peer} update-source @var{}} {} From b304dcb8abc4e5b93f86a4024990980746e730be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 20 May 2014 09:04:49 +0300 Subject: [PATCH 0375/1342] bgpd: route-map: share aspath object compilation code where possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Timo Teräs --- bgpd/bgp_routemap.c | 72 +++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index cb5ccffd7..a0b1fb422 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -101,6 +101,26 @@ o Local extensions */ + /* generic as path object to be shared in multiple rules */ + +static void * +route_aspath_compile (const char *arg) +{ + struct aspath *aspath; + + aspath = aspath_str2aspath (arg); + if (! aspath) + return NULL; + return aspath; +} + +static void +route_aspath_free (void *rule) +{ + struct aspath *aspath = rule; + aspath_free (aspath); +} + /* 'match peer (A.B.C.D|X:X::X:X)' */ /* Compares the peer specified in the 'match peer' clause with the peer @@ -1228,33 +1248,13 @@ route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t return RMAP_OKAY; } -/* Compile function for as-path prepend. */ -static void * -route_set_aspath_prepend_compile (const char *arg) -{ - struct aspath *aspath; - - aspath = aspath_str2aspath (arg); - if (! aspath) - return NULL; - return aspath; -} - -/* Compile function for as-path prepend. */ -static void -route_set_aspath_prepend_free (void *rule) -{ - struct aspath *aspath = rule; - aspath_free (aspath); -} - /* Set as-path prepend rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", route_set_aspath_prepend, - route_set_aspath_prepend_compile, - route_set_aspath_prepend_free, + route_aspath_compile, + route_aspath_free, }; /* `set as-path exclude ASn' */ @@ -1282,37 +1282,13 @@ route_set_aspath_exclude (void *rule, struct prefix *dummy, route_map_object_t t return RMAP_OKAY; } -/* FIXME: consider using route_set_aspath_prepend_compile() and - * route_set_aspath_prepend_free(), which two below function are - * exact clones of. - */ - -/* Compile function for as-path exclude. */ -static void * -route_set_aspath_exclude_compile (const char *arg) -{ - struct aspath *aspath; - - aspath = aspath_str2aspath (arg); - if (! aspath) - return NULL; - return aspath; -} - -static void -route_set_aspath_exclude_free (void *rule) -{ - struct aspath *aspath = rule; - aspath_free (aspath); -} - /* Set ASn exlude rule structure. */ struct route_map_rule_cmd route_set_aspath_exclude_cmd = { "as-path exclude", route_set_aspath_exclude, - route_set_aspath_exclude_compile, - route_set_aspath_exclude_free, + route_aspath_compile, + route_aspath_free, }; /* `set community COMMUNITY' */ From c460e5720c1101a6da53e5b753b736ac2c7981af Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 00:54:58 +0200 Subject: [PATCH 0376/1342] bgpd: fix some bgp_update_main() attribute leaks bgp_update_main() wasn't doing anything to release attribute values set from route maps for two of its error paths. To fix, pull up the appropriate cleanup from further down and apply it here. bgp_update_rsclient() doesn't have the issue since it immediately does bgp_attr_intern() on the results from bgp_{export,import}_modifier. Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f421ca5eb..ed8464d27 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -713,11 +713,8 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) - { - /* Free newly generated AS path and community by route-map. */ - bgp_attr_flush (attr); - return RMAP_DENY; - } + /* caller has multiple error paths with bgp_attr_flush() */ + return RMAP_DENY; } return RMAP_PERMIT; } @@ -2143,10 +2140,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); - /* Apply incoming route-map. */ + /* Apply incoming route-map. + * NB: new_attr may now contain newly allocated values from route-map "set" + * commands, so we need bgp_attr_flush in the error paths, until we intern + * the attr (which takes over the memory references) */ if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "route-map;"; + bgp_attr_flush (&new_attr); goto filtered; } @@ -2160,6 +2161,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { reason = "non-connected next-hop;"; + bgp_attr_flush (&new_attr); goto filtered; } @@ -2170,6 +2172,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, || bgp_nexthop_self (&new_attr)) { reason = "martian next-hop;"; + bgp_attr_flush (&new_attr); goto filtered; } } From 73d78ea0153fd36a300be5fec2ef0fca34a67477 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 00:58:47 +0200 Subject: [PATCH 0377/1342] bgpd: remove duplicate route-map extcommunity code route_set_ecommunity_rt and _soo share almost all of their code. Let's remove one of the redundant copies. Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 59 +++++++-------------------------------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 6dc88b3aa..eb5e80f83 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1530,10 +1530,10 @@ struct route_map_rule_cmd route_set_community_delete_cmd = /* `set extcommunity rt COMMUNITY' */ -/* For community set mechanism. */ +/* For community set mechanism. Used by _rt and _soo. */ static route_map_result_t -route_set_ecommunity_rt (void *rule, struct prefix *prefix, - route_map_object_t type, void *object) +route_set_ecommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { struct ecommunity *ecom; struct ecommunity *new_ecom; @@ -1578,9 +1578,9 @@ route_set_ecommunity_rt_compile (const char *arg) return ecommunity_intern (ecom); } -/* Free function for set community. */ +/* Free function for set community. Used by _rt and _soo */ static void -route_set_ecommunity_rt_free (void *rule) +route_set_ecommunity_free (void *rule) { struct ecommunity *ecom = rule; ecommunity_unintern (&ecom); @@ -1590,46 +1590,13 @@ route_set_ecommunity_rt_free (void *rule) struct route_map_rule_cmd route_set_ecommunity_rt_cmd = { "extcommunity rt", - route_set_ecommunity_rt, + route_set_ecommunity, route_set_ecommunity_rt_compile, - route_set_ecommunity_rt_free, + route_set_ecommunity_free, }; /* `set extcommunity soo COMMUNITY' */ -/* For community set mechanism. */ -static route_map_result_t -route_set_ecommunity_soo (void *rule, struct prefix *prefix, - route_map_object_t type, void *object) -{ - struct ecommunity *ecom, *old_ecom, *new_ecom; - struct bgp_info *bgp_info; - - if (type == RMAP_BGP) - { - ecom = rule; - bgp_info = object; - - if (! ecom) - return RMAP_OKAY; - - old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; - - if (old_ecom) - new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); - else - new_ecom = ecommunity_dup (ecom); - - bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); - - if (old_ecom) - ecommunity_unintern (&old_ecom); - - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); - } - return RMAP_OKAY; -} - /* Compile function for set community. */ static void * route_set_ecommunity_soo_compile (const char *arg) @@ -1643,21 +1610,13 @@ route_set_ecommunity_soo_compile (const char *arg) return ecommunity_intern (ecom); } -/* Free function for set community. */ -static void -route_set_ecommunity_soo_free (void *rule) -{ - struct ecommunity *ecom = rule; - ecommunity_unintern (&ecom); -} - /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { "extcommunity soo", - route_set_ecommunity_soo, + route_set_ecommunity, route_set_ecommunity_soo_compile, - route_set_ecommunity_soo_free, + route_set_ecommunity_free, }; /* `set origin ORIGIN' */ From 27bf90a14670283a899b96c56dd23f8413e0973e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 00:59:01 +0200 Subject: [PATCH 0378/1342] bgpd: fix double free after extcommunity set (BZ#799) The route-map extcommunity set code was incorrectly assuming that it owns the intern'd struct ecommunity reference. In reality, the intern'd reference belongs to bgp_update_receive() and we're not supposed to touch it in the route-map code. Instead, like all the other set commands, we use a on-heap but non-intern'd ecommunity to set the new value. This is then either intern'd in bgp_update_main/_rsclient() through bgp_attr_intern(), or free'd through bgp_attr_flush(). This fixes Bugzilla #799, which is that bgpd otherwise crashes with a double free. The ecommunity got unintern'd first in the route-map set command, then in bgp_update_receive(). Debugged-by: Milan Kocian Reported-by: Florian S Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index eb5e80f83..36d177d2a 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1552,14 +1552,19 @@ route_set_ecommunity (void *rule, struct prefix *prefix, old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; if (old_ecom) - new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + { + new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + + /* old_ecom->refcnt = 1 => owned elsewhere, e.g. bgp_update_receive() + * ->refcnt = 0 => set by a previous route-map statement */ + if (!old_ecom->refcnt) + ecommunity_free (&old_ecom); + } else new_ecom = ecommunity_dup (ecom); - bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); - - if (old_ecom) - ecommunity_unintern (&old_ecom); + /* will be intern()'d or attr_flush()'d by bgp_update_main() */ + bgp_info->attr->extra->ecommunity = new_ecom; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } From f80f838b2f54738937ef1281b237710132195c44 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 01:00:51 +0200 Subject: [PATCH 0379/1342] bgpd: fix memory leak on malformed attribute When bgp_attr_parse returns BGP_ATTR_PARSE_ERROR, it may already have parsed and allocated some attributes before hitting that error. Free the attr's data before returning. Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 80651f155..65c6cac16 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1720,7 +1720,10 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, &mp_update, &mp_withdraw); if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) - return -1; + { + bgp_attr_unintern_sub (&attr); + return -1; + } } /* Logging the attribute. */ From bb02b82354a80f74706efc5e4c914b3f89fb033e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 01:01:00 +0200 Subject: [PATCH 0380/1342] bgpd: fix IP endianness in debug message inet_ntop expects network byte order. Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a1fd16545..f9fde9f0c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1110,7 +1110,7 @@ bgp_attr_nexthop (struct bgp_attr_parser_args *args) if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) { char buf[INET_ADDRSTRLEN]; - inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN); + inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, From f57000c0dbdd0e30e71b6651022392f284201e19 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Jun 2014 01:01:10 +0200 Subject: [PATCH 0381/1342] bgpd: don't send NOTIFY twice for malformed attrs Most of the attribute parsing functions were already sending a notify, let's clean up the code to make it happen only once. Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 34 ++++++++++++++++++++++------------ bgpd/bgp_attr.h | 3 +++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f9fde9f0c..fcf82551c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -794,7 +794,7 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, return BGP_ATTR_PARSE_WITHDRAW; /* default to reset */ - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Find out what is wrong with the path attribute flag bits and log the error. @@ -1483,7 +1483,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, { zlog_info ("%s: %s sent invalid length, %lu", __func__, peer->host, (unsigned long)length); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Load AFI, SAFI. */ @@ -1497,7 +1497,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, { zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", __func__, peer->host, attre->mp_nexthop_len); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Nexthop length check. */ @@ -1540,14 +1540,14 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!LEN_LEFT) { zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, peer->host); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } { @@ -1563,7 +1563,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, { zlog_info ("%s: (%s) Failed to read NLRI", __func__, peer->host); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (safi != SAFI_MPLS_LABELED_VPN) @@ -1573,7 +1573,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", __func__, peer->host); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } } @@ -1605,7 +1605,7 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, #define BGP_MP_UNREACH_MIN_SIZE 3 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; afi = stream_getw (s); safi = stream_getc (s); @@ -1616,7 +1616,7 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); if (ret < 0) - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } mp_withdraw->afi = afi; @@ -1913,6 +1913,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, break; } + if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) + { + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + ret = BGP_ATTR_PARSE_ERROR; + } + /* If hard error occured immediately return to the caller. */ if (ret == BGP_ATTR_PARSE_ERROR) { @@ -1920,9 +1928,6 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, "%s: Attribute %s, parse error", peer->host, LOOKUP (attr_str, type)); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); if (as4_path) aspath_unintern (&as4_path); return ret; @@ -1979,9 +1984,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. */ + /* actually... this doesn't ever return failure currently, but + * better safe than sorry */ if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, as4_aggregator, &as4_aggregator_addr)) { + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index cdd54674b..cb401e711 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -136,6 +136,9 @@ typedef enum { BGP_ATTR_PARSE_PROCEED = 0, BGP_ATTR_PARSE_ERROR = -1, BGP_ATTR_PARSE_WITHDRAW = -2, + + /* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR */ + BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3, } bgp_attr_parse_ret_t; /* Prototypes. */ From 342a31bfda21616209366679ac522471e5772a2f Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Wed, 25 Jun 2014 07:43:15 +0000 Subject: [PATCH 0382/1342] ripd: use only one constant for derivation RIP_MAX_RTE is defined in ripd.h as 25 but is in fact the result of a formula. More over it is not used in the code: the code itself includes the fomula. This makes it un-clear for maintenance. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: David Lamparter --- ripd/ripd.c | 2 +- ripd/ripd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index dfeb951c5..8a7fef875 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2169,7 +2169,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, /* Reset stream and RTE counter. */ stream_reset (s); - rtemax = (RIP_PACKET_MAXSIZ - 4) / 20; + rtemax = RIP_MAX_RTE; /* Get RIP interface. */ ri = ifc->ifp->info; diff --git a/ripd/ripd.h b/ripd/ripd.h index 45b07b9cb..0fc2fd375 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -49,7 +49,7 @@ #define RIP_RTE_SIZE 20 /* Max count of routing table entry in one rip packet. */ -#define RIP_MAX_RTE 25 +#define RIP_MAX_RTE ((RIP_PACKET_MAXSIZ - RIP_HEADER_SIZE) / RIP_RTE_SIZE) /* RIP version 2 multicast address. */ #ifndef INADDR_RIP_GROUP From 8b16ed74fa61523c3348d2584b66a56a8ad4e350 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 6 Jul 2014 22:33:48 +0200 Subject: [PATCH 0383/1342] tests/bgpd: don't hardcode error number (fix f57000c) f57000c ("bgpd: don't send NOTIFY twice for malformed attrs") introduces BGP_ATTR_PARSE_ERROR_NOTIFYPLS as additional error code that implies the caller should sent a NOTIFY and convert it to BGP_ATTR_PARSE_ERROR. Sadly, the latter was hardcoded in bgp_mp_attr_test.c, which now didn't consider the new value to be an error. Make the testcase treat all nonzero values as error without discern. Signed-off-by: David Lamparter --- tests/bgp_mp_attr_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 177c1ad8d..aa8e485d6 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -478,7 +478,7 @@ parse_test (struct peer *peer, struct test_segment *t, int type) printf ("parsed?: %s\n", ret ? "no" : "yes"); - if (ret != t->parses) + if ((ret == 0) != (t->parses == 0)) failed++; if (tty) From 28a8cfcbc3a5cc74bb3b87981b878f8b4edc2dd6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 29 Jun 2014 13:48:18 +0200 Subject: [PATCH 0384/1342] isisd: don't require IPv4 for adjacency This was precluding isisd from IPv6-only operation; no adjacency would come up unless there was IPv4 in parallel. Reported-by: Martin Winter Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 89 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 8a92789ff..5f18135e8 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -402,6 +402,7 @@ process_p2p_hello (struct isis_circuit *circuit) u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; uint16_t pdu_len; struct tlvs tlvs; + int v4_usable = 0, v6_usable = 0; if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -518,11 +519,44 @@ process_p2p_hello (struct isis_circuit *circuit) /* * check if it's own interface ip match iih ip addrs */ - if ((found & TLVFLAG_IPV4_ADDR) == 0 || - ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) + if (found & TLVFLAG_IPV4_ADDR) + { + if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) + v4_usable = 1; + else + zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " + "in P2P IIH from %s\n", circuit->interface->name); + } +#ifndef HAVE_IPV6 + else /* !(found & TLVFLAG_IPV4_ADDR) */ + zlog_warn ("ISIS-Adj: no IPv4 in P2P IIH from %s " + "(this isisd has no IPv6)\n", circuit->interface->name); + +#else + if (found & TLVFLAG_IPV6_ADDR) + { + /* TBA: check that we have a linklocal ourselves? */ + struct listnode *node; + struct prefix_ipv6 *ip; + for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) + if (IN6_IS_ADDR_LINKLOCAL (ip)) + { + v6_usable = 1; + break; + } + + if (!v6_usable) + zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " + "in P2P IIH from %s\n", circuit->interface->name); + } + + if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) + zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", + circuit->interface->name); +#endif + + if (!v6_usable && !v4_usable) { - zlog_warn ("ISIS-Adj: No usable IP interface addresses " - "in LAN IIH from %s\n", circuit->interface->name); free_tlvs (&tlvs); return ISIS_WARNING; } @@ -859,6 +893,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) struct tlvs tlvs; u_char *snpa; struct listnode *node; + int v4_usable = 0, v6_usable = 0; if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -1045,15 +1080,49 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) /* * check if it's own interface ip match iih ip addrs */ - if ((found & TLVFLAG_IPV4_ADDR) == 0 || - ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) + if (found & TLVFLAG_IPV4_ADDR) { - zlog_debug ("ISIS-Adj: No usable IP interface addresses " - "in LAN IIH from %s\n", circuit->interface->name); - retval = ISIS_WARNING; - goto out; + if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) + v4_usable = 1; + else + zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " + "in LAN IIH from %s\n", circuit->interface->name); + } +#ifndef HAVE_IPV6 + else /* !(found & TLVFLAG_IPV4_ADDR) */ + zlog_warn ("ISIS-Adj: no IPv4 in LAN IIH from %s " + "(this isisd has no IPv6)\n", circuit->interface->name); + +#else + if (found & TLVFLAG_IPV6_ADDR) + { + /* TBA: check that we have a linklocal ourselves? */ + struct listnode *node; + struct prefix_ipv6 *ip; + for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) + if (IN6_IS_ADDR_LINKLOCAL (ip)) + { + v6_usable = 1; + break; + } + + if (!v6_usable) + zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " + "in LAN IIH from %s\n", circuit->interface->name); } + if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) + zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", + circuit->interface->name); +#endif + + if (!v6_usable && !v4_usable) + { + free_tlvs (&tlvs); + return ISIS_WARNING; + } + + adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]); if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) || (adj->level != level)) From 16ffb26fbbf8b3d1fee7a14eb401ecb02eed5058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 29 Jul 2014 09:41:54 +0000 Subject: [PATCH 0385/1342] *: fix detection and usage of sys/cdefs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This header is non-standard (though present on many systems) and there is no standard for what it should or should not define. Remove it where it is not really needed. But add also a configure check, so it can be used if available but otherwise fallback to defining the needed macroes. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- configure.ac | 2 +- isisd/include-netbsd/iso.h | 2 +- lib/queue.h | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 220124ab8..3dba3b357 100755 --- a/configure.ac +++ b/configure.ac @@ -442,7 +442,7 @@ dnl Check other header files. dnl ------------------------- AC_CHECK_HEADERS([stropts.h sys/ksym.h sys/times.h sys/select.h \ sys/types.h linux/version.h netdb.h asm/types.h \ - sys/param.h limits.h signal.h \ + sys/cdefs.h sys/param.h limits.h signal.h \ sys/socket.h netinet/in.h time.h sys/time.h]) dnl Utility macro to avoid retyping includes all the time diff --git a/isisd/include-netbsd/iso.h b/isisd/include-netbsd/iso.h index 1a80aec8e..42b9bc88d 100644 --- a/isisd/include-netbsd/iso.h +++ b/isisd/include-netbsd/iso.h @@ -192,7 +192,7 @@ extern struct protosw isosw[]; #else /* user utilities definitions from the iso library */ -#ifdef SUNOS_5 +#ifndef HAVE_SYS_CDEFS_H #define __P(x) x #define __BEGIN_DECLS #define __END_DECLS diff --git a/lib/queue.h b/lib/queue.h index 70cffab1b..48b363e24 100644 --- a/lib/queue.h +++ b/lib/queue.h @@ -33,8 +33,6 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ -#include - /* * This file defines four types of data structures: singly-linked lists, * singly-linked tail queues, lists and tail queues. From c299ed717eea4dbf7ca3581bcba05ff09f79276c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 29 Jul 2014 09:41:55 +0000 Subject: [PATCH 0386/1342] zebra: fix struct msghdr initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct msghdr field orders are not strictly specified in POSIX. Improve portability by using designated initializer. This fixes build against musl c-library where struct msghdr is POSIX compliant (Linux kernel and glibc definitions are non-conforming). As the result is also more readable, struct iovec initilizers were also converted. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 452ea6421..95a82fd2e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -282,9 +282,17 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), while (1) { char buf[NL_PKT_BUF_SIZE]; - struct iovec iov = { buf, sizeof buf }; + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof buf + }; struct sockaddr_nl snl; - struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; + struct msghdr msg = { + .msg_name = (void *) &snl, + .msg_namelen = sizeof snl, + .msg_iov = &iov, + .msg_iovlen = 1 + }; struct nlmsghdr *h; status = recvmsg (nl->sock, &msg, 0); @@ -1312,8 +1320,16 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) { int status; struct sockaddr_nl snl; - struct iovec iov = { (void *) n, n->nlmsg_len }; - struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; + struct iovec iov = { + .iov_base = (void *) n, + .iov_len = n->nlmsg_len + }; + struct msghdr msg = { + .msg_name = (void *) &snl, + .msg_namelen = sizeof snl, + .msg_iov = &iov, + .msg_iovlen = 1, + }; int save_errno; memset (&snl, 0, sizeof snl); From 3ef0b877f08344aa52367794aa4ec32b12becd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 29 Jul 2014 09:41:56 +0000 Subject: [PATCH 0387/1342] build: do not assume glibc on linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole IPv6 stack detection could need refactoring. But this fixes the linux check to not assume glibc. Fixes build against musl c-library. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 3dba3b357..f1df482b3 100755 --- a/configure.ac +++ b/configure.ac @@ -1204,21 +1204,22 @@ dnl ---------- if test "$zebra_cv_linux_ipv6" = "yes";then AC_MSG_CHECKING(for GNU libc >= 2.1) AC_DEFINE(HAVE_IPV6,1,Linux IPv6) + AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) + AC_EGREP_CPP(yes, [ #include #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 yes #endif], [glibc=yes - AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) AC_MSG_RESULT(yes)], AC_MSG_RESULT(no) ) RIPNGD="ripngd" OSPF6D="ospf6d" if test "$glibc" != "yes"; then - INCLUDES="-I/usr/inet6/include" if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then + INCLUDES="-I/usr/inet6/include" LIB_IPV6="-L/usr/inet6/lib -linet6" fi fi From 4c005e3f65a1f5b4592b1ebbac392cbb1a710998 Mon Sep 17 00:00:00 2001 From: John Glotzer Date: Mon, 4 Aug 2014 19:39:23 +0000 Subject: [PATCH 0388/1342] bgpd: memmove needed in community_del_val In bgpd/bgp_community_del_val memcpy is used for potentially overlapping regions which is *not* safe. It may "work" in some cases but is not guaranteed to work in all cases. The case that I saw fail was on an x86_64 architecture with the number of bytes being moved/copied equal to 8. The way the code is written the uint32_t pointers will always differ by 1, which is equivalent to a memcpy/memmove of regions that are 4 bytes away from one another. So the code failed while copying an 8 byte region to an address that is 4 bytes lower i.e. overlapping regions. Interestingly, the same architecture had no problems with a 12 byte copy. When the code failed the communities were [200,300,400] and a call was made to delete the 200 community. The result of this was an array that looked like [400,400] which was uniquified to [400]. Of course the expected result should have been [300, 400]. One additional point - in our production environment memmove would not *link* without including but in an isolated quagga git repo this #include does not seem to be required and I see memmove is used in vtysh.c without this #include either. Signed-off-by: David Lamparter --- bgpd/bgp_community.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index fc1bef88b..1bd2dd84e 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -78,7 +78,7 @@ community_del_val (struct community *com, u_int32_t *val) c = com->size -i -1; if (c > 0) - memcpy (com->val + i, com->val + (i + 1), c * sizeof (*val)); + memmove (com->val + i, com->val + (i + 1), c * sizeof (*val)); com->size--; From ad2f92b6b07883f6a2a26499eab1776933185960 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 18 Aug 2014 18:05:25 +0200 Subject: [PATCH 0389/1342] isisd: type mix-up in 28a8cfc "don't require IPv4" Whoops, these are in6_addrs, not prefix_ipv6... funnily enough, it does the right thing either way, if it compiles, which it only does on Linux because IN6_IS_ADDR_LINKLOCAL contains a cast to the right type. On BSD there is no such cast, hence it explodes on trying to compile, trying to access struct members of in6_addrs while operating on prefix_ipv6... Fixes: 28a8cfc ("isisd: don't require IPv4 for adjacency") Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 5f18135e8..e0208fa47 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -537,7 +537,7 @@ process_p2p_hello (struct isis_circuit *circuit) { /* TBA: check that we have a linklocal ourselves? */ struct listnode *node; - struct prefix_ipv6 *ip; + struct in6_addr *ip; for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) if (IN6_IS_ADDR_LINKLOCAL (ip)) { @@ -1098,7 +1098,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) { /* TBA: check that we have a linklocal ourselves? */ struct listnode *node; - struct prefix_ipv6 *ip; + struct in6_addr *ip; for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) if (IN6_IS_ADDR_LINKLOCAL (ip)) { From 90444ca35e3037ed43ec695428f0ef6d82f9a320 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 1 Jul 2014 16:14:05 +0200 Subject: [PATCH 0390/1342] lib: unset ZEBRA_IFA_PEER if no dst addr present (BZ#801) On OpenBSD, carp interfaces claim to be PtP interfaces with a 0.0.0.0/0 peer address. We process those in zebra and try to send them to clients, at which point they get encoded as all-0. The client code, however, decodes that to a NULL pointer instead of 0.0.0.0. This later turns into a SEGV when CONNECTED_PREFIX sees that ZEBRA_IFA_PEER is set and tries to access the peer prefix. This is a band-aid fix for stable/0.99.23, a long-term solution needs some conceptual improvements on the entire thing. (The usefulness of a PtP-to-0.0.0.0/0 is a separate question; at this point dropping the peer prefix seems the least intrusive solution.) Reported-by: Laurent Lavaud Signed-off-by: David Lamparter --- lib/zclient.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index 20188f6ab..3b5477e90 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -805,6 +805,16 @@ zebra_interface_address_read (int type, struct stream *s) ifc->flags = ifc_flags; if (ifc->destination) ifc->destination->prefixlen = ifc->address->prefixlen; + else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) + { + /* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */ + char buf[BUFSIZ]; + prefix2str (ifc->address, buf, sizeof(buf)); + zlog_warn("warning: interface %s address %s " + "with peer flag set, but no peer address!", + ifp->name, buf); + UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); + } } } else From b397cf4f0fc484c5ebfc8a680090055c8e6cbe32 Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Fri, 18 Jul 2014 06:13:18 +0000 Subject: [PATCH 0391/1342] ripd: add ECMP support * Each node in the routing table is changed into a list, holding the multiple equal-cost paths. * If one of the multiple entries gets less-preferred (greater metric or greater distance), it will be directly deleted instead of starting a garbage-collection timer for it. The garbage-collection timer is started only when the last entry in the list gets INFINITY. * Some new functions are used to maintain the ECMP list. And hence rip_rte_process(), rip_redistribute_add() and rip_timeout() are significantly simplified. * rip_zebra_ipv4_add() and rip_zebra_ipv4_delete() now can share the common code. The common part is moved to rip_zebra_ipv4_send(). Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: David Lamparter --- ripd/rip_interface.c | 38 +-- ripd/rip_zebra.c | 90 +++--- ripd/ripd.c | 661 ++++++++++++++++++++++++------------------- ripd/ripd.h | 8 +- 4 files changed, 442 insertions(+), 355 deletions(-) diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 22cef4540..bdd319e17 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -577,37 +577,15 @@ rip_if_down(struct interface *ifp) struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL, *nextnode = NULL; if (rip) - { - for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) - { - /* Routes got through this interface. */ - if (rinfo->ifindex == ifp->ifindex && - rinfo->type == ZEBRA_ROUTE_RIP && - rinfo->sub_type == RIP_ROUTE_RTE) - { - rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &rp->p, - &rinfo->nexthop, - rinfo->metric); - - rip_redistribute_delete (rinfo->type,rinfo->sub_type, - (struct prefix_ipv4 *)&rp->p, - rinfo->ifindex); - } - else - { - /* All redistributed routes but static and system */ - if ((rinfo->ifindex == ifp->ifindex) && - /* (rinfo->type != ZEBRA_ROUTE_STATIC) && */ - (rinfo->type != ZEBRA_ROUTE_SYSTEM)) - rip_redistribute_delete (rinfo->type,rinfo->sub_type, - (struct prefix_ipv4 *)&rp->p, - rinfo->ifindex); - } - } - } - + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo)) + if (rinfo->ifindex == ifp->ifindex) + rip_ecmp_delete (rinfo); + ri = ifp->info; if (ri->running) diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 1f6ef6120..8b1c64d6e 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -23,7 +23,9 @@ #include "command.h" #include "prefix.h" +#include "table.h" #include "stream.h" +#include "memory.h" #include "routemap.h" #include "zclient.h" #include "log.h" @@ -34,12 +36,18 @@ /* All information about zebra. */ struct zclient *zclient = NULL; -/* RIPd to zebra command interface. */ -void -rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, - u_int32_t metric, u_char distance) +/* Send ECMP routes to zebra. */ +static void +rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) { + static struct in_addr **nexthops = NULL; + static unsigned int nexthops_len = 0; + + struct list *list = (struct list *)rp->info; struct zapi_ipv4 api; + struct listnode *listnode = NULL; + struct rip_info *rinfo = NULL; + int count = 0; if (zclient->redist[ZEBRA_ROUTE_RIP]) { @@ -47,48 +55,64 @@ rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; + + if (nexthops_len < listcount (list)) + { + nexthops_len = listcount (list); + nexthops = XREALLOC (MTYPE_TMP, nexthops, + nexthops_len * sizeof (struct in_addr *)); + } + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + nexthops[count++] = &rinfo->nexthop; + if (cmd == ZEBRA_IPV4_ROUTE_ADD) + SET_FLAG (rinfo->flags, RIP_RTF_FIB); + else + UNSET_FLAG (rinfo->flags, RIP_RTF_FIB); + } + + api.nexthop = nexthops; + api.nexthop_num = count; api.ifindex_num = 0; + + rinfo = listgetdata (listhead (list)); + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; + api.metric = rinfo->metric; - if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT) - { - SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = distance; - } + if (rinfo->distance && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) + { + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = rinfo->distance; + } + + zapi_ipv4_route (cmd, zclient, + (struct prefix_ipv4 *)&rp->p, &api); - zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api); + if (IS_RIP_DEBUG_ZEBRA) + zlog_debug ("%s: %s/%d nexthops %d", + (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); rip_global_route_changes++; } } +/* Add/update ECMP routes to zebra. */ void -rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, - u_int32_t metric) +rip_zebra_ipv4_add (struct route_node *rp) { - struct zapi_ipv4 api; - - if (zclient->redist[ZEBRA_ROUTE_RIP]) - { - api.type = ZEBRA_ROUTE_RIP; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; - api.ifindex_num = 0; - SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - - zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); + rip_zebra_ipv4_send (rp, ZEBRA_IPV4_ROUTE_ADD); +} - rip_global_route_changes++; - } +/* Delete ECMP routes from zebra. */ +void +rip_zebra_ipv4_delete (struct route_node *rp) +{ + rip_zebra_ipv4_send (rp, ZEBRA_IPV4_ROUTE_DELETE); } /* Zebra route add and delete treatment. */ diff --git a/ripd/ripd.c b/ripd/ripd.c index 8a7fef875..b00241c9b 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -138,8 +138,13 @@ rip_garbage_collect (struct thread *t) rp = rinfo->rp; /* Unlock route_node. */ - rp->info = NULL; - route_unlock_node (rp); + listnode_delete (rp->info, rinfo); + if (list_isempty ((struct list *)rp->info)) + { + list_free (rp->info); + rp->info = NULL; + route_unlock_node (rp); + } /* Free RIP routing information. */ rip_info_free (rinfo); @@ -147,36 +152,149 @@ rip_garbage_collect (struct thread *t) return 0; } -/* Timeout RIP routes. */ -static int -rip_timeout (struct thread *t) +static void rip_timeout_update (struct rip_info *rinfo); + +/* Add new route to the ECMP list. + * RETURN: the new entry added in the list + */ +struct rip_info * +rip_ecmp_add (struct rip_info *rinfo_new) { - struct rip_info *rinfo; - struct route_node *rn; + struct route_node *rp = rinfo_new->rp; + struct rip_info *rinfo = NULL; + struct list *list = NULL; - rinfo = THREAD_ARG (t); - rinfo->t_timeout = NULL; + if (rp->info == NULL) + rp->info = list_new (); + list = (struct list *)rp->info; + + rinfo = rip_info_new (); + memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); + listnode_add (list, rinfo); + + if (rip_route_rte (rinfo)) + { + rip_timeout_update (rinfo); + rip_zebra_ipv4_add (rp); + } + + /* Set the route change flag on the first entry. */ + rinfo = listgetdata (listhead (list)); + SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + + /* Signal the output process to trigger an update (see section 2.5). */ + rip_event (RIP_TRIGGERED_UPDATE, 0); - rn = rinfo->rp; + return rinfo; +} + +/* Replace the ECMP list with the new route. + * RETURN: the new entry added in the list + */ +struct rip_info * +rip_ecmp_replace (struct rip_info *rinfo_new) +{ + struct route_node *rp = rinfo_new->rp; + struct list *list = (struct list *)rp->info; + struct rip_info *rinfo = NULL, *tmp_rinfo = NULL; + struct listnode *node = NULL, *nextnode = NULL; + + if (list == NULL || listcount (list) == 0) + return rip_ecmp_add (rinfo_new); + + /* Get the first entry */ + rinfo = listgetdata (listhead (list)); + + /* Learnt route replaced by a local one. Delete it from zebra. */ + if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new)) + if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) + rip_zebra_ipv4_delete (rp); + + /* Re-use the first entry, and delete the others. */ + for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) + if (tmp_rinfo != rinfo) + { + RIP_TIMER_OFF (tmp_rinfo->t_timeout); + RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); + list_delete_node (list, node); + rip_info_free (tmp_rinfo); + } - /* - The garbage-collection timer is set for 120 seconds. */ - RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, - rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); - rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop, - rinfo->metric); - /* - The metric for the route is set to 16 (infinity). This causes - the route to be removed from service. */ - rinfo->metric = RIP_METRIC_INFINITY; - rinfo->flags &= ~RIP_RTF_FIB; + if (rip_route_rte (rinfo)) + { + rip_timeout_update (rinfo); + /* The ADD message implies an update. */ + rip_zebra_ipv4_add (rp); + } - /* - The route change flag is to indicate that this entry has been - changed. */ - rinfo->flags |= RIP_RTF_CHANGED; + /* Set the route change flag. */ + SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); - /* - The output process is signalled to trigger a response. */ + /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); + return rinfo; +} + +/* Delete one route from the ECMP list. + * RETURN: + * null - the entry is freed, and other entries exist in the list + * the entry - the entry is the last one in the list; its metric is set + * to INFINITY, and the garbage collector is started for it + */ +struct rip_info * +rip_ecmp_delete (struct rip_info *rinfo) +{ + struct route_node *rp = rinfo->rp; + struct list *list = (struct list *)rp->info; + + RIP_TIMER_OFF (rinfo->t_timeout); + + if (listcount (list) > 1) + { + /* Some other ECMP entries still exist. Just delete this entry. */ + RIP_TIMER_OFF (rinfo->t_garbage_collect); + listnode_delete (list, rinfo); + if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) + /* The ADD message implies the update. */ + rip_zebra_ipv4_add (rp); + rip_info_free (rinfo); + rinfo = NULL; + } + else + { + assert (rinfo == listgetdata (listhead (list))); + + /* This is the only entry left in the list. We must keep it in + * the list for garbage collection time, with INFINITY metric. */ + + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + + if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) + rip_zebra_ipv4_delete (rp); + } + + /* Set the route change flag on the first entry. */ + rinfo = listgetdata (listhead (list)); + SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + + /* Signal the output process to trigger an update (see section 2.5). */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + + return rinfo; +} + +/* Timeout RIP routes. */ +static int +rip_timeout (struct thread *t) +{ + rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t)); return 0; } @@ -365,13 +483,13 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, int ret; struct prefix_ipv4 p; struct route_node *rp; - struct rip_info *rinfo, rinfotmp; + struct rip_info *rinfo = NULL, newinfo; struct rip_interface *ri; struct in_addr *nexthop; - u_char oldmetric; int same = 0; - int route_reuse = 0; unsigned char old_dist, new_dist; + struct list *list = NULL; + struct listnode *node = NULL; /* Make prefix structure. */ memset (&p, 0, sizeof (struct prefix_ipv4)); @@ -389,21 +507,20 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, if (ret < 0) return; + memset (&newinfo, 0, sizeof (newinfo)); + newinfo.type = ZEBRA_ROUTE_RIP; + newinfo.sub_type = RIP_ROUTE_RTE; + newinfo.nexthop = rte->nexthop; + newinfo.from = from->sin_addr; + newinfo.ifindex = ifp->ifindex; + newinfo.metric = rte->metric; + newinfo.metric_out = rte->metric; /* XXX */ + newinfo.tag = ntohs (rte->tag); /* XXX */ + /* Modify entry according to the interface routemap. */ if (ri->routemap[RIP_FILTER_IN]) { int ret; - struct rip_info newinfo; - - memset (&newinfo, 0, sizeof (newinfo)); - newinfo.type = ZEBRA_ROUTE_RIP; - newinfo.sub_type = RIP_ROUTE_RTE; - newinfo.nexthop = rte->nexthop; - newinfo.from = from->sin_addr; - newinfo.ifindex = ifp->ifindex; - newinfo.metric = rte->metric; - newinfo.metric_out = rte->metric; /* XXX */ - newinfo.tag = ntohs (rte->tag); /* XXX */ /* The object should be of the type of rip_info */ ret = route_map_apply (ri->routemap[RIP_FILTER_IN], @@ -455,8 +572,62 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, /* Get index for the prefix. */ rp = route_node_get (rip->table, (struct prefix *) &p); + newinfo.rp = rp; + newinfo.nexthop = *nexthop; + newinfo.metric = rte->metric; + newinfo.tag = ntohs (rte->tag); + newinfo.distance = rip_distance_apply (&newinfo); + + new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT; + /* Check to see whether there is already RIP route on the table. */ - rinfo = rp->info; + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) + { + /* Need to compare with redistributed entry or local entry */ + if (!rip_route_rte (rinfo)) + break; + + if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && + IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) + break; + + if (!listnextnode (node)) + { + /* Not found in the list */ + + if (rte->metric > rinfo->metric) + { + /* New route has a greater metric. Discard it. */ + route_unlock_node (rp); + return; + } + + if (rte->metric < rinfo->metric) + /* New route has a smaller metric. Replace the ECMP list + * with the new one in below. */ + break; + + /* Metrics are same. We compare the distances. */ + old_dist = rinfo->distance ? \ + rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; + + if (new_dist > old_dist) + { + /* New route has a greater distance. Discard it. */ + route_unlock_node (rp); + return; + } + + if (new_dist < old_dist) + /* New route has a smaller distance. Replace the ECMP list + * with the new one in below. */ + break; + + /* Metrics and distances are both same. Keep "rinfo" null and + * the new route is added in the ECMP list in below. */ + } + } if (rinfo) { @@ -474,13 +645,6 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->metric != RIP_METRIC_INFINITY) { - /* Fill in a minimaly temporary rip_info structure, for a future - rip_distance_apply() use) */ - memset (&rinfotmp, 0, sizeof (rinfotmp)); - IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr); - rinfotmp.rp = rinfo->rp; - new_dist = rip_distance_apply (&rinfotmp); - new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT; old_dist = rinfo->distance; /* Only routes directly connected to an interface (nexthop == 0) * may have a valid NULL distance */ @@ -488,88 +652,30 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; /* If imported route does not have STRICT precedence, mark it as a ghost */ - if (new_dist > old_dist - || rte->metric == RIP_METRIC_INFINITY) - { - route_unlock_node (rp); - return; - } - else - { - RIP_TIMER_OFF (rinfo->t_timeout); - RIP_TIMER_OFF (rinfo->t_garbage_collect); - - rp->info = NULL; - if (rip_route_rte (rinfo)) - rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, - &rinfo->nexthop, rinfo->metric); - rip_info_free (rinfo); - rinfo = NULL; - route_reuse = 1; - } + if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY) + rip_ecmp_replace (&newinfo); + + route_unlock_node (rp); + return; } } if (!rinfo) { + if (rp->info) + route_unlock_node (rp); + /* Now, check to see whether there is already an explicit route for the destination prefix. If there is no such route, add this route to the routing table, unless the metric is infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIP_METRIC_INFINITY) - { - rinfo = rip_info_new (); - - /* - Setting the destination prefix and length to those in - the RTE. */ - rinfo->rp = rp; - - /* - Setting the metric to the newly calculated metric (as - described above). */ - rinfo->metric = rte->metric; - rinfo->tag = ntohs (rte->tag); - - /* - Set the next hop address to be the address of the router - from which the datagram came or the next hop address - specified by a next hop RTE. */ - IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); - IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); - rinfo->ifindex = ifp->ifindex; - - /* - Initialize the timeout for the route. If the - garbage-collection timer is running for this route, stop it - (see section 2.3 for a discussion of the timers). */ - rip_timeout_update (rinfo); - - /* - Set the route change flag. */ - rinfo->flags |= RIP_RTF_CHANGED; - - /* - Signal the output process to trigger an update (see section - 2.5). */ - rip_event (RIP_TRIGGERED_UPDATE, 0); - - /* Finally, route goes into the kernel. */ - rinfo->type = ZEBRA_ROUTE_RIP; - rinfo->sub_type = RIP_ROUTE_RTE; - - /* Set distance value. */ - rinfo->distance = rip_distance_apply (rinfo); - - rp->info = rinfo; - rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric, - rinfo->distance); - rinfo->flags |= RIP_RTF_FIB; - } - - /* Unlock temporary lock, i.e. same behaviour */ - if (route_reuse) - route_unlock_node (rp); + rip_ecmp_add (&newinfo); } else { /* Route is there but we are not sure the route is RIP or not. */ - rinfo = rp->info; /* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. @@ -578,16 +684,8 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && (rinfo->ifindex == ifp->ifindex)); - if (same) - rip_timeout_update (rinfo); - - - /* Fill in a minimaly temporary rip_info structure, for a future - rip_distance_apply() use) */ - memset (&rinfotmp, 0, sizeof (rinfotmp)); - IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr); - rinfotmp.rp = rinfo->rp; - + old_dist = rinfo->distance ? \ + rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different @@ -599,95 +697,51 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, || (rte->metric < rinfo->metric) || ((same) && (rinfo->metric == rte->metric) - && ntohs (rte->tag) != rinfo->tag) - || (rinfo->distance > rip_distance_apply (&rinfotmp)) - || ((rinfo->distance != rip_distance_apply (rinfo)) && same)) + && (newinfo.tag != rinfo->tag)) + || (old_dist > new_dist) + || ((old_dist != new_dist) && same)) { - /* - Adopt the route from the datagram. That is, put the - new metric in, and adjust the next hop address (if - necessary). */ - oldmetric = rinfo->metric; - rinfo->metric = rte->metric; - rinfo->tag = ntohs (rte->tag); - IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); - rinfo->ifindex = ifp->ifindex; - rinfo->distance = rip_distance_apply (rinfo); - - /* Should a new route to this network be established - while the garbage-collection timer is running, the - new route will replace the one that is about to be - deleted. In this case the garbage-collection timer - must be cleared. */ - - if (oldmetric == RIP_METRIC_INFINITY && - rinfo->metric < RIP_METRIC_INFINITY) + if (listcount (list) == 1) { - rinfo->type = ZEBRA_ROUTE_RIP; - rinfo->sub_type = RIP_ROUTE_RTE; - - RIP_TIMER_OFF (rinfo->t_garbage_collect); - - if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) - IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); - - rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, - rinfo->distance); - rinfo->flags |= RIP_RTF_FIB; + if (newinfo.metric != RIP_METRIC_INFINITY) + rip_ecmp_replace (&newinfo); + else + rip_ecmp_delete (rinfo); } - - /* Update nexthop and/or metric value. */ - if (oldmetric != RIP_METRIC_INFINITY) + else { - rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); - rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, - rinfo->distance); - rinfo->flags |= RIP_RTF_FIB; - - if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) - IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); - } + if (newinfo.metric < rinfo->metric) + rip_ecmp_replace (&newinfo); + else if (newinfo.metric > rinfo->metric) + rip_ecmp_delete (rinfo); + else if (new_dist < old_dist) + rip_ecmp_replace (&newinfo); + else if (new_dist > old_dist) + rip_ecmp_delete (rinfo); + else + { + int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0; - /* - Set the route change flag and signal the output process - to trigger an update. */ - rinfo->flags |= RIP_RTF_CHANGED; - rip_event (RIP_TRIGGERED_UPDATE, 0); + assert (newinfo.metric != RIP_METRIC_INFINITY); - /* - If the new metric is infinity, start the deletion - process (described above); */ - if (rinfo->metric == RIP_METRIC_INFINITY) - { - /* If the new metric is infinity, the deletion process - begins for the route, which is no longer used for - routing packets. Note that the deletion process is - started only when the metric is first set to - infinity. If the metric was already infinity, then a - new deletion process is not started. */ - if (oldmetric != RIP_METRIC_INFINITY) - { - /* - The garbage-collection timer is set for 120 seconds. */ - RIP_TIMER_ON (rinfo->t_garbage_collect, - rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + memcpy (rinfo, &newinfo, sizeof (struct rip_info)); + rip_timeout_update (rinfo); + + if (update) + rip_zebra_ipv4_add (rp); - /* - The metric for the route is set to 16 - (infinity). This causes the route to be removed - from service. */ - rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); - rinfo->flags &= ~RIP_RTF_FIB; - - /* - The route change flag is to indicate that this - entry has been changed. */ - /* - The output process is signalled to trigger a - response. */ - ; /* Above processes are already done previously. */ + /* - Set the route change flag on the first entry. */ + rinfo = listgetdata (listhead (list)); + SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + rip_event (RIP_TRIGGERED_UPDATE, 0); } } - else - { - /* otherwise, re-initialize the timeout. */ - rip_timeout_update (rinfo); - } } + else /* same & no change */ + rip_timeout_update (rinfo); + /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } @@ -1520,8 +1574,9 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, unsigned int metric, unsigned char distance) { int ret; - struct route_node *rp; - struct rip_info *rinfo; + struct route_node *rp = NULL; + struct rip_info *rinfo = NULL, newinfo; + struct list *list = NULL; /* Redistribute route */ ret = rip_destination_check (p->prefix); @@ -1530,10 +1585,21 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, rp = route_node_get (rip->table, (struct prefix *) p); - rinfo = rp->info; + memset (&newinfo, 0, sizeof (struct rip_info)); + newinfo.type = type; + newinfo.sub_type = sub_type; + newinfo.ifindex = ifindex; + newinfo.metric = 1; + newinfo.external_metric = metric; + newinfo.distance = distance; + newinfo.rp = rp; + if (nexthop) + newinfo.nexthop = *nexthop; - if (rinfo) + if ((list = rp->info) != NULL && listcount (list) != 0) { + rinfo = listgetdata (listhead (list)); + if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIP_ROUTE_INTERFACE && rinfo->metric != RIP_METRIC_INFINITY) @@ -1555,35 +1621,11 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, } } - RIP_TIMER_OFF (rinfo->t_timeout); - RIP_TIMER_OFF (rinfo->t_garbage_collect); - - if (rip_route_rte (rinfo)) - rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, - rinfo->metric); - rp->info = NULL; - rip_info_free (rinfo); - - route_unlock_node (rp); + rinfo = rip_ecmp_replace (&newinfo); + route_unlock_node (rp); } - - rinfo = rip_info_new (); - - rinfo->type = type; - rinfo->sub_type = sub_type; - rinfo->ifindex = ifindex; - rinfo->metric = 1; - rinfo->external_metric = metric; - rinfo->distance = distance; - rinfo->rp = rp; - - if (nexthop) - rinfo->nexthop = *nexthop; - - rinfo->flags |= RIP_RTF_FIB; - rp->info = rinfo; - - rinfo->flags |= RIP_RTF_CHANGED; + else + rinfo = rip_ecmp_add (&newinfo); if (IS_RIP_DEBUG_EVENT) { if (!nexthop) @@ -1596,7 +1638,6 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, ifindex2ifname(ifindex)); } - rip_event (RIP_TRIGGERED_UPDATE, 0); } @@ -1616,27 +1657,33 @@ rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, rp = route_node_lookup (rip->table, (struct prefix *) p); if (rp) { - rinfo = rp->info; + struct list *list = rp->info; - if (rinfo != NULL - && rinfo->type == type - && rinfo->sub_type == sub_type - && rinfo->ifindex == ifindex) - { - /* Perform poisoned reverse. */ - rinfo->metric = RIP_METRIC_INFINITY; - RIP_TIMER_ON (rinfo->t_garbage_collect, - rip_garbage_collect, rip->garbage_time); - RIP_TIMER_OFF (rinfo->t_timeout); - rinfo->flags |= RIP_RTF_CHANGED; + if (list != NULL && listcount (list) != 0) + { + rinfo = listgetdata (listhead (list)); + if (rinfo != NULL + && rinfo->type == type + && rinfo->sub_type == sub_type + && rinfo->ifindex == ifindex) + { + /* Perform poisoned reverse. */ + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + rinfo->flags |= RIP_RTF_CHANGED; - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]", - inet_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(ifindex)); + if (IS_RIP_DEBUG_EVENT) + zlog_debug ("Poisone %s/%d on the interface %s with an " + "infinity metric [delete]", + inet_ntoa(p->prefix), p->prefixlen, + ifindex2ifname(ifindex)); - rip_event (RIP_TRIGGERED_UPDATE, 0); - } + rip_event (RIP_TRIGGERED_UPDATE, 0); + } + } + route_unlock_node (rp); } } @@ -1718,7 +1765,7 @@ rip_request_process (struct rip_packet *packet, int size, rp = route_node_lookup (rip->table, (struct prefix *) &p); if (rp) { - rinfo = rp->info; + rinfo = listgetdata (listhead ((struct list *)rp->info)); rte->metric = htonl (rinfo->metric); route_unlock_node (rp); } @@ -2153,6 +2200,8 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, int num = 0; int rtemax; int subnetted = 0; + struct list *list = NULL; + struct listnode *listnode = NULL; /* Logging output event. */ if (IS_RIP_DEBUG_EVENT) @@ -2210,8 +2259,9 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, } for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) + if ((list = rp->info) != NULL && listcount (list) != 0) { + rinfo = listgetdata (listhead (list)); /* For RIPv1, if we are subnetted, output subnets in our network */ /* that have the same mask as the output "interface". For other */ /* networks, only the classfull version is output. */ @@ -2270,11 +2320,22 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, * (in order to handle the case when multiple subnets are * configured on the same interface). */ - if (rinfo->type == ZEBRA_ROUTE_RIP && - rinfo->ifindex == ifc->ifp->ifindex) - continue; - if (rinfo->type == ZEBRA_ROUTE_CONNECT && + int suppress = 0; + struct rip_info *tmp_rinfo = NULL; + + for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && + tmp_rinfo->ifindex == ifc->ifp->ifindex) + { + suppress = 1; + break; + } + + if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) + suppress = 1; + + if (suppress) continue; } @@ -2368,12 +2429,15 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, * (in order to handle the case when multiple subnets are * configured on the same interface). */ - if (rinfo->type == ZEBRA_ROUTE_RIP && - rinfo->ifindex == ifc->ifp->ifindex) - rinfo->metric_out = RIP_METRIC_INFINITY; - if (rinfo->type == ZEBRA_ROUTE_CONNECT && + struct rip_info *tmp_rinfo = NULL; + + for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && + tmp_rinfo->ifindex == ifc->ifp->ifindex) + rinfo->metric_out = RIP_METRIC_INFINITY; + if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) - rinfo->metric_out = RIP_METRIC_INFINITY; + rinfo->metric_out = RIP_METRIC_INFINITY; } /* Prepare preamble, auth headers, if needs be */ @@ -2593,12 +2657,18 @@ static void rip_clear_changed_flag (void) { struct route_node *rp; - struct rip_info *rinfo; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) - if (rinfo->flags & RIP_RTF_CHANGED) - rinfo->flags &= ~RIP_RTF_CHANGED; + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + /* This flag can be set only on the first entry. */ + break; + } } /* Triggered update interval timer. */ @@ -2663,14 +2733,16 @@ void rip_redistribute_withdraw (int type) { struct route_node *rp; - struct rip_info *rinfo; + struct rip_info *rinfo = NULL; + struct list *list = NULL; if (!rip) return; for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) + if ((list = rp->info) != NULL) { + rinfo = listgetdata (listhead (list)); if (rinfo->type == type && rinfo->sub_type != RIP_ROUTE_INTERFACE) { @@ -2983,12 +3055,15 @@ static void rip_update_default_metric (void) { struct route_node *np; - struct rip_info *rinfo; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; for (np = route_top (rip->table); np; np = route_next (np)) - if ((rinfo = np->info) != NULL) - if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) - rinfo->metric = rip->default_metric; + if ((list = np->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) + rinfo->metric = rip->default_metric; } #endif @@ -3427,7 +3502,9 @@ DEFUN (show_ip_rip, "Show RIP routes\n") { struct route_node *np; - struct rip_info *rinfo; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; if (! rip) return CMD_SUCCESS; @@ -3440,7 +3517,8 @@ DEFUN (show_ip_rip, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (np = route_top (rip->table); np; np = route_next (np)) - if ((rinfo = np->info) != NULL) + if ((list = np->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { int len; @@ -3794,27 +3872,30 @@ rip_clean (void) { int i; struct route_node *rp; - struct rip_info *rinfo; + struct rip_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; if (rip) { /* Clear RIP routes */ for (rp = route_top (rip->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) - { - if (rinfo->type == ZEBRA_ROUTE_RIP && - rinfo->sub_type == RIP_ROUTE_RTE) - rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, - &rinfo->nexthop, rinfo->metric); - - RIP_TIMER_OFF (rinfo->t_timeout); - RIP_TIMER_OFF (rinfo->t_garbage_collect); - - rp->info = NULL; - route_unlock_node (rp); - - rip_info_free (rinfo); - } + if ((list = rp->info) != NULL) + { + rinfo = listgetdata (listhead (list)); + if (rip_route_rte (rinfo)) + rip_zebra_ipv4_delete (rp); + + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + rip_info_free (rinfo); + } + list_delete (list); + rp->info = NULL; + route_unlock_node (rp); + } /* Cancel RIP related timers. */ RIP_TIMER_OFF (rip->t_update); diff --git a/ripd/ripd.h b/ripd/ripd.h index 0fc2fd375..0f0e2160b 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -401,8 +401,8 @@ extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, struct in_addr *, unsigned int, unsigned char); extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); extern void rip_redistribute_withdraw (int); -extern void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char); -extern void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t); +extern void rip_zebra_ipv4_add (struct route_node *); +extern void rip_zebra_ipv4_delete (struct route_node *); extern void rip_interface_multicast_set (int, struct connected *); extern void rip_distribute_update_interface (struct interface *); extern void rip_if_rmap_update_interface (struct interface *); @@ -429,6 +429,10 @@ extern void rip_redistribute_clean (void); extern void rip_ifaddr_add (struct interface *, struct connected *); extern void rip_ifaddr_delete (struct interface *, struct connected *); +extern struct rip_info *rip_ecmp_add (struct rip_info *); +extern struct rip_info *rip_ecmp_replace (struct rip_info *); +extern struct rip_info *rip_ecmp_delete (struct rip_info *); + /* There is only one rip strucutre. */ extern struct rip *rip; From 0b74a0a5db7bcf65bf68c44b547b02b1310b5cdb Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Fri, 18 Jul 2014 06:13:19 +0000 Subject: [PATCH 0392/1342] ripd: allow to enable/disable the ECMP feature Introduce a new command "[no] allow-ecmp" to enable/disable the ECMP feature in RIP. By default, ECMP is not allowed. Once ECMP is disabled, only one route entry can exist in the list. * rip_zebra.c: adjust a debugging information, which shows the number of nexthops according to whether ECMP is enabled. * ripd.c: rip_ecmp_add() will reject the new route if ECMP is not allowed and some entry already exists. A new configurable command "allow-ecmp" is added to control whether ECMP is allowed. When ECMP is disabled, rip_ecmp_disable() is called to remove the multiple nexthops. * ripd.h: Add a new member "ecmp" to "struct rip", indicating whether ECMP is allowed or not. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: David Lamparter --- ripd/rip_zebra.c | 16 ++++++--- ripd/ripd.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++- ripd/ripd.h | 3 ++ 3 files changed, 102 insertions(+), 5 deletions(-) diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 8b1c64d6e..b005ece96 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -92,10 +92,18 @@ rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) (struct prefix_ipv4 *)&rp->p, &api); if (IS_RIP_DEBUG_ZEBRA) - zlog_debug ("%s: %s/%d nexthops %d", - (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ - "Install into zebra" : "Delete from zebra", - inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); + { + if (rip->ecmp) + zlog_debug ("%s: %s/%d nexthops %d", + (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); + else + zlog_debug ("%s: %s/%d", + (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); + } rip_global_route_changes++; } diff --git a/ripd/ripd.c b/ripd/ripd.c index b00241c9b..c69ef7fc6 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -155,7 +155,8 @@ rip_garbage_collect (struct thread *t) static void rip_timeout_update (struct rip_info *rinfo); /* Add new route to the ECMP list. - * RETURN: the new entry added in the list + * RETURN: the new entry added in the list, or NULL if it is not the first + * entry and ECMP is not allowed. */ struct rip_info * rip_ecmp_add (struct rip_info *rinfo_new) @@ -168,6 +169,11 @@ rip_ecmp_add (struct rip_info *rinfo_new) rp->info = list_new (); list = (struct list *)rp->info; + /* If ECMP is not allowed and some entry already exists in the list, + * do nothing. */ + if (listcount (list) && !rip->ecmp) + return NULL; + rinfo = rip_info_new (); memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); listnode_add (list, rinfo); @@ -3448,6 +3454,80 @@ DEFUN (no_rip_distance_source_access_list, return CMD_SUCCESS; } +/* Update ECMP routes to zebra when ECMP is disabled. */ +static void +rip_ecmp_disable (void) +{ + struct route_node *rp; + struct rip_info *rinfo, *tmp_rinfo; + struct list *list; + struct listnode *node, *nextnode; + + if (!rip) + return; + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((list = rp->info) != NULL && listcount (list) > 1) + { + rinfo = listgetdata (listhead (list)); + if (!rip_route_rte (rinfo)) + continue; + + /* Drop all other entries, except the first one. */ + for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) + if (tmp_rinfo != rinfo) + { + RIP_TIMER_OFF (tmp_rinfo->t_timeout); + RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); + list_delete_node (list, node); + rip_info_free (tmp_rinfo); + } + + /* Update zebra. */ + rip_zebra_ipv4_add (rp); + + /* Set the route change flag. */ + SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + } +} + +DEFUN (rip_allow_ecmp, + rip_allow_ecmp_cmd, + "allow-ecmp", + "Allow Equal Cost MultiPath\n") +{ + if (rip->ecmp) + { + vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip->ecmp = 1; + zlog_info ("ECMP is enabled."); + return CMD_SUCCESS; +} + +DEFUN (no_rip_allow_ecmp, + no_rip_allow_ecmp_cmd, + "no allow-ecmp", + NO_STR + "Allow Equal Cost MultiPath\n") +{ + if (!rip->ecmp) + { + vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip->ecmp = 0; + zlog_info ("ECMP is disabled."); + rip_ecmp_disable (); + return CMD_SUCCESS; +} + /* Print out routes update time. */ static void rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) @@ -3755,6 +3835,10 @@ config_write_rip (struct vty *vty) rdistance->access_list ? rdistance->access_list : "", VTY_NEWLINE); + /* ECMP configuration. */ + if (rip->ecmp) + vty_out (vty, " allow-ecmp%s", VTY_NEWLINE); + /* RIP static route configuration. */ for (rn = route_top (rip->route); rn; rn = route_next (rn)) if (rn->info) @@ -4092,6 +4176,8 @@ rip_init (void) install_element (RIP_NODE, &no_rip_distance_source_cmd); install_element (RIP_NODE, &rip_distance_source_access_list_cmd); install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); + install_element (RIP_NODE, &rip_allow_ecmp_cmd); + install_element (RIP_NODE, &no_rip_allow_ecmp_cmd); /* Debug related init. */ rip_debug_init (); diff --git a/ripd/ripd.h b/ripd/ripd.h index 0f0e2160b..4f40e79ab 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -143,6 +143,9 @@ struct rip u_char distance; struct route_table *distance_table; + /* RIP ECMP flag */ + unsigned int ecmp; + /* For redistribute route map. */ struct { From 621e2aaf33d8ab73bf44b0eea3f3900135d34996 Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Fri, 11 Jul 2014 07:52:15 +0000 Subject: [PATCH 0393/1342] zebra: fix rtnh_len in the rt_netlink messages for multipath case In _netlink_route_build_multipath(): - Each time when appending a IPv4 gateway in the message, rtnh_len is increased by sizeof (struct rtattr) + 4, where we should use "bytelen" instead of the hard coding "4". - As what done for IPv4, we should increase rtnh_len accordingly along with adding a IPv6 gateway, or else the IPv6 gateways will be lost. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 95a82fd2e..f3cdcdc3f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1561,7 +1561,7 @@ _netlink_route_build_multipath( { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); - rtnh->rtnh_len += sizeof (struct rtattr) + 4; + rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; if (nexthop->src.ipv4.s_addr) *src = &nexthop->src; @@ -1580,6 +1580,7 @@ _netlink_route_build_multipath( { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); + rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " From 3493b7731b750cbc62f00be94b624a08ccccf0b2 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 18 Nov 2013 23:04:27 +0100 Subject: [PATCH 0394/1342] lib: unstupidify thread debug information the library's thread scheduling functions keep track of the thread function's name, so far so good. However, copying the compiler-provided constant into a buffer inside the thread structure is plain useless. Also, strip_funcname() was trying to support something that never happens. Instead, let's use some bytes here to track where threads are scheduled from. Another commit will print that information on crashes. Ripping out useless stuff: -64 bytes in the thread structure Re-add as const ptr: +8 bytes Extra debug info: +12 bytes Signed-off-by: David Lamparter --- lib/thread.c | 84 ++++++++++++++++++++++------------------------------ lib/thread.h | 41 +++++++++++++------------ 2 files changed, 58 insertions(+), 67 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 468edd90c..9de5f94f9 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -267,7 +267,7 @@ cpu_record_hash_alloc (struct cpu_thread_history *a) struct cpu_thread_history *new; new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history)); new->func = a->func; - strcpy(new->funcname, a->funcname); + new->funcname = a->funcname; return new; } @@ -334,7 +334,7 @@ cpu_record_print(struct vty *vty, thread_type filter) void *args[3] = {&tmp, vty, &filter}; memset(&tmp, 0, sizeof tmp); - strcpy(tmp.funcname, "TOTAL"); + tmp.funcname = "TOTAL"; tmp.types = filter; #ifdef HAVE_RUSAGE @@ -582,7 +582,6 @@ thread_add_unuse (struct thread_master *m, struct thread *thread) assert (thread->prev == NULL); assert (thread->type == THREAD_UNUSED); thread_list_add (&m->unuse, thread); - /* XXX: Should we deallocate funcname here? */ } /* Free all unused thread. */ @@ -663,35 +662,13 @@ thread_timer_remain_second (struct thread *thread) return 0; } -/* Trim blankspace and "()"s */ -void -strip_funcname (char *dest, const char *funcname) -{ - char buff[FUNCNAME_LEN]; - char tmp, *e, *b = buff; - - strncpy(buff, funcname, sizeof(buff)); - buff[ sizeof(buff) -1] = '\0'; - e = buff +strlen(buff) -1; - - /* Wont work for funcname == "Word (explanation)" */ - - while (*b == ' ' || *b == '(') - ++b; - while (*e == ' ' || *e == ')') - --e; - e++; - - tmp = *e; - *e = '\0'; - strcpy (dest, b); - *e = tmp; -} +#define debugargdef const char *funcname, const char *schedfrom, int fromln +#define debugargpass funcname, schedfrom, fromln /* Get new thread. */ static struct thread * thread_get (struct thread_master *m, u_char type, - int (*func) (struct thread *), void *arg, const char* funcname) + int (*func) (struct thread *), void *arg, debugargdef) { struct thread *thread = thread_trim_head (&m->unuse); @@ -707,7 +684,9 @@ thread_get (struct thread_master *m, u_char type, thread->arg = arg; thread->index = -1; - strip_funcname (thread->funcname, funcname); + thread->funcname = funcname; + thread->schedfrom = schedfrom; + thread->schedfrom_line = fromln; return thread; } @@ -715,7 +694,8 @@ thread_get (struct thread_master *m, u_char type, /* Add new read thread. */ struct thread * funcname_thread_add_read (struct thread_master *m, - int (*func) (struct thread *), void *arg, int fd, const char* funcname) + int (*func) (struct thread *), void *arg, int fd, + debugargdef) { struct thread *thread; @@ -727,7 +707,7 @@ funcname_thread_add_read (struct thread_master *m, return NULL; } - thread = thread_get (m, THREAD_READ, func, arg, funcname); + thread = thread_get (m, THREAD_READ, func, arg, debugargpass); FD_SET (fd, &m->readfd); thread->u.fd = fd; thread_list_add (&m->read, thread); @@ -738,7 +718,8 @@ funcname_thread_add_read (struct thread_master *m, /* Add new write thread. */ struct thread * funcname_thread_add_write (struct thread_master *m, - int (*func) (struct thread *), void *arg, int fd, const char* funcname) + int (*func) (struct thread *), void *arg, int fd, + debugargdef) { struct thread *thread; @@ -750,7 +731,7 @@ funcname_thread_add_write (struct thread_master *m, return NULL; } - thread = thread_get (m, THREAD_WRITE, func, arg, funcname); + thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass); FD_SET (fd, &m->writefd); thread->u.fd = fd; thread_list_add (&m->write, thread); @@ -763,8 +744,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m, int (*func) (struct thread *), int type, void *arg, - struct timeval *time_relative, - const char* funcname) + struct timeval *time_relative, + debugargdef) { struct thread *thread; struct pqueue *queue; @@ -776,7 +757,7 @@ funcname_thread_add_timer_timeval (struct thread_master *m, assert (time_relative); queue = ((type == THREAD_TIMER) ? m->timer : m->background); - thread = thread_get (m, type, func, arg, funcname); + thread = thread_get (m, type, func, arg, debugargpass); /* Do we need jitter here? */ quagga_get_relative (NULL); @@ -793,7 +774,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m, struct thread * funcname_thread_add_timer (struct thread_master *m, int (*func) (struct thread *), - void *arg, long timer, const char* funcname) + void *arg, long timer, + debugargdef) { struct timeval trel; @@ -803,14 +785,15 @@ funcname_thread_add_timer (struct thread_master *m, trel.tv_usec = 0; return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, - &trel, funcname); + &trel, debugargpass); } /* Add timer event thread with "millisecond" resolution */ struct thread * funcname_thread_add_timer_msec (struct thread_master *m, int (*func) (struct thread *), - void *arg, long timer, const char* funcname) + void *arg, long timer, + debugargdef) { struct timeval trel; @@ -820,15 +803,15 @@ funcname_thread_add_timer_msec (struct thread_master *m, trel.tv_usec = 1000*(timer % 1000); return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, - arg, &trel, funcname); + arg, &trel, debugargpass); } /* Add a background thread, with an optional millisec delay */ struct thread * funcname_thread_add_background (struct thread_master *m, int (*func) (struct thread *), - void *arg, long delay, - const char *funcname) + void *arg, long delay, + debugargdef) { struct timeval trel; @@ -846,19 +829,20 @@ funcname_thread_add_background (struct thread_master *m, } return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND, - arg, &trel, funcname); + arg, &trel, debugargpass); } /* Add simple event thread. */ struct thread * funcname_thread_add_event (struct thread_master *m, - int (*func) (struct thread *), void *arg, int val, const char* funcname) + int (*func) (struct thread *), void *arg, int val, + debugargdef) { struct thread *thread; assert (m != NULL); - thread = thread_get (m, THREAD_EVENT, func, arg, funcname); + thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass); thread->u.val = val; thread_list_add (&m->event, thread); @@ -1253,7 +1237,7 @@ thread_call (struct thread *thread) struct cpu_thread_history tmp; tmp.func = thread->func; - strcpy(tmp.funcname, thread->funcname); + tmp.funcname = thread->funcname; thread->hist = hash_get (cpu_record, &tmp, (void * (*) (void *))cpu_record_hash_alloc); @@ -1301,7 +1285,7 @@ funcname_thread_execute (struct thread_master *m, int (*func)(struct thread *), void *arg, int val, - const char* funcname) + debugargdef) { struct thread dummy; @@ -1313,7 +1297,11 @@ funcname_thread_execute (struct thread_master *m, dummy.func = func; dummy.arg = arg; dummy.u.val = val; - strip_funcname (dummy.funcname, funcname); + + dummy.funcname = funcname; + dummy.schedfrom = schedfrom; + dummy.schedfrom_line = fromln; + thread_call (&dummy); return NULL; diff --git a/lib/thread.h b/lib/thread.h index dbf5f25b8..a088b4729 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -64,9 +64,6 @@ struct thread_master typedef unsigned char thread_type; -/* ISO C99 maximum function name length is 63 */ -#define FUNCNAME_LEN 64 - /* Thread itself. */ struct thread { @@ -85,7 +82,9 @@ struct thread int index; /* used for timers to store position in queue */ struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ - char funcname[FUNCNAME_LEN]; + const char *funcname; + const char *schedfrom; + int schedfrom_line; }; struct cpu_thread_history @@ -100,7 +99,7 @@ struct cpu_thread_history struct time_stats cpu; #endif thread_type types; - char funcname[FUNCNAME_LEN]; + const char *funcname; }; /* Clocks supported by Quagga */ @@ -165,15 +164,17 @@ enum quagga_clkid { #define THREAD_WRITE_OFF(thread) THREAD_OFF(thread) #define THREAD_TIMER_OFF(thread) THREAD_OFF(thread) -#define thread_add_read(m,f,a,v) funcname_thread_add_read(m,f,a,v,#f) -#define thread_add_write(m,f,a,v) funcname_thread_add_write(m,f,a,v,#f) -#define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f) -#define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f) -#define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f) -#define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f) +#define debugargdef const char *funcname, const char *schedfrom, int fromln + +#define thread_add_read(m,f,a,v) funcname_thread_add_read(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_write(m,f,a,v) funcname_thread_add_write(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f,__FILE__,__LINE__) /* The 4th arg to thread_add_background is the # of milliseconds to delay. */ -#define thread_add_background(m,f,a,v) funcname_thread_add_background(m,f,a,v,#f) +#define thread_add_background(m,f,a,v) funcname_thread_add_background(m,f,a,v,#f,__FILE__,__LINE__) /* Prototypes. */ extern struct thread_master *thread_master_create (void); @@ -181,27 +182,29 @@ extern void thread_master_free (struct thread_master *); extern struct thread *funcname_thread_add_read (struct thread_master *, int (*)(struct thread *), - void *, int, const char*); + void *, int, debugargdef); extern struct thread *funcname_thread_add_write (struct thread_master *, int (*)(struct thread *), - void *, int, const char*); + void *, int, debugargdef); extern struct thread *funcname_thread_add_timer (struct thread_master *, int (*)(struct thread *), - void *, long, const char*); + void *, long, debugargdef); extern struct thread *funcname_thread_add_timer_msec (struct thread_master *, int (*)(struct thread *), - void *, long, const char*); + void *, long, debugargdef); extern struct thread *funcname_thread_add_event (struct thread_master *, int (*)(struct thread *), - void *, int, const char*); + void *, int, debugargdef); extern struct thread *funcname_thread_add_background (struct thread_master *, int (*func)(struct thread *), void *arg, long milliseconds_to_delay, - const char *funcname); + debugargdef); extern struct thread *funcname_thread_execute (struct thread_master *, int (*)(struct thread *), - void *, int, const char *); + void *, int, debugargdef); +#undef debugargdef + extern void thread_cancel (struct thread *); extern unsigned int thread_cancel_event (struct thread_master *, void *); extern struct thread *thread_fetch (struct thread_master *, struct thread *); From 615f9f18fc025757a255f936748fc1e86e922783 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 18 Nov 2013 23:52:02 +0100 Subject: [PATCH 0395/1342] lib: include thread information in backtraces now that we know what thread we're currently executing, let's add that information to SEGV / assert backtraces. Signed-off-by: David Lamparter --- lib/log.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ lib/log.h | 2 ++ lib/thread.c | 4 ++++ lib/thread.h | 4 ++++ 4 files changed, 55 insertions(+) diff --git a/lib/log.c b/lib/log.c index 1058844b7..04f8fab63 100644 --- a/lib/log.c +++ b/lib/log.c @@ -425,6 +425,40 @@ zlog_signal(int signo, const char *action NULL #endif ); + + s = buf; + if (!thread_current) + s = str_append (LOC, "no thread information available\n"); + else + { + s = str_append (LOC, "in thread "); + s = str_append (LOC, thread_current->funcname); + s = str_append (LOC, " scheduled from "); + s = str_append (LOC, thread_current->schedfrom); + s = str_append (LOC, ":"); + s = num_append (LOC, thread_current->schedfrom_line); + s = str_append (LOC, "\n"); + } + +#define DUMP(FD) write(FD, buf, s-buf); + /* If no file logging configured, try to write to fallback log file. */ + if (logfile_fd >= 0) + DUMP(logfile_fd) + if (!zlog_default) + DUMP(STDERR_FILENO) + else + { + if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) + DUMP(STDOUT_FILENO) + /* Remove trailing '\n' for monitor and syslog */ + *--s = '\0'; + if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) + vty_log_fixed(buf,s-buf); + if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) + syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart); + } +#undef DUMP + #undef PRI #undef LOC } @@ -604,6 +638,16 @@ PLOG_FUNC(plog_debug, LOG_DEBUG) #undef PLOG_FUNC +void zlog_thread_info (int log_level) +{ + if (thread_current) + zlog(NULL, log_level, "Current thread function %s, scheduled from " + "file %s, line %u", thread_current->funcname, + thread_current->schedfrom, thread_current->schedfrom_line); + else + zlog(NULL, log_level, "Current thread not known/applicable"); +} + void _zlog_assert_failed (const char *assertion, const char *file, unsigned int line, const char *function) @@ -616,6 +660,7 @@ _zlog_assert_failed (const char *assertion, const char *file, zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s", assertion,file,line,(function ? function : "?")); zlog_backtrace(LOG_CRIT); + zlog_thread_info(LOG_CRIT); abort(); } diff --git a/lib/log.h b/lib/log.h index cf247a838..f3b43ad12 100644 --- a/lib/log.h +++ b/lib/log.h @@ -132,6 +132,8 @@ extern void plog_notice (struct zlog *, const char *format, ...) extern void plog_debug (struct zlog *, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); +extern void zlog_thread_info (int log_level); + /* Set logging level for the given destination. If the log_level argument is ZLOG_DISABLED, then the destination is disabled. This function should not be used for file logging (use zlog_set_file diff --git a/lib/thread.c b/lib/thread.c index 9de5f94f9..9c3ee8238 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1217,6 +1217,8 @@ thread_getrusage (RUSAGE_T *r) #endif /* HAVE_CLOCK_MONOTONIC */ } +struct thread *thread_current = NULL; + /* We check thread consumed time. If the system has getrusage, we'll use that to get in-depth stats on the performance of the thread in addition to wall clock time stats from gettimeofday. */ @@ -1246,7 +1248,9 @@ thread_call (struct thread *thread) GETRUSAGE (&before); thread->real = before.real; + thread_current = thread; (*thread->func) (thread); + thread_current = NULL; GETRUSAGE (&after); diff --git a/lib/thread.h b/lib/thread.h index a088b4729..9743a22d1 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -234,4 +234,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, extern struct timeval recent_time; /* Similar to recent_time, but a monotonically increasing time value */ extern struct timeval recent_relative_time (void); + +/* only for use in logging functions! */ +extern struct thread *thread_current; + #endif /* _ZEBRA_THREAD_H */ From d4a8607d12e1d3f655055647f1633ec154685545 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Oct 2012 12:02:42 +0100 Subject: [PATCH 0396/1342] HACKING: remove an unneeded escape --- HACKING.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HACKING.tex b/HACKING.tex index a49113fb9..c868e7ca4 100644 --- a/HACKING.tex +++ b/HACKING.tex @@ -207,7 +207,7 @@ \section{COMMIT MESSAGES} detect loss of frob. * frob.h: (struct frob) Add DOWN state flag. -* frob.c: (frob\_change) set/clear DOWN appropriately on state change. +* frob.c: (frob_change) set/clear DOWN appropriately on state change. * bar.c: (barinate) Check frob for DOWN state. \end{verbatim}\end{quote} From ea55500409651b0f8fd2c8a02fdbf245acc96dd8 Mon Sep 17 00:00:00 2001 From: Steve Hill Date: Tue, 28 Jul 2009 16:36:14 -0400 Subject: [PATCH 0397/1342] lib: Improve error reporting from broken config files * command.h: (config_from_file) Add variable to interface for line number reporting. * command.c: (config_from_file) Set & increment 'line_num' while parsing. * vty.c: (vty_read_file) Report parse errors in the correct order to stderr, with added line numbers. --- lib/command.c | 4 +++- lib/command.h | 2 +- lib/vty.c | 23 ++++++++++++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/command.c b/lib/command.c index 7249c6530..1087ceb8d 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2762,13 +2762,15 @@ cmd_execute_command_strict (vector vline, struct vty *vty, /* Configration make from file. */ int -config_from_file (struct vty *vty, FILE *fp) +config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num) { int ret; + *line_num = 0; vector vline; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { + ++(*line_num); vline = cmd_make_strvec (vty->buf); /* In case of comment line */ diff --git a/lib/command.h b/lib/command.h index e47c42552..8dc50d0df 100644 --- a/lib/command.h +++ b/lib/command.h @@ -518,7 +518,7 @@ extern void cmd_free_strvec (vector); extern vector cmd_describe_command (vector, struct vty *, int *status); extern char **cmd_complete_command (vector, struct vty *, int *status); extern const char *cmd_prompt (enum node_type); -extern int config_from_file (struct vty *, FILE *); +extern int config_from_file (struct vty *, FILE *, unsigned int *line_num); extern enum node_type node_parent (enum node_type); extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int); extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); diff --git a/lib/vty.c b/lib/vty.c index 114135760..488f8d5fa 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2229,28 +2229,37 @@ vty_read_file (FILE *confp) { int ret; struct vty *vty; + unsigned int line_num = 0; vty = vty_new (); - vty->fd = 0; /* stdout */ - vty->type = VTY_TERM; + vty->fd = dup(STDERR_FILENO); /* vty_close() will close this */ + if (vty->fd < 0) + { + /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */ + vty->fd = STDOUT_FILENO; + } + vty->type = VTY_FILE; vty->node = CONFIG_NODE; /* Execute configuration file */ - ret = config_from_file (vty, confp); + ret = config_from_file (vty, confp, &line_num); + + /* Flush any previous errors before printing messages below */ + buffer_flush_all (vty->obuf, vty->fd); if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) { case CMD_ERR_AMBIGUOUS: - fprintf (stderr, "Ambiguous command.\n"); + fprintf (stderr, "*** Error reading config: Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: - fprintf (stderr, "There is no such command.\n"); + fprintf (stderr, "*** Error reading config: There is no such command.\n"); break; } - fprintf (stderr, "Error occured during reading below line.\n%s\n", - vty->buf); + fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n", + line_num, vty->buf); vty_close (vty); exit (1); } From 010ebbbca6396f272cc2d50d147dd922dda68213 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 16 Sep 2014 11:53:49 +0100 Subject: [PATCH 0398/1342] Add missing GPL headers, and copyright claims that certainly apply. * Fix (a subset of)? files with non-trivial code that are missing GPL headers. * A few copyright claims added which I am certain apply, but which I had missed out on the original commits. NB: Copyright claims are not exclusive and the addition of any copyright claim should not be read as implying a lack of any further claims, or denying the validity of any other claims. All those with claims of copyright over any portion of Quagga are welcome to submit them, ideally as patches to update copyright strings in files. --- lib/memtypes.awk | 21 ++++++++++++++++++++- lib/str.c | 18 ++++++++++++++++++ lib/zassert.h | 17 +++++++++++++++++ ospfclient/ospfclient.c | 18 ++++++++++++++++++ tests/aspath_test.c | 21 +++++++++++++++++++++ tests/bgp_capability_test.c | 21 +++++++++++++++++++++ tests/bgp_mp_attr_test.c | 21 +++++++++++++++++++++ tests/ecommunity_test.c | 20 ++++++++++++++++++++ tests/test-buffer.c | 21 +++++++++++++++++++++ tests/test-checksum.c | 21 +++++++++++++++++++++ tests/test-memory.c | 19 +++++++++++++++++++ tests/test-sig.c | 19 +++++++++++++++++++ tests/test-stream.c | 22 ++++++++++++++++++++++ zebra/ioctl_null.c | 21 +++++++++++++++++++++ zebra/kernel_null.c | 21 +++++++++++++++++++++ zebra/misc_null.c | 21 +++++++++++++++++++++ zebra/redistribute_null.c | 21 +++++++++++++++++++++ 17 files changed, 342 insertions(+), 1 deletion(-) diff --git a/lib/memtypes.awk b/lib/memtypes.awk index 5429f6e8e..bd13327db 100644 --- a/lib/memtypes.awk +++ b/lib/memtypes.awk @@ -1,4 +1,23 @@ -# $Id: memtypes.awk,v 1.4 2006/03/30 14:30:19 paul Exp $ +### +# Copyright (C) Paul Jakma 2005 +# +# 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. +### # # Scan a file of memory definitions (see eg memtypes.c) and generate # a corresponding header file with an enum of the MTYPE's and declarations diff --git a/lib/str.c b/lib/str.c index 4ab71e197..d8f039a09 100644 --- a/lib/str.c +++ b/lib/str.c @@ -16,6 +16,24 @@ Copyright (C) 1996, 1997, 1998, 2001, 2002 Free Software Foundation, Inc. */ +/* + * 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 diff --git a/lib/zassert.h b/lib/zassert.h index 79126760a..bf0a851ba 100644 --- a/lib/zassert.h +++ b/lib/zassert.h @@ -1,5 +1,22 @@ /* * $Id: zassert.h,v 1.2 2004/12/03 18:01:04 ajs Exp $ + * + * 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 _QUAGGA_ASSERT_H diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c index 3608ebaca..1de7644f6 100644 --- a/ospfclient/ospfclient.c +++ b/ospfclient/ospfclient.c @@ -1,3 +1,21 @@ +/* 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. + */ + /* * Simple program to demonstrate how OSPF API can be used. This * application retrieves the LSDB from the OSPF daemon and then diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 7fdb5e221..0e57c535d 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2005 Sun Microsystems, Inc. + * + * 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 #include "vty.h" diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index 65c6a7002..96f18f01f 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2007 Sun Microsystems, Inc. + * + * 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 #include "vty.h" diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index aa8e485d6..5f0e733dd 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2008 Sun Microsystems, Inc. + * + * 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 #include "vty.h" diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c index 87f20f282..cd1681d55 100644 --- a/tests/ecommunity_test.c +++ b/tests/ecommunity_test.c @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2007 Sun Microsystems, Inc. + * + * 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 #include "vty.h" diff --git a/tests/test-buffer.c b/tests/test-buffer.c index b310776f8..e95d6fb82 100644 --- a/tests/test-buffer.c +++ b/tests/test-buffer.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2004 Paul Jakma + * + * 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 #include #include diff --git a/tests/test-checksum.c b/tests/test-checksum.c index 921b58c40..9672e95a1 100644 --- a/tests/test-checksum.c +++ b/tests/test-checksum.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2008 Sun Microsystems, Inc. + * + * 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 #include #include diff --git a/tests/test-memory.c b/tests/test-memory.c index 2971160b7..807249ea6 100644 --- a/tests/test-memory.c +++ b/tests/test-memory.c @@ -1,3 +1,22 @@ +/* + * 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 #include diff --git a/tests/test-sig.c b/tests/test-sig.c index df023fac6..7415d7ae6 100644 --- a/tests/test-sig.c +++ b/tests/test-sig.c @@ -1,3 +1,22 @@ +/* + * 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 #include #include "lib/log.h" diff --git a/tests/test-stream.c b/tests/test-stream.c index 785ce5882..5997b47d3 100644 --- a/tests/test-stream.c +++ b/tests/test-stream.c @@ -1,3 +1,25 @@ +/* Simple stream test. + * + * Copyright (C) 2006 Sun Microsystems, Inc. + * + * 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 #include #include diff --git a/zebra/ioctl_null.c b/zebra/ioctl_null.c index 5d046d36d..5a8be991d 100644 --- a/zebra/ioctl_null.c +++ b/zebra/ioctl_null.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. + * + * 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 #include "zebra/rib.h" diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index cdb6e23f0..29c7881b9 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -1,5 +1,26 @@ /* NULL kernel methods for testing. */ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. + * + * 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 #include diff --git a/zebra/misc_null.c b/zebra/misc_null.c index 06807267e..b4416e635 100644 --- a/zebra/misc_null.c +++ b/zebra/misc_null.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. + * + * 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 #include "prefix.h" diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index 54198c8e6..c45ebe1db 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. + * + * 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 #include "zebra/rib.h" #include "zebra/zserv.h" From 7aa9dcef80b2ce50ecaa77653d87c8b84e009c49 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Sep 2014 14:42:23 +0100 Subject: [PATCH 0399/1342] Fix most compiler warnings in default GCC build. Fix lots of warnings. Some const and type-pun breaks strict-aliasing warnings left but much reduced. * bgp_advertise.h: (struct bgp_advertise_fifo) is functionally identical to (struct fifo), so just use that. Makes it clearer the beginning of (struct bgp_advertise) is compatible with with (struct fifo), which seems to be enough for gcc. Add a BGP_ADV_FIFO_HEAD macro to contain the right cast to try shut up type-punning breaks strict aliasing warnings. * bgp_packet.c: Use BGP_ADV_FIFO_HEAD. (bgp_route_refresh_receive) fix an interesting logic error in (!ok || (ret != BLAH)) where ret is only well-defined if ok. * bgp_vty.c: Peer commands should use bgp_vty_return to set their return. * jhash.{c,h}: Can take const on * args without adding issues & fix warnings. * libospf.h: LSA sequence numbers use the unsigned range of values, and constants need to be set to unsigned, or it causes warnings in ospf6d. * md5.h: signedness of caddr_t is implementation specific, change to an explicit (uint_8 *), fix sign/unsigned comparison warnings. * vty.c: (vty_log_fixed) const on level is well-intentioned, but not going to fly given iov_base. * workqueue.c: ALL_LIST_ELEMENTS_RO tests for null pointer, which is always true for address of static variable. Correct but pointless warning in this case, but use a 2nd pointer to shut it up. * ospf6_route.h: Add a comment about the use of (struct prefix) to stuff 2 different 32 bit IDs into in (struct ospf6_route), and the resulting type-pun strict-alias breakage warnings this causes. Need to use 2 different fields to fix that warning? general: * remove unused variables, other than a few cases where they serve a sufficiently useful documentary purpose (e.g. for code that needs fixing), or they're required dummies. In those cases, try mark them as unused. * Remove dead code that can't be reached. * Quite a few 'no ...' forms of vty commands take arguments, but do not check the argument matches the command being negated. E.g., should 'distance X ' succeed if previously 'distance Y ' was set? Or should it be required that the distance match the previously configured distance for the prefix? Ultimately, probably better to be strict about this. However, changing from slack to strict might expose problems in command aliases and tools. * Fix uninitialised use of variables. * Fix sign/unsigned comparison warnings by making signedness of types consistent. * Mark functions as static where their use is restricted to the same compilation unit. * Add required headers * Move constants defined in headers into code. * remove dead, unused functions that have no debug purpose. --- bgpd/bgp_advertise.h | 17 ++++++----------- bgpd/bgp_attr.c | 1 - bgpd/bgp_mplsvpn.c | 6 +++--- bgpd/bgp_nexthop.c | 35 +++++++++++++++++++++-------------- bgpd/bgp_packet.c | 27 ++++++++++++--------------- bgpd/bgp_route.c | 23 ++++++++--------------- bgpd/bgp_routemap.c | 14 +++++--------- bgpd/bgp_vty.c | 25 +++++++------------------ lib/command.c | 4 ++-- lib/if.c | 4 +--- lib/jhash.c | 6 +++--- lib/jhash.h | 4 ++-- lib/libospf.h | 4 ++-- lib/md5.c | 2 +- lib/md5.h | 2 +- lib/table.c | 3 --- lib/vty.c | 4 ++-- lib/vty.h | 2 +- lib/workqueue.c | 12 ++++++++---- ospf6d/ospf6_abr.h | 2 ++ ospf6d/ospf6_area.c | 2 -- ospf6d/ospf6_asbr.c | 7 +------ ospf6d/ospf6_interface.c | 1 - ospf6d/ospf6_lsa.c | 2 +- ospf6d/ospf6_neighbor.c | 25 +++++++++++++++++++++++++ ospf6d/ospf6_neighbor.h | 25 ------------------------- ospf6d/ospf6_network.c | 18 ++++-------------- ospf6d/ospf6_network.h | 6 ------ ospf6d/ospf6_route.h | 5 +++++ ospf6d/ospf6_spf.c | 3 ++- ospf6d/ospf6_top.c | 6 ++---- ospfd/ospf_api.c | 8 ++++---- ospfd/ospf_vty.c | 1 - ripd/ripd.c | 13 ------------- zebra/irdp_interface.c | 3 --- zebra/router-id.c | 33 +++++++++++++++++++-------------- zebra/rt_netlink.c | 8 ++++---- zebra/rt_netlink.h | 4 ++-- 38 files changed, 156 insertions(+), 211 deletions(-) diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 4ebde907d..2cf2a29b2 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -21,13 +21,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_ADVERTISE_H #define _QUAGGA_BGP_ADVERTISE_H -/* BGP advertise FIFO. */ -struct bgp_advertise_fifo -{ - struct bgp_advertise *next; - struct bgp_advertise *prev; -}; - /* BGP advertise attribute. */ struct bgp_advertise_attr { @@ -44,7 +37,7 @@ struct bgp_advertise_attr struct bgp_advertise { /* FIFO for advertisement. */ - struct bgp_advertise_fifo fifo; + struct fifo fifo; /* Link list for same attribute advertise. */ struct bgp_advertise *next; @@ -97,11 +90,13 @@ struct bgp_adj_in /* BGP advertisement list. */ struct bgp_synchronize { - struct bgp_advertise_fifo update; - struct bgp_advertise_fifo withdraw; - struct bgp_advertise_fifo withdraw_low; + struct fifo update; + struct fifo withdraw; + struct fifo withdraw_low; }; +#define BGP_ADV_FIFO_HEAD(F) ((struct bgp_advertise *)FIFO_HEAD(F)) + /* BGP adjacency linked list. */ #define BGP_INFO_ADD(N,A,TYPE) \ do { \ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index fcf82551c..b62a4f826 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2110,7 +2110,6 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, case SAFI_UNICAST: case SAFI_MULTICAST: { - unsigned long sizep; struct attr_extra *attre = attr->extra; assert (attr->extra); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index b0cf2a988..3d2dadef6 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -84,7 +84,6 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, struct prefix p; int psize; int prefixlen; - u_int32_t label; u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; @@ -117,8 +116,9 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, zlog_err ("prefix length is less than 88: %d", prefixlen); return -1; } - - label = decode_label (pnt); + + /* XXX: Not doing anything with the label */ + decode_label (pnt); /* Copyr label to prefix. */ tagpnt = pnt;; diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 5b1d13ac8..6218e6704 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -789,9 +789,9 @@ zlookup_read (void) uint16_t length; u_char marker; u_char version; - uint16_t command; - int nbytes; - struct in_addr raddr; + uint16_t command __attribute__((unused)); + int nbytes __attribute__((unused)); + struct in_addr raddr __attribute__((unused)); uint32_t metric; int i; u_char nexthop_num; @@ -801,6 +801,7 @@ zlookup_read (void) s = zlookup->ibuf; stream_reset (s); + /* nbytes not being checked */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); @@ -814,9 +815,11 @@ zlookup_read (void) __func__, zlookup->sock, marker, version); return NULL; } - + + /* XXX: not checking command */ command = stream_getw (s); + /* XXX: not doing anything with raddr */ raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); @@ -901,8 +904,6 @@ zlookup_read_ipv6 (void) struct stream *s; uint16_t length; u_char version, marker; - uint16_t command; - int nbytes; struct in6_addr raddr; uint32_t metric; int i; @@ -913,10 +914,11 @@ zlookup_read_ipv6 (void) s = zlookup->ibuf; stream_reset (s); - nbytes = stream_read (s, zlookup->sock, 2); + /* XXX: ignoring nbytes, see also zread_lookup */ + stream_read (s, zlookup->sock, 2); length = stream_getw (s); - nbytes = stream_read (s, zlookup->sock, length - 2); + stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); @@ -926,9 +928,11 @@ zlookup_read_ipv6 (void) __func__, zlookup->sock, marker, version); return NULL; } - - command = stream_getw (s); + /* XXX: ignoring command */ + stream_getw (s); + + /* XXX: not actually doing anything with raddr */ stream_get (&raddr, s, 16); metric = stream_getl (s); @@ -1014,10 +1018,10 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, { struct stream *s; int ret; - u_int16_t length, command; + u_int16_t length, command __attribute__((unused)); u_char version, marker; - int nbytes; - struct in_addr addr; + int nbytes __attribute__((unused)); + struct in_addr addr __attribute__((unused)); struct in_addr nexthop; u_int32_t metric = 0; u_char nexthop_num; @@ -1063,6 +1067,7 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, stream_reset (s); /* Fetch length. */ + /* XXX: not using nbytes */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); @@ -1077,9 +1082,11 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, __func__, zlookup->sock, marker, version); return 0; } - + + /* XXX: not using command */ command = stream_getw (s); + /* XXX: not using addr */ addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 65c6cac16..0fab1b089 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -158,7 +158,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) snlri = peer->scratch; stream_reset (snlri); - adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); while (adv) { @@ -331,7 +331,6 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) struct bgp_adj_out *adj; struct bgp_advertise *adv; struct bgp_node *rn; - unsigned long pos; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; size_t mp_start = 0; @@ -342,7 +341,7 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) s = peer->work; stream_reset (s); - while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) + while ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { assert (adv->rn); adj = adv->adj; @@ -595,7 +594,7 @@ bgp_write_packet (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw); + adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw); if (adv) { s = bgp_withdraw_packet (peer, afi, safi); @@ -607,7 +606,7 @@ bgp_write_packet (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) @@ -663,7 +662,7 @@ bgp_write_proceed (struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) - if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) + if ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) if (adv->binfo->uptime < peer->synctime) return 1; @@ -2036,7 +2035,6 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) { afi_t afi; safi_t safi; - u_char reserved; struct stream *s; /* If peer does not have the capability, send notification. */ @@ -2064,7 +2062,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) /* Parse packet. */ afi = stream_getw (s); - reserved = stream_getc (s); + /* reserved byte */ + stream_getc (s); safi = stream_getc (s); if (BGP_DEBUG (normal, NORMAL)) @@ -2116,8 +2115,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) { - u_char *p_pnt = stream_pnt (s); - u_char *p_end = stream_pnt (s) + orf_len; + uint8_t *p_pnt = stream_pnt (s); + uint8_t *p_end = stream_pnt (s) + orf_len; struct orf_prefix orfp; u_char common = 0; u_int32_t seq; @@ -2157,7 +2156,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) prefix_bgp_orf_remove_all (name); break; } - ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ; + ok = ((size_t)(p_end - p_pnt) >= sizeof(u_int32_t)) ; if (ok) { memcpy (&seq, p_pnt, sizeof (u_int32_t)); @@ -2209,8 +2208,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); - - if (!ok || (ret != CMD_SUCCESS)) + + if (!ok || (ok && ret != CMD_SUCCESS)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Received misformatted prefixlist ORF." @@ -2246,11 +2245,9 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) struct capability_mp_data mpc; struct capability_header *hdr; u_char action; - struct bgp *bgp; afi_t afi; safi_t safi; - bgp = peer->bgp; end = pnt + length; while (pnt < end) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 04cbb8ab8..e7357e544 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4525,20 +4525,11 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, struct aspath *asmerge = NULL; struct community *community = NULL; struct community *commerge = NULL; - struct in_addr nexthop; - u_int32_t med = 0; struct bgp_info *ri; struct bgp_info *new; int first = 1; unsigned long match = 0; - /* Record adding route's nexthop and med. */ - if (rinew) - { - nexthop = rinew->attr->nexthop; - med = rinew->attr->med; - } - /* ORIGIN attribute: If at least one route among routes that are aggregated has ORIGIN with the value INCOMPLETE, then the aggregated route must have the ORIGIN attribute with the value @@ -4566,11 +4557,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, continue; if (! rinew && first) - { - nexthop = ri->attr->nexthop; - med = ri->attr->med; - first = 0; - } + first = 0; #ifdef AGGREGATE_NEXTHOP_CHECK if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop) @@ -11773,7 +11760,13 @@ bgp_distance_unset (struct vty *vty, const char *distance_str, } bdistance = rn->info; - + + if (bdistance->distance != distance) + { + vty_out (vty, "Distance does not match configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (bdistance->access_list) free (bdistance->access_list); bgp_distance_free (bdistance); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index c498f584d..06b085924 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1174,7 +1174,6 @@ route_set_metric (void *rule, struct prefix *prefix, static void * route_set_metric_compile (const char *arg) { - u_int32_t metric; unsigned long larg; char *endptr = NULL; @@ -1185,7 +1184,6 @@ route_set_metric_compile (const char *arg) larg = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; - metric = larg; } else { @@ -1199,7 +1197,6 @@ route_set_metric_compile (const char *arg) larg = strtoul (arg+1, &endptr, 10); if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; - metric = larg; } return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); @@ -1802,22 +1799,21 @@ static route_map_result_t route_match_ipv6_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - struct in6_addr *addr; + struct in6_addr *addr = rule; struct bgp_info *bgp_info; if (type == RMAP_BGP) { - addr = rule; bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; - if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, rule)) + if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, addr)) return RMAP_MATCH; if (bgp_info->attr->extra->mp_nexthop_len == 32 && - IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, rule)) + IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, addr)) return RMAP_MATCH; return RMAP_NOMATCH; @@ -3430,7 +3426,7 @@ DEFUN (set_aggregator_as, "IP address of aggregator\n") { int ret; - as_t as; + as_t as __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; @@ -3464,7 +3460,7 @@ DEFUN (no_set_aggregator_as, "AS number of aggregator\n") { int ret; - as_t as; + as_t as __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a818fe7a8..ca44774ac 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -576,7 +576,7 @@ DEFUN (no_bgp_confederation_identifier, "AS number\n") { struct bgp *bgp; - as_t as; + as_t as __attribute__((unused)); /* Dummy for VTY_GET_INTEGER_RANGE */ bgp = vty->index; @@ -3205,7 +3205,6 @@ static int peer_weight_set_vty (struct vty *vty, const char *ip_str, const char *weight_str) { - int ret; struct peer *peer; unsigned long weight; @@ -3215,9 +3214,7 @@ peer_weight_set_vty (struct vty *vty, const char *ip_str, VTY_GET_INTEGER_RANGE("weight", weight, weight_str, 0, 65535); - ret = peer_weight_set (peer, weight); - - return CMD_SUCCESS; + return bgp_vty_return (vty, peer_weight_set (peer, weight)); } static int @@ -3229,9 +3226,7 @@ peer_weight_unset_vty (struct vty *vty, const char *ip_str) if (! peer) return CMD_WARNING; - peer_weight_unset (peer); - - return CMD_SUCCESS; + return bgp_vty_return (vty, peer_weight_unset (peer)); } DEFUN (neighbor_weight, @@ -3371,7 +3366,6 @@ static int peer_timers_connect_set_vty (struct vty *vty, const char *ip_str, const char *time_str) { - int ret; struct peer *peer; u_int32_t connect; @@ -3381,24 +3375,19 @@ peer_timers_connect_set_vty (struct vty *vty, const char *ip_str, VTY_GET_INTEGER_RANGE ("Connect time", connect, time_str, 0, 65535); - ret = peer_timers_connect_set (peer, connect); - - return CMD_SUCCESS; + return bgp_vty_return (vty, peer_timers_connect_set (peer, connect)); } static int peer_timers_connect_unset_vty (struct vty *vty, const char *ip_str) { - int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; - ret = peer_timers_connect_unset (peer); - - return CMD_SUCCESS; + return bgp_vty_return (vty, peer_timers_connect_unset (peer)); } DEFUN (neighbor_timers_connect, @@ -3455,7 +3444,7 @@ peer_advertise_interval_vty (struct vty *vty, const char *ip_str, else ret = peer_advertise_interval_unset (peer); - return CMD_SUCCESS; + return bgp_vty_return (vty, ret); } DEFUN (neighbor_advertise_interval, @@ -3505,7 +3494,7 @@ peer_interface_vty (struct vty *vty, const char *ip_str, const char *str) else ret = peer_interface_unset (peer); - return CMD_SUCCESS; + return bgp_vty_return (vty, ret); } DEFUN (neighbor_interface, diff --git a/lib/command.c b/lib/command.c index 1087ceb8d..d1af7fa2f 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1411,7 +1411,7 @@ cmd_matcher_read_keywords(struct cmd_matcher *matcher, const char *word; int keyword_argc; const char **keyword_argv; - enum matcher_rv rv; + enum matcher_rv rv = MATCHER_NO_MATCH; keyword_mask = 0; while (1) @@ -1642,7 +1642,7 @@ cmd_element_match(struct cmd_element *cmd_element, { struct cmd_matcher matcher; unsigned int token_index; - enum matcher_rv rv; + enum matcher_rv rv = MATCHER_NO_MATCH; cmd_matcher_init(&matcher, cmd_element, filter, vline, index, match_type, match); diff --git a/lib/if.c b/lib/if.c index 18e2fb314..3a1f9b415 100644 --- a/lib/if.c +++ b/lib/if.c @@ -309,8 +309,6 @@ struct interface * if_lookup_prefix (struct prefix *prefix) { struct listnode *node; - struct prefix addr; - int bestlen = 0; struct listnode *cnode; struct interface *ifp; struct connected *c; @@ -453,7 +451,7 @@ static void if_dump (const struct interface *ifp) { struct listnode *node; - struct connected *c; + struct connected *c __attribute__((unused)); for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) zlog_info ("Interface %s index %d metric %d mtu %d " diff --git a/lib/jhash.c b/lib/jhash.c index 071fed6e6..6154c3463 100644 --- a/lib/jhash.c +++ b/lib/jhash.c @@ -42,10 +42,10 @@ * the input key. */ u_int32_t -jhash (void *key, u_int32_t length, u_int32_t initval) +jhash (const void *key, u_int32_t length, u_int32_t initval) { u_int32_t a, b, c, len; - u_int8_t *k = key; + const u_int8_t *k = key; len = length; a = b = JHASH_GOLDEN_RATIO; @@ -105,7 +105,7 @@ jhash (void *key, u_int32_t length, u_int32_t initval) * The length parameter here is the number of u_int32_ts in the key. */ u_int32_t -jhash2 (u_int32_t * k, u_int32_t length, u_int32_t initval) +jhash2 (const u_int32_t *k, u_int32_t length, u_int32_t initval) { u_int32_t a, b, c, len; diff --git a/lib/jhash.h b/lib/jhash.h index 44dd1b562..985ac94e0 100644 --- a/lib/jhash.h +++ b/lib/jhash.h @@ -24,12 +24,12 @@ * of bytes. No alignment or length assumptions are made about * the input key. */ -extern u_int32_t jhash(void *key, u_int32_t length, u_int32_t initval); +extern u_int32_t jhash(const void *key, u_int32_t length, u_int32_t initval); /* A special optimized version that handles 1 or more of u_int32_ts. * The length parameter here is the number of u_int32_ts in the key. */ -extern u_int32_t jhash2(u_int32_t *k, u_int32_t length, u_int32_t initval); +extern u_int32_t jhash2(const u_int32_t *k, u_int32_t length, u_int32_t initval); /* A special ultra-optimized versions that knows they are hashing exactly * 3, 2 or 1 word(s). diff --git a/lib/libospf.h b/lib/libospf.h index 856c76df5..2796209d7 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -47,8 +47,8 @@ #define OSPF_LSA_MAXAGE_DIFF 900 #define OSPF_LS_INFINITY 0xffffff #define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */ -#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001 -#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff +#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001U +#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffffU /* OSPF Interface Types */ #define OSPF_IFTYPE_NONE 0 diff --git a/lib/md5.c b/lib/md5.c index 2fc36e179..ce459bbe0 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -306,7 +306,7 @@ unsigned char* text; /* pointer to data stream */ int text_len; /* length of data stream */ unsigned char* key; /* pointer to authentication key */ int key_len; /* length of authentication key */ -caddr_t digest; /* caller digest to be filled in */ +uint8_t * digest; /* caller digest to be filled in */ { MD5_CTX context; diff --git a/lib/md5.h b/lib/md5.h index a03bf22a2..4e5ffbd9e 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -84,6 +84,6 @@ do { \ /* From RFC 2104 */ void hmac_md5(unsigned char* text, int text_len, unsigned char* key, - int key_len, caddr_t digest); + int key_len, uint8_t *digest); #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/table.c b/lib/table.c index 220e9b81e..bd7023c12 100644 --- a/lib/table.c +++ b/lib/table.c @@ -626,11 +626,8 @@ route_table_get_next_internal (const struct route_table *table, struct prefix *p) { struct route_node *node, *tmp_node; - u_char prefixlen; int cmp; - prefixlen = p->prefixlen; - node = table->top; while (node) diff --git a/lib/vty.c b/lib/vty.c index 488f8d5fa..3f08b9e9c 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2458,7 +2458,7 @@ vty_log (const char *level, const char *proto_str, /* Async-signal-safe version of vty_log for fixed strings. */ void -vty_log_fixed (const char *buf, size_t len) +vty_log_fixed (char *buf, size_t len) { unsigned int i; struct iovec iov[2]; @@ -2467,7 +2467,7 @@ vty_log_fixed (const char *buf, size_t len) if (!vtyvec) return; - iov[0].iov_base = (void *)buf; + iov[0].iov_base = buf; iov[0].iov_len = len; iov[1].iov_base = (void *)"\r\n"; iov[1].iov_len = 2; diff --git a/lib/vty.h b/lib/vty.h index 1798585ec..4d6048c95 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -242,6 +242,6 @@ extern void vty_hello (struct vty *); /* Send a fixed-size message to all vty terminal monitors; this should be an async-signal-safe function. */ -extern void vty_log_fixed (const char *buf, size_t len); +extern void vty_log_fixed (char *buf, size_t len); #endif /* _ZEBRA_VTY_H */ diff --git a/lib/workqueue.c b/lib/workqueue.c index 61643bf81..e09d009f1 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -30,7 +30,11 @@ #include "log.h" /* master list of work_queues */ -static struct list work_queues; +static struct list _work_queues; +/* pointer primarily to avoid an otherwise harmless warning on + * ALL_LIST_ELEMENTS_RO + */ +static struct list *work_queues = &_work_queues; #define WORK_QUEUE_MIN_GRANULARITY 1 @@ -78,7 +82,7 @@ work_queue_new (struct thread_master *m, const char *queue_name) new->items->del = (void (*)(void *)) work_queue_item_free; - listnode_add (&work_queues, new); + listnode_add (work_queues, new); new->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY; @@ -96,7 +100,7 @@ work_queue_free (struct work_queue *wq) /* list_delete frees items via callback */ list_delete (wq->items); - listnode_delete (&work_queues, wq); + listnode_delete (work_queues, wq); XFREE (MTYPE_WORK_QUEUE_NAME, wq->name); XFREE (MTYPE_WORK_QUEUE, wq); @@ -187,7 +191,7 @@ DEFUN(show_work_queues, "Name", VTY_NEWLINE); - for (ALL_LIST_ELEMENTS_RO ((&work_queues), node, wq)) + for (ALL_LIST_ELEMENTS_RO (work_queues, node, wq)) { vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s", (CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'), diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h index 816f59645..e5e2660ba 100644 --- a/ospf6d/ospf6_abr.h +++ b/ospf6d/ospf6_abr.h @@ -24,6 +24,8 @@ /* for struct ospf6_route */ #include "ospf6_route.h" +/* for struct ospf6_prefix */ +#include "ospf6_proto.h" /* Debug option */ extern unsigned char conf_debug_ospf6_abr; diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 4b4ca1304..9b704221b 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -518,13 +518,11 @@ DEFUN (no_area_filter_list, "Filter networks sent from this area\n") { struct ospf6_area *area; - struct prefix_list *plist; OSPF6_CMD_AREA_GET (argv[0], area); argc--; argv++; - plist = prefix_list_lookup (AFI_IP6, argv[0]); if (strncmp (argv[1], "in", 2) == 0) { if (PREFIX_NAME_IN (area)) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 6ba6cdf6b..b1620d4a5 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -58,18 +58,13 @@ ospf6_as_external_lsa_originate (struct ospf6_route *route) { char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; - struct ospf6_lsa *old, *lsa; + struct ospf6_lsa *lsa; struct ospf6_external_info *info = route->route_option; struct ospf6_as_external_lsa *as_external_lsa; char buf[64]; caddr_t p; - /* find previous LSA */ - old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), - route->path.origin.id, ospf6->router_id, - ospf6->lsdb); - if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index f0ef79093..772caff7f 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1283,7 +1283,6 @@ DEFUN (no_ipv6_ospf6_cost, { struct ospf6_interface *oi; struct interface *ifp; - unsigned long int lcost; ifp = (struct interface *) vty->index; assert (ifp); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 2e6153557..e57306bcb 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -493,7 +493,7 @@ ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) vty_out (vty, "Flag: %x %s", lsa->flag, VNL); vty_out (vty, "Lock: %d %s", lsa->lock, VNL); vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); - vty_out (vty, "Threads: Expire: %x, Refresh: %x %s", + vty_out (vty, "Threads: Expire: 0x%p, Refresh: 0x%p %s", lsa->expire, lsa->refresh, VNL); vty_out (vty, "%s", VNL); return; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 7f6c6c5cd..f20c83b9f 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -46,6 +46,31 @@ const char *ospf6_neighbor_state_str[] = { "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange", "Loading", "Full", NULL }; +static const char *ospf6_neighbor_event_str[] = + { + "NoEvent", + "HelloReceived", + "2-WayReceived", + "NegotiationDone", + "ExchangeDone", + "LoadingDone", + "AdjOK?", + "SeqNumberMismatch", + "BadLSReq", + "1-WayReceived", + "InactivityTimer", + }; + +static const char * +ospf6_neighbor_event_string (int event) +{ + #define OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING "UnknownEvent" + + if (event < OSPF6_NEIGHBOR_EVENT_MAX_EVENT) + return ospf6_neighbor_event_str[event]; + return OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING; +} + int ospf6_neighbor_cmp (void *va, void *vb) { diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 65c43fd2e..93ffa289b 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -122,33 +122,8 @@ struct ospf6_neighbor #define OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER 10 #define OSPF6_NEIGHBOR_EVENT_MAX_EVENT 11 -static const char *ospf6_neighbor_event_str[] = - { - "NoEvent", - "HelloReceived", - "2-WayReceived", - "NegotiationDone", - "ExchangeDone", - "LoadingDone", - "AdjOK?", - "SeqNumberMismatch", - "BadLSReq", - "1-WayReceived", - "InactivityTimer", - }; - -static const char *ospf6_neighbor_event_string (int event) -{ - #define OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING "UnknownEvent" - - if (event < OSPF6_NEIGHBOR_EVENT_MAX_EVENT) - return ospf6_neighbor_event_str[event]; - return OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING; -} - extern const char *ospf6_neighbor_state_str[]; - /* Function Prototypes */ int ospf6_neighbor_cmp (void *va, void *vb); void ospf6_neighbor_dbex_init (struct ospf6_neighbor *on); diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 74cfbec7c..e0be38b32 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -37,18 +37,8 @@ int ospf6_sock; struct in6_addr allspfrouters6; struct in6_addr alldrouters6; -/* setsockopt ReUseAddr to on */ -void -ospf6_set_reuseaddr (void) -{ - u_int on = 0; - if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on, - sizeof (u_int)) < 0) - zlog_warn ("Network: set SO_REUSEADDR failed: %s", safe_strerror (errno)); -} - /* setsockopt MulticastLoop to off */ -void +static void ospf6_reset_mcastloop (void) { u_int off = 0; @@ -58,13 +48,13 @@ ospf6_reset_mcastloop (void) safe_strerror (errno)); } -void +static void ospf6_set_pktinfo (void) { setsockopt_ipv6_pktinfo (ospf6_sock, 1); } -void +static void ospf6_set_transport_class (void) { #ifdef IPTOS_PREC_INTERNETCONTROL @@ -72,7 +62,7 @@ ospf6_set_transport_class (void) #endif } -void +static void ospf6_set_checksum (void) { int offset = 12; diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 947834d56..127bf45c7 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -28,12 +28,6 @@ extern int ospf6_sock; extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; -/* Function Prototypes */ -extern void ospf6_set_reuseaddr (void); -extern void ospf6_reset_mcastloop (void); -extern void ospf6_set_pktinfo (void); -extern void ospf6_set_checksum (void); - extern int ospf6_serv_sock (void); extern void ospf6_sso (u_int ifindex, struct in6_addr *group, int option); diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index b384824cb..c0dcf9f1f 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -122,6 +122,10 @@ struct ospf6_route /* Destination Type */ u_char type; + /* XXX: It would likely be better to use separate struct in_addr's + * for the advertising router-ID and prefix IDs, instead of stuffing them + * into one. See also XXX below. + */ /* Destination ID */ struct prefix prefix; @@ -235,6 +239,7 @@ extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0) #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) +/* XXX: This gives GCC heartburn aboutbreaking aliasing rules. */ #define ospf6_linkstate_prefix_adv_router(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) #define ospf6_linkstate_prefix_id(x) \ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 3ef5485fd..d0e9101b8 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -40,6 +40,7 @@ #include "ospf6_intra.h" #include "ospf6_interface.h" #include "ospf6d.h" +#include "ospf6_abr.h" unsigned char conf_debug_ospf6_spf = 0; @@ -391,7 +392,7 @@ static const char *ospf6_spf_reason_str[] = void ospf6_spf_reason_string (unsigned int reason, char *buf, int size) { - int bit; + size_t bit; int len = 0; if (!buf) diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 719127014..e4e6f17a2 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -180,6 +180,7 @@ ospf6_delete (struct ospf6 *o) } static void +__attribute__((unused)) ospf6_enable (struct ospf6 *o) { struct listnode *node, *nnode; @@ -219,7 +220,7 @@ ospf6_disable (struct ospf6 *o) } } -int +static int ospf6_maxage_remover (struct thread *thread) { struct ospf6 *o = (struct ospf6 *) THREAD_ARG (thread); @@ -471,14 +472,11 @@ DEFUN (no_ospf6_interface_area, "OSPF6 area ID in IPv4 address notation\n" ) { - struct ospf6 *o; struct ospf6_interface *oi; struct ospf6_area *oa; struct interface *ifp; u_int32_t area_id; - o = (struct ospf6 *) vty->index; - ifp = if_lookup_by_name (argv[0]); if (ifp == NULL) { diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index fae942ec2..cbb234ae6 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -464,7 +464,7 @@ new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_register_event *emsg; - int len; + size_t len; emsg = (struct msg_register_event *) buf; len = sizeof (struct msg_register_event) + @@ -483,7 +483,7 @@ new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_sync_lsdb *smsg; - int len; + size_t len; smsg = (struct msg_sync_lsdb *) buf; len = sizeof (struct msg_sync_lsdb) + @@ -504,7 +504,7 @@ new_msg_originate_request (u_int32_t seqnum, struct in_addr area_id, struct lsa_header *data) { struct msg_originate_request *omsg; - int omsglen; + size_t omsglen; char buf[OSPF_API_MAX_MSG_SIZE]; omsg = (struct msg_originate_request *) buf; @@ -630,7 +630,7 @@ new_msg_lsa_change_notify (u_char msgtype, { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_lsa_change_notify *nmsg; - int len; + size_t len; assert (data); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 8bfcaa829..97fcffd11 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -4034,7 +4034,6 @@ static void show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) { struct route_node *rn; - struct ospf_lsa *lsa; vty_out (vty, "%s MaxAge Link States:%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); diff --git a/ripd/ripd.c b/ripd/ripd.c index c69ef7fc6..9d355ecb9 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1737,16 +1737,6 @@ rip_request_process (struct rip_packet *packet, int size, ntohs (rte->family) == 0 && ntohl (rte->metric) == RIP_METRIC_INFINITY) { - struct prefix_ipv4 saddr; - - /* saddr will be used for determining which routes to split-horizon. - Since the source address we'll pick will be on the same subnet as the - destination, for the purpose of split-horizoning, we'll - pretend that "from" is our source address. */ - saddr.family = AF_INET; - saddr.prefixlen = IPV4_MAX_BITLEN; - saddr.prefix = from->sin_addr; - /* All route with split horizon */ rip_output_process (ifc, from, rip_all_route, packet->version); } @@ -3262,7 +3252,6 @@ rip_distance_unset (struct vty *vty, const char *distance_str, { int ret; struct prefix_ipv4 p; - u_char distance; struct route_node *rn; struct rip_distance *rdistance; @@ -3273,8 +3262,6 @@ rip_distance_unset (struct vty *vty, const char *distance_str, return CMD_WARNING; } - distance = atoi (distance_str); - rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); if (! rn) { diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 6403830b9..43c63a83f 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -638,7 +638,6 @@ DEFUN (no_ip_irdp_address_preference, { struct listnode *node, *nnode; struct in_addr ip; - int pref; int ret; struct interface *ifp; struct zebra_if *zi; @@ -657,8 +656,6 @@ DEFUN (no_ip_irdp_address_preference, if (!ret) return CMD_WARNING; - pref = atoi(argv[1]); - for (ALL_LIST_ELEMENTS (irdp->AdvPrefList, node, nnode, adv)) { if(adv->ip.s_addr == ip.s_addr ) diff --git a/zebra/router-id.c b/zebra/router-id.c index b738027ec..94a294199 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -41,8 +41,13 @@ #include "zebra/router-id.h" #include "zebra/redistribute.h" -static struct list rid_all_sorted_list; -static struct list rid_lo_sorted_list; +/* 2nd pointer type used primarily to quell a warning on + * ALL_LIST_ELEMENTS_RO + */ +static struct list _rid_all_sorted_list; +static struct list _rid_lo_sorted_list; +static struct list *rid_all_sorted_list = &_rid_all_sorted_list; +static struct list *rid_lo_sorted_list = &_rid_lo_sorted_list; static struct prefix rid_user_assigned; /* master zebra server structure */ @@ -86,15 +91,15 @@ router_id_get (struct prefix *p) if (rid_user_assigned.u.prefix4.s_addr) p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr; - else if (!list_isempty (&rid_lo_sorted_list)) + else if (!list_isempty (rid_lo_sorted_list)) { - node = listtail (&rid_lo_sorted_list); + node = listtail (rid_lo_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } - else if (!list_isempty (&rid_all_sorted_list)) + else if (!list_isempty (rid_all_sorted_list)) { - node = listtail (&rid_all_sorted_list); + node = listtail (rid_all_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } @@ -131,9 +136,9 @@ router_id_add_address (struct connected *ifc) if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) - l = &rid_lo_sorted_list; + l = rid_lo_sorted_list; else - l = &rid_all_sorted_list; + l = rid_all_sorted_list; if (!router_id_find_node (l, ifc)) listnode_add_sort (l, ifc); @@ -164,9 +169,9 @@ router_id_del_address (struct connected *ifc) if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) - l = &rid_lo_sorted_list; + l = rid_lo_sorted_list; else - l = &rid_all_sorted_list; + l = rid_all_sorted_list; if ((c = router_id_find_node (l, ifc))) listnode_delete (l, c); @@ -240,12 +245,12 @@ router_id_init (void) install_element (CONFIG_NODE, &router_id_cmd); install_element (CONFIG_NODE, &no_router_id_cmd); - memset (&rid_all_sorted_list, 0, sizeof (rid_all_sorted_list)); - memset (&rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list)); + memset (rid_all_sorted_list, 0, sizeof (rid_all_sorted_list)); + memset (rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list)); memset (&rid_user_assigned, 0, sizeof (rid_user_assigned)); - rid_all_sorted_list.cmp = router_id_cmp; - rid_lo_sorted_list.cmp = router_id_cmp; + rid_all_sorted_list->cmp = router_id_cmp; + rid_lo_sorted_list->cmp = router_id_cmp; rid_user_assigned.family = AF_INET; rid_user_assigned.prefixlen = 32; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f3cdcdc3f..12dbd1ad5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1246,9 +1246,9 @@ netlink_route_read (void) /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int -addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) +addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen) { - int len; + size_t len; struct rtattr *rta; len = RTA_LENGTH (alen); @@ -1288,9 +1288,9 @@ rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int -addattr32 (struct nlmsghdr *n, int maxlen, int type, int data) +addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data) { - int len; + size_t len; struct rtattr *rta; len = RTA_LENGTH (4); diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 452b3974e..0facd49e0 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -27,9 +27,9 @@ #define NL_PKT_BUF_SIZE 8192 extern int -addattr32 (struct nlmsghdr *n, int maxlen, int type, int data); +addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data); extern int -addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen); +addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen); extern int rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen); From b2dd59ee0e74926278e128846624f5c93288223b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Sep 2014 15:34:48 +0100 Subject: [PATCH 0400/1342] bgpd.c: Remove unused store to variable --- bgpd/bgpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4d374cc19..3a9bc480a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1028,9 +1028,9 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as, if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) && afi == AFI_IP && safi == SAFI_UNICAST) - peer = peer_create (su, bgp, local_as, *as, 0, 0); + peer_create (su, bgp, local_as, *as, 0, 0); else - peer = peer_create (su, bgp, local_as, *as, afi, safi); + peer_create (su, bgp, local_as, *as, afi, safi); } return 0; From 7bef33cbf5027189bd55e4890a07a6bef8277f93 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Sep 2014 15:35:15 +0100 Subject: [PATCH 0401/1342] ospf6_lsdb: trivial, make it clear that showfunc is set before deref. --- ospf6d/ospf6_lsdb.c | 27 +++++++++++++++++---------- ospf6d/ospf6_lsdb.h | 13 ++++++++----- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 707afc67e..b5a4587c2 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -485,22 +485,29 @@ ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) } void -ospf6_lsdb_show (struct vty *vty, int level, +ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL; - if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) - showfunc = ospf6_lsa_show_summary; - else if (level == OSPF6_LSDB_SHOW_LEVEL_DETAIL) - showfunc = ospf6_lsa_show; - else if (level == OSPF6_LSDB_SHOW_LEVEL_INTERNAL) - showfunc = ospf6_lsa_show_internal; - else if (level == OSPF6_LSDB_SHOW_LEVEL_DUMP) - showfunc = ospf6_lsa_show_dump; - + switch (level) + { + case OSPF6_LSDB_SHOW_LEVEL_DETAIL: + showfunc = ospf6_lsa_show; + break; + case OSPF6_LSDB_SHOW_LEVEL_INTERNAL: + showfunc = ospf6_lsa_show_internal; + break; + case OSPF6_LSDB_SHOW_LEVEL_DUMP: + showfunc = ospf6_lsa_show_dump; + break; + case OSPF6_LSDB_SHOW_LEVEL_NORMAL: + default: + showfunc = ospf6_lsa_show_summary; + } + if (type && id && adv_router) { lsa = ospf6_lsdb_lookup (*type, *id, *adv_router, lsdb); diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index a124adbf0..425f61537 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -66,12 +66,15 @@ extern struct ospf6_lsa *ospf6_lsdb_type_next (u_int16_t type, extern void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa); -#define OSPF6_LSDB_SHOW_LEVEL_NORMAL 0 -#define OSPF6_LSDB_SHOW_LEVEL_DETAIL 1 -#define OSPF6_LSDB_SHOW_LEVEL_INTERNAL 2 -#define OSPF6_LSDB_SHOW_LEVEL_DUMP 3 +enum ospf_lsdb_show_level { + OSPF6_LSDB_SHOW_LEVEL_NORMAL = 0, + OSPF6_LSDB_SHOW_LEVEL_DETAIL, + OSPF6_LSDB_SHOW_LEVEL_INTERNAL, + OSPF6_LSDB_SHOW_LEVEL_DUMP, +}; -extern void ospf6_lsdb_show (struct vty *vty, int level, u_int16_t *type, +extern void ospf6_lsdb_show (struct vty *vty, + enum ospf_lsdb_show_level level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb); From 16f1606382b77ac6b951ea0de15384fcbc1df73f Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Sep 2014 15:35:54 +0100 Subject: [PATCH 0402/1342] ripng_nexthop: remove unused store to variable --- ripngd/ripng_nexthop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c index 05f190e27..b966af001 100644 --- a/ripngd/ripng_nexthop.c +++ b/ripngd/ripng_nexthop.c @@ -209,7 +209,6 @@ ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, if (ret >= 0 && IS_RIPNG_DEBUG_SEND) ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), stream_get_endp (s), "SEND"); - num = 0; stream_reset (s); } } From 18f420e9f99e7f6557cf5877673cd6e71ac32192 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Sep 2014 16:55:46 +0100 Subject: [PATCH 0403/1342] lib/plist: Add some required parentheses, according to clang-analyzer --- lib/plist.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/plist.c b/lib/plist.c index 7416ebd2f..610755608 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -733,16 +733,16 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, #endif /* HAVE_IPV6 */ /* ge and le check. */ - if (genum && genum <= p.prefixlen) + if (genum && (genum <= p.prefixlen)) return vty_invalid_prefix_range (vty, prefix); - if (lenum && lenum <= p.prefixlen) + if (lenum && (lenum <= p.prefixlen)) return vty_invalid_prefix_range (vty, prefix); - if (lenum && genum > lenum) + if (lenum && (genum > lenum)) return vty_invalid_prefix_range (vty, prefix); - if (genum && lenum == (afi == AFI_IP ? 32 : 128)) + if (genum && (lenum == (afi == AFI_IP ? 32 : 128))) lenum = 0; /* Get prefix_list with name. */ From b166ea2dda9f04a8b75e0bf5adb7064580695f22 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 25 Jun 2009 16:40:06 +0100 Subject: [PATCH 0404/1342] [lib] Add support for backtrace on more platforms * lib/sigevent.c: (program_counter) extend to support more platforms. Joint effort with Paul Jakma. --- configure.ac | 12 ++++++++++++ lib/sigevent.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index f1df482b3..9d188284d 100755 --- a/configure.ac +++ b/configure.ac @@ -533,6 +533,18 @@ AC_CHECK_HEADERS([ucontext.h], [], [], QUAGGA_INCLUDES ]) +m4_define([UCONTEXT_INCLUDES], +[#include ])dnl + +AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.uc_regs], + [], [], [UCONTEXT_INCLUDES]) +AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.regs], + [AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.regs.nip], + [], [], [UCONTEXT_INCLUDES])], + [], [UCONTEXT_INCLUDES]) +AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.gregs], + [], [], [UCONTEXT_INCLUDES]) + m4_define([QUAGGA_INCLUDES], QUAGGA_INCLUDES [#if HAVE_SYS_UN_H diff --git a/lib/sigevent.c b/lib/sigevent.c index 7d08fd97c..c80a72901 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -175,11 +175,35 @@ program_counter(void *context) { #ifdef HAVE_UCONTEXT_H #ifdef GNU_LINUX -#ifdef REG_EIP - if (context) - return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]); -#endif /* REG_EIP */ + /* these are from GNU libc, rather than Linux, strictly speaking */ +# if defined(REG_EIP) +# define REG_INDEX REG_EIP +# elif defined(REG_RIP) +# define REG_INDEX REG_RIP +# elif defined(__powerpc__) +# define REG_INDEX 32 +# endif +#elif defined(SUNOS_5) /* !GNU_LINUX */ +# define REG_INDEX REG_PC #endif /* GNU_LINUX */ + +#ifdef REG_INDEX +# ifdef HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS +# define REGS gregs[REG_INDEX] +# elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS) +# define REGS uc_regs->gregs[REG_INDEX] +# endif /* HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS */ +#endif /* REG_INDEX */ + +#ifdef REGS + if (context) + return (void *)(((ucontext_t *)context)->uc_mcontext.REGS); +#elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_REGS__NIP) + /* older Linux / struct pt_regs ? */ + if (context) + return (void *)(((ucontext_t *)context)->uc_mcontext.regs->nip); +#endif /* REGS */ + #endif /* HAVE_UCONTEXT_H */ return NULL; } From 055086f70febc30fdfd94bb4406e9075d6934cd8 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 23 Sep 2014 15:23:01 +0100 Subject: [PATCH 0405/1342] bgpd: well-known attr check only run for v4/uni, which could cause a crash. * ANVL testing by Martin Winter threw up a crash in bgpd in aspath_dup called from bgp_packet_attribute, if attr->aspath was NULL, on an IPv6 UPDATE. This root cause is that the checks for well-known, mandatory attributes were being applied only if an UPDATE contained the IPv4 NLRI and the peer was configured for v4/unicast (i.e. not deconfigured). This is something inherited from GNU Zebra, and never noticed before. * bgp_attr.c: (bgp_attr_parse) Move the well-known mandatory attribute check to here, so that it can be run immediately after all attributes are parsed, and before any further processing of attributes that might assume the existence of WK/M attributes (e.g. AS4-Path). (bgp_attr_munge_as4_attrs) Missing AS_PATH shouldn't happen here anymore, but retain a check anyway for robustness - it's definitely a hard error though. * bgp_attr.h: (bgp_attr_check) No longer needs to be exported, make static. * bgp_packet.c: (bgp_update_receive) Responsibility for well-known check now in bgp_attr_parse. --- bgpd/bgp_attr.c | 101 +++++++++++++++++++++++++++------------------- bgpd/bgp_attr.h | 1 - bgpd/bgp_packet.c | 11 ----- 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b62a4f826..69ca786db 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1282,7 +1282,17 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, int ignore_as4_path = 0; struct aspath *newpath; struct attr_extra *attre = attr->extra; - + + if (!attr->aspath) + { + /* NULL aspath shouldn't be possible as bgp_attr_parse should have + * checked that all well-known, mandatory attributes were present. + * + * Can only be a problem with peer itself - hard error + */ + return BGP_ATTR_PARSE_ERROR; + } + if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) { /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR @@ -1362,12 +1372,9 @@ bgp_attr_munge_as4_attrs (struct peer *const peer, /* need to reconcile NEW_AS_PATH and AS_PATH */ if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) { - if (!attr->aspath) - return BGP_ATTR_PARSE_PROCEED; - - newpath = aspath_reconcile_as4 (attr->aspath, as4_path); - aspath_unintern (&attr->aspath); - attr->aspath = aspath_intern (newpath); + newpath = aspath_reconcile_as4 (attr->aspath, as4_path); + aspath_unintern (&attr->aspath); + attr->aspath = aspath_intern (newpath); } return BGP_ATTR_PARSE_PROCEED; } @@ -1726,6 +1733,39 @@ bgp_attr_unknown (struct bgp_attr_parser_args *args) return BGP_ATTR_PARSE_PROCEED; } +/* Well-known attribute check. */ +static int +bgp_attr_check (struct peer *peer, struct attr *attr) +{ + u_char type = 0; + + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) + type = BGP_ATTR_ORIGIN; + + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) + type = BGP_ATTR_AS_PATH; + + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) + type = BGP_ATTR_NEXT_HOP; + + if (peer->sort == BGP_PEER_IBGP + && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) + type = BGP_ATTR_LOCAL_PREF; + + if (type) + { + zlog (peer->log, LOG_WARNING, + "%s Missing well-known attribute %d.", + peer->host, type); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MISS_ATTR, + &type, 1); + return BGP_ATTR_PARSE_ERROR; + } + return BGP_ATTR_PARSE_PROCEED; +} + /* Read attribute of update packet. This function is called from bgp_update_receive() in bgp_packet.c. */ bgp_attr_parse_ret_t @@ -1958,7 +1998,6 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, return BGP_ATTR_PARSE_ERROR; } } - /* Check final read pointer is same as end pointer. */ if (BGP_INPUT_PNT (peer) != endp) { @@ -1972,7 +2011,18 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } - + + /* Check all mandatory well-known attributes are present */ + { + bgp_attr_parse_ret_t ret; + if ((ret = bgp_attr_check (peer, attr)) < 0) + { + if (as4_path) + aspath_unintern (&as4_path); + return ret; + } + } + /* * At this place we can see whether we got AS4_PATH and/or * AS4_AGGREGATOR from a 16Bit peer and act accordingly. @@ -2033,39 +2083,6 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, return BGP_ATTR_PARSE_PROCEED; } -/* Well-known attribute check. */ -int -bgp_attr_check (struct peer *peer, struct attr *attr) -{ - u_char type = 0; - - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) - type = BGP_ATTR_ORIGIN; - - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) - type = BGP_ATTR_AS_PATH; - - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) - type = BGP_ATTR_NEXT_HOP; - - if (peer->sort == BGP_PEER_IBGP - && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) - type = BGP_ATTR_LOCAL_PREF; - - if (type) - { - zlog (peer->log, LOG_WARNING, - "%s Missing well-known attribute %d.", - peer->host, type); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MISS_ATTR, - &type, 1); - return BGP_ATTR_PARSE_ERROR; - } - return BGP_ATTR_PARSE_PROCEED; -} - int stream_put_prefix (struct stream *, struct prefix *); size_t diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index cb401e711..b59fa8e4d 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -147,7 +147,6 @@ extern void bgp_attr_finish (void); extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); -extern int bgp_attr_check (struct peer *, struct attr *); extern struct attr_extra *bgp_attr_extra_get (struct attr *); extern void bgp_attr_extra_free (struct attr *); extern void bgp_attr_dup (struct attr *, struct attr *); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0fab1b089..35a22c1e3 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1775,18 +1775,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) bgp_nlri_parse (peer, NULL, &withdraw); if (update.length) - { - /* We check well-known attribute only for IPv4 unicast - update. */ - ret = bgp_attr_check (peer, &attr); - if (ret < 0) - { - bgp_attr_unintern_sub (&attr); - return -1; - } - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); - } if (mp_update.length && mp_update.afi == AFI_IP From f6444e4f6e1664f49f7552f894c8c94e45dd3c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cochard-Labb=C3=A9?= Date: Thu, 9 Oct 2014 10:28:21 +0100 Subject: [PATCH 0406/1342] FreeBSD has changed its SOCK_RAW for being truly raw. --- lib/zebra.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/zebra.h b/lib/zebra.h index 3715b342e..b289a19e1 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -358,7 +358,8 @@ struct in_pktinfo * OpenBSD: network byte order, apart from older versions which are as per * *BSD */ -#if defined(__NetBSD__) || defined(__FreeBSD__) \ +#if defined(__NetBSD__) \ + || (defined(__FreeBSD__) && (__FreeBSD_version < 1100030)) \ || (defined(__OpenBSD__) && (OpenBSD < 200311)) \ || (defined(__APPLE__)) \ || (defined(SUNOS_5) && defined(WORDS_BIGENDIAN)) From 7a6eec54eaffa82f4f03363314bb81c400eb2a66 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Oct 2014 10:51:41 +0100 Subject: [PATCH 0407/1342] zebra: Build the test client, can be useful, and add IPv6 to testrib.conf --- zebra/Makefile.am | 4 ++-- zebra/testrib.conf | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 96f7bef30..0591a555c 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -59,8 +59,8 @@ EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c if_proc.c \ ioctl.c ioctl_solaris.c \ GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB -#client : client_main.o ../lib/libzebra.la -# $(CC) -g -o client client_main.o ../liblzebra.la $(LIBS) $(LIB_IPV6) +client : client_main.o ../lib/libzebra.la + $(CC) -g -o client client_main.o ../liblzebra.la $(LIBS) $(LIB_IPV6) quaggaconfdir = $(sysconfdir) diff --git a/zebra/testrib.conf b/zebra/testrib.conf index 75ba0ccd7..0df7dc24f 100644 --- a/zebra/testrib.conf +++ b/zebra/testrib.conf @@ -11,45 +11,65 @@ debug zebra kernel ! interface eth0 ip address 10.0.0.1/24 + ipv6 address 1::0:1/64 state up ! interface eth1 ip address 10.0.1.1/24 + ipv6 address 1::1:1/64 ! interface eth2 ip address 10.0.2.1/24 + ipv6 address 1::2:1/64 ! +! Unnumbered interface foo1 ip address 192.168.1.1/32 + ipv6 address 2::1:1/128 ! interface foo0 ip address 192.168.1.1/32 ip address 192.168.1.1/24 label foo + ipv6 address 2::1:1/128 state up ! -ip route 1.1.1.0/24 1.1.2.2 ! statics that should be subsumed by connected routes, according to interface ! state ip route 10.0.0.0/24 10.0.1.254 ip route 10.0.1.0/24 10.0.2.254 ip route 10.0.2.0/24 10.0.0.254 +ipv6 route 1::0:0/64 1::1:f +ipv6 route 1::1:0/64 1::2:f +ipv6 route 1::2:0/64 1::0:f + +! null route +ip route 10.1.0.1/32 null0 +ipv6 route 100::1:1/128 null0 -! normalish route +! normalish routes ip route 1.1.2.0/24 10.0.0.2 +ipv6 route 80::/64 1::0:e + ! different admin distances ip route 1.1.0.2/32 10.0.0.3 10 ip route 1.1.0.2/32 10.0.0.4 20 ip route 1.1.0.2/32 10.0.1.3 30 +ipv6 route 90::1/128 1::0:a 10 +ipv6 route 90::1/128 1::0:b 20 +ipv6 route 90::1/128 1::1:c 30 + ! multiple-nexthop + distance ip route 1.1.0.2/32 10.0.0.5 10 +ipv6 route 90::1/128 1::0:d 10 ! a recursive route, potentially. ip route 1.1.3.0/24 10.0.0.2 ! double recursive, potentially ip route 1.1.0.1/32 1.1.3.1 ! +ip route 1.1.1.0/24 1.1.2.2 line vty exec-timeout 0 0 From 384d7ad98c109e92eaf65bf10a3256e5657639c3 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Oct 2014 16:09:10 +0100 Subject: [PATCH 0408/1342] docs: defines.texi include seems to want to be after setfilename * quagga.texi: I'm getting warnings about stuff in defines.texi not being defined when building quagga.info. Seems to be fixed by moving the include of defines.texi to the end of the header. Also, the Texinfo docs suggest setfilename must go first. --- doc/quagga.texi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/quagga.texi b/doc/quagga.texi index b4105ac96..af82e5153 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -1,11 +1,10 @@ \input texinfo @c -*- texinfo -*- -@c Set variables - sourced from defines.texi -@include defines.texi @c %**start of header -@setchapternewpage odd -@settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @setfilename quagga.info +@settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} +@c Set variables - sourced from defines.texi +@include defines.texi @c %**end of header @c automake will automatically generate version.texi From 969d3550a8cbb07f8b4d5ebe8dde5064f8260140 Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Tue, 21 Oct 2014 06:24:07 +0000 Subject: [PATCH 0409/1342] zebra: route_unlock_node is missing in "show ip[v6] route " commands Signed-off-by: Feng Lu Acked-by: Vincent Jardin --- zebra/zebra_vty.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index baa60db9a..1d12ac5f1 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -998,6 +998,8 @@ DEFUN (show_ip_route_prefix, if (! rn || rn->p.prefixlen != p.prefixlen) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + if (rn) + route_unlock_node (rn); return CMD_WARNING; } @@ -1897,6 +1899,8 @@ DEFUN (show_ipv6_route_prefix, if (! rn || rn->p.prefixlen != p.prefixlen) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + if (rn) + route_unlock_node (rn); return CMD_WARNING; } From ea2a598411cc7bd20456849e56bbc9e93c9916e7 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 26 Nov 2009 12:23:07 +0000 Subject: [PATCH 0410/1342] ospfd: invalid MD5 auth_key? This looks fishy in ospf_make_md5_digest() if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) auth_key = (const u_int8_t *) ""; ... MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); auth_key points to a "" string of len 1 which is a lot smaller that OSPF_AUTH_MD5_SIZE. Is this intentional to get some random data or just a plain bug? Anyone using MD5 should have a closer look and decide what to do. Acked-by: Feng Lu --- ospfd/ospf_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index efdf8263b..17260eb1e 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -383,7 +383,7 @@ static int ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) { struct ospf_header *ospfh; - unsigned char digest[OSPF_AUTH_MD5_SIZE]; + unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; MD5_CTX ctx; void *ibuf; u_int32_t t; @@ -410,7 +410,7 @@ ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) /* Get MD5 Authentication key from auth_key list. */ if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) - auth_key = (const u_int8_t *) ""; + auth_key = (const u_int8_t *) digest; else { ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); From bdd8cd70a042473477f9144c9cedb8dde11ba2c1 Mon Sep 17 00:00:00 2001 From: Yasuhiro Ohara Date: Thu, 17 Dec 2009 05:41:17 +0000 Subject: [PATCH 0411/1342] Bug in ospf6_lsa_compare() This fix is probably correct on 32bit systems, but i think it will not work on 64bit systems. sizeof(signed long) would be 8 and therefore the cast from u_int32_t will map all the values to non-negative part of long int. You would like to use int (like in ospfd) and change the type of seqnuma, seqnumb to that. The type int32_t would be even more proper, but sizeof(int) is 4 on relevant platforms. Signed-off: Ondrej Zajicek Acked-by: Feng Lu Acked-by: Yasuhiro Ohara --- ospf6d/ospf6_lsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index e57306bcb..8eeb99595 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -306,7 +306,7 @@ ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) int ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) { - int seqnuma, seqnumb; + int32_t seqnuma, seqnumb; u_int16_t cksuma, cksumb; u_int16_t agea, ageb; @@ -314,8 +314,8 @@ ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) assert (b && b->header); assert (OSPF6_LSA_IS_SAME (a, b)); - seqnuma = (int) ntohl (a->header->seqnum); - seqnumb = (int) ntohl (b->header->seqnum); + seqnuma = (int32_t) ntohl (a->header->seqnum); + seqnumb = (int32_t) ntohl (b->header->seqnum); /* compare by sequence number */ if (seqnuma > seqnumb) From 3790eb0d3f0bbb24b9c6be97f547cec144ee05d1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 13 Jan 2010 00:32:43 +0000 Subject: [PATCH 0412/1342] stream: remove unused stream_read_unblock The one place this was being used in BGP is now gone, can remove deprecated interface. Acked-by: Feng Lu --- lib/stream.c | 26 -------------------------- lib/stream.h | 4 ---- 2 files changed, 30 deletions(-) diff --git a/lib/stream.c b/lib/stream.c index 0fc3c3b11..c6f20c85b 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -754,32 +754,6 @@ stream_read (struct stream *s, int fd, size_t size) return nbytes; } -/* Read size from fd. */ -int -stream_read_unblock (struct stream *s, int fd, size_t size) -{ - int nbytes; - int val; - - STREAM_VERIFY_SANE(s); - - if (STREAM_WRITEABLE (s) < size) - { - STREAM_BOUND_WARN (s, "put"); - return 0; - } - - val = fcntl (fd, F_GETFL, 0); - fcntl (fd, F_SETFL, val|O_NONBLOCK); - nbytes = read (fd, s->data + s->endp, size); - fcntl (fd, F_SETFL, val); - - if (nbytes > 0) - s->endp += nbytes; - - return nbytes; -} - ssize_t stream_read_try(struct stream *s, int fd, size_t size) { diff --git a/lib/stream.h b/lib/stream.h index f0c742c05..1fc382d68 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -193,10 +193,6 @@ extern u_int32_t stream_get_ipv4 (struct stream *); Use stream_read_try instead. */ extern int stream_read (struct stream *, int, size_t); -/* Deprecated: all file descriptors should already be non-blocking. - Will be removed. Use stream_read_try instead. */ -extern int stream_read_unblock (struct stream *, int, size_t); - /* Read up to size bytes into the stream. Return code: >0: number of bytes read From 6b274d90fa9b0c9f43e3ca9494cd78df1ccad14e Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Tue, 9 Mar 2010 06:42:30 +0000 Subject: [PATCH 0413/1342] ospfd: Don't leave stale RouterLSA's when changing areaID Signed-off-by: Joakim Tjernlund Acked-by: Feng Lu --- ospfd/ospfd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index dd57f645b..c55bdaebf 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -827,7 +827,10 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, } if (found == 0) - ospf_if_free (oi); + { + ospf_if_free (oi); + ospf_area_check_free (ospf, area_id); + } } /* Update connected redistribute. */ From f80ba04074f1211d857d08d6deddc41d029be1c7 Mon Sep 17 00:00:00 2001 From: Vincent JARDIN Date: Mon, 27 Oct 2014 13:03:14 +0000 Subject: [PATCH 0414/1342] Handy guidelines to contribute Explain how to be a nice contributor in a handy way. Signed-off-by: Vincent JARDIN Acked-by: Paul Jakma --- HACKING.tex | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/HACKING.tex b/HACKING.tex index c868e7ca4..54931d121 100644 --- a/HACKING.tex +++ b/HACKING.tex @@ -105,6 +105,68 @@ \section{GUIDELINES FOR HACKING ON QUAGGA} See also section~\ref{sec:dll-versioning} below regarding SHARED LIBRARY VERSIONING. +\section{YOUR FIRST CONTRIBUTIONS} + +Routing protocols can be very complex sometimes. Then, working with an +Opensource community can be complex too, but usually friendly with +anyone who is ready to be willing to do it properly. + +\begin{itemize} + + \item First, start doing simple tasks. Quagga's patchwork is a good place + to start with. Pickup some patches, apply them on your git trie, + review them and send your ack't or review comments. Then, a + maintainer will apply the patch if ack't or the author will + have to provide a new update. It help a lot to drain the + patchwork queues. + See \url{http://patchwork.quagga.net/project/quagga/list/} + + \item The more you'll review patches from patchwork, the more the + Quagga's maintainers will be willing to consider some patches you will + be sending. + + \item start using git clone, pwclient \url{http://patchwork.quagga.net/help/pwclient/} + +\begin{verbatim} +$ pwclient list -s new +ID State Name +-- ----- ---- +179 New [quagga-dev,6648] Re: quagga on FreeBSD 4.11 (gcc-2.95) +181 New [quagga-dev,6660] proxy-arp patch +[...] + +$ pwclient git-am 1046 +\end{verbatim} + +\end{itemize} + +\section{HANDY GUIDELINES FOR MAINTAINERS} + +Get your cloned trie: +\begin{verbatim} + git clone vjardin@git.sv.gnu.org:/srv/git/quagga.git +\end{verbatim} + +Apply some ack't patches: +\begin{verbatim} + pwclient git-am 1046 + Applying patch #1046 using 'git am' + Description: [quagga-dev,11595] zebra: route_unlock_node is missing in "show ip[v6] route " commands + Applying: zebra: route_unlock_node is missing in "show ip[v6] route " commands +\end{verbatim} + +Run a quick review. If the ack't was not done properly, you know who you have +to blame. + +Push the patches: +\begin{verbatim} + git push +\end{verbatim} + +Set the patch to accepted on patchwork +\begin{verbatim} + pwclient update -s Accepted 1046 +\end{verbatim} \section{COMPILE-TIME CONDITIONAL CODE} From 9562a7774b76df050d3e01632c6203796dc72c87 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 21 Oct 2014 10:59:45 +0100 Subject: [PATCH 0415/1342] mrlg: Remove obsolete version. * mrlg.cgi: The version we shipped was very much out of date, remove it. * mrlg.txt: Add file pointing to the official MRLG site. --- tools/mrlg.cgi | 395 ------------------------------------------------- tools/mrlg.txt | 5 + 2 files changed, 5 insertions(+), 395 deletions(-) delete mode 100755 tools/mrlg.cgi create mode 100644 tools/mrlg.txt diff --git a/tools/mrlg.cgi b/tools/mrlg.cgi deleted file mode 100755 index ac468eef1..000000000 --- a/tools/mrlg.cgi +++ /dev/null @@ -1,395 +0,0 @@ -#!/usr/bin/perl -## -## Zebra Looking Glass version 1.0 -## 01 FEB 2000 -## Copyright (C) 2000 John W. Fraizer III -## *All* copyright notices must remain in place to use this code. -## -## The latest version of this code is available at: -## ftp://ftp.enterzone.net/looking-glass/ -## -## -## This file is part of GNU Zebra. -## -## GNU Zebra 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. -## -## GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the -## Free Software Foundation, Inc., 59 Temple Place - Suite 330, -## Boston, MA 02111-1307, USA. - -require 5.002; -use POSIX; -use Net::Telnet (); - - - -## Set the URL for your site. -$url="http://www.sample.com/mrlg.cgi"; - -## Set your router variables in sub set_router and modify the selections in Main to match. - - -############################################################ -#Main -############################################################ -{ - -## Set the router default -@Form{'router'} = "router1"; - -## Get the form results now so we can override the default router -get_form(); - -print "Content-type: text/html\n\n"; - -print ' - - -Multi-Router Looking Glass for Zebra - - - - -

Multi-Router Looking Glass for Zebra

-Copyright 2000 - John Fraizer, EnterZone Inc. -
-'; - -print ' - -'; -print "
\n"; -print "Router: -

-Query: -
-show ip bgp
-show ip bgp summary
-show ip route
-show interface
-show ipv6 bgp
-show ipv6 bgp summary
-show ipv6 route
-
-Argument: -
-'; - -## Set up the address, pw and ports, etc for the selected router. -set_router(); - -## Set up which command is to be executed (and then execute it!) -set_command(); - - -print ' -

-
- -Multi-Router Looking Glass for Zebra version 1.0
-Written by: John Fraizer - -EnterZone, Inc
-Source code: ftp://ftp.enterzone.net/looking-glass/ - - -'; - -## All done! - -exit (0); -} - - -############################################################ -sub get_form -############################################################ -{ - - #read STDIN - read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); - - # Split the name-value pairs - @pairs = split(/&/, $buffer); - - # For each name-value pair: - foreach $pair (@pairs) - { - - # Split the pair up into individual variables. - local($name, $value) = split(/=/, $pair); - - # Decode the form encoding on the name and value variables. - $name =~ tr/+/ /; - $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; - - $value =~ tr/+/ /; - $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; - - # If they try to include server side includes, erase them, so they - # aren't a security risk if the html gets returned. Another - # security hole plugged up. - $value =~ s///g; - - @Form{$name} = $value ; - - } - -} - -############################################################ -sub set_router -############################################################ - -## $server is the IP address of the router running zebra -## $login_pass is the password of the router -## $bgpd is the port that bgpd will answer on -## $zebra is the port that zebra will answer on -## if $zebra is "", it will disable sh ip route and sh int for that router. -## if $full_tables is set to "1" for a router, full BGP and IP ROUTE table dumps will be allowed via the looking glass. -## This is a BAD thing to do if you have multiple full views on a router. That's why the option is there. - -{ -if ($Form{'router'} eq 'router1') - { -$server = '10.1.1.1'; -$login_pass = 'zebra'; -$bgpd = "2605"; -$zebra = ""; -$full_tables=1; - - } - -elsif ($Form{'router'} eq 'router2') - { -$server = '10.1.1.2'; -$login_pass = 'zebra'; -$bgpd = "2605"; -$zebra = "2601"; - } - -elsif ($Form{'router'} eq 'router3') - { -$server = '10.1.1.3'; -$login_pass = 'zebra'; -$bgpd = "2605"; -$zebra = "2601"; -$full_tables=1; - } - -elsif ($Form{'router'} eq 'router4') - { -$server = '10.1.1.4'; -$login_pass = 'zebra'; -$bgpd = "2605"; -$zebra = "2601"; - } - - -} - - -############################################################ -sub set_command -############################################################ -{ -if ($Form{'query'} eq '1') - { - sh_ip_bgp('ip'); - } - -elsif ($Form{'query'} eq '2') - { - sh_ip_bgp_sum('ip'); - } - -if ($Form{'query'} eq '3') - { - sh_ip_route('ip'); - } - -if ($Form{'query'} eq '4') - { - sh_int(); - } -if ($Form{'query'} eq '5') - { - sh_ip_bgp('ipv6'); - } -if ($Form{'query'} eq '6') - { - sh_ip_bgp_sum('ipv6'); - } -if ($Form{'query'} eq '7') - { - sh_ip_route('ipv6'); - } -} -############################################################ -sub sh_ip_bgp -############################################################ -{ -my $protocol = shift(@_); -$port = $bgpd; -if ($protocol ne 'ip' && $protocol ne 'ipv6') - { - print "Invalid protocol: $protocol\n"; - print "protocol must be 'ip' or 'ipv6'\n\n"; - return; - } -$command = "show $protocol bgp $Form{'arg'}"; -if ($Form{'arg'} eq '') - { - if ($full_tables eq '1') - { - execute_command(); - } - else - { - print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; - } - } -else - { - execute_command(); - } -} - -############################################################ -sub sh_ip_bgp_sum -############################################################ -{ - my $protocol = shift(@_); - $port = $bgpd; - if ($protocol ne 'ip' && $protocol ne 'ipv6') - { - print "Invalid protocol: $protocol\n"; - print "protocol must be 'ip' or 'ipv6'\n\n"; - return; - } - $command = "show $protocol bgp summary"; - execute_command(); -} - -############################################################ -sub sh_ip_route -############################################################ -{ - -if ($zebra eq '') - { - print "Sorry. The show ip route command is disabled for this router." - } -else - { - - $port = $zebra; - my $protocol = shift(@_); - if ($protocol ne 'ip' && $protocol ne 'ipv6') - { - print "Invalid protocol: $protocol\n"; - print "protocol must be 'ip' or 'ipv6'\n\n"; - return; - } - $command = "show $protocol route $Form{'arg'}"; - if ($Form{'arg'} eq '') - { - if ($full_tables eq '1') - { - execute_command(); - } - else - { - print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; - } - } - else - { - execute_command(); - } - } -} - -############################################################ -sub sh_int -############################################################ -{ -if ($zebra eq '') - { - print "Sorry. The show interface command is disabled for this router." - } -else - { - $port = $zebra; - $command = "show interface $Form{'arg'}"; - execute_command(); - } -} - - - -############################################################ -sub execute_command -############################################################ -## This code is based on: -## -## Zebra interactive console -## Copyright (C) 2000 Vladimir B. Grebenschikov -## - - -{ - -print "Executing command = $command"; - -# my $port = ($opt_z ? 'zebra' : 0) || -# ($opt_b ? 'bgpd' : 0) || -# ($opt_o ? 'ospfd' : 0) || -# ($opt_r ? 'ripd' : 0) || 'bgpd'; - -my $cmd = $command; - - - my $t = new Net::Telnet (Timeout => 10, - Prompt => '/[\>\#] $/', - Port => $port); - - $t->open ($server); - - $t->cmd ($login_pass); - - if ($cmd) - { - docmd ($t, $cmd); - } - -} - -############################################################ -sub docmd -############################################################ -{ - my ($t, $cmd) = @_; - my @lines = $t->cmd ($cmd); - print "
\n";
-  print join ('', grep (!/[\>\#] $/, @lines)), "\n";
-  print "
"; -} - - - diff --git a/tools/mrlg.txt b/tools/mrlg.txt new file mode 100644 index 000000000..0ebf7ee68 --- /dev/null +++ b/tools/mrlg.txt @@ -0,0 +1,5 @@ +The Multi-Router Looking Glass (MRLG) CGI script now lives at: + + http://mrlg.op-sec.us/ + +Please obtain the latest version from there. From aed1b556cf2f55680ae09d7ad1a1f22729dea8c5 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 21 Oct 2014 16:59:01 +0100 Subject: [PATCH 0416/1342] bgpd: Fixes for recent well-known-attr check patch. * bgp_attr.c: Recent patch to tighten well-known attr checks and apply that to all AFIs has some breakage with MP-extensions and GR, which needs to be fixed. (bgp_attr_check) Graceful Restart EoR can be an empty UPDATE for IPv4/uni. MP-Ext allow UPDATE with just MP_UNREACH_NLRI. Check for these and return proceed. NEXT_HOP becomes optional, if MP_REACH_NLRI is present and there's no v4 NLTI, update NEXT_HOP check accordingly. Print the missing attr in string form in the log message. (bgp_attr_parse) AS_PATH need not be there, so bgp_attr_munge_as4_attrs call needs to be conditional on that. --- bgpd/bgp_attr.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 69ca786db..da17e82e7 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1739,15 +1739,32 @@ bgp_attr_check (struct peer *peer, struct attr *attr) { u_char type = 0; + /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an + * empty UPDATE. */ + if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag) + return BGP_ATTR_PARSE_PROCEED; + + /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required + to carry any other path attributes.", though if MP_REACH_NLRI or NLRI + are present, it should. Check for any other attribute being present + instead. + */ + if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI)) + return BGP_ATTR_PARSE_PROCEED; + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) type = BGP_ATTR_ORIGIN; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) type = BGP_ATTR_AS_PATH; - - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) + + /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and + * NLRI is empty. We can't easily check NLRI empty here though. + */ + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)) + && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) type = BGP_ATTR_NEXT_HOP; - + if (peer->sort == BGP_PEER_IBGP && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) type = BGP_ATTR_LOCAL_PREF; @@ -1755,8 +1772,8 @@ bgp_attr_check (struct peer *peer, struct attr *attr) if (type) { zlog (peer->log, LOG_WARNING, - "%s Missing well-known attribute %d.", - peer->host, type); + "%s Missing well-known attribute %d / %s", + peer->host, type, LOOKUP (attr_str, type)); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MISS_ATTR, @@ -2033,10 +2050,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, * So, to be defensive, we are not relying on any order and read * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. + * + * It is possible to not have AS_PATH, e.g. GR EoR and sole + * MP_UNREACH_NLRI. */ /* actually... this doesn't ever return failure currently, but * better safe than sorry */ - if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)) + && bgp_attr_munge_as4_attrs (peer, attr, as4_path, as4_aggregator, &as4_aggregator_addr)) { bgp_notify_send (peer, From 773224404cb33b2dbd3d8d8d2572013603995ce4 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 12:39:24 -0700 Subject: [PATCH 0417/1342] zebra: Set link-detect on by default Signed-off-by: Roopa Prabhu Reviewed-by: Dinesh G Dutt Reviewed-by: Scott Feldman --- lib/if.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/if.c b/lib/if.c index 3a1f9b415..2b46a1bb9 100644 --- a/lib/if.c +++ b/lib/if.c @@ -132,6 +132,9 @@ if_create (const char *name, int namelen) ifp->connected = list_new (); ifp->connected->del = (void (*) (void *)) connected_free; + /* Enable Link-detection by default */ + SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + if (if_master.if_new_hook) (*if_master.if_new_hook) (ifp); From 93b344f3b14390e3952ea9025ac5996ae9131148 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 28 Oct 2014 14:52:49 +0100 Subject: [PATCH 0418/1342] Revert "zebra: Set link-detect on by default" This reverts commit 773224404cb33b2dbd3d8d8d2572013603995ce4. This patch is nontrivial but wasn't passed along on the mailing list; this is a revert purely on procedural reasons. Signed-off-by: David Lamparter --- lib/if.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/if.c b/lib/if.c index 2b46a1bb9..3a1f9b415 100644 --- a/lib/if.c +++ b/lib/if.c @@ -132,9 +132,6 @@ if_create (const char *name, int namelen) ifp->connected = list_new (); ifp->connected->del = (void (*) (void *)) connected_free; - /* Enable Link-detection by default */ - SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); - if (if_master.if_new_hook) (*if_master.if_new_hook) (ifp); From 59135bde25441cd39cea0389467eb206fc9030c9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 30 Oct 2014 06:19:15 +0100 Subject: [PATCH 0419/1342] build: fix 9562a77... (mrlg removal) mrlg.cgi was removed in 9562a77 "mrlg: Remove obsolete version." but the file was still listed in Makefile.am. Fixes: 9562a77 ("mrlg: Remove obsolete version.") Signed-off-by: David Lamparter --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6916470bd..b6082535c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,7 +11,7 @@ DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ - tools/mrlg.cgi tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ + tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ tools/zebra.el tools/multiple-bgpd.sh \ fpm/fpm.h From c68f6d9dbb9f910d3ee82e099655fff7c12ef856 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 30 Oct 2014 06:42:00 +0100 Subject: [PATCH 0420/1342] tests: fix tests for 055086f (well-known attr check) Fix tests/aspathtest.c by including an ORIGIN attribute in the testcases. After 055086f "bgpd: well-known attr check only run for v4/uni, which could cause a crash," we're now checking for it and tests are failing due to that. Note that test #11 ("4b AS4_PATH w/o AS_PATH") is no longer accepted as OK since the function now checks for the existence of an AS_PATH attr. Fixes: 055086f ("bgpd: well-known attr check only run for v4/uni"...) Signed-off-by: David Lamparter --- tests/aspath_test.c | 76 ++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 0e57c535d..71a310222 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -453,6 +453,13 @@ static struct test_segment { }, { NULL, NULL, {0}, 0, { NULL, 0, 0 } } }; +#define COMMON_ATTRS \ + BGP_ATTR_FLAG_TRANS, \ + BGP_ATTR_ORIGIN, \ + 1, \ + BGP_ORIGIN_EGP +#define COMMON_ATTR_SIZE 4 + /* */ static struct aspath_tests { const char *desc; @@ -474,11 +481,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS2_DATA, 0, 0, - { BGP_ATTR_FLAG_TRANS, - BGP_ATTR_AS_PATH, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, 10, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 1 */ { @@ -487,11 +495,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS2_DATA, -1, 0, - { BGP_ATTR_FLAG_TRANS, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 8, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 2 */ { @@ -500,11 +509,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS2_DATA, -1, 0, - { BGP_ATTR_FLAG_TRANS, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 12, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 3 */ { @@ -513,11 +523,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS2_DATA, -1, 0, - { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 10, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 4 */ { @@ -526,11 +537,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS2_DATA, -1, 0, - { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 5 */ { @@ -539,11 +551,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV, - { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 6 */ { @@ -552,11 +565,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, 0, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 18, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 7 */ { @@ -565,11 +579,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 16, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 8 */ { @@ -578,11 +593,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 20, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 9 */ { @@ -591,11 +607,12 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 22, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 10 */ { @@ -604,24 +621,26 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 18, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 11 */ { "4b AS4_PATH w/o AS_PATH", &test_segments[6], NULL, - AS4_DATA, 0, + AS4_DATA, -1, PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, - 3, + COMMON_ATTR_SIZE + 3, }, /* 12 */ { @@ -630,11 +649,12 @@ static struct aspath_tests { "8466 3 52737 4096 (123 456 789)", AS4_DATA, 0, PEER_CAP_AS4_ADV, - { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, + { COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, - 3, + COMMON_ATTR_SIZE + 3, &test_segments[0], }, { NULL, NULL, NULL, 0, 0, 0, { 0 }, 0 }, From 9511633e08ff15c23608983fdc1bc735d427332e Mon Sep 17 00:00:00 2001 From: Balaji Date: Thu, 23 Oct 2014 15:25:25 +0000 Subject: [PATCH 0421/1342] zebra: MBGP routes should not be installed in the kernel MBGP routes are used only for PIM RPF checks and hence should not be installed in the kernel's FIB. Ignore route node set to Multicast SAFI. Signed-off-by: Balaji.G Acked-by: Everton Marques [pushed down rn->table->info assignment below assert] Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index dc7e1ca19..b1d88369a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1249,9 +1249,12 @@ rib_process (struct route_node *rn) struct nexthop *nexthop = NULL, *tnexthop; int recursing; char buf[INET6_ADDRSTRLEN]; - + rib_table_info_t *info; + assert (rn); - + + info = rn->table->info; + if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); @@ -1286,6 +1289,9 @@ rib_process (struct route_node *rn) if (! nexthop_active_update (rn, rib, 0)) continue; + if (info->safi == SAFI_MULTICAST) + continue; + /* Infinit distance. */ if (rib->distance == DISTANCE_INFINITY) continue; From 88d37b902bc8127379d3293b9671aa6a11479c23 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 3 Nov 2014 01:20:09 +0000 Subject: [PATCH 0422/1342] make some structures constant. These pre-initialized arrays are not modified. Signed-off-by: Stephen Hemminger Acked-by: Feng Lu --- isisd/isis_pdu.c | 2 +- ripd/rip_interface.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index e0208fa47..8d8a5e001 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -62,7 +62,7 @@ #endif /* PNBBY */ /* Utility mask array. */ -static u_char maskbit[] = { +static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index bdd319e17..35685a75b 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -50,7 +50,7 @@ static int rip_enable_if_lookup (const char *ifname); static int rip_enable_network_lookup2 (struct connected *connected); static void rip_enable_apply_all (void); -struct message ri_version_msg[] = +const struct message ri_version_msg[] = { {RI_RIP_VERSION_1, "1"}, {RI_RIP_VERSION_2, "2"}, From 50f38b3500a6af6e1b0d1389d65c62d70c41e8c2 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 12:53:28 -0700 Subject: [PATCH 0423/1342] Compute and display SPF execution statistics Detailed SPF statistics, all around time spent executing various pieces of SPF such as the SPF algorithm itself, installing routes, pruning unreachable networks etc. Reason codes for firing up SPF are: R - Router LSA, N - Network LSA, S - Summary LSA, ABR - ABR status change, ASBR - ASBR Status Change, AS - ASBR Summary, M - MaxAge Signed-off-by: Dinesh G Dutt Reviewed-by: JR Rivers Reviewed-by: Scott Feldman Reviewed-by: Ayan Banerjee Reviewed-by: Paul Jakma --- lib/thread.c | 2 +- lib/thread.h | 1 + ospfd/ospf_abr.c | 1 + ospfd/ospf_asbr.c | 1 + ospfd/ospf_ase.c | 9 ++++ ospfd/ospf_dump.c | 21 ++++++--- ospfd/ospf_lsa.c | 16 +++++-- ospfd/ospf_spf.c | 115 ++++++++++++++++++++++++++++++++++++++++------ ospfd/ospf_spf.h | 13 ++++++ ospfd/ospf_vty.c | 3 ++ ospfd/ospfd.h | 6 ++- 11 files changed, 161 insertions(+), 27 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 9c3ee8238..cb5133233 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -102,7 +102,7 @@ timeval_cmp (struct timeval a, struct timeval b) ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); } -static unsigned long +unsigned long timeval_elapsed (struct timeval a, struct timeval b) { return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) diff --git a/lib/thread.h b/lib/thread.h index 9743a22d1..4856dec74 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -211,6 +211,7 @@ extern struct thread *thread_fetch (struct thread_master *, struct thread *); extern void thread_call (struct thread *); extern unsigned long thread_timer_remain_second (struct thread *); extern int thread_should_yield (struct thread *); +extern unsigned long timeval_elapsed (struct timeval a, struct timeval b); /* Internal libzebra exports */ extern void thread_getrusage (RUSAGE_T *); diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 4bb70b6a9..ca1af2c4a 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -556,6 +556,7 @@ ospf_check_abr_status (struct ospf *ospf) if (new_flags != ospf->flags) { + ospf_flag_spf_reason (SPF_FLAG_ABR_STATUS_CHANGE); ospf_spf_calculate_schedule (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_check_abr_status(): new router flags: %x",new_flags); diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 7e9412c88..dbf7f11f5 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -264,6 +264,7 @@ ospf_asbr_status_update (struct ospf *ospf, u_char status) } /* Transition from/to status ASBR, schedule timer. */ + ospf_flag_spf_reason (SPF_FLAG_ASBR_STATUS_CHANGE); ospf_spf_calculate_schedule (ospf); ospf_router_lsa_update (ospf); } diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 6a72e31dc..9038b3a5c 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -636,6 +636,7 @@ ospf_ase_calculate_timer (struct thread *t) struct route_node *rn; struct listnode *node; struct ospf_area *area; + struct timeval start_time, stop_time; ospf = THREAD_ARG (t); ospf->t_ase_calc = NULL; @@ -644,6 +645,8 @@ ospf_ase_calculate_timer (struct thread *t) { ospf->ase_calc = 0; + quagga_gettime(QUAGGA_CLK_MONOTONIC, &start_time); + /* Calculate external route for each AS-external-LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_ase_calculate_route (ospf, lsa); @@ -673,6 +676,12 @@ ospf_ase_calculate_timer (struct thread *t) ospf_route_table_free (ospf->old_external_route); ospf->old_external_route = ospf->new_external_route; ospf->new_external_route = route_table_init (); + + quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time); + + zlog_info ("SPF Processing Time(usecs): External Routes: %d\n", + (stop_time.tv_sec - start_time.tv_sec)*1000000L+ + (stop_time.tv_usec - start_time.tv_usec)); } return 0; } diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index ef023366a..ebcc717ff 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -247,16 +247,21 @@ ospf_timeval_dump (struct timeval *t, char *buf, size_t size) #define HOUR_IN_SECONDS (60*MINUTE_IN_SECONDS) #define DAY_IN_SECONDS (24*HOUR_IN_SECONDS) #define WEEK_IN_SECONDS (7*DAY_IN_SECONDS) - unsigned long w, d, h, m, s, ms; + unsigned long w, d, h, m, s, ms, us; if (!t) return "inactive"; - w = d = h = m = s = ms = 0; + w = d = h = m = s = ms = us = 0; memset (buf, 0, size); - - ms = t->tv_usec / 1000; - + + us = t->tv_usec; + if (us >= 1000) + { + ms = us / 1000; + us %= 1000; + } + if (ms >= 1000) { t->tv_sec += ms / 1000; @@ -297,9 +302,11 @@ ospf_timeval_dump (struct timeval *t, char *buf, size_t size) snprintf (buf, size, "%ldh%02ldm%02lds", h, m, t->tv_sec); else if (m) snprintf (buf, size, "%ldm%02lds", m, t->tv_sec); - else + else if (ms) snprintf (buf, size, "%ld.%03lds", t->tv_sec, ms); - + else + snprintf (buf, size, "%ld usecs", t->tv_usec); + return buf; } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index fef6b162f..31cbaaef2 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2409,8 +2409,10 @@ ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new, ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) - ospf_spf_calculate_schedule (ospf); - + { + ospf_flag_spf_reason (SPF_FLAG_ROUTER_LSA_INSTALL); + ospf_spf_calculate_schedule (ospf); + } return new; } @@ -2444,7 +2446,10 @@ ospf_network_lsa_install (struct ospf *ospf, ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) - ospf_spf_calculate_schedule (ospf); + { + ospf_flag_spf_reason (SPF_FLAG_NETWORK_LSA_INSTALL); + ospf_spf_calculate_schedule (ospf); + } return new; } @@ -2467,11 +2472,10 @@ ospf_summary_lsa_install (struct ospf *ospf, struct ospf_lsa *new, /* This doesn't exist yet... */ ospf_summary_incremental_update(new); */ #else /* #if 0 */ + ospf_flag_spf_reason (SPF_FLAG_SUMMARY_LSA_INSTALL); ospf_spf_calculate_schedule (ospf); #endif /* #if 0 */ - if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) - zlog_debug ("ospf_summary_lsa_install(): SPF scheduled"); } if (IS_LSA_SELF (new)) @@ -2500,6 +2504,7 @@ ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new, - RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */ #else /* #if 0 */ + ospf_flag_spf_reason (SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); ospf_spf_calculate_schedule (ospf); #endif /* #if 0 */ } @@ -3022,6 +3027,7 @@ ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) ospf_ase_incremental_update (ospf, lsa); break; default: + ospf_flag_spf_reason (SPF_FLAG_MAXAGE); ospf_spf_calculate_schedule (ospf); break; } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index c40fc33ef..a7155bc64 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -46,6 +46,50 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "ospfd/ospf_abr.h" #include "ospfd/ospf_dump.h" +/* Variables to ensure a SPF scheduled log message is printed only once */ + +static unsigned int spf_reason_flags = 0; + +static void ospf_clear_spf_reason_flags () +{ + spf_reason_flags = 0; +} + +void ospf_flag_spf_reason (unsigned int reason) +{ + if (reason <= SPF_FLAG_MAX_VALUE) + spf_reason_flags |= reason; + else + spf_reason_flags |= SPF_FLAG_MISC; +} + +static void +ospf_get_spf_reason_str (char *buf) +{ + if (buf) + { + buf[0] = '\0'; + if (spf_reason_flags) + { + if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) + strcat (buf, "R, "); + if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) + strcat (buf, "N, "); + if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) + strcat (buf, "S, "); + if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) + strcat (buf, "AS, "); + if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) + strcat (buf, "ABR, "); + if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) + strcat (buf, "ASBR, "); + if (spf_reason_flags & SPF_FLAG_MAXAGE) + strcat (buf, "M, "); + } + buf[strlen(buf)-2] = '\0'; /* skip the last ", " */ + } +} + static void ospf_vertex_free (void *); /* List of allocated vertices, to simplify cleanup of SPF. * Not thread-safe obviously. If it ever needs to be, it'd have to be @@ -1232,27 +1276,28 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, /* Free candidate queue. */ pqueue_delete (candidate); - + ospf_vertex_dump (__func__, area->spf, 0, 1); /* Free nexthop information, canonical versions of which are attached * the first level of router vertices attached to the root vertex, see * ospf_nexthop_calculation. */ ospf_canonical_nexthops_free (area->spf); - - /* Free SPF vertices, but not the list. List has ospf_vertex_free - * as deconstructor. - */ - list_delete_all_node (&vertex_list); - + /* Increment SPF Calculation Counter. */ area->spf_calculation++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); + area->ts_spf = area->ospf->ts_spf; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); + + /* Free SPF vertices, but not the list. List has ospf_vertex_free + * as deconstructor. + */ + list_delete_all_node (&vertex_list); } /* Timer for SPF calculation. */ @@ -1263,12 +1308,18 @@ ospf_spf_calculate_timer (struct thread *thread) struct route_table *new_table, *new_rtrs; struct ospf_area *area; struct listnode *node, *nnode; + struct timeval start_time, stop_time, spf_start_time; + int areas_processed = 0; + unsigned long ia_time, prune_time, rt_time; + unsigned long abr_time, total_spf_time, spf_time; + char rbuf[32]; /* reason_buf */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: Timer (SPF calculation expire)"); ospf->t_spf_calc = NULL; + quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time); /* Allocate new table tree. */ new_table = route_table_init (); new_rtrs = route_table_init (); @@ -1283,21 +1334,36 @@ ospf_spf_calculate_timer (struct thread *thread) */ if (ospf->backbone && ospf->backbone == area) continue; - + ospf_spf_calculate (area, new_table, new_rtrs); + areas_processed++; } - + /* SPF for backbone, if required */ if (ospf->backbone) - ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); - + { + ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); + areas_processed++; + } + + quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); + spf_time = timeval_elapsed (stop_time, spf_start_time); + ospf_vl_shut_unapproved (ospf); + start_time = stop_time; /* saving a call */ + ospf_ia_routing (ospf, new_table, new_rtrs); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); + ia_time = timeval_elapsed (stop_time, start_time); + + quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); ospf_prune_unreachable_networks (new_table); ospf_prune_unreachable_routers (new_rtrs); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); + prune_time = timeval_elapsed (stop_time, start_time); /* AS-external-LSA calculation should not be performed here. */ /* If new Router Route is installed, @@ -1307,9 +1373,13 @@ ospf_spf_calculate_timer (struct thread *thread) ospf_ase_calculate_timer_add (ospf); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); + /* Update routing table. */ ospf_route_install (ospf, new_table); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); + rt_time = timeval_elapsed (stop_time, start_time); /* Update ABR/ASBR routing table */ if (ospf->old_rtrs) { @@ -1321,11 +1391,28 @@ ospf_spf_calculate_timer (struct thread *thread) ospf->old_rtrs = ospf->new_rtrs; ospf->new_rtrs = new_rtrs; + quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); if (IS_OSPF_ABR (ospf)) ospf_abr_task (ospf); - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF: calculation complete"); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); + abr_time = timeval_elapsed (stop_time, start_time); + + quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); + total_spf_time = timeval_elapsed (stop_time, spf_start_time); + ospf->ts_spf_duration.tv_sec = total_spf_time/1000000; + ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000; + + ospf_get_spf_reason_str (rbuf); + + if (IS_OSPF_ABR (ospf)) + zlog_info ("SPF Processing Time(usecs): # Areas: %d, SPF Time: %ld, InterArea: %ld, Prune: %ld, RouteInstall: %ld, ABR: %ld, Total: %ld, Reason: %s\n", + areas_processed, spf_time, ia_time, prune_time, rt_time, abr_time, total_spf_time, rbuf); + else + zlog_info ("SPF Processing Time(usecs): SPF Time: %ld, InterArea: %ld, Prune: %ld, RouteInstall: %ld, Total: %ld, Reason: %s\n", + spf_time, ia_time, prune_time, rt_time, total_spf_time, rbuf); + + ospf_clear_spf_reason_flags (); return 0; } @@ -1389,6 +1476,8 @@ ospf_spf_calculate_schedule (struct ospf *ospf) if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer delay = %ld", delay); + zlog_info ("SPF: Scheduled in %ld msec", delay); + ospf->t_spf_calc = thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); } diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h index c1316e4cc..c9c539ad7 100644 --- a/ospfd/ospf_spf.h +++ b/ospfd/ospf_spf.h @@ -64,4 +64,17 @@ extern void ospf_rtrs_free (struct route_table *); /* void ospf_spf_calculate_timer_add (); */ +/* What triggered the SPF ? Can have at most 32 reasons with this */ +#define SPF_FLAG_ROUTER_LSA_INSTALL 0x1 +#define SPF_FLAG_NETWORK_LSA_INSTALL 0x2 +#define SPF_FLAG_SUMMARY_LSA_INSTALL 0x4 +#define SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL 0x8 +#define SPF_FLAG_MAXAGE 0x10 +#define SPF_FLAG_ABR_STATUS_CHANGE 0x20 +#define SPF_FLAG_ASBR_STATUS_CHANGE 0x40 +#define SPF_FLAG_MAX_VALUE 0x40 /* Update this when adding flags */ +#define SPF_FLAG_MISC 0x1000000 /* Keep this last */ + +extern void ospf_flag_spf_reason (unsigned int reason); + #endif /* _QUAGGA_OSPF_SPF_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 97fcffd11..5674da0cd 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2749,6 +2749,9 @@ DEFUN (show_ip_ospf, vty_out (vty, "last executed %s ago%s", ospf_timeval_dump (&result, timebuf, sizeof (timebuf)), VTY_NEWLINE); + vty_out (vty, " Last SPF duration %s%s", + ospf_timeval_dump (&ospf->ts_spf_duration, timebuf, sizeof (timebuf)), + VTY_NEWLINE); } else vty_out (vty, "has not been run%s", VTY_NEWLINE); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 4242aa01b..bf70d0227 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -194,8 +194,9 @@ struct ospf struct route_table *external_lsas; /* Database of external LSAs, prefix is LSA's adv. network*/ - /* Time stamps. */ + /* Time stamps */ struct timeval ts_spf; /* SPF calculation time stamp. */ + struct timeval ts_spf_duration; /* Execution time of last SPF */ struct route_table *maxage_lsa; /* List of MaxAge LSA for deletion. */ int redistribute; /* Num of redistributed protocols. */ @@ -393,6 +394,9 @@ struct ospf_area /* Statistics field. */ u_int32_t spf_calculation; /* SPF Calculation Count. */ + /* Time stamps. */ + struct timeval ts_spf; /* SPF calculation time stamp. */ + /* Router count. */ u_int32_t abr_count; /* ABR router in this area. */ u_int32_t asbr_count; /* ASBR router in this area. */ From b6eef003e1a79471addea0b01853b08aed812cc8 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Oct 2014 14:19:51 +0100 Subject: [PATCH 0424/1342] ospfd: Some small tweaks to the SPF execution reason patch * ospf_spf.h: use an enum for the reason, and have it as a new argument to ospf_spf_calculate_schedule, no need for additional call, and let compiler do the checking. * ospf_spf.c: format changes - Quagga coding style places function names at the start of a new line, for easy grepping for definition. (ospf_spf_calculate_timer) Change the log format of SPF execution time to avoid ginormous line, and make logging conditional, as is the norm. --- ospfd/ospf_abr.c | 3 +- ospfd/ospf_asbr.c | 3 +- ospfd/ospf_ase.c | 2 +- ospfd/ospf_lsa.c | 19 ++++-------- ospfd/ospf_spf.c | 73 ++++++++++++++++++++++++++--------------------- ospfd/ospf_spf.h | 28 +++++++++--------- ospfd/ospf_vty.c | 6 ++-- 7 files changed, 64 insertions(+), 70 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index ca1af2c4a..e172e53cd 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -556,8 +556,7 @@ ospf_check_abr_status (struct ospf *ospf) if (new_flags != ospf->flags) { - ospf_flag_spf_reason (SPF_FLAG_ABR_STATUS_CHANGE); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_ABR_STATUS_CHANGE); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_check_abr_status(): new router flags: %x",new_flags); ospf->flags = new_flags; diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index dbf7f11f5..8bef1754f 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -264,8 +264,7 @@ ospf_asbr_status_update (struct ospf *ospf, u_char status) } /* Transition from/to status ASBR, schedule timer. */ - ospf_flag_spf_reason (SPF_FLAG_ASBR_STATUS_CHANGE); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_ASBR_STATUS_CHANGE); ospf_router_lsa_update (ospf); } diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 9038b3a5c..8aedc8088 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -679,7 +679,7 @@ ospf_ase_calculate_timer (struct thread *t) quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time); - zlog_info ("SPF Processing Time(usecs): External Routes: %d\n", + zlog_info ("SPF Processing Time(usecs): External Routes: %ld\n", (stop_time.tv_sec - start_time.tv_sec)*1000000L+ (stop_time.tv_usec - start_time.tv_usec)); } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 31cbaaef2..94c31c9f1 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2409,10 +2409,7 @@ ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new, ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) - { - ospf_flag_spf_reason (SPF_FLAG_ROUTER_LSA_INSTALL); - ospf_spf_calculate_schedule (ospf); - } + ospf_spf_calculate_schedule (ospf, SPF_FLAG_ROUTER_LSA_INSTALL); return new; } @@ -2446,10 +2443,7 @@ ospf_network_lsa_install (struct ospf *ospf, ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) - { - ospf_flag_spf_reason (SPF_FLAG_NETWORK_LSA_INSTALL); - ospf_spf_calculate_schedule (ospf); - } + ospf_spf_calculate_schedule (ospf, SPF_FLAG_NETWORK_LSA_INSTALL); return new; } @@ -2472,8 +2466,7 @@ ospf_summary_lsa_install (struct ospf *ospf, struct ospf_lsa *new, /* This doesn't exist yet... */ ospf_summary_incremental_update(new); */ #else /* #if 0 */ - ospf_flag_spf_reason (SPF_FLAG_SUMMARY_LSA_INSTALL); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ } @@ -2504,8 +2497,7 @@ ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new, - RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */ #else /* #if 0 */ - ospf_flag_spf_reason (SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ } @@ -3027,8 +3019,7 @@ ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) ospf_ase_incremental_update (ospf, lsa); break; default: - ospf_flag_spf_reason (SPF_FLAG_MAXAGE); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_MAXAGE); break; } ospf_lsa_maxage (ospf, lsa); diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index a7155bc64..1fe8ab4b4 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -50,42 +50,41 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA static unsigned int spf_reason_flags = 0; -static void ospf_clear_spf_reason_flags () +static void +ospf_clear_spf_reason_flags () { spf_reason_flags = 0; } -void ospf_flag_spf_reason (unsigned int reason) +static void +ospf_spf_set_reason (ospf_spf_reason_t reason) { - if (reason <= SPF_FLAG_MAX_VALUE) - spf_reason_flags |= reason; - else - spf_reason_flags |= SPF_FLAG_MISC; + spf_reason_flags |= 1 << reason; } static void ospf_get_spf_reason_str (char *buf) { - if (buf) + if (!buf) + return; + + buf[0] = '\0'; + if (spf_reason_flags) { - buf[0] = '\0'; - if (spf_reason_flags) - { - if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) - strcat (buf, "R, "); - if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) - strcat (buf, "N, "); - if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) - strcat (buf, "S, "); - if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) - strcat (buf, "AS, "); - if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) - strcat (buf, "ABR, "); - if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) - strcat (buf, "ASBR, "); - if (spf_reason_flags & SPF_FLAG_MAXAGE) - strcat (buf, "M, "); - } + if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) + strcat (buf, "R, "); + if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) + strcat (buf, "N, "); + if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) + strcat (buf, "S, "); + if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) + strcat (buf, "AS, "); + if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) + strcat (buf, "ABR, "); + if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) + strcat (buf, "ASBR, "); + if (spf_reason_flags & SPF_FLAG_MAXAGE) + strcat (buf, "M, "); buf[strlen(buf)-2] = '\0'; /* skip the last ", " */ } } @@ -1313,7 +1312,7 @@ ospf_spf_calculate_timer (struct thread *thread) unsigned long ia_time, prune_time, rt_time; unsigned long abr_time, total_spf_time, spf_time; char rbuf[32]; /* reason_buf */ - + if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: Timer (SPF calculation expire)"); @@ -1405,12 +1404,18 @@ ospf_spf_calculate_timer (struct thread *thread) ospf_get_spf_reason_str (rbuf); - if (IS_OSPF_ABR (ospf)) - zlog_info ("SPF Processing Time(usecs): # Areas: %d, SPF Time: %ld, InterArea: %ld, Prune: %ld, RouteInstall: %ld, ABR: %ld, Total: %ld, Reason: %s\n", - areas_processed, spf_time, ia_time, prune_time, rt_time, abr_time, total_spf_time, rbuf); - else - zlog_info ("SPF Processing Time(usecs): SPF Time: %ld, InterArea: %ld, Prune: %ld, RouteInstall: %ld, Total: %ld, Reason: %s\n", - spf_time, ia_time, prune_time, rt_time, total_spf_time, rbuf); + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("SPF Processing Time(usecs): %ld", total_spf_time); + zlog_info ("\t SPF Time: %ld", spf_time); + zlog_info ("\t InterArea: %ld", ia_time); + zlog_info ("\t Prune: %ld", prune_time); + zlog_info ("\tRouteInstall: %ld", rt_time); + if (IS_OSPF_ABR (ospf)) + zlog_info ("\t ABR: %ld (%d areas)", + abr_time, areas_processed); + zlog_info ("Reason(s) for SPF: %s", rbuf); + } ospf_clear_spf_reason_flags (); @@ -1420,7 +1425,7 @@ ospf_spf_calculate_timer (struct thread *thread) /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ void -ospf_spf_calculate_schedule (struct ospf *ospf) +ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason) { unsigned long delay, elapsed, ht; struct timeval result; @@ -1432,6 +1437,8 @@ ospf_spf_calculate_schedule (struct ospf *ospf) if (ospf == NULL) return; + ospf_spf_set_reason (reason); + /* SPF calculation timer is already scheduled. */ if (ospf->t_spf_calc) { diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h index c9c539ad7..e33b3e5f5 100644 --- a/ospfd/ospf_spf.h +++ b/ospfd/ospf_spf.h @@ -59,22 +59,20 @@ struct vertex_parent int backlink; /* index back to parent for router-lsa's */ }; -extern void ospf_spf_calculate_schedule (struct ospf *); +/* What triggered the SPF ? */ +typedef enum { + SPF_FLAG_ROUTER_LSA_INSTALL = 1, + SPF_FLAG_NETWORK_LSA_INSTALL, + SPF_FLAG_SUMMARY_LSA_INSTALL, + SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL, + SPF_FLAG_MAXAGE, + SPF_FLAG_ABR_STATUS_CHANGE, + SPF_FLAG_ASBR_STATUS_CHANGE, + SPF_FLAG_CONFIG_CHANGE, +} ospf_spf_reason_t; + +extern void ospf_spf_calculate_schedule (struct ospf *, ospf_spf_reason_t); extern void ospf_rtrs_free (struct route_table *); /* void ospf_spf_calculate_timer_add (); */ - -/* What triggered the SPF ? Can have at most 32 reasons with this */ -#define SPF_FLAG_ROUTER_LSA_INSTALL 0x1 -#define SPF_FLAG_NETWORK_LSA_INSTALL 0x2 -#define SPF_FLAG_SUMMARY_LSA_INSTALL 0x4 -#define SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL 0x8 -#define SPF_FLAG_MAXAGE 0x10 -#define SPF_FLAG_ABR_STATUS_CHANGE 0x20 -#define SPF_FLAG_ASBR_STATUS_CHANGE 0x40 -#define SPF_FLAG_MAX_VALUE 0x40 /* Update this when adding flags */ -#define SPF_FLAG_MISC 0x1000000 /* Keep this last */ - -extern void ospf_flag_spf_reason (unsigned int reason); - #endif /* _QUAGGA_OSPF_SPF_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 5674da0cd..72493a201 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -771,7 +771,7 @@ ospf_find_vl_data (struct ospf *ospf, struct ospf_vl_config_data *vl_config) { vl_data->vl_oi = ospf_vl_new (ospf, vl_data); ospf_vl_add (ospf, vl_data); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_CONFIG_CHANGE); } } return vl_data; @@ -2172,7 +2172,7 @@ DEFUN (ospf_compatible_rfc1583, if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { SET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_CONFIG_CHANGE); } return CMD_SUCCESS; } @@ -2189,7 +2189,7 @@ DEFUN (no_ospf_compatible_rfc1583, if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { UNSET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); - ospf_spf_calculate_schedule (ospf); + ospf_spf_calculate_schedule (ospf, SPF_FLAG_CONFIG_CHANGE); } return CMD_SUCCESS; } From d1b0991ad8404366811a7ccc86e76f70a1ba399e Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 12:54:13 -0700 Subject: [PATCH 0425/1342] Make static IPv6 routes respect non-default routing tables. Signed-off-by: Nolan Leake Reviewed-by: Shrijeet Mukherjee Reviewed-by: Paul Jakma --- zebra/zebra_rib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b1d88369a..245011ebf 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2916,6 +2916,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; + rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; switch (si->type) From 56a5f7752d9bf7297ea022544112909cf2ccba97 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 12:58:04 -0700 Subject: [PATCH 0426/1342] Added show command to display only the routes in the RIB that does not count ECMPs Signed-off-by: Ayan Banerjee Reviewed-by: JR Rivers Reviewed-by: Paul Jakma --- zebra/zebra_vty.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 1d12ac5f1..9d6c1dddb 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1074,6 +1074,84 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table) fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); } +/* + * Implementation of the ip route summary prefix command. + * + * This command prints the primary prefixes that have been installed by various + * protocols on the box. + * + */ +static void +vty_show_ip_route_summary_prefix (struct vty *vty, struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; +#define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX +#define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1) + u_int32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1]; + u_int32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1]; + u_int32_t i; + int cnt; + + memset (&rib_cnt, 0, sizeof(rib_cnt)); + memset (&fib_cnt, 0, sizeof(fib_cnt)); + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + + /* + * In case of ECMP, count only once. + */ + cnt = 0; + for (nexthop = rib->nexthop; (!cnt && nexthop); nexthop = nexthop->next) + { + cnt++; + rib_cnt[ZEBRA_ROUTE_TOTAL]++; + rib_cnt[rib->type]++; + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + fib_cnt[ZEBRA_ROUTE_TOTAL]++; + fib_cnt[rib->type]++; + } + if (rib->type == ZEBRA_ROUTE_BGP && + CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) + { + rib_cnt[ZEBRA_ROUTE_IBGP]++; + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + fib_cnt[ZEBRA_ROUTE_IBGP]++; + } + } + } + + vty_out (vty, "%-20s %-20s %-20s %s", + "Route Source", "Prefix Routes", "FIB", VTY_NEWLINE); + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rib_cnt[i] > 0) + { + if (i == ZEBRA_ROUTE_BGP) + { + vty_out (vty, "%-20s %-20d %-20d %s", "ebgp", + rib_cnt[ZEBRA_ROUTE_BGP] - rib_cnt[ZEBRA_ROUTE_IBGP], + fib_cnt[ZEBRA_ROUTE_BGP] - fib_cnt[ZEBRA_ROUTE_IBGP], + VTY_NEWLINE); + vty_out (vty, "%-20s %-20d %-20d %s", "ibgp", + rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_IBGP], + VTY_NEWLINE); + } + else + vty_out (vty, "%-20s %-20d %-20d %s", zebra_route_string(i), + rib_cnt[i], fib_cnt[i], VTY_NEWLINE); + } + } + + vty_out (vty, "------%s", VTY_NEWLINE); + vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL], + fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); +} + /* Show route summary. */ DEFUN (show_ip_route_summary, show_ip_route_summary_cmd, @@ -1094,6 +1172,27 @@ DEFUN (show_ip_route_summary, return CMD_SUCCESS; } +/* Show route summary prefix. */ +DEFUN (show_ip_route_summary_prefix, + show_ip_route_summary_prefix_cmd, + "show ip route summary prefix", + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n" + "Prefix routes\n") +{ + struct route_table *table; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + vty_show_ip_route_summary_prefix (vty, table); + + return CMD_SUCCESS; +} + /* Write IPv4 static route configuration. */ static int static_config_ipv4 (struct vty *vty) @@ -1931,6 +2030,27 @@ DEFUN (show_ipv6_route_summary, return CMD_SUCCESS; } +/* Show ipv6 route summary prefix. */ +DEFUN (show_ipv6_route_summary_prefix, + show_ipv6_route_summary_prefix_cmd, + "show ipv6 route summary prefix", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Summary of all IPv6 routes\n" + "Prefix routes\n") +{ + struct route_table *table; + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + vty_show_ip_route_summary_prefix (vty, table); + + return CMD_SUCCESS; +} + /* * Show IPv6 mroute command.Used to dump * the Multicast routing table. @@ -2100,6 +2220,7 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_route_protocol_cmd); install_element (VIEW_NODE, &show_ip_route_supernets_cmd); install_element (VIEW_NODE, &show_ip_route_summary_cmd); + install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd); install_element (ENABLE_NODE, &show_ip_route_cmd); install_element (ENABLE_NODE, &show_ip_route_addr_cmd); install_element (ENABLE_NODE, &show_ip_route_prefix_cmd); @@ -2107,6 +2228,7 @@ zebra_vty_init (void) install_element (ENABLE_NODE, &show_ip_route_protocol_cmd); install_element (ENABLE_NODE, &show_ip_route_supernets_cmd); install_element (ENABLE_NODE, &show_ip_route_summary_cmd); + install_element (ENABLE_NODE, &show_ip_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (ENABLE_NODE, &show_ip_mroute_cmd); @@ -2131,6 +2253,7 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd); install_element (VIEW_NODE, &show_ipv6_route_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_cmd); + install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); install_element (VIEW_NODE, &show_ipv6_route_addr_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd); @@ -2141,6 +2264,7 @@ zebra_vty_init (void) install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_route_summary_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_mroute_cmd); install_element (ENABLE_NODE, &show_ipv6_mroute_cmd); From 1c06334f51c00471b0731227384ef42dc463db54 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 13:04:45 -0700 Subject: [PATCH 0427/1342] Avoid timing out of adjacencies by serving all interfaces in round-robin. Ensure that all interfaces are served in a round robin fashion during write. This prevents adjacencies from timing out when you have a lot of LSAs to be sent out each adjacency. This is essentially a scalability improvement. Signed-off-by: Ayan Banerjee Reviewed-by: Dinesh G Dutt Reviewed-by: Scott Feldman Reviewed-by: Paul Jakma --- ospfd/ospf_packet.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 17260eb1e..d2504c78d 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -760,6 +760,11 @@ ospf_write (struct thread *thread) sockopt_iphdrincl_swab_htosys (&iph); ret = sendmsg (ospf->fd, &msg, flags); sockopt_iphdrincl_swab_systoh (&iph); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_write to %s, " + "id %d, off %d, len %d, interface %s, mtu %u:", + inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, + oi->ifp->name, oi->ifp->mtu); if (ret < 0) zlog_warn ("*** sendmsg in ospf_write failed to %s, " @@ -789,10 +794,16 @@ ospf_write (struct thread *thread) /* Now delete packet from queue. */ ospf_packet_delete (oi); + /* Move this interface to the tail of write_q to + serve everyone in a round robin fashion */ + list_delete_node (ospf->oi_write_q, node); if (ospf_fifo_head (oi->obuf) == NULL) { oi->on_write_q = 0; - list_delete_node (ospf->oi_write_q, node); + } + else + { + listnode_add (ospf->oi_write_q, oi); } /* If packets still remain in queue, call write thread. */ @@ -3326,7 +3337,7 @@ ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream u_int16_t ls_age; if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_make_ls_upd: List Iteration"); + zlog_debug ("ospf_make_ls_upd: List Iteration %d", count); lsa = listgetdata (node); @@ -3732,7 +3743,8 @@ ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update, u_int16_t length = OSPF_HEADER_SIZE; if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr)); + zlog_debug ("listcount = %d, [%s]dst %s", listcount (update), IF_NAME(oi), + inet_ntoa(addr)); op = ospf_ls_upd_packet_new (update, oi); From 6d831139569dbee69acc631361db917e2c47feeb Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Oct 2014 16:05:15 +0100 Subject: [PATCH 0428/1342] ospfd: Tweak previous iface RR write patch to avoid free/malloc & redundant log * linklist.{c,h}: (listnode_move_to_tail) new unction to move a listnode to tail of list. * ospf_packet.c: (ospf_write) remove debug that seemed to be mostly covered by existing debug. Use listnode_move_to_tail to just move the list node to the end of the tail, rather than freeing the one to hand and allocing a new one. --- lib/linklist.c | 7 +++++++ lib/linklist.h | 1 + ospfd/ospf_packet.c | 12 ++---------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/linklist.c b/lib/linklist.c index 370b2fa61..4b16f07dd 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -159,6 +159,13 @@ listnode_add_after (struct list *list, struct listnode *pp, void *val) list->count++; } +/* Move given listnode to tail of the list */ +void +listnode_move_to_tail (struct list *l, struct listnode *n) +{ + LISTNODE_DETACH(l,n); + LISTNODE_ATTACH(l,n); +} /* Delete specific date pointer from the list. */ void diff --git a/lib/linklist.h b/lib/linklist.h index 24a9e2069..c8d715e12 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -68,6 +68,7 @@ extern void list_free (struct list *); extern void listnode_add (struct list *, void *); extern void listnode_add_sort (struct list *, void *); extern void listnode_add_after (struct list *, struct listnode *, void *); +extern void listnode_move_to_tail (struct list *, struct listnode *); extern void listnode_delete (struct list *, void *); extern struct listnode *listnode_lookup (struct list *, void *); extern void *listnode_head (struct list *); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index d2504c78d..36aa8958a 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -760,11 +760,6 @@ ospf_write (struct thread *thread) sockopt_iphdrincl_swab_htosys (&iph); ret = sendmsg (ospf->fd, &msg, flags); sockopt_iphdrincl_swab_systoh (&iph); - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_write to %s, " - "id %d, off %d, len %d, interface %s, mtu %u:", - inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, - oi->ifp->name, oi->ifp->mtu); if (ret < 0) zlog_warn ("*** sendmsg in ospf_write failed to %s, " @@ -796,14 +791,11 @@ ospf_write (struct thread *thread) /* Move this interface to the tail of write_q to serve everyone in a round robin fashion */ - list_delete_node (ospf->oi_write_q, node); + listnode_move_to_tail (ospf->oi_write_q, node); if (ospf_fifo_head (oi->obuf) == NULL) { oi->on_write_q = 0; - } - else - { - listnode_add (ospf->oi_write_q, oi); + list_delete_node (ospf->oi_write_q, node); } /* If packets still remain in queue, call write thread. */ From 8306be211f1bcd5a19e74d08cde399e1b518ed25 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 14:11:17 -0700 Subject: [PATCH 0429/1342] OSPFd: Update timestamps when we MaxAge LSAs. When an LSA is flushed we need to update the timestamps for them. This allows for the node to give the neighbor sufficient time to send back an acknowledgement before retransmission kicks in. Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman Reviewed-by: James Li Reviewed-by: Paul Jakma --- ospfd/ospf_flood.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 2c33b00ef..d18314a9d 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -980,7 +980,12 @@ ospf_ls_retransmit_delete_nbr_as (struct ospf *ospf, struct ospf_lsa *lsa) void ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area) { + /* Reset the lsa origination time such that it gives + more time for the ACK to be received and avoid + retransmissions */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + lsa->tv_recv = recent_relative_time (); + lsa->tv_orig = lsa->tv_recv; ospf_flood_through_area (area, NULL, lsa); ospf_lsa_maxage (area->ospf, lsa); } @@ -988,7 +993,12 @@ ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area) void ospf_lsa_flush_as (struct ospf *ospf, struct ospf_lsa *lsa) { + /* Reset the lsa origination time such that it gives + more time for the ACK to be received and avoid + retransmissions */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + lsa->tv_recv = recent_relative_time (); + lsa->tv_orig = lsa->tv_recv; ospf_flood_through_as (ospf, NULL, lsa); ospf_lsa_maxage (ospf, lsa); } From ad5233a1bcdd7124992300673ad9c1035336eadd Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Tue, 30 Sep 2014 14:19:57 -0700 Subject: [PATCH 0430/1342] Add set ipv6 next-hop peer-address command. IPv4 has the ability to specify the peer address with the keyword peer-address. IPv6 mandates the use of a specific global or local address only in setting the next-hop in routemaps. This makes it cumbersome to configure some large networks with BGP and IPv6. This patch fixes that deficiency. Signed-off-by: Dinesh G Dutt Reviewed-by: Paul Jakma --- bgpd/bgp_routemap.c | 122 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 06b085924..a1b7f3396 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2021,6 +2021,100 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = route_set_ipv6_nexthop_local_compile, route_set_ipv6_nexthop_local_free }; + +/* `set ipv6 nexthop peer-address' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +static route_map_result_t +route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + int *use_peer_address; + struct in6_addr peer_address; + struct bgp_info *bgp_info; + struct peer *peer; + char peer_addr_buf[INET6_ADDRSTRLEN]; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + use_peer_address = rule; + bgp_info = object; + peer = bgp_info->peer; + + if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || + CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) + && peer->su_remote + && sockunion_family (peer->su_remote) == AF_INET6) + { + inet_pton (AF_INET6, sockunion2str (peer->su_remote, + peer_addr_buf, + INET6_ADDRSTRLEN), + &peer_address); + } + else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) + && peer->su_local + && sockunion_family (peer->su_local) == AF_INET6) + { + inet_pton (AF_INET, sockunion2str (peer->su_local, + peer_addr_buf, + INET6_ADDRSTRLEN), + &peer_address); + } + + if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) + { + /* Set next hop value. */ + (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address; + + /* Set nexthop length. */ + if (bgp_info->attr->extra->mp_nexthop_len != 32) + bgp_info->attr->extra->mp_nexthop_len = 32; + } + else + { + /* Set next hop value. */ + (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address; + + /* Set nexthop length. */ + if (bgp_info->attr->extra->mp_nexthop_len == 0) + bgp_info->attr->extra->mp_nexthop_len = 16; + } + } + + return RMAP_OKAY; +} + +/* Route map `ip next-hop' compile function. Given string is converted + to struct in_addr structure. */ +static void * +route_set_ipv6_nexthop_peer_compile (const char *arg) +{ + int ret; + int *rins = NULL; + + rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); + *rins = 1; + + return rins; +} + +/* Free route map's compiled `ip next-hop' value. */ +static void +route_set_ipv6_nexthop_peer_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = +{ + "ipv6 next-hop peer-address", + route_set_ipv6_nexthop_peer, + route_set_ipv6_nexthop_peer_compile, + route_set_ipv6_nexthop_peer_free +}; + #endif /* HAVE_IPV6 */ /* `set vpnv4 nexthop A.B.C.D' */ @@ -3571,6 +3665,29 @@ DEFUN (no_match_ipv6_address_prefix_list, return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); } +DEFUN (set_ipv6_nexthop_peer, + set_ipv6_nexthop_peer_cmd, + "set ipv6 next-hop peer-address", + SET_STR + IPV6_STR + "Next hop address\n" + "Use peer address (for BGP only)\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop peer-address", NULL); +} + +DEFUN (no_set_ipv6_nexthop_peer, + no_set_ipv6_nexthop_peer_cmd, + "no set ipv6 next-hop peer-address", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + ) +{ + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop", argv[0]); +} + DEFUN (set_ipv6_nexthop_global, set_ipv6_nexthop_global_cmd, "set ipv6 next-hop global X:X::X:X", @@ -3909,7 +4026,8 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); - + route_map_install_set (&route_set_ipv6_nexthop_peer_cmd); + install_element (RMAP_NODE, &match_ipv6_address_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_cmd); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); @@ -3922,6 +4040,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); + install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd); #endif /* HAVE_IPV6 */ /* AS-Pathlimit: functionality removed, commands kept for From 4bab6806914dbb4b43f376ebf966a034a0ea72cd Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 30 Sep 2014 14:32:22 -0700 Subject: [PATCH 0431/1342] Fix to take care of ordering between interface and router ospf command. SYMPTOM: Interface mode OSPF area configuration is not retained after restarting quagga. Example - quagga(config)# interface swp49 quagga(config-if)# ip ospf area 0.0.0.0 quagga# sh run interface swp49 ip ospf area 0.0.0.0 ipv6 nd suppress-ra link-detect ! quagga# write memory * Restart quagga at this point* quagga# sh run interface swp49 ipv6 nd suppress-ra link-detect ! ISSUE: The issue is that the interface mode commands can reach the OSPF process even before 'router ospf' command that initializes the default OSPF instance, this is not getting handled properly in OSPF process. FIX: Initialize the default OSPF instance during OSPF process initializations, which is before 'router ospf' command is received in OSPF process. So, when interface mode command is received, it is guaranteed to have ospf instance to work with. Other way could be to call ospf_get() instead of ospf_lookup() while processing the config command callbacks, although OSPF needs to have at least one instance structure anyways, therefore calling it unconditionally in OSPF initializations should be fine too. There could be more elaborate fix(es) possible to handle this, like adding some ordering mechanism for commands as they are read by a process, or storing the received command and applying it after the commands its dependent upon are processed. For the issue at hand, initializing the default instance in main() serves the purpose well. Signed-off-by: Vipin Kumar Reviewed-by: Dinesh Dutt Reviewed-by: Paul Jakma --- ospfd/ospf_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 82735b731..96dfd5799 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -310,6 +310,15 @@ main (int argc, char **argv) ospf_opaque_init (); #endif /* HAVE_OPAQUE_LSA */ + /* Need to initialize the default ospf structure, so the interface mode + commands can be duly processed if they are received before 'router ospf', + when quagga(ospfd) is restarted */ + if (!ospf_get()) + { + zlog_err("OSPF instance init failed: %s", strerror(errno)); + exit (1); + } + /* Get configuration file. */ vty_read_config (config_file, config_default); From 443010383e2c8e5dc1bc722d9e22a97c513b4647 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Oct 2014 18:14:54 +0100 Subject: [PATCH 0432/1342] bgpd: remove unused variables --- bgpd/bgp_routemap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index a1b7f3396..b74554d63 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2029,7 +2029,6 @@ static route_map_result_t route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - int *use_peer_address; struct in6_addr peer_address; struct bgp_info *bgp_info; struct peer *peer; @@ -2038,7 +2037,6 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - use_peer_address = rule; bgp_info = object; peer = bgp_info->peer; @@ -2090,7 +2088,6 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, static void * route_set_ipv6_nexthop_peer_compile (const char *arg) { - int ret; int *rins = NULL; rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); From dd49eb1f0232cd0600a3565b44b5c066a8d7872d Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 30 Sep 2014 14:36:38 -0700 Subject: [PATCH 0433/1342] Fix BGP's use of restart bit. bgpd-restart-bit-fix.patch ISSUE: Quagga BGP doesn't send or use the restart-bit via the Graceful-Restart(GR) capability. GR capability implementation isn't complete as per the RFC. PATCH: Patch uses BGP instance creation as the beginning of the startup period, and 'restart_time' is taken as the startup period. As a result, BGP will set the restart bit in the GR capability of the OPEN messages during the startup period. As an indication of quagga implementation's capability of sending End-Of-RIB, helping a restarting neighbor, quagga BGP will now send global GR capability irrespective of the graceful-restart config in BGP and the address-family specific GR capability will be sent only if the GR config is present. Forwarding bit is not set assuming its not preserved. Incorporated feedback from David Lamparter via the quagga-dev mailing list. Signed-off-by: Vipin Kumar Reviewed-by: Pradosh Mohapatra Reviewed-by: Paul Jakma --- bgpd/bgp_open.c | 51 +++++++++++++++++++++++++++++++++++++---------- bgpd/bgp_packet.c | 4 ++++ bgpd/bgpd.c | 15 ++++++++++++++ bgpd/bgpd.h | 4 ++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 7bf350165..fe741aa3a 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -344,7 +344,10 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) - restart_bit = 1; + { + SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); + restart_bit = 1; + } UNSET_FLAG (restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; @@ -898,10 +901,11 @@ void bgp_open_capability (struct stream *s, struct peer *peer) { u_char len; - unsigned long cp; + unsigned long cp, capp, rcapp; afi_t afi; safi_t safi; as_t local_as; + u_int32_t restart_time; /* Remember current pointer for Opt Parm Len. */ cp = stream_get_endp (s); @@ -1020,16 +1024,43 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN); } - /* Graceful restart capability */ + /* Sending base graceful-restart capability irrespective of the config */ + SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); + stream_putc (s, BGP_OPEN_OPT_CAP); + capp = stream_get_endp (s); /* Set Capability Len Pointer */ + stream_putc (s, 0); /* Capability Length */ + stream_putc (s, CAPABILITY_CODE_RESTART); + rcapp = stream_get_endp (s); /* Set Restart Capability Len Pointer */ + stream_putc (s, 0); + restart_time = peer->bgp->restart_time; + if (peer->bgp->t_startup) + { + SET_FLAG (restart_time, RESTART_R_BIT); + SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_ADV); + } + stream_putw (s, restart_time); + + /* Send address-family specific graceful-restart capability only when GR config + is present */ if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) { - SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); - stream_putc (s, BGP_OPEN_OPT_CAP); - stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2); - stream_putc (s, CAPABILITY_CODE_RESTART); - stream_putc (s, CAPABILITY_CODE_RESTART_LEN); - stream_putw (s, peer->bgp->restart_time); - } + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (peer->afc[afi][safi]) + { + stream_putw (s, afi); + stream_putc (s, safi); + stream_putc (s, 0); //Forwarding is not retained as of now. + } + } + + /* Total Graceful restart capability Len. */ + len = stream_get_endp (s) - rcapp - 1; + stream_putc_at (s, rcapp, len); + + /* Total Capability Len. */ + len = stream_get_endp (s) - capp - 1; + stream_putc_at (s, capp, len); /* Total Opt Parm Len. */ len = stream_get_endp (s) - cp - 1; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 35a22c1e3..14fd6e51e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -613,6 +613,10 @@ bgp_write_packet (struct peer *peer) { if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) + && ! (CHECK_FLAG (adv->binfo->peer->cap, + PEER_CAP_RESTART_BIT_RCV) && + CHECK_FLAG (adv->binfo->peer->cap, + PEER_CAP_RESTART_BIT_ADV)) && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) && safi != SAFI_MPLS_VPN) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3a9bc480a..79bcaaf05 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1927,6 +1927,18 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, return 0; } + +static int +bgp_startup_timer_expire (struct thread *thread) +{ + struct bgp *bgp; + + bgp = THREAD_ARG (thread); + bgp->t_startup = NULL; + + return 0; +} + /* BGP instance creation by `router bgp' commands. */ static struct bgp * bgp_create (as_t *as, const char *name) @@ -1972,6 +1984,9 @@ bgp_create (as_t *as, const char *name) if (name) bgp->name = strdup (name); + THREAD_TIMER_ON (master, bgp->t_startup, bgp_startup_timer_expire, + bgp, bgp->restart_time); + return bgp; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index eae803de1..40c381c24 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -104,6 +104,8 @@ struct bgp as_t *confed_peers; int confed_peers_cnt; + struct thread *t_startup; + /* BGP flags. */ u_int16_t flags; #define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0) @@ -366,6 +368,8 @@ struct peer #define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */ #define PEER_CAP_AS4_ADV (1 << 7) /* as4 advertised */ #define PEER_CAP_AS4_RCV (1 << 8) /* as4 received */ +#define PEER_CAP_RESTART_BIT_ADV (1 << 9) /* sent restart state */ +#define PEER_CAP_RESTART_BIT_RCV (1 << 10) /* peer restart state */ /* Capability flags (reset in bgp_stop) */ u_int16_t af_cap[AFI_MAX][SAFI_MAX]; From ec98d90767b341877fb7f1547f025b946955899a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 14 Oct 2014 11:14:06 +0100 Subject: [PATCH 0434/1342] bgpd: trivial, remove unneeded extra variable in bgp_capability_restart --- bgpd/bgp_open.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index fe741aa3a..b9d6e93f3 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -338,16 +338,13 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { struct stream *s = BGP_INPUT (peer); u_int16_t restart_flag_time; - int restart_bit = 0; size_t end = stream_get_getp (s) + caphdr->length; SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) - { - SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); - restart_bit = 1; - } + SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); + UNSET_FLAG (restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; @@ -355,7 +352,9 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); zlog_debug ("%s Peer has%srestarted. Restart Time : %d", - peer->host, restart_bit ? " " : " not ", + peer->host, + CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV) ? " " + : " not ", peer->v_gr_restart); } From 1a211cb369dc865a4e7e9f58a100c041af457262 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 1 Nov 2014 17:21:47 +0000 Subject: [PATCH 0435/1342] bgpd: one more fix for tightening of check for missing well-known attributes * bgp_attr.c: (bgp_attr_check) The check for missing NEXT_HOP has the right spirit, but wrong where it counts, on the logic. It wouldn't catch a missing NEXT_HOP on a v4-only UPDATE. It would though have incorrectly flagged next-hop as missing on multi-protocol-only UPDATEs. Caught by Martin Winter with a test-suite. --- bgpd/bgp_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index da17e82e7..5e213db4d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1761,8 +1761,8 @@ bgp_attr_check (struct peer *peer, struct attr *attr) /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and * NLRI is empty. We can't easily check NLRI empty here though. */ - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)) - && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) + if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) + && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI))) type = BGP_ATTR_NEXT_HOP; if (peer->sort == BGP_PEER_IBGP From 85c854aa720c02a56b1ecbbf12a763a326d11a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 30 Sep 2014 11:31:53 +0300 Subject: [PATCH 0436/1342] bgpd: implement route-map set as-path prepend last-as MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It picks up the AS to add from the aspath, or uses the peers AS number. Useful mostly in iBGP setups. Signed-off-by: Timo Teräs Reviewed-by: Paul Jakma --- bgpd/bgp_aspath.c | 65 ++++++++++++++++++++++++++++----------------- bgpd/bgp_aspath.h | 2 ++ bgpd/bgp_routemap.c | 47 +++++++++++++++++++++++++++++--- doc/bgpd.texi | 1 + 4 files changed, 87 insertions(+), 28 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index e8559bea6..cfa9bc145 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -476,6 +476,19 @@ aspath_highest (struct aspath *aspath) return highest; } +/* Return the left-most ASN in path */ +as_t +aspath_leftmost (struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + as_t leftmost = 0; + + if (seg && seg->length && seg->type == AS_SEQUENCE) + leftmost = seg->as[0]; + + return leftmost; +} + /* Return 1 if there are any 4-byte ASes in the path */ unsigned int aspath_has_as4 (struct aspath *aspath) @@ -1362,46 +1375,50 @@ aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list) /* Add specified AS to the leftmost of aspath. */ static struct aspath * -aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) +aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) { struct assegment *assegment = aspath->segments; + int i; - /* In case of empty aspath. */ - if (assegment == NULL || assegment->length == 0) + if (assegment && assegment->type == type) { - aspath->segments = assegment_new (type, 1); - aspath->segments->as[0] = asno; - - if (assegment) - assegment_free (assegment); - - return aspath; + /* extend existing segment */ + aspath->segments = assegment_prepend_asns (aspath->segments, asno, num); } - - if (assegment->type == type) - aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1); else { - /* create new segment - * push it onto head of aspath's segment chain - */ - struct assegment *newsegment; - - newsegment = assegment_new (type, 1); - newsegment->as[0] = asno; - - newsegment->next = assegment; + /* prepend with new segment */ + struct assegment *newsegment = assegment_new (type, num); + for (i = 0; i < num; i++) + newsegment->as[i] = asno; + + /* insert potentially replacing empty segment */ + if (assegment && assegment->length == 0) + { + newsegment->next = assegment->next; + assegment_free (assegment); + } + else + newsegment->next = assegment; aspath->segments = newsegment; } + aspath_str_update (aspath); return aspath; } +/* Add specified AS to the leftmost of aspath num times. */ +struct aspath * +aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num) +{ + return aspath_add_asns (aspath, asno, AS_SEQUENCE, num); +} + /* Add specified AS to the leftmost of aspath. */ struct aspath * aspath_add_seq (struct aspath *aspath, as_t asno) { - return aspath_add_one_as (aspath, asno, AS_SEQUENCE); + return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1); } /* Compare leftmost AS value for MED check. If as1's leftmost AS and @@ -1600,7 +1617,7 @@ aspath_delete_confed_seq (struct aspath *aspath) struct aspath* aspath_add_confed_seq (struct aspath *aspath, as_t asno) { - return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE); + return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1); } /* Add new as value to as path structure. */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index e8764cca2..1311f8a5a 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -71,6 +71,7 @@ extern struct aspath *aspath_dup (struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); +extern struct aspath *aspath_add_seq_n (struct aspath *, as_t, unsigned); extern struct aspath *aspath_add_seq (struct aspath *, as_t); extern struct aspath *aspath_add_confed_seq (struct aspath *, as_t); extern int aspath_cmp (const void *, const void *); @@ -97,6 +98,7 @@ extern unsigned int aspath_count_hops (struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); extern unsigned int aspath_size (struct aspath *); extern as_t aspath_highest (struct aspath *); +extern as_t aspath_leftmost (struct aspath *); extern size_t aspath_put (struct stream *, struct aspath *, int); extern struct aspath *aspath_reconcile_as4 (struct aspath *, struct aspath *); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b74554d63..857781fea 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1230,7 +1230,6 @@ route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t if (type == RMAP_BGP) { - aspath = rule; binfo = object; if (binfo->attr->aspath->refcnt) @@ -1238,20 +1237,50 @@ route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t else new = binfo->attr->aspath; - aspath_prepend (aspath, new); + if ((uintptr_t)rule > 10) + { + aspath = rule; + aspath_prepend (aspath, new); + } + else + { + as_t as = aspath_leftmost(new); + if (!as) as = binfo->peer->as; + new = aspath_add_seq_n (new, as, (uintptr_t) rule); + } + binfo->attr->aspath = new; } return RMAP_OKAY; } +static void * +route_set_aspath_prepend_compile (const char *arg) +{ + unsigned int num; + + if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) + return (void*)(uintptr_t)num; + + return route_aspath_compile(arg); +} + +static void +route_set_aspath_prepend_free (void *rule) +{ + if ((uintptr_t)rule > 10) + route_aspath_free(rule); +} + + /* Set as-path prepend rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", route_set_aspath_prepend, - route_aspath_compile, - route_aspath_free, + route_set_aspath_prepend_compile, + route_set_aspath_prepend_free, }; /* `set as-path exclude ASn' */ @@ -3127,6 +3156,15 @@ DEFUN (set_aspath_prepend, return ret; } +ALIAS (set_aspath_prepend, + set_aspath_prepend_lastas_cmd, + "set as-path prepend (last-as) <1-10>", + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "Use the peer's AS-number\n" + "Number of times to insert"); + DEFUN (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend", @@ -3983,6 +4021,7 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_aspath_prepend_cmd); + install_element (RMAP_NODE, &set_aspath_prepend_lastas_cmd); install_element (RMAP_NODE, &set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); diff --git a/doc/bgpd.texi b/doc/bgpd.texi index de709707a..5004cbfc3 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -496,6 +496,7 @@ This command defines a new AS path access list. @end deffn @deffn {Route Map} {set as-path prepend @var{as-path}} {} +@deffnx {Route Map} {set as-path prepend last-as @var{num}} {} @end deffn @node Private AS Numbers From 5e4ba81dc212b172e715afa7b6ea668cddd8485d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 20 Oct 2014 17:49:44 +0100 Subject: [PATCH 0437/1342] doc: Document 'set as-path prepend' and 'set as-path prepend last-as' --- doc/bgpd.texi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 5004cbfc3..7d92b5e16 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -496,7 +496,11 @@ This command defines a new AS path access list. @end deffn @deffn {Route Map} {set as-path prepend @var{as-path}} {} -@deffnx {Route Map} {set as-path prepend last-as @var{num}} {} +Prepend the given string of AS numbers to the AS_PATH. +@end deffn + +@deffn {Route Map} {set as-path prepend last-as @var{num}} {} +Prepend the existing last AS number (the leftmost ASN) to the AS_PATH. @end deffn @node Private AS Numbers From 273b1bd341afff86ba571e0be296d88dba627136 Mon Sep 17 00:00:00 2001 From: Greg Troxel Date: Tue, 2 Dec 2014 14:51:49 -0500 Subject: [PATCH 0438/1342] zebra/kernel_socket.c: Use platform alignment Use the platform-provided RT_ROUNDUP macro to align sockaddrs on the routing socket, rather than using hard-coded assumptions about alignment. Emit a warning if the OS doesn't define alignment macros. Resolves failure of ripngd on NetBSD 6 i386, which changed alignment to uint64_t from long. --- zebra/kernel_socket.c | 50 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 3dbeb98bc..1518c1ab4 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -42,22 +42,52 @@ extern struct zebra_privs_t zserv_privs; extern struct zebra_t zebrad; /* - * Given a sockaddr length, round it up to include pad bytes following - * it. Assumes the kernel pads to sizeof(long). + * Historically, the BSD routing socket has aligned data following a + * struct sockaddr to sizeof(long), which was 4 bytes on some + * platforms, and 8 bytes on others. NetBSD 6 changed the routing + * socket to align to sizeof(uint64_t), which is 8 bytes. OS X + * appears to align to sizeof(int), which is 4 bytes. * - * XXX: why is ROUNDUP(0) sizeof(long)? 0 is an illegal sockaddr - * length anyway (< sizeof (struct sockaddr)), so this shouldn't - * matter. - * On OS X, both 32, 64bit syatems align on 4 byte boundary + * Alignment of zero-sized sockaddrs is nonsensical, but historically + * BSD defines RT_ROUNDUP(0) to be the alignment interval (rather than + * 0). We follow this practice without questioning it, but it is a + * bug if quagga calls ROUNDUP with 0. */ + +/* + * Because of these varying conventions, the only sane approach is for + * the header to define some flavor of ROUNDUP macro. + */ +#if defined(RT_ROUNDUP) +#define ROUNDUP(a) RT_ROUNDUP(a) +#endif /* defined(RT_ROUNDUP) */ + +/* + * If ROUNDUP has not yet been defined in terms of platform-provided + * defines, attempt to cope with heuristics. + */ +#if !defined(ROUNDUP) + +/* + * It's a bug for a platform not to define rounding/alignment for + * sockaddrs on the routing socket. This warning really is + * intentional, to provoke filing bug reports with operating systems + * that don't define RT_ROUNDUP or equivalent. + */ +#warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!" + +/* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */ #ifdef __APPLE__ -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int)) +#define ROUNDUP_TYPE long #else -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ROUNDUP_TYPE int #endif +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(ROUNDUP_TYPE) - 1))) : sizeof(ROUNDUP_TYPE)) + +#endif /* defined(ROUNDUP) */ + /* * Given a pointer (sockaddr or void *), return the number of bytes * taken up by the sockaddr and any padding needed for alignment. From cffe7807c03b7edea005869086720e2f1fb070c6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 7 Dec 2014 03:27:13 +0100 Subject: [PATCH 0439/1342] bgpd: stop startup timer on stopping BGP (fixes dd49eb1) bgp_delete() really needs to kill t_startup, otherwise after creating and quickly destroying a BGP instance it may fire on a deallocated struct bgp, overwriting memory. Reported-by: Martin Winter Fixes: dd49eb1 ("Fix BGP's use of restart bit.") Cc: Vipin Kumar Signed-off-by: David Lamparter Acked-by: Vincent JARDIN --- bgpd/bgpd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 79bcaaf05..d72708e4a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2103,6 +2103,8 @@ bgp_delete (struct bgp *bgp) afi_t afi; int i; + THREAD_OFF (bgp->t_startup); + /* Delete static route. */ bgp_static_delete (bgp); From daefeb8755e194dd19a5f1910bc78d13c8147efb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 8 Dec 2014 17:42:12 +0100 Subject: [PATCH 0440/1342] bgpd: set BGP_ATTR_MP_[UN]REACH_NLRI (fixes 1a211cb) Unfortunately, the attribute present bits for MP_REACH and MP_UNREACH which 1a211cb ("bgpd: one more fix"...) tests for are never set in their corresponding attribute parsing functions. Reported-by: Martin Winter Fixes: 1a211cb "bgpd: one more fix for tightening of check for missing well-known attributes" Cc: Paul Jakma Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5e213db4d..be316daa6 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1591,6 +1591,8 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, stream_forward_getp (s, nlri_len); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI); + return BGP_ATTR_PARSE_PROCEED; #undef LEN_LEFT } @@ -1606,6 +1608,7 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, u_int16_t withdraw_len; int ret; struct peer *const peer = args->peer; + struct attr *const attr = args->attr; const bgp_size_t length = args->length; s = peer->ibuf; @@ -1633,6 +1636,8 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, stream_forward_getp (s, withdraw_len); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI); + return BGP_ATTR_PARSE_PROCEED; } From 1c6db0d2da34044ddfb42665fda8a3387ecc451d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 12 Dec 2014 21:35:28 +0100 Subject: [PATCH 0441/1342] lib: don't create circular lists (fixes 6d83113) LISTNODE_DETACH doesn't clear out the node, and LISTNODE_ATTACH doesn't set ->next (since it assumes a fresh/zeroed listnode). As a result, the new listnode_move_to_tail() created a nice circular list, in turn crashing ospfd in ospf_write() later. Reported-by: Martin Winter Fixes: 6d83113 ("ospfd: Tweak previous iface RR write patch to avoid free/malloc & redundant log") Cc: Paul Jakma Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Dinesh Dutt Acked-by: Vincent JARDIN --- lib/linklist.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/linklist.h b/lib/linklist.h index c8d715e12..6209c8b9d 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -113,6 +113,7 @@ extern void list_add_list (struct list *, struct list *); #define LISTNODE_ATTACH(L,N) \ do { \ (N)->prev = (L)->tail; \ + (N)->next = NULL; \ if ((L)->head == NULL) \ (L)->head = (N); \ else \ From e0b0ac8c97d9b8885785ed0461f87a34e70f368e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 24 Apr 2014 20:22:53 +0200 Subject: [PATCH 0442/1342] zebra: factor out rib debug logs Introduces a logging function that takes a struct route_node * argument, and prefixes log output with that node's prefix. While this removes some duplication, it will also later be useful for srcdest route nodes. Behaviour before and after the patch should be exactly identical. Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 114 +++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 245011ebf..4ee1a84c8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -75,6 +75,37 @@ static const struct /* Vector for routing table. */ static vector vrf_vector; +static void +_rnode_zlog(const char *_func, struct route_node *rn, int priority, + const char *msgfmt, ...) +{ + char buf[INET6_ADDRSTRLEN + 4], *bptr; + char msgbuf[512]; + va_list ap; + + va_start(ap, msgfmt); + vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap); + va_end(ap); + + if (rn) + { + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); + bptr = buf + strlen(buf); + snprintf(bptr, buf + sizeof(buf) - bptr, "/%d", rn->p.prefixlen); + } + else + { + snprintf(buf, sizeof(buf), "{(route_node *) NULL}"); + } + + zlog (NULL, priority, "%s: %s: %s", _func, buf, msgbuf); +} + +#define rnode_debug(node, ...) \ + _rnode_zlog(__func__, node, LOG_DEBUG, __VA_ARGS__) +#define rnode_info(node, ...) \ + _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) + /* * vrf_table_create */ @@ -1209,7 +1240,6 @@ int rib_gc_dest (struct route_node *rn) { rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; dest = rib_dest_from_rnode (rn); if (!dest) @@ -1219,11 +1249,7 @@ rib_gc_dest (struct route_node *rn) return 0; if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); - zlog_debug ("%s: %s/%d: removing dest from table", __func__, - buf, rn->p.prefixlen); - } + rnode_debug (rn, "removing dest from table"); dest->rnode = NULL; XFREE (MTYPE_RIB_DEST, dest); @@ -1248,16 +1274,12 @@ rib_process (struct route_node *rn) int installed = 0; struct nexthop *nexthop = NULL, *tnexthop; int recursing; - char buf[INET6_ADDRSTRLEN]; rib_table_info_t *info; assert (rn); info = rn->table->info; - if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - RNODE_FOREACH_RIB_SAFE (rn, rib, next) { /* Currently installed rib. */ @@ -1275,8 +1297,7 @@ rib_process (struct route_node *rn) if (rib != fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, - buf, rn->p.prefixlen, rn, rib); + rnode_debug (rn, "rn %p, removing rib %p", rn, rib); rib_unlink (rn, rib); } else @@ -1350,8 +1371,8 @@ rib_process (struct route_node *rn) if (select && select == fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", - __func__, buf, rn->p.prefixlen, select, fib); + rnode_debug (rn, "Updating existing route, select %p, fib %p", + select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { zfpm_trigger_update (rn, "updating existing route"); @@ -1395,8 +1416,7 @@ rib_process (struct route_node *rn) if (fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, - buf, rn->p.prefixlen, fib); + rnode_debug (rn, "Removing existing route, fib %p", fib); zfpm_trigger_update (rn, "removing existing route"); @@ -1416,8 +1436,7 @@ rib_process (struct route_node *rn) if (select) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, - rn->p.prefixlen, select); + rnode_debug (rn, "Adding route, select %p", select); zfpm_trigger_update (rn, "new route selected"); @@ -1434,14 +1453,13 @@ rib_process (struct route_node *rn) if (del) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf, - rn->p.prefixlen, del, rn); + rnode_debug (rn, "Deleting fib %p, rn %p", del, rn); rib_unlink (rn, del); } end: if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); + rnode_debug (rn, "rn %p dequeued", rn); /* * Check if the dest can be deleted now. @@ -1525,10 +1543,6 @@ static void rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) { struct rib *rib; - char buf[INET6_ADDRSTRLEN]; - - if (IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); RNODE_FOREACH_RIB (rn, rib) { @@ -1539,8 +1553,8 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) RIB_ROUTE_QUEUED (qindex))) { if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", - __func__, buf, rn->p.prefixlen, rn, qindex); + rnode_debug (rn, "rn %p is already queued in sub-queue %u", + rn, qindex); continue; } @@ -1550,8 +1564,8 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) mq->size++; if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", - __func__, buf, rn->p.prefixlen, rn, qindex); + rnode_debug (rn, "queued rn %p into sub-queue %u", + rn, qindex); } } @@ -1559,11 +1573,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { - char buf[INET_ADDRSTRLEN]; assert (zebra && rn); - - if (IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); /* Pointless to queue a route_node with no RIB entries to add or remove */ if (!rnode_to_ribs (rn)) @@ -1575,7 +1585,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) } if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); + rnode_info (rn, "work queue added"); assert (zebra); @@ -1599,7 +1609,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) rib_meta_queue_add (zebra->mq, rn); if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); + rnode_debug (rn, "rn %p queued", rn); return; } @@ -1696,25 +1706,17 @@ rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; assert (rib && rn); if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, - buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, rib %p", rn, rib); dest = rib_dest_from_rnode (rn); if (!dest) { if (IS_ZEBRA_DEBUG_RIB) - { - zlog_debug ("%s: %s/%d: adding dest to table", __func__, - buf, rn->p.prefixlen); - } + rnode_debug (rn, "adding dest to table"); dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t)); route_lock_node (rn); /* rn route table reference */ @@ -1741,12 +1743,8 @@ rib_addnode (struct route_node *rn, struct rib *rib) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", - __func__, buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, un-removed rib %p", rn, rib); + UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); return; } @@ -1765,17 +1763,12 @@ rib_addnode (struct route_node *rn, struct rib *rib) static void rib_unlink (struct route_node *rn, struct rib *rib) { - char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, rib %p", - __func__, buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, rib %p", rn, rib); dest = rib_dest_from_rnode (rn); @@ -1799,12 +1792,7 @@ static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, - buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, rib %p, removing", rn, rib); SET_FLAG (rib->status, RIB_ENTRY_REMOVED); rib_queue_add (&zebrad, rn); } From f7b3d1e067ac8088a61136c53d24078b675e0197 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:02:13 +0100 Subject: [PATCH 0443/1342] zebra: identify MRIB on debug messages since the same code handles both URIB and MRIB, the debug messages can get rather confusing if the RIB isn't identified. Mark the MRIB in debug messages so we can distinguish that. Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 4ee1a84c8..8354513c5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -89,9 +89,12 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, if (rn) { + rib_table_info_t *info = rn->table->info; + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); bptr = buf + strlen(buf); - snprintf(bptr, buf + sizeof(buf) - bptr, "/%d", rn->p.prefixlen); + snprintf(bptr, buf + sizeof(buf) - bptr, "/%d%s", rn->p.prefixlen, + info->safi == SAFI_MULTICAST ? " (MRIB)" : ""); } else { From 346a8b50334ac837e6a6af0dbe472e9a87dacd1e Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 19:35:51 -0300 Subject: [PATCH 0444/1342] zebra: add rib_match_ipv4_safi() This is the same as rib_lookup_ipv4(), without the SAFI hardcoded. Cc: Balaji G Cc: Everton Marques Signed-off-by: David Lamparter --- zebra/rib.h | 1 + zebra/zebra_rib.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/zebra/rib.h b/zebra/rib.h index d3a83c68a..13011e26e 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -419,6 +419,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, u_int32_t, safi_t safi); extern struct rib *rib_match_ipv4 (struct in_addr); +extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8354513c5..5b9b00ed6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -781,6 +781,63 @@ rib_match_ipv4 (struct in_addr addr) return NULL; } +struct rib * +rib_match_ipv4_safi (struct in_addr addr, safi_t safi) +{ + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop, *tnewhop; + int recursing; + + /* Lookup table. */ + table = vrf_table (AFI_IP, safi, 0); + if (! table) + return 0; + + rn = route_node_match_ipv4 (table, &addr); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + RNODE_FOREACH_RIB (rn, match) + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} + struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p) { From a59b6152bbcd2ff6734872ecbffbc9c43701e1a8 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 21 Nov 2014 15:57:45 -0800 Subject: [PATCH 0445/1342] zebra: point rib_match_ipv4() to ._safi() Since rib_match_ipv4() is just rib_match_ipv4_safi() for SAFI_UNICAST, the former can be removed and pointed to the latter instead. Cc: Balaji G Cc: Everton Marques Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 59 +---------------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b9b00ed6..469c10b21 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -721,64 +721,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct rib * rib_match_ipv4 (struct in_addr addr) { - struct prefix_ipv4 p; - struct route_table *table; - struct route_node *rn; - struct rib *match; - struct nexthop *newhop, *tnewhop; - int recursing; - - /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); - if (! table) - return 0; - - memset (&p, 0, sizeof (struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = addr; - - rn = route_node_match (table, (struct prefix *) &p); - - while (rn) - { - route_unlock_node (rn); - - /* Pick up selected route. */ - RNODE_FOREACH_RIB (rn, match) - { - if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) - continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; - } - - /* If there is no selected route or matched route is EGP, go up - tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) - { - do { - rn = rn->parent; - } while (rn && rn->info == NULL); - if (rn) - route_lock_node (rn); - } - else - { - if (match->type == ZEBRA_ROUTE_CONNECT) - /* Directly point connected route. */ - return match; - else - { - for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) - if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) - return match; - return NULL; - } - } - } - return NULL; + return rib_match_ipv4_safi (addr, SAFI_UNICAST); } struct rib * From be4fb4312531cdae986a83b0375dbd1e0606067e Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 1 Jul 2014 15:15:52 -0300 Subject: [PATCH 0446/1342] zebra: add ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB This adds a new zapi call "ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB" performing a Multicast RPF lookup for a given source. Details of the lookup behaviour are left to the zebra side of things. Note: this is non-reactive, as in, only delivers a snapshot of the state at a particular point in time. There's no push notification of changes happening to the RIB. This combines the following 3 original patches: - zebra: add zsend_ipv4_nexthop_lookup_mrib() - zserv: Query mrib (SAFI_MULTICAST). - zebra: Cleanups to zebra_rib. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- lib/zebra.h | 3 +- zebra/zserv.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/lib/zebra.h b/lib/zebra.h index b289a19e1..a4e02148d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -425,7 +425,8 @@ struct in_pktinfo #define ZEBRA_ROUTER_ID_DELETE 21 #define ZEBRA_ROUTER_ID_UPDATE 22 #define ZEBRA_HELLO 23 -#define ZEBRA_MESSAGE_MAX 24 +#define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24 +#define ZEBRA_MESSAGE_MAX 25 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new diff --git a/zebra/zserv.c b/zebra/zserv.c index ca17c2c6d..89eb266a1 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -599,6 +599,89 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) return zebra_server_send_message(client); } +/* + Modified version of zsend_ipv4_nexthop_lookup(): + Query unicast rib if nexthop is not found on mrib. + Returns both route metric and protocol distance. +*/ +static int +zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + + /* Lookup nexthop. */ + rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST); + + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); + + if (!rib) { + /* Retry lookup with unicast rib */ + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST); + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: %s rib entry found.", __func__, rib ? "Matching" : "No matching"); + } + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + /* Fill in result. */ + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); + stream_put_in_addr (s, &addr); + + if (rib) + { + stream_putc (s, rib->distance); + stream_putl (s, rib->metric); + num = 0; + nump = stream_get_endp(s); /* remember position for nexthop_num */ + stream_putc (s, 0); /* reserve room for nexthop_num */ + /* 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) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + default: + /* do nothing */ + break; + } + num++; + } + + stream_putc_at (s, nump, num); /* store nexthop_num */ + } + else + { + stream_putc (s, 0); /* distance */ + stream_putl (s, 0); /* metric */ + stream_putc (s, 0); /* nexthop_num */ + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + return zebra_server_send_message(client); +} + static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) { @@ -920,6 +1003,16 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) return zsend_ipv4_nexthop_lookup (client, addr); } +/* MRIB Nexthop lookup for IPv4. */ +static int +zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length) +{ + struct in_addr addr; + + addr.s_addr = stream_get_ipv4 (client->ibuf); + return zsend_ipv4_nexthop_lookup_mrib (client, addr); +} + /* Nexthop lookup for IPv4. */ static int zread_ipv4_import_lookup (struct zserv *client, u_short length) @@ -1352,6 +1445,9 @@ zebra_client_read (struct thread *thread) case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; + case ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB: + zread_ipv4_nexthop_lookup_mrib (client, length); + break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); From 12150f08b76c91225dcd877308fecb13026041ef Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 19 Sep 2014 16:39:34 -0300 Subject: [PATCH 0447/1342] zebra: mrib: Include BGP routes in RPF lookups The rib_match_ipv4() function was previously used only for iBGP recursive nexthop lookups, which ignore eBGP routes. This is not desirable for PIM RPF lookups, which may well use an eBGP route. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 2 +- zebra/zebra_rib.c | 7 +++---- zebra/zserv.c | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 13011e26e..aef715008 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -419,7 +419,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, u_int32_t, safi_t safi); extern struct rib *rib_match_ipv4 (struct in_addr); -extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi); +extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 469c10b21..f4a915542 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -721,11 +721,11 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct rib * rib_match_ipv4 (struct in_addr addr) { - return rib_match_ipv4_safi (addr, SAFI_UNICAST); + return rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); } struct rib * -rib_match_ipv4_safi (struct in_addr addr, safi_t safi) +rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) { struct route_table *table; struct route_node *rn; @@ -755,8 +755,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi) /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP))) { do { rn = rn->parent; diff --git a/zebra/zserv.c b/zebra/zserv.c index 89eb266a1..1b6931593 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -612,16 +612,17 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr) unsigned long nump; u_char num; struct nexthop *nexthop; + int skip_bgp = 0; /* bool */ /* Lookup nexthop. */ - rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST); + rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); if (!rib) { /* Retry lookup with unicast rib */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: %s rib entry found.", __func__, rib ? "Matching" : "No matching"); } From c409791083892f6c95baca1c79c80290dc595be4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 22 Nov 2014 14:44:20 -0800 Subject: [PATCH 0448/1342] zebra: kill rib_match_ipv4() Since this function is internal to zebra, there is no reason to keep this one-line indirect wrapper to rib_match_ipv4_safi() around. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 1 - zebra/zebra_rib.c | 6 ------ zebra/zserv.c | 4 ++-- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index aef715008..d40b17e81 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -418,7 +418,6 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, u_int32_t, safi_t safi); -extern struct rib *rib_match_ipv4 (struct in_addr); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f4a915542..08ce96452 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -718,12 +718,6 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } #endif /* HAVE_IPV6 */ -struct rib * -rib_match_ipv4 (struct in_addr addr) -{ - return rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); -} - struct rib * rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) { diff --git a/zebra/zserv.c b/zebra/zserv.c index 1b6931593..e9236deca 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -539,8 +539,8 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) u_char num; struct nexthop *nexthop; - /* Lookup nexthop. */ - rib = rib_match_ipv4 (addr); + /* Lookup nexthop - eBGP excluded */ + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); /* Get output stream. */ s = client->obuf; From 96bb266e0fde451f36c5463e789714eacc1ae63c Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 14 Jul 2014 11:19:00 -0300 Subject: [PATCH 0449/1342] zebra: mrib: static route support With the MRIB being independent from the Unicast RIB, there's currently now way to add static routes to the MRIB. Address that by adding a separate set of commands for MRIB static routes. Combines these original patches: - zebra: mrib: ip mroute command to add unicast route to MRIB for multicast RPF. - zebra: mrib: no ip mroute: Fix removal of static multicast RPF route. - zebra: mrib: remove unused static_add/delete_ipv4 - zebra: Cleanups to zebra_rib. - pimd: Merge pim-only branch. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 10 +++--- zebra/zebra_rib.c | 30 ++++++++-------- zebra/zebra_vty.c | 87 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 36 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index d40b17e81..5eedfde6f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -430,12 +430,12 @@ extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); extern int -static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id); - +static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char flags, u_char distance, + u_int32_t vrf_id); extern int -static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char distance, u_int32_t vrf_id); +static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char distance, u_int32_t vrf_id); #ifdef HAVE_IPV6 extern int diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 08ce96452..a07036e59 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2276,14 +2276,14 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Install static route into rib. */ static void -static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) +static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) { struct rib *rib; struct route_node *rn; struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return; @@ -2368,7 +2368,7 @@ static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) /* Uninstall static route from RIB. */ static void -static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) +static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) { struct route_node *rn; struct rib *rib; @@ -2376,7 +2376,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return; @@ -2427,10 +2427,10 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) route_unlock_node (rn); } -/* Add static route into static route configuration. */ int -static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id) +static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char flags, u_char distance, + u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2441,7 +2441,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + stable = vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2475,7 +2475,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, /* Distance changed. */ if (update) - static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); + static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); @@ -2517,15 +2517,14 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, si->next = cp; /* Install into rib. */ - static_install_ipv4 (p, si); + static_install_ipv4 (safi, p, si); return 1; } -/* Delete static route from static route configuration. */ int -static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char distance, u_int32_t vrf_id) +static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char distance, u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2533,7 +2532,7 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + stable = vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2565,7 +2564,7 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, } /* Install into rib. */ - static_uninstall_ipv4 (p, si); + static_uninstall_ipv4 (safi, p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -2586,7 +2585,6 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, return 1; } - #ifdef HAVE_IPV6 static int rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 9d6c1dddb..6802eceb5 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -30,11 +30,14 @@ #include "zebra/zserv.h" -/* General fucntion for static route. */ +static int do_show_ip_route(struct vty *vty, safi_t safi); + +/* General function for static route. */ static int -zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, - const char *mask_str, const char *gate_str, - const char *flag_str, const char *distance_str) +zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, + const char *dest_str, const char *mask_str, + const char *gate_str, const char *flag_str, + const char *distance_str) { int ret; u_char distance; @@ -81,9 +84,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, return CMD_WARNING; } if (add_cmd) - static_add_ipv4 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); + static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); else - static_delete_ipv4 (&p, NULL, NULL, distance, 0); + static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, 0); return CMD_SUCCESS; } @@ -107,9 +110,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, if (gate_str == NULL) { if (add_cmd) - static_add_ipv4 (&p, NULL, NULL, flag, distance, 0); + static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, 0); else - static_delete_ipv4 (&p, NULL, NULL, distance, 0); + static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, 0); return CMD_SUCCESS; } @@ -123,13 +126,58 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, ifname = gate_str; if (add_cmd) - static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, distance, 0); + static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, 0); else - static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); + static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, 0); return CMD_SUCCESS; } +static int +zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, + const char *mask_str, const char *gate_str, + const char *flag_str, const char *distance_str) +{ + return zebra_static_ipv4_safi(vty, SAFI_UNICAST, add_cmd, dest_str, mask_str, gate_str, flag_str, distance_str); +} + +/* Static unicast routes for multicast RPF lookup. */ +DEFUN (ip_mroute, + ip_mroute_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n") +{ + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, argv[2]); +} + +DEFUN (no_ip_mroute, + no_ip_mroute_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n") +{ + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, argv[2]); +} + +DEFUN (show_ip_rpf, + show_ip_rpf_cmd, + "show ip rpf", + SHOW_STR + IP_STR + "Display RPF information for multicast source\n") +{ + return do_show_ip_route(vty, SAFI_MULTICAST); +} + /* Static route configuration. */ DEFUN (ip_route, ip_route_cmd, @@ -788,12 +836,16 @@ DEFUN (show_ip_route, IP_STR "IP routing table\n") { + return do_show_ip_route(vty, SAFI_UNICAST); +} + +static int do_show_ip_route(struct vty *vty, safi_t safi) { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return CMD_SUCCESS; @@ -1195,7 +1247,7 @@ DEFUN (show_ip_route_summary_prefix, /* Write IPv4 static route configuration. */ static int -static_config_ipv4 (struct vty *vty) +static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) { struct route_node *rn; struct static_ipv4 *si; @@ -1205,14 +1257,14 @@ static_config_ipv4 (struct vty *vty) write = 0; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0); + stable = vrf_static_table (AFI_IP, safi, 0); if (! stable) return -1; for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { - vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4), + vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); switch (si->type) @@ -2146,7 +2198,8 @@ zebra_ip_config (struct vty *vty) { int write = 0; - write += static_config_ipv4 (vty); + write += static_config_ipv4 (vty, SAFI_UNICAST, "ip route"); + write += static_config_ipv4 (vty, SAFI_MULTICAST, "ip mroute"); #ifdef HAVE_IPV6 write += static_config_ipv6 (vty); #endif /* HAVE_IPV6 */ @@ -2185,6 +2238,8 @@ zebra_vty_init (void) install_node (&ip_node, zebra_ip_config); install_node (&protocol_node, config_write_protocol); + install_element (CONFIG_NODE, &ip_mroute_cmd); + install_element (CONFIG_NODE, &no_ip_mroute_cmd); install_element (CONFIG_NODE, &ip_protocol_cmd); install_element (CONFIG_NODE, &no_ip_protocol_cmd); install_element (VIEW_NODE, &show_ip_protocol_cmd); @@ -2233,6 +2288,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (ENABLE_NODE, &show_ip_mroute_cmd); + install_element (VIEW_NODE, &show_ip_rpf_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_cmd); #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); From 9e6366d73675a5b65220641b71d7710cde8c1143 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:03:53 +0100 Subject: [PATCH 0450/1342] zebra: fix optional distance on static mrib route Unfortunately, the quagga CLI parser doesn't support [<1-255>]. Fix by working around with an alias. Replaces the following commits: - zebra: mrib: [no] ip mroute - require distance. - zebra: mrib: [no] ip mroute - make distance optional. (Rewritten as alias) Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6802eceb5..69245a54a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -142,9 +142,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, } /* Static unicast routes for multicast RPF lookup. */ -DEFUN (ip_mroute, - ip_mroute_cmd, - "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", +DEFUN (ip_mroute_dist, + ip_mroute_dist_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -152,12 +152,22 @@ DEFUN (ip_mroute, "Nexthop interface name\n" "Distance\n") { - return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, argv[2]); + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], + NULL, argc > 2 ? argv[2] : NULL); } -DEFUN (no_ip_mroute, - no_ip_mroute_cmd, - "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", +ALIAS (ip_mroute_dist, + ip_mroute_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n") + +DEFUN (no_ip_mroute_dist, + no_ip_mroute_dist_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -165,9 +175,20 @@ DEFUN (no_ip_mroute, "Nexthop interface name\n" "Distance\n") { - return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, argv[2]); + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], + NULL, argc > 2 ? argv[2] : NULL); } +ALIAS (no_ip_mroute_dist, + no_ip_mroute_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", + NO_STR + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n") + DEFUN (show_ip_rpf, show_ip_rpf_cmd, "show ip rpf", @@ -2239,7 +2260,9 @@ zebra_vty_init (void) install_node (&protocol_node, config_write_protocol); install_element (CONFIG_NODE, &ip_mroute_cmd); + install_element (CONFIG_NODE, &ip_mroute_dist_cmd); install_element (CONFIG_NODE, &no_ip_mroute_cmd); + install_element (CONFIG_NODE, &no_ip_mroute_dist_cmd); install_element (CONFIG_NODE, &ip_protocol_cmd); install_element (CONFIG_NODE, &no_ip_protocol_cmd); install_element (VIEW_NODE, &show_ip_protocol_cmd); From 149210656045c363d8f59b97ad9251b0c06a15df Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Mon, 3 Nov 2014 14:59:06 +0100 Subject: [PATCH 0451/1342] ospfd: Fix initial Opaque LSA DB synchronisation ospfd has issues resynchronising its Opaque LSA DB with neighbours after restart or interface events. The problem comes from opaque_lsa.c code that blocks subsequent opaque LSA flooding until the neighbour router acknowledge that, and removes the old opaque LSA from its LSDB. The bug comes from the fact that the lock is never release, thus avoiding subsequent opaque LSA flooding. More detail about the bugs and its solution is describeid in file doc/te-link-params.md Signed-off-by: Olivier Dugeon --- ospfd/ospf_opaque.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 744952c96..ecb28ffe3 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -2126,10 +2126,12 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) *------------------------------------------------------------------------*/ static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); +#ifdef BUGGY_UNLOCK static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); +#endif /* BUGGY_UNLOCK */ void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas) @@ -2296,17 +2298,20 @@ ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { case OSPF_OPAQUE_LINK_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) - ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); + UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); + /* BUGGY_UNLOCK: ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); */ /* Callback function... */ break; case OSPF_OPAQUE_AREA_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) - ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); + UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); + /* BUGGY_UNLOCK: ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); */ /* Callback function... */ break; case OSPF_OPAQUE_AS_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) - ospf_opaque_type11_lsa_rxmt_nbr_check (top); + UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); + /* BUGGY_UNLOCK: ospf_opaque_type11_lsa_rxmt_nbr_check (top); */ /* Callback function... */ break; default: @@ -2315,11 +2320,10 @@ ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Block Opaque-LSA origination: ON -> OFF"); return; /* Blocking still in progress. */ - } + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("Block Opaque-LSA origination: ON -> OFF"); if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) return; /* Opaque capability condition must have changed. */ @@ -2339,6 +2343,7 @@ ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) return; } +#ifdef BUGGY_UNLOCK static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) { @@ -2439,6 +2444,7 @@ ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) return n; } +#endif /* BUGGY_UNLOCK */ /*------------------------------------------------------------------------* * Followings are util functions; probably be used by Opaque-LSAs only... From c048dccaf537508019ccda658d75bbb0cfd7ad18 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 12 Jan 2015 07:05:06 +0100 Subject: [PATCH 0452/1342] zebra: dummy kernel "install" multicast routes This is a followup to 9511633 ("zebra: MBGP routes should not be installed in the kernel"), which was correct in disabling MRIB routes being installed in the kernel, yet broke the MRIB since now routes were never marked as active. Hence, push down the check into the kernel install functions, so that the routes are still marked active. At the same time, the FPM calls get a check each since otherwise we'd bump the FPM interface on MRIB updates. Fixes: 9511633 ("zebra: MBGP routes should not be installed in the kernel") Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a07036e59..b4ea2424c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1124,8 +1124,16 @@ rib_install_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; struct nexthop *nexthop, *tnexthop; + rib_table_info_t *info = rn->table->info; int recursing; + if (info->safi != SAFI_UNICAST) + { + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return; + } + /* * Make sure we update the FPM any time we send new information to * the kernel. @@ -1157,8 +1165,16 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; struct nexthop *nexthop, *tnexthop; + rib_table_info_t *info = rn->table->info; int recursing; + if (info->safi != SAFI_UNICAST) + { + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return ret; + } + /* * Make sure we update the FPM any time we send new information to * the kernel. @@ -1187,9 +1203,12 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) static void rib_uninstall (struct route_node *rn, struct rib *rib) { + rib_table_info_t *info = rn->table->info; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { - zfpm_trigger_update (rn, "rib_uninstall"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "rib_uninstall"); redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) @@ -1306,9 +1325,6 @@ rib_process (struct route_node *rn) if (! nexthop_active_update (rn, rib, 0)) continue; - if (info->safi == SAFI_MULTICAST) - continue; - /* Infinit distance. */ if (rib->distance == DISTANCE_INFINITY) continue; @@ -1371,7 +1387,8 @@ rib_process (struct route_node *rn) select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { - zfpm_trigger_update (rn, "updating existing route"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "updating existing route"); redistribute_delete (&rn->p, select); if (! RIB_SYSTEM_ROUTE (select)) @@ -1414,7 +1431,8 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Removing existing route, fib %p", fib); - zfpm_trigger_update (rn, "removing existing route"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "removing existing route"); redistribute_delete (&rn->p, fib); if (! RIB_SYSTEM_ROUTE (fib)) @@ -1434,7 +1452,8 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Adding route, select %p", select); - zfpm_trigger_update (rn, "new route selected"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "new route selected"); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); @@ -3267,6 +3286,7 @@ static void rib_close_table (struct route_table *table) { struct route_node *rn; + rib_table_info_t *info = table->info; struct rib *rib; if (table) @@ -3276,7 +3296,8 @@ rib_close_table (struct route_table *table) if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) continue; - zfpm_trigger_update (rn, NULL); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); From 29ce93ebf6427d1d64eae8b385e36873e3ddcb88 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:09:36 +0100 Subject: [PATCH 0453/1342] zebra: return route_node from rib_match_ipv4_safi The multicast code needs to know the route_node in addition to the rib entry in order to perform distance or prefix-length comparisons. Add it as optional "out" pointer parameter. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 3 ++- zebra/zebra_rib.c | 21 ++++++++++++++------- zebra/zserv.c | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 5eedfde6f..347fadb0d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -418,7 +418,8 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, u_int32_t, safi_t safi); -extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp); +extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, + int skip_bgp, struct route_node **rn_out); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b4ea2424c..abef90fb9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -719,7 +719,8 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, #endif /* HAVE_IPV6 */ struct rib * -rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) +rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, + struct route_node **rn_out) { struct route_table *table; struct route_node *rn; @@ -759,16 +760,22 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) } else { - if (match->type == ZEBRA_ROUTE_CONNECT) - /* Directly point connected route. */ - return match; - else + if (match->type != ZEBRA_ROUTE_CONNECT) { + int found = 0; for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) - return match; - return NULL; + { + found = 1; + break; + } + if (!found) + return NULL; } + + if (rn_out) + *rn_out = rn; + return match; } } return NULL; diff --git a/zebra/zserv.c b/zebra/zserv.c index e9236deca..e678f3a32 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -540,7 +540,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL); /* Get output stream. */ s = client->obuf; @@ -615,7 +615,7 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr) int skip_bgp = 0; /* bool */ /* Lookup nexthop. */ - rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp); + rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, NULL); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); From 240c56f3a41cb7018460ba6e36c9b559c897e3d0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 6 Jan 2015 19:53:24 +0100 Subject: [PATCH 0454/1342] zebra: make MRIB lookup behaviour switchable depending on the usage scenario (and availability of multitopology IGP protocols, which is currently zero in Quagga), different approaches of Multicast RPF lookups are useful. Reference behaviours from commercial vendors are urib-only/mrib-only (Juniper, depending on inet.2 availability) and lowest-distance (Cisco). As we are currently without MT IGP support, mrib-first seems the most useful default for Quagga. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 17 +++++++++++ zebra/zebra_rib.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_vty.c | 76 ++++++++++++++++++++++++++++++++++++++++++++--- zebra/zserv.c | 22 ++++---------- 4 files changed, 169 insertions(+), 21 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 347fadb0d..94a74194f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -373,6 +373,21 @@ typedef struct rib_tables_iter_t_ rib_tables_iter_state_t state; } rib_tables_iter_t; +/* RPF lookup behaviour */ +enum multicast_mode +{ + MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */ + MCAST_MRIB_ONLY, /* MRIB only */ + MCAST_URIB_ONLY, /* URIB only */ + MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */ + MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */ + MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */ + /* on equal value, MRIB wins for last 2 */ +}; + +extern void multicast_mode_ipv4_set (enum multicast_mode mode); +extern enum multicast_mode multicast_mode_ipv4_get (void); + extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); @@ -420,6 +435,8 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, struct route_node **rn_out); +extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, + struct route_node **rn_out); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index abef90fb9..effe23384 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -75,6 +75,9 @@ static const struct /* Vector for routing table. */ static vector vrf_vector; +/* RPF lookup behaviour */ +static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; + static void _rnode_zlog(const char *_func, struct route_node *rn, int priority, const char *msgfmt, ...) @@ -781,6 +784,78 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, return NULL; } +struct rib * +rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) +{ + struct rib *rib = NULL, *mrib = NULL, *urib = NULL; + struct route_node *m_rn = NULL, *u_rn = NULL; + int skip_bgp = 0; /* bool */ + + switch (ipv4_multicast_mode) + { + case MCAST_MRIB_ONLY: + return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out); + case MCAST_URIB_ONLY: + return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out); + case MCAST_NO_CONFIG: + case MCAST_MIX_MRIB_FIRST: + rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + if (!mrib) + rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + break; + case MCAST_MIX_DISTANCE: + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + if (mrib && urib) + rib = urib->distance < mrib->distance ? urib : mrib; + else if (mrib) + rib = mrib; + else if (urib) + rib = urib; + break; + case MCAST_MIX_PFXLEN: + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + if (mrib && urib) + rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; + else if (mrib) + rib = mrib; + else if (urib) + rib = urib; + break; + } + + if (rn_out) + *rn_out = (rib == mrib) ? m_rn : u_rn; + + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[BUFSIZ]; + inet_ntop (AF_INET, &addr, buf, BUFSIZ); + + zlog_debug("%s: %s: found %s, using %s", + __func__, buf, + mrib ? (urib ? "MRIB+URIB" : "MRIB") : + urib ? "URIB" : "nothing", + rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none"); + } + return rib; +} + +void +multicast_mode_ipv4_set (enum multicast_mode mode) +{ + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("%s: multicast lookup mode set (%d)", __func__, mode); + ipv4_multicast_mode = mode; +} + +enum multicast_mode +multicast_mode_ipv4_get (void) +{ + return ipv4_multicast_mode; +} + struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 69245a54a..f00e35eff 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -189,6 +189,62 @@ ALIAS (no_ip_mroute_dist, "Nexthop address\n" "Nexthop interface name\n") +DEFUN (ip_multicast_mode, + ip_multicast_mode_cmd, + "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", + IP_STR + "Multicast options\n" + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + if (!strncmp (argv[0], "u", 1)) + multicast_mode_ipv4_set (MCAST_URIB_ONLY); + else if (!strncmp (argv[0], "mrib-o", 6)) + multicast_mode_ipv4_set (MCAST_MRIB_ONLY); + else if (!strncmp (argv[0], "mrib-t", 6)) + multicast_mode_ipv4_set (MCAST_MIX_MRIB_FIRST); + else if (!strncmp (argv[0], "low", 3)) + multicast_mode_ipv4_set (MCAST_MIX_DISTANCE); + else if (!strncmp (argv[0], "lon", 3)) + multicast_mode_ipv4_set (MCAST_MIX_PFXLEN); + else + { + vty_out (vty, "Invalid mode specified%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_multicast_mode, + no_ip_multicast_mode_cmd, + "no ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", + NO_STR + IP_STR + "Multicast options\n" + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + multicast_mode_ipv4_set (MCAST_NO_CONFIG); + return CMD_SUCCESS; +} + +ALIAS (no_ip_multicast_mode, + no_ip_multicast_mode_noarg_cmd, + "no ip multicast rpf-lookup-mode", + NO_STR + IP_STR + "Multicast options\n" + "RPF lookup behavior\n") + DEFUN (show_ip_rpf, show_ip_rpf_cmd, "show ip rpf", @@ -2228,10 +2284,19 @@ zebra_ip_config (struct vty *vty) return write; } -/* ip protocol configuration write function */ -static int config_write_protocol(struct vty *vty) -{ +static int config_write_vty(struct vty *vty) +{ int i; + enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get (); + + if (ipv4_multicast_mode != MCAST_NO_CONFIG) + vty_out (vty, "ip multicast rpf-lookup-mode %s%s", + ipv4_multicast_mode == MCAST_URIB_ONLY ? "urib-only" : + ipv4_multicast_mode == MCAST_MRIB_ONLY ? "mrib-only" : + ipv4_multicast_mode == MCAST_MIX_MRIB_FIRST ? "mrib-then-urib" : + ipv4_multicast_mode == MCAST_MIX_DISTANCE ? "lower-distance" : + "longer-prefix", + VTY_NEWLINE); for (i=0;iobuf; @@ -1009,9 +995,11 @@ static int zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length) { struct in_addr addr; + struct rib *rib; addr.s_addr = stream_get_ipv4 (client->ibuf); - return zsend_ipv4_nexthop_lookup_mrib (client, addr); + rib = rib_match_ipv4_multicast (addr, NULL); + return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib); } /* Nexthop lookup for IPv4. */ From ca2b105f3bdd8859117756dc8d8c2406e28af28b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:12:35 +0100 Subject: [PATCH 0455/1342] zebra: add "show ip rpf" to get result of RPF lookup Checking what route exactly a RPF lookup for a given source uses is essential for an administrator to debug multicast routing issues. This command provides exactly that, using the multicst RPF lookup function and printing out its result to the CLI. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 52 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index f00e35eff..29c01c3ca 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -31,6 +31,8 @@ #include "zebra/zserv.h" static int do_show_ip_route(struct vty *vty, safi_t safi); +static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, + int mcast); /* General function for static route. */ static int @@ -255,6 +257,36 @@ DEFUN (show_ip_rpf, return do_show_ip_route(vty, SAFI_MULTICAST); } +DEFUN (show_ip_rpf_addr, + show_ip_rpf_addr_cmd, + "show ip rpf A.B.C.D", + SHOW_STR + IP_STR + "Display RPF information for multicast source\n" + "IP multicast source address (e.g. 10.0.0.0)\n") +{ + struct in_addr addr; + struct route_node *rn; + struct rib *rib; + int ret; + + ret = inet_aton (argv[0], &addr); + if (ret == 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rib = rib_match_ipv4_multicast (addr, &rn); + + if (rib) + vty_show_ip_route_detail (vty, rn, 1); + else + vty_out (vty, "%% No match for RPF lookup%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + /* Static route configuration. */ DEFUN (ip_route, ip_route_cmd, @@ -655,7 +687,7 @@ DEFUN (no_ip_protocol, /* New RIB. Detailed information for IPv4 route. */ 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, int mcast) { struct rib *rib; struct nexthop *nexthop, *tnexthop; @@ -663,8 +695,16 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) RNODE_FOREACH_RIB (rn, rib) { - vty_out (vty, "Routing entry for %s/%d%s", - inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + const char *mcast_info; + if (mcast) + { + rib_table_info_t *info = rn->table->info; + mcast_info = (info->safi == SAFI_MULTICAST) + ? " using Multicast RIB" + : " using Unicast RIB"; + } + vty_out (vty, "Routing entry for %s/%d%s%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, mcast_info, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); @@ -1092,7 +1132,7 @@ DEFUN (show_ip_route_addr, return CMD_WARNING; } - vty_show_ip_route_detail (vty, rn); + vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); @@ -1132,7 +1172,7 @@ DEFUN (show_ip_route_prefix, return CMD_WARNING; } - vty_show_ip_route_detail (vty, rn); + vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); @@ -2381,6 +2421,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_rpf_cmd); install_element (ENABLE_NODE, &show_ip_rpf_cmd); + install_element (VIEW_NODE, &show_ip_rpf_addr_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_addr_cmd); #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); From e832c34fd19aa6b2df7c28e78f07617095cf136e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Jan 2015 20:24:15 +0100 Subject: [PATCH 0456/1342] zebra: mark multicast commands experimental depending on feedback from actually having these commands in a released version, we may want to adjust them. Thus, mark them as experimental so users are aware of this. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- lib/vty.h | 8 ++++++++ zebra/zebra_vty.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/lib/vty.h b/lib/vty.h index 4d6048c95..f31f4b5d6 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -217,6 +217,14 @@ do { } \ } while (0) +#define VTY_WARN_EXPERIMENTAL() \ +do { \ + vty_out (vty, "%% WARNING: this command is experimental. Both its name and" \ + " parameters may%s%% change in a future version of Quagga," \ + " possibly breaking your configuration!%s", \ + VTY_NEWLINE, VTY_NEWLINE); \ +} while (0) + /* Exported variables */ extern char integrate_default[]; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 29c01c3ca..598b40de9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -154,6 +154,7 @@ DEFUN (ip_mroute_dist, "Nexthop interface name\n" "Distance\n") { + VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, argc > 2 ? argv[2] : NULL); } @@ -177,6 +178,7 @@ DEFUN (no_ip_mroute_dist, "Nexthop interface name\n" "Distance\n") { + VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, argc > 2 ? argv[2] : NULL); } @@ -203,6 +205,8 @@ DEFUN (ip_multicast_mode, "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") { + VTY_WARN_EXPERIMENTAL(); + if (!strncmp (argv[0], "u", 1)) multicast_mode_ipv4_set (MCAST_URIB_ONLY); else if (!strncmp (argv[0], "mrib-o", 6)) @@ -254,6 +258,7 @@ DEFUN (show_ip_rpf, IP_STR "Display RPF information for multicast source\n") { + VTY_WARN_EXPERIMENTAL(); return do_show_ip_route(vty, SAFI_MULTICAST); } @@ -270,6 +275,8 @@ DEFUN (show_ip_rpf_addr, struct rib *rib; int ret; + VTY_WARN_EXPERIMENTAL(); + ret = inet_aton (argv[0], &addr); if (ret == 0) { From a4e830c7cc0e10a851047aebe008ce7a3f8ef29b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 30 Jan 2015 01:44:25 +0100 Subject: [PATCH 0457/1342] doc: zebra multicast RIB commands Signed-off-by: David Lamparter --- doc/main.texi | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/doc/main.texi b/doc/main.texi index a6bf0d1c9..810866aa1 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -10,6 +10,7 @@ different routing protocols. * Invoking zebra:: Running the program * Interface Commands:: Commands for zebra interfaces * Static Route Commands:: Commands for adding static routes +* Multicast RIB Commands:: Commands for controlling MRIB behavior * zebra Route Filtering:: Commands for zebra route filtering * zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY @@ -185,6 +186,81 @@ and later). After setting @var{tableno} with this command, static routes defined after this are added to the specified table. @end deffn +@node Multicast RIB Commands +@section Multicast RIB Commands + +The Multicast RIB provides a separate table of unicast destinations which +is used for Multicast Reverse Path Forwarding decisions. It is used with +a multicast source's IP address, hence contains not multicast group +addresses but unicast addresses. + +This table is fully separate from the default unicast table. However, +RPF lookup can include the unicast table. + +WARNING: RPF lookup results are non-responsive in this version of Quagga, +i.e. multicast routing does not actively react to changes in underlying +unicast topology! + +@deffn Command {ip multicast rpf-lookup-mode @var{mode}} {} +@deffnx Command {no ip multicast rpf-lookup-mode [@var{mode}]} {} + +@var{mode} sets the method used to perform RPF lookups. Supported modes: + +@table @samp +@item urib-only +Performs the lookup on the Unicast RIB. The Multicast RIB is never used. +@item mrib-only +Performs the lookup on the Multicast RIB. The Unicast RIB is never used. +@item mrib-then-urib +Tries to perform the lookup on the Multicast RIB. If any route is found, +that route is used. Otherwise, the Unicast RIB is tried. +@item lower-distance +Performs a lookup on the Multicast RIB and Unicast RIB each. The result +with the lower administrative distance is used; if they're equal, the +Multicast RIB takes precedence. +@item longer-prefix +Performs a lookup on the Multicast RIB and Unicast RIB each. The result +with the longer prefix length is used; if they're equal, the +Multicast RIB takes precedence. +@end table + +WARNING: Unreachable routes do not receive special treatment and do not +cause fallback to a second lookup. +@end deffn + +@deffn Command {show ip rpf @var{addr}} {} + +Performs a Multicast RPF lookup, as configured with +@command{ip multicast rpf-lookup-mode @var{mode}}. @var{addr} specifies +the multicast source address to look up. + +@example +> show ip rpf 192.0.2.1 +Routing entry for 192.0.2.0/24 using Unicast RIB + Known via "kernel", distance 0, metric 0, best + * 198.51.100.1, via eth0 +@end example + +Indicates that a multicast source lookup for 192.0.2.1 would use an +Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. +@end deffn + +@deffn Command {show ip rpf} {} + +Prints the entire Multicast RIB. Note that this is independent of the +configured RPF lookup mode, the Multicast RIB may be printed yet not +used at all. +@end deffn + +@deffn Command {ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} +@deffnx Command {no ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} + +Adds a static route entry to the Multicast RIB. This performs exactly as +the @command{ip route} command, except that it inserts the route in the +Multicast RIB instead of the Unicast RIB. +@end deffn + + @node zebra Route Filtering @section zebra Route Filtering Zebra supports @command{prefix-list} and @command{route-map} to match From b162ab753e70328cb6815e58b4bc5b03e9dd4f42 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 2 Feb 2015 03:00:22 +0100 Subject: [PATCH 0458/1342] doc: explain rpf lookup default mode Reported-by: Alexis Rosen Signed-off-by: David Lamparter --- doc/main.texi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/main.texi b/doc/main.texi index 810866aa1..4c11d2440 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -224,6 +224,11 @@ with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. @end table +The @code{mrib-then-urib} setting is the default behavior if nothing is +configured. If this is the desired behavior, it should be explicitly +configured to make the configuration immune against possible changes in +what the default behavior is. + WARNING: Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. @end deffn From 871dbcfede60a8d2d286728bcbd88f27c2035b87 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 11 Aug 2009 15:43:05 -0300 Subject: [PATCH 0459/1342] [pim] Initial pim 0.155 --- Makefile.am | 4 +- SERVICES | 1 + configure.ac | 54 +- doc/Makefile.am | 4 +- doc/install.texi | 1 + doc/pimd.8 | 108 + lib/command.h | 2 + lib/log.c | 2 + lib/log.h | 2 + lib/memory.c | 15 +- lib/memtypes.c | 17 + lib/zebra.h | 17 +- pimd/AUTHORS | 9 + pimd/CAVEATS | 137 ++ pimd/COMMANDS | 62 + pimd/COPYING | 340 +++ pimd/DEBUG | 49 + pimd/LINUX_KERNEL_MROUTE_MFC | 22 + pimd/Makefile.am | 70 + pimd/README | 157 ++ pimd/TODO | 356 +++ pimd/pim_assert.c | 803 +++++++ pimd/pim_assert.h | 75 + pimd/pim_cmd.c | 3923 ++++++++++++++++++++++++++++++++++ pimd/pim_cmd.h | 56 + pimd/pim_hello.c | 529 +++++ pimd/pim_hello.h | 46 + pimd/pim_iface.c | 1132 ++++++++++ pimd/pim_iface.h | 160 ++ pimd/pim_ifchannel.c | 893 ++++++++ pimd/pim_ifchannel.h | 145 ++ pimd/pim_igmp.c | 1411 ++++++++++++ pimd/pim_igmp.h | 172 ++ pimd/pim_igmpv3.c | 1717 +++++++++++++++ pimd/pim_igmpv3.h | 100 + pimd/pim_join.c | 428 ++++ pimd/pim_join.h | 43 + pimd/pim_macro.c | 437 ++++ pimd/pim_macro.h | 44 + pimd/pim_main.c | 276 +++ pimd/pim_mroute.c | 432 ++++ pimd/pim_mroute.h | 173 ++ pimd/pim_msg.c | 106 + pimd/pim_msg.h | 52 + pimd/pim_neighbor.c | 696 ++++++ pimd/pim_neighbor.h | 74 + pimd/pim_oil.c | 140 ++ pimd/pim_oil.h | 53 + pimd/pim_pim.c | 716 +++++++ pimd/pim_pim.h | 71 + pimd/pim_rand.c | 60 + pimd/pim_rand.h | 30 + pimd/pim_rpf.c | 254 +++ pimd/pim_rpf.h | 36 + pimd/pim_signals.c | 85 + pimd/pim_signals.h | 28 + pimd/pim_sock.c | 348 +++ pimd/pim_sock.h | 52 + pimd/pim_str.c | 46 + pimd/pim_str.h | 32 + pimd/pim_time.c | 151 ++ pimd/pim_time.h | 39 + pimd/pim_tlv.c | 707 ++++++ pimd/pim_tlv.h | 133 ++ pimd/pim_upstream.c | 686 ++++++ pimd/pim_upstream.h | 122 ++ pimd/pim_util.c | 132 ++ pimd/pim_util.h | 41 + pimd/pim_version.c | 25 + pimd/pim_version.h | 30 + pimd/pim_vty.c | 145 ++ pimd/pim_vty.h | 32 + pimd/pim_zebra.c | 1172 ++++++++++ pimd/pim_zebra.h | 40 + pimd/pim_zlookup.c | 455 ++++ pimd/pim_zlookup.h | 47 + pimd/pimd.c | 125 ++ pimd/pimd.conf.sample | 35 + pimd/pimd.h | 121 ++ pimd/quagga-bootstrap.sh | 21 + pimd/quagga-build.sh | 10 + pimd/quagga-configure.sh | 10 + pimd/quagga-git-add.sh | 12 + pimd/quagga-memtypes.sh | 22 + pimd/savannah-git-clone.sh | 16 + ports/Makefile | 1 + ports/pkg/DESCR | 1 + redhat/quagga.spec.in | 11 +- zebra/zebra_rib.c | 93 +- zebra/zserv.c | 1 + 90 files changed, 21722 insertions(+), 17 deletions(-) create mode 100644 doc/pimd.8 create mode 100644 pimd/AUTHORS create mode 100644 pimd/CAVEATS create mode 100644 pimd/COMMANDS create mode 100644 pimd/COPYING create mode 100644 pimd/DEBUG create mode 100644 pimd/LINUX_KERNEL_MROUTE_MFC create mode 100644 pimd/Makefile.am create mode 100644 pimd/README create mode 100644 pimd/TODO create mode 100644 pimd/pim_assert.c create mode 100644 pimd/pim_assert.h create mode 100644 pimd/pim_cmd.c create mode 100644 pimd/pim_cmd.h create mode 100644 pimd/pim_hello.c create mode 100644 pimd/pim_hello.h create mode 100644 pimd/pim_iface.c create mode 100644 pimd/pim_iface.h create mode 100644 pimd/pim_ifchannel.c create mode 100644 pimd/pim_ifchannel.h create mode 100644 pimd/pim_igmp.c create mode 100644 pimd/pim_igmp.h create mode 100644 pimd/pim_igmpv3.c create mode 100644 pimd/pim_igmpv3.h create mode 100644 pimd/pim_join.c create mode 100644 pimd/pim_join.h create mode 100644 pimd/pim_macro.c create mode 100644 pimd/pim_macro.h create mode 100644 pimd/pim_main.c create mode 100644 pimd/pim_mroute.c create mode 100644 pimd/pim_mroute.h create mode 100644 pimd/pim_msg.c create mode 100644 pimd/pim_msg.h create mode 100644 pimd/pim_neighbor.c create mode 100644 pimd/pim_neighbor.h create mode 100644 pimd/pim_oil.c create mode 100644 pimd/pim_oil.h create mode 100644 pimd/pim_pim.c create mode 100644 pimd/pim_pim.h create mode 100644 pimd/pim_rand.c create mode 100644 pimd/pim_rand.h create mode 100644 pimd/pim_rpf.c create mode 100644 pimd/pim_rpf.h create mode 100644 pimd/pim_signals.c create mode 100644 pimd/pim_signals.h create mode 100644 pimd/pim_sock.c create mode 100644 pimd/pim_sock.h create mode 100644 pimd/pim_str.c create mode 100644 pimd/pim_str.h create mode 100644 pimd/pim_time.c create mode 100644 pimd/pim_time.h create mode 100644 pimd/pim_tlv.c create mode 100644 pimd/pim_tlv.h create mode 100644 pimd/pim_upstream.c create mode 100644 pimd/pim_upstream.h create mode 100644 pimd/pim_util.c create mode 100644 pimd/pim_util.h create mode 100644 pimd/pim_version.c create mode 100644 pimd/pim_version.h create mode 100644 pimd/pim_vty.c create mode 100644 pimd/pim_vty.h create mode 100644 pimd/pim_zebra.c create mode 100644 pimd/pim_zebra.h create mode 100644 pimd/pim_zlookup.c create mode 100644 pimd/pim_zlookup.h create mode 100644 pimd/pimd.c create mode 100644 pimd/pimd.conf.sample create mode 100644 pimd/pimd.h create mode 100755 pimd/quagga-bootstrap.sh create mode 100755 pimd/quagga-build.sh create mode 100755 pimd/quagga-configure.sh create mode 100755 pimd/quagga-git-add.sh create mode 100755 pimd/quagga-memtypes.sh create mode 100755 pimd/savannah-git-clone.sh diff --git a/Makefile.am b/Makefile.am index b6082535c..405142f85 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,12 +1,12 @@ ## Process this file with automake to produce Makefile.in. SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \ - @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ + @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ - solaris + solaris pimd EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ diff --git a/SERVICES b/SERVICES index 9c3546bc8..c69d0c1a7 100644 --- a/SERVICES +++ b/SERVICES @@ -17,3 +17,4 @@ bgpd 2605/tcp ospf6d 2606/tcp ospfapi 2607/tcp isisd 2608/tcp +pimd 2611/tcp diff --git a/configure.ac b/configure.ac index 9d188284d..7696bd70b 100755 --- a/configure.ac +++ b/configure.ac @@ -220,6 +220,8 @@ AC_ARG_ENABLE(watchquagga, [ --disable-watchquagga do not build watchquagga]) AC_ARG_ENABLE(isisd, [ --enable-isisd build isisd]) +AC_ARG_ENABLE(pimd, +[ --enable-pimd build pimd]) AC_ARG_ENABLE(solaris, [ --enable-solaris build solaris]) AC_ARG_ENABLE(bgp-announce, @@ -1362,6 +1364,12 @@ case "${enable_isisd}" in esac AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") +case "${enable_pimd}" in + "yes") PIMD="pimd";; + "no" ) PIMD="";; + * ) ;; +esac + # XXX Perhaps auto-enable on Solaris, but that's messy for cross builds. case "${enable_solaris}" in "yes") SOLARIS="solaris";; @@ -1385,6 +1393,7 @@ AC_SUBST(OSPF6D) AC_SUBST(BABELD) AC_SUBST(WATCHQUAGGA) AC_SUBST(ISISD) +AC_SUBST(PIMD) AC_SUBST(SOLARIS) AC_SUBST(VTYSH) AC_SUBST(INCLUDES) @@ -1467,7 +1476,8 @@ dnl sockaddr and netinet checks dnl --------------------------- AC_CHECK_TYPES([struct sockaddr, struct sockaddr_in, struct sockaddr_in6, struct sockaddr_un, struct sockaddr_dl, - socklen_t, + socklen_t, struct vifctl, struct mfcctl, struct sioc_sg_req, + vifi_t, struct sioc_vif_req, struct igmpmsg, struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq, struct nd_opt_adv_interval, struct rt_addrinfo, struct nd_opt_homeagent_info, struct nd_opt_adv_interval], @@ -1496,6 +1506,45 @@ AC_CHECK_TYPES([struct in_pktinfo], AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!']) fi], [QUAGGA_INCLUDES]) +dnl ----------------------- +dnl checking for IP_PKTINFO +dnl ----------------------- +AC_MSG_CHECKING(for IP_PKTINFO) +AC_TRY_COMPILE([#include ], [ + int opt = IP_PKTINFO; +], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IP_PKTINFO, 1, [Have IP_PKTINFO]) +], [ + AC_MSG_RESULT(no) +]) + +dnl --------------------------- +dnl checking for IP_RECVDSTADDR +dnl --------------------------- +AC_MSG_CHECKING(for IP_RECVDSTADDR) +AC_TRY_COMPILE([#include ], [ + int opt = IP_RECVDSTADDR; +], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IP_RECVDSTADDR, 1, [Have IP_RECVDSTADDR]) +], [ + AC_MSG_RESULT(no) +]) + +dnl ---------------------- +dnl checking for IP_RECVIF +dnl ---------------------- +AC_MSG_CHECKING(for IP_RECVIF) +AC_TRY_COMPILE([#include ], [ + int opt = IP_RECVIF; +], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IP_RECVIF, 1, [Have IP_RECVIF]) +], [ + AC_MSG_RESULT(no) +]) + dnl -------------------------------------- dnl checking for getrusage struct and call dnl -------------------------------------- @@ -1685,6 +1734,7 @@ AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID) AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID) AC_DEFINE_UNQUOTED(PATH_BABELD_PID, "$quagga_statedir/babeld.pid",babeld PID) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID) +AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID) AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID) AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$quagga_statedir/zserv.api",zebra api socket) AC_DEFINE_UNQUOTED(ZEBRA_VTYSH_PATH, "$quagga_statedir/zebra.vty",zebra vty socket) @@ -1695,6 +1745,7 @@ AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socke AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket) AC_DEFINE_UNQUOTED(BABEL_VTYSH_PATH, "$quagga_statedir/babeld.vty",babeld vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket) +AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket) AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory) dnl ------------------------------- @@ -1720,6 +1771,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile + pimd/Makefile tests/bgpd.tests/Makefile tests/libzebra.tests/Makefile redhat/Makefile diff --git a/doc/Makefile.am b/doc/Makefile.am index f58657b97..8869c818e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -61,7 +61,9 @@ quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ .dia.png: $(DIATOPNG) "$@" $< -man_MANS = +if PIMD +man_MANS += pimd.8 +endif if BGPD man_MANS += bgpd.8 diff --git a/doc/install.texi b/doc/install.texi index e958d845f..7349e92cb 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -273,6 +273,7 @@ bgpd 2605/tcp # BGPd vty ospf6d 2606/tcp # OSPF6d vty ospfapi 2607/tcp # ospfapi isisd 2608/tcp # ISISd vty +pimd 2611/tcp # PIMd vty @end example If you use a FreeBSD newer than 2.2.8, the above entries are already diff --git a/doc/pimd.8 b/doc/pimd.8 new file mode 100644 index 000000000..b26b11284 --- /dev/null +++ b/doc/pimd.8 @@ -0,0 +1,108 @@ +.TH PIM 8 "10 December 2008" "Quagga PIM daemon" "Version 0.99.11" +.SH NAME +pimd \- a PIM routing for use with Quagga Routing Suite. +.SH SYNOPSIS +.B pimd +[ +.B \-dhvZ +] [ +.B \-f +.I config-file +] [ +.B \-i +.I pid-file +] [ +.B \-P +.I port-number +] [ +.B \-A +.I vty-address +] [ +.B \-u +.I user +] [ +.B \-g +.I group +] +.SH DESCRIPTION +.B pimd +is a protocol-independent multicast component that works with the +.B Quagga +Routing Suite. +.SH OPTIONS +Options available for the +.B pimd +command: +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/pimd.conf\fR. +.TP +\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR +Specify the group to run as. Default is \fIquagga\fR. +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When pimd starts its process identifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart pimd. The likely default is \fB\fI/var/run/pimd.pid\fR. +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the pimd VTY will listen on. This defaults to +2611, as specified in \fB\fI/etc/services\fR. +.TP +\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR +Specify the address that the pimd VTY will listen on. Default is all +interfaces. +.TP +\fB\-u\fR, \fB\-\-user \fR\fIuser\fR +Specify the user to run as. Default is \fIquagga\fR. +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. +.TP +\fB\-Z\fR, \fB\-\-debug_zclient\fR +Enable logging information for zclient debugging. +.SH FILES +.TP +.BI /usr/local/sbin/pimd +The default location of the +.B pimd +binary. +.TP +.BI /usr/local/etc/pimd.conf +The default location of the +.B pimd +config file. +.TP +.BI $(PWD)/pimd.log +If the +.B pimd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBpimd\fR. +.SH WARNING +This man page is intended to be a quick reference for command line +options. +.SH DIAGNOSTICS +The pimd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. +.SH "SEE ALSO" +.BR zebra (8), +.BR vtysh (1) +.SH BUGS +\fBpimd\fR is in early development at the moment and is not ready for +production use. + +.B pimd +eats bugs for breakfast. If you have food for the maintainers try +.BI http://savannah.nongnu.org/projects/qpimd +.SH AUTHORS +See +.BI http://savannah.nongnu.org/projects/qpimd +for an accurate list of authors. + diff --git a/lib/command.h b/lib/command.h index 8dc50d0df..5156dbf13 100644 --- a/lib/command.h +++ b/lib/command.h @@ -1,6 +1,7 @@ /* * Zebra configuration command interface routine * Copyright (C) 1997, 98 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * @@ -88,6 +89,7 @@ enum node_type OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ ISIS_NODE, /* ISIS protocol mode */ + PIM_NODE, /* PIM protocol mode */ MASC_NODE, /* MASC for multicast. */ IRDP_NODE, /* ICMP Router Discovery Protocol mode. */ IP_NODE, /* Static ip route node. */ diff --git a/lib/log.c b/lib/log.c index 04f8fab63..abfd35bc5 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1,6 +1,7 @@ /* * Logging of zebra * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * @@ -51,6 +52,7 @@ const char *zlog_proto_names[] = "BABEL", "OSPF6", "ISIS", + "PIM", "MASC", NULL, }; diff --git a/lib/log.h b/lib/log.h index f3b43ad12..d9f1ecaae 100644 --- a/lib/log.h +++ b/lib/log.h @@ -1,6 +1,7 @@ /* * Zebra logging funcions. * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * @@ -53,6 +54,7 @@ typedef enum ZLOG_BABEL, ZLOG_OSPF6, ZLOG_ISIS, + ZLOG_PIM, ZLOG_MASC } zlog_proto_t; diff --git a/lib/memory.c b/lib/memory.c index 620bdee51..28bbdc119 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -1,6 +1,7 @@ /* * Memory management routine * Copyright (C) 1998 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * @@ -521,6 +522,17 @@ DEFUN (show_memory_isis, return CMD_SUCCESS; } +DEFUN (show_memory_pim, + show_memory_pim_cmd, + "show memory pim", + SHOW_STR + "Memory statistics\n" + "PIM memory\n") +{ + show_memory_vty (vty, memory_list_pim); + return CMD_SUCCESS; +} + void memory_init (void) { @@ -545,6 +557,7 @@ memory_init (void) install_element (VIEW_NODE, &show_memory_ospf_cmd); install_element (VIEW_NODE, &show_memory_ospf6_cmd); install_element (VIEW_NODE, &show_memory_isis_cmd); + install_element (VIEW_NODE, &show_memory_pim_cmd); install_element (ENABLE_NODE, &show_memory_cmd); install_element (ENABLE_NODE, &show_memory_all_cmd); @@ -556,7 +569,7 @@ memory_init (void) install_element (ENABLE_NODE, &show_memory_bgp_cmd); install_element (ENABLE_NODE, &show_memory_ospf_cmd); install_element (ENABLE_NODE, &show_memory_ospf6_cmd); - install_element (ENABLE_NODE, &show_memory_isis_cmd); + install_element (ENABLE_NODE, &show_memory_pim_cmd); } /* Stats querying from users */ diff --git a/lib/memtypes.c b/lib/memtypes.c index 47a343873..26e27e72d 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -1,4 +1,6 @@ /* + * Portions Copyright (c) 2008 Everton da Silva Marques + * * Memory type definitions. This file is parsed by memtypes.awk to extract * MTYPE_ and memory_list_.. information in order to autogenerate * memtypes.h. @@ -255,6 +257,20 @@ struct memory_list memory_list_isis[] = { -1, NULL }, }; +struct memory_list memory_list_pim[] = +{ + { MTYPE_PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL" }, + { MTYPE_PIM_INTERFACE, "PIM interface" }, + { MTYPE_PIM_IGMP_JOIN, "PIM interface IGMP static join" }, + { MTYPE_PIM_IGMP_SOCKET, "PIM interface IGMP socket" }, + { MTYPE_PIM_IGMP_GROUP, "PIM interface IGMP group" }, + { MTYPE_PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source" }, + { MTYPE_PIM_NEIGHBOR, "PIM interface neighbor" }, + { MTYPE_PIM_IFCHANNEL, "PIM interface (S,G) state" }, + { MTYPE_PIM_UPSTREAM, "PIM upstream (S,G) state" }, + { -1, NULL }, +}; + struct memory_list memory_list_vtysh[] = { { MTYPE_VTYSH_CONFIG, "Vtysh configuration", }, @@ -271,5 +287,6 @@ struct mlist mlists[] __attribute__ ((unused)) = { { memory_list_ospf6, "OSPF6" }, { memory_list_isis, "ISIS" }, { memory_list_bgp, "BGP" }, + { memory_list_pim, "PIM" }, { NULL, NULL}, }; diff --git a/lib/zebra.h b/lib/zebra.h index a4e02148d..67d714cf8 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -1,5 +1,6 @@ /* Zebra common header. Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro + Portions Copyright (c) 2008 Everton da Silva Marques This file is part of GNU Zebra. @@ -434,8 +435,20 @@ struct in_pktinfo */ #define ZEBRA_HEADER_MARKER 255 -/* Zebra route's types are defined in route_types.h */ -#include "route_types.h" +/* Zebra route's types. */ +#define ZEBRA_ROUTE_SYSTEM 0 +#define ZEBRA_ROUTE_KERNEL 1 +#define ZEBRA_ROUTE_CONNECT 2 +#define ZEBRA_ROUTE_STATIC 3 +#define ZEBRA_ROUTE_RIP 4 +#define ZEBRA_ROUTE_RIPNG 5 +#define ZEBRA_ROUTE_OSPF 6 +#define ZEBRA_ROUTE_OSPF6 7 +#define ZEBRA_ROUTE_ISIS 8 +#define ZEBRA_ROUTE_BGP 9 +#define ZEBRA_ROUTE_HSLS 10 +#define ZEBRA_ROUTE_PIM 11 +#define ZEBRA_ROUTE_MAX 12 /* Note: whenever a new route-type or zserv-command is added the * corresponding {command,route}_types[] table in lib/log.c MUST be diff --git a/pimd/AUTHORS b/pimd/AUTHORS new file mode 100644 index 000000000..f6135a410 --- /dev/null +++ b/pimd/AUTHORS @@ -0,0 +1,9 @@ +# $QuaggaId: $Format:%an, %ai, %h$ $ + +# Everton da Silva Marques +$ more ~/.gitconfig +[user] + name = Everton Marques + email = everton.marques@gmail.com + +-x- diff --git a/pimd/CAVEATS b/pimd/CAVEATS new file mode 100644 index 000000000..7dc950fed --- /dev/null +++ b/pimd/CAVEATS @@ -0,0 +1,137 @@ +# $QuaggaId: $Format:%an, %ai, %h$ $ + +C1 IGMPv3 backward compatibility with IGMPv1 and IGMPv2 is not + implemented. See RFC 3376, 7.3. Multicast Router Behavior. That's + because only Source-Specific Multicast is currently targeted. + +C2 IGMPv3 support for forwarding any-source groups is not + implemented. Traffic for groups in mode EXCLUDE {empty} won't be + forwarded. See RFC 3376, 6.3. Source-Specific Forwarding + Rules. That's because only Source-Specific Multicast is currently + targeted. + +C3 Load Splitting of IP Multicast Traffic over ECMP is not supported. + See also: RFC 2991 + Multipath Issues in Unicast and Multicast Next-Hop Selection + http://www.rfc-editor.org/rfc/rfc2991.txt + +C4 IPSec AH authentication is not supported (RFC 4601: + 6.3. Authentication Using IPsec). + +C5 PIM support is limited to SSM mode as defined in section 4.8.2 + (PIM-SSM-Only Routers) of RFC4601. That's because only + Source-Specific Multicast is currently targeted. + +C6 PIM implementation currently does not support IPv6. PIM-SSM + requires IGMPv3 for IPv4 and MLDv2 for IPv6. MLDv2 is currently + missing. See also CAVEAT C9. + +C7 (S,G) Assert state machine (RFC 4601, section 4.6.1) is not + implemented. See also TODO T6. See also CAVEAT C10. + +C8 It is not possible to disable join suppression in order to + explicitly track the join membership of individual downstream + routers. + - IGMPv3 Explicit Membership Tracking is not supported. + When explicit tracking is enabled on a router, the router can + individually track the Internet Group Management Protocol (IGMP) + membership state of all reporting hosts. This feature allows the + router to achieve minimal leave latencies when hosts leave a + multicast group or channel. Example: + conf t + interface eth0 + ip igmp explicit-tracking + +C9 Only IPv4 Address Family (number=1) is supported in the PIM Address + Family field. + See also RFC 4601: 5.1. PIM Address Family + See also CAVEAT C6. + See also http://www.iana.org/assignments/address-family-numbers + +C10 FIXED Assert metric depends on metric_preference and + route_metric. Those parameters should be fetched from RIB + (zebra). See also pim_rpf.c, pim_rpf_update(). + +C11 SSM Mapping is not supported + + SSM Mapping Overview: + + SSM mapping introduces a means for the last hop router to discover + sources sending to groups. When SSM mapping is configured, if a + router receives an IGMPv1 or IGMPv2 membership report for a + particular group G, the router translates this report into one or + more (S, G) channel memberships for the well-known sources + associated with this group. + + When the router receives an IGMPv1 or IGMPv2 membership report for + a group G, the router uses SSM mapping to determine one or more + source IP addresses for the group G. SSM mapping then translates + the membership report as an IGMPv3 report INCLUDE (G, [S1, G], + [S2, G]...[Sn, G] and continues as if it had received an IGMPv3 + report. The router then sends out PIM joins toward (S1, G) to (Sn, + G) and continues to be joined to these groups as long as it + continues to receive the IGMPv1 or IGMPv2 membership reports and + as long as the SSM mapping for the group remains the same. SSM + mapping, thus, enables you to leverage SSM for video delivery to + legacy STBs that do not support IGMPv3 or for applications that do + not take advantage of the IGMPv3 host stack. + + SSM mapping enables the last hop router to determine the source + addresses either by a statically configured table on the router or + by consulting a DNS server. When the statically configured table + is changed, or when the DNS mapping changes, the router will leave + the current sources associated with the joined groups. + +C12 MRIB for incongruent unicast/multicast topologies is not supported. + RPF mechanism currently just looks up the information in the + unicast routing table. + + See also: + RFC5110: 2.2.3. Issue: Overlapping Unicast/Multicast Topology + + Sometimes, multicast RPF mechanisms first look up the multicast + routing table, or M-RIB ("topology database") with a longest + prefix match algorithm, and if they find any entry (including a + default route), that is used; if no match is found, the unicast + routing table is used instead. + +C13 Can't detect change of primary address before the actual change. + Possible approach is to craft old interface address into ip source + address by using raw ip socket. + + See also: + + RFC 4601: 4.3.1. Sending Hello Messages + + Before an interface goes down or changes primary IP address, a + Hello message with a zero HoldTime should be sent immediately + (with the old IP address if the IP address changed). + + See also pim_sock_delete(). + +C14 Detection of interface primary address changes may fail when there + are multiple addresses. + See also TODO T32. + +C15 Changes in interface secondary address list are not immediately + detected. + See also TODO T31. + +C16 AMT Draft (mboned-auto-multicast) is not supported. + AMT = Automatic IP Multicast Without Explicit Tunnels + + See also: + + Draft + http://tools.ietf.org/html/draft-ietf-mboned-auto-multicast + http://tools.ietf.org/html/draft-ietf-mboned-auto-multicast-09 + + AMT gateway implementation for Linux + http://cs.utdallas.edu/amt/ + + AMT for Streaming (IPTV) on Global IP Multicast by Greg Shepherd (Cisco) + http://nznog.miniconf.org/nznog-2008-sysadmin-miniconf-greg-shepherd-iptv.pdf + +C17 SNMP / RFC 5060 (PIM MIB) is not supported. + +-x- diff --git a/pimd/COMMANDS b/pimd/COMMANDS new file mode 100644 index 000000000..5679e95a7 --- /dev/null +++ b/pimd/COMMANDS @@ -0,0 +1,62 @@ +# $QuaggaId: $Format:%an, %ai, %h$ $ + +global configuration commands: + ip multicast-routing Enable IP multicast forwarding + +interface configuration commands: + ip igmp Enable IGMP operation + ip igmp join IGMP join multicast group + ip igmp query-interval <1-1800> IGMP host query interval + ip igmp query-max-response-time <1-25> IGMP max query response (seconds) + ip igmp query-max-response-time-dsec <10-250> IGMP max query response (deciseconds) + ip pim ssm Enable PIM SSM operation + +verification commands: + show ip igmp interface IGMP interface information + show ip igmp parameters IGMP parameters information + show ip igmp groups IGMP groups information + show ip igmp groups retransmissions IGMP group retransmission + show ip igmp sources IGMP sources information + show ip igmp sources retransmissions IGMP source retransmission + show ip pim address PIM interface address + show ip pim assert PIM interface assert + show ip pim assert-internal PIM interface internal assert state + show ip pim assert-metric PIM interface assert metric + show ip pim assert-winner-metric PIM interface assert winner metric + show ip pim designated-router PIM interface designated router + show ip pim hello PIM interface hello information + show ip pim interface PIM interface information + show ip pim lan-prune-delay PIM neighbors LAN prune delay parameters + show ip pim local-membership PIM interface local-membership + show ip pim jp-override-interval PIM interface J/P override interval + show ip pim join PIM interface join information + show ip pim neighbor PIM neighbor information + show ip pim rpf PIM cached source rpf information + show ip pim secondary PIM neighbor addresses + show ip pim upstream PIM upstream information + show ip pim upstream-join-desired PIM upstream join-desired + show ip pim upstream-rpf PIM upstream source rpf + show ip multicast Multicast global information + show ip mroute IP multicast routing table + show ip mroute count Route and packet count data + show ip route IP routing table + +debug commands: + clear ip interfaces Reset interfaces + clear ip igmp interfaces Reset IGMP interfaces + clear ip pim interfaces Reset PIM interfaces + debug igmp IGMP protocol activity + debug pim PIM protocol activity + debug pim zebra ZEBRA protocol activity + show debugging State of each debugging option + test igmp receive report Test reception of IGMPv3 report + test pim receive assert Test reception of PIM assert + test pim receive hello Test reception of PIM hello + test pim receive join Test reception of PIM join + test pim receive prune Test reception of PIM prune + test pim receive upcall Test reception of kernel upcall + +statistics commands: + show memory pim PIM memory statistics + +-x- diff --git a/pimd/COPYING b/pimd/COPYING new file mode 100644 index 000000000..3912109b5 --- /dev/null +++ b/pimd/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/pimd/DEBUG b/pimd/DEBUG new file mode 100644 index 000000000..aeed9da19 --- /dev/null +++ b/pimd/DEBUG @@ -0,0 +1,49 @@ +# $QuaggaId: $Format:%an, %ai, %h$ $ + +DEBUG HINTS + + - Check the source is issuing multicast packets with TTL high enough + to reach the recipients. + + - Check the multicast packets are not being dropped due to + fragmentation problems. + + - The following command generates a 100-kbps multicast stream for + channel 1.1.1.1,239.1.1.1 with TTL 10 and 1000-byte payload per UDP + packet (to avoid fragmentation): + + nepim -b 1.1.1.1 -c 239.1.1.1 -T 10 -W 1000 -r 100k -a 1d + + - Remotely you can receive that stream by running: + + nepim -j 1.1.1.1+239.1.1.1@eth0 + (Remember of enabling both "ip pim ssm" and "ip igmp" under eth0.) + + +SAMPLE DEBUG COMMANDS + + conf t + int eth0 + ip pim ssm + + test pim receive hello eth0 192.168.0.2 600 10 111 1000 3000 0 + test pim receive join eth0 600 192.168.0.1 192.168.0.2 239.1.1.1 1.1.1.1 + + show ip pim join + + +INTEROPERABILITY WITH CISCO + + ! Cisco IP Multicast command reference: + ! ftp://ftpeng.cisco.com/ipmulticast/Multicast-Commands + ! + ip pim ssm default ! enable SSM mode for groups 232.0.0.0/8 + ip multicast-routing + ip pim state-refresh disable + no ip pim dm-fallback + ! + interface FastEthernet0 + ip pim sparse-mode + ip igmp version 3 + +-x- diff --git a/pimd/LINUX_KERNEL_MROUTE_MFC b/pimd/LINUX_KERNEL_MROUTE_MFC new file mode 100644 index 000000000..7dc44b0d1 --- /dev/null +++ b/pimd/LINUX_KERNEL_MROUTE_MFC @@ -0,0 +1,22 @@ +# $QuaggaId: $Format:%an, %ai, %h$ $ + +# +# The Linux Kernel MFC (Multicast Forwarding Cache) +# + +# Check Linux kernel multicast interfaces: +cat /proc/net/dev_mcast + +# Check that interface eth0 is forwarding multicast: +cat /proc/sys/net/ipv4/conf/eth0/mc_forwarding + +# Check Linux kernel multicast VIFs: +cat /proc/net/ip_mr_vif +Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote + +# Check Linux kernel MFC: +# Oifs format = vifi:TTL +cat /proc/net/ip_mr_cache +Group Origin Iif Pkts Bytes Wrong Oifs + +# -- end-of-file -- diff --git a/pimd/Makefile.am b/pimd/Makefile.am new file mode 100644 index 000000000..80df2e6b8 --- /dev/null +++ b/pimd/Makefile.am @@ -0,0 +1,70 @@ +## Process this file with automake to produce Makefile.in. +## $QuaggaId: $Format:%an, %ai, %h$ $ + +# qpimd - pimd for quagga +# Copyright (C) 2008 Everton da Silva Marques +# +# qpimd 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. +# +# qpimd 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 qpimd; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 59 Temple Place - Suite +# 330, Boston, MA 02111-1307, USA. + +# PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands +# PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging +# PIM_MOTD_VERSION: Includes pimd version in default MOTD +# PIM_USE_QUAGGA_INET_CHECKSUM: Prefer Quagga inet checksum +# PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex +# PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch +# PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries +# PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall + +PIM_DEFS = +#PIM_DEFS += -DPIM_DEBUG_BYDEFAULT +PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY +#PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH +PIM_DEFS += -DPIM_ZCLIENT_DEBUG +PIM_DEFS += -DPIM_MOTD_VERSION +PIM_DEFS += -DPIM_USE_QUAGGA_INET_CHECKSUM +PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC +#PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) +INSTALL_SDATA=@INSTALL@ -m 600 +LIBS = @LIBS@ +noinst_LIBRARIES = libpim.a +sbin_PROGRAMS = pimd + +libpim_a_SOURCES = \ + pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ + pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \ + pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ + pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ + pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ + pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c + +noinst_HEADERS = \ + pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ + pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \ + pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ + pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ + pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ + pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h + +pimd_SOURCES = \ + pim_main.c $(libpim_a_SOURCES) + +pimd_LDADD = ../lib/libzebra.la @LIBCAP@ + +examplesdir = $(exampledir) +dist_examples_DATA = pimd.conf.sample diff --git a/pimd/README b/pimd/README new file mode 100644 index 000000000..e42ceda24 --- /dev/null +++ b/pimd/README @@ -0,0 +1,157 @@ +# +# $QuaggaId: $Format:%an, %ai, %h$ $ +# + +INTRODUCTION + + qpimd aims to implement a PIM (Protocol Independent Multicast) + daemon for the Quagga Routing Suite. + + Initially qpimd targets only PIM SSM (Source-Specific + Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only + Routers) of RFC 4601. + + In order to deliver end-to-end multicast routing control + plane, qpimd includes the router-side of IGMPv3 (RFC 3376). + +LICENSE + + qpimd - pimd for quagga + Copyright (C) 2008 Everton da Silva Marques + + qpimd 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. + + qpimd 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 qpimd; see the file COPYING. If not, write + to the Free Software Foundation, Inc., 59 Temple Place - Suite + 330, Boston, MA 02111-1307, USA. + +HOME SITE + + qpimd lives at: + + http://savannah.nongnu.org/projects/qpimd + +PLATFORMS + + qpimd has been tested with Debian Lenny under Linux 2.6. + +REQUIREMENTS + + qpimd requires Quagga (0.99.11 or higher from http://www.quagga.net) + + The GNU Build System (Autotools) is required to build from + source code repository. + + gawk is also needed to build with Autotools. Any other awk + usually won't work. + +BUILDING FROM QUAGGA GIT REPOSITORY + + 1) Get the latest quagga source tree + + # git clone git://code.quagga.net/quagga.git quagga + + 2) Apply qpimd patch into quagga source tree + + # patch -p1 -d quagga < pimd-0.153-quagga-git20090623.patch + + 3) Compile and install quagga + + # cd quagga + # ./bootstrap.sh + # ./configure --prefix=/usr/local/quagga --enable-pimd + # make + # make install + +BUILDING FROM QUAGGA TARBALL + + 1) Get the latest quagga tarball + + # wget http://www.quagga.net/download/quagga-0.99.13.tar.gz + + 2) Unpack the quagga tarball + + # tar xzf quagga-0.99.13.tar.gz + + 3) Apply qpimd patch into quagga source tree + + # patch -p1 -d quagga-0.99.13 < pimd-0.153-quagga-0.99.13.patch + + 4) Compile and install quagga + + # cd quagga-0.99.13 + # ./configure --prefix=/usr/local/quagga --enable-pimd + # make + # make install + +USAGE + + 1) Configure and start the zebra daemon + + # cp /usr/local/quagga/etc/zebra.conf.sample /usr/local/quagga/etc/zebra.conf + # vi /usr/local/quagga/etc/zebra.conf + # /usr/local/quagga/sbin/zebra + + 2) Configure and start the pimd daemon + + # cp /usr/local/quagga/etc/pimd.conf.sample /usr/local/quagga/etc/pimd.conf + # vi /usr/local/quagga/etc/pimd.conf + # /usr/local/quagga/sbin/pimd + + 3) Access pimd vty interface at port TCP 2611 + + # telnet localhost 2611 + +CONFIGURATION COMMANDS + + See available commands in the file pimd/COMMANDS. + +KNOWN CAVEATS + + See list of known caveats in the file pimd/CAVEATS. + +SUPPORT + + Please post comments, questions, patches, bug reports at the + support site: + + http://savannah.nongnu.org/projects/qpimd + +RELATED WORK + + igmprt: An IGMPv3-router implementation + - http://www.loria.fr/~lahmadi/igmpv3-router.html + + pimd: PIMv2-SM daemon + - http://netweb.usc.edu/pim/pimd (URL broken in 2008-12-23) + - http://packages.debian.org/source/sid/pimd (from Debian) + + zpimd: zpimd is not dependent of zebra or any other routing daemon + - ftp://robur.slu.se/pub/Routing/Zebra + - http://sunsite2.icm.edu.pl/pub/unix/routing/zpimd + + mrd6: an IPv6 Multicast Router for Linux systems + - http://fivebits.net/proj/mrd6/ + + MBGP: Implementation of RFC 2858 for Quagga + - git://git.coplanar.net/~balajig/quagga + - http://www.gossamer-threads.com/lists/quagga/dev/18000 + +REFERENCES + + IANA Protocol Independent Multicast (PIM) Parameters + http://www.iana.org/assignments/pim-parameters/pim-parameters.txt + + Address Family Numbers + http://www.iana.org/assignments/address-family-numbers + + -- END -- diff --git a/pimd/TODO b/pimd/TODO new file mode 100644 index 000000000..7a2ca0b65 --- /dev/null +++ b/pimd/TODO @@ -0,0 +1,356 @@ +# $QuaggaId: $Format:%an, %ai, %h$ $ + +T1 DONE Implement debug command + test pim receive join + +T2 DONE Implement debug command + test pim receive prune + +T3 DONE Per-interface Downstream (S,G) state machine + (RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages) + +T4 DONE Upstream (S,G) state machine + (RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages) + +T5 DONE Verify Data Packet Forwarding Rules + RFC 4601 4.2. Data Packet Forwarding Rules + RFC 4601 4.8.2. PIM-SSM-Only Routers + + Additionally, the Packet forwarding rules of Section 4.2 can be + simplified in a PIM-SSM-only router: + + iif is the incoming interface of the packet. + oiflist = NULL + if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { + oiflist = inherited_olist(S,G) + } else if (iif is in inherited_olist(S,G)) { + send Assert(S,G) on iif + } + oiflist = oiflist (-) iif + forward packet on all interfaces in oiflist + + Macro: + inherited_olist(S,G) = + joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) + +T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1). + Changes in pim_ifchannel.ifassert_winner should trigger + pim_upstream_update_join_desired(). + Depends on TODO T27. + Depends on TODO T33. + See also CAVEAT C7. + See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages + Transitions from Joined State + RPF'(S,G) changes due to an Assert + + http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html: + + The PIM Assert mechanism is used to shutoff duplicate flows onto + the same multiaccess network. Routers detect this condiction when + they receive an (S,G) packet via a multi-access interface that is + in the (S,G) OIL. This causes the routers to send Assert + Messages. + + Note that neighbors will not accept Join/Prune or Assert messages + from a router unless they have first heard a Hello message from that + router. Thus, if a router needs to send a Join/Prune or Assert + message on an interface on which it has not yet sent a Hello message + with the currently configured IP address, then it MUST immediately + send the relevant Hello message without waiting for the Hello Timer + to expire, followed by the Join/Prune or Assert message. + +T7 DONE Implement hello option: LAN Prune Delay + +T8 DONE Implement J/P_Override_Interval(I) + Depends on TODO T7. + See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval. + +T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update. + channel_oil vif index accordingly ? + Beware accidentaly adding looped MFC entries (IIF=OIF). + +T10 DONE React to (S,G) join directed to another upstream address. See + also: + + RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages + + If a router wishes to propagate a Join(S,G) upstream, it must also + watch for messages on its upstream interface from other routers on + that subnet, and these may modify its behavior. If it sees a + Join(S,G) to the correct upstream neighbor, it should suppress its + own Join(S,G). If it sees a Prune(S,G), Prune(S,G,rpt), or + Prune(*,G) to the correct upstream neighbor towards S, it should + be prepared to override that prune by scheduling a Join(S,G) to be + sent almost immediately. + +T11 DONE Review protocol modifications for SSM + (RFC 4601 4.8.1. Protocol Modifications for SSM Destination + Addresses) + +T12 DONE Review updates of RPF entries. + FIXME pim_upstream.c send_join(): + Currently only one upstream state is affected by detection of RPF change. + RPF change should affect all upstream states sharing the RPF cache. + +T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually + implemented with this strategy: + rpf_ifch=find_ifch(up->rpf->interface). + See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example. + + $ grep -i macro pimd/*.c + pimd/pim_iface.c: RFC 4601: 4.1.6. State Summarization Macros + pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros + pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros + pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros + pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros + pimd/pim_ifchannel.c: Macro: + pimd/pim_rpf.c: RFC 4601: 4.1.6. State Summarization Macros + +T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. + See pim_mroute.c mroute_msg(). + +T15 DONE Interface command to statically join (S,G). + interface eth0 + ip igmp join-group 239.1.1.1 source 1.1.1.1 + +T16 DONE RPF'(S,G) lookup is not working for S reachable with default route. + See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c. + Zebra daemon RIB is not reflecting changes in kernel routes + accurately? + +T17 DONE Prevent CLI from creating bogus interfaces. + Example: + conf t + interface xxx + +T18 Consider reliable pim solution (refresh reduction) + A Reliable Transport Mechanism for PIM + http://tools.ietf.org/wg/pim/draft-ietf-pim-port/ + PORT=PIM-Over-Reliable-Transport + +T19 DONE Fix self as neighbor + See mailing list post: + http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html + +T20 DONE Fix debug message: "pim_neighbor_update: internal error: + trying to replace same prefix list" + See mailing list post: + http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html + +T21 DONE Clean-up PIM/IGMP interface mismatch debugging + See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am + See mailing list post: + http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html + +T22 DONE IGMP must be protected against adding looped MFC entries + created by both source and receiver attached to the same + interface. + +T23 DONE libzebra crash after zclient_lookup_nexthop. + See mailing list post: + http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html + +T24 DONE zserv may return recursive routes: + - nexthop type is set to ZEBRA_NEXTHOP_IPV4 + - ifindex is not reported + - calls expecting ifindex (fib_lookup_if_vif_index) are disrupted + See also this mailing list post: + [PATCH 21/21] Link detect and recursive routes + http://www.gossamer-threads.com/lists/quagga/dev/17564 + +T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32 + See also: + pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32 + zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32 + +T26 DONE Zebra daemon is marking recursive static route as inactive. + + FIXED: zebra daemon was incorrectly marking recursive routes + pointing to kernel routes as inactive: + zebra/zebra_rib.c nexthop_active_ipv4: + -- Original: + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + -- Fixed: + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || + match->type == ZEBRA_ROUTE_KERNEL) + + Old problem description: + + This prevents rib_match_ipv4 from returning its nexthop: + client: pim_zlookup.c zclient_read_nexthop + server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4 + + Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4 + Examples: + rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); + rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); + + This patch didn't fix the issue: + [PATCH 21/21] Link detect and recursive routes + http://www.gossamer-threads.com/lists/quagga/dev/17564 + + See the example below for the route 2.2.2.2. + +bash# route add -host 1.1.1.1 gw 127.0.0.1 +bash# route add -host 2.2.2.2 gw 1.1.1.1 +bash# netstat -nvr +Kernel IP routing table +Destination Gateway Genmask Flags MSS Window irtt Iface +2.2.2.2 1.1.1.1 255.255.255.255 UGH 0 0 0 lo +1.1.1.1 127.0.0.1 255.255.255.255 UGH 0 0 0 lo +192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 +0.0.0.0 192.168.0.2 0.0.0.0 UG 0 0 0 eth0 +bash# + +zebra# sh ip route +Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, + I - ISIS, B - BGP, > - selected route, * - FIB route + +K>* 0.0.0.0/0 via 192.168.0.2, eth0 +K>* 1.1.1.1/32 via 127.0.0.1, lo +K * 2.2.2.2/32 via 1.1.1.1, lo inactive +C>* 127.0.0.0/8 is directly connected, lo +C>* 192.168.0.0/24 is directly connected, eth0 + +quagga-pimd-router# sh ip route 1.1.1.1 +Address NextHop Interface Metric Preference +1.1.1.1 127.0.0.1 lo 0 0 +quagga-pimd-router# +quagga-pimd-router# sh ip route 2.2.2.2 +Address NextHop Interface Metric Preference +2.2.2.2 192.168.0.2 eth0 0 0 +quagga-pimd-router# + +T27 DONE Implement debug command + test pim receive assert + See also TODO T6: (S,G) Assert state machine. + +T28 DONE Bad IPv4 address family=02 in Join/Prune dump + Reported by Andrew Lunn + + # 58-byte pim v2 Join/Prune dump + # ------------------------------ + # IPv4 address family=02 is wrong, correct IPv4 address family is 01 + # See http://www.iana.org/assignments/address-family-numbers + # + c8XX YY03 : ip src 200.xx.yy.3 + e000 000d : ip dst 224.0.0.13 + 9404 0000 : ip router alert option 148.4.0.0 + 2300 ab13 : pimv2,type=3 res=00 checksum=ab13 + 0200 : upstream family=02, encoding=00 + c8XX YY08 : upstream 200.xx.yy.8 + 0001 00d2 : res=00 groups=01 holdtime=00d2 + 0200 0020 : group family=02, encoding=00, res=00, mask_len=20 + ef01 0101 : group address 239.1.1.1 + 0001 0000 : joined=0001 pruned=0000 + 0200 0020 : source family=02, encoding=00, res=00, mask_len=20 + 0101 0101 : source address 1.1.1.1 + +T29 DONE Reset interface PIM-hello-sent counter when primary address changes + See pim_ifp->pim_ifstat_hello_sent + + RFC 4601: 4.3.1. Sending Hello Messages + + Thus, if a router needs to send a Join/Prune or Assert message on + an interface on which it has not yet sent a Hello message with the + currently configured IP address, then it MUST immediately send the + relevant Hello message without waiting for the Hello Timer to + expire, followed by the Join/Prune or Assert message. + +T30 DONE Run interface DR election when primary address changes + Reported by Andrew Lunn + See pim_if_dr_election(). + +T31 If an interface changes one of its secondary IP addresses, a Hello + message with an updated Address_List option and a non-zero + HoldTime should be sent immediately. + See also CAVEAT C15. + See also RFC 4601: 4.3.1. Sending Hello Messages + +T32 Detection of interface primary address changes may fail when there + are multiple addresses. + See also CAVEAT C14. + + pim_find_primary_addr() should return interface primary address + from connected list. Currently it returns the first address. + + Zebra daemon "show int" is able to keep the primary address as + first address. + +T33 DONE Implement debug command: test pim receive upcall + See also TODO T6: (S,G) Assert state machine. + +T34 DONE assert_action_a1 + +T35 DONE Review macros depending on interface I. + + See also: grep ,I\) pimd/*.c + + For the case (S,G,I) check if I is either + 1) interface attached to this per-interface S,G state (don't think so) + or + 2) an arbitrary interface (most probably) + + For the arbitrary interface case (2), consider representing + interface ifp as its primary address (struct in_addr ifaddr). The + benefit is in_addr does not need to be dereferenced, so it does + not demand protection against crashes. + +T36 DONE React to zebra daemon link-detect up/down notification. + pim_ifp->primary_address is managed by detect_primary_address_change() + depending on to ifp->connected (managed by zebra_interface_address_read()). + +T37 DONE Review list of variables which may affect pim_upstream.c + pim_upstream_evaluate_join_desired(). + Call pim_upstream_update_join_desired() accordingly. + + See the order of invokation: + pim_if_dr_election(ifp); + pim_if_update_join_desired(pim_ifp); /* depends on DR */ + pim_if_update_could_assert(ifp); /* depends on DR */ + pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ + + join_desired depends on: + pim_ifp->primary_address + pim_ifp->pim_dr_addr + ch->ifassert_winner_metric + ch->ifassert_winner + ch->local_ifmembership + ch->ifjoin_state + ch->upstream->rpf.source_nexthop.mrib_metric_preference + ch->upstream->rpf.source_nexthop.mrib_route_metric + ch->upstream->rpf.source_nexthop.interface + +T38 DONE Detect change in AssertTrackingDesired(S,G,I) + + See the order of invokation: + dr_election: none + update_join_desired: depends on DR + update_tracking_desired: depends on DR, join_desired + + AssertTrackingDesired(S,G,I) depends on: + pim_ifp->primary_address + pim_ifp->pim_dr_addr + ch->local_ifmembership + ch->ifassert_winner + ch->ifjoin_state + ch->upstream->rpf.source_nexthop.interface + PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags) + +T39 DONE AssertTrackingDesired: flags is not matching evaluation + + # show ip pim assert-internal + CA: CouldAssert + ECA: Evaluate CouldAssert + ATD: AssertTrackingDesired + eATD: Evaluate AssertTrackingDesired + + Interface Address Source Group CA eCA ATD eATD + eth0 192.168.1.100 1.1.1.1 239.1.1.1 no no no yes + # + +T40 Lightweight MLDv2 + http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt + http://www.ietf.org/html.charters/mboned-charter.html + +-x- diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c new file mode 100644 index 000000000..0ce0e5d0d --- /dev/null +++ b/pimd/pim_assert.c @@ -0,0 +1,803 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "prefix.h" + +#include "pimd.h" +#include "pim_str.h" +#include "pim_tlv.h" +#include "pim_msg.h" +#include "pim_pim.h" +#include "pim_time.h" +#include "pim_iface.h" +#include "pim_hello.h" +#include "pim_macro.h" +#include "pim_assert.h" +#include "pim_ifchannel.h" + +static int assert_action_a3(struct pim_ifchannel *ch); +static void assert_action_a2(struct pim_ifchannel *ch, + struct pim_assert_metric winner_metric); +static void assert_action_a6(struct pim_ifchannel *ch, + struct pim_assert_metric winner_metric); + +void pim_ifassert_winner_set(struct pim_ifchannel *ch, + enum pim_ifassert_state new_state, + struct in_addr winner, + struct pim_assert_metric winner_metric) +{ + int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr); + int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric, + &winner_metric); + + if (ch->ifassert_state != new_state) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_info("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + pim_ifchannel_ifassert_name(ch->ifassert_state), + pim_ifchannel_ifassert_name(new_state), + ch->interface->name); + } + + { + char src_str[100]; + char grp_str[100]; + char winner_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", winner, winner_str, sizeof(winner_str)); + zlog_info("%s: (S,G)=(%s,%s) assert winner now is %s on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + winner_str, ch->interface->name); + } + + ch->ifassert_state = new_state; + ch->ifassert_winner = winner; + ch->ifassert_winner_metric = winner_metric; + ch->ifassert_creation = pim_time_monotonic_sec(); + + if (winner_changed || metric_changed) { + pim_upstream_update_join_desired(ch->upstream); + pim_ifchannel_update_could_assert(ch); + pim_ifchannel_update_assert_tracking_desired(ch); + } +} + +static void on_trace(const char *label, + struct interface *ifp, struct in_addr src) +{ + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src, src_str, sizeof(src_str)); + zlog_debug("%s: from %s on %s", + label, src_str, ifp->name); + } +} + +static int preferred_assert(const struct pim_ifchannel *ch, + const struct pim_assert_metric *recv_metric) +{ + return pim_assert_metric_better(recv_metric, + &ch->ifassert_winner_metric); +} + +static int acceptable_assert(const struct pim_assert_metric *my_metric, + const struct pim_assert_metric *recv_metric) +{ + return pim_assert_metric_better(recv_metric, + my_metric); +} + +static int inferior_assert(const struct pim_assert_metric *my_metric, + const struct pim_assert_metric *recv_metric) +{ + return pim_assert_metric_better(my_metric, + recv_metric); +} + +static int cancel_assert(const struct pim_assert_metric *recv_metric) +{ + return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) + && + (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX); +} + +static void if_could_assert_do_a1(const char *caller, + struct pim_ifchannel *ch) +{ + if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { + if (assert_action_a1(ch)) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s", + __PRETTY_FUNCTION__, caller, + src_str, grp_str, ch->interface->name); + /* log warning only */ + } + } +} + +static int dispatch_assert(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr, + struct pim_assert_metric recv_metric) +{ + struct pim_ifchannel *ch; + + ch = pim_ifchannel_add(ifp, source_addr, group_addr); + if (!ch) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s", + __PRETTY_FUNCTION__, + source_str, group_str, ifp->name); + return -1; + } + + switch (ch->ifassert_state) { + case PIM_IFASSERT_NOINFO: + if (recv_metric.rpt_bit_flag) { + /* RPT bit set */ + if_could_assert_do_a1(__PRETTY_FUNCTION__, ch); + } + else { + /* RPT bit clear */ + if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { + if_could_assert_do_a1(__PRETTY_FUNCTION__, ch); + } + else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) { + if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) { + assert_action_a6(ch, recv_metric); + } + } + } + break; + case PIM_IFASSERT_I_AM_WINNER: + if (preferred_assert(ch, &recv_metric)) { + assert_action_a2(ch, recv_metric); + } + else { + if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ + assert_action_a3(ch); + } + } + break; + case PIM_IFASSERT_I_AM_LOSER: + if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) { + /* Assert from current winner */ + + if (cancel_assert(&recv_metric)) { + assert_action_a5(ch); + } + else { + if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { + assert_action_a5(ch); + } + else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) { + if (!recv_metric.rpt_bit_flag) { + assert_action_a2(ch, recv_metric); + } + } + } + } + else if (preferred_assert(ch, &recv_metric)) { + assert_action_a2(ch, recv_metric); + } + break; + default: + { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s", + __PRETTY_FUNCTION__, + source_str, group_str, ch->ifassert_state, ifp->name); + } + return -2; + } + + return 0; +} + +int pim_assert_recv(struct interface *ifp, + struct pim_neighbor *neigh, + struct in_addr src_addr, + char *buf, int buf_size) +{ + struct prefix msg_group_addr; + struct prefix msg_source_addr; + struct pim_assert_metric msg_metric; + int offset; + char *curr; + int curr_size; + + on_trace(__PRETTY_FUNCTION__, ifp, src_addr); + + curr = buf; + curr_size = buf_size; + + /* + Parse assert group addr + */ + offset = pim_parse_addr_group(ifp->name, src_addr, + &msg_group_addr, + curr, curr_size); + if (offset < 1) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + return -1; + } + curr += offset; + curr_size -= offset; + + /* + Parse assert source addr + */ + offset = pim_parse_addr_ucast(ifp->name, src_addr, + &msg_source_addr, + curr, curr_size); + if (offset < 1) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + return -2; + } + curr += offset; + curr_size -= offset; + + if (curr_size != 8) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s", + __PRETTY_FUNCTION__, + curr_size, + src_str, ifp->name); + return -3; + } + + /* + Parse assert metric preference + */ + + msg_metric.metric_preference = ntohl(*(const uint32_t *) curr); + + msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */ + msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */ + + curr += 4; + + /* + Parse assert route metric + */ + + msg_metric.route_metric = ntohl(*(const uint32_t *) curr); + + if (PIM_DEBUG_PIM_TRACE) { + char neigh_str[100]; + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", src_addr, neigh_str, sizeof(neigh_str)); + pim_inet4_dump("", msg_source_addr.u.prefix4, source_str, sizeof(source_str)); + pim_inet4_dump("", msg_group_addr.u.prefix4, group_str, sizeof(group_str)); + zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", + __PRETTY_FUNCTION__, neigh_str, ifp->name, + source_str, group_str, + msg_metric.metric_preference, + msg_metric.route_metric, + PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag)); + } + + msg_metric.ip_address = src_addr; + + return dispatch_assert(ifp, + msg_source_addr.u.prefix4, + msg_group_addr.u.prefix4, + msg_metric); +} + +/* + RFC 4601: 4.6.3. Assert Metrics + + Assert metrics are defined as: + + When comparing assert_metrics, the rpt_bit_flag, metric_preference, + and route_metric field are compared in order, where the first lower + value wins. If all fields are equal, the primary IP address of the + router that sourced the Assert message is used as a tie-breaker, + with the highest IP address winning. +*/ +int pim_assert_metric_better(const struct pim_assert_metric *m1, + const struct pim_assert_metric *m2) +{ + if (m1->rpt_bit_flag < m2->rpt_bit_flag) + return 1; + if (m1->rpt_bit_flag > m2->rpt_bit_flag) + return 0; + + if (m1->metric_preference < m2->metric_preference) + return 1; + if (m1->metric_preference > m2->metric_preference) + return 0; + + if (m1->route_metric < m2->route_metric) + return 1; + if (m1->route_metric > m2->route_metric) + return 0; + + return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr); +} + +int pim_assert_metric_match(const struct pim_assert_metric *m1, + const struct pim_assert_metric *m2) +{ + if (m1->rpt_bit_flag != m2->rpt_bit_flag) + return 0; + if (m1->metric_preference != m2->metric_preference) + return 0; + if (m1->route_metric != m2->route_metric) + return 0; + + return m1->ip_address.s_addr == m2->ip_address.s_addr; +} + +int pim_assert_build_msg(char *pim_msg, int buf_size, + struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr, + uint32_t metric_preference, + uint32_t route_metric, + uint32_t rpt_bit_flag) +{ + char *buf_pastend = pim_msg + buf_size; + char *pim_msg_curr; + int pim_msg_size; + int remain; + + pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */ + + /* Encode group */ + remain = buf_pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, + remain, + group_addr); + if (!pim_msg_curr) { + char group_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: failure encoding group address %s: space left=%d", + __PRETTY_FUNCTION__, group_str, remain); + return -1; + } + + /* Encode source */ + remain = buf_pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, + remain, + source_addr); + if (!pim_msg_curr) { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: failure encoding source address %s: space left=%d", + __PRETTY_FUNCTION__, source_str, remain); + return -2; + } + + /* Metric preference */ + *((uint32_t *) pim_msg_curr) = htonl(rpt_bit_flag ? + metric_preference | 0x80000000 : + metric_preference); + pim_msg_curr += 4; + + /* Route metric */ + *((uint32_t *) pim_msg_curr) = htonl(route_metric); + pim_msg_curr += 4; + + /* + Add PIM header + */ + pim_msg_size = pim_msg_curr - pim_msg; + pim_msg_build_header(pim_msg, pim_msg_size, + PIM_MSG_TYPE_ASSERT); + + return pim_msg_size; +} + +static int pim_assert_do(struct pim_ifchannel *ch, + struct pim_assert_metric metric) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + char pim_msg[1000]; + int pim_msg_size; + + ifp = ch->interface; + zassert(ifp); + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: pim not enabled on interface: %s", + __PRETTY_FUNCTION__, ifp->name); + return -1; + } + + pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, + ch->group_addr, ch->source_addr, + metric.metric_preference, + metric.route_metric, + metric.rpt_bit_flag); + if (pim_msg_size < 1) { + zlog_warn("%s: failure building PIM assert message: msg_size=%d", + __PRETTY_FUNCTION__, pim_msg_size); + return -2; + } + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + Thus, if a router needs to send a Join/Prune or Assert message on + an interface on which it has not yet sent a Hello message with the + currently configured IP address, then it MUST immediately send the + relevant Hello message without waiting for the Hello Timer to + expire, followed by the Join/Prune or Assert message. + */ + pim_hello_require(ifp); + + if (PIM_DEBUG_PIM_TRACE) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", + __PRETTY_FUNCTION__, + ifp->name, source_str, group_str, + metric.metric_preference, + metric.route_metric, + PIM_FORCE_BOOLEAN(metric.rpt_bit_flag)); + } + + if (pim_msg_send(pim_ifp->pim_sock_fd, + qpim_all_pim_routers_addr, + pim_msg, + pim_msg_size, + ifp->name)) { + zlog_warn("%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, ifp->name); + return -3; + } + + return 0; +} + +int pim_assert_send(struct pim_ifchannel *ch) +{ + return pim_assert_do(ch, ch->ifassert_my_metric); +} + +/* + RFC 4601: 4.6.4. AssertCancel Messages + + An AssertCancel(S,G) is an infinite metric assert with the RPT bit + set that names S as the source. + */ +static int pim_assert_cancel(struct pim_ifchannel *ch) +{ + struct pim_assert_metric metric; + + metric.rpt_bit_flag = 0; + metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; + metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; + metric.ip_address = ch->source_addr; + + return pim_assert_do(ch, metric); +} + +static int on_assert_timer(struct thread *t) +{ + struct pim_ifchannel *ch; + struct interface *ifp; + + zassert(t); + ch = THREAD_ARG(t); + zassert(ch); + + ifp = ch->interface; + zassert(ifp); + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + } + + ch->t_ifassert_timer = 0; + + switch (ch->ifassert_state) { + case PIM_IFASSERT_I_AM_WINNER: + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ + assert_action_a3(ch); + break; + case PIM_IFASSERT_I_AM_LOSER: + assert_action_a5(ch); + break; + default: + { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s", + __PRETTY_FUNCTION__, + source_str, group_str, ch->ifassert_state, ifp->name); + } + } + + return 0; +} + +static void assert_timer_off(struct pim_ifchannel *ch) +{ + struct interface *ifp; + + zassert(ch); + ifp = ch->interface; + zassert(ifp); + + if (PIM_DEBUG_PIM_TRACE) { + if (ch->t_ifassert_timer) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + } + } + THREAD_OFF(ch->t_ifassert_timer); + zassert(!ch->t_ifassert_timer); +} + +static void pim_assert_timer_set(struct pim_ifchannel *ch, + int interval) +{ + struct interface *ifp; + + zassert(ch); + ifp = ch->interface; + zassert(ifp); + + assert_timer_off(ch); + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, interval, ifp->name); + } + + THREAD_TIMER_ON(master, ch->t_ifassert_timer, + on_assert_timer, + ch, interval); +} + +static void pim_assert_timer_reset(struct pim_ifchannel *ch) +{ + pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL); +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + (S,G) Assert State machine Actions + + A1: Send Assert(S,G). + Set Assert Timer to (Assert_Time - Assert_Override_Interval). + Store self as AssertWinner(S,G,I). + Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I). +*/ +int assert_action_a1(struct pim_ifchannel *ch) +{ + struct interface *ifp = ch->interface; + struct pim_interface *pim_ifp; + + zassert(ifp); + + pim_ifp = ifp->info; + if (!pim_ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s) multicast no enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -1; /* must return since pim_ifp is used below */ + } + + /* Switch to I_AM_WINNER before performing action_a3 below */ + pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER, + pim_ifp->primary_address, + pim_macro_spt_assert_metric(&ch->upstream->rpf, + pim_ifp->primary_address)); + + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ + if (assert_action_a3(ch)) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + /* warning only */ + } + + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); + + return 0; +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + (S,G) Assert State machine Actions + + A2: Store new assert winner as AssertWinner(S,G,I) and assert + winner metric as AssertWinnerMetric(S,G,I). + Set Assert Timer to Assert_Time. +*/ +static void assert_action_a2(struct pim_ifchannel *ch, + struct pim_assert_metric winner_metric) +{ + pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER, + winner_metric.ip_address, + winner_metric); + + pim_assert_timer_set(ch, PIM_ASSERT_TIME); + + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + (S,G) Assert State machine Actions + + A3: Send Assert(S,G). + Set Assert Timer to (Assert_Time - Assert_Override_Interval). +*/ +static int assert_action_a3(struct pim_ifchannel *ch) +{ + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); + + pim_assert_timer_reset(ch); + + if (pim_assert_send(ch)) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + + zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name); + return -1; + } + + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); + + return 0; +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + (S,G) Assert State machine Actions + + A4: Send AssertCancel(S,G). + Delete assert info (AssertWinner(S,G,I) and + AssertWinnerMetric(S,G,I) will then return their default + values). +*/ +void assert_action_a4(struct pim_ifchannel *ch) +{ + if (pim_assert_cancel(ch)) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name); + /* log warning only */ + } + + assert_action_a5(ch); + + zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + (S,G) Assert State machine Actions + + A5: Delete assert info (AssertWinner(S,G,I) and + AssertWinnerMetric(S,G,I) will then return their default values). +*/ +void assert_action_a5(struct pim_ifchannel *ch) +{ + reset_ifassert_state(ch); + zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + (S,G) Assert State machine Actions + + A6: Store new assert winner as AssertWinner(S,G,I) and assert + winner metric as AssertWinnerMetric(S,G,I). + Set Assert Timer to Assert_Time. + If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) + set SPTbit(S,G) to TRUE. +*/ +static void assert_action_a6(struct pim_ifchannel *ch, + struct pim_assert_metric winner_metric) +{ + assert_action_a2(ch, winner_metric); + + /* + If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set + SPTbit(S,G) to TRUE. + + Notice: For PIM SSM, SPTbit(S,G) is already always true. + */ + + zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); +} + diff --git a/pimd/pim_assert.h b/pimd/pim_assert.h new file mode 100644 index 000000000..6a8594ce1 --- /dev/null +++ b/pimd/pim_assert.h @@ -0,0 +1,75 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_ASSERT_H +#define PIM_ASSERT_H + +#include + +#include "if.h" + +#include "pim_neighbor.h" +#include "pim_ifchannel.h" + +/* + RFC 4601: 4.11. Timer Values + + Note that for historical reasons, the Assert message lacks a + Holdtime field. Thus, changing the Assert Time from the default + value is not recommended. + */ +#define PIM_ASSERT_OVERRIDE_INTERVAL (3) /* seconds */ +#define PIM_ASSERT_TIME (180) /* seconds */ + +#define PIM_ASSERT_METRIC_PREFERENCE_MAX (0xFFFFFFFF) +#define PIM_ASSERT_ROUTE_METRIC_MAX (0xFFFFFFFF) + +void pim_ifassert_winner_set(struct pim_ifchannel *ch, + enum pim_ifassert_state new_state, + struct in_addr winner, + struct pim_assert_metric winner_metric); + +int pim_assert_recv(struct interface *ifp, + struct pim_neighbor *neigh, + struct in_addr src_addr, + char *buf, int buf_size); + +int pim_assert_metric_better(const struct pim_assert_metric *m1, + const struct pim_assert_metric *m2); +int pim_assert_metric_match(const struct pim_assert_metric *m1, + const struct pim_assert_metric *m2); + +int pim_assert_build_msg(char *pim_msg, int buf_size, + struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr, + uint32_t metric_preference, + uint32_t route_metric, + uint32_t rpt_bit_flag); + +int pim_assert_send(struct pim_ifchannel *ch); + +int assert_action_a1(struct pim_ifchannel *ch); +void assert_action_a4(struct pim_ifchannel *ch); +void assert_action_a5(struct pim_ifchannel *ch); + +#endif /* PIM_ASSERT_H */ diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c new file mode 100644 index 000000000..b1349ed3b --- /dev/null +++ b/pimd/pim_cmd.c @@ -0,0 +1,3923 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include + +#include "command.h" +#include "if.h" +#include "prefix.h" + +#include "pimd.h" +#include "pim_cmd.h" +#include "pim_iface.h" +#include "pim_vty.h" +#include "pim_mroute.h" +#include "pim_str.h" +#include "pim_igmpv3.h" +#include "pim_sock.h" +#include "pim_time.h" +#include "pim_util.h" +#include "pim_oil.h" +#include "pim_neighbor.h" +#include "pim_pim.h" +#include "pim_ifchannel.h" +#include "pim_hello.h" +#include "pim_msg.h" +#include "pim_upstream.h" +#include "pim_rpf.h" +#include "pim_macro.h" + +static struct cmd_node pim_global_node = { + PIM_NODE, + "", + 1 /* vtysh ? yes */ +}; + +static struct cmd_node pim_interface_node = { + INTERFACE_NODE, + "%s(config-if-pim)# ", + 1 /* vtysh ? yes */ +}; + +static void pim_if_membership_clear(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (PIM_IF_TEST_PIM(pim_ifp->options) && + PIM_IF_TEST_IGMP(pim_ifp->options)) { + return; + } + + pim_ifchannel_membership_clear(ifp); +} + +/* + When PIM is disabled on interface, IGMPv3 local membership + information is not injected into PIM interface state. + + The function pim_if_membership_refresh() fetches all IGMPv3 local + membership information into PIM. It is intented to be called + whenever PIM is enabled on the interface in order to collect missed + local membership information. + */ +static void pim_if_membership_refresh(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + return; + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) + return; + + /* + First clear off membership from all PIM (S,G) entries on the + interface + */ + + pim_ifchannel_membership_clear(ifp); + + /* + Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on + the interface + */ + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + struct listnode *grpnode; + struct igmp_group *grp; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { + struct listnode *srcnode; + struct igmp_source *src; + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { + + if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) { + pim_ifchannel_local_membership_add(ifp, + src->source_addr, + grp->group_addr); + } + + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + + /* + Finally delete every PIM (S,G) entry lacking all state info + */ + + pim_ifchannel_delete_on_noinfo(ifp); + +} + +static void pim_show_assert(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, + "Interface Address Source Group State Winner Uptime Timer%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + char ch_src_str[100]; + char ch_grp_str[100]; + char winner_str[100]; + char uptime[10]; + char timer[10]; + + pim_inet4_dump("", ch->source_addr, + ch_src_str, sizeof(ch_src_str)); + pim_inet4_dump("", ch->group_addr, + ch_grp_str, sizeof(ch_grp_str)); + pim_inet4_dump("", ch->ifassert_winner, + winner_str, sizeof(winner_str)); + + pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation); + pim_time_timer_to_mmss(timer, sizeof(timer), + ch->t_ifassert_timer); + + vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s%s", + ifp->name, + inet_ntoa(ifaddr), + ch_src_str, + ch_grp_str, + pim_ifchannel_ifassert_name(ch->ifassert_state), + winner_str, + uptime, + timer, + VTY_NEWLINE); + } /* scan interface channels */ + } /* scan interfaces */ +} + +static void pim_show_assert_internal(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + + vty_out(vty, + "CA: CouldAssert%s" + "ECA: Evaluate CouldAssert%s" + "ATD: AssertTrackingDesired%s" + "eATD: Evaluate AssertTrackingDesired%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, + "Interface Address Source Group CA eCA ATD eATD%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + char ch_src_str[100]; + char ch_grp_str[100]; + + pim_inet4_dump("", ch->source_addr, + ch_src_str, sizeof(ch_src_str)); + pim_inet4_dump("", ch->group_addr, + ch_grp_str, sizeof(ch_grp_str)); + vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s%s", + ifp->name, + inet_ntoa(ifaddr), + ch_src_str, + ch_grp_str, + PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", + pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", + PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes" : "no", + pim_macro_assert_tracking_desired_eval(ch) ? "yes" : "no", + VTY_NEWLINE); + } /* scan interface channels */ + } /* scan interfaces */ +} + +static void pim_show_assert_metric(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + + vty_out(vty, + "Interface Address Source Group RPT Pref Metric Address %s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + char ch_src_str[100]; + char ch_grp_str[100]; + char addr_str[100]; + struct pim_assert_metric am; + + am = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); + + pim_inet4_dump("", ch->source_addr, + ch_src_str, sizeof(ch_src_str)); + pim_inet4_dump("", ch->group_addr, + ch_grp_str, sizeof(ch_grp_str)); + pim_inet4_dump("", am.ip_address, + addr_str, sizeof(addr_str)); + + vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s%s", + ifp->name, + inet_ntoa(ifaddr), + ch_src_str, + ch_grp_str, + am.rpt_bit_flag ? "yes" : "no", + am.metric_preference, + am.route_metric, + addr_str, + VTY_NEWLINE); + } /* scan interface channels */ + } /* scan interfaces */ +} + +static void pim_show_assert_winner_metric(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + + vty_out(vty, + "Interface Address Source Group RPT Pref Metric Address %s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + char ch_src_str[100]; + char ch_grp_str[100]; + char addr_str[100]; + struct pim_assert_metric *am; + char pref_str[5]; + char metr_str[7]; + + am = &ch->ifassert_winner_metric; + + pim_inet4_dump("", ch->source_addr, + ch_src_str, sizeof(ch_src_str)); + pim_inet4_dump("", ch->group_addr, + ch_grp_str, sizeof(ch_grp_str)); + pim_inet4_dump("", am->ip_address, + addr_str, sizeof(addr_str)); + + if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) + snprintf(pref_str, sizeof(pref_str), "INFI"); + else + snprintf(pref_str, sizeof(pref_str), "%4u", am->metric_preference); + + if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX) + snprintf(metr_str, sizeof(metr_str), "INFI"); + else + snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric); + + vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s%s", + ifp->name, + inet_ntoa(ifaddr), + ch_src_str, + ch_grp_str, + am->rpt_bit_flag ? "yes" : "no", + pref_str, + metr_str, + addr_str, + VTY_NEWLINE); + } /* scan interface channels */ + } /* scan interfaces */ +} + +static void pim_show_membership(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + + vty_out(vty, + "Interface Address Source Group Membership%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + char ch_src_str[100]; + char ch_grp_str[100]; + + pim_inet4_dump("", ch->source_addr, + ch_src_str, sizeof(ch_src_str)); + pim_inet4_dump("", ch->group_addr, + ch_grp_str, sizeof(ch_grp_str)); + + vty_out(vty, "%-9s %-15s %-15s %-15s %-10s%s", + ifp->name, + inet_ntoa(ifaddr), + ch_src_str, + ch_grp_str, + ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO ? + "NOINFO" : "INCLUDE", + VTY_NEWLINE); + } /* scan interface channels */ + } /* scan interfaces */ + +} + +static void igmp_show_interfaces(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, + "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char uptime[10]; + int mloop; + + pim_time_uptime(uptime, sizeof(uptime), now - igmp->sock_creation); + + mloop = pim_socket_mcastloop_get(igmp->fd); + + vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s", + ifp->name, + inet_ntoa(igmp->ifaddr), + ifp->ifindex, + igmp->fd, + uptime, + if_is_multicast(ifp) ? "yes" : "no", + if_is_broadcast(ifp) ? "yes" : "no", + (mloop < 0) ? "?" : (mloop ? "yes" : "no"), + (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", + (ifp->flags & IFF_PROMISC) ? "yes" : "no", + PIM_IF_IS_DELETED(ifp) ? "yes" : "no", + VTY_NEWLINE); + } + } +} + +static void show_interface_address(struct vty *vty) +{ + struct listnode *ifpnode; + struct interface *ifp; + + vty_out(vty, + "Interface Primary Secondary %s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifpnode, ifp)) { + struct listnode *ifcnode; + struct connected *ifc; + struct in_addr pri_addr; + char pri_addr_str[100]; + + pri_addr = pim_find_primary_addr(ifp); + + pim_inet4_dump("", pri_addr, pri_addr_str, sizeof(pri_addr_str)); + + for (ALL_LIST_ELEMENTS_RO(ifp->connected, ifcnode, ifc)) { + char sec_addr_str[100]; + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + if (p->u.prefix4.s_addr == pri_addr.s_addr) { + sec_addr_str[0] = '\0'; + } + else { + pim_inet4_dump("", p->u.prefix4, sec_addr_str, sizeof(sec_addr_str)); + } + + vty_out(vty, "%-9s %-15s %-15s%s", + ifp->name, + pri_addr_str, + sec_addr_str, + VTY_NEWLINE); + } + } +} + +static void pim_show_dr(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, + "NonPri: Number of neighbors missing DR Priority hello option%s%s", + VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, "Interface Address DR Uptime Elections NonPri%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + char dr_str[100]; + char dr_uptime[10]; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + pim_time_uptime(dr_uptime, sizeof(dr_uptime), + now - pim_ifp->pim_dr_election_last); + + pim_inet4_dump("", pim_ifp->pim_dr_addr, + dr_str, sizeof(dr_str)); + + vty_out(vty, "%-9s %-15s %-15s %8s %9d %6d%s", + ifp->name, + inet_ntoa(ifaddr), + dr_str, + dr_uptime, + pim_ifp->pim_dr_election_count, + pim_ifp->pim_dr_num_nondrpri_neighbors, + VTY_NEWLINE); + } +} + +static void pim_show_hello(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address Period Timer StatStart Recv Rfail Send Sfail%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + char hello_period[10]; + char hello_timer[10]; + char stat_uptime[10]; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + pim_time_timer_to_mmss(hello_timer, sizeof(hello_timer), pim_ifp->t_pim_hello_timer); + pim_time_mmss(hello_period, sizeof(hello_period), pim_ifp->pim_hello_period); + pim_time_uptime(stat_uptime, sizeof(stat_uptime), now - pim_ifp->pim_ifstat_start); + + vty_out(vty, "%-9s %-15s %6s %5s %9s %4u %5u %4u %5u%s", + ifp->name, + inet_ntoa(ifaddr), + hello_period, + hello_timer, + stat_uptime, + pim_ifp->pim_ifstat_hello_recv, + pim_ifp->pim_ifstat_hello_recvfail, + pim_ifp->pim_ifstat_hello_sent, + pim_ifp->pim_ifstat_hello_sendfail, + VTY_NEWLINE); + } +} + +static void pim_show_interfaces(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + char uptime[10]; + int mloop; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + pim_time_uptime(uptime, sizeof(uptime), now - pim_ifp->pim_sock_creation); + + mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); + + vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s", + ifp->name, + inet_ntoa(ifaddr), + ifp->ifindex, + pim_ifp->pim_sock_fd, + uptime, + if_is_multicast(ifp) ? "yes" : "no", + if_is_broadcast(ifp) ? "yes" : "no", + (mloop < 0) ? "?" : (mloop ? "yes" : "no"), + (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", + (ifp->flags & IFF_PROMISC) ? "yes" : "no", + PIM_IF_IS_DELETED(ifp) ? "yes" : "no", + VTY_NEWLINE); + } +} + +static void pim_show_join(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, + "Interface Address Source Group State Uptime Expire Prune%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + char ch_src_str[100]; + char ch_grp_str[100]; + char uptime[10]; + char expire[10]; + char prune[10]; + + pim_inet4_dump("", ch->source_addr, + ch_src_str, sizeof(ch_src_str)); + pim_inet4_dump("", ch->group_addr, + ch_grp_str, sizeof(ch_grp_str)); + + pim_time_uptime(uptime, sizeof(uptime), now - ch->ifjoin_creation); + pim_time_timer_to_mmss(expire, sizeof(expire), + ch->t_ifjoin_expiry_timer); + pim_time_timer_to_mmss(prune, sizeof(prune), + ch->t_ifjoin_prune_pending_timer); + + vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s%s", + ifp->name, + inet_ntoa(ifaddr), + ch_src_str, + ch_grp_str, + pim_ifchannel_ifjoin_name(ch->ifjoin_state), + uptime, + expire, + prune, + VTY_NEWLINE); + } /* scan interface channels */ + } /* scan interfaces */ + +} + +static void pim_show_neighbors(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, + "Recv flags: H=holdtime L=lan_prune_delay P=dr_priority G=generation_id A=address_list%s" + " T=can_disable_join_suppression%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, "Interface Address Neighbor Uptime Timer Holdt DrPri GenId Recv %s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *neighnode; + struct pim_neighbor *neigh; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { + char uptime[10]; + char holdtime[10]; + char expire[10]; + char neigh_src_str[100]; + char recv[7]; + + pim_inet4_dump("", neigh->source_addr, + neigh_src_str, sizeof(neigh_src_str)); + pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation); + pim_time_mmss(holdtime, sizeof(holdtime), neigh->holdtime); + pim_time_timer_to_mmss(expire, sizeof(expire), neigh->t_expire_timer); + + recv[0] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_HOLDTIME) ? 'H' : ' '; + recv[1] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? 'L' : ' '; + recv[2] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) ? 'P' : ' '; + recv[3] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ? 'G' : ' '; + recv[4] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_ADDRESS_LIST) ? 'A' : ' '; + recv[5] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION) ? 'T' : ' '; + recv[6] = '\0'; + + vty_out(vty, "%-9s %-15s %-15s %8s %5s %5s %5u %08x %6s%s", + ifp->name, + inet_ntoa(ifaddr), + neigh_src_str, + uptime, + expire, + holdtime, + neigh->dr_priority, + neigh->generation_id, + recv, + VTY_NEWLINE); + } + + + } +} + +static void pim_show_lan_prune_delay(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + + vty_out(vty, + "PrDly=propagation_delay (msec) OvInt=override_interval (msec)%s" + "HiDly=highest_propagation_delay (msec) HiInt=highest_override_interval (msec)%s" + "NoDly=number_of_non_lan_delay_neighbors%s" + "T=t_bit LPD=lan_prune_delay_hello_option%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, "Interface Address PrDly OvInt NoDly HiDly HiInt T Neighbor LPD PrDly OvInt T%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *neighnode; + struct pim_neighbor *neigh; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { + char neigh_src_str[100]; + + pim_inet4_dump("", neigh->source_addr, + neigh_src_str, sizeof(neigh_src_str)); + + vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u %-15s %s %5u %5u %1u%s", + ifp->name, + inet_ntoa(ifaddr), + pim_ifp->pim_propagation_delay_msec, + pim_ifp->pim_override_interval_msec, + pim_ifp->pim_number_of_nonlandelay_neighbors, + pim_ifp->pim_neighbors_highest_propagation_delay_msec, + pim_ifp->pim_neighbors_highest_override_interval_msec, + PIM_FORCE_BOOLEAN(PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)), + neigh_src_str, + PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? "yes" : "no", + neigh->propagation_delay_msec, + neigh->override_interval_msec, + PIM_FORCE_BOOLEAN(PIM_OPTION_IS_SET(neigh->hello_options, + PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)), + VTY_NEWLINE); + } + + } +} + +static void pim_show_jp_override_interval(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + + vty_out(vty, + "EffPDelay=effective_propagation_delay (msec)%s" + "EffOvrInt=override_interval (msec)%s" + "JPOvrInt=jp_override_interval (msec)%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, "Interface Address LAN_Delay EffPDelay EffOvrInt JPOvrInt%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + vty_out(vty, "%-9s %-15s %-9s %9u %9u %8u%s", + ifp->name, + inet_ntoa(ifaddr), + pim_if_lan_delay_enabled(ifp) ? "enabled" : "disabled", + pim_if_effective_propagation_delay_msec(ifp), + pim_if_effective_override_interval_msec(ifp), + pim_if_jp_override_interval_msec(ifp), + VTY_NEWLINE); + } +} + +static void pim_show_neighbors_secondary(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + + vty_out(vty, "Interface Address Neighbor Secondary %s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct listnode *neighnode; + struct pim_neighbor *neigh; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (pim_ifp->pim_sock_fd < 0) + continue; + + ifaddr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { + char neigh_src_str[100]; + struct listnode *prefix_node; + struct prefix *p; + + if (!neigh->prefix_list) + continue; + + pim_inet4_dump("", neigh->source_addr, + neigh_src_str, sizeof(neigh_src_str)); + + for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) { + char neigh_sec_str[100]; + + if (p->family != AF_INET) + continue; + + pim_inet4_dump("", p->u.prefix4, + neigh_sec_str, sizeof(neigh_sec_str)); + + vty_out(vty, "%-9s %-15s %-15s %-15s%s", + ifp->name, + inet_ntoa(ifaddr), + neigh_src_str, + neigh_sec_str, + VTY_NEWLINE); + } + } + } +} + +static void pim_show_upstream(struct vty *vty) +{ + struct listnode *upnode; + struct pim_upstream *up; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Source Group State Uptime JoinTimer RefCnt%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) { + char src_str[100]; + char grp_str[100]; + char uptime[10]; + char join_timer[10]; + + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition); + pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), up->t_join_timer); + + vty_out(vty, "%-15s %-15s %-5s %-8s %-9s %6d%s", + src_str, + grp_str, + up->join_state == PIM_UPSTREAM_JOINED ? "Jnd" : "NtJnd", + uptime, + join_timer, + up->ref_count, + VTY_NEWLINE); + } +} + +static void pim_show_join_desired(struct vty *vty) +{ + struct listnode *ifnode; + struct listnode *chnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + struct in_addr me_ifaddr; + char src_str[100]; + char grp_str[100]; + + vty_out(vty, + "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD%s", + VTY_NEWLINE); + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + me_ifaddr = pim_ifp->primary_address; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, chnode, ch)) { + struct pim_upstream *up = ch->upstream; + + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + + vty_out(vty, "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s%s", + ifp->name, + src_str, + grp_str, + pim_macro_ch_lost_assert(ch) ? "yes" : "no", + pim_macro_chisin_joins(ch) ? "yes" : "no", + pim_macro_chisin_pim_include(ch) ? "yes" : "no", + PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags) ? "yes" : "no", + pim_upstream_evaluate_join_desired(up) ? "yes" : "no", + VTY_NEWLINE); + } + } +} + +static void pim_show_upstream_rpf(struct vty *vty) +{ + struct listnode *upnode; + struct pim_upstream *up; + + vty_out(vty, + "Source Group RpfIface RibNextHop RpfAddress %s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) { + char src_str[100]; + char grp_str[100]; + char rpf_nexthop_str[100]; + char rpf_addr_str[100]; + struct pim_rpf *rpf; + const char *rpf_ifname; + + rpf = &up->rpf; + + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, rpf_nexthop_str, sizeof(rpf_nexthop_str)); + pim_inet4_dump("", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); + + rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; + + vty_out(vty, "%-15s %-15s %-8s %-15s %-15s%s", + src_str, + grp_str, + rpf_ifname, + rpf_nexthop_str, + rpf_addr_str, + VTY_NEWLINE); + } +} + +static void pim_show_rpf(struct vty *vty) +{ + struct listnode *up_node; + struct pim_upstream *up; + + vty_out(vty, + "Source Group RpfIface RpfAddress RibNextHop Metric Pref%s", + VTY_NEWLINE); + + + for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { + char src_str[100]; + char grp_str[100]; + char rpf_addr_str[100]; + char rib_nexthop_str[100]; + const char *rpf_ifname; + struct pim_rpf *rpf = &up->rpf; + + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); + pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, rib_nexthop_str, sizeof(rib_nexthop_str)); + + rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; + + vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d%s", + src_str, + grp_str, + rpf_ifname, + rpf_addr_str, + rib_nexthop_str, + rpf->source_nexthop.mrib_route_metric, + rpf->source_nexthop.mrib_metric_preference, + VTY_NEWLINE); + } +} + +static void igmp_show_querier(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address Querier StartCount Query-Timer Other-Timer%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char query_hhmmss[10]; + char other_hhmmss[10]; + + pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer); + pim_time_timer_to_hhmmss(other_hhmmss, sizeof(other_hhmmss), igmp->t_other_querier_timer); + + vty_out(vty, "%-9s %-15s %7s %10d %11s %11s%s", + ifp->name, + inet_ntoa(igmp->ifaddr), + igmp->t_igmp_query_timer ? "THIS" : "OTHER", + igmp->startup_query_count, + query_hhmmss, + other_hhmmss, + VTY_NEWLINE); + } + } +} + +static void igmp_show_groups(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address Group Mode Timer Srcs V Uptime %s", VTY_NEWLINE); + + /* scan interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char ifaddr_str[100]; + struct listnode *grpnode; + struct igmp_group *grp; + + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { + char group_str[100]; + char hhmmss[10]; + char uptime[10]; + + pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); + pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss), grp->t_group_timer); + pim_time_uptime(uptime, sizeof(uptime), now - grp->group_creation); + + vty_out(vty, "%-9s %-15s %-15s %4s %8s %4d %d %8s%s", + ifp->name, + ifaddr_str, + group_str, + grp->group_filtermode_isexcl ? "EXCL" : "INCL", + hhmmss, + grp->group_source_list ? listcount(grp->group_source_list) : 0, + igmp_group_compat_mode(igmp, grp), + uptime, + VTY_NEWLINE); + + } /* scan igmp groups */ + } /* scan igmp sockets */ + } /* scan interfaces */ +} + +static void igmp_show_group_retransmission(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address Group RetTimer Counter RetSrcs%s", VTY_NEWLINE); + + /* scan interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char ifaddr_str[100]; + struct listnode *grpnode; + struct igmp_group *grp; + + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { + char group_str[100]; + char grp_retr_mmss[10]; + struct listnode *src_node; + struct igmp_source *src; + int grp_retr_sources = 0; + + pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); + pim_time_timer_to_mmss(grp_retr_mmss, sizeof(grp_retr_mmss), grp->t_group_query_retransmit_timer); + + + /* count group sources with retransmission state */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node, src)) { + if (src->source_query_retransmit_count > 0) { + ++grp_retr_sources; + } + } + + vty_out(vty, "%-9s %-15s %-15s %-8s %7d %7d%s", + ifp->name, + ifaddr_str, + group_str, + grp_retr_mmss, + grp->group_specific_query_retransmit_count, + grp_retr_sources, + VTY_NEWLINE); + + } /* scan igmp groups */ + } /* scan igmp sockets */ + } /* scan interfaces */ +} + +static void igmp_show_parameters(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + + vty_out(vty, + "QRV: Robustness Variable SQI: Startup Query Interval%s" + "QQI: Query Interval OQPI: Other Querier Present Interval%s" + "QRI: Query Response Interval LMQT: Last Member Query Time%s" + "GMI: Group Membership Interval OHPI: Older Host Present Interval%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, + "Interface Address QRV QQI QRI GMI SQI OQPI LMQT OHPI %s", + VTY_NEWLINE); + + /* scan interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char ifaddr_str[100]; + long gmi_dsec; /* Group Membership Interval */ + long oqpi_dsec; /* Other Querier Present Interval */ + int sqi; + long lmqt_dsec; + long ohpi_dsec; + long qri_dsec; + + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + gmi_dsec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec) / 100; + + sqi = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval); + + oqpi_dsec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec) / 100; + + lmqt_dsec = PIM_IGMP_LMQT_MSEC(pim_ifp->igmp_query_max_response_time_dsec, + igmp->querier_robustness_variable) / 100; + + ohpi_dsec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec); + + qri_dsec = pim_ifp->igmp_query_max_response_time_dsec; + + vty_out(vty, + "%-9s %-15s %3d %3d %3ld.%ld %3ld.%ld %3d %3ld.%ld %3ld.%ld %3ld.%ld%s", + ifp->name, + ifaddr_str, + igmp->querier_robustness_variable, + igmp->querier_query_interval, + qri_dsec / 10, qri_dsec % 10, + gmi_dsec / 10, gmi_dsec % 10, + sqi, + oqpi_dsec / 10, oqpi_dsec % 10, + lmqt_dsec / 10, lmqt_dsec % 10, + ohpi_dsec / 10, ohpi_dsec % 10, + VTY_NEWLINE); + + } /* scan igmp sockets */ + } /* scan interfaces */ +} + +static void igmp_show_sources(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address Group Source Timer Fwd Uptime %s", VTY_NEWLINE); + + /* scan interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char ifaddr_str[100]; + struct listnode *grpnode; + struct igmp_group *grp; + + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { + char group_str[100]; + struct listnode *srcnode; + struct igmp_source *src; + + pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { + char source_str[100]; + char mmss[10]; + char uptime[10]; + + pim_inet4_dump("", src->source_addr, source_str, sizeof(source_str)); + + pim_time_timer_to_mmss(mmss, sizeof(mmss), src->t_source_timer); + + pim_time_uptime(uptime, sizeof(uptime), now - src->source_creation); + + vty_out(vty, "%-9s %-15s %-15s %-15s %5s %3s %8s%s", + ifp->name, + ifaddr_str, + group_str, + source_str, + mmss, + IGMP_SOURCE_TEST_FORWARDING(src->source_flags) ? "Y" : "N", + uptime, + VTY_NEWLINE); + + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + } /* scan interfaces */ +} + +static void igmp_show_source_retransmission(struct vty *vty) +{ + struct listnode *ifnode; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, "Interface Address Group Source Counter%s", VTY_NEWLINE); + + /* scan interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + char ifaddr_str[100]; + struct listnode *grpnode; + struct igmp_group *grp; + + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { + char group_str[100]; + struct listnode *srcnode; + struct igmp_source *src; + + pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { + char source_str[100]; + + pim_inet4_dump("", src->source_addr, source_str, sizeof(source_str)); + + vty_out(vty, "%-9s %-15s %-15s %-15s %7d%s", + ifp->name, + ifaddr_str, + group_str, + source_str, + src->source_query_retransmit_count, + VTY_NEWLINE); + + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + } /* scan interfaces */ +} + +static void clear_igmp_interfaces() +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_if_addr_del_all_igmp(ifp); + } + + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_if_addr_add_all(ifp); + } +} + +static void clear_pim_interfaces() +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + if (ifp->info) { + pim_neighbor_delete_all(ifp, "interface cleared"); + } + } +} + +static void clear_interfaces() +{ + clear_igmp_interfaces(); + clear_pim_interfaces(); +} + +DEFUN (pim_interface, + pim_interface_cmd, + "interface IFNAME", + "Select an interface to configure\n" + "Interface's name\n") +{ + struct interface *ifp; + const char *ifname = argv[0]; + size_t sl; + + sl = strlen(ifname); + if (sl > INTERFACE_NAMSIZ) { + vty_out(vty, "%% Interface name %s is invalid: length exceeds " + "%d characters%s", + ifname, INTERFACE_NAMSIZ, VTY_NEWLINE); + return CMD_WARNING; + } + + ifp = if_lookup_by_name_len(ifname, sl); + if (!ifp) { + vty_out(vty, "%% Interface %s does not exist%s", ifname, VTY_NEWLINE); + + /* Returning here would prevent pimd from booting when there are + interface commands in pimd.conf, since all interfaces are + unknown at pimd boot time (the zebra daemon has not been + contacted for interface discovery). */ + + ifp = if_get_by_name_len(ifname, sl); + if (!ifp) { + vty_out(vty, "%% Could not create interface %s%s", ifname, VTY_NEWLINE); + return CMD_WARNING; + } + } + + vty->index = ifp; + vty->node = INTERFACE_NODE; + + return CMD_SUCCESS; +} + +DEFUN (clear_ip_interfaces, + clear_ip_interfaces_cmd, + "clear ip interfaces", + CLEAR_STR + IP_STR + "Reset interfaces\n") +{ + clear_interfaces(); + + return CMD_SUCCESS; +} + +DEFUN (clear_ip_igmp_interfaces, + clear_ip_igmp_interfaces_cmd, + "clear ip igmp interfaces", + CLEAR_STR + IP_STR + CLEAR_IP_IGMP_STR + "Reset IGMP interfaces\n") +{ + clear_igmp_interfaces(); + + return CMD_SUCCESS; +} + +DEFUN (clear_ip_pim_interfaces, + clear_ip_pim_interfaces_cmd, + "clear ip pim interfaces", + CLEAR_STR + IP_STR + CLEAR_IP_PIM_STR + "Reset PIM interfaces\n") +{ + clear_pim_interfaces(); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_interface, + show_ip_igmp_interface_cmd, + "show ip igmp interface", + SHOW_STR + IP_STR + IGMP_STR + "IGMP interface information\n") +{ + igmp_show_interfaces(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_groups, + show_ip_igmp_groups_cmd, + "show ip igmp groups", + SHOW_STR + IP_STR + IGMP_STR + IGMP_GROUP_STR) +{ + igmp_show_groups(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_groups_retransmissions, + show_ip_igmp_groups_retransmissions_cmd, + "show ip igmp groups retransmissions", + SHOW_STR + IP_STR + IGMP_STR + IGMP_GROUP_STR + "IGMP group retransmissions\n") +{ + igmp_show_group_retransmission(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_parameters, + show_ip_igmp_parameters_cmd, + "show ip igmp parameters", + SHOW_STR + IP_STR + IGMP_STR + "IGMP parameters information\n") +{ + igmp_show_parameters(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_sources, + show_ip_igmp_sources_cmd, + "show ip igmp sources", + SHOW_STR + IP_STR + IGMP_STR + IGMP_SOURCE_STR) +{ + igmp_show_sources(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_sources_retransmissions, + show_ip_igmp_sources_retransmissions_cmd, + "show ip igmp sources retransmissions", + SHOW_STR + IP_STR + IGMP_STR + IGMP_SOURCE_STR + "IGMP source retransmissions\n") +{ + igmp_show_source_retransmission(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_querier, + show_ip_igmp_querier_cmd, + "show ip igmp querier", + SHOW_STR + IP_STR + IGMP_STR + "IGMP querier information\n") +{ + igmp_show_querier(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_address, + show_ip_pim_address_cmd, + "show ip pim address", + SHOW_STR + IP_STR + PIM_STR + "PIM interface address\n") +{ + show_interface_address(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_assert, + show_ip_pim_assert_cmd, + "show ip pim assert", + SHOW_STR + IP_STR + PIM_STR + "PIM interface assert\n") +{ + pim_show_assert(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_assert_internal, + show_ip_pim_assert_internal_cmd, + "show ip pim assert-internal", + SHOW_STR + IP_STR + PIM_STR + "PIM interface internal assert state\n") +{ + pim_show_assert_internal(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_assert_metric, + show_ip_pim_assert_metric_cmd, + "show ip pim assert-metric", + SHOW_STR + IP_STR + PIM_STR + "PIM interface assert metric\n") +{ + pim_show_assert_metric(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_assert_winner_metric, + show_ip_pim_assert_winner_metric_cmd, + "show ip pim assert-winner-metric", + SHOW_STR + IP_STR + PIM_STR + "PIM interface assert winner metric\n") +{ + pim_show_assert_winner_metric(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_dr, + show_ip_pim_dr_cmd, + "show ip pim designated-router", + SHOW_STR + IP_STR + PIM_STR + "PIM interface designated router\n") +{ + pim_show_dr(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_hello, + show_ip_pim_hello_cmd, + "show ip pim hello", + SHOW_STR + IP_STR + PIM_STR + "PIM interface hello information\n") +{ + pim_show_hello(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_interface, + show_ip_pim_interface_cmd, + "show ip pim interface", + SHOW_STR + IP_STR + PIM_STR + "PIM interface information\n") +{ + pim_show_interfaces(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_join, + show_ip_pim_join_cmd, + "show ip pim join", + SHOW_STR + IP_STR + PIM_STR + "PIM interface join information\n") +{ + pim_show_join(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_lan_prune_delay, + show_ip_pim_lan_prune_delay_cmd, + "show ip pim lan-prune-delay", + SHOW_STR + IP_STR + PIM_STR + "PIM neighbors LAN prune delay parameters\n") +{ + pim_show_lan_prune_delay(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_local_membership, + show_ip_pim_local_membership_cmd, + "show ip pim local-membership", + SHOW_STR + IP_STR + PIM_STR + "PIM interface local-membership\n") +{ + pim_show_membership(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_jp_override_interval, + show_ip_pim_jp_override_interval_cmd, + "show ip pim jp-override-interval", + SHOW_STR + IP_STR + PIM_STR + "PIM interface J/P override interval\n") +{ + pim_show_jp_override_interval(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_neighbor, + show_ip_pim_neighbor_cmd, + "show ip pim neighbor", + SHOW_STR + IP_STR + PIM_STR + "PIM neighbor information\n") +{ + pim_show_neighbors(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_secondary, + show_ip_pim_secondary_cmd, + "show ip pim secondary", + SHOW_STR + IP_STR + PIM_STR + "PIM neighbor addresses\n") +{ + pim_show_neighbors_secondary(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_upstream, + show_ip_pim_upstream_cmd, + "show ip pim upstream", + SHOW_STR + IP_STR + PIM_STR + "PIM upstream information\n") +{ + pim_show_upstream(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_upstream_join_desired, + show_ip_pim_upstream_join_desired_cmd, + "show ip pim upstream-join-desired", + SHOW_STR + IP_STR + PIM_STR + "PIM upstream join-desired\n") +{ + pim_show_join_desired(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_upstream_rpf, + show_ip_pim_upstream_rpf_cmd, + "show ip pim upstream-rpf", + SHOW_STR + IP_STR + PIM_STR + "PIM upstream source rpf\n") +{ + pim_show_upstream_rpf(vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_rpf, + show_ip_pim_rpf_cmd, + "show ip pim rpf", + SHOW_STR + IP_STR + PIM_STR + "PIM cached source rpf information\n") +{ + pim_show_rpf(vty); + + return CMD_SUCCESS; +} + +static void show_multicast_interfaces(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + + vty_out(vty, "%s", VTY_NEWLINE); + + vty_out(vty, "Interface Address ifIndex VifIndex PktsIn PktsOut BytesIn BytesOut%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct sioc_vif_req vreq; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + memset(&vreq, 0, sizeof(vreq)); + vreq.vifi = pim_ifp->mroute_vif_index; + + if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) { + int e = errno; + vty_out(vty, + "ioctl(SIOCGETVIFCNT=%d) failure for interface %s vif_index=%d: errno=%d: %s%s", + SIOCGETVIFCNT, + ifp->name, + pim_ifp->mroute_vif_index, + e, + strerror(e), + VTY_NEWLINE); + continue; + } + + ifaddr = pim_ifp->primary_address; + + vty_out(vty, "%-9s %-15s %7d %8d %6lu %7lu %7lu %8lu%s", + ifp->name, + inet_ntoa(ifaddr), + ifp->ifindex, + pim_ifp->mroute_vif_index, + vreq.icount, + vreq.ocount, + vreq.ibytes, + vreq.obytes, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_multicast, + show_ip_multicast_cmd, + "show ip multicast", + SHOW_STR + IP_STR + "Multicast global information\n") +{ + if (PIM_MROUTE_IS_ENABLED) { + time_t now; + char uptime[10]; + + vty_out(vty, "Mroute socket descriptor: %d%s", + qpim_mroute_socket_fd, + VTY_NEWLINE); + + now = pim_time_monotonic_sec(); + pim_time_uptime(uptime, sizeof(uptime), now - qpim_mroute_socket_creation); + vty_out(vty, "Mroute socket uptime: %s%s", + uptime, + VTY_NEWLINE); + } + else { + vty_out(vty, "Multicast disabled%s", + VTY_NEWLINE); + } + + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "Current highest VifIndex: %d%s", + qpim_mroute_oif_highest_vif_index, + VTY_NEWLINE); + vty_out(vty, "Maximum highest VifIndex: %d%s", + MAXVIFS - 1, + VTY_NEWLINE); + + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "Upstream Join Timer: %d secs%s", + qpim_t_periodic, + VTY_NEWLINE); + vty_out(vty, "Join/Prune Holdtime: %d secs%s", + PIM_JP_HOLDTIME, + VTY_NEWLINE); + + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "RPF Cache Refresh Delay: %ld msecs%s", + qpim_rpf_cache_refresh_delay_msec, + VTY_NEWLINE); + vty_out(vty, "RPF Cache Refresh Timer: %ld msecs%s", + pim_time_timer_remain_msec(qpim_rpf_cache_refresher), + VTY_NEWLINE); + + show_multicast_interfaces(vty); + + return CMD_SUCCESS; +} + +static void show_mroute(struct vty *vty) +{ + struct listnode *node; + struct channel_oil *c_oil; + time_t now; + + vty_out(vty, "Proto: I=IGMP P=PIM%s%s", VTY_NEWLINE, VTY_NEWLINE); + + vty_out(vty, "Source Group Proto Input iVifI Output oVifI TTL Uptime %s", + VTY_NEWLINE); + + now = pim_time_monotonic_sec(); + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + char group_str[100]; + char source_str[100]; + int oif_vif_index; + + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + + for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) { + struct interface *ifp_in; + struct interface *ifp_out; + char oif_uptime[10]; + int ttl; + char proto[5]; + + ttl = c_oil->oil.mfcc_ttls[oif_vif_index]; + if (ttl < 1) + continue; + + ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); + ifp_out = pim_if_find_by_vif_index(oif_vif_index); + + pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]); + + proto[0] = '\0'; + if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_PIM) { + strcat(proto, "P"); + } + if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP) { + strcat(proto, "I"); + } + + vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s", + source_str, + group_str, + proto, + ifp_in ? ifp_in->name : "", + c_oil->oil.mfcc_parent, + ifp_out ? ifp_out->name : "", + oif_vif_index, + ttl, + oif_uptime, + VTY_NEWLINE); + } + } +} + +DEFUN (show_ip_mroute, + show_ip_mroute_cmd, + "show ip mroute", + SHOW_STR + IP_STR + MROUTE_STR) +{ + show_mroute(vty); + return CMD_SUCCESS; +} + +static void show_mroute_count(struct vty *vty) +{ + struct listnode *node; + struct channel_oil *c_oil; + + vty_out(vty, "%s", VTY_NEWLINE); + + vty_out(vty, "Source Group Packets Bytes WrongIf %s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + char group_str[100]; + char source_str[100]; + struct sioc_sg_req sgreq; + + memset(&sgreq, 0, sizeof(sgreq)); + sgreq.src = c_oil->oil.mfcc_origin; + sgreq.grp = c_oil->oil.mfcc_mcastgrp; + + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + + if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { + int e = errno; + vty_out(vty, + "ioctl(SIOCGETSGCNT=%d) failure for (S,G)=(%s,%s): errno=%d: %s%s", + SIOCGETSGCNT, + source_str, + group_str, + e, + strerror(e), + VTY_NEWLINE); + continue; + } + + vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", + source_str, + group_str, + sgreq.pktcnt, + sgreq.bytecnt, + sgreq.wrong_if, + VTY_NEWLINE); + + } +} + +DEFUN (show_ip_mroute_count, + show_ip_mroute_count_cmd, + "show ip mroute count", + SHOW_STR + IP_STR + MROUTE_STR + "Route and packet count data\n") +{ + show_mroute_count(vty); + return CMD_SUCCESS; +} + +DEFUN (show_ip_route, + show_ip_route_cmd, + "show ip route A.B.C.D", + SHOW_STR + IP_STR + ROUTE_STR + "Unicast address\n") +{ + struct in_addr addr; + const char *addr_str; + struct pim_nexthop nexthop; + char nexthop_addr_str[100]; + int result; + + addr_str = argv[0]; + result = inet_pton(AF_INET, addr_str, &addr); + if (result <= 0) { + vty_out(vty, "Bad unicast address %s: errno=%d: %s%s", + addr_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (pim_nexthop_lookup(&nexthop, addr)) { + vty_out(vty, "Failure querying RIB nexthop for unicast address %s%s", + addr_str, VTY_NEWLINE); + return CMD_WARNING; + } + + vty_out(vty, "Address NextHop Interface Metric Preference%s", + VTY_NEWLINE); + + pim_inet4_dump("", nexthop.mrib_nexthop_addr, + nexthop_addr_str, sizeof(nexthop_addr_str)); + + vty_out(vty, "%-15s %-15s %-9s %6d %10d%s", + addr_str, + nexthop_addr_str, + nexthop.interface ? nexthop.interface->name : "", + nexthop.mrib_route_metric, + nexthop.mrib_metric_preference, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +static void mroute_add_all() +{ + struct listnode *node; + struct channel_oil *c_oil; + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + if (pim_mroute_add(&c_oil->oil)) { + /* just log warning */ + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } +} + +static void mroute_del_all() +{ + struct listnode *node; + struct channel_oil *c_oil; + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + if (pim_mroute_del(&c_oil->oil)) { + /* just log warning */ + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } +} + +DEFUN (ip_multicast_routing, + ip_multicast_routing_cmd, + PIM_CMD_IP_MULTICAST_ROUTING, + IP_STR + "Enable IP multicast forwarding\n") +{ + pim_mroute_socket_enable(); + pim_if_add_vif_all(); + mroute_add_all(); + return CMD_SUCCESS; +} + +DEFUN (no_ip_multicast_routing, + no_ip_multicast_routing_cmd, + PIM_CMD_NO " " PIM_CMD_IP_MULTICAST_ROUTING, + NO_STR + IP_STR + "Global IP configuration subcommands\n" + "Enable IP multicast forwarding\n") +{ + mroute_del_all(); + pim_if_del_vif_all(); + pim_mroute_socket_disable(); + return CMD_SUCCESS; +} + +DEFUN (interface_ip_igmp, + interface_ip_igmp_cmd, + "ip igmp", + IP_STR + IFACE_IGMP_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + pim_ifp = pim_if_new(ifp, 1 /* igmp=true */, 0 /* pim=false */); + if (!pim_ifp) { + vty_out(vty, "Could not enable IGMP on interface %s%s", + ifp->name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else { + PIM_IF_DO_IGMP(pim_ifp->options); + } + + pim_if_addr_add_all(ifp); + pim_if_membership_refresh(ifp); + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_igmp, + interface_no_ip_igmp_cmd, + "no ip igmp", + NO_STR + IP_STR + IFACE_IGMP_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + if (!pim_ifp) + return CMD_SUCCESS; + + PIM_IF_DONT_IGMP(pim_ifp->options); + + pim_if_membership_clear(ifp); + + pim_if_addr_del_all(ifp); + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) { + pim_if_delete(ifp); + } + + return CMD_SUCCESS; +} + +DEFUN (interface_ip_igmp_join, + interface_ip_igmp_join_cmd, + "ip igmp join A.B.C.D A.B.C.D", + IP_STR + IFACE_IGMP_STR + "IGMP join multicast group\n" + "Multicast group address\n" + "Source address\n") +{ + struct interface *ifp; + const char *group_str; + const char *source_str; + struct in_addr group_addr; + struct in_addr source_addr; + int result; + + ifp = vty->index; + + /* Group address */ + group_str = argv[0]; + result = inet_pton(AF_INET, group_str, &group_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + group_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Source address */ + source_str = argv[1]; + result = inet_pton(AF_INET, source_str, &source_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + source_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_if_igmp_join_add(ifp, group_addr, source_addr); + if (result) { + vty_out(vty, "%% Failure joining IGMP group %s source %s on interface %s: %d%s", + group_str, source_str, ifp->name, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_igmp_join, + interface_no_ip_igmp_join_cmd, + "no ip igmp join A.B.C.D A.B.C.D", + NO_STR + IP_STR + IFACE_IGMP_STR + "IGMP join multicast group\n" + "Multicast group address\n" + "Source address\n") +{ + struct interface *ifp; + const char *group_str; + const char *source_str; + struct in_addr group_addr; + struct in_addr source_addr; + int result; + + ifp = vty->index; + + /* Group address */ + group_str = argv[0]; + result = inet_pton(AF_INET, group_str, &group_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + group_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Source address */ + source_str = argv[1]; + result = inet_pton(AF_INET, source_str, &source_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + source_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_if_igmp_join_del(ifp, group_addr, source_addr); + if (result) { + vty_out(vty, "%% Failure leaving IGMP group %s source %s on interface %s: %d%s", + group_str, source_str, ifp->name, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* + CLI reconfiguration affects the interface level (struct pim_interface). + This function propagates the reconfiguration to every active socket + for that interface. + */ +static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + zassert(igmp); + + /* other querier present? */ + + if (igmp->t_other_querier_timer) + return; + + /* this is the querier */ + + zassert(igmp->interface); + zassert(igmp->interface->info); + + ifp = igmp->interface; + pim_ifp = ifp->info; + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", + __PRETTY_FUNCTION__, + ifaddr_str, + ifp->name, + pim_ifp->igmp_default_query_interval); + } + + /* + igmp_startup_mode_on() will reset QQI: + + igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; + */ + igmp_startup_mode_on(igmp); +} + +static void igmp_sock_query_reschedule(struct igmp_sock *igmp) +{ + if (igmp->t_igmp_query_timer) { + /* other querier present */ + zassert(igmp->t_igmp_query_timer); + zassert(!igmp->t_other_querier_timer); + + pim_igmp_general_query_off(igmp); + pim_igmp_general_query_on(igmp); + + zassert(igmp->t_igmp_query_timer); + zassert(!igmp->t_other_querier_timer); + } + else { + /* this is the querier */ + + zassert(!igmp->t_igmp_query_timer); + zassert(igmp->t_other_querier_timer); + + pim_igmp_other_querier_timer_off(igmp); + pim_igmp_other_querier_timer_on(igmp); + + zassert(!igmp->t_igmp_query_timer); + zassert(igmp->t_other_querier_timer); + } +} + +static void change_query_interval(struct pim_interface *pim_ifp, + int query_interval) +{ + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp->igmp_default_query_interval = query_interval; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + igmp_sock_query_interval_reconfig(igmp); + igmp_sock_query_reschedule(igmp); + } +} + +static void change_query_max_response_time(struct pim_interface *pim_ifp, + int query_max_response_time_dsec) +{ + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp->igmp_query_max_response_time_dsec = query_max_response_time_dsec; + + /* + Below we modify socket/group/source timers in order to quickly + reflect the change. Otherwise, those timers would eventually catch + up. + */ + + /* scan all sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + struct listnode *grp_node; + struct igmp_group *grp; + + /* reschedule socket general query */ + igmp_sock_query_reschedule(igmp); + + /* scan socket groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node, grp)) { + struct listnode *src_node; + struct igmp_source *src; + + /* reset group timers for groups in EXCLUDE mode */ + if (grp->group_filtermode_isexcl) { + igmp_group_reset_gmi(grp); + } + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node, src)) { + + /* reset source timers for sources with running timers */ + if (src->t_source_timer) { + igmp_source_reset_gmi(igmp, grp, src); + } + } + } + } +} + +#define IGMP_QUERY_INTERVAL_MIN (1) +#define IGMP_QUERY_INTERVAL_MAX (1800) + +DEFUN (interface_ip_igmp_query_interval, + interface_ip_igmp_query_interval_cmd, + PIM_CMD_IP_IGMP_QUERY_INTERVAL " <1-1800>", + IP_STR + IFACE_IGMP_STR + IFACE_IGMP_QUERY_INTERVAL_STR + "Query interval in seconds\n") +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int query_interval; + int query_interval_dsec; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, + "IGMP not enabled on interface %s. Please enable IGMP first.%s", + ifp->name, + VTY_NEWLINE); + return CMD_WARNING; + } + + query_interval = atoi(argv[0]); + query_interval_dsec = 10 * query_interval; + + /* + It seems we don't need to check bounds since command.c does it + already, but we verify them anyway for extra safety. + */ + if (query_interval < IGMP_QUERY_INTERVAL_MIN) { + vty_out(vty, "General query interval %d lower than minimum %d%s", + query_interval, + IGMP_QUERY_INTERVAL_MIN, + VTY_NEWLINE); + return CMD_WARNING; + } + if (query_interval > IGMP_QUERY_INTERVAL_MAX) { + vty_out(vty, "General query interval %d higher than maximum %d%s", + query_interval, + IGMP_QUERY_INTERVAL_MAX, + VTY_NEWLINE); + return CMD_WARNING; + } + + if (query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { + vty_out(vty, + "Can't set general query interval %d dsec <= query max response time %d dsec.%s", + query_interval_dsec, pim_ifp->igmp_query_max_response_time_dsec, + VTY_NEWLINE); + return CMD_WARNING; + } + + change_query_interval(pim_ifp, query_interval); + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_igmp_query_interval, + interface_no_ip_igmp_query_interval_cmd, + PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_INTERVAL, + NO_STR + IP_STR + IFACE_IGMP_STR + IFACE_IGMP_QUERY_INTERVAL_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int default_query_interval_dsec; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) + return CMD_SUCCESS; + + default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10; + + if (default_query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { + vty_out(vty, + "Can't set default general query interval %d dsec <= query max response time %d dsec.%s", + default_query_interval_dsec, pim_ifp->igmp_query_max_response_time_dsec, + VTY_NEWLINE); + return CMD_WARNING; + } + + change_query_interval(pim_ifp, IGMP_GENERAL_QUERY_INTERVAL); + + return CMD_SUCCESS; +} + +#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN (1) +#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX (25) + +DEFUN (interface_ip_igmp_query_max_response_time, + interface_ip_igmp_query_max_response_time_cmd, + PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME " <1-25>", + IP_STR + IFACE_IGMP_STR + IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR + "Query response value in seconds\n") +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int query_max_response_time; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, + "IGMP not enabled on interface %s. Please enable IGMP first.%s", + ifp->name, + VTY_NEWLINE); + return CMD_WARNING; + } + + query_max_response_time = atoi(argv[0]); + + /* + It seems we don't need to check bounds since command.c does it + already, but we verify them anyway for extra safety. + */ + if (query_max_response_time < IGMP_QUERY_MAX_RESPONSE_TIME_MIN) { + vty_out(vty, "Query max response time %d sec lower than minimum %d sec%s", + query_max_response_time, + IGMP_QUERY_MAX_RESPONSE_TIME_MIN, + VTY_NEWLINE); + return CMD_WARNING; + } + if (query_max_response_time > IGMP_QUERY_MAX_RESPONSE_TIME_MAX) { + vty_out(vty, "Query max response time %d sec higher than maximum %d sec%s", + query_max_response_time, + IGMP_QUERY_MAX_RESPONSE_TIME_MAX, + VTY_NEWLINE); + return CMD_WARNING; + } + + if (query_max_response_time >= pim_ifp->igmp_default_query_interval) { + vty_out(vty, + "Can't set query max response time %d sec >= general query interval %d sec%s", + query_max_response_time, pim_ifp->igmp_default_query_interval, + VTY_NEWLINE); + return CMD_WARNING; + } + + change_query_max_response_time(pim_ifp, 10 * query_max_response_time); + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_igmp_query_max_response_time, + interface_no_ip_igmp_query_max_response_time_cmd, + PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME, + NO_STR + IP_STR + IFACE_IGMP_STR + IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int default_query_interval_dsec; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) + return CMD_SUCCESS; + + default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; + + if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) { + vty_out(vty, + "Can't set default query max response time %d dsec >= general query interval %d dsec.%s", + IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec, + VTY_NEWLINE); + return CMD_WARNING; + } + + change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); + + return CMD_SUCCESS; +} + +#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10) +#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250) + +DEFUN (interface_ip_igmp_query_max_response_time_dsec, + interface_ip_igmp_query_max_response_time_dsec_cmd, + PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC " <10-250>", + IP_STR + IFACE_IGMP_STR + IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR + "Query response value in deciseconds\n") +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int query_max_response_time_dsec; + int default_query_interval_dsec; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, + "IGMP not enabled on interface %s. Please enable IGMP first.%s", + ifp->name, + VTY_NEWLINE); + return CMD_WARNING; + } + + query_max_response_time_dsec = atoi(argv[0]); + + /* + It seems we don't need to check bounds since command.c does it + already, but we verify them anyway for extra safety. + */ + if (query_max_response_time_dsec < IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC) { + vty_out(vty, "Query max response time %d dsec lower than minimum %d dsec%s", + query_max_response_time_dsec, + IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC, + VTY_NEWLINE); + return CMD_WARNING; + } + if (query_max_response_time_dsec > IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC) { + vty_out(vty, "Query max response time %d dsec higher than maximum %d dsec%s", + query_max_response_time_dsec, + IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC, + VTY_NEWLINE); + return CMD_WARNING; + } + + default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; + + if (query_max_response_time_dsec >= default_query_interval_dsec) { + vty_out(vty, + "Can't set query max response time %d dsec >= general query interval %d dsec%s", + query_max_response_time_dsec, default_query_interval_dsec, + VTY_NEWLINE); + return CMD_WARNING; + } + + change_query_max_response_time(pim_ifp, query_max_response_time_dsec); + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_igmp_query_max_response_time_dsec, + interface_no_ip_igmp_query_max_response_time_dsec_cmd, + PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, + NO_STR + IP_STR + IFACE_IGMP_STR + IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int default_query_interval_dsec; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) + return CMD_SUCCESS; + + default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; + + if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) { + vty_out(vty, + "Can't set default query max response time %d dsec >= general query interval %d dsec.%s", + IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec, + VTY_NEWLINE); + return CMD_WARNING; + } + + change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); + + return CMD_SUCCESS; +} + +DEFUN (interface_ip_pim_ssm, + interface_ip_pim_ssm_cmd, + "ip pim ssm", + IP_STR + PIM_STR + IFACE_PIM_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + pim_ifp = pim_if_new(ifp, 0 /* igmp=false */, 1 /* pim=true */); + if (!pim_ifp) { + vty_out(vty, "Could not enable PIM on interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else { + PIM_IF_DO_PIM(pim_ifp->options); + } + + pim_if_addr_add_all(ifp); + pim_if_membership_refresh(ifp); + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_pim_ssm, + interface_no_ip_pim_ssm_cmd, + "no ip pim ssm", + NO_STR + IP_STR + PIM_STR + IFACE_PIM_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + if (!pim_ifp) + return CMD_SUCCESS; + + PIM_IF_DONT_PIM(pim_ifp->options); + + pim_if_membership_clear(ifp); + + /* + pim_if_addr_del_all() removes all sockets from + pim_ifp->igmp_socket_list. + */ + pim_if_addr_del_all(ifp); + + /* + pim_sock_delete() removes all neighbors from + pim_ifp->pim_neighbor_list. + */ + pim_sock_delete(ifp, "pim unconfigured on interface"); + + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { + pim_if_delete(ifp); + } + + return CMD_SUCCESS; +} + +DEFUN (debug_igmp, + debug_igmp_cmd, + "debug igmp", + DEBUG_STR + DEBUG_IGMP_STR) +{ + PIM_DO_DEBUG_IGMP_EVENTS; + PIM_DO_DEBUG_IGMP_PACKETS; + PIM_DO_DEBUG_IGMP_TRACE; + return CMD_SUCCESS; +} + +DEFUN (no_debug_igmp, + no_debug_igmp_cmd, + "no debug igmp", + NO_STR + DEBUG_STR + DEBUG_IGMP_STR) +{ + PIM_DONT_DEBUG_IGMP_EVENTS; + PIM_DONT_DEBUG_IGMP_PACKETS; + PIM_DONT_DEBUG_IGMP_TRACE; + return CMD_SUCCESS; +} + +ALIAS (no_debug_igmp, + undebug_igmp_cmd, + "undebug igmp", + UNDEBUG_STR + DEBUG_IGMP_STR) + +DEFUN (debug_igmp_events, + debug_igmp_events_cmd, + "debug igmp events", + DEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_EVENTS_STR) +{ + PIM_DO_DEBUG_IGMP_EVENTS; + return CMD_SUCCESS; +} + +DEFUN (no_debug_igmp_events, + no_debug_igmp_events_cmd, + "no debug igmp events", + NO_STR + DEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_EVENTS_STR) +{ + PIM_DONT_DEBUG_IGMP_EVENTS; + return CMD_SUCCESS; +} + +ALIAS (no_debug_igmp_events, + undebug_igmp_events_cmd, + "undebug igmp events", + UNDEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_EVENTS_STR) + +DEFUN (debug_igmp_packets, + debug_igmp_packets_cmd, + "debug igmp packets", + DEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_PACKETS_STR) +{ + PIM_DO_DEBUG_IGMP_PACKETS; + return CMD_SUCCESS; +} + +DEFUN (no_debug_igmp_packets, + no_debug_igmp_packets_cmd, + "no debug igmp packets", + NO_STR + DEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_PACKETS_STR) +{ + PIM_DONT_DEBUG_IGMP_PACKETS; + return CMD_SUCCESS; +} + +ALIAS (no_debug_igmp_packets, + undebug_igmp_packets_cmd, + "undebug igmp packets", + UNDEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_PACKETS_STR) + +DEFUN (debug_igmp_trace, + debug_igmp_trace_cmd, + "debug igmp trace", + DEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_TRACE_STR) +{ + PIM_DO_DEBUG_IGMP_TRACE; + return CMD_SUCCESS; +} + +DEFUN (no_debug_igmp_trace, + no_debug_igmp_trace_cmd, + "no debug igmp trace", + NO_STR + DEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_TRACE_STR) +{ + PIM_DONT_DEBUG_IGMP_TRACE; + return CMD_SUCCESS; +} + +ALIAS (no_debug_igmp_trace, + undebug_igmp_trace_cmd, + "undebug igmp trace", + UNDEBUG_STR + DEBUG_IGMP_STR + DEBUG_IGMP_TRACE_STR) + +DEFUN (debug_pim, + debug_pim_cmd, + "debug pim", + DEBUG_STR + DEBUG_PIM_STR) +{ + PIM_DO_DEBUG_PIM_EVENTS; + PIM_DO_DEBUG_PIM_PACKETS; + PIM_DO_DEBUG_PIM_TRACE; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim, + no_debug_pim_cmd, + "no debug pim", + NO_STR + DEBUG_STR + DEBUG_PIM_STR) +{ + PIM_DONT_DEBUG_PIM_EVENTS; + PIM_DONT_DEBUG_PIM_PACKETS; + PIM_DONT_DEBUG_PIM_TRACE; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim, + undebug_pim_cmd, + "undebug pim", + UNDEBUG_STR + DEBUG_PIM_STR) + +DEFUN (debug_pim_events, + debug_pim_events_cmd, + "debug pim events", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_EVENTS_STR) +{ + PIM_DO_DEBUG_PIM_EVENTS; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_events, + no_debug_pim_events_cmd, + "no debug pim events", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_EVENTS_STR) +{ + PIM_DONT_DEBUG_PIM_EVENTS; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim_events, + undebug_pim_events_cmd, + "undebug pim events", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_EVENTS_STR) + +DEFUN (debug_pim_packets, + debug_pim_packets_cmd, + "debug pim packets", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETS_STR) +{ + PIM_DO_DEBUG_PIM_PACKETS; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_packets, + no_debug_pim_packets_cmd, + "no debug pim packets", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETS_STR) +{ + PIM_DONT_DEBUG_PIM_PACKETS; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim_packets, + undebug_pim_packets_cmd, + "undebug pim packets", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETS_STR) + +DEFUN (debug_pim_trace, + debug_pim_trace_cmd, + "debug pim trace", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_TRACE_STR) +{ + PIM_DO_DEBUG_PIM_TRACE; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_trace, + no_debug_pim_trace_cmd, + "no debug pim trace", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_TRACE_STR) +{ + PIM_DONT_DEBUG_PIM_TRACE; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim_trace, + undebug_pim_trace_cmd, + "undebug pim trace", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_TRACE_STR) + +DEFUN (debug_pim_zebra, + debug_pim_zebra_cmd, + "debug pim zebra", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_ZEBRA_STR) +{ + PIM_DO_DEBUG_ZEBRA; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_zebra, + no_debug_pim_zebra_cmd, + "no debug pim zebra", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_ZEBRA_STR) +{ + PIM_DONT_DEBUG_ZEBRA; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim_zebra, + undebug_pim_zebra_cmd, + "undebug pim zebra", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_ZEBRA_STR) + +DEFUN (show_debugging, + show_debugging_cmd, + "show debugging", + SHOW_STR + "State of each debugging option\n") +{ + pim_debug_config_write(vty); + return CMD_SUCCESS; +} + +static struct igmp_sock *find_igmp_sock_by_fd(int fd) +{ + struct listnode *ifnode; + struct interface *ifp; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + struct pim_interface *pim_ifp; + struct igmp_sock *igmp; + + if (!ifp->info) + continue; + + pim_ifp = ifp->info; + + /* lookup igmp socket under current interface */ + igmp = igmp_sock_lookup_by_fd(pim_ifp->igmp_socket_list, fd); + if (igmp) + return igmp; + } + + return 0; +} + +DEFUN (test_igmp_receive_report, + test_igmp_receive_report_cmd, + "test igmp receive report <0-65535> A.B.C.D <1-6> .LINE", + "Test\n" + "Test IGMP protocol\n" + "Test IGMP message\n" + "Test IGMP report\n" + "Socket\n" + "IGMP group address\n" + "Record type\n" + "Sources\n") +{ + char buf[1000]; + char *igmp_msg; + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + int ip_msg_len; + int igmp_msg_len; + const char *socket; + int socket_fd; + const char *grp_str; + struct in_addr grp_addr; + const char *record_type_str; + int record_type; + const char *src_str; + int result; + struct igmp_sock *igmp; + char *group_record; + int num_sources; + struct in_addr *sources; + struct in_addr *src_addr; + int argi; + + socket = argv[0]; + socket_fd = atoi(socket); + igmp = find_igmp_sock_by_fd(socket_fd); + if (!igmp) { + vty_out(vty, "Could not find IGMP socket %s: fd=%d%s", + socket, socket_fd, VTY_NEWLINE); + return CMD_WARNING; + } + + grp_str = argv[1]; + result = inet_pton(AF_INET, grp_str, &grp_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + grp_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + record_type_str = argv[2]; + record_type = atoi(record_type_str); + + /* + Tweak IP header + */ + ip_hdr = (struct ip *) buf; + ip_hdr->ip_p = PIM_IP_PROTO_IGMP; + ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ + ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ + ip_hdr->ip_src = igmp->ifaddr; + ip_hdr->ip_dst = igmp->ifaddr; + + /* + Build IGMP v3 report message + */ + igmp_msg = buf + ip_hlen; + group_record = igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; + *igmp_msg = PIM_IGMP_V3_MEMBERSHIP_REPORT; /* type */ + *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ + *(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET) = htons(1); /* one group record */ + *(uint8_t *) (group_record + IGMP_V3_GROUP_RECORD_TYPE_OFFSET) = record_type; + *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET) = grp_addr; + + /* Scan LINE sources */ + sources = (struct in_addr *) (group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET); + src_addr = sources; + for (argi = 3; argi < argc; ++argi,++src_addr) { + src_str = argv[argi]; + result = inet_pton(AF_INET, src_str, src_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + src_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + } + num_sources = src_addr - sources; + + *(uint16_t *)(group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET) = htons(num_sources); + + igmp_msg_len = IGMP_V3_MSG_MIN_SIZE + (num_sources << 4); /* v3 report for one single group record */ + + /* compute checksum */ + *(uint16_t *)(igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = pim_inet_checksum(igmp_msg, igmp_msg_len); + + /* "receive" message */ + + ip_msg_len = ip_hlen + igmp_msg_len; + result = pim_igmp_packet(igmp, buf, ip_msg_len); + if (result) { + vty_out(vty, "pim_igmp_packet(len=%d) returned: %d%s", + ip_msg_len, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (test_pim_receive_hello, + test_pim_receive_hello_cmd, + "test pim receive hello INTERFACE A.B.C.D <0-65535> <0-65535> <0-65535> <0-32767> <0-65535> <0-1>[LINE]", + "Test\n" + "Test PIM protocol\n" + "Test PIM message reception\n" + "Test PIM hello reception from neighbor\n" + "Interface\n" + "Neighbor address\n" + "Neighbor holdtime\n" + "Neighbor DR priority\n" + "Neighbor generation ID\n" + "Neighbor propagation delay (msec)\n" + "Neighbor override interval (msec)\n" + "Neighbor LAN prune delay T-bit\n" + "Neighbor secondary addresses\n") +{ + char buf[1000]; + char *pim_msg; + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + int ip_msg_len; + int pim_tlv_size; + int pim_msg_size; + const char *neigh_str; + struct in_addr neigh_addr; + const char *ifname; + struct interface *ifp; + uint16_t neigh_holdtime; + uint16_t neigh_propagation_delay; + uint16_t neigh_override_interval; + int neigh_can_disable_join_suppression; + uint32_t neigh_dr_priority; + uint32_t neigh_generation_id; + int argi; + int result; + + /* Find interface */ + ifname = argv[0]; + ifp = if_lookup_by_name(ifname); + if (!ifp) { + vty_out(vty, "No such interface name %s%s", + ifname, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Neighbor address */ + neigh_str = argv[1]; + result = inet_pton(AF_INET, neigh_str, &neigh_addr); + if (result <= 0) { + vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", + neigh_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + neigh_holdtime = atoi(argv[2]); + neigh_dr_priority = atoi(argv[3]); + neigh_generation_id = atoi(argv[4]); + neigh_propagation_delay = atoi(argv[5]); + neigh_override_interval = atoi(argv[6]); + neigh_can_disable_join_suppression = atoi(argv[7]); + + /* + Tweak IP header + */ + ip_hdr = (struct ip *) buf; + ip_hdr->ip_p = PIM_IP_PROTO_PIM; + ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ + ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ + ip_hdr->ip_src = neigh_addr; + ip_hdr->ip_dst = qpim_all_pim_routers_addr; + + /* + Build PIM hello message + */ + pim_msg = buf + ip_hlen; + + /* Scan LINE addresses */ + for (argi = 8; argi < argc; ++argi) { + const char *sec_str = argv[argi]; + struct in_addr sec_addr; + result = inet_pton(AF_INET, sec_str, &sec_addr); + if (result <= 0) { + vty_out(vty, "Bad neighbor secondary address %s: errno=%d: %s%s", + sec_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + vty_out(vty, + "FIXME WRITEME consider neighbor secondary address %s%s", + sec_str, VTY_NEWLINE); + } + + pim_tlv_size = pim_hello_build_tlv(ifp->name, + pim_msg + PIM_PIM_MIN_LEN, + sizeof(buf) - ip_hlen - PIM_PIM_MIN_LEN, + neigh_holdtime, + neigh_dr_priority, + neigh_generation_id, + neigh_propagation_delay, + neigh_override_interval, + neigh_can_disable_join_suppression, + 0 /* FIXME secondary address list */); + if (pim_tlv_size < 0) { + vty_out(vty, "pim_hello_build_tlv() returned failure: %d%s", + pim_tlv_size, VTY_NEWLINE); + return CMD_WARNING; + } + + pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; + + pim_msg_build_header(pim_msg, pim_msg_size, + PIM_MSG_TYPE_HELLO); + + /* "receive" message */ + + ip_msg_len = ip_hlen + pim_msg_size; + result = pim_pim_packet(ifp, buf, ip_msg_len); + if (result) { + vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", + ip_msg_len, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (test_pim_receive_assert, + test_pim_receive_assert_cmd, + "test pim receive assert INTERFACE A.B.C.D A.B.C.D A.B.C.D <0-65535> <0-65535> <0-1>", + "Test\n" + "Test PIM protocol\n" + "Test PIM message reception\n" + "Test reception of PIM assert\n" + "Interface\n" + "Neighbor address\n" + "Assert multicast group address\n" + "Assert unicast source address\n" + "Assert metric preference\n" + "Assert route metric\n" + "Assert RPT bit flag\n") +{ + char buf[1000]; + char *buf_pastend = buf + sizeof(buf); + char *pim_msg; + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + int ip_msg_len; + int pim_msg_size; + const char *neigh_str; + struct in_addr neigh_addr; + const char *group_str; + struct in_addr group_addr; + const char *source_str; + struct in_addr source_addr; + const char *ifname; + struct interface *ifp; + uint32_t assert_metric_preference; + uint32_t assert_route_metric; + uint32_t assert_rpt_bit_flag; + int remain; + int result; + + /* Find interface */ + ifname = argv[0]; + ifp = if_lookup_by_name(ifname); + if (!ifp) { + vty_out(vty, "No such interface name %s%s", + ifname, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Neighbor address */ + neigh_str = argv[1]; + result = inet_pton(AF_INET, neigh_str, &neigh_addr); + if (result <= 0) { + vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", + neigh_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Group address */ + group_str = argv[2]; + result = inet_pton(AF_INET, group_str, &group_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + group_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Source address */ + source_str = argv[3]; + result = inet_pton(AF_INET, source_str, &source_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + source_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + assert_metric_preference = atoi(argv[4]); + assert_route_metric = atoi(argv[5]); + assert_rpt_bit_flag = atoi(argv[6]); + + remain = buf_pastend - buf; + if (remain < (int) sizeof(struct ip)) { + vty_out(vty, "No room for ip header: buf_size=%d < ip_header_size=%d%s", + remain, sizeof(struct ip), VTY_NEWLINE); + return CMD_WARNING; + } + + /* + Tweak IP header + */ + ip_hdr = (struct ip *) buf; + ip_hdr->ip_p = PIM_IP_PROTO_PIM; + ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ + ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ + ip_hdr->ip_src = neigh_addr; + ip_hdr->ip_dst = qpim_all_pim_routers_addr; + + /* + Build PIM assert message + */ + pim_msg = buf + ip_hlen; /* skip ip header */ + + pim_msg_size = pim_assert_build_msg(pim_msg, buf_pastend - pim_msg, ifp, + group_addr, source_addr, + assert_metric_preference, + assert_route_metric, + assert_rpt_bit_flag); + if (pim_msg_size < 0) { + vty_out(vty, "Failure building PIM assert message: size=%d%s", + pim_msg_size, VTY_NEWLINE); + return CMD_WARNING; + } + + /* "receive" message */ + + ip_msg_len = ip_hlen + pim_msg_size; + result = pim_pim_packet(ifp, buf, ip_msg_len); + if (result) { + vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", + ip_msg_len, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +static int recv_joinprune(struct vty *vty, + const char *argv[], + int src_is_join) +{ + char buf[1000]; + const char *buf_pastend = buf + sizeof(buf); + char *pim_msg; + char *pim_msg_curr; + int pim_msg_size; + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + int ip_msg_len; + uint16_t neigh_holdtime; + const char *neigh_dst_str; + struct in_addr neigh_dst_addr; + const char *neigh_src_str; + struct in_addr neigh_src_addr; + const char *group_str; + struct in_addr group_addr; + const char *source_str; + struct in_addr source_addr; + const char *ifname; + struct interface *ifp; + int result; + int remain; + uint16_t num_joined; + uint16_t num_pruned; + + /* Find interface */ + ifname = argv[0]; + ifp = if_lookup_by_name(ifname); + if (!ifp) { + vty_out(vty, "No such interface name %s%s", + ifname, VTY_NEWLINE); + return CMD_WARNING; + } + + neigh_holdtime = atoi(argv[1]); + + /* Neighbor destination address */ + neigh_dst_str = argv[2]; + result = inet_pton(AF_INET, neigh_dst_str, &neigh_dst_addr); + if (result <= 0) { + vty_out(vty, "Bad neighbor destination address %s: errno=%d: %s%s", + neigh_dst_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Neighbor source address */ + neigh_src_str = argv[3]; + result = inet_pton(AF_INET, neigh_src_str, &neigh_src_addr); + if (result <= 0) { + vty_out(vty, "Bad neighbor source address %s: errno=%d: %s%s", + neigh_src_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Multicast group address */ + group_str = argv[4]; + result = inet_pton(AF_INET, group_str, &group_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + group_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Multicast source address */ + source_str = argv[5]; + result = inet_pton(AF_INET, source_str, &source_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + source_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* + Tweak IP header + */ + ip_hdr = (struct ip *) buf; + ip_hdr->ip_p = PIM_IP_PROTO_PIM; + ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ + ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ + ip_hdr->ip_src = neigh_src_addr; + ip_hdr->ip_dst = qpim_all_pim_routers_addr; + + /* + Build PIM message + */ + pim_msg = buf + ip_hlen; + + /* skip room for pim header */ + pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; + + remain = buf_pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, + remain, + neigh_dst_addr); + if (!pim_msg_curr) { + vty_out(vty, "Failure encoding destination address %s: space left=%d%s", + neigh_dst_str, remain, VTY_NEWLINE); + return CMD_WARNING; + } + + remain = buf_pastend - pim_msg_curr; + if (remain < 4) { + vty_out(vty, "Group will not fit: space left=%d%s", + remain, VTY_NEWLINE); + return CMD_WARNING; + } + + *pim_msg_curr = 0; /* reserved */ + ++pim_msg_curr; + *pim_msg_curr = 1; /* number of groups */ + ++pim_msg_curr; + *((uint16_t *) pim_msg_curr) = htons(neigh_holdtime); + ++pim_msg_curr; + ++pim_msg_curr; + + remain = buf_pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, + remain, + group_addr); + if (!pim_msg_curr) { + vty_out(vty, "Failure encoding group address %s: space left=%d%s", + group_str, remain, VTY_NEWLINE); + return CMD_WARNING; + } + + remain = buf_pastend - pim_msg_curr; + if (remain < 4) { + vty_out(vty, "Sources will not fit: space left=%d%s", + remain, VTY_NEWLINE); + return CMD_WARNING; + } + + if (src_is_join) { + num_joined = 1; + num_pruned = 0; + } + else { + num_joined = 0; + num_pruned = 1; + } + + /* number of joined sources */ + *((uint16_t *) pim_msg_curr) = htons(num_joined); + ++pim_msg_curr; + ++pim_msg_curr; + + /* number of pruned sources */ + *((uint16_t *) pim_msg_curr) = htons(num_pruned); + ++pim_msg_curr; + ++pim_msg_curr; + + remain = buf_pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr, + remain, + source_addr); + if (!pim_msg_curr) { + vty_out(vty, "Failure encoding source address %s: space left=%d%s", + source_str, remain, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Add PIM header */ + + pim_msg_size = pim_msg_curr - pim_msg; + + pim_msg_build_header(pim_msg, pim_msg_size, + PIM_MSG_TYPE_JOIN_PRUNE); + + /* + "Receive" message + */ + + ip_msg_len = ip_hlen + pim_msg_size; + result = pim_pim_packet(ifp, buf, ip_msg_len); + if (result) { + vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", + ip_msg_len, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (test_pim_receive_join, + test_pim_receive_join_cmd, + "test pim receive join INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "Test\n" + "Test PIM protocol\n" + "Test PIM message reception\n" + "Test PIM join reception from neighbor\n" + "Interface\n" + "Neighbor holdtime\n" + "Upstream neighbor unicast destination address\n" + "Downstream neighbor unicast source address\n" + "Multicast group address\n" + "Unicast source address\n") +{ + return recv_joinprune(vty, argv, 1 /* src_is_join=true */); +} + +DEFUN (test_pim_receive_prune, + test_pim_receive_prune_cmd, + "test pim receive prune INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "Test\n" + "Test PIM protocol\n" + "Test PIM message reception\n" + "Test PIM prune reception from neighbor\n" + "Interface\n" + "Neighbor holdtime\n" + "Upstream neighbor unicast destination address\n" + "Downstream neighbor unicast source address\n" + "Multicast group address\n" + "Unicast source address\n") +{ + return recv_joinprune(vty, argv, 0 /* src_is_join=false */); +} + +DEFUN (test_pim_receive_upcall, + test_pim_receive_upcall_cmd, + "test pim receive upcall (nocache|wrongvif|wholepkt) <0-65535> A.B.C.D A.B.C.D", + "Test\n" + "Test PIM protocol\n" + "Test PIM message reception\n" + "Test reception of kernel upcall\n" + "NOCACHE kernel upcall\n" + "WRONGVIF kernel upcall\n" + "WHOLEPKT kernel upcall\n" + "Input interface vif index\n" + "Multicast group address\n" + "Multicast source address\n") +{ + struct igmpmsg msg; + const char *upcall_type; + const char *group_str; + const char *source_str; + int result; + + upcall_type = argv[0]; + + if (upcall_type[0] == 'n') + msg.im_msgtype = IGMPMSG_NOCACHE; + else if (upcall_type[1] == 'r') + msg.im_msgtype = IGMPMSG_WRONGVIF; + else if (upcall_type[1] == 'h') + msg.im_msgtype = IGMPMSG_WHOLEPKT; + else { + vty_out(vty, "Unknown kernel upcall type: %s%s", + upcall_type, VTY_NEWLINE); + return CMD_WARNING; + } + + msg.im_vif = atoi(argv[1]); + + /* Group address */ + group_str = argv[2]; + result = inet_pton(AF_INET, group_str, &msg.im_dst); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + group_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Source address */ + source_str = argv[3]; + result = inet_pton(AF_INET, source_str, &msg.im_src); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + source_str, errno, strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + msg.im_mbz = 0; /* Must be zero */ + + result = pim_mroute_msg(-1, (char *) &msg, sizeof(msg)); + if (result) { + vty_out(vty, "pim_mroute_msg(len=%d) returned failure: %d%s", + sizeof(msg), result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +void pim_cmd_init() +{ + install_node(&pim_global_node, pim_global_config_write); /* PIM_NODE */ + install_node(&pim_interface_node, pim_interface_config_write); /* INTERFACE_NODE */ + + install_element(CONFIG_NODE, &ip_multicast_routing_cmd); + install_element(CONFIG_NODE, &no_ip_multicast_routing_cmd); +#if 0 + install_element(CONFIG_NODE, &interface_cmd); /* from if.h */ +#else + install_element(CONFIG_NODE, &pim_interface_cmd); +#endif + install_element(CONFIG_NODE, &no_interface_cmd); /* from if.h */ + + install_default(INTERFACE_NODE); + install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); + install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); + + install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); + install_element(VIEW_NODE, &show_ip_igmp_parameters_cmd); + install_element(VIEW_NODE, &show_ip_igmp_groups_cmd); + install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); + install_element(VIEW_NODE, &show_ip_igmp_sources_cmd); + install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); + install_element(VIEW_NODE, &show_ip_igmp_querier_cmd); + install_element(VIEW_NODE, &show_ip_pim_assert_cmd); + install_element(VIEW_NODE, &show_ip_pim_assert_internal_cmd); + install_element(VIEW_NODE, &show_ip_pim_assert_metric_cmd); + install_element(VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd); + install_element(VIEW_NODE, &show_ip_pim_dr_cmd); + install_element(VIEW_NODE, &show_ip_pim_hello_cmd); + install_element(VIEW_NODE, &show_ip_pim_interface_cmd); + install_element(VIEW_NODE, &show_ip_pim_join_cmd); + install_element(VIEW_NODE, &show_ip_pim_jp_override_interval_cmd); + install_element(VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd); + install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd); + install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd); + install_element(VIEW_NODE, &show_ip_pim_rpf_cmd); + install_element(VIEW_NODE, &show_ip_pim_secondary_cmd); + install_element(VIEW_NODE, &show_ip_pim_upstream_cmd); + install_element(VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd); + install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); + install_element(VIEW_NODE, &show_ip_multicast_cmd); + install_element(VIEW_NODE, &show_ip_mroute_cmd); + install_element(VIEW_NODE, &show_ip_mroute_count_cmd); + install_element(VIEW_NODE, &show_ip_route_cmd); + install_element(VIEW_NODE, &show_debugging_cmd); + + install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); + install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); + install_element(ENABLE_NODE, &clear_ip_pim_interfaces_cmd); + + install_element(ENABLE_NODE, &show_ip_igmp_interface_cmd); + install_element(ENABLE_NODE, &show_ip_igmp_parameters_cmd); + install_element(ENABLE_NODE, &show_ip_igmp_groups_cmd); + install_element(ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd); + install_element(ENABLE_NODE, &show_ip_igmp_sources_cmd); + install_element(ENABLE_NODE, &show_ip_igmp_sources_retransmissions_cmd); + install_element(ENABLE_NODE, &show_ip_igmp_querier_cmd); + install_element(ENABLE_NODE, &show_ip_pim_address_cmd); + install_element(ENABLE_NODE, &show_ip_pim_assert_cmd); + install_element(ENABLE_NODE, &show_ip_pim_assert_internal_cmd); + install_element(ENABLE_NODE, &show_ip_pim_assert_metric_cmd); + install_element(ENABLE_NODE, &show_ip_pim_assert_winner_metric_cmd); + install_element(ENABLE_NODE, &show_ip_pim_dr_cmd); + install_element(ENABLE_NODE, &show_ip_pim_hello_cmd); + install_element(ENABLE_NODE, &show_ip_pim_interface_cmd); + install_element(ENABLE_NODE, &show_ip_pim_join_cmd); + install_element(ENABLE_NODE, &show_ip_pim_jp_override_interval_cmd); + install_element(ENABLE_NODE, &show_ip_pim_lan_prune_delay_cmd); + install_element(ENABLE_NODE, &show_ip_pim_local_membership_cmd); + install_element(ENABLE_NODE, &show_ip_pim_neighbor_cmd); + install_element(ENABLE_NODE, &show_ip_pim_rpf_cmd); + install_element(ENABLE_NODE, &show_ip_pim_secondary_cmd); + install_element(ENABLE_NODE, &show_ip_pim_upstream_cmd); + install_element(ENABLE_NODE, &show_ip_pim_upstream_join_desired_cmd); + install_element(ENABLE_NODE, &show_ip_pim_upstream_rpf_cmd); + install_element(ENABLE_NODE, &show_ip_multicast_cmd); + install_element(ENABLE_NODE, &show_ip_mroute_cmd); + install_element(ENABLE_NODE, &show_ip_mroute_count_cmd); + install_element(ENABLE_NODE, &show_ip_route_cmd); + install_element(ENABLE_NODE, &show_debugging_cmd); + + install_element(ENABLE_NODE, &test_igmp_receive_report_cmd); + install_element(ENABLE_NODE, &test_pim_receive_assert_cmd); + install_element(ENABLE_NODE, &test_pim_receive_hello_cmd); + install_element(ENABLE_NODE, &test_pim_receive_join_cmd); + install_element(ENABLE_NODE, &test_pim_receive_prune_cmd); + install_element(ENABLE_NODE, &test_pim_receive_upcall_cmd); + + install_element(ENABLE_NODE, &debug_igmp_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_cmd); + install_element(ENABLE_NODE, &undebug_igmp_cmd); + install_element(ENABLE_NODE, &debug_igmp_events_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); + install_element(ENABLE_NODE, &undebug_igmp_events_cmd); + install_element(ENABLE_NODE, &debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &undebug_igmp_packets_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &undebug_igmp_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_cmd); + install_element(ENABLE_NODE, &no_debug_pim_cmd); + install_element(ENABLE_NODE, &undebug_pim_cmd); + install_element(ENABLE_NODE, &debug_pim_events_cmd); + install_element(ENABLE_NODE, &no_debug_pim_events_cmd); + install_element(ENABLE_NODE, &undebug_pim_events_cmd); + install_element(ENABLE_NODE, &debug_pim_packets_cmd); + install_element(ENABLE_NODE, &no_debug_pim_packets_cmd); + install_element(ENABLE_NODE, &undebug_pim_packets_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_cmd); + install_element(ENABLE_NODE, &no_debug_pim_trace_cmd); + install_element(ENABLE_NODE, &undebug_pim_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &undebug_pim_zebra_cmd); + + install_element(CONFIG_NODE, &debug_igmp_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_cmd); + install_element(CONFIG_NODE, &undebug_igmp_cmd); + install_element(CONFIG_NODE, &debug_igmp_events_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); + install_element(CONFIG_NODE, &undebug_igmp_events_cmd); + install_element(CONFIG_NODE, &debug_igmp_packets_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); + install_element(CONFIG_NODE, &undebug_igmp_packets_cmd); + install_element(CONFIG_NODE, &debug_igmp_trace_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); + install_element(CONFIG_NODE, &undebug_igmp_trace_cmd); + install_element(CONFIG_NODE, &debug_pim_cmd); + install_element(CONFIG_NODE, &no_debug_pim_cmd); + install_element(CONFIG_NODE, &undebug_pim_cmd); + install_element(CONFIG_NODE, &debug_pim_events_cmd); + install_element(CONFIG_NODE, &no_debug_pim_events_cmd); + install_element(CONFIG_NODE, &undebug_pim_events_cmd); + install_element(CONFIG_NODE, &debug_pim_packets_cmd); + install_element(CONFIG_NODE, &no_debug_pim_packets_cmd); + install_element(CONFIG_NODE, &undebug_pim_packets_cmd); + install_element(CONFIG_NODE, &debug_pim_trace_cmd); + install_element(CONFIG_NODE, &no_debug_pim_trace_cmd); + install_element(CONFIG_NODE, &undebug_pim_trace_cmd); + install_element(CONFIG_NODE, &debug_pim_zebra_cmd); + install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd); + install_element(CONFIG_NODE, &undebug_pim_zebra_cmd); +} diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h new file mode 100644 index 000000000..c2bb61bba --- /dev/null +++ b/pimd/pim_cmd.h @@ -0,0 +1,56 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_CMD_H +#define PIM_CMD_H + +#define PIM_STR "PIM information\n" +#define IGMP_STR "IGMP information\n" +#define IGMP_GROUP_STR "IGMP groups information\n" +#define IGMP_SOURCE_STR "IGMP sources information\n" +#define IFACE_PIM_STR "Enable PIM SSM operation\n" +#define IFACE_IGMP_STR "Enable IGMP operation\n" +#define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" +#define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "IGMP max query response value (seconds)\n" +#define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n" +#define DEBUG_IGMP_STR "IGMP protocol activity\n" +#define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n" +#define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n" +#define DEBUG_IGMP_TRACE_STR "IGMP internal daemon activity\n" +#define DEBUG_PIM_STR "PIM protocol activity\n" +#define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" +#define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" +#define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" +#define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" +#define CLEAR_IP_IGMP_STR "IGMP clear commands\n" +#define CLEAR_IP_PIM_STR "PIM clear commands\n" +#define MROUTE_STR "IP multicast routing table\n" + +#define PIM_CMD_NO "no" +#define PIM_CMD_IP_MULTICAST_ROUTING "ip multicast-routing" +#define PIM_CMD_IP_IGMP_QUERY_INTERVAL "ip igmp query-interval" +#define PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME "ip igmp query-max-response-time" +#define PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC "ip igmp query-max-response-time-dsec" + +void pim_cmd_init(void); + +#endif /* PIM_CMD_H */ diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c new file mode 100644 index 000000000..8b710b8c0 --- /dev/null +++ b/pimd/pim_hello.c @@ -0,0 +1,529 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" + +#include "pimd.h" +#include "pim_pim.h" +#include "pim_str.h" +#include "pim_tlv.h" +#include "pim_util.h" +#include "pim_hello.h" +#include "pim_iface.h" +#include "pim_neighbor.h" +#include "pim_upstream.h" + +static void on_trace(const char *label, + struct interface *ifp, struct in_addr src) +{ + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src, src_str, sizeof(src_str)); + zlog_debug("%s: from %s on %s", + label, src_str, ifp->name); + } +} + +static void tlv_trace_bool(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int isset, int value) +{ + if (isset) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d", + label, + src_str, ifname, + tlv_name, value); + } +} + +static void tlv_trace_uint16(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int isset, uint16_t value) +{ + if (isset) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", + label, + src_str, ifname, + tlv_name, value); + } +} + +static void tlv_trace_uint32(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int isset, uint32_t value) +{ + if (isset) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", + label, + src_str, ifname, + tlv_name, value); + } +} + +static void tlv_trace_uint32_hex(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int isset, uint32_t value) +{ + if (isset) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x", + label, + src_str, ifname, + tlv_name, value); + } +} + +#if 0 +static void tlv_trace(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int isset) +{ + if (isset) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello option from %s on interface %s: %s", + label, + src_str, ifname, + tlv_name); + } +} +#endif + +static void tlv_trace_list(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int isset, struct list *addr_list) +{ + if (isset) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%x", + label, + src_str, ifname, + tlv_name, + addr_list ? ((int) listcount(addr_list)) : -1, + (unsigned) addr_list); + } +} + +#define FREE_ADDR_LIST \ + if (hello_option_addr_list) { \ + list_delete(hello_option_addr_list); \ + } + +#define FREE_ADDR_LIST_THEN_RETURN(code) \ +{ \ + FREE_ADDR_LIST \ + return (code); \ +} + +int pim_hello_recv(struct interface *ifp, + struct in_addr src_addr, + char *tlv_buf, int tlv_buf_size) +{ + struct pim_interface *pim_ifp; + struct pim_neighbor *neigh; + char *tlv_curr; + char *tlv_pastend; + pim_hello_options hello_options = 0; /* bit array recording options found */ + uint16_t hello_option_holdtime = 0; + uint16_t hello_option_propagation_delay = 0; + uint16_t hello_option_override_interval = 0; + uint32_t hello_option_dr_priority = 0; + uint32_t hello_option_generation_id = 0; + struct list *hello_option_addr_list = 0; + + on_trace(__PRETTY_FUNCTION__, ifp, src_addr); + + pim_ifp = ifp->info; + zassert(pim_ifp); + + ++pim_ifp->pim_ifstat_hello_recv; + + /* + Parse PIM hello TLVs + */ + zassert(tlv_buf_size >= 0); + tlv_curr = tlv_buf; + tlv_pastend = tlv_buf + tlv_buf_size; + + while (tlv_curr < tlv_pastend) { + uint16_t option_type; + uint16_t option_len; + int remain = tlv_pastend - tlv_curr; + + if (remain < PIM_TLV_MIN_SIZE) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", + __PRETTY_FUNCTION__, + remain, PIM_TLV_MIN_SIZE, + src_str, ifp->name); + FREE_ADDR_LIST_THEN_RETURN(-1); + } + + option_type = PIM_TLV_GET_TYPE(tlv_curr); + tlv_curr += PIM_TLV_TYPE_SIZE; + option_len = PIM_TLV_GET_LENGTH(tlv_curr); + tlv_curr += PIM_TLV_LENGTH_SIZE; + + if ((tlv_curr + option_len) > tlv_pastend) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: long PIM hello TLV type=%d length=%d > max=%d from %s on interface %s", + __PRETTY_FUNCTION__, + option_type, option_len, tlv_pastend - tlv_curr, + src_str, ifp->name); + FREE_ADDR_LIST_THEN_RETURN(-2); + } + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", + __PRETTY_FUNCTION__, + remain, + option_type, option_len, + src_str, ifp->name); + } + + switch (option_type) { + case PIM_MSG_OPTION_TYPE_HOLDTIME: + if (pim_tlv_parse_holdtime(ifp->name, src_addr, + &hello_options, + &hello_option_holdtime, + option_len, + tlv_curr)) { + FREE_ADDR_LIST_THEN_RETURN(-3); + } + break; + case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY: + if (pim_tlv_parse_lan_prune_delay(ifp->name, src_addr, + &hello_options, + &hello_option_propagation_delay, + &hello_option_override_interval, + option_len, + tlv_curr)) { + FREE_ADDR_LIST_THEN_RETURN(-4); + } + break; + case PIM_MSG_OPTION_TYPE_DR_PRIORITY: + if (pim_tlv_parse_dr_priority(ifp->name, src_addr, + &hello_options, + &hello_option_dr_priority, + option_len, + tlv_curr)) { + FREE_ADDR_LIST_THEN_RETURN(-5); + } + break; + case PIM_MSG_OPTION_TYPE_GENERATION_ID: + if (pim_tlv_parse_generation_id(ifp->name, src_addr, + &hello_options, + &hello_option_generation_id, + option_len, + tlv_curr)) { + FREE_ADDR_LIST_THEN_RETURN(-6); + } + break; + case PIM_MSG_OPTION_TYPE_ADDRESS_LIST: + if (pim_tlv_parse_addr_list(ifp->name, src_addr, + &hello_options, + &hello_option_addr_list, + option_len, + tlv_curr)) { + return -7; + } + break; + case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", + __PRETTY_FUNCTION__, + option_type, option_len, + src_str, ifp->name); + } + break; + default: + { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", + __PRETTY_FUNCTION__, + option_type, option_len, + src_str, ifp->name); + } + } + + tlv_curr += option_len; + } + + /* + Check received PIM hello options + */ + + if (PIM_DEBUG_PIM_TRACE) { + tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME), + hello_option_holdtime); + tlv_trace_uint16(__PRETTY_FUNCTION__, "propagation_delay", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), + hello_option_propagation_delay); + tlv_trace_uint16(__PRETTY_FUNCTION__, "override_interval", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), + hello_option_override_interval); + tlv_trace_bool(__PRETTY_FUNCTION__, "can_disable_join_suppression", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)); + tlv_trace_uint32(__PRETTY_FUNCTION__, "dr_priority", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY), + hello_option_dr_priority); + tlv_trace_uint32_hex(__PRETTY_FUNCTION__, "generation_id", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID), + hello_option_generation_id); + tlv_trace_list(__PRETTY_FUNCTION__, "address_list", + ifp->name, src_addr, + PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_ADDRESS_LIST), + hello_option_addr_list); + } + + if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: PIM hello missing holdtime from %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + } + + /* + New neighbor? + */ + + neigh = pim_neighbor_find(ifp, src_addr); + if (!neigh) { + /* Add as new neighbor */ + + neigh = pim_neighbor_add(ifp, src_addr, + hello_options, + hello_option_holdtime, + hello_option_propagation_delay, + hello_option_override_interval, + hello_option_dr_priority, + hello_option_generation_id, + hello_option_addr_list); + if (!neigh) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: failure creating PIM neighbor %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + FREE_ADDR_LIST_THEN_RETURN(-8); + } + + /* actual addr list has been saved under neighbor */ + return 0; + } + + /* + Received generation ID ? + */ + + if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) { + /* GenID mismatch ? */ + if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) || + (hello_option_generation_id != neigh->generation_id)) { + + /* GenID changed */ + + pim_upstream_rpf_genid_changed(neigh->source_addr); + + /* GenID mismatch, then replace neighbor */ + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", + __PRETTY_FUNCTION__, + hello_option_generation_id, + neigh->generation_id, + src_str, ifp->name); + } + + pim_upstream_rpf_genid_changed(neigh->source_addr); + + pim_neighbor_delete(ifp, neigh, "GenID mismatch"); + neigh = pim_neighbor_add(ifp, src_addr, + hello_options, + hello_option_holdtime, + hello_option_propagation_delay, + hello_option_override_interval, + hello_option_dr_priority, + hello_option_generation_id, + hello_option_addr_list); + if (!neigh) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: failure re-creating PIM neighbor %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + FREE_ADDR_LIST_THEN_RETURN(-9); + } + /* actual addr list is saved under neighbor */ + return 0; + + } /* GenId mismatch: replace neighbor */ + + } /* GenId received */ + + /* + Update existing neighbor + */ + + pim_neighbor_update(neigh, + hello_options, + hello_option_holdtime, + hello_option_dr_priority, + hello_option_addr_list); + /* actual addr list is saved under neighbor */ + return 0; +} + +int pim_hello_build_tlv(const char *ifname, + char *tlv_buf, int tlv_buf_size, + uint16_t holdtime, + uint32_t dr_priority, + uint32_t generation_id, + uint16_t propagation_delay, + uint16_t override_interval, + int can_disable_join_suppression, + struct list *ifconnected) +{ + char *curr = tlv_buf; + char *pastend = tlv_buf + tlv_buf_size; + char *tmp; + + /* + * Append options + */ + + /* Holdtime */ + curr = pim_tlv_append_uint16(curr, + pastend, + PIM_MSG_OPTION_TYPE_HOLDTIME, + holdtime); + if (!curr) { + zlog_warn("%s: could not set PIM hello Holdtime option for interface %s", + __PRETTY_FUNCTION__, ifname); + return -1; + } + + /* LAN Prune Delay */ + tmp = pim_tlv_append_2uint16(curr, + pastend, + PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY, + propagation_delay, + override_interval); + if (!tmp) { + zlog_warn("%s: could not set PIM LAN Prune Delay option for interface %s", + __PRETTY_FUNCTION__, ifname); + return -1; + } + if (can_disable_join_suppression) { + *((uint8_t*)(curr) + 4) |= 0x80; /* enable T bit */ + } + curr = tmp; + + /* DR Priority */ + curr = pim_tlv_append_uint32(curr, + pastend, + PIM_MSG_OPTION_TYPE_DR_PRIORITY, + dr_priority); + if (!curr) { + zlog_warn("%s: could not set PIM hello DR Priority option for interface %s", + __PRETTY_FUNCTION__, ifname); + return -2; + } + + /* Generation ID */ + curr = pim_tlv_append_uint32(curr, + pastend, + PIM_MSG_OPTION_TYPE_GENERATION_ID, + generation_id); + if (!curr) { + zlog_warn("%s: could not set PIM hello Generation ID option for interface %s", + __PRETTY_FUNCTION__, ifname); + return -3; + } + + /* Secondary Address List */ + if (ifconnected) { + curr = pim_tlv_append_addrlist_ucast(curr, + pastend, + ifconnected); + if (!curr) { + zlog_warn("%s: could not set PIM hello Secondary Address List option for interface %s", + __PRETTY_FUNCTION__, ifname); + return -4; + } + } + + return curr - tlv_buf; +} + +/* + RFC 4601: 4.3.1. Sending Hello Messages + + Thus, if a router needs to send a Join/Prune or Assert message on an + interface on which it has not yet sent a Hello message with the + currently configured IP address, then it MUST immediately send the + relevant Hello message without waiting for the Hello Timer to + expire, followed by the Join/Prune or Assert message. +*/ +void pim_hello_require(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + + pim_ifp = ifp->info; + + zassert(pim_ifp); + + if (pim_ifp->pim_ifstat_hello_sent) + return; + + pim_hello_restart_now(ifp); /* Send hello and restart timer */ +} diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h new file mode 100644 index 000000000..90a11ba6a --- /dev/null +++ b/pimd/pim_hello.h @@ -0,0 +1,46 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_HELLO_H +#define PIM_HELLO_H + +#include + +#include "if.h" + +int pim_hello_recv(struct interface *ifp, + struct in_addr src_addr, + char *tlv_buf, int tlv_buf_size); + +int pim_hello_build_tlv(const char *ifname, + char *tlv_buf, int tlv_buf_size, + uint16_t holdtime, + uint32_t dr_priority, + uint32_t generation_id, + uint16_t propagation_delay, + uint16_t override_interval, + int can_disable_join_suppression, + struct list *ifconnected); + +void pim_hello_require(struct interface *ifp); + +#endif /* PIM_HELLO_H */ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c new file mode 100644 index 000000000..b4fbaec59 --- /dev/null +++ b/pimd/pim_iface.c @@ -0,0 +1,1132 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "if.h" +#include "log.h" +#include "vty.h" +#include "memory.h" +#include "prefix.h" + +#include "pimd.h" +#include "pim_iface.h" +#include "pim_igmp.h" +#include "pim_mroute.h" +#include "pim_oil.h" +#include "pim_str.h" +#include "pim_pim.h" +#include "pim_neighbor.h" +#include "pim_ifchannel.h" +#include "pim_rand.h" +#include "pim_sock.h" + +static void pim_if_igmp_join_del_all(struct interface *ifp); + +void pim_if_init() +{ + if_init(); +} + +static void *if_list_clean(struct pim_interface *pim_ifp) +{ + if (pim_ifp->igmp_join_list) { + list_delete(pim_ifp->igmp_join_list); + } + + if (pim_ifp->igmp_socket_list) { + list_delete(pim_ifp->igmp_socket_list); + } + + if (pim_ifp->pim_neighbor_list) { + list_delete(pim_ifp->pim_neighbor_list); + } + + if (pim_ifp->pim_ifchannel_list) { + list_delete(pim_ifp->pim_ifchannel_list); + } + + XFREE(MTYPE_PIM_INTERFACE, pim_ifp); + + return 0; +} + +struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + zassert(!ifp->info); + + pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); + if (!pim_ifp) { + zlog_err("PIM XMALLOC(%d) failure", sizeof(*pim_ifp)); + return 0; + } + + pim_ifp->options = 0; + pim_ifp->mroute_vif_index = -1; + + pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; + pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; + pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; + + /* + RFC 3376: 8.3. Query Response Interval + The number of seconds represented by the [Query Response Interval] + must be less than the [Query Interval]. + */ + zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval); + + if (pim) + PIM_IF_DO_PIM(pim_ifp->options); + if (igmp) + PIM_IF_DO_IGMP(pim_ifp->options); + +#if 0 + /* FIXME: Should join? */ + PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); +#endif + + pim_ifp->igmp_join_list = 0; + pim_ifp->igmp_socket_list = 0; + pim_ifp->pim_neighbor_list = 0; + pim_ifp->pim_ifchannel_list = 0; + + /* list of struct igmp_sock */ + pim_ifp->igmp_socket_list = list_new(); + if (!pim_ifp->igmp_socket_list) { + zlog_err("%s %s: failure: igmp_socket_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return if_list_clean(pim_ifp); + } + pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free; + + /* list of struct pim_neighbor */ + pim_ifp->pim_neighbor_list = list_new(); + if (!pim_ifp->pim_neighbor_list) { + zlog_err("%s %s: failure: pim_neighbor_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return if_list_clean(pim_ifp); + } + pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free; + + /* list of struct pim_ifchannel */ + pim_ifp->pim_ifchannel_list = list_new(); + if (!pim_ifp->pim_ifchannel_list) { + zlog_err("%s %s: failure: pim_ifchannel_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return if_list_clean(pim_ifp); + } + pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; + + ifp->info = pim_ifp; + + pim_sock_reset(ifp); + + zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options)); + + if (PIM_MROUTE_IS_ENABLED) { + pim_if_add_vif(ifp); + } + + return pim_ifp; +} + +void pim_if_delete(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (pim_ifp->igmp_join_list) { + pim_if_igmp_join_del_all(ifp); + } + zassert(!pim_ifp->igmp_join_list); + + zassert(pim_ifp->igmp_socket_list); + zassert(!listcount(pim_ifp->igmp_socket_list)); + + zassert(pim_ifp->pim_neighbor_list); + zassert(!listcount(pim_ifp->pim_neighbor_list)); + + zassert(pim_ifp->pim_ifchannel_list); + zassert(!listcount(pim_ifp->pim_ifchannel_list)); + + if (PIM_MROUTE_IS_ENABLED) { + pim_if_del_vif(ifp); + } + + list_delete(pim_ifp->igmp_socket_list); + list_delete(pim_ifp->pim_neighbor_list); + list_delete(pim_ifp->pim_ifchannel_list); + + XFREE(MTYPE_PIM_INTERFACE, pim_ifp); + + ifp->info = 0; +} + +void pim_if_update_could_assert(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *next_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { + pim_ifchannel_update_could_assert(ch); + } +} + +static void pim_if_update_my_assert_metric(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *next_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { + pim_ifchannel_update_my_assert_metric(ch); + } +} + +static void pim_addr_change(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + pim_if_dr_election(ifp); /* Done TODO T30 */ + pim_if_update_join_desired(pim_ifp); /* depends on DR */ + pim_if_update_could_assert(ifp); /* depends on DR */ + pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ + pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */ + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + 1) Before an interface goes down or changes primary IP address, a + Hello message with a zero HoldTime should be sent immediately + (with the old IP address if the IP address changed). + -- FIXME See CAVEAT C13 + + 2) After an interface has changed its IP address, it MUST send a + Hello message with its new IP address. + -- DONE below + + 3) If an interface changes one of its secondary IP addresses, a + Hello message with an updated Address_List option and a non-zero + HoldTime should be sent immediately. + -- FIXME See TODO T31 + */ + pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */ + if (pim_ifp->pim_sock_fd < 0) + return; + pim_hello_restart_now(ifp); /* send hello and restart timer */ +} + +static void on_primary_address_change(struct interface *ifp, + const char *caller, + struct in_addr old_addr, + struct in_addr new_addr) +{ + struct pim_interface *pim_ifp; + + { + char old_str[100]; + char new_str[100]; + pim_inet4_dump("", old_addr, old_str, sizeof(old_str)); + pim_inet4_dump("", new_addr, new_str, sizeof(new_str)); + zlog_info("%s: %s: primary address changed from %s to %s on interface %s", + __PRETTY_FUNCTION__, caller, + old_str, new_str, ifp->name); + } + + pim_ifp = ifp->info; + + if (pim_ifp) { + if (PIM_IF_TEST_PIM(pim_ifp->options)) { + pim_addr_change(ifp); + } + } +} + +static void detect_primary_address_change(struct interface *ifp, + const char *caller) +{ + struct pim_interface *pim_ifp; + struct in_addr new_prim_addr; + + pim_ifp = ifp->info; + if (!pim_ifp) + return; + + new_prim_addr = pim_find_primary_addr(ifp); + + if (PIM_DEBUG_ZEBRA) { + char new_prim_str[100]; + char old_prim_str[100]; + pim_inet4_dump("", new_prim_addr, new_prim_str, sizeof(new_prim_str)); + pim_inet4_dump("", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str)); + zlog_debug("%s: old primary addr %s, new primary addr %s on interface %s", + __PRETTY_FUNCTION__, + old_prim_str, new_prim_str, ifp->name); + } + + if (new_prim_addr.s_addr != pim_ifp->primary_address.s_addr) { + struct in_addr old_addr = pim_ifp->primary_address; + pim_ifp->primary_address = new_prim_addr; + + on_primary_address_change(ifp, caller, old_addr, new_prim_addr); + } +} + +void pim_if_addr_add(struct connected *ifc) +{ + struct pim_interface *pim_ifp; + struct interface *ifp; + struct in_addr ifaddr; + + zassert(ifc); + + ifp = ifc->ifp; + zassert(ifp); + pim_ifp = ifp->info; + if (!pim_ifp) + return; + + if (!if_is_operative(ifp)) + return; + + ifaddr = ifc->address->u.prefix4; + + detect_primary_address_change(ifp, __PRETTY_FUNCTION__); + + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { + struct igmp_sock *igmp; + + /* lookup IGMP socket */ + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, + ifaddr); + if (!igmp) { + /* if addr new, add IGMP socket */ + pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp); + } + } /* igmp */ + + if (PIM_IF_TEST_PIM(pim_ifp->options)) { + + /* Interface has a valid primary address ? */ + if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + + /* Interface has a valid socket ? */ + if (pim_ifp->pim_sock_fd < 0) { + if (pim_sock_add(ifp)) { + zlog_warn("Failure creating PIM socket for interface %s", + ifp->name); + } + } + + } + } /* pim */ + + if (PIM_MROUTE_IS_ENABLED) { + /* + PIM or IGMP is enabled on interface, and there is at least one + address assigned, then try to create a vif_index. + */ + if (pim_ifp->mroute_vif_index < 0) { + pim_if_add_vif(ifp); + } + } +} + +static void pim_if_addr_del_igmp(struct connected *ifc) +{ + struct pim_interface *pim_ifp = ifc->ifp->info; + struct igmp_sock *igmp; + struct in_addr ifaddr; + + if (ifc->address->family != AF_INET) { + /* non-IPv4 address */ + return; + } + + if (!pim_ifp) { + /* IGMP not enabled on interface */ + return; + } + + ifaddr = ifc->address->u.prefix4; + + /* lookup IGMP socket */ + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, + ifaddr); + if (igmp) { + /* if addr found, del IGMP socket */ + igmp_sock_delete(igmp); + } +} + +static void pim_if_addr_del_pim(struct connected *ifc) +{ + struct pim_interface *pim_ifp = ifc->ifp->info; + + if (ifc->address->family != AF_INET) { + /* non-IPv4 address */ + return; + } + + if (!pim_ifp) { + /* PIM not enabled on interface */ + return; + } + + if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + /* Interface keeps a valid primary address */ + return; + } + + if (pim_ifp->pim_sock_fd < 0) { + /* Interface does not hold a valid socket any longer */ + return; + } + + /* + pim_sock_delete() closes the socket, stops read and timer threads, + and kills all neighbors. + */ + pim_sock_delete(ifc->ifp, "last address has been removed from interface"); +} + +void pim_if_addr_del(struct connected *ifc) +{ + struct interface *ifp; + + zassert(ifc); + ifp = ifc->ifp; + zassert(ifp); + + detect_primary_address_change(ifp, __PRETTY_FUNCTION__); + + pim_if_addr_del_igmp(ifc); + pim_if_addr_del_pim(ifc); +} + +void pim_if_addr_add_all(struct interface *ifp) +{ + struct connected *ifc; + struct listnode *node; + struct listnode *nextnode; + + /* PIM/IGMP enabled ? */ + if (!ifp->info) + return; + + for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + pim_if_addr_add(ifc); + } +} + +void pim_if_addr_del_all(struct interface *ifp) +{ + struct connected *ifc; + struct listnode *node; + struct listnode *nextnode; + + /* PIM/IGMP enabled ? */ + if (!ifp->info) + return; + + for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + pim_if_addr_del(ifc); + } +} + +void pim_if_addr_del_all_igmp(struct interface *ifp) +{ + struct connected *ifc; + struct listnode *node; + struct listnode *nextnode; + + /* PIM/IGMP enabled ? */ + if (!ifp->info) + return; + + for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + pim_if_addr_del_igmp(ifc); + } +} + +void pim_if_addr_del_all_pim(struct interface *ifp) +{ + struct connected *ifc; + struct listnode *node; + struct listnode *nextnode; + + /* PIM/IGMP enabled ? */ + if (!ifp->info) + return; + + for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + pim_if_addr_del_pim(ifc); + } +} + +static struct in_addr find_first_addr(struct interface *ifp) +{ + struct connected *ifc; + struct listnode *node; + struct in_addr addr; + + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + if (PIM_INADDR_IS_ANY(p->u.prefix4)) { + zlog_warn("%s: null IPv4 address connected to interface %s", + __PRETTY_FUNCTION__, ifp->name); + continue; + } + + return p->u.prefix4; + } + + addr.s_addr = PIM_NET_INADDR_ANY; + + return addr; +} + +struct in_addr pim_find_primary_addr(struct interface *ifp) +{ + return find_first_addr(ifp); +} + +/* + pim_if_add_vif() uses ifindex as vif_index + + see also pim_if_find_vifindex_by_ifindex() + */ +int pim_if_add_vif(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + struct in_addr ifaddr; + + zassert(pim_ifp); + + if (pim_ifp->mroute_vif_index > 0) { + zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d", + __PRETTY_FUNCTION__, + pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex); + return -1; + } + + if (ifp->ifindex < 1) { + zlog_warn("%s: ifindex=%d < 1 on interface %s", + __PRETTY_FUNCTION__, + ifp->ifindex, ifp->name); + return -2; + } + + if (ifp->ifindex >= MAXVIFS) { + zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s", + __PRETTY_FUNCTION__, + ifp->ifindex, MAXVIFS, ifp->name); + return -3; + } + + ifaddr = pim_ifp->primary_address; + if (PIM_INADDR_IS_ANY(ifaddr)) { + zlog_warn("%s: could not get address for interface %s ifindex=%d", + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex); + return -4; + } + + if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) { + /* pim_mroute_add_vif reported error */ + return -5; + } + + pim_ifp->mroute_vif_index = ifp->ifindex; + + /* + Update highest vif_index + */ + if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) { + qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index; + } + + return 0; +} + +static int iflist_find_highest_vif_index() +{ + struct listnode *ifnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + int highest_vif_index = -1; + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + if (pim_ifp->mroute_vif_index > highest_vif_index) { + highest_vif_index = pim_ifp->mroute_vif_index; + } + } + + return highest_vif_index; +} + +int pim_if_del_vif(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + int old_vif_index; + + if (pim_ifp->mroute_vif_index < 1) { + zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d", + __PRETTY_FUNCTION__, + pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex); + return -1; + } + + if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) { + /* pim_mroute_del_vif reported error */ + return -2; + } + + /* + Update highest vif_index + */ + + /* save old vif_index in order to compare with highest below */ + old_vif_index = pim_ifp->mroute_vif_index; + + pim_ifp->mroute_vif_index = -1; + + if (old_vif_index == qpim_mroute_oif_highest_vif_index) { + qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index(); + } + + return 0; +} + +void pim_if_add_vif_all() +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + if (!ifp->info) + continue; + + pim_if_add_vif(ifp); + } +} + +void pim_if_del_vif_all() +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + if (!ifp->info) + continue; + + pim_if_del_vif(ifp); + } +} + +struct interface *pim_if_find_by_vif_index(int vif_index) +{ + struct listnode *ifnode; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + if (ifp->info) { + struct pim_interface *pim_ifp; + pim_ifp = ifp->info; + if (vif_index == pim_ifp->mroute_vif_index) + return ifp; + } + } + + return 0; +} + +/* + pim_if_add_vif() uses ifindex as vif_index + */ +int pim_if_find_vifindex_by_ifindex(int ifindex) +{ + return ifindex; +} + +int pim_if_lan_delay_enabled(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0); + + return pim_ifp->pim_number_of_nonlandelay_neighbors == 0; +} + +uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp) +{ + if (pim_if_lan_delay_enabled(ifp)) { + struct pim_interface *pim_ifp; + pim_ifp = ifp->info; + return pim_ifp->pim_neighbors_highest_propagation_delay_msec; + } + else { + return PIM_DEFAULT_PROPAGATION_DELAY_MSEC; + } +} + +uint16_t pim_if_effective_override_interval_msec(struct interface *ifp) +{ + if (pim_if_lan_delay_enabled(ifp)) { + struct pim_interface *pim_ifp; + pim_ifp = ifp->info; + return pim_ifp->pim_neighbors_highest_override_interval_msec; + } + else { + return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; + } +} + +int pim_if_t_override_msec(struct interface *ifp) +{ + int effective_override_interval_msec; + int t_override_msec; + + effective_override_interval_msec = + pim_if_effective_override_interval_msec(ifp); + + t_override_msec = pim_rand_next(0, effective_override_interval_msec); + + return t_override_msec; +} + +uint16_t pim_if_jp_override_interval_msec(struct interface *ifp) +{ + return pim_if_effective_propagation_delay_msec(ifp) + + pim_if_effective_override_interval_msec(ifp); +} + +/* + RFC 4601: 4.1.6. State Summarization Macros + + The function NBR( I, A ) uses information gathered through PIM Hello + messages to map the IP address A of a directly connected PIM + neighbor router on interface I to the primary IP address of the same + router (Section 4.3.4). The primary IP address of a neighbor is the + address that it uses as the source of its PIM Hello messages. +*/ +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, + struct in_addr addr) +{ + struct listnode *neighnode; + struct pim_neighbor *neigh; + struct pim_interface *pim_ifp; + + zassert(ifp); + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + return 0; + } + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { + + /* primary address ? */ + if (neigh->source_addr.s_addr == addr.s_addr) + return neigh; + + /* secondary address ? */ + if (pim_neighbor_find_secondary(neigh, addr)) + return neigh; + } + + if (PIM_DEBUG_PIM_TRACE) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s: neighbor not found for address %s on interface %s", + __PRETTY_FUNCTION__, + addr_str, ifp->name); + } + + return 0; +} + +long pim_if_t_suppressed_msec(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + long t_suppressed_msec; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + /* join suppression disabled ? */ + if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)) + return 0; + + /* t_suppressed = t_periodic * rand(1.1, 1.4) */ + + t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400); + + return t_suppressed_msec; +} + +static void igmp_join_free(struct igmp_join *ij) +{ + XFREE(MTYPE_PIM_IGMP_JOIN, ij); +} + +static struct igmp_join *igmp_join_find(struct list *join_list, + struct in_addr group_addr, + struct in_addr source_addr) +{ + struct listnode *node; + struct igmp_join *ij; + + zassert(join_list); + + for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) { + if ((group_addr.s_addr == ij->group_addr.s_addr) && + (source_addr.s_addr == ij->source_addr.s_addr)) + return ij; + } + + return 0; +} + +static int igmp_join_sock(const char *ifname, + int ifindex, + struct in_addr group_addr, + struct in_addr source_addr) +{ + int join_fd; + + join_fd = pim_socket_raw(IPPROTO_IGMP); + if (join_fd < 0) { + return -1; + } + + if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) { + close(join_fd); + return -2; + } + + return join_fd; +} + +static struct igmp_join *igmp_join_new(struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct igmp_join *ij; + int join_fd; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr); + if (join_fd < 0) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s", + __PRETTY_FUNCTION__, + group_str, source_str, ifp->name); + return 0; + } + + ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij)); + if (!ij) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_err("%s: XMALLOC(%d) failure for IGMP group %s source %s on interface %s", + __PRETTY_FUNCTION__, + sizeof(*ij), group_str, source_str, ifp->name); + close(join_fd); + return 0; + } + + ij->sock_fd = join_fd; + ij->group_addr = group_addr; + ij->source_addr = source_addr; + + listnode_add(pim_ifp->igmp_join_list, ij); + + return ij; +} + +int pim_if_igmp_join_add(struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct igmp_join *ij; + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + return -1; + } + + if (!pim_ifp->igmp_join_list) { + pim_ifp->igmp_join_list = list_new(); + if (!pim_ifp->igmp_join_list) { + zlog_err("%s %s: failure: igmp_join_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return -2; + } + pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free; + } + + ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); + if (ij) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s", + __PRETTY_FUNCTION__, + group_str, source_str, ifp->name); + return -3; + } + + ij = igmp_join_new(ifp, group_addr, source_addr); + if (!ij) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s", + __PRETTY_FUNCTION__, + group_str, source_str, ifp->name); + return -4; + } + + return 0; +} + + + +int pim_if_igmp_join_del(struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct igmp_join *ij; + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + return -1; + } + + if (!pim_ifp->igmp_join_list) { + zlog_warn("%s: no IGMP join on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + return -2; + } + + ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); + if (!ij) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: could not find IGMP group %s source %s on interface %s", + __PRETTY_FUNCTION__, + group_str, source_str, ifp->name); + return -3; + } + + if (close(ij->sock_fd)) { + int e = errno; + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s", + __PRETTY_FUNCTION__, + ij->sock_fd, group_str, source_str, ifp->name, e, strerror(e)); + /* warning only */ + } + listnode_delete(pim_ifp->igmp_join_list, ij); + igmp_join_free(ij); + if (listcount(pim_ifp->igmp_join_list) < 1) { + list_delete(pim_ifp->igmp_join_list); + pim_ifp->igmp_join_list = 0; + } + + return 0; +} + +static void pim_if_igmp_join_del_all(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *nextnode; + struct igmp_join *ij; + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + return; + } + + if (!pim_ifp->igmp_join_list) + return; + + for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij)) + pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr); +} + +/* + RFC 4601 + + Transitions from "I am Assert Loser" State + + Current Winner's GenID Changes or NLT Expires + + The Neighbor Liveness Timer associated with the current winner + expires or we receive a Hello message from the current winner + reporting a different GenID from the one it previously reported. + This indicates that the current winner's interface or router has + gone down (and may have come back up), and so we must assume it no + longer knows it was the winner. + */ +void pim_if_assert_on_neighbor_down(struct interface *ifp, + struct in_addr neigh_addr) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *next_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { + /* Is (S,G,I) assert loser ? */ + if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) + continue; + /* Dead neighbor was winner ? */ + if (ch->ifassert_winner.s_addr != neigh_addr.s_addr) + continue; + + assert_action_a5(ch); + } +} + +void pim_if_update_join_desired(struct pim_interface *pim_ifp) +{ + struct listnode *ch_node; + struct pim_ifchannel *ch; + + /* clear off flag from interface's upstreams */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags); + } + + /* scan per-interface (S,G,I) state on this I interface */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + struct pim_upstream *up = ch->upstream; + + if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags)) + continue; + + /* update join_desired for the global (S,G) state */ + pim_upstream_update_join_desired(up); + PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags); + } +} + +void pim_if_update_assert_tracking_desired(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *next_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + if (!pim_ifp) + return; + + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { + pim_ifchannel_update_assert_tracking_desired(ch); + } +} diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h new file mode 100644 index 000000000..6ce866bad --- /dev/null +++ b/pimd/pim_iface.h @@ -0,0 +1,160 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_IFACE_H +#define PIM_IFACE_H + +#include + +#include "if.h" +#include "vty.h" + +#include "pim_igmp.h" + +#define PIM_IF_MASK_PIM (1 << 0) +#define PIM_IF_MASK_IGMP (1 << 1) +#define PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS (1 << 2) +#define PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION (1 << 3) + +#define PIM_IF_IS_DELETED(ifp) ((ifp)->ifindex == IFINDEX_INTERNAL) + +#define PIM_IF_TEST_PIM(options) (PIM_IF_MASK_PIM & (options)) +#define PIM_IF_TEST_IGMP(options) (PIM_IF_MASK_IGMP & (options)) +#define PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(options) (PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS & (options)) +#define PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) (PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION & (options)) + +#define PIM_IF_DO_PIM(options) ((options) |= PIM_IF_MASK_PIM) +#define PIM_IF_DO_IGMP(options) ((options) |= PIM_IF_MASK_IGMP) +#define PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(options) ((options) |= PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS) +#define PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) |= PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION) + +#define PIM_IF_DONT_PIM(options) ((options) &= ~PIM_IF_MASK_PIM) +#define PIM_IF_DONT_IGMP(options) ((options) &= ~PIM_IF_MASK_IGMP) +#define PIM_IF_DONT_IGMP_LISTEN_ALLROUTERS(options) ((options) &= ~PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS) +#define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION) + +struct pim_interface { + uint32_t options; /* bit vector */ + int mroute_vif_index; + struct in_addr primary_address; /* remember addr to detect change */ + + int igmp_default_robustness_variable; /* IGMPv3 QRV */ + int igmp_default_query_interval; /* IGMPv3 secs between general queries */ + int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs */ + struct list *igmp_socket_list; /* list of struct igmp_sock */ + struct list *igmp_join_list; /* list of struct igmp_join */ + + int pim_sock_fd; /* PIM socket file descriptor */ + struct thread *t_pim_sock_read; /* thread for reading PIM socket */ + int64_t pim_sock_creation; /* timestamp of PIM socket creation */ + + struct thread *t_pim_hello_timer; + int pim_hello_period; + int pim_default_holdtime; + int pim_triggered_hello_delay; + uint32_t pim_generation_id; + uint16_t pim_propagation_delay_msec; /* config */ + uint16_t pim_override_interval_msec; /* config */ + struct list *pim_neighbor_list; /* list of struct pim_neighbor */ + struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */ + + /* neighbors without lan_delay */ + int pim_number_of_nonlandelay_neighbors; + uint16_t pim_neighbors_highest_propagation_delay_msec; + uint16_t pim_neighbors_highest_override_interval_msec; + + /* DR Election */ + int64_t pim_dr_election_last; /* timestamp */ + int pim_dr_election_count; + struct in_addr pim_dr_addr; + uint32_t pim_dr_priority; /* config */ + int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ + + int64_t pim_ifstat_start; /* start timestamp for stats */ + uint32_t pim_ifstat_hello_sent; + uint32_t pim_ifstat_hello_sendfail; + uint32_t pim_ifstat_hello_recv; + uint32_t pim_ifstat_hello_recvfail; +}; + +/* + if default_holdtime is set (>= 0), use it; + otherwise default_holdtime is 3.5 * hello_period + */ +#define PIM_IF_DEFAULT_HOLDTIME(pim_ifp) \ + (((pim_ifp)->pim_default_holdtime < 0) ? \ + ((pim_ifp)->pim_hello_period * 7 / 2) : \ + ((pim_ifp)->pim_default_holdtime)) + +void pim_if_init(void); + +struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); +void pim_if_delete(struct interface *ifp); +int pim_if_igmp_listen(struct vty *vty, + struct interface *ifp); +void pim_if_addr_add(struct connected *ifc); +void pim_if_addr_del(struct connected *ifc); +void pim_if_addr_add_all(struct interface *ifp); +void pim_if_addr_del_all(struct interface *ifp); +void pim_if_addr_del_all_igmp(struct interface *ifp); +void pim_if_addr_del_all_pim(struct interface *ifp); + +int pim_if_add_vif(struct interface *ifp); +int pim_if_del_vif(struct interface *ifp); +void pim_if_add_vif_all(void); +void pim_if_del_vif_all(void); + +struct interface *pim_if_find_by_vif_index(int vif_index); +int pim_if_find_vifindex_by_ifindex(int ifindex); + +int pim_if_lan_delay_enabled(struct interface *ifp); +uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); +uint16_t pim_if_effective_override_interval_msec(struct interface *ifp); +uint16_t pim_if_jp_override_interval_msec(struct interface *ifp); +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, + struct in_addr addr); + +long pim_if_t_suppressed_msec(struct interface *ifp); +int pim_if_t_override_msec(struct interface *ifp); + +struct in_addr pim_find_primary_addr(struct interface *ifp); + +int pim_if_igmp_join_add(struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr); +int pim_if_igmp_join_del(struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr); + +void pim_if_update_could_assert(struct interface *ifp); + +void pim_if_assert_on_neighbor_down(struct interface *ifp, + struct in_addr neigh_addr); + +void pim_if_rpf_interface_changed(struct interface *old_rpf_ifp, + struct pim_upstream *up); + +void pim_if_update_join_desired(struct pim_interface *pim_ifp); + +void pim_if_update_assert_tracking_desired(struct interface *ifp); + +#endif /* PIM_IFACE_H */ diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c new file mode 100644 index 000000000..7f946cfdc --- /dev/null +++ b/pimd/pim_ifchannel.c @@ -0,0 +1,893 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "linklist.h" +#include "thread.h" +#include "memory.h" + +#include "pimd.h" +#include "pim_str.h" +#include "pim_iface.h" +#include "pim_ifchannel.h" +#include "pim_zebra.h" +#include "pim_time.h" +#include "pim_msg.h" +#include "pim_pim.h" +#include "pim_join.h" +#include "pim_rpf.h" +#include "pim_macro.h" + +void pim_ifchannel_free(struct pim_ifchannel *ch) +{ + zassert(!ch->t_ifjoin_expiry_timer); + zassert(!ch->t_ifjoin_prune_pending_timer); + zassert(!ch->t_ifassert_timer); + + XFREE(MTYPE_PIM_IFCHANNEL, ch); +} + +void pim_ifchannel_delete(struct pim_ifchannel *ch) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ch->interface->info; + zassert(pim_ifp); + + if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) { + pim_upstream_update_join_desired(ch->upstream); + } + + pim_upstream_del(ch->upstream); + + THREAD_OFF(ch->t_ifjoin_expiry_timer); + THREAD_OFF(ch->t_ifjoin_prune_pending_timer); + THREAD_OFF(ch->t_ifassert_timer); + + /* + notice that listnode_delete() can't be moved + into pim_ifchannel_free() because the later is + called by list_delete_all_node() + */ + listnode_delete(pim_ifp->pim_ifchannel_list, ch); + + pim_ifchannel_free(ch); +} + +#define IFCHANNEL_NOINFO(ch) \ + ( \ + ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \ + && \ + ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \ + && \ + ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \ + ) + +static void delete_on_noinfo(struct pim_ifchannel *ch) +{ + if (IFCHANNEL_NOINFO(ch)) { + + /* In NOINFO state, timers should have been cleared */ + zassert(!ch->t_ifjoin_expiry_timer); + zassert(!ch->t_ifjoin_prune_pending_timer); + zassert(!ch->t_ifassert_timer); + + pim_ifchannel_delete(ch); + } +} + +void pim_ifchannel_ifjoin_switch(const char *caller, + struct pim_ifchannel *ch, + enum pim_ifjoin_state new_state) +{ + enum pim_ifjoin_state old_state = ch->ifjoin_state; + + if (old_state == new_state) { + zlog_debug("%s calledby %s: non-transition on state %d (%s)", + __PRETTY_FUNCTION__, caller, new_state, + pim_ifchannel_ifjoin_name(new_state)); + return; + } + + zassert(old_state != new_state); + + ch->ifjoin_state = new_state; + + /* Transition to/from NOINFO ? */ + if ( + (old_state == PIM_IFJOIN_NOINFO) + || + (new_state == PIM_IFJOIN_NOINFO) + ) { + + if (PIM_DEBUG_PIM_EVENTS) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s", + ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"), + src_str, grp_str, ch->interface->name); + } + + /* + Record uptime of state transition to/from NOINFO + */ + ch->ifjoin_creation = pim_time_monotonic_sec(); + + pim_upstream_update_join_desired(ch->upstream); + pim_ifchannel_update_could_assert(ch); + pim_ifchannel_update_assert_tracking_desired(ch); + } +} + +const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state) +{ + switch (ifjoin_state) { + case PIM_IFJOIN_NOINFO: return "NOINFO"; + case PIM_IFJOIN_JOIN: return "JOIN"; + case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP"; + } + + return "ifjoin_bad_state"; +} + +const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state) +{ + switch (ifassert_state) { + case PIM_IFASSERT_NOINFO: return "NOINFO"; + case PIM_IFASSERT_I_AM_WINNER: return "WINNER"; + case PIM_IFASSERT_I_AM_LOSER: return "LOSER"; + } + + return "ifassert_bad_state"; +} + +/* + RFC 4601: 4.6.5. Assert State Macros + + AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I) + defaults to Infinity when in the NoInfo state. +*/ +void reset_ifassert_state(struct pim_ifchannel *ch) +{ + THREAD_OFF(ch->t_ifassert_timer); + + pim_ifassert_winner_set(ch, + PIM_IFASSERT_NOINFO, + qpim_inaddr_any, + qpim_infinite_assert_metric); +} + +static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp; + struct pim_upstream *up; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + up = pim_upstream_add(source_addr, group_addr); + if (!up) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return 0; + } + + ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch)); + if (!ch) { + zlog_err("%s: PIM XMALLOC(%d) failure", + __PRETTY_FUNCTION__, sizeof(*ch)); + return 0; + } + + ch->flags = 0; + ch->upstream = up; + ch->interface = ifp; + ch->source_addr = source_addr; + ch->group_addr = group_addr; + ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO; + + ch->ifjoin_state = PIM_IFJOIN_NOINFO; + ch->t_ifjoin_expiry_timer = 0; + ch->t_ifjoin_prune_pending_timer = 0; + ch->ifjoin_creation = 0; + + /* Assert state */ + ch->t_ifassert_timer = 0; + reset_ifassert_state(ch); + if (pim_macro_ch_could_assert_eval(ch)) + PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags); + else + PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags); + + if (pim_macro_assert_tracking_desired_eval(ch)) + PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags); + else + PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); + + ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); + + /* Attach to list */ + listnode_add(pim_ifp->pim_ifchannel_list, ch); + + zassert(IFCHANNEL_NOINFO(ch)); + + return ch; +} + +struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_interface *pim_ifp; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + zassert(ifp); + + pim_ifp = ifp->info; + + if (!pim_ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + ifp->name); + return 0; + } + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + if ( + (source_addr.s_addr == ch->source_addr.s_addr) && + (group_addr.s_addr == ch->group_addr.s_addr) + ) { + return ch; + } + } + + return 0; +} + +static void ifmembership_set(struct pim_ifchannel *ch, + enum pim_ifmembership membership) +{ + if (ch->local_ifmembership == membership) + return; + + { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_info("%s: (S,G)=(%s,%s) membership now is %s on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO", + ch->interface->name); + } + + ch->local_ifmembership = membership; + + pim_upstream_update_join_desired(ch->upstream); + pim_ifchannel_update_could_assert(ch); + pim_ifchannel_update_assert_tracking_desired(ch); +} + + +void pim_ifchannel_membership_clear(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *ch_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); + } +} + +void pim_ifchannel_delete_on_noinfo(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *next_node; + struct pim_ifchannel *ch; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { + delete_on_noinfo(ch); + } +} + +struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_ifchannel *ch; + char src_str[100]; + char grp_str[100]; + + ch = pim_ifchannel_find(ifp, source_addr, group_addr); + if (ch) + return ch; + + ch = pim_ifchannel_new(ifp, source_addr, group_addr); + if (ch) + return ch; + + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + + return 0; +} + +static void ifjoin_to_noinfo(struct pim_ifchannel *ch) +{ + pim_forward_stop(ch); + pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO); + delete_on_noinfo(ch); +} + +static int on_ifjoin_expiry_timer(struct thread *t) +{ + struct pim_ifchannel *ch; + + zassert(t); + ch = THREAD_ARG(t); + zassert(ch); + + ch->t_ifjoin_expiry_timer = 0; + + zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN); + + ifjoin_to_noinfo(ch); + /* ch may have been deleted */ + + return 0; +} + +static void prune_echo(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_interface *pim_ifp; + struct in_addr neigh_dst_addr; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + neigh_dst_addr = pim_ifp->primary_address; + + if (PIM_DEBUG_PIM_EVENTS) { + char source_str[100]; + char group_str[100]; + char neigh_dst_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str)); + zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s", + __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name); + } + + pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr, + 0 /* boolean: send_join=false (prune) */); +} + +static int on_ifjoin_prune_pending_timer(struct thread *t) +{ + struct pim_ifchannel *ch; + int send_prune_echo; /* boolean */ + struct interface *ifp; + struct pim_interface *pim_ifp; + struct in_addr ch_source; + struct in_addr ch_group; + + zassert(t); + ch = THREAD_ARG(t); + zassert(ch); + + ch->t_ifjoin_prune_pending_timer = 0; + + zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING); + + /* Send PruneEcho(S,G) ? */ + ifp = ch->interface; + pim_ifp = ifp->info; + send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1); + + /* Save (S,G) */ + ch_source = ch->source_addr; + ch_group = ch->group_addr; + + ifjoin_to_noinfo(ch); + /* from here ch may have been deleted */ + + if (send_prune_echo) + prune_echo(ifp, ch_source, ch_group); + + return 0; +} + +static void check_recv_upstream(int is_join, + struct interface *recv_ifp, + struct in_addr upstream, + struct in_addr source_addr, + struct in_addr group_addr, + uint8_t source_flags, + int holdtime) +{ + struct pim_upstream *up; + + /* Upstream (S,G) in Joined state ? */ + up = pim_upstream_find(source_addr, group_addr); + if (!up) + return; + if (up->join_state != PIM_UPSTREAM_JOINED) + return; + + /* Upstream (S,G) in Joined state */ + + if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { + /* RPF'(S,G) not found */ + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s %s: RPF'(%s,%s) not found", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str); + return; + } + + /* upstream directed to RPF'(S,G) ? */ + if (upstream.s_addr != up->rpf.rpf_addr.s_addr) { + char src_str[100]; + char grp_str[100]; + char up_str[100]; + char rpf_str[100]; + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", upstream, up_str, sizeof(up_str)); + pim_inet4_dump("", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, + up_str, rpf_str, recv_ifp->name); + return; + } + /* upstream directed to RPF'(S,G) */ + + if (is_join) { + /* Join(S,G) to RPF'(S,G) */ + pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime); + return; + } + + /* Prune to RPF'(S,G) */ + + if (source_flags & PIM_RPT_BIT_MASK) { + if (source_flags & PIM_WILDCARD_BIT_MASK) { + /* Prune(*,G) to RPF'(S,G) */ + pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", + up, up->rpf.rpf_addr); + return; + } + + /* Prune(S,G,rpt) to RPF'(S,G) */ + pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", + up, up->rpf.rpf_addr); + return; + } + + /* Prune(S,G) to RPF'(S,G) */ + pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up, + up->rpf.rpf_addr); +} + +static int nonlocal_upstream(int is_join, + struct interface *recv_ifp, + struct in_addr upstream, + struct in_addr source_addr, + struct in_addr group_addr, + uint8_t source_flags, + uint16_t holdtime) +{ + struct pim_interface *recv_pim_ifp; + int is_local; /* boolean */ + + recv_pim_ifp = recv_ifp->info; + zassert(recv_pim_ifp); + + is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr); + + if (PIM_DEBUG_PIM_TRACE) { + char up_str[100]; + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", upstream, up_str, sizeof(up_str)); + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s", + __PRETTY_FUNCTION__, + is_join ? "join" : "prune", + src_str, grp_str, + is_local ? "local" : "non-local", + up_str, recv_ifp->name); + } + + if (is_local) + return 0; + + /* + Since recv upstream addr was not directed to our primary + address, check if we should react to it in any way. + */ + check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr, + source_flags, holdtime); + + return 1; /* non-local */ +} + +void pim_ifchannel_join_add(struct interface *ifp, + struct in_addr neigh_addr, + struct in_addr upstream, + struct in_addr source_addr, + struct in_addr group_addr, + uint8_t source_flags, + uint16_t holdtime) +{ + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + + if (nonlocal_upstream(1 /* join */, ifp, upstream, + source_addr, group_addr, source_flags, holdtime)) { + return; + } + + ch = pim_ifchannel_add(ifp, source_addr, group_addr); + if (!ch) + return; + + /* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + Transitions from "I am Assert Loser" State + + Receive Join(S,G) on Interface I + + We receive a Join(S,G) that has the Upstream Neighbor Address + field set to my primary IP address on interface I. The action is + to transition to NoInfo state, delete this (S,G) assert state + (Actions A5 below), and allow the normal PIM Join/Prune mechanisms + to operate. + + Notice: The nonlocal_upstream() test above ensures the upstream + address of the join message is our primary address. + */ + if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { + char src_str[100]; + char grp_str[100]; + char neigh_str[100]; + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", neigh_addr, neigh_str, sizeof(neigh_str)); + zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s", + __PRETTY_FUNCTION__, + src_str, grp_str, neigh_str, ifp->name); + + assert_action_a5(ch); + } + + pim_ifp = ifp->info; + zassert(pim_ifp); + + switch (ch->ifjoin_state) { + case PIM_IFJOIN_NOINFO: + pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); + if (pim_macro_chisin_oiflist(ch)) { + pim_forward_start(ch); + } + break; + case PIM_IFJOIN_JOIN: + zassert(!ch->t_ifjoin_prune_pending_timer); + + /* + In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a + previously received join message with holdtime=0xFFFF. + */ + if (ch->t_ifjoin_expiry_timer) { + unsigned long remain = + thread_timer_remain_second(ch->t_ifjoin_expiry_timer); + if (remain > holdtime) { + /* + RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages + + Transitions from Join State + + The (S,G) downstream state machine on interface I remains in + Join state, and the Expiry Timer (ET) is restarted, set to + maximum of its current value and the HoldTime from the + triggering Join/Prune message. + + Conclusion: Do not change the ET if the current value is + higher than the received join holdtime. + */ + return; + } + } + THREAD_OFF(ch->t_ifjoin_expiry_timer); + break; + case PIM_IFJOIN_PRUNE_PENDING: + zassert(!ch->t_ifjoin_expiry_timer); + zassert(ch->t_ifjoin_prune_pending_timer); + THREAD_OFF(ch->t_ifjoin_prune_pending_timer); + pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); + break; + } + + zassert(!IFCHANNEL_NOINFO(ch)); + + if (holdtime != 0xFFFF) { + THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer, + on_ifjoin_expiry_timer, + ch, holdtime); + } +} + +void pim_ifchannel_prune(struct interface *ifp, + struct in_addr upstream, + struct in_addr source_addr, + struct in_addr group_addr, + uint8_t source_flags, + uint16_t holdtime) +{ + struct pim_ifchannel *ch; + int jp_override_interval_msec; + + if (nonlocal_upstream(0 /* prune */, ifp, upstream, + source_addr, group_addr, source_flags, holdtime)) { + return; + } + + ch = pim_ifchannel_add(ifp, source_addr, group_addr); + if (!ch) + return; + + switch (ch->ifjoin_state) { + case PIM_IFJOIN_NOINFO: + case PIM_IFJOIN_PRUNE_PENDING: + /* nothing to do */ + break; + case PIM_IFJOIN_JOIN: + { + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + + zassert(ch->t_ifjoin_expiry_timer); + zassert(!ch->t_ifjoin_prune_pending_timer); + + THREAD_OFF(ch->t_ifjoin_expiry_timer); + + pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING); + + if (listcount(pim_ifp->pim_neighbor_list) > 1) { + jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp); + } + else { + jp_override_interval_msec = 0; /* schedule to expire immediately */ + /* If we called ifjoin_prune() directly instead, care should + be taken not to use "ch" afterwards since it would be + deleted. */ + } + + THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer, + on_ifjoin_prune_pending_timer, + ch, jp_override_interval_msec); + + zassert(!ch->t_ifjoin_expiry_timer); + zassert(ch->t_ifjoin_prune_pending_timer); + } + break; + } + +} + +void pim_ifchannel_local_membership_add(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp; + + /* PIM enabled on interface? */ + pim_ifp = ifp->info; + if (!pim_ifp) + return; + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + return; + + ch = pim_ifchannel_add(ifp, source_addr, group_addr); + if (!ch) { + return; + } + + ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); + + zassert(!IFCHANNEL_NOINFO(ch)); +} + +void pim_ifchannel_local_membership_del(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp; + + /* PIM enabled on interface? */ + pim_ifp = ifp->info; + if (!pim_ifp) + return; + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + return; + + ch = pim_ifchannel_find(ifp, source_addr, group_addr); + if (!ch) + return; + + ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); + + delete_on_noinfo(ch); +} + +void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) +{ + int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)); + int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch)); + + if (new_couldassert == old_couldassert) + return; + + { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_info("%s: CouldAssert(%s,%s,%s) changed from %d to %d", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name, + old_couldassert, new_couldassert); + } + + if (new_couldassert) { + /* CouldAssert(S,G,I) switched from FALSE to TRUE */ + PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags); + } + else { + /* CouldAssert(S,G,I) switched from TRUE to FALSE */ + PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags); + + if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) { + assert_action_a4(ch); + } + } + + pim_ifchannel_update_my_assert_metric(ch); +} + +/* + my_assert_metric may be affected by: + + CouldAssert(S,G) + pim_ifp->primary_address + rpf->source_nexthop.mrib_metric_preference; + rpf->source_nexthop.mrib_route_metric; + */ +void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) +{ + struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch); + + if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric)) + return; + + { + char src_str[100]; + char grp_str[100]; + char old_addr_str[100]; + char new_addr_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str)); + pim_inet4_dump("", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str)); + zlog_info("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name, + ch->ifassert_my_metric.rpt_bit_flag, + ch->ifassert_my_metric.metric_preference, + ch->ifassert_my_metric.route_metric, + old_addr_str, + my_metric_new.rpt_bit_flag, + my_metric_new.metric_preference, + my_metric_new.route_metric, + new_addr_str); + } + + ch->ifassert_my_metric = my_metric_new; + + if (pim_assert_metric_better(&ch->ifassert_my_metric, + &ch->ifassert_winner_metric)) { + assert_action_a5(ch); + } +} + +void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch) +{ + int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)); + int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch)); + + if (new_atd == old_atd) + return; + + { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_info("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name, + old_atd, new_atd); + } + + if (new_atd) { + /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */ + PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags); + } + else { + /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */ + PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); + + if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { + assert_action_a5(ch); + } + } +} diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h new file mode 100644 index 000000000..e6f1c2947 --- /dev/null +++ b/pimd/pim_ifchannel.h @@ -0,0 +1,145 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_IFCHANNEL_H +#define PIM_IFCHANNEL_H + +#include + +#include "if.h" + +#include "pim_upstream.h" + +enum pim_ifmembership { + PIM_IFMEMBERSHIP_NOINFO, + PIM_IFMEMBERSHIP_INCLUDE +}; + +enum pim_ifjoin_state { + PIM_IFJOIN_NOINFO, + PIM_IFJOIN_JOIN, + PIM_IFJOIN_PRUNE_PENDING +}; + +enum pim_ifassert_state { + PIM_IFASSERT_NOINFO, + PIM_IFASSERT_I_AM_WINNER, + PIM_IFASSERT_I_AM_LOSER +}; + +struct pim_assert_metric { + uint32_t rpt_bit_flag; + uint32_t metric_preference; + uint32_t route_metric; + struct in_addr ip_address; /* neighbor router that sourced the Assert message */ +}; + +/* + Flag to detect change in CouldAssert(S,G,I) +*/ +#define PIM_IF_FLAG_MASK_COULD_ASSERT (1 << 0) +#define PIM_IF_FLAG_TEST_COULD_ASSERT(flags) ((flags) & PIM_IF_FLAG_MASK_COULD_ASSERT) +#define PIM_IF_FLAG_SET_COULD_ASSERT(flags) ((flags) |= PIM_IF_FLAG_MASK_COULD_ASSERT) +#define PIM_IF_FLAG_UNSET_COULD_ASSERT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_COULD_ASSERT) +/* + Flag to detect change in AssertTrackingDesired(S,G,I) +*/ +#define PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED (1 << 1) +#define PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(flags) ((flags) & PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) +#define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) +#define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) + +/* + Per-interface (S,G) state +*/ +struct pim_ifchannel { + struct in_addr source_addr; /* (S,G) source key */ + struct in_addr group_addr; /* (S,G) group key */ + struct interface *interface; /* backpointer to interface */ + uint32_t flags; + + /* IGMPv3 determined interface has local members for (S,G) ? */ + enum pim_ifmembership local_ifmembership; + + /* Per-interface (S,G) Join/Prune State (Section 4.1.4 of RFC4601) */ + enum pim_ifjoin_state ifjoin_state; + struct thread *t_ifjoin_expiry_timer; + struct thread *t_ifjoin_prune_pending_timer; + int64_t ifjoin_creation; /* Record uptime of ifjoin state */ + + /* Per-interface (S,G) Assert State (Section 4.6.1 of RFC4601) */ + enum pim_ifassert_state ifassert_state; + struct thread *t_ifassert_timer; + struct in_addr ifassert_winner; + struct pim_assert_metric ifassert_winner_metric; + int64_t ifassert_creation; /* Record uptime of ifassert state */ + struct pim_assert_metric ifassert_my_metric; + + /* Upstream (S,G) state */ + struct pim_upstream *upstream; +}; + +void pim_ifchannel_free(struct pim_ifchannel *ch); +void pim_ifchannel_delete(struct pim_ifchannel *ch); +void pim_ifchannel_membership_clear(struct interface *ifp); +void pim_ifchannel_delete_on_noinfo(struct interface *ifp); +struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr); +struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr); +void pim_ifchannel_join_add(struct interface *ifp, + struct in_addr neigh_addr, + struct in_addr upstream, + struct in_addr source_addr, + struct in_addr group_addr, + uint8_t source_flags, + uint16_t holdtime); +void pim_ifchannel_prune(struct interface *ifp, + struct in_addr upstream, + struct in_addr source_addr, + struct in_addr group_addr, + uint8_t source_flags, + uint16_t holdtime); +void pim_ifchannel_local_membership_add(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr); +void pim_ifchannel_local_membership_del(struct interface *ifp, + struct in_addr source_addr, + struct in_addr group_addr); + +void pim_ifchannel_ifjoin_switch(const char *caller, + struct pim_ifchannel *ch, + enum pim_ifjoin_state new_state); +const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state); +const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state); + +int pim_ifchannel_isin_oiflist(struct pim_ifchannel *ch); + +void reset_ifassert_state(struct pim_ifchannel *ch); + +void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch); +void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch); +void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch); + +#endif /* PIM_IFCHANNEL_H */ diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c new file mode 100644 index 000000000..e38ac96a7 --- /dev/null +++ b/pimd/pim_igmp.c @@ -0,0 +1,1411 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "memory.h" + +#include "pimd.h" +#include "pim_igmp.h" +#include "pim_igmpv3.h" +#include "pim_iface.h" +#include "pim_sock.h" +#include "pim_mroute.h" +#include "pim_str.h" +#include "pim_util.h" +#include "pim_time.h" +#include "pim_zebra.h" + +#define IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE (1) +#define IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE (2) +#define IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE (3) +#define IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE (4) +#define IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES (5) +#define IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES (6) + +static void group_timer_off(struct igmp_group *group); + +static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, + struct in_addr group_addr); + +static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_options) +{ + int fd; + int join = 0; + struct in_addr group; + + fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, 1 /* loop=true */); + if (fd < 0) + return -1; + + if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) { + if (inet_aton(PIM_ALL_ROUTERS, &group)) { + if (!pim_socket_join(fd, group, ifaddr, ifindex)) + ++join; + } + else { + zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), + PIM_ALL_ROUTERS, errno, strerror(errno)); + } + } + + /* + IGMP routers periodically send IGMP general queries to AllSystems=224.0.0.1 + IGMP routers must receive general queries for querier election. + */ + if (inet_aton(PIM_ALL_SYSTEMS, &group)) { + if (!pim_socket_join(fd, group, ifaddr, ifindex)) + ++join; + } + else { + zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), + PIM_ALL_SYSTEMS, errno, strerror(errno)); + } + + if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) { + if (!pim_socket_join(fd, group, ifaddr, ifindex)) { + ++join; + } + } + else { + zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), + PIM_ALL_IGMP_ROUTERS, errno, strerror(errno)); + } + + if (!join) { + zlog_err("IGMP socket fd=%d could not join any group on interface address %s", + fd, inet_ntoa(ifaddr)); + close(fd); + fd = -1; + } + + return fd; +} + +#undef IGMP_SOCK_DUMP + +#ifdef IGMP_SOCK_DUMP +static void igmp_sock_dump(array_t *igmp_sock_array) +{ + int size = array_size(igmp_sock_array); + for (int i = 0; i < size; ++i) { + + struct igmp_sock *igmp = array_get(igmp_sock_array, i); + + zlog_debug("%s %s: [%d/%d] igmp_addr=%s fd=%d", + __FILE__, __PRETTY_FUNCTION__, + i, size, + inet_ntoa(igmp->ifaddr), + igmp->fd); + } +} +#endif + +struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, + struct in_addr ifaddr) +{ + struct listnode *sock_node; + struct igmp_sock *igmp; + +#ifdef IGMP_SOCK_DUMP + igmp_sock_dump(igmp_sock_list); +#endif + + for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) + if (ifaddr.s_addr == igmp->ifaddr.s_addr) + return igmp; + + return 0; +} + +struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, + int fd) +{ + struct listnode *sock_node; + struct igmp_sock *igmp; + + for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) + if (fd == igmp->fd) + return igmp; + + return 0; +} + +static int pim_igmp_other_querier_expire(struct thread *t) +{ + struct igmp_sock *igmp; + + zassert(t); + igmp = THREAD_ARG(t); + zassert(igmp); + + zassert(igmp->t_other_querier_timer); + zassert(!igmp->t_igmp_query_timer); + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("%s: Querier %s resuming", + __PRETTY_FUNCTION__, + ifaddr_str); + } + + igmp->t_other_querier_timer = 0; + + /* + We are the current querier, then + re-start sending general queries. + */ + pim_igmp_general_query_on(igmp); + + return 0; +} + +void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp) +{ + long other_querier_present_interval_msec; + struct pim_interface *pim_ifp; + + zassert(igmp); + zassert(igmp->interface); + zassert(igmp->interface->info); + + pim_ifp = igmp->interface->info; + + if (igmp->t_other_querier_timer) { + /* + There is other querier present already, + then reset the other-querier-present timer. + */ + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("Querier %s resetting TIMER event for Other-Querier-Present", + ifaddr_str); + } + + THREAD_OFF(igmp->t_other_querier_timer); + zassert(!igmp->t_other_querier_timer); + } + else { + /* + We are the current querier, then stop sending general queries: + igmp->t_igmp_query_timer = 0; + */ + pim_igmp_general_query_off(igmp); + } + + /* + Since this socket is starting the other-querier-present timer, + there should not be periodic query timer for this socket. + */ + zassert(!igmp->t_igmp_query_timer); + + /* + RFC 3376: 8.5. Other Querier Present Interval + + The Other Querier Present Interval is the length of time that must + pass before a multicast router decides that there is no longer + another multicast router which should be the querier. This value + MUST be ((the Robustness Variable) times (the Query Interval)) plus + (one half of one Query Response Interval). + + other_querier_present_interval_msec = \ + igmp->querier_robustness_variable * \ + 1000 * igmp->querier_query_interval + \ + 100 * (pim_ifp->query_max_response_time_dsec >> 1); + */ + other_querier_present_interval_msec = + PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec); + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("Querier %s scheduling %ld.%03ld sec TIMER event for Other-Querier-Present", + ifaddr_str, + other_querier_present_interval_msec / 1000, + other_querier_present_interval_msec % 1000); + } + + THREAD_TIMER_MSEC_ON(master, igmp->t_other_querier_timer, + pim_igmp_other_querier_expire, + igmp, other_querier_present_interval_msec); +} + +void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp) +{ + zassert(igmp); + + if (PIM_DEBUG_IGMP_TRACE) { + if (igmp->t_other_querier_timer) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("IGMP querier %s fd=%d cancelling other-querier-present TIMER event on %s", + ifaddr_str, igmp->fd, igmp->interface->name); + } + } + THREAD_OFF(igmp->t_other_querier_timer); + zassert(!igmp->t_other_querier_timer); +} + +static int recv_igmp_query(struct igmp_sock *igmp, int query_version, + int max_resp_code, + struct in_addr from, const char *from_str, + char *igmp_msg, int igmp_msg_len) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + uint8_t resv_s_qrv; + uint8_t s_flag; + uint8_t qrv; + struct in_addr group_addr; + uint16_t recv_checksum; + uint16_t checksum; + + group_addr = *(struct in_addr *)(igmp_msg + 4); + + ifp = igmp->interface; + pim_ifp = ifp->info; + + recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET); + + /* for computing checksum */ + *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; + + checksum = pim_inet_checksum(igmp_msg, igmp_msg_len); + if (checksum != recv_checksum) { + zlog_warn("Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x", + query_version, from_str, ifp->name, recv_checksum, checksum); + return -1; + } + + if (PIM_DEBUG_IGMP_PACKETS) { + char group_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_debug("Recv IGMP query v%d from %s on %s: size=%d checksum=%x group=%s", + query_version, from_str, ifp->name, + igmp_msg_len, checksum, group_str); + } + + /* + RFC 3376: 6.6.2. Querier Election + + When a router receives a query with a lower IP address, it sets + the Other-Querier-Present timer to Other Querier Present Interval + and ceases to send queries on the network if it was the previously + elected querier. + */ + if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) { + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("%s: local address %s (%u) lost querier election to %s (%u)", + ifp->name, + ifaddr_str, ntohl(igmp->ifaddr.s_addr), + from_str, ntohl(from.s_addr)); + } + + pim_igmp_other_querier_timer_on(igmp); + } + + /* + RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) + + Routers adopt the QRV value from the most recently received Query + as their own [Robustness Variable] value, unless that most + recently received QRV was zero, in which case the receivers use + the default [Robustness Variable] value specified in section 8.1 + or a statically configured value. + */ + resv_s_qrv = igmp_msg[8]; + qrv = 7 & resv_s_qrv; + igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable; + + /* + RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) + + Multicast routers that are not the current querier adopt the QQI + value from the most recently received Query as their own [Query + Interval] value, unless that most recently received QQI was zero, + in which case the receiving routers use the default. + */ + if (igmp->t_other_querier_timer) { + /* other querier present */ + uint8_t qqic; + uint16_t qqi; + qqic = igmp_msg[9]; + qqi = igmp_msg_decode8to16(qqic); + igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval; + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)", + ifaddr_str, + qqi ? "recv-non-default" : "default", + igmp->querier_query_interval, + qqic, + from_str); + } + } + + /* + RFC 3376: 6.6.1. Timer Updates + + When a router sends or receives a query with a clear Suppress + Router-Side Processing flag, it must update its timers to reflect + the correct timeout values for the group or sources being queried. + + General queries don't trigger timer update. + */ + s_flag = (1 << 3) & resv_s_qrv; + if (!s_flag) { + /* s_flag is clear */ + + if (PIM_INADDR_IS_ANY(group_addr)) { + /* this is a general query */ + + /* log that general query should have the s_flag set */ + zlog_warn("General IGMP query v%d from %s on %s: Router-Side Processing flag is clear", + query_version, from_str, ifp->name); + } + else { + struct igmp_group *group; + + /* this is a non-general query: perform timer updates */ + + group = find_group_by_addr(igmp, group_addr); + if (group) { + int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET)); + + /* + RFC 3376: 6.6.1. Timer Updates + Query Q(G,A): Source Timer for sources in A are lowered to LMQT + Query Q(G): Group Timer is lowered to LMQT + */ + if (recv_num_sources < 1) { + /* Query Q(G): Group Timer is lowered to LMQT */ + + igmp_group_timer_lower_to_lmqt(group); + } + else { + /* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */ + + /* Scan sources in query and lower their timers to LMQT */ + struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET); + for (int i = 0; i < recv_num_sources; ++i) { + struct in_addr src_addr = sources[i]; + struct igmp_source *src = igmp_find_source_by_addr(group, src_addr); + if (src) { + igmp_source_timer_lower_to_lmqt(src); + } + } + } + + } + else { + char group_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_warn("IGMP query v%d from %s on %s: could not find group %s for timer update", + query_version, from_str, ifp->name, group_str); + } + } + } /* s_flag is clear: timer updates */ + + return 0; +} + +static int igmp_v3_report(struct igmp_sock *igmp, + struct in_addr from, const char *from_str, + char *igmp_msg, int igmp_msg_len) +{ + uint16_t recv_checksum; + uint16_t checksum; + int num_groups; + uint8_t *group_record; + uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len; + struct interface *ifp = igmp->interface; + + if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) { + zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d", + from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE); + return -1; + } + + recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET); + + /* for computing checksum */ + *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; + + checksum = pim_inet_checksum(igmp_msg, igmp_msg_len); + if (checksum != recv_checksum) { + zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x", + from_str, ifp->name, recv_checksum, checksum); + return -1; + } + + num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET)); + if (num_groups < 1) { + zlog_warn("Recv IGMP report v3 from %s on %s: missing group records", + from_str, ifp->name); + return -1; + } + + if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d", + from_str, ifp->name, igmp_msg_len, checksum, num_groups); + } + + group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; + + /* Scan groups */ + for (int i = 0; i < num_groups; ++i) { + struct in_addr rec_group; + uint8_t *sources; + uint8_t *src; + int rec_type; + int rec_auxdatalen; + int rec_num_sources; + int j; + + if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) { + zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end", + from_str, ifp->name); + return -1; + } + + rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET]; + rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET]; + rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET)); + + rec_group = *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET); + + if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s", + from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group)); + } + + /* Scan sources */ + + sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET; + + for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) { + + if ((src + 4) > report_pastend) { + zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end", + from_str, ifp->name); + return -1; + } + + if (PIM_DEBUG_IGMP_PACKETS) { + char src_str[200]; + + if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str))) + sprintf(src_str, ""); + + zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s", + from_str, ifp->name, i, inet_ntoa(rec_group), src_str); + } + } /* for (sources) */ + + switch (rec_type) { + case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE: + igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); + break; + case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE: + igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); + break; + case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE: + igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); + break; + case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE: + igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); + break; + case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES: + igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); + break; + case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES: + igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); + break; + default: + zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d", + from_str, ifp->name, rec_type); + } + + group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2); + + } /* for (group records) */ + + return 0; +} + +static void on_trace(const char *label, + struct interface *ifp, struct in_addr from) +{ + if (PIM_DEBUG_IGMP_TRACE) { + char from_str[100]; + pim_inet4_dump("", from, from_str, sizeof(from_str)); + zlog_debug("%s: from %s on %s", + label, from_str, ifp->name); + } +} + +static int igmp_v2_report(struct igmp_sock *igmp, + struct in_addr from, const char *from_str, + char *igmp_msg, int igmp_msg_len) +{ + struct interface *ifp = igmp->interface; + struct igmp_group *group; + struct in_addr group_addr; + + on_trace(__PRETTY_FUNCTION__, igmp->interface, from); + + if (igmp_msg_len != IGMP_V12_MSG_SIZE) { + zlog_warn("Recv IGMP report v2 from %s on %s: size=%d other than correct=%d", + from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); + return -1; + } + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_warn("%s %s: FIXME WRITEME", + __FILE__, __PRETTY_FUNCTION__); + } + + group_addr = *(struct in_addr *)(igmp_msg + 4); + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return -1; + } + + group->last_igmp_v2_report_dsec = pim_time_monotonic_dsec(); + + return 0; +} + +static int igmp_v2_leave(struct igmp_sock *igmp, + struct in_addr from, const char *from_str, + char *igmp_msg, int igmp_msg_len) +{ + struct interface *ifp = igmp->interface; + + on_trace(__PRETTY_FUNCTION__, igmp->interface, from); + + if (igmp_msg_len != IGMP_V12_MSG_SIZE) { + zlog_warn("Recv IGMP leave v2 from %s on %s: size=%d other than correct=%d", + from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); + return -1; + } + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_warn("%s %s: FIXME WRITEME", + __FILE__, __PRETTY_FUNCTION__); + } + + return 0; +} + +static int igmp_v1_report(struct igmp_sock *igmp, + struct in_addr from, const char *from_str, + char *igmp_msg, int igmp_msg_len) +{ + struct interface *ifp = igmp->interface; + struct igmp_group *group; + struct in_addr group_addr; + + on_trace(__PRETTY_FUNCTION__, igmp->interface, from); + + if (igmp_msg_len != IGMP_V12_MSG_SIZE) { + zlog_warn("Recv IGMP report v1 from %s on %s: size=%d other than correct=%d", + from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); + return -1; + } + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_warn("%s %s: FIXME WRITEME", + __FILE__, __PRETTY_FUNCTION__); + } + + group_addr = *(struct in_addr *)(igmp_msg + 4); + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return -1; + } + + group->last_igmp_v1_report_dsec = pim_time_monotonic_dsec(); + + return 0; +} + +int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) +{ + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + char *igmp_msg; + int igmp_msg_len; + int msg_type; + char from_str[100]; + char to_str[100]; + + if (len < sizeof(*ip_hdr)) { + zlog_warn("IGMP packet size=%d shorter than minimum=%d", + len, sizeof(*ip_hdr)); + return -1; + } + + ip_hdr = (struct ip *) buf; + + pim_inet4_dump("", ip_hdr->ip_src, from_str , sizeof(from_str)); + pim_inet4_dump("", ip_hdr->ip_dst, to_str , sizeof(to_str)); + + ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ + + if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug("Recv IP packet from %s to %s on %s: size=%d ip_header_size=%d ip_proto=%d", + from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p); + } + + if (ip_hdr->ip_p != PIM_IP_PROTO_IGMP) { + zlog_warn("IP packet protocol=%d is not IGMP=%d", + ip_hdr->ip_p, PIM_IP_PROTO_IGMP); + return -1; + } + + if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { + zlog_warn("IP packet header size=%d shorter than minimum=%d", + ip_hlen, PIM_IP_HEADER_MIN_LEN); + return -1; + } + if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { + zlog_warn("IP packet header size=%d greater than maximum=%d", + ip_hlen, PIM_IP_HEADER_MAX_LEN); + return -1; + } + + igmp_msg = buf + ip_hlen; + msg_type = *igmp_msg; + igmp_msg_len = len - ip_hlen; + + if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug("Recv IGMP packet from %s to %s on %s: ttl=%d msg_type=%d msg_size=%d", + from_str, to_str, igmp->interface->name, ip_hdr->ip_ttl, msg_type, + igmp_msg_len); + } + + if (igmp_msg_len < PIM_IGMP_MIN_LEN) { + zlog_warn("IGMP message size=%d shorter than minimum=%d", + igmp_msg_len, PIM_IGMP_MIN_LEN); + return -1; + } + + switch (msg_type) { + case PIM_IGMP_MEMBERSHIP_QUERY: + { + int max_resp_code = igmp_msg[1]; + int query_version; + + /* + RFC 3376: 7.1. Query Version Distinctions + IGMPv1 Query: length = 8 octets AND Max Resp Code field is zero + IGMPv2 Query: length = 8 octets AND Max Resp Code field is non-zero + IGMPv3 Query: length >= 12 octets + */ + + if (igmp_msg_len == 8) { + query_version = max_resp_code ? 2 : 1; + } + else if (igmp_msg_len >= 12) { + query_version = 3; + } + else { + zlog_warn("Unknown IGMP query version"); + return -1; + } + + return recv_igmp_query(igmp, query_version, max_resp_code, + ip_hdr->ip_src, from_str, + igmp_msg, igmp_msg_len); + } + + case PIM_IGMP_V3_MEMBERSHIP_REPORT: + return igmp_v3_report(igmp, ip_hdr->ip_src, from_str, + igmp_msg, igmp_msg_len); + + case PIM_IGMP_V2_MEMBERSHIP_REPORT: + return igmp_v2_report(igmp, ip_hdr->ip_src, from_str, + igmp_msg, igmp_msg_len); + + case PIM_IGMP_V1_MEMBERSHIP_REPORT: + return igmp_v1_report(igmp, ip_hdr->ip_src, from_str, + igmp_msg, igmp_msg_len); + + case PIM_IGMP_V2_LEAVE_GROUP: + return igmp_v2_leave(igmp, ip_hdr->ip_src, from_str, + igmp_msg, igmp_msg_len); + } + + zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type); + + return -1; +} + +static int pim_igmp_general_query(struct thread *t); + +void pim_igmp_general_query_on(struct igmp_sock *igmp) +{ + struct pim_interface *pim_ifp; + int startup_mode; + int query_interval; + + zassert(igmp); + zassert(igmp->interface); + + /* + Since this socket is starting as querier, + there should not exist a timer for other-querier-present. + */ + zassert(!igmp->t_other_querier_timer); + pim_ifp = igmp->interface->info; + zassert(pim_ifp); + + /* + RFC 3376: 8.6. Startup Query Interval + + The Startup Query Interval is the interval between General Queries + sent by a Querier on startup. Default: 1/4 the Query Interval. + */ + startup_mode = igmp->startup_query_count > 0; + if (startup_mode) { + --igmp->startup_query_count; + + /* query_interval = pim_ifp->igmp_default_query_interval >> 2; */ + query_interval = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval); + } + else { + query_interval = igmp->querier_query_interval; + } + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("Querier %s scheduling %d-second (%s) TIMER event for IGMP query on fd=%d", + ifaddr_str, + query_interval, + startup_mode ? "startup" : "non-startup", + igmp->fd); + } + igmp->t_igmp_query_timer = 0; + zassert(!igmp->t_igmp_query_timer); + THREAD_TIMER_ON(master, igmp->t_igmp_query_timer, + pim_igmp_general_query, + igmp, query_interval); +} + +void pim_igmp_general_query_off(struct igmp_sock *igmp) +{ + zassert(igmp); + + if (PIM_DEBUG_IGMP_TRACE) { + if (igmp->t_igmp_query_timer) { + char ifaddr_str[100]; + pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); + zlog_debug("IGMP querier %s fd=%d cancelling query TIMER event on %s", + ifaddr_str, igmp->fd, igmp->interface->name); + } + } + THREAD_OFF(igmp->t_igmp_query_timer); + zassert(!igmp->t_igmp_query_timer); +} + +/* Issue IGMP general query */ +static int pim_igmp_general_query(struct thread *t) +{ + char query_buf[PIM_IGMP_BUFSIZE_WRITE]; + struct igmp_sock *igmp; + struct in_addr dst_addr; + struct in_addr group_addr; + struct pim_interface *pim_ifp; + + zassert(t); + + igmp = THREAD_ARG(t); + + zassert(igmp); + zassert(igmp->interface); + zassert(igmp->interface->info); + + pim_ifp = igmp->interface->info; + + /* + RFC3376: 4.1.12. IP Destination Addresses for Queries + + In IGMPv3, General Queries are sent with an IP destination address + of 224.0.0.1, the all-systems multicast address. Group-Specific + and Group-and-Source-Specific Queries are sent with an IP + destination address equal to the multicast address of interest. + */ + + dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + group_addr.s_addr = PIM_NET_INADDR_ANY; + + if (PIM_DEBUG_IGMP_TRACE) { + char querier_str[100]; + char dst_str[100]; + pim_inet4_dump("", igmp->ifaddr, querier_str, + sizeof(querier_str)); + pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); + zlog_debug("Querier %s issuing IGMP general query to %s on %s", + querier_str, dst_str, igmp->interface->name); + } + + pim_igmp_send_membership_query(0 /* igmp_group */, + igmp->fd, + igmp->interface->name, + query_buf, + sizeof(query_buf), + 0 /* num_sources */, + dst_addr, + group_addr, + pim_ifp->igmp_query_max_response_time_dsec, + 1 /* s_flag: always set for general queries */, + igmp->querier_robustness_variable, + igmp->querier_query_interval); + + pim_igmp_general_query_on(igmp); + + return 0; +} + +static int pim_igmp_read(struct thread *t); + +static void igmp_read_on(struct igmp_sock *igmp) +{ + zassert(igmp); + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("Scheduling READ event on IGMP socket fd=%d", + igmp->fd); + } + igmp->t_igmp_read = 0; + zassert(!igmp->t_igmp_read); + THREAD_READ_ON(master, igmp->t_igmp_read, pim_igmp_read, igmp, igmp->fd); +} + +static int pim_igmp_read(struct thread *t) +{ + struct igmp_sock *igmp; + int fd; + struct sockaddr_in from; + struct sockaddr_in to; + socklen_t fromlen = sizeof(from); + socklen_t tolen = sizeof(to); + char buf[PIM_IGMP_BUFSIZE_READ]; + int len; + int ifindex = -1; + int result = -1; /* defaults to bad */ + + zassert(t); + + igmp = THREAD_ARG(t); + + zassert(igmp); + + fd = THREAD_FD(t); + + zassert(fd == igmp->fd); + + len = pim_socket_recvfromto(fd, buf, sizeof(buf), + &from, &fromlen, + &to, &tolen, + &ifindex); + if (len < 0) { + zlog_warn("Failure receiving IP IGMP packet on fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + goto done; + } + + if (PIM_DEBUG_IGMP_PACKETS) { + char from_str[100]; + char to_str[100]; + + if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) + sprintf(from_str, ""); + if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) + sprintf(to_str, ""); + + zlog_debug("Recv IP IGMP pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)", + len, from_str, to_str, fd, ifindex, igmp->interface->ifindex); + } + +#ifdef PIM_CHECK_RECV_IFINDEX_SANITY + /* ifindex sanity check */ + if (ifindex != (int) igmp->interface->ifindex) { + char from_str[100]; + char to_str[100]; + struct interface *ifp; + + if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) + sprintf(from_str, ""); + if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) + sprintf(to_str, ""); + + ifp = if_lookup_by_index(ifindex); + if (ifp) { + zassert(ifindex == (int) ifp->ifindex); + } + +#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH + zlog_warn("Interface mismatch: recv IGMP pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", + from_str, to_str, fd, + ifindex, ifp ? ifp->name : "", + igmp->interface->ifindex, igmp->interface->name); +#endif + goto done; + } +#endif + + if (pim_igmp_packet(igmp, buf, len)) { + goto done; + } + + result = 0; /* good */ + + done: + igmp_read_on(igmp); + + return result; +} + +static void sock_close(struct igmp_sock *igmp) +{ + pim_igmp_other_querier_timer_off(igmp); + pim_igmp_general_query_off(igmp); + + if (PIM_DEBUG_IGMP_TRACE) { + if (igmp->t_igmp_read) { + zlog_debug("Cancelling READ event on IGMP socket %s fd=%d on interface %s", + inet_ntoa(igmp->ifaddr), igmp->fd, + igmp->interface->name); + } + } + THREAD_OFF(igmp->t_igmp_read); + zassert(!igmp->t_igmp_read); + + if (close(igmp->fd)) { + zlog_err("Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s", + inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name, + errno, strerror(errno)); + } + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("Deleted IGMP socket %s fd=%d on interface %s", + inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name); + } +} + +void igmp_startup_mode_on(struct igmp_sock *igmp) +{ + struct pim_interface *pim_ifp; + + pim_ifp = igmp->interface->info; + + /* + RFC 3376: 8.7. Startup Query Count + + The Startup Query Count is the number of Queries sent out on + startup, separated by the Startup Query Interval. Default: the + Robustness Variable. + */ + igmp->startup_query_count = igmp->querier_robustness_variable; + + /* + Since we're (re)starting, reset QQI to default Query Interval + */ + igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; +} + +static void igmp_group_free(struct igmp_group *group) +{ + zassert(!group->t_group_query_retransmit_timer); + zassert(!group->t_group_timer); + zassert(group->group_source_list); + zassert(!listcount(group->group_source_list)); + + list_free(group->group_source_list); + + XFREE(MTYPE_PIM_IGMP_GROUP, group); +} + +static void igmp_group_delete(struct igmp_group *group) +{ + struct listnode *src_node; + struct listnode *src_nextnode; + struct igmp_source *src; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("Deleting IGMP group %s from socket %d interface %s", + group_str, + group->group_igmp_sock->fd, + group->group_igmp_sock->interface->name); + } + + for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_nextnode, src)) { + igmp_source_delete(src); + } + + if (group->t_group_query_retransmit_timer) { + THREAD_OFF(group->t_group_query_retransmit_timer); + zassert(!group->t_group_query_retransmit_timer); + } + + group_timer_off(group); + listnode_delete(group->group_igmp_sock->igmp_group_list, group); + igmp_group_free(group); +} + +void igmp_group_delete_empty_include(struct igmp_group *group) +{ + zassert(!group->group_filtermode_isexcl); + zassert(!listcount(group->group_source_list)); + + igmp_group_delete(group); +} + +void igmp_sock_free(struct igmp_sock *igmp) +{ + zassert(!igmp->t_igmp_read); + zassert(!igmp->t_igmp_query_timer); + zassert(!igmp->t_other_querier_timer); + zassert(igmp->igmp_group_list); + zassert(!listcount(igmp->igmp_group_list)); + + list_free(igmp->igmp_group_list); + + XFREE(MTYPE_PIM_IGMP_SOCKET, igmp); +} + +void igmp_sock_delete(struct igmp_sock *igmp) +{ + struct pim_interface *pim_ifp; + struct listnode *grp_node; + struct listnode *grp_nextnode; + struct igmp_group *grp; + + for (ALL_LIST_ELEMENTS(igmp->igmp_group_list, grp_node, grp_nextnode, grp)) { + igmp_group_delete(grp); + } + + sock_close(igmp); + + pim_ifp = igmp->interface->info; + + listnode_delete(pim_ifp->igmp_socket_list, igmp); + + igmp_sock_free(igmp); +} + +static struct igmp_sock *igmp_sock_new(int fd, + struct in_addr ifaddr, + struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct igmp_sock *igmp; + + pim_ifp = ifp->info; + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("Creating IGMP socket fd=%d for address %s on interface %s", + fd, inet_ntoa(ifaddr), ifp->name); + } + + igmp = XMALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp)); + if (!igmp) { + zlog_warn("%s %s: XMALLOC() failure", + __FILE__, __PRETTY_FUNCTION__); + return 0; + } + + igmp->igmp_group_list = list_new(); + if (!igmp->igmp_group_list) { + zlog_err("%s %s: failure: igmp_group_list = list_new()", + __FILE__, __PRETTY_FUNCTION__); + return 0; + } + igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free; + + igmp->fd = fd; + igmp->interface = ifp; + igmp->ifaddr = ifaddr; + igmp->t_igmp_read = 0; + igmp->t_igmp_query_timer = 0; + igmp->t_other_querier_timer = 0; /* no other querier present */ + igmp->querier_robustness_variable = pim_ifp->igmp_default_robustness_variable; + igmp->sock_creation = pim_time_monotonic_sec(); + + /* + igmp_startup_mode_on() will reset QQI: + + igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; + */ + igmp_startup_mode_on(igmp); + + igmp_read_on(igmp); + pim_igmp_general_query_on(igmp); + + return igmp; +} + +struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, + struct in_addr ifaddr, + struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct igmp_sock *igmp; + int fd; + + pim_ifp = ifp->info; + + fd = igmp_sock_open(ifaddr, ifp->ifindex, pim_ifp->options); + if (fd < 0) { + zlog_warn("Could not open IGMP socket for %s on %s", + inet_ntoa(ifaddr), ifp->name); + return 0; + } + + igmp = igmp_sock_new(fd, ifaddr, ifp); + if (!igmp) { + zlog_err("%s %s: igmp_sock_new() failure", + __FILE__, __PRETTY_FUNCTION__); + close(fd); + return 0; + } + + listnode_add(igmp_sock_list, igmp); + +#ifdef IGMP_SOCK_DUMP + igmp_sock_dump(igmp_sock_array); +#endif + + return igmp; +} + +/* + RFC 3376: 6.5. Switching Router Filter-Modes + + When a router's filter-mode for a group is EXCLUDE and the group + timer expires, the router filter-mode for the group transitions to + INCLUDE. + + A router uses source records with running source timers as its state + for the switch to a filter-mode of INCLUDE. If there are any source + records with source timers greater than zero (i.e., requested to be + forwarded), a router switches to filter-mode of INCLUDE using those + source records. Source records whose timers are zero (from the + previous EXCLUDE mode) are deleted. + */ +static int igmp_group_timer(struct thread *t) +{ + struct igmp_group *group; + + zassert(t); + group = THREAD_ARG(t); + zassert(group); + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: Timer for group %s on interface %s", + __PRETTY_FUNCTION__, + group_str, group->group_igmp_sock->interface->name); + } + + zassert(group->group_filtermode_isexcl); + + group->t_group_timer = 0; + group->group_filtermode_isexcl = 0; + + /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ + igmp_anysource_forward_stop(group); + + igmp_source_delete_expired(group->group_source_list); + + zassert(!group->t_group_timer); + zassert(!group->group_filtermode_isexcl); + + /* + RFC 3376: 6.2.2. Definition of Group Timers + + If there are no more source records for the group, delete group + record. + */ + if (listcount(group->group_source_list) < 1) { + igmp_group_delete_empty_include(group); + } + + return 0; +} + +static void group_timer_off(struct igmp_group *group) +{ + if (!group->t_group_timer) + return; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("Cancelling TIMER event for group %s on %s", + group_str, group->group_igmp_sock->interface->name); + } + + THREAD_OFF(group->t_group_timer); + zassert(!group->t_group_timer); +} + +void igmp_group_timer_on(struct igmp_group *group, + long interval_msec, const char *ifname) +{ + group_timer_off(group); + + if (PIM_DEBUG_IGMP_EVENTS) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s on %s", + interval_msec / 1000, + interval_msec % 1000, + group_str, ifname); + } + + /* + RFC 3376: 6.2.2. Definition of Group Timers + + The group timer is only used when a group is in EXCLUDE mode and + it represents the time for the *filter-mode* of the group to + expire and switch to INCLUDE mode. + */ + zassert(group->group_filtermode_isexcl); + + THREAD_TIMER_MSEC_ON(master, group->t_group_timer, + igmp_group_timer, + group, interval_msec); +} + +static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, + struct in_addr group_addr) +{ + struct igmp_group *group; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, node, group)) + if (group_addr.s_addr == group->group_addr.s_addr) + return group; + + return 0; +} + +struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, + struct in_addr group_addr, + const char *ifname) +{ + struct igmp_group *group; + + group = find_group_by_addr(igmp, group_addr); + if (group) { + return group; + } + + /* + Non-existant group is created as INCLUDE {empty}: + + RFC 3376 - 5.1. Action on Change of Interface State + + If no interface state existed for that multicast address before + the change (i.e., the change consisted of creating a new + per-interface record), or if no state exists after the change + (i.e., the change consisted of deleting a per-interface record), + then the "non-existent" state is considered to have a filter mode + of INCLUDE and an empty source list. + */ + + group = XMALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group)); + if (!group) { + zlog_warn("%s %s: XMALLOC() failure", + __FILE__, __PRETTY_FUNCTION__); + return 0; /* error, not found, could not create */ + } + + group->group_source_list = list_new(); + if (!group->group_source_list) { + zlog_warn("%s %s: list_new() failure", + __FILE__, __PRETTY_FUNCTION__); + XFREE(MTYPE_PIM_IGMP_GROUP, group); /* discard group */ + return 0; /* error, not found, could not initialize */ + } + group->group_source_list->del = (void (*)(void *)) igmp_source_free; + + group->t_group_timer = 0; + group->t_group_query_retransmit_timer = 0; + group->group_specific_query_retransmit_count = 0; + group->group_addr = group_addr; + group->group_igmp_sock = igmp; + group->last_igmp_v1_report_dsec = -1; + group->last_igmp_v2_report_dsec = -1; + group->group_creation = pim_time_monotonic_sec(); + + /* initialize new group as INCLUDE {empty} */ + group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */ + + listnode_add(igmp->igmp_group_list, group); + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("Creating new IGMP group %s on socket %d interface %s", + group_str, group->group_igmp_sock->fd, ifname); + } + + /* + RFC 3376: 6.2.2. Definition of Group Timers + + The group timer is only used when a group is in EXCLUDE mode and + it represents the time for the *filter-mode* of the group to + expire and switch to INCLUDE mode. + */ + zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */ + zassert(!group->t_group_timer); /* group timer == 0 */ + + /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ + igmp_anysource_forward_stop(group); + + return group; +} diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h new file mode 100644 index 000000000..656147f27 --- /dev/null +++ b/pimd/pim_igmp.h @@ -0,0 +1,172 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_IGMP_H +#define PIM_IGMP_H + +#include + +#include +#include "vty.h" +#include "linklist.h" + +/* + The following sizes are likely to support + any message sent within local MTU. +*/ +#define PIM_IGMP_BUFSIZE_READ (20000) +#define PIM_IGMP_BUFSIZE_WRITE (20000) + +#define PIM_IGMP_MEMBERSHIP_QUERY (0x11) +#define PIM_IGMP_V1_MEMBERSHIP_REPORT (0x12) +#define PIM_IGMP_V2_MEMBERSHIP_REPORT (0x16) +#define PIM_IGMP_V2_LEAVE_GROUP (0x17) +#define PIM_IGMP_V3_MEMBERSHIP_REPORT (0x22) + +#define IGMP_V3_REPORT_HEADER_SIZE (8) +#define IGMP_V3_GROUP_RECORD_MIN_SIZE (8) +#define IGMP_V3_MSG_MIN_SIZE (IGMP_V3_REPORT_HEADER_SIZE + \ + IGMP_V3_GROUP_RECORD_MIN_SIZE) +#define IGMP_V12_MSG_SIZE (8) + +#define IGMP_V3_GROUP_RECORD_TYPE_OFFSET (0) +#define IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET (1) +#define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2) +#define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4) +#define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8) + +/* RFC 3376: 8.1. Robustness Variable - Default: 2 */ +#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2) + +/* RFC 3376: 8.2. Query Interval - Default: 125 seconds */ +#define IGMP_GENERAL_QUERY_INTERVAL (125) + +/* RFC 3376: 8.3. Query Response Interval - Default: 100 deciseconds */ +#define IGMP_QUERY_MAX_RESPONSE_TIME_DSEC (100) + +struct igmp_join { + struct in_addr group_addr; + struct in_addr source_addr; + int sock_fd; +}; + +struct igmp_sock { + int fd; + struct interface *interface; + struct in_addr ifaddr; + time_t sock_creation; + + struct thread *t_igmp_read; /* read: IGMP sockets */ + struct thread *t_igmp_query_timer; /* timer: issue IGMP general queries */ + struct thread *t_other_querier_timer; /* timer: other querier present */ + + int querier_query_interval; /* QQI */ + int querier_robustness_variable; /* QRV */ + int startup_query_count; + + struct list *igmp_group_list; /* list of struct igmp_group */ +}; + +struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, + struct in_addr ifaddr); +struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, + int fd); +struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, + struct in_addr ifaddr, + struct interface *ifp); +void igmp_sock_delete(struct igmp_sock *igmp); +void igmp_sock_free(struct igmp_sock *igmp); + +int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len); + +void pim_igmp_general_query_on(struct igmp_sock *igmp); +void pim_igmp_general_query_off(struct igmp_sock *igmp); +void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp); +void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp); + +#define IGMP_SOURCE_MASK_FORWARDING (1 << 0) +#define IGMP_SOURCE_MASK_DELETE (1 << 1) +#define IGMP_SOURCE_MASK_SEND (1 << 2) +#define IGMP_SOURCE_TEST_FORWARDING(flags) ((flags) & IGMP_SOURCE_MASK_FORWARDING) +#define IGMP_SOURCE_TEST_DELETE(flags) ((flags) & IGMP_SOURCE_MASK_DELETE) +#define IGMP_SOURCE_TEST_SEND(flags) ((flags) & IGMP_SOURCE_MASK_SEND) +#define IGMP_SOURCE_DO_FORWARDING(flags) ((flags) |= IGMP_SOURCE_MASK_FORWARDING) +#define IGMP_SOURCE_DO_DELETE(flags) ((flags) |= IGMP_SOURCE_MASK_DELETE) +#define IGMP_SOURCE_DO_SEND(flags) ((flags) |= IGMP_SOURCE_MASK_SEND) +#define IGMP_SOURCE_DONT_FORWARDING(flags) ((flags) &= ~IGMP_SOURCE_MASK_FORWARDING) +#define IGMP_SOURCE_DONT_DELETE(flags) ((flags) &= ~IGMP_SOURCE_MASK_DELETE) +#define IGMP_SOURCE_DONT_SEND(flags) ((flags) &= ~IGMP_SOURCE_MASK_SEND) + +struct igmp_source { + struct in_addr source_addr; + struct thread *t_source_timer; + struct igmp_group *source_group; /* back pointer */ + time_t source_creation; + uint32_t source_flags; + struct channel_oil *source_channel_oil; + + /* + RFC 3376: 6.6.3.2. Building and Sending Group and Source Specific Queries + */ + int source_query_retransmit_count; +}; + +struct igmp_group { + /* + RFC 3376: 6.2.2. Definition of Group Timers + + The group timer is only used when a group is in EXCLUDE mode and it + represents the time for the *filter-mode* of the group to expire and + switch to INCLUDE mode. + */ + struct thread *t_group_timer; + + /* Shared between group-specific and + group-and-source-specific retransmissions */ + struct thread *t_group_query_retransmit_timer; + + /* Counter exclusive for group-specific retransmissions + (not used by group-and-source-specific retransmissions, + since sources have their counters) */ + int group_specific_query_retransmit_count; + + struct in_addr group_addr; + int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */ + struct list *group_source_list; /* list of struct igmp_source */ + time_t group_creation; + struct igmp_sock *group_igmp_sock; /* back pointer */ + int64_t last_igmp_v1_report_dsec; + int64_t last_igmp_v2_report_dsec; +}; + +struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, + struct in_addr group_addr, + const char *ifname); + +void igmp_group_delete_empty_include(struct igmp_group *group); + +void igmp_startup_mode_on(struct igmp_sock *igmp); + +void igmp_group_timer_on(struct igmp_group *group, + long interval_msec, const char *ifname); + +#endif /* PIM_IGMP_H */ diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c new file mode 100644 index 000000000..f9fa123f1 --- /dev/null +++ b/pimd/pim_igmpv3.c @@ -0,0 +1,1717 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include "log.h" +#include "memory.h" + +#include "pimd.h" +#include "pim_iface.h" +#include "pim_igmp.h" +#include "pim_igmpv3.h" +#include "pim_str.h" +#include "pim_util.h" +#include "pim_time.h" +#include "pim_zebra.h" +#include "pim_oil.h" + +static void group_retransmit_timer_on(struct igmp_group *group); +static long igmp_group_timer_remain_msec(struct igmp_group *group); +static long igmp_source_timer_remain_msec(struct igmp_source *source); +static void group_query_send(struct igmp_group *group); +static void source_query_send_by_flag(struct igmp_group *group, + int num_sources_tosend); + +static void on_trace(const char *label, + struct interface *ifp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + if (PIM_DEBUG_IGMP_TRACE) { + char from_str[100]; + char group_str[100]; + + pim_inet4_dump("", from, from_str, sizeof(from_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + + zlog_debug("%s: from %s on %s: group=%s sources=%d", + label, from_str, ifp->name, group_str, num_sources); + } +} + +int igmp_group_compat_mode(const struct igmp_sock *igmp, + const struct igmp_group *group) +{ + struct pim_interface *pim_ifp; + int64_t now_dsec; + long older_host_present_interval_dsec; + + zassert(igmp); + zassert(igmp->interface); + zassert(igmp->interface->info); + + pim_ifp = igmp->interface->info; + + /* + RFC 3376: 8.13. Older Host Present Interval + + This value MUST be ((the Robustness Variable) times (the Query + Interval)) plus (one Query Response Interval). + + older_host_present_interval_dsec = \ + igmp->querier_robustness_variable * \ + 10 * igmp->querier_query_interval + \ + pim_ifp->query_max_response_time_dsec; + */ + older_host_present_interval_dsec = + PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec); + + now_dsec = pim_time_monotonic_dsec(); + if (now_dsec < 1) { + /* broken timer logged by pim_time_monotonic_dsec() */ + return 3; + } + + if ((now_dsec - group->last_igmp_v1_report_dsec) < older_host_present_interval_dsec) + return 1; /* IGMPv1 */ + + if ((now_dsec - group->last_igmp_v2_report_dsec) < older_host_present_interval_dsec) + return 2; /* IGMPv2 */ + + return 3; /* IGMPv3 */ +} + +void igmp_group_reset_gmi(struct igmp_group *group) +{ + long group_membership_interval_msec; + struct pim_interface *pim_ifp; + struct igmp_sock *igmp; + struct interface *ifp; + + igmp = group->group_igmp_sock; + ifp = igmp->interface; + pim_ifp = ifp->info; + + /* + RFC 3376: 8.4. Group Membership Interval + + The Group Membership Interval is the amount of time that must pass + before a multicast router decides there are no more members of a + group or a particular source on a network. + + This value MUST be ((the Robustness Variable) times (the Query + Interval)) plus (one Query Response Interval). + + group_membership_interval_msec = querier_robustness_variable * + (1000 * querier_query_interval) + + 100 * query_response_interval_dsec; + */ + group_membership_interval_msec = + PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec); + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s", + group_str, + group_membership_interval_msec / 1000, + group_membership_interval_msec % 1000, + ifp->name); + } + + /* + RFC 3376: 6.2.2. Definition of Group Timers + + The group timer is only used when a group is in EXCLUDE mode and + it represents the time for the *filter-mode* of the group to + expire and switch to INCLUDE mode. + */ + zassert(group->group_filtermode_isexcl); + + igmp_group_timer_on(group, group_membership_interval_msec, ifp->name); +} + +static int igmp_source_timer(struct thread *t) +{ + struct igmp_source *source; + struct igmp_group *group; + + zassert(t); + source = THREAD_ARG(t); + zassert(source); + + group = source->source_group; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_debug("%s: Source timer expired for group %s source %s on %s", + __PRETTY_FUNCTION__, + group_str, source_str, + group->group_igmp_sock->interface->name); + } + + zassert(source->t_source_timer); + source->t_source_timer = 0; + + /* + RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules + + Group + Filter-Mode Source Timer Value Action + ----------- ------------------ ------ + INCLUDE TIMER == 0 Suggest to stop forwarding + traffic from source and + remove source record. If + there are no more source + records for the group, delete + group record. + + EXCLUDE TIMER == 0 Suggest to not forward + traffic from source + (DO NOT remove record) + + Source timer switched from (T > 0) to (T == 0): disable forwarding. + */ + + zassert(!source->t_source_timer); + + if (group->group_filtermode_isexcl) { + /* EXCLUDE mode */ + + igmp_source_forward_stop(source); + } + else { + /* INCLUDE mode */ + + /* igmp_source_delete() will stop forwarding source */ + igmp_source_delete(source); + + /* + If there are no more source records for the group, delete group + record. + */ + if (!listcount(group->group_source_list)) { + igmp_group_delete_empty_include(group); + } + } + + return 0; +} + +static void source_timer_off(struct igmp_group *group, + struct igmp_source *source) +{ + if (!source->t_source_timer) + return; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_debug("Cancelling TIMER event for group %s source %s on %s", + group_str, source_str, + group->group_igmp_sock->interface->name); + } + + THREAD_OFF(source->t_source_timer); + zassert(!source->t_source_timer); +} + +static void igmp_source_timer_on(struct igmp_group *group, + struct igmp_source *source, + long interval_msec) +{ + source_timer_off(group, source); + + if (PIM_DEBUG_IGMP_EVENTS) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s", + interval_msec / 1000, + interval_msec % 1000, + group_str, source_str, + group->group_igmp_sock->interface->name); + } + + THREAD_TIMER_MSEC_ON(master, source->t_source_timer, + igmp_source_timer, + source, interval_msec); + zassert(source->t_source_timer); + + /* + RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules + + Source timer switched from (T == 0) to (T > 0): enable forwarding. + */ + igmp_source_forward_start(source); +} + +void igmp_source_reset_gmi(struct igmp_sock *igmp, + struct igmp_group *group, + struct igmp_source *source) +{ + long group_membership_interval_msec; + struct pim_interface *pim_ifp; + struct interface *ifp; + + ifp = igmp->interface; + pim_ifp = ifp->info; + + group_membership_interval_msec = + PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, + igmp->querier_query_interval, + pim_ifp->igmp_query_max_response_time_dsec); + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + char source_str[100]; + + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + + zlog_debug("Resetting source %s timer to GMI=%ld.%03ld sec for group %s on %s", + source_str, + group_membership_interval_msec / 1000, + group_membership_interval_msec % 1000, + group_str, + ifp->name); + } + + igmp_source_timer_on(group, source, + group_membership_interval_msec); +} + +static void source_mark_delete_flag(struct list *source_list) +{ + struct listnode *src_node; + struct igmp_source *src; + + for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { + IGMP_SOURCE_DO_DELETE(src->source_flags); + } +} + +static void source_mark_send_flag(struct list *source_list) +{ + struct listnode *src_node; + struct igmp_source *src; + + for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { + IGMP_SOURCE_DO_SEND(src->source_flags); + } +} + +static int source_mark_send_flag_by_timer(struct list *source_list) +{ + struct listnode *src_node; + struct igmp_source *src; + int num_marked_sources = 0; + + for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { + /* Is source timer running? */ + if (src->t_source_timer) { + IGMP_SOURCE_DO_SEND(src->source_flags); + ++num_marked_sources; + } + else { + IGMP_SOURCE_DONT_SEND(src->source_flags); + } + } + + return num_marked_sources; +} + +static void source_clear_send_flag(struct list *source_list) +{ + struct listnode *src_node; + struct igmp_source *src; + + for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { + IGMP_SOURCE_DONT_SEND(src->source_flags); + } +} + +/* + Any source (*,G) is forwarded only if mode is EXCLUDE {empty} +*/ +static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group) +{ + zassert(group->group_filtermode_isexcl); + + if (listcount(group->group_source_list) < 1) { + igmp_anysource_forward_start(group); + } +} + +void igmp_source_free(struct igmp_source *source) +{ + /* make sure there is no source timer running */ + zassert(!source->t_source_timer); + + XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source); +} + +static void source_channel_oil_detach(struct igmp_source *source) +{ + if (source->source_channel_oil) { + pim_channel_oil_del(source->source_channel_oil); + source->source_channel_oil = 0; + } +} + +void igmp_source_delete(struct igmp_source *source) +{ + struct igmp_group *group; + + group = source->source_group; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s", + source_str, group_str, + group->group_igmp_sock->fd, + group->group_igmp_sock->interface->name); + } + + source_timer_off(group, source); + igmp_source_forward_stop(source); + + /* make sure forwarding is disabled */ + zassert(!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); + + source_channel_oil_detach(source); + + /* + notice that listnode_delete() can't be moved + into igmp_source_free() because the later is + called by list_delete_all_node() + */ + listnode_delete(group->group_source_list, source); + + igmp_source_free(source); + + if (group->group_filtermode_isexcl) { + group_exclude_fwd_anysrc_ifempty(group); + } +} + +static void source_delete_by_flag(struct list *source_list) +{ + struct listnode *src_node; + struct listnode *src_nextnode; + struct igmp_source *src; + + for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) + if (IGMP_SOURCE_TEST_DELETE(src->source_flags)) + igmp_source_delete(src); +} + +void igmp_source_delete_expired(struct list *source_list) +{ + struct listnode *src_node; + struct listnode *src_nextnode; + struct igmp_source *src; + + for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) + if (!src->t_source_timer) + igmp_source_delete(src); +} + +struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, + struct in_addr src_addr) +{ + struct listnode *src_node; + struct igmp_source *src; + + for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) + if (src_addr.s_addr == src->source_addr.s_addr) + return src; + + return 0; +} + +static struct igmp_source *source_new(struct igmp_group *group, + struct in_addr src_addr, + const char *ifname) +{ + struct igmp_source *src; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", src_addr, source_str, sizeof(source_str)); + zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s", + source_str, group_str, + group->group_igmp_sock->fd, + ifname); + } + + src = XMALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src)); + if (!src) { + zlog_warn("%s %s: XMALLOC() failure", + __FILE__, __PRETTY_FUNCTION__); + return 0; /* error, not found, could not create */ + } + + src->t_source_timer = 0; + src->source_group = group; /* back pointer */ + src->source_addr = src_addr; + src->source_creation = pim_time_monotonic_sec(); + src->source_flags = 0; + src->source_query_retransmit_count = 0; + src->source_channel_oil = 0; + + listnode_add(group->group_source_list, src); + + zassert(!src->t_source_timer); /* source timer == 0 */ + + /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ + igmp_anysource_forward_stop(group); + + return src; +} + +static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp, + struct igmp_group *group, + struct in_addr src_addr, + const char *ifname) +{ + struct igmp_source *src; + + src = igmp_find_source_by_addr(group, src_addr); + if (src) { + return src; + } + + src = source_new(group, src_addr, ifname); + if (!src) { + return 0; + } + + return src; +} + +static void allow(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + struct interface *ifp = igmp->interface; + struct pim_interface *pim_ifp; + struct igmp_group *group; + + pim_ifp = ifp->info; + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return; + } + + /* scan received sources */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + source = add_source_by_addr(igmp, group, *src_addr, ifp->name); + if (!source) { + continue; + } + + /* + RFC 3376: 6.4.1. Reception of Current-State Records + + When receiving IS_IN reports for groups in EXCLUDE mode is + sources should be moved from set with (timers = 0) to set with + (timers > 0). + + igmp_source_reset_gmi() below, resetting the source timers to + GMI, accomplishes this. + */ + igmp_source_reset_gmi(igmp, group, source); + + } /* scan received sources */ +} + +void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + on_trace(__PRETTY_FUNCTION__, + igmp->interface, from, group_addr, num_sources, sources); + + allow(igmp, from, group_addr, num_sources, sources); +} + +static void isex_excl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + /* EXCLUDE mode */ + zassert(group->group_filtermode_isexcl); + + /* E.1: set deletion flag for known sources (X,Y) */ + source_mark_delete_flag(group->group_source_list); + + /* scan received sources (A) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* E.2: lookup reported source from (A) in (X,Y) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + /* E.3: if found, clear deletion flag: (X*A) or (Y*A) */ + IGMP_SOURCE_DONT_DELETE(source->source_flags); + } + else { + /* E.4: if not found, create source with timer=GMI: (A-X-Y) */ + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + zassert(!source->t_source_timer); /* timer == 0 */ + igmp_source_reset_gmi(group->group_igmp_sock, group, source); + zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ + } + + } /* scan received sources */ + + /* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */ + source_delete_by_flag(group->group_source_list); +} + +static void isex_incl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + /* INCLUDE mode */ + zassert(!group->group_filtermode_isexcl); + + /* I.1: set deletion flag for known sources (A) */ + source_mark_delete_flag(group->group_source_list); + + /* scan received sources (B) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* I.2: lookup reported source (B) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + /* I.3: if found, clear deletion flag (A*B) */ + IGMP_SOURCE_DONT_DELETE(source->source_flags); + } + else { + /* I.4: if not found, create source with timer=0 (B-A) */ + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + zassert(!source->t_source_timer); /* (B-A) timer=0 */ + } + + } /* scan received sources */ + + /* I.5: delete all sources marked with deletion flag (A-B) */ + source_delete_by_flag(group->group_source_list); + + group->group_filtermode_isexcl = 1; /* boolean=true */ + + zassert(group->group_filtermode_isexcl); + + group_exclude_fwd_anysrc_ifempty(group); +} + +void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + struct interface *ifp = igmp->interface; + struct pim_interface *pim_ifp; + struct igmp_group *group; + + on_trace(__PRETTY_FUNCTION__, + ifp, from, group_addr, num_sources, sources); + + pim_ifp = ifp->info; + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return; + } + + if (group->group_filtermode_isexcl) { + /* EXCLUDE mode */ + isex_excl(group, num_sources, sources); + } + else { + /* INCLUDE mode */ + isex_incl(group, num_sources, sources); + zassert(group->group_filtermode_isexcl); + } + + zassert(group->group_filtermode_isexcl); + + igmp_group_reset_gmi(group); +} + +static void toin_incl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + struct igmp_sock *igmp = group->group_igmp_sock; + int num_sources_tosend = listcount(group->group_source_list); + + /* Set SEND flag for all known sources (A) */ + source_mark_send_flag(group->group_source_list); + + /* Scan received sources (B) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* Lookup reported source (B) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + /* If found, clear SEND flag (A*B) */ + IGMP_SOURCE_DONT_SEND(source->source_flags); + --num_sources_tosend; + } + else { + /* If not found, create new source */ + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + } + + /* (B)=GMI */ + igmp_source_reset_gmi(igmp, group, source); + } + + /* Send sources marked with SEND flag: Q(G,A-B) */ + if (num_sources_tosend > 0) { + source_query_send_by_flag(group, num_sources_tosend); + } +} + +static void toin_excl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + struct igmp_sock *igmp = group->group_igmp_sock; + int num_sources_tosend; + + /* Set SEND flag for X (sources with timer > 0) */ + num_sources_tosend = source_mark_send_flag_by_timer(group->group_source_list); + + /* Scan received sources (A) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* Lookup reported source (A) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + if (source->t_source_timer) { + /* If found and timer running, clear SEND flag (X*A) */ + IGMP_SOURCE_DONT_SEND(source->source_flags); + --num_sources_tosend; + } + } + else { + /* If not found, create new source */ + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + } + + /* (A)=GMI */ + igmp_source_reset_gmi(igmp, group, source); + } + + /* Send sources marked with SEND flag: Q(G,X-A) */ + if (num_sources_tosend > 0) { + source_query_send_by_flag(group, num_sources_tosend); + } + + /* Send Q(G) */ + group_query_send(group); +} + +void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + struct interface *ifp = igmp->interface; + struct pim_interface *pim_ifp; + struct igmp_group *group; + + on_trace(__PRETTY_FUNCTION__, + ifp, from, group_addr, num_sources, sources); + + pim_ifp = ifp->info; + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return; + } + + if (group->group_filtermode_isexcl) { + /* EXCLUDE mode */ + toin_excl(group, num_sources, sources); + } + else { + /* INCLUDE mode */ + toin_incl(group, num_sources, sources); + } +} + +static void toex_incl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + int num_sources_tosend = 0; + + zassert(!group->group_filtermode_isexcl); + + /* Set DELETE flag for all known sources (A) */ + source_mark_delete_flag(group->group_source_list); + + /* Clear off SEND flag from all known sources (A) */ + source_clear_send_flag(group->group_source_list); + + /* Scan received sources (B) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* Lookup reported source (B) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + /* If found, clear deletion flag: (A*B) */ + IGMP_SOURCE_DONT_DELETE(source->source_flags); + /* and set SEND flag (A*B) */ + IGMP_SOURCE_DO_SEND(source->source_flags); + ++num_sources_tosend; + } + else { + /* If source not found, create source with timer=0: (B-A)=0 */ + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + zassert(!source->t_source_timer); /* (B-A) timer=0 */ + } + + } /* Scan received sources (B) */ + + group->group_filtermode_isexcl = 1; /* boolean=true */ + + /* Delete all sources marked with DELETE flag (A-B) */ + source_delete_by_flag(group->group_source_list); + + /* Send sources marked with SEND flag: Q(G,A*B) */ + if (num_sources_tosend > 0) { + source_query_send_by_flag(group, num_sources_tosend); + } + + zassert(group->group_filtermode_isexcl); + + group_exclude_fwd_anysrc_ifempty(group); +} + +static void toex_excl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + int num_sources_tosend = 0; + + /* set DELETE flag for all known sources (X,Y) */ + source_mark_delete_flag(group->group_source_list); + + /* clear off SEND flag from all known sources (X,Y) */ + source_clear_send_flag(group->group_source_list); + + /* scan received sources (A) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* lookup reported source (A) in known sources (X,Y) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + /* if found, clear off DELETE flag from reported source (A) */ + IGMP_SOURCE_DONT_DELETE(source->source_flags); + } + else { + /* if not found, create source with Group Timer: (A-X-Y)=Group Timer */ + long group_timer_msec; + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + + zassert(!source->t_source_timer); /* timer == 0 */ + group_timer_msec = igmp_group_timer_remain_msec(group); + igmp_source_timer_on(group, source, group_timer_msec); + zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ + + /* make sure source is created with DELETE flag unset */ + zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags)); + } + + /* make sure reported source has DELETE flag unset */ + zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags)); + + if (source->t_source_timer) { + /* if source timer>0 mark SEND flag: Q(G,A-Y) */ + IGMP_SOURCE_DO_SEND(source->source_flags); + ++num_sources_tosend; + } + + } /* scan received sources (A) */ + + /* + delete all sources marked with DELETE flag: + Delete (X-A) + Delete (Y-A) + */ + source_delete_by_flag(group->group_source_list); + + /* send sources marked with SEND flag: Q(G,A-Y) */ + if (num_sources_tosend > 0) { + source_query_send_by_flag(group, num_sources_tosend); + } +} + +void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + struct interface *ifp = igmp->interface; + struct pim_interface *pim_ifp; + struct igmp_group *group; + + on_trace(__PRETTY_FUNCTION__, + ifp, from, group_addr, num_sources, sources); + + pim_ifp = ifp->info; + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return; + } + + if (group->group_filtermode_isexcl) { + /* EXCLUDE mode */ + toex_excl(group, num_sources, sources); + } + else { + /* INCLUDE mode */ + toex_incl(group, num_sources, sources); + zassert(group->group_filtermode_isexcl); + } + zassert(group->group_filtermode_isexcl); + + /* Group Timer=GMI */ + igmp_group_reset_gmi(group); +} + +void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + on_trace(__PRETTY_FUNCTION__, + igmp->interface, from, group_addr, num_sources, sources); + + allow(igmp, from, group_addr, num_sources, sources); +} + +/* + RFC3376: 6.6.3.1. Building and Sending Group Specific Queries + + When transmitting a group specific query, if the group timer is + larger than LMQT, the "Suppress Router-Side Processing" bit is set + in the query message. +*/ +static void group_retransmit_group(struct igmp_group *group) +{ + char query_buf[PIM_IGMP_BUFSIZE_WRITE]; + struct igmp_sock *igmp; + struct pim_interface *pim_ifp; + long lmqc; /* Last Member Query Count */ + long lmqi_msec; /* Last Member Query Interval */ + long lmqt_msec; /* Last Member Query Time */ + int s_flag; + + igmp = group->group_igmp_sock; + pim_ifp = igmp->interface->info; + + lmqc = igmp->querier_robustness_variable; + lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqt_msec = lmqc * lmqi_msec; + + /* + RFC3376: 6.6.3.1. Building and Sending Group Specific Queries + + When transmitting a group specific query, if the group timer is + larger than LMQT, the "Suppress Router-Side Processing" bit is set + in the query message. + */ + s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d", + group_str, igmp->interface->name, s_flag, + group->group_specific_query_retransmit_count); + } + + /* + RFC3376: 4.1.12. IP Destination Addresses for Queries + + Group-Specific and Group-and-Source-Specific Queries are sent with + an IP destination address equal to the multicast address of + interest. + */ + + pim_igmp_send_membership_query(group, + igmp->fd, + igmp->interface->name, + query_buf, + sizeof(query_buf), + 0 /* num_sources_tosend */, + group->group_addr /* dst_addr */, + group->group_addr /* group_addr */, + pim_ifp->igmp_query_max_response_time_dsec, + s_flag, + igmp->querier_robustness_variable, + igmp->querier_query_interval); +} + +/* + RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries + + When building a group and source specific query for a group G, two + separate query messages are sent for the group. The first one has + the "Suppress Router-Side Processing" bit set and contains all the + sources with retransmission state and timers greater than LMQT. The + second has the "Suppress Router-Side Processing" bit clear and + contains all the sources with retransmission state and timers lower + or equal to LMQT. If either of the two calculated messages does not + contain any sources, then its transmission is suppressed. + */ +static int group_retransmit_sources(struct igmp_group *group, + int send_with_sflag_set) +{ + struct igmp_sock *igmp; + struct pim_interface *pim_ifp; + long lmqc; /* Last Member Query Count */ + long lmqi_msec; /* Last Member Query Interval */ + long lmqt_msec; /* Last Member Query Time */ + char query_buf1[PIM_IGMP_BUFSIZE_WRITE]; /* 1 = with s_flag set */ + char query_buf2[PIM_IGMP_BUFSIZE_WRITE]; /* 2 = with s_flag clear */ + int query_buf1_max_sources; + int query_buf2_max_sources; + struct in_addr *source_addr1; + struct in_addr *source_addr2; + int num_sources_tosend1; + int num_sources_tosend2; + struct listnode *src_node; + struct igmp_source *src; + int num_retransmit_sources_left = 0; + + query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; + query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; + + source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); + source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); + + igmp = group->group_igmp_sock; + pim_ifp = igmp->interface->info; + + lmqc = igmp->querier_robustness_variable; + lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqt_msec = lmqc * lmqi_msec; + + /* Scan all group sources */ + for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { + + /* Source has retransmission state? */ + if (src->source_query_retransmit_count < 1) + continue; + + if (--src->source_query_retransmit_count > 0) { + ++num_retransmit_sources_left; + } + + /* Copy source address into appropriate query buffer */ + if (igmp_source_timer_remain_msec(src) > lmqt_msec) { + *source_addr1 = src->source_addr; + ++source_addr1; + } + else { + *source_addr2 = src->source_addr; + ++source_addr2; + } + + } + + num_sources_tosend1 = source_addr1 - (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); + num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d", + group_str, igmp->interface->name, + num_sources_tosend1, + num_sources_tosend2, + send_with_sflag_set, + num_retransmit_sources_left); + } + + if (num_sources_tosend1 > 0) { + /* + Send group-and-source-specific query with s_flag set and all + sources with timers greater than LMQT. + */ + + if (send_with_sflag_set) { + + query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; + if (num_sources_tosend1 > query_buf1_max_sources) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%d (max_sources=%d)", + __PRETTY_FUNCTION__, group_str, igmp->interface->name, + num_sources_tosend1, sizeof(query_buf1), query_buf1_max_sources); + } + else { + /* + RFC3376: 4.1.12. IP Destination Addresses for Queries + + Group-Specific and Group-and-Source-Specific Queries are sent with + an IP destination address equal to the multicast address of + interest. + */ + + pim_igmp_send_membership_query(group, + igmp->fd, + igmp->interface->name, + query_buf1, + sizeof(query_buf1), + num_sources_tosend1, + group->group_addr, + group->group_addr, + pim_ifp->igmp_query_max_response_time_dsec, + 1 /* s_flag */, + igmp->querier_robustness_variable, + igmp->querier_query_interval); + + } + + } /* send_with_sflag_set */ + + } + + if (num_sources_tosend2 > 0) { + /* + Send group-and-source-specific query with s_flag clear and all + sources with timers lower or equal to LMQT. + */ + + query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; + if (num_sources_tosend2 > query_buf2_max_sources) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%d (max_sources=%d)", + __PRETTY_FUNCTION__, group_str, igmp->interface->name, + num_sources_tosend2, sizeof(query_buf2), query_buf2_max_sources); + } + else { + /* + RFC3376: 4.1.12. IP Destination Addresses for Queries + + Group-Specific and Group-and-Source-Specific Queries are sent with + an IP destination address equal to the multicast address of + interest. + */ + + pim_igmp_send_membership_query(group, + igmp->fd, + igmp->interface->name, + query_buf2, + sizeof(query_buf2), + num_sources_tosend2, + group->group_addr, + group->group_addr, + pim_ifp->igmp_query_max_response_time_dsec, + 0 /* s_flag */, + igmp->querier_robustness_variable, + igmp->querier_query_interval); + + } + } + + return num_retransmit_sources_left; +} + +static int igmp_group_retransmit(struct thread *t) +{ + struct igmp_group *group; + int num_retransmit_sources_left; + int send_with_sflag_set; /* boolean */ + + zassert(t); + group = THREAD_ARG(t); + zassert(group); + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("group_retransmit_timer: group %s on %s", + group_str, group->group_igmp_sock->interface->name); + } + + /* Retransmit group-specific queries? (RFC3376: 6.6.3.1) */ + if (group->group_specific_query_retransmit_count > 0) { + + /* Retransmit group-specific queries (RFC3376: 6.6.3.1) */ + group_retransmit_group(group); + --group->group_specific_query_retransmit_count; + + /* + RFC3376: 6.6.3.2 + If a group specific query is scheduled to be transmitted at the + same time as a group and source specific query for the same group, + then transmission of the group and source specific message with the + "Suppress Router-Side Processing" bit set may be suppressed. + */ + send_with_sflag_set = 0; /* boolean=false */ + } + else { + send_with_sflag_set = 1; /* boolean=true */ + } + + /* Retransmit group-and-source-specific queries (RFC3376: 6.6.3.2) */ + num_retransmit_sources_left = group_retransmit_sources(group, + send_with_sflag_set); + + group->t_group_query_retransmit_timer = 0; + + /* + Keep group retransmit timer running if there is any retransmit + counter pending + */ + if ((num_retransmit_sources_left > 0) || + (group->group_specific_query_retransmit_count > 0)) { + group_retransmit_timer_on(group); + } + + return 0; +} + +/* + group_retransmit_timer_on: + if group retransmit timer isn't running, starts it; + otherwise, do nothing +*/ +static void group_retransmit_timer_on(struct igmp_group *group) +{ + struct igmp_sock *igmp; + struct pim_interface *pim_ifp; + long lmqi_msec; /* Last Member Query Interval */ + + /* if group retransmit timer is running, do nothing */ + if (group->t_group_query_retransmit_timer) { + return; + } + + igmp = group->group_igmp_sock; + pim_ifp = igmp->interface->info; + + lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s", + lmqi_msec / 1000, + lmqi_msec % 1000, + group_str, + igmp->interface->name); + } + + THREAD_TIMER_MSEC_ON(master, group->t_group_query_retransmit_timer, + igmp_group_retransmit, + group, lmqi_msec); +} + +static long igmp_group_timer_remain_msec(struct igmp_group *group) +{ + return pim_time_timer_remain_msec(group->t_group_timer); +} + +static long igmp_source_timer_remain_msec(struct igmp_source *source) +{ + return pim_time_timer_remain_msec(source->t_source_timer); +} + +/* + RFC3376: 6.6.3.1. Building and Sending Group Specific Queries +*/ +static void group_query_send(struct igmp_group *group) +{ + long lmqc; /* Last Member Query Count */ + + lmqc = group->group_igmp_sock->querier_robustness_variable; + + /* lower group timer to lmqt */ + igmp_group_timer_lower_to_lmqt(group); + + /* reset retransmission counter */ + group->group_specific_query_retransmit_count = lmqc; + + /* immediately send group specific query (decrease retransmit counter by 1)*/ + group_retransmit_group(group); + + /* make sure group retransmit timer is running */ + group_retransmit_timer_on(group); +} + +/* + RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries +*/ +static void source_query_send_by_flag(struct igmp_group *group, + int num_sources_tosend) +{ + struct igmp_sock *igmp; + struct pim_interface *pim_ifp; + struct listnode *src_node; + struct igmp_source *src; + long lmqc; /* Last Member Query Count */ + long lmqi_msec; /* Last Member Query Interval */ + long lmqt_msec; /* Last Member Query Time */ + + zassert(num_sources_tosend > 0); + + igmp = group->group_igmp_sock; + pim_ifp = igmp->interface->info; + + lmqc = igmp->querier_robustness_variable; + lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqt_msec = lmqc * lmqi_msec; + + /* + RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries + + (...) for each of the sources in X of group G, with source timer larger + than LMQT: + o Set number of retransmissions for each source to [Last Member + Query Count]. + o Lower source timer to LMQT. + */ + for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { + if (IGMP_SOURCE_TEST_SEND(src->source_flags)) { + /* source "src" in X of group G */ + if (igmp_source_timer_remain_msec(src) > lmqt_msec) { + src->source_query_retransmit_count = lmqc; + igmp_source_timer_lower_to_lmqt(src); + } + } + } + + /* send group-and-source specific queries */ + group_retransmit_sources(group, 1 /* send_with_sflag_set=true */); + + /* make sure group retransmit timer is running */ + group_retransmit_timer_on(group); +} + +static void block_excl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + int num_sources_tosend = 0; + + /* 1. clear off SEND flag from all known sources (X,Y) */ + source_clear_send_flag(group->group_source_list); + + /* 2. scan received sources (A) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* lookup reported source (A) in known sources (X,Y) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (!source) { + /* 3: if not found, create source with Group Timer: (A-X-Y)=Group Timer */ + long group_timer_msec; + source = source_new(group, *src_addr, + group->group_igmp_sock->interface->name); + if (!source) { + /* ugh, internal malloc failure, skip source */ + continue; + } + + zassert(!source->t_source_timer); /* timer == 0 */ + group_timer_msec = igmp_group_timer_remain_msec(group); + igmp_source_timer_on(group, source, group_timer_msec); + zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ + } + + if (source->t_source_timer) { + /* 4. if source timer>0 mark SEND flag: Q(G,A-Y) */ + IGMP_SOURCE_DO_SEND(source->source_flags); + ++num_sources_tosend; + } + } + + /* 5. send sources marked with SEND flag: Q(G,A-Y) */ + if (num_sources_tosend > 0) { + source_query_send_by_flag(group, num_sources_tosend); + } +} + +static void block_incl(struct igmp_group *group, + int num_sources, struct in_addr *sources) +{ + int num_sources_tosend = 0; + + /* 1. clear off SEND flag from all known sources (B) */ + source_clear_send_flag(group->group_source_list); + + /* 2. scan received sources (A) */ + for (int i = 0; i < num_sources; ++i) { + struct igmp_source *source; + struct in_addr *src_addr; + + src_addr = sources + i; + + /* lookup reported source (A) in known sources (B) */ + source = igmp_find_source_by_addr(group, *src_addr); + if (source) { + /* 3. if found (A*B), mark SEND flag: Q(G,A*B) */ + IGMP_SOURCE_DO_SEND(source->source_flags); + ++num_sources_tosend; + } + } + + /* 4. send sources marked with SEND flag: Q(G,A*B) */ + if (num_sources_tosend > 0) { + source_query_send_by_flag(group, num_sources_tosend); + } +} + +void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources) +{ + struct interface *ifp = igmp->interface; + struct pim_interface *pim_ifp; + struct igmp_group *group; + + on_trace(__PRETTY_FUNCTION__, + ifp, from, group_addr, num_sources, sources); + + pim_ifp = ifp->info; + + /* non-existant group is created as INCLUDE {empty} */ + group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + if (!group) { + return; + } + + if (group->group_filtermode_isexcl) { + /* EXCLUDE mode */ + block_excl(group, num_sources, sources); + } + else { + /* INCLUDE mode */ + block_incl(group, num_sources, sources); + } +} + +void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) +{ + struct igmp_sock *igmp; + struct interface *ifp; + struct pim_interface *pim_ifp; + char *ifname; + int lmqi_dsec; /* Last Member Query Interval */ + int lmqc; /* Last Member Query Count */ + int lmqt_msec; /* Last Member Query Time */ + + /* + RFC 3376: 6.2.2. Definition of Group Timers + + The group timer is only used when a group is in EXCLUDE mode and + it represents the time for the *filter-mode* of the group to + expire and switch to INCLUDE mode. + */ + if (!group->group_filtermode_isexcl) { + return; + } + + igmp = group->group_igmp_sock; + ifp = igmp->interface; + pim_ifp = ifp->info; + ifname = ifp->name; + + lmqi_dsec = pim_ifp->igmp_query_max_response_time_dsec; + lmqc = igmp->querier_robustness_variable; + lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", + __PRETTY_FUNCTION__, + group_str, ifname, + lmqc, lmqi_dsec, lmqt_msec); + } + + zassert(group->group_filtermode_isexcl); + + igmp_group_timer_on(group, lmqt_msec, ifname); +} + +void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) +{ + struct igmp_group *group; + struct igmp_sock *igmp; + struct interface *ifp; + struct pim_interface *pim_ifp; + char *ifname; + int lmqi_dsec; /* Last Member Query Interval */ + int lmqc; /* Last Member Query Count */ + int lmqt_msec; /* Last Member Query Time */ + + group = source->source_group; + igmp = group->group_igmp_sock; + ifp = igmp->interface; + pim_ifp = ifp->info; + ifname = ifp->name; + + lmqi_dsec = pim_ifp->igmp_query_max_response_time_dsec; + lmqc = igmp->querier_robustness_variable; + lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ + + if (PIM_DEBUG_IGMP_TRACE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", + __PRETTY_FUNCTION__, + group_str, source_str, ifname, + lmqc, lmqi_dsec, lmqt_msec); + } + + igmp_source_timer_on(group, source, lmqt_msec); +} + +/* + Copy sources to message: + + struct in_addr *sources = (struct in_addr *)(query_buf + IGMP_V3_SOURCES_OFFSET); + if (num_sources > 0) { + struct listnode *node; + struct igmp_source *src; + int i = 0; + + for (ALL_LIST_ELEMENTS_RO(source_list, node, src)) { + sources[i++] = src->source_addr; + } + } +*/ +void pim_igmp_send_membership_query(struct igmp_group *group, + int fd, + const char *ifname, + char *query_buf, + int query_buf_size, + int num_sources, + struct in_addr dst_addr, + struct in_addr group_addr, + int query_max_response_time_dsec, + uint8_t s_flag, + uint8_t querier_robustness_variable, + uint16_t querier_query_interval) +{ + ssize_t msg_size; + uint8_t max_resp_code; + uint8_t qqic; + ssize_t sent; + struct sockaddr_in to; + socklen_t tolen; + uint16_t checksum; + + zassert(num_sources >= 0); + + msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2); + if (msg_size > query_buf_size) { + zlog_err("%s %s: unable to send: msg_size=%d larger than query_buf_size=%d", + __FILE__, __PRETTY_FUNCTION__, + msg_size, query_buf_size); + return; + } + + s_flag = PIM_FORCE_BOOLEAN(s_flag); + zassert((s_flag == 0) || (s_flag == 1)); + + max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec); + qqic = igmp_msg_encode16to8(querier_query_interval); + + /* + RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) + + If non-zero, the QRV field contains the [Robustness Variable] + value used by the querier, i.e., the sender of the Query. If the + querier's [Robustness Variable] exceeds 7, the maximum value of + the QRV field, the QRV is set to zero. + */ + if (querier_robustness_variable > 7) { + querier_robustness_variable = 0; + } + + query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY; + query_buf[1] = max_resp_code; + *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ + *(struct in_addr *)(query_buf + 4) = group_addr; + query_buf[8] = (s_flag << 3) | querier_robustness_variable; + query_buf[9] = qqic; + *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources); + + checksum = pim_inet_checksum(query_buf, msg_size); + *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = checksum; + + if (PIM_DEBUG_IGMP_PACKETS) { + char dst_str[100]; + char group_str[100]; + pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%d s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x", + __PRETTY_FUNCTION__, + dst_str, ifname, group_str, num_sources, + msg_size, s_flag, querier_robustness_variable, + querier_query_interval, qqic, checksum); + } + +#if 0 + memset(&to, 0, sizeof(to)); +#endif + to.sin_family = AF_INET; + to.sin_addr = dst_addr; +#if 0 + to.sin_port = htons(0); +#endif + tolen = sizeof(to); + + sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, &to, tolen); + if (sent != (ssize_t) msg_size) { + int e = errno; + char dst_str[100]; + char group_str[100]; + pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + if (sent < 0) { + zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%d: errno=%d: %s", + __PRETTY_FUNCTION__, + dst_str, ifname, group_str, msg_size, + e, strerror(e)); + } + else { + zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%d: sent=%d", + __PRETTY_FUNCTION__, + dst_str, ifname, group_str, + msg_size, sent); + } + return; + } + + /* + s_flag sanity test: s_flag must be set for general queries + + RFC 3376: 6.6.1. Timer Updates + + When a router sends or receives a query with a clear Suppress + Router-Side Processing flag, it must update its timers to reflect + the correct timeout values for the group or sources being queried. + + General queries don't trigger timer update. + */ + if (!s_flag) { + /* general query? */ + if (PIM_INADDR_IS_ANY(group_addr)) { + char dst_str[100]; + char group_str[100]; + pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!", + __PRETTY_FUNCTION__, + dst_str, ifname, group_str, num_sources); + } + } + +} diff --git a/pimd/pim_igmpv3.h b/pimd/pim_igmpv3.h new file mode 100644 index 000000000..bb7e92672 --- /dev/null +++ b/pimd/pim_igmpv3.h @@ -0,0 +1,100 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_IGMPV3_H +#define PIM_IGMPV3_H + +#include +#include "if.h" + +#define IGMP_V3_CHECKSUM_OFFSET (2) +#define IGMP_V3_REPORT_NUMGROUPS_OFFSET (6) +#define IGMP_V3_REPORT_GROUPPRECORD_OFFSET (8) +#define IGMP_V3_NUMSOURCES_OFFSET (10) +#define IGMP_V3_SOURCES_OFFSET (12) + +/* GMI: Group Membership Interval */ +#define PIM_IGMP_GMI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * (qri_dsec)) + +/* OQPI: Other Querier Present Interval */ +#define PIM_IGMP_OQPI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * ((qri_dsec) >> 1)) + +/* SQI: Startup Query Interval */ +#define PIM_IGMP_SQI(qi) (((qi) < 4) ? 1 : ((qi) >> 2)) + +/* LMQT: Last Member Query Time */ +#define PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc) ((lmqc) * (100 * (lmqi_dsec))) + +/* OHPI: Older Host Present Interval */ +#define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec)) + +void igmp_group_reset_gmi(struct igmp_group *group); +void igmp_source_reset_gmi(struct igmp_sock *igmp, + struct igmp_group *group, + struct igmp_source *source); + +void igmp_source_free(struct igmp_source *source); +void igmp_source_delete(struct igmp_source *source); +void igmp_source_delete_expired(struct list *source_list); + +int igmp_group_compat_mode(const struct igmp_sock *igmp, + const struct igmp_group *group); + +void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources); +void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources); +void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources); +void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources); +void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources); +void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, + struct in_addr group_addr, + int num_sources, struct in_addr *sources); + +void igmp_group_timer_lower_to_lmqt(struct igmp_group *group); +void igmp_source_timer_lower_to_lmqt(struct igmp_source *source); + +struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, + struct in_addr src_addr); + +void pim_igmp_send_membership_query(struct igmp_group *group, + int fd, + const char *ifname, + char *query_buf, + int query_buf_size, + int num_sources, + struct in_addr dst_addr, + struct in_addr group_addr, + int query_max_response_time_dsec, + uint8_t s_flag, + uint8_t querier_robustness_variable, + uint16_t querier_query_interval); + +#endif /* PIM_IGMPV3_H */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c new file mode 100644 index 000000000..ce4ec4e6c --- /dev/null +++ b/pimd/pim_join.c @@ -0,0 +1,428 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "prefix.h" + +#include "pimd.h" +#include "pim_str.h" +#include "pim_tlv.h" +#include "pim_msg.h" +#include "pim_pim.h" +#include "pim_join.h" +#include "pim_iface.h" +#include "pim_hello.h" +#include "pim_ifchannel.h" + +static void on_trace(const char *label, + struct interface *ifp, struct in_addr src) +{ + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src, src_str, sizeof(src_str)); + zlog_debug("%s: from %s on %s", + label, src_str, ifp->name); + } +} + +static void recv_join(struct interface *ifp, + struct pim_neighbor *neigh, + uint16_t holdtime, + struct in_addr upstream, + struct in_addr group, + struct in_addr source, + uint8_t source_flags) +{ + if (PIM_DEBUG_PIM_TRACE) { + char up_str[100]; + char src_str[100]; + char grp_str[100]; + char neigh_str[100]; + pim_inet4_dump("", upstream, up_str, sizeof(up_str)); + pim_inet4_dump("", source, src_str, sizeof(src_str)); + pim_inet4_dump("", group, grp_str, sizeof(grp_str)); + pim_inet4_dump("", neigh->source_addr, neigh_str, sizeof(neigh_str)); + zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + source_flags & PIM_RPT_BIT_MASK, + source_flags & PIM_WILDCARD_BIT_MASK, + up_str, holdtime, neigh_str, ifp->name); + } + + /* Restart join expiry timer */ + pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, + source, group, source_flags, holdtime); +} + +static void recv_prune(struct interface *ifp, + struct pim_neighbor *neigh, + uint16_t holdtime, + struct in_addr upstream, + struct in_addr group, + struct in_addr source, + uint8_t source_flags) +{ + if (PIM_DEBUG_PIM_TRACE) { + char up_str[100]; + char src_str[100]; + char grp_str[100]; + char neigh_str[100]; + pim_inet4_dump("", upstream, up_str, sizeof(up_str)); + pim_inet4_dump("", source, src_str, sizeof(src_str)); + pim_inet4_dump("", group, grp_str, sizeof(grp_str)); + pim_inet4_dump("", neigh->source_addr, neigh_str, sizeof(neigh_str)); + zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + source_flags & PIM_RPT_BIT_MASK, + source_flags & PIM_WILDCARD_BIT_MASK, + up_str, holdtime, neigh_str, ifp->name); + } + + pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime); +} + +int pim_joinprune_recv(struct interface *ifp, + struct pim_neighbor *neigh, + struct in_addr src_addr, + char *tlv_buf, int tlv_buf_size) +{ + struct prefix msg_upstream_addr; + uint8_t msg_num_groups; + uint16_t msg_holdtime; + int addr_offset; + char *buf; + char *pastend; + int remain; + int group; + + on_trace(__PRETTY_FUNCTION__, ifp, src_addr); + + buf = tlv_buf; + pastend = tlv_buf + tlv_buf_size; + + /* + Parse ucast addr + */ + addr_offset = pim_parse_addr_ucast(ifp->name, src_addr, + &msg_upstream_addr, + buf, pastend - buf); + if (addr_offset < 1) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + return -1; + } + buf += addr_offset; + + /* + Check upstream address family + */ + if (msg_upstream_addr.family != AF_INET) { + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", + __PRETTY_FUNCTION__, + msg_upstream_addr.family, src_str, ifp->name); + } + return -2; + } + + remain = pastend - buf; + if (remain < 4) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", + __PRETTY_FUNCTION__, + remain, 4, src_str, ifp->name); + return -4; + } + + ++buf; /* skip reserved byte */ + msg_num_groups = *(const uint8_t *) buf; + ++buf; + msg_holdtime = ntohs(*(const uint16_t *) buf); + ++buf; + ++buf; + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char upstream_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", msg_upstream_addr.u.prefix4, + upstream_str, sizeof(upstream_str)); + zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", + __PRETTY_FUNCTION__, + upstream_str, msg_num_groups, msg_holdtime, + src_str, ifp->name); + } + + /* Scan groups */ + for (group = 0; group < msg_num_groups; ++group) { + struct prefix msg_group_addr; + struct prefix msg_source_addr; + uint8_t msg_source_flags; + uint16_t msg_num_joined_sources; + uint16_t msg_num_pruned_sources; + int source; + + addr_offset = pim_parse_addr_group(ifp->name, src_addr, + &msg_group_addr, + buf, pastend - buf); + if (addr_offset < 1) { + return -5; + } + buf += addr_offset; + + remain = pastend - buf; + if (remain < 4) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", + __PRETTY_FUNCTION__, + remain, 4, src_str, ifp->name); + return -6; + } + + msg_num_joined_sources = ntohs(*(const uint16_t *) buf); + buf += 2; + msg_num_pruned_sources = ntohs(*(const uint16_t *) buf); + buf += 2; + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char upstream_str[100]; + char group_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", msg_upstream_addr.u.prefix4, + upstream_str, sizeof(upstream_str)); + pim_inet4_dump("", msg_group_addr.u.prefix4, + group_str, sizeof(group_str)); + zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s", + __PRETTY_FUNCTION__, + upstream_str, group_str, msg_group_addr.prefixlen, + msg_num_joined_sources, msg_num_pruned_sources, + src_str, ifp->name); + } + + /* Scan joined sources */ + for (source = 0; source < msg_num_joined_sources; ++source) { + addr_offset = pim_parse_addr_source(ifp->name, src_addr, + &msg_source_addr, + &msg_source_flags, + buf, pastend - buf); + if (addr_offset < 1) { + return -7; + } + buf += addr_offset; + + recv_join(ifp, neigh, msg_holdtime, + msg_upstream_addr.u.prefix4, + msg_group_addr.u.prefix4, + msg_source_addr.u.prefix4, + msg_source_flags); + } + + /* Scan pruned sources */ + for (source = 0; source < msg_num_pruned_sources; ++source) { + addr_offset = pim_parse_addr_source(ifp->name, src_addr, + &msg_source_addr, + &msg_source_flags, + buf, pastend - buf); + if (addr_offset < 1) { + return -8; + } + buf += addr_offset; + + recv_prune(ifp, neigh, msg_holdtime, + msg_upstream_addr.u.prefix4, + msg_group_addr.u.prefix4, + msg_source_addr.u.prefix4, + msg_source_flags); + } + + } /* scan groups */ + + return 0; +} + +int pim_joinprune_send(struct interface *ifp, + struct in_addr upstream_addr, + struct in_addr source_addr, + struct in_addr group_addr, + int send_join) +{ + struct pim_interface *pim_ifp; + char pim_msg[1000]; + const char *pastend = pim_msg + sizeof(pim_msg); + char *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */ + int pim_msg_size; + int remain; + + zassert(ifp); + + pim_ifp = ifp->info; + + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + return -1; + } + + if (PIM_DEBUG_PIM_TRACE) { + char source_str[100]; + char group_str[100]; + char dst_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); + zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s", + __PRETTY_FUNCTION__, + send_join ? "Join" : "Prune", + source_str, group_str, dst_str, ifp->name); + } + + if (PIM_INADDR_IS_ANY(upstream_addr)) { + if (PIM_DEBUG_PIM_TRACE) { + char source_str[100]; + char group_str[100]; + char dst_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); + zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s", + __PRETTY_FUNCTION__, + send_join ? "Join" : "Prune", + source_str, group_str, dst_str, ifp->name); + } + return 0; + } + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + Thus, if a router needs to send a Join/Prune or Assert message on + an interface on which it has not yet sent a Hello message with the + currently configured IP address, then it MUST immediately send the + relevant Hello message without waiting for the Hello Timer to + expire, followed by the Join/Prune or Assert message. + */ + pim_hello_require(ifp); + + /* + Build PIM message + */ + + remain = pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, + remain, + upstream_addr); + if (!pim_msg_curr) { + char dst_str[100]; + pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); + zlog_warn("%s: failure encoding destination address %s: space left=%d", + __PRETTY_FUNCTION__, dst_str, remain); + return -3; + } + + remain = pastend - pim_msg_curr; + if (remain < 4) { + zlog_warn("%s: group will not fit: space left=%d", + __PRETTY_FUNCTION__, remain); + return -4; + } + + *pim_msg_curr = 0; /* reserved */ + ++pim_msg_curr; + *pim_msg_curr = 1; /* number of groups */ + ++pim_msg_curr; + *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME); + ++pim_msg_curr; + ++pim_msg_curr; + + remain = pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, + remain, + group_addr); + if (!pim_msg_curr) { + char group_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: failure encoding group address %s: space left=%d", + __PRETTY_FUNCTION__, group_str, remain); + return -5; + } + + remain = pastend - pim_msg_curr; + if (remain < 4) { + zlog_warn("%s: sources will not fit: space left=%d", + __PRETTY_FUNCTION__, remain); + return -6; + } + + /* number of joined sources */ + *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0); + ++pim_msg_curr; + ++pim_msg_curr; + + /* number of pruned sources */ + *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1); + ++pim_msg_curr; + ++pim_msg_curr; + + remain = pastend - pim_msg_curr; + pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr, + remain, + source_addr); + if (!pim_msg_curr) { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: failure encoding source address %s: space left=%d", + __PRETTY_FUNCTION__, source_str, remain); + return -7; + } + + /* Add PIM header */ + + pim_msg_size = pim_msg_curr - pim_msg; + + pim_msg_build_header(pim_msg, pim_msg_size, + PIM_MSG_TYPE_JOIN_PRUNE); + + if (pim_msg_send(pim_ifp->pim_sock_fd, + qpim_all_pim_routers_addr, + pim_msg, + pim_msg_size, + ifp->name)) { + zlog_warn("%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, ifp->name); + return -8; + } + + return 0; +} diff --git a/pimd/pim_join.h b/pimd/pim_join.h new file mode 100644 index 000000000..4d9407be1 --- /dev/null +++ b/pimd/pim_join.h @@ -0,0 +1,43 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_JOIN_H +#define PIM_JOIN_H + +#include + +#include "if.h" + +#include "pim_neighbor.h" + +int pim_joinprune_recv(struct interface *ifp, + struct pim_neighbor *neigh, + struct in_addr src_addr, + char *tlv_buf, int tlv_buf_size); + +int pim_joinprune_send(struct interface *ifp, + struct in_addr upstream_addr, + struct in_addr source_addr, + struct in_addr group_addr, + int send_join); + +#endif /* PIM_JOIN_H */ diff --git a/pimd/pim_macro.c b/pimd/pim_macro.c new file mode 100644 index 000000000..3f5653252 --- /dev/null +++ b/pimd/pim_macro.c @@ -0,0 +1,437 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" + +#include "pim_macro.h" +#include "pimd.h" +#include "pim_str.h" +#include "pim_iface.h" +#include "pim_ifchannel.h" + +#define PIM_IFP_I_am_DR(pim_ifp) ((pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr) + +/* + DownstreamJPState(S,G,I) is the per-interface state machine for + receiving (S,G) Join/Prune messages. + + DownstreamJPState(S,G,I) is either Join or Prune-Pending ? +*/ +static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch) +{ + return ch->ifjoin_state != PIM_IFJOIN_NOINFO; +} + +/* + The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD + module or other local membership mechanism has determined that local + members on interface I desire to receive traffic sent specifically + by S to G. +*/ +static int local_receiver_include(const struct pim_ifchannel *ch) +{ + /* local_receiver_include(S,G,I) ? */ + return ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE; +} + +/* + RFC 4601: 4.1.6. State Summarization Macros + + The set "joins(S,G)" is the set of all interfaces on which the + router has received (S,G) Joins: + + joins(S,G) = + { all interfaces I such that + DownstreamJPState(S,G,I) is either Join or Prune-Pending } + + DownstreamJPState(S,G,I) is either Join or Prune-Pending ? +*/ +int pim_macro_chisin_joins(const struct pim_ifchannel *ch) +{ + return downstream_jpstate_isjoined(ch); +} + +/* + RFC 4601: 4.6.5. Assert State Macros + + The set "lost_assert(S,G)" is the set of all interfaces on which the + router has received (S,G) joins but has lost an (S,G) assert. + + lost_assert(S,G) = + { all interfaces I such that + lost_assert(S,G,I) == TRUE } + + bool lost_assert(S,G,I) { + if ( RPF_interface(S) == I ) { + return FALSE + } else { + return ( AssertWinner(S,G,I) != NULL AND + AssertWinner(S,G,I) != me AND + (AssertWinnerMetric(S,G,I) is better + than spt_assert_metric(S,I) ) + } + } + + AssertWinner(S,G,I) is the IP source address of the Assert(S,G) + packet that won an Assert. +*/ +int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_assert_metric spt_assert_metric; + + ifp = ch->interface; + if (!ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): null interface", + __PRETTY_FUNCTION__, + src_str, grp_str); + return 0; /* false */ + } + + /* RPF_interface(S) == I ? */ + if (ch->upstream->rpf.source_nexthop.interface == ifp) + return 0; /* false */ + + pim_ifp = ifp->info; + if (!pim_ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return 0; /* false */ + } + + if (PIM_INADDR_IS_ANY(ch->ifassert_winner)) + return 0; /* false */ + + /* AssertWinner(S,G,I) == me ? */ + if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + return 0; /* false */ + + spt_assert_metric = pim_macro_spt_assert_metric(&ch->upstream->rpf, + pim_ifp->primary_address); + + return pim_assert_metric_better(&ch->ifassert_winner_metric, + &spt_assert_metric); +} + +/* + RFC 4601: 4.1.6. State Summarization Macros + + pim_include(S,G) = + { all interfaces I such that: + ( (I_am_DR( I ) AND lost_assert(S,G,I) == FALSE ) + OR AssertWinner(S,G,I) == me ) + AND local_receiver_include(S,G,I) } + + AssertWinner(S,G,I) is the IP source address of the Assert(S,G) + packet that won an Assert. +*/ +int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch) +{ + struct pim_interface *pim_ifp = ch->interface->info; + + if (!pim_ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name); + return 0; /* false */ + } + + /* local_receiver_include(S,G,I) ? */ + if (!local_receiver_include(ch)) + return 0; /* false */ + + /* OR AssertWinner(S,G,I) == me ? */ + if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + return 1; /* true */ + + return ( + /* I_am_DR( I ) ? */ + PIM_IFP_I_am_DR(pim_ifp) + && + /* lost_assert(S,G,I) == FALSE ? */ + (!pim_macro_ch_lost_assert(ch)) + ); +} + +int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch) +{ + if (pim_macro_chisin_joins(ch)) + return 1; /* true */ + + return pim_macro_chisin_pim_include(ch); +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + CouldAssert(S,G,I) = + SPTbit(S,G)==TRUE + AND (RPF_interface(S) != I) + AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) ) + (+) ( pim_include(*,G) (-) pim_exclude(S,G) ) + (-) lost_assert(*,G) + (+) joins(S,G) (+) pim_include(S,G) ) ) + + CouldAssert(S,G,I) is true for downstream interfaces that would be in + the inherited_olist(S,G) if (S,G) assert information was not taken + into account. + + CouldAssert(S,G,I) may be affected by changes in the following: + + pim_ifp->primary_address + pim_ifp->pim_dr_addr + ch->ifassert_winner_metric + ch->ifassert_winner + ch->local_ifmembership + ch->ifjoin_state + ch->upstream->rpf.source_nexthop.mrib_metric_preference + ch->upstream->rpf.source_nexthop.mrib_route_metric + ch->upstream->rpf.source_nexthop.interface +*/ +int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch) +{ + struct interface *ifp; + + /* SPTbit(S,G) is always true for PIM-SSM-Only Routers */ + + ifp = ch->interface; + if (!ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): null interface", + __PRETTY_FUNCTION__, + src_str, grp_str); + return 0; /* false */ + } + + /* RPF_interface(S) != I ? */ + if (ch->upstream->rpf.source_nexthop.interface == ifp) + return 0; /* false */ + + /* I in joins(S,G) (+) pim_include(S,G) ? */ + return pim_macro_chisin_joins_or_include(ch); +} + +/* + RFC 4601: 4.6.3. Assert Metrics + + spt_assert_metric(S,I) gives the assert metric we use if we're + sending an assert based on active (S,G) forwarding state: + + assert_metric + spt_assert_metric(S,I) { + return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)} + } +*/ +struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, + struct in_addr ifaddr) +{ + struct pim_assert_metric metric; + + metric.rpt_bit_flag = 0; + metric.metric_preference = rpf->source_nexthop.mrib_metric_preference; + metric.route_metric = rpf->source_nexthop.mrib_route_metric; + metric.ip_address = ifaddr; + + return metric; +} + +/* + RFC 4601: 4.6.3. Assert Metrics + + An assert metric for (S,G) to include in (or compare against) an + Assert message sent on interface I should be computed using the + following pseudocode: + + assert_metric my_assert_metric(S,G,I) { + if( CouldAssert(S,G,I) == TRUE ) { + return spt_assert_metric(S,I) + } else if( CouldAssert(*,G,I) == TRUE ) { + return rpt_assert_metric(G,I) + } else { + return infinite_assert_metric() + } + } +*/ +struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ch->interface->info; + + if (pim_ifp) { + if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { + return pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); + } + } + + return qpim_infinite_assert_metric; +} + +/* + RFC 4601 4.2. Data Packet Forwarding Rules + RFC 4601 4.8.2. PIM-SSM-Only Routers + + Macro: + inherited_olist(S,G) = + joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) +*/ +static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch) +{ + if (pim_macro_ch_lost_assert(ch)) + return 0; /* false */ + + return pim_macro_chisin_joins_or_include(ch); +} + +/* + RFC 4601 4.2. Data Packet Forwarding Rules + RFC 4601 4.8.2. PIM-SSM-Only Routers + + Additionally, the Packet forwarding rules of Section 4.2 can be + simplified in a PIM-SSM-only router: + + iif is the incoming interface of the packet. + oiflist = NULL + if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { + oiflist = inherited_olist(S,G) + } else if (iif is in inherited_olist(S,G)) { + send Assert(S,G) on iif + } + oiflist = oiflist (-) iif + forward packet on all interfaces in oiflist + + Macro: + inherited_olist(S,G) = + joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) + + Note: + - The following test is performed as response to WRONGVIF kernel + upcall: + if (iif is in inherited_olist(S,G)) { + send Assert(S,G) on iif + } + See pim_mroute.c mroute_msg(). +*/ +int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch) +{ + if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) { + /* oiflist is NULL */ + return 0; /* false */ + } + + /* oiflist = oiflist (-) iif */ + if (ch->interface == ch->upstream->rpf.source_nexthop.interface) + return 0; /* false */ + + return pim_macro_chisin_inherited_olist(ch); +} + +/* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + AssertTrackingDesired(S,G,I) = + (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) ) + (+) ( pim_include(*,G) (-) pim_exclude(S,G) ) + (-) lost_assert(*,G) + (+) joins(S,G) ) ) + OR (local_receiver_include(S,G,I) == TRUE + AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me))) + OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == TRUE)) + OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == TRUE) + AND (SPTbit(S,G) == FALSE)) + + AssertTrackingDesired(S,G,I) is true on any interface in which an + (S,G) assert might affect our behavior. +*/ +int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch) +{ + struct pim_interface *pim_ifp; + struct interface *ifp; + + ifp = ch->interface; + if (!ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): null interface", + __PRETTY_FUNCTION__, + src_str, grp_str); + return 0; /* false */ + } + + pim_ifp = ifp->info; + if (!pim_ifp) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name); + return 0; /* false */ + } + + /* I in joins(S,G) ? */ + if (pim_macro_chisin_joins(ch)) + return 1; /* true */ + + /* local_receiver_include(S,G,I) ? */ + if (local_receiver_include(ch)) { + /* I_am_DR(I) ? */ + if (PIM_IFP_I_am_DR(pim_ifp)) + return 1; /* true */ + + /* AssertWinner(S,G,I) == me ? */ + if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + return 1; /* true */ + } + + /* RPF_interface(S) == I ? */ + if (ch->upstream->rpf.source_nexthop.interface == ifp) { + /* JoinDesired(S,G) ? */ + if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags)) + return 1; /* true */ + } + + return 0; /* false */ +} + diff --git a/pimd/pim_macro.h b/pimd/pim_macro.h new file mode 100644 index 000000000..472fa9b4e --- /dev/null +++ b/pimd/pim_macro.h @@ -0,0 +1,44 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_MACRO_H +#define PIM_MACRO_H + +#include + +#include "if.h" + +#include "pim_upstream.h" +#include "pim_ifchannel.h" + +int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch); +int pim_macro_chisin_joins(const struct pim_ifchannel *ch); +int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch); +int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch); +int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch); +struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, + struct in_addr ifaddr); +struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch); +int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch); +int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch); + +#endif /* PIM_MACRO_H */ diff --git a/pimd/pim_main.c b/pimd/pim_main.c new file mode 100644 index 000000000..1206b5514 --- /dev/null +++ b/pimd/pim_main.c @@ -0,0 +1,276 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "version.h" +#include +#include "command.h" +#include "thread.h" +#include + +#include "memory.h" +#include "filter.h" +#include "vty.h" +#include "sigevent.h" +#include "version.h" + +#include "pimd.h" +#include "pim_version.h" +#include "pim_signals.h" +#include "pim_zebra.h" + +#ifdef PIM_ZCLIENT_DEBUG +extern int zclient_debug; +#endif + +extern struct host host; +extern const char *default_motd; + +char config_default[] = SYSCONFDIR PIMD_DEFAULT_CONFIG; + +struct option longopts[] = { + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { "debug_zclient", no_argument, NULL, 'Z'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +char* progname; +const char *pid_file = PATH_PIMD_PID; + +static void usage(int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages PIM.\n\n\ +-d, --daemon Run in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +" + +#ifdef PIM_ZCLIENT_DEBUG +"\ +-Z, --debug_zclient Enable zclient debugging\n\ +" +#endif + +"\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, PIMD_BUG_ADDRESS); + } + + exit (status); +} + + +int main(int argc, char** argv, char** envp) { + char *p; + char *vty_addr = NULL; + int vty_port = -1; + int daemon_mode = 0; + char *config_file = NULL; + struct thread thread; + + umask(0027); + + progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog(progname, ZLOG_PIM, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* this while just reads the options */ + while (1) { + int opt; + + opt = getopt_long (argc, argv, "df:i:A:P:vZh", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'v': + printf(PIMD_PROGNAME " version %s\n", PIMD_VERSION); + print_version(QUAGGA_PROGNAME); + exit (0); + break; +#ifdef PIM_ZCLIENT_DEBUG + case 'Z': + zclient_debug = 1; + break; +#endif + case 'h': + usage (0); + break; + default: + usage (1); + break; + } + } + + master = thread_master_create(); + + /* + * Temporarily send zlog to stdout + */ + zlog_default->maxlvl[ZLOG_DEST_STDOUT] = zlog_default->default_lvl; + zlog_notice("Boot logging temporarily directed to stdout - begin"); + + zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting", + QUAGGA_VERSION, PIMD_VERSION); + + /* + * Initializations + */ + pim_signals_init(); + cmd_init(1); + vty_init(master); + memory_init(); + access_list_init(); + pim_init(); + sort_node(); + + /* + * reset zlog default, then will obey configuration file + */ + zlog_notice("Boot logging temporarily directed to stdout - end"); +#if 0 + /* this would disable logging to stdout, but config has not been + loaded yet to reconfig the logging output */ + zlog_default->maxlvl[ZLOG_DEST_STDOUT] = ZLOG_DISABLED; +#endif + + zlog_notice("Loading configuration - begin"); + + /* Get configuration file. */ + vty_read_config(config_file, config_default); + + /* + Starting from here zlog_* functions will log according configuration + */ + + zlog_notice("Loading configuration - end"); + + /* Change to the daemon program. */ + if (daemon_mode) { + if (daemon(0, 0)) { + zlog_warn("failed to daemonize"); + } + } + + /* Process ID file creation. */ + pid_output(pid_file); + + /* Create pimd VTY socket */ + if (vty_port < 0) + vty_port = PIMD_VTY_PORT; + vty_serv_sock(vty_addr, vty_port, PIM_VTYSH_PATH); + + zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting, VTY interface at port TCP %d", + QUAGGA_VERSION, PIMD_VERSION, vty_port); + +#ifdef PIM_MOTD_VERSION + /* Tweak default MOTD to include pimd version */ + zlog_notice("PIM_MOTD_VERSION: adding pimd version to default MOTD"); + if (host.motd == default_motd) { + host.motd = + "\r\n\ +Hello, this is " QUAGGA_PROGNAME " " QUAGGA_VERSION " " PIMD_PROGNAME " " PIMD_VERSION_STR "\r\n\ +" QUAGGA_COPYRIGHT "\r\n\ +\r\n"; + } +#endif + +#ifdef PIM_DEBUG_BYDEFAULT + zlog_notice("PIM_DEBUG_BYDEFAULT: Enabling all debug commands"); + PIM_DO_DEBUG_PIM_EVENTS; + PIM_DO_DEBUG_PIM_PACKETS; + PIM_DO_DEBUG_PIM_TRACE; + PIM_DO_DEBUG_IGMP_EVENTS; + PIM_DO_DEBUG_IGMP_PACKETS; + PIM_DO_DEBUG_IGMP_TRACE; + PIM_DO_DEBUG_ZEBRA; +#endif + +#ifdef PIM_ZCLIENT_DEBUG + zlog_notice("PIM_ZCLIENT_DEBUG: zclient debugging is supported, mode is %s (see option -Z)", + zclient_debug ? "ON" : "OFF"); +#endif + +#ifdef PIM_CHECK_RECV_IFINDEX_SANITY + zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex"); +#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH + zlog_notice("PIM_REPORT_RECV_IFINDEX_MISMATCH: will report sock/recv ifindex mismatch"); +#endif +#endif + +#ifdef PIM_USE_QUAGGA_INET_CHECKSUM + zlog_notice("PIM_USE_QUAGGA_INET_CHECKSUM: using Quagga's builtin checksum"); +#endif + +#ifdef PIM_UNEXPECTED_KERNEL_UPCALL + zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); +#endif + + /* + Initialize zclient "update" and "lookup" sockets + */ + pim_zebra_init(); + + while (thread_fetch(master, &thread)) + thread_call(&thread); + + zlog_err("%s %s: thread_fetch() returned NULL, exiting", + __FILE__, __PRETTY_FUNCTION__); + + /* never reached */ + return 0; +} diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c new file mode 100644 index 000000000..f021abaa3 --- /dev/null +++ b/pimd/pim_mroute.c @@ -0,0 +1,432 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include "log.h" + +#include "pimd.h" +#include "pim_mroute.h" +#include "pim_str.h" +#include "pim_time.h" +#include "pim_iface.h" +#include "pim_macro.h" + +static void mroute_read_on(void); + +static int pim_mroute_set(int fd, int enable) +{ + int err; + int opt = enable ? MRT_INIT : MRT_DONE; + socklen_t opt_len = sizeof(opt); + + err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, strerror(e)); + errno = e; + return -1; + } + +#if 0 + zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok", + __FILE__, __PRETTY_FUNCTION__, + fd, opt); +#endif + + return 0; +} + +int pim_mroute_msg(int fd, const char *buf, int buf_size) +{ + struct interface *ifp; + const struct ip *ip_hdr; + const struct igmpmsg *msg; + const char *upcall; + char src_str[100]; + char grp_str[100]; + + ip_hdr = (const struct ip *) buf; + + /* kernel upcall must have protocol=0 */ + if (ip_hdr->ip_p) { + /* this is not a kernel upcall */ +#ifdef PIM_UNEXPECTED_KERNEL_UPCALL + zlog_warn("%s: not a kernel upcall proto=%d msg_size=%d", + __PRETTY_FUNCTION__, ip_hdr->ip_p, buf_size); +#endif + return 0; + } + + msg = (const struct igmpmsg *) buf; + + switch (msg->im_msgtype) { + case IGMPMSG_NOCACHE: upcall = "NOCACHE"; break; + case IGMPMSG_WRONGVIF: upcall = "WRONGVIF"; break; + case IGMPMSG_WHOLEPKT: upcall = "WHOLEPKT"; break; + default: upcall = ""; + } + ifp = pim_if_find_by_vif_index(msg->im_vif); + pim_inet4_dump("", msg->im_src, src_str, sizeof(src_str)); + pim_inet4_dump("", msg->im_dst, grp_str, sizeof(grp_str)); + + if (msg->im_msgtype == IGMPMSG_WRONGVIF) { + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp; + + /* + Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. + + RFC 4601 4.8.2. PIM-SSM-Only Routers + + iif is the incoming interface of the packet. + if (iif is in inherited_olist(S,G)) { + send Assert(S,G) on iif + } + */ + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", + __PRETTY_FUNCTION__, + fd, + src_str, + grp_str, + ifp ? ifp->name : "", + msg->im_vif); + } + + if (!ifp) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, + src_str, grp_str, msg->im_vif); + return -1; + } + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -2; + } + + ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst); + if (!ch) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -3; + } + + /* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + Transitions from NoInfo State + + An (S,G) data packet arrives on interface I, AND + CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an + downstream interface that is in our (S,G) outgoing interface + list. We optimistically assume that we will be the assert + winner for this (S,G), and so we transition to the "I am Assert + Winner" state and perform Actions A1 (below), which will + initiate the assert negotiation for (S,G). + */ + + if (ch->ifassert_state != PIM_IFASSERT_NOINFO) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -4; + } + + if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -5; + } + + if (assert_action_a1(ch)) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -6; + } + + return 0; + } /* IGMPMSG_WRONGVIF */ + + zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", + __PRETTY_FUNCTION__, + upcall, + msg->im_msgtype, + ip_hdr->ip_p, + fd, + src_str, + grp_str, + ifp ? ifp->name : "", + msg->im_vif); + + return 0; +} + +static int mroute_read_msg(int fd) +{ + const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg)); + char buf[1000]; + int rd; + + if (((int) sizeof(buf)) < msg_min_size) { + zlog_err("%s: fd=%d: buf size=%d lower than msg_min=%d", + __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size); + return -1; + } + + rd = read(fd, buf, sizeof(buf)); + if (rd < 0) { + zlog_warn("%s: failure reading fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, strerror(errno)); + return -2; + } + + if (rd < msg_min_size) { + zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d", + __PRETTY_FUNCTION__, fd, rd, msg_min_size); + return -3; + } + + return pim_mroute_msg(fd, buf, rd); +} + +static int mroute_read(struct thread *t) +{ + int fd; + int result; + + zassert(t); + zassert(!THREAD_ARG(t)); + + fd = THREAD_FD(t); + zassert(fd == qpim_mroute_socket_fd); + + result = mroute_read_msg(fd); + + /* Keep reading */ + qpim_mroute_socket_reader = 0; + mroute_read_on(); + + return result; +} + +static void mroute_read_on() +{ + zassert(!qpim_mroute_socket_reader); + zassert(PIM_MROUTE_IS_ENABLED); + + THREAD_READ_ON(master, qpim_mroute_socket_reader, + mroute_read, 0, qpim_mroute_socket_fd); +} + +static void mroute_read_off() +{ + THREAD_OFF(qpim_mroute_socket_reader); +} + +int pim_mroute_socket_enable() +{ + int fd; + + if (PIM_MROUTE_IS_ENABLED) + return -1; + + fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + if (fd < 0) { + zlog_warn("Could not create mroute socket: errno=%d: %s", + errno, strerror(errno)); + return -2; + } + + if (pim_mroute_set(fd, 1)) { + zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return -3; + } + + qpim_mroute_socket_fd = fd; + qpim_mroute_socket_creation = pim_time_monotonic_sec(); + mroute_read_on(); + + zassert(PIM_MROUTE_IS_ENABLED); + + return 0; +} + +int pim_mroute_socket_disable() +{ + if (PIM_MROUTE_IS_DISABLED) + return -1; + + if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { + zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s", + qpim_mroute_socket_fd, errno, strerror(errno)); + return -2; + } + + if (close(qpim_mroute_socket_fd)) { + zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", + qpim_mroute_socket_fd, errno, strerror(errno)); + return -3; + } + + mroute_read_off(); + qpim_mroute_socket_fd = -1; + + zassert(PIM_MROUTE_IS_DISABLED); + + return 0; +} + +/* + For each network interface (e.g., physical or a virtual tunnel) that + would be used for multicast forwarding, a corresponding multicast + interface must be added to the kernel. + */ +int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) +{ + struct vifctl vc; + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + memset(&vc, 0, sizeof(vc)); + vc.vifc_vifi = vif_index; + vc.vifc_flags = 0; + vc.vifc_threshold = PIM_MROUTE_MIN_TTL; + vc.vifc_rate_limit = 0; + memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr)); + +#ifdef PIM_DVMRP_TUNNEL + if (vc.vifc_flags & VIFF_TUNNEL) { + memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr)); + } +#endif + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); + if (err) { + char ifaddr_str[100]; + int e = errno; + + pim_inet4_dump("", ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, vif_index, ifaddr_str, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} + +int pim_mroute_del_vif(int vif_index) +{ + struct vifctl vc; + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + memset(&vc, 0, sizeof(vc)); + vc.vifc_vifi = vif_index; + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc)); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, vif_index, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} + +int pim_mroute_add(struct mfcctl *mc) +{ + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, + mc, sizeof(*mc)); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} + +int pim_mroute_del(struct mfcctl *mc) +{ + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc)); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h new file mode 100644 index 000000000..350b1e373 --- /dev/null +++ b/pimd/pim_mroute.h @@ -0,0 +1,173 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_MROUTE_H +#define PIM_MROUTE_H + +/* + For msghdr.msg_control in Solaris 10 +*/ +#ifndef _XPG4_2 +#define _XPG4_2 +#endif +#ifndef __EXTENSIONS__ +#define __EXTENSIONS__ +#endif + +#include +#ifdef HAVE_NETINET_IP_MROUTE_H +#include +#endif + +#define PIM_MROUTE_MIN_TTL (1) + +/* + Below: from +*/ + +#ifndef MAXVIFS +#define MAXVIFS (32) +#endif + +#ifndef SIOCGETVIFCNT +#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ +#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) +#define SIOCGETRPF (SIOCPROTOPRIVATE+2) +#endif + +#ifndef MRT_INIT +#define MRT_BASE 200 +#define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */ +#define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */ +#define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */ +#define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */ +#define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */ +#define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ +#define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ +#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ +#define MRT_PIM (MRT_BASE+8) /* enable PIM code */ +#endif + +#ifndef HAVE_VIFI_T +typedef unsigned short vifi_t; +#endif + +#ifndef HAVE_STRUCT_VIFCTL +struct vifctl { + vifi_t vifc_vifi; /* Index of VIF */ + unsigned char vifc_flags; /* VIFF_ flags */ + unsigned char vifc_threshold; /* ttl limit */ + unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ + struct in_addr vifc_lcl_addr; /* Our address */ + struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ +}; +#endif + +#ifndef HAVE_STRUCT_MFCCTL +struct mfcctl { + struct in_addr mfcc_origin; /* Origin of mcast */ + struct in_addr mfcc_mcastgrp; /* Group in question */ + vifi_t mfcc_parent; /* Where it arrived */ + unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */ + unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */ + unsigned int mfcc_byte_cnt; + unsigned int mfcc_wrong_if; + int mfcc_expire; +}; +#endif + +/* + * Group count retrieval for mrouted + */ +/* + struct sioc_sg_req sgreq; + memset(&sgreq, 0, sizeof(sgreq)); + memcpy(&sgreq.src, &source_addr, sizeof(sgreq.src)); + memcpy(&sgreq.grp, &group_addr, sizeof(sgreq.grp)); + ioctl(mrouter_s4, SIOCGETSGCNT, &sgreq); + */ +#ifndef HAVE_STRUCT_SIOC_SG_REQ +struct sioc_sg_req { + struct in_addr src; + struct in_addr grp; + unsigned long pktcnt; + unsigned long bytecnt; + unsigned long wrong_if; +}; +#endif + +/* + * To get vif packet counts + */ +/* + struct sioc_vif_req vreq; + memset(&vreq, 0, sizeof(vreq)); + vreq.vifi = vif_index; + ioctl(mrouter_s4, SIOCGETVIFCNT, &vreq); + */ +#ifndef HAVE_STRUCT_SIOC_VIF_REQ +struct sioc_vif_req { + vifi_t vifi; /* Which iface */ + unsigned long icount; /* In packets */ + unsigned long ocount; /* Out packets */ + unsigned long ibytes; /* In bytes */ + unsigned long obytes; /* Out bytes */ +}; +#endif + +/* + * Pseudo messages used by mrouted + */ +#ifndef IGMPMSG_NOCACHE +#define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ +#define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ +#define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ +#endif + +#ifndef HAVE_STRUCT_IGMPMSG +struct igmpmsg +{ + uint32_t unused1,unused2; + unsigned char im_msgtype; /* What is this */ + unsigned char im_mbz; /* Must be zero */ + unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */ + unsigned char unused3; + struct in_addr im_src,im_dst; +}; +#endif + +/* + Above: from +*/ + +int pim_mroute_socket_enable(void); +int pim_mroute_socket_disable(void); + +int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr); +int pim_mroute_del_vif(int vif_index); + +int pim_mroute_add(struct mfcctl *mc); +int pim_mroute_del(struct mfcctl *mc); + +int pim_mroute_msg(int fd, const char *buf, int buf_size); + +#endif /* PIM_MROUTE_H */ diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c new file mode 100644 index 000000000..76f78f8ae --- /dev/null +++ b/pimd/pim_msg.c @@ -0,0 +1,106 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "pimd.h" +#include "pim_pim.h" +#include "pim_msg.h" +#include "pim_util.h" + +void pim_msg_build_header(char *pim_msg, int pim_msg_size, + uint8_t pim_msg_type) +{ + uint16_t checksum; + + zassert(pim_msg_size >= PIM_PIM_MIN_LEN); + + /* + * Write header + */ + + *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type; + *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0; + + /* + * Compute checksum + */ + + *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; + checksum = pim_inet_checksum(pim_msg, pim_msg_size); + *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum; +} + +char *pim_msg_addr_encode_ipv4_ucast(char *buf, + int buf_size, + struct in_addr addr) +{ + const int ENCODED_IPV4_UCAST_SIZE = 6; + + if (buf_size < ENCODED_IPV4_UCAST_SIZE) { + return 0; + } + + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ + buf[1] = '\0'; /* native encoding */ + *(struct in_addr *)(buf + 2) = addr; + + return buf + ENCODED_IPV4_UCAST_SIZE; +} + +char *pim_msg_addr_encode_ipv4_group(char *buf, + int buf_size, + struct in_addr addr) +{ + const int ENCODED_IPV4_GROUP_SIZE = 8; + + if (buf_size < ENCODED_IPV4_GROUP_SIZE) { + return 0; + } + + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf[2] = '\0'; /* reserved */ + buf[3] = 32; /* mask len */ + *(struct in_addr *)(buf + 4) = addr; + + return buf + ENCODED_IPV4_GROUP_SIZE; +} + +char *pim_msg_addr_encode_ipv4_source(char *buf, + int buf_size, + struct in_addr addr) +{ + const int ENCODED_IPV4_SOURCE_SIZE = 8; + + if (buf_size < ENCODED_IPV4_SOURCE_SIZE) { + return 0; + } + + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf[2] = '\0'; /* reserved */ + buf[3] = 32; /* mask len */ + *(struct in_addr *)(buf + 4) = addr; + + return buf + ENCODED_IPV4_SOURCE_SIZE; +} diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h new file mode 100644 index 000000000..228d6a856 --- /dev/null +++ b/pimd/pim_msg.h @@ -0,0 +1,52 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_MSG_H +#define PIM_MSG_H + +#include + +/* + Number Description + ---------- ------------------ + 0 Reserved + 1 IP (IP version 4) + 2 IP6 (IP version 6) + + From: + http://www.iana.org/assignments/address-family-numbers +*/ +#define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) + +void pim_msg_build_header(char *pim_msg, int pim_msg_size, + uint8_t pim_msg_type); +char *pim_msg_addr_encode_ipv4_ucast(char *buf, + int buf_size, + struct in_addr addr); +char *pim_msg_addr_encode_ipv4_group(char *buf, + int buf_size, + struct in_addr addr); +char *pim_msg_addr_encode_ipv4_source(char *buf, + int buf_size, + struct in_addr addr); + +#endif /* PIM_MSG_H */ diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c new file mode 100644 index 000000000..67aa9d088 --- /dev/null +++ b/pimd/pim_neighbor.c @@ -0,0 +1,696 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "prefix.h" +#include "memory.h" + +#include "pimd.h" +#include "pim_neighbor.h" +#include "pim_time.h" +#include "pim_str.h" +#include "pim_iface.h" +#include "pim_pim.h" +#include "pim_upstream.h" +#include "pim_ifchannel.h" + +static void dr_election_by_addr(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct pim_neighbor *neigh; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + pim_ifp->pim_dr_addr = pim_ifp->primary_address; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { + if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) { + pim_ifp->pim_dr_addr = neigh->source_addr; + } + } +} + +static void dr_election_by_pri(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct pim_neighbor *neigh; + uint32_t dr_pri; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + pim_ifp->pim_dr_addr = pim_ifp->primary_address; + dr_pri = pim_ifp->pim_dr_priority; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { + if ( + (neigh->dr_priority > dr_pri) || + ( + (neigh->dr_priority == dr_pri) && + (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) + ) + ) { + pim_ifp->pim_dr_addr = neigh->source_addr; + dr_pri = neigh->dr_priority; + } + } +} + +/* + RFC 4601: 4.3.2. DR Election + + A router's idea of the current DR on an interface can change when a + PIM Hello message is received, when a neighbor times out, or when a + router's own DR Priority changes. + */ +void pim_if_dr_election(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + struct in_addr old_dr_addr; + + pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ + ++pim_ifp->pim_dr_election_count; + + old_dr_addr = pim_ifp->pim_dr_addr; + + if (pim_ifp->pim_dr_num_nondrpri_neighbors) { + dr_election_by_addr(ifp); + } + else { + dr_election_by_pri(ifp); + } + + /* DR changed ? */ + if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { + char dr_old_str[100]; + char dr_new_str[100]; + pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); + pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); + zlog_info("%s: DR was %s now is %s on interface %s", + __PRETTY_FUNCTION__, + dr_old_str, dr_new_str, ifp->name); + + pim_if_update_join_desired(pim_ifp); + pim_if_update_could_assert(ifp); + pim_if_update_assert_tracking_desired(ifp); + } +} + +static void update_dr_priority(struct pim_neighbor *neigh, + pim_hello_options hello_options, + uint32_t dr_priority) +{ + pim_hello_options will_set_pri; /* boolean */ + pim_hello_options bit_flip; /* boolean */ + pim_hello_options pri_change; /* boolean */ + + will_set_pri = PIM_OPTION_IS_SET(hello_options, + PIM_OPTION_MASK_DR_PRIORITY); + + bit_flip = + ( + will_set_pri != + PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) + ); + + if (bit_flip) { + struct pim_interface *pim_ifp = neigh->interface->info; + + /* update num. of neighbors without dr_pri */ + + if (will_set_pri) { + --pim_ifp->pim_dr_num_nondrpri_neighbors; + } + else { + ++pim_ifp->pim_dr_num_nondrpri_neighbors; + } + } + + pri_change = + ( + bit_flip + || + (neigh->dr_priority != dr_priority) + ); + + if (will_set_pri) { + neigh->dr_priority = dr_priority; + } + else { + neigh->dr_priority = 0; /* cosmetic unset */ + } + + if (pri_change) { + /* + RFC 4601: 4.3.2. DR Election + + A router's idea of the current DR on an interface can change when a + PIM Hello message is received, when a neighbor times out, or when a + router's own DR Priority changes. + */ + pim_if_dr_election(neigh->interface); + } +} + +static int on_neighbor_timer(struct thread *t) +{ + struct pim_neighbor *neigh; + struct interface *ifp; + char msg[100]; + + zassert(t); + neigh = THREAD_ARG(t); + zassert(neigh); + + ifp = neigh->interface; + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); + zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s", + neigh->holdtime, src_str, ifp->name); + } + + neigh->t_expire_timer = 0; + + snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); + pim_neighbor_delete(ifp, neigh, msg); + + /* + RFC 4601: 4.3.2. DR Election + + A router's idea of the current DR on an interface can change when a + PIM Hello message is received, when a neighbor times out, or when a + router's own DR Priority changes. + */ + pim_if_dr_election(ifp); + + return 0; +} + +static void neighbor_timer_off(struct pim_neighbor *neigh) +{ + if (PIM_DEBUG_PIM_TRACE) { + if (neigh->t_expire_timer) { + char src_str[100]; + pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); + zlog_debug("%s: cancelling timer for neighbor %s on %s", + __PRETTY_FUNCTION__, + src_str, neigh->interface->name); + } + } + THREAD_OFF(neigh->t_expire_timer); + zassert(!neigh->t_expire_timer); +} + +void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) +{ + neigh->holdtime = holdtime; + + neighbor_timer_off(neigh); + + /* + 0xFFFF is request for no holdtime + */ + if (neigh->holdtime == 0xFFFF) { + return; + } + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); + zlog_debug("%s: starting %u sec timer for neighbor %s on %s", + __PRETTY_FUNCTION__, + neigh->holdtime, src_str, neigh->interface->name); + } + + THREAD_TIMER_ON(master, neigh->t_expire_timer, + on_neighbor_timer, + neigh, neigh->holdtime); +} + +static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, + struct in_addr source_addr, + pim_hello_options hello_options, + uint16_t holdtime, + uint16_t propagation_delay, + uint16_t override_interval, + uint32_t dr_priority, + uint32_t generation_id, + struct list *addr_list) +{ + struct pim_interface *pim_ifp; + struct pim_neighbor *neigh; + char src_str[100]; + + zassert(ifp); + pim_ifp = ifp->info; + zassert(pim_ifp); + + neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); + if (!neigh) { + zlog_err("%s: PIM XMALLOC(%d) failure", + __PRETTY_FUNCTION__, sizeof(*neigh)); + return 0; + } + + neigh->creation = pim_time_monotonic_sec(); + neigh->source_addr = source_addr; + neigh->hello_options = hello_options; + neigh->propagation_delay_msec = propagation_delay; + neigh->override_interval_msec = override_interval; + neigh->dr_priority = dr_priority; + neigh->generation_id = generation_id; + neigh->prefix_list = addr_list; + neigh->t_expire_timer = 0; + neigh->interface = ifp; + + pim_neighbor_timer_reset(neigh, holdtime); + + pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); + + if (PIM_DEBUG_PIM_EVENTS) { + zlog_debug("%s: creating PIM neighbor %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + } + + zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", + src_str, ifp->name); + + if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { + pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec; + } + if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) { + pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec; + } + + if (!PIM_OPTION_IS_SET(neigh->hello_options, + PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { + /* update num. of neighbors without hello option lan_delay */ + ++pim_ifp->pim_number_of_nonlandelay_neighbors; + } + + if (!PIM_OPTION_IS_SET(neigh->hello_options, + PIM_OPTION_MASK_DR_PRIORITY)) { + /* update num. of neighbors without hello option dr_pri */ + ++pim_ifp->pim_dr_num_nondrpri_neighbors; + } + + /* + RFC 4601: 4.3.2. DR Election + + A router's idea of the current DR on an interface can change when a + PIM Hello message is received, when a neighbor times out, or when a + router's own DR Priority changes. + */ + pim_if_dr_election(neigh->interface); + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + To allow new or rebooting routers to learn of PIM neighbors quickly, + when a Hello message is received from a new neighbor, or a Hello + message with a new GenID is received from an existing neighbor, a + new Hello message should be sent on this interface after a + randomized delay between 0 and Triggered_Hello_Delay. + */ + pim_hello_restart_triggered(neigh->interface); + + return neigh; +} + +static void delete_prefix_list(struct pim_neighbor *neigh) +{ + if (neigh->prefix_list) { + +#ifdef DUMP_PREFIX_LIST + struct listnode *p_node; + struct prefix *p; + char addr_str[10]; + int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1; + int i = 0; + for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) { + pim_inet4_dump("", p->u.prefix4, addr_str, sizeof(addr_str)); + zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]", + __PRETTY_FUNCTION__, + (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p, + addr_str, i, list_size); + ++i; + } +#endif + + list_delete(neigh->prefix_list); + neigh->prefix_list = 0; + } +} + +void pim_neighbor_free(struct pim_neighbor *neigh) +{ + zassert(!neigh->t_expire_timer); + + delete_prefix_list(neigh); + + XFREE(MTYPE_PIM_NEIGHBOR, neigh); +} + +struct pim_neighbor *pim_neighbor_find(struct interface *ifp, + struct in_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct pim_neighbor *neigh; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { + if (source_addr.s_addr == neigh->source_addr.s_addr) { + return neigh; + } + } + + return 0; +} + +struct pim_neighbor *pim_neighbor_add(struct interface *ifp, + struct in_addr source_addr, + pim_hello_options hello_options, + uint16_t holdtime, + uint16_t propagation_delay, + uint16_t override_interval, + uint32_t dr_priority, + uint32_t generation_id, + struct list *addr_list) +{ + struct pim_interface *pim_ifp; + struct pim_neighbor *neigh; + + neigh = pim_neighbor_new(ifp, source_addr, + hello_options, + holdtime, + propagation_delay, + override_interval, + dr_priority, + generation_id, + addr_list); + if (!neigh) { + return 0; + } + + pim_ifp = ifp->info; + zassert(pim_ifp); + + listnode_add(pim_ifp->pim_neighbor_list, neigh); + + return neigh; +} + +static uint16_t +find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp, + struct pim_neighbor *highest_neigh) +{ + struct pim_interface *pim_ifp; + struct listnode *neigh_node; + struct pim_neighbor *neigh; + uint16_t next_highest_delay_msec; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { + if (neigh == highest_neigh) + continue; + if (neigh->propagation_delay_msec > next_highest_delay_msec) + next_highest_delay_msec = neigh->propagation_delay_msec; + } + + return next_highest_delay_msec; +} + +static uint16_t +find_neighbors_next_highest_override_interval_msec(struct interface *ifp, + struct pim_neighbor *highest_neigh) +{ + struct pim_interface *pim_ifp; + struct listnode *neigh_node; + struct pim_neighbor *neigh; + uint16_t next_highest_interval_msec; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + next_highest_interval_msec = pim_ifp->pim_override_interval_msec; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { + if (neigh == highest_neigh) + continue; + if (neigh->override_interval_msec > next_highest_interval_msec) + next_highest_interval_msec = neigh->override_interval_msec; + } + + return next_highest_interval_msec; +} + +void pim_neighbor_delete(struct interface *ifp, + struct pim_neighbor *neigh, + const char *delete_message) +{ + struct pim_interface *pim_ifp; + char src_str[100]; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); + zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", + src_str, ifp->name, delete_message); + + neighbor_timer_off(neigh); + + pim_if_assert_on_neighbor_down(ifp, neigh->source_addr); + + if (!PIM_OPTION_IS_SET(neigh->hello_options, + PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { + /* update num. of neighbors without hello option lan_delay */ + + --pim_ifp->pim_number_of_nonlandelay_neighbors; + } + + if (!PIM_OPTION_IS_SET(neigh->hello_options, + PIM_OPTION_MASK_DR_PRIORITY)) { + /* update num. of neighbors without dr_pri */ + + --pim_ifp->pim_dr_num_nondrpri_neighbors; + } + + zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec); + zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec); + + if (pim_if_lan_delay_enabled(ifp)) { + + /* will delete a neighbor with highest propagation delay? */ + if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) { + /* then find the next highest propagation delay */ + pim_ifp->pim_neighbors_highest_propagation_delay_msec = + find_neighbors_next_highest_propagation_delay_msec(ifp, neigh); + } + + /* will delete a neighbor with highest override interval? */ + if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) { + /* then find the next highest propagation delay */ + pim_ifp->pim_neighbors_highest_override_interval_msec = + find_neighbors_next_highest_override_interval_msec(ifp, neigh); + } + } + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: deleting PIM neighbor %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + } + + listnode_delete(pim_ifp->pim_neighbor_list, neigh); + + pim_neighbor_free(neigh); +} + +void pim_neighbor_delete_all(struct interface *ifp, + const char *delete_message) +{ + struct pim_interface *pim_ifp; + struct listnode *neigh_node; + struct listnode *neigh_nextnode; + struct pim_neighbor *neigh; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node, + neigh_nextnode, neigh)) { + pim_neighbor_delete(ifp, neigh, delete_message); + } +} + +struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, + struct in_addr addr) +{ + struct listnode *node; + struct prefix *p; + + if (!neigh->prefix_list) + return 0; + + for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) { + if (p->family == AF_INET) { + if (addr.s_addr == p->u.prefix4.s_addr) { + return p; + } + } + } + + return 0; +} + +/* + RFC 4601: 4.3.4. Maintaining Secondary Address Lists + + All the advertised secondary addresses in received Hello messages + must be checked against those previously advertised by all other + PIM neighbors on that interface. If there is a conflict and the + same secondary address was previously advertised by another + neighbor, then only the most recently received mapping MUST be + maintained, and an error message SHOULD be logged to the + administrator in a rate-limited manner. +*/ +static void delete_from_neigh_addr(struct interface *ifp, + struct list *addr_list, + struct in_addr neigh_addr) +{ + struct listnode *addr_node; + struct prefix *addr; + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + zassert(addr_list); + + /* + Scan secondary address list + */ + for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, + addr)) { + struct listnode *neigh_node; + struct pim_neighbor *neigh; + + if (addr->family != AF_INET) + continue; + + /* + Scan neighbors + */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, + neigh)) { + { + struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); + if (p) { + char addr_str[100]; + char this_neigh_str[100]; + char other_neigh_str[100]; + + pim_inet4_dump("", addr->u.prefix4, addr_str, sizeof(addr_str)); + pim_inet4_dump("", neigh_addr, this_neigh_str, sizeof(this_neigh_str)); + pim_inet4_dump("", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str)); + + zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s", + addr_str, this_neigh_str, other_neigh_str, ifp->name); + + listnode_delete(neigh->prefix_list, p); + prefix_free(p); + } + } + + } /* scan neighbors */ + + } /* scan addr list */ + +} + +void pim_neighbor_update(struct pim_neighbor *neigh, + pim_hello_options hello_options, + uint16_t holdtime, + uint32_t dr_priority, + struct list *addr_list) +{ + struct pim_interface *pim_ifp = neigh->interface->info; + + /* Received holdtime ? */ + if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { + pim_neighbor_timer_reset(neigh, holdtime); + } + else { + pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); + } + +#ifdef DUMP_PREFIX_LIST + zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d", + __PRETTY_FUNCTION__, + (unsigned) neigh->prefix_list, + neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1, + (unsigned) addr_list, + addr_list ? (int) listcount(addr_list) : -1); +#endif + + if (neigh->prefix_list == addr_list) { + if (addr_list) { + zlog_err("%s: internal error: trying to replace same prefix list=%u", + __PRETTY_FUNCTION__, (unsigned) addr_list); + } + } + else { + /* Delete existing secondary address list */ + delete_prefix_list(neigh); + } + + if (addr_list) { + delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr); + } + + /* Replace secondary address list */ + neigh->prefix_list = addr_list; + + update_dr_priority(neigh, + hello_options, + dr_priority); + /* + Copy flags + */ + neigh->hello_options = hello_options; +} diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h new file mode 100644 index 000000000..8f19c7505 --- /dev/null +++ b/pimd/pim_neighbor.h @@ -0,0 +1,74 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_NEIGHBOR_H +#define PIM_NEIGHBOR_H + +#include + +#include "if.h" +#include "linklist.h" + +#include "pim_tlv.h" + +struct pim_neighbor { + int64_t creation; /* timestamp of creation */ + struct in_addr source_addr; + pim_hello_options hello_options; + uint16_t holdtime; + uint16_t propagation_delay_msec; + uint16_t override_interval_msec; + uint32_t dr_priority; + uint32_t generation_id; + struct list *prefix_list; /* list of struct prefix */ + struct thread *t_expire_timer; + struct interface *interface; +}; + +void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); +void pim_neighbor_free(struct pim_neighbor *neigh); +struct pim_neighbor *pim_neighbor_find(struct interface *ifp, + struct in_addr source_addr); +struct pim_neighbor *pim_neighbor_add(struct interface *ifp, + struct in_addr source_addr, + pim_hello_options hello_options, + uint16_t holdtime, + uint16_t propagation_delay, + uint16_t override_interval, + uint32_t dr_priority, + uint32_t generation_id, + struct list *addr_list); +void pim_neighbor_delete(struct interface *ifp, + struct pim_neighbor *neigh, + const char *delete_message); +void pim_neighbor_delete_all(struct interface *ifp, + const char *delete_message); +void pim_neighbor_update(struct pim_neighbor *neigh, + pim_hello_options hello_options, + uint16_t holdtime, + uint32_t dr_priority, + struct list *addr_list); +struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, + struct in_addr addr); +void pim_if_dr_election(struct interface *ifp); + +#endif /* PIM_NEIGHBOR_H */ diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c new file mode 100644 index 000000000..2c8b056e1 --- /dev/null +++ b/pimd/pim_oil.c @@ -0,0 +1,140 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "memory.h" +#include "linklist.h" + +#include "pimd.h" +#include "pim_oil.h" +#include "pim_str.h" +#include "pim_iface.h" + +void pim_channel_oil_free(struct channel_oil *c_oil) +{ + XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil); +} + +static void pim_channel_oil_delete(struct channel_oil *c_oil) +{ + /* + notice that listnode_delete() can't be moved + into pim_channel_oil_free() because the later is + called by list_delete_all_node() + */ + listnode_delete(qpim_channel_oil_list, c_oil); + + pim_channel_oil_free(c_oil); +} + +static struct channel_oil *channel_oil_new(struct in_addr group_addr, + struct in_addr source_addr, + int input_vif_index) +{ + struct channel_oil *c_oil; + struct interface *ifp_in; + + ifp_in = pim_if_find_by_vif_index(input_vif_index); + if (!ifp_in) { + /* warning only */ + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, + source_str, group_str, input_vif_index); + } + + c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); + if (!c_oil) { + zlog_err("PIM XCALLOC(%d) failure", sizeof(*c_oil)); + return 0; + } + + c_oil->oil.mfcc_mcastgrp = group_addr; + c_oil->oil.mfcc_origin = source_addr; + c_oil->oil.mfcc_parent = input_vif_index; + c_oil->oil_ref_count = 1; + + zassert(c_oil->oil_size == 0); + + return c_oil; +} + +static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr, + struct in_addr source_addr, + int input_vif_index) +{ + struct channel_oil *c_oil; + + c_oil = channel_oil_new(group_addr, source_addr, input_vif_index); + if (!c_oil) { + zlog_warn("PIM XCALLOC(%d) failure", sizeof(*c_oil)); + return 0; + } + + listnode_add(qpim_channel_oil_list, c_oil); + + return c_oil; +} + +static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr, + struct in_addr source_addr) +{ + struct listnode *node; + struct channel_oil *c_oil; + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) && + (source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr)) + return c_oil; + } + + return 0; +} + +struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, + struct in_addr source_addr, + int input_vif_index) +{ + struct channel_oil *c_oil; + + c_oil = pim_find_channel_oil(group_addr, source_addr); + if (c_oil) { + ++c_oil->oil_ref_count; + return c_oil; + } + + return pim_add_channel_oil(group_addr, source_addr, input_vif_index); +} + +void pim_channel_oil_del(struct channel_oil *c_oil) +{ + --c_oil->oil_ref_count; + + if (c_oil->oil_ref_count < 1) { + pim_channel_oil_delete(c_oil); + } +} diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h new file mode 100644 index 000000000..1753545ab --- /dev/null +++ b/pimd/pim_oil.h @@ -0,0 +1,53 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_OIL_H +#define PIM_OIL_H + +#include "pim_mroute.h" + +#define PIM_OIF_FLAG_PROTO_IGMP (1 << 0) /* bitmask 1 */ +#define PIM_OIF_FLAG_PROTO_PIM (1 << 1) /* bitmask 2 */ +#define PIM_OIF_FLAG_PROTO_ANY (3) /* bitmask (1 | 2) */ + +/* + qpim_channel_oil_list holds a list of struct channel_oil. + + Each channel_oil.oil is used to control an (S,G) entry in the Kernel + Multicast Forwarding Cache. +*/ + +struct channel_oil { + struct mfcctl oil; + int oil_size; + int oil_ref_count; + time_t oif_creation[MAXVIFS]; + uint32_t oif_flags[MAXVIFS]; +}; + +void pim_channel_oil_free(struct channel_oil *c_oil); +struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, + struct in_addr source_addr, + int input_vif_index); +void pim_channel_oil_del(struct channel_oil *c_oil); + +#endif /* PIM_OIL_H */ diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c new file mode 100644 index 000000000..bbf67763c --- /dev/null +++ b/pimd/pim_pim.c @@ -0,0 +1,716 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "thread.h" +#include "memory.h" + +#include "pimd.h" +#include "pim_pim.h" +#include "pim_time.h" +#include "pim_iface.h" +#include "pim_sock.h" +#include "pim_str.h" +#include "pim_util.h" +#include "pim_tlv.h" +#include "pim_neighbor.h" +#include "pim_hello.h" +#include "pim_join.h" +#include "pim_assert.h" +#include "pim_msg.h" +#include "pim_rand.h" + +static int on_pim_hello_send(struct thread *t); +static int pim_hello_send(struct interface *ifp, + uint16_t holdtime); + +static void sock_close(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + + if (PIM_DEBUG_PIM_TRACE) { + if (pim_ifp->t_pim_sock_read) { + zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s", + pim_ifp->pim_sock_fd, + ifp->name); + } + } + THREAD_OFF(pim_ifp->t_pim_sock_read); + + if (PIM_DEBUG_PIM_TRACE) { + if (pim_ifp->t_pim_hello_timer) { + zlog_debug("Cancelling PIM hello timer for interface %s", + ifp->name); + } + } + THREAD_OFF(pim_ifp->t_pim_hello_timer); + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("Deleting PIM socket fd=%d on interface %s", + pim_ifp->pim_sock_fd, ifp->name); + } + + if (close(pim_ifp->pim_sock_fd)) { + zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s", + pim_ifp->pim_sock_fd, ifp->name, + errno, strerror(errno)); + } + + pim_ifp->pim_sock_fd = -1; + pim_ifp->pim_sock_creation = 0; + + zassert(pim_ifp->pim_sock_fd < 0); + zassert(!pim_ifp->t_pim_sock_read); + zassert(!pim_ifp->t_pim_hello_timer); + zassert(!pim_ifp->pim_sock_creation); +} + +void pim_sock_delete(struct interface *ifp, const char *delete_message) +{ + zlog_info("PIM INTERFACE DOWN: on interface %s: %s", + ifp->name, delete_message); + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + Before an interface goes down or changes primary IP address, a Hello + message with a zero HoldTime should be sent immediately (with the + old IP address if the IP address changed). + */ + pim_hello_send(ifp, 0 /* zero-sec holdtime */); + + pim_neighbor_delete_all(ifp, delete_message); + + sock_close(ifp); +} + +int pim_pim_packet(struct interface *ifp, char *buf, size_t len) +{ + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + char src_str[100]; + char dst_str[100]; + char *pim_msg; + int pim_msg_len; + uint8_t pim_version; + uint8_t pim_type; + uint16_t pim_checksum; /* received checksum */ + uint16_t checksum; /* computed checksum */ + struct pim_neighbor *neigh; + + if (!ifp->info) { + zlog_warn("%s: PIM not enabled on interface %s", + __PRETTY_FUNCTION__, ifp->name); + return -1; + } + + if (len < sizeof(*ip_hdr)) { + zlog_warn("PIM packet size=%d shorter than minimum=%d", + len, sizeof(*ip_hdr)); + return -1; + } + + ip_hdr = (struct ip *) buf; + + pim_inet4_dump("", ip_hdr->ip_src, src_str, sizeof(src_str)); + pim_inet4_dump("", ip_hdr->ip_dst, dst_str, sizeof(dst_str)); + + ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ + + if (PIM_DEBUG_PIM_PACKETS) { + zlog_debug("Recv IP packet from %s to %s on %s: size=%d ip_header_size=%d ip_proto=%d", + src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p); + } + + if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) { + zlog_warn("IP packet protocol=%d is not PIM=%d", + ip_hdr->ip_p, PIM_IP_PROTO_PIM); + return -1; + } + + if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { + zlog_warn("IP packet header size=%d shorter than minimum=%d", + ip_hlen, PIM_IP_HEADER_MIN_LEN); + return -1; + } + if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { + zlog_warn("IP packet header size=%d greater than maximum=%d", + ip_hlen, PIM_IP_HEADER_MAX_LEN); + return -1; + } + + pim_msg = buf + ip_hlen; + pim_msg_len = len - ip_hlen; + + if (pim_msg_len < PIM_PIM_MIN_LEN) { + zlog_warn("PIM message size=%d shorter than minimum=%d", + pim_msg_len, PIM_PIM_MIN_LEN); + return -1; + } + + pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg); + pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg); + + if (pim_version != PIM_PROTO_VERSION) { + zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d", + ifp->name, pim_version); + return -1; + } + + /* save received checksum */ + pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg); + + /* for computing checksum */ + *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; + + checksum = pim_inet_checksum(pim_msg, pim_msg_len); + if (checksum != pim_checksum) { + zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", + ifp->name, pim_checksum, checksum); + return -1; + } + + if (PIM_DEBUG_PIM_PACKETS) { + zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x", + src_str, dst_str, ifp->name, ip_hdr->ip_ttl, + pim_version, pim_type, pim_msg_len, checksum); + } + + if (pim_type == PIM_MSG_TYPE_HELLO) { + return pim_hello_recv(ifp, + ip_hdr->ip_src, + pim_msg + PIM_MSG_HEADER_LEN, + pim_msg_len - PIM_MSG_HEADER_LEN); + } + + neigh = pim_neighbor_find(ifp, ip_hdr->ip_src); + if (!neigh) { + zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s", + __FILE__, __PRETTY_FUNCTION__, + pim_type, src_str, ifp->name); + return -1; + } + + switch (pim_type) { + case PIM_MSG_TYPE_JOIN_PRUNE: + return pim_joinprune_recv(ifp, neigh, + ip_hdr->ip_src, + pim_msg + PIM_MSG_HEADER_LEN, + pim_msg_len - PIM_MSG_HEADER_LEN); + case PIM_MSG_TYPE_ASSERT: + return pim_assert_recv(ifp, neigh, + ip_hdr->ip_src, + pim_msg + PIM_MSG_HEADER_LEN, + pim_msg_len - PIM_MSG_HEADER_LEN); + default: + zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s", + __FILE__, __PRETTY_FUNCTION__, + pim_type, src_str, ifp->name); + } + + return -1; +} + +static void pim_sock_read_on(struct interface *ifp); + +static int pim_sock_read(struct thread *t) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int fd; + struct sockaddr_in from; + struct sockaddr_in to; + socklen_t fromlen = sizeof(from); + socklen_t tolen = sizeof(to); + char buf[PIM_PIM_BUFSIZE_READ]; + int len; + int ifindex = -1; + int result = -1; /* defaults to bad */ + + zassert(t); + + ifp = THREAD_ARG(t); + zassert(ifp); + + fd = THREAD_FD(t); + + pim_ifp = ifp->info; + zassert(pim_ifp); + + zassert(fd == pim_ifp->pim_sock_fd); + + len = pim_socket_recvfromto(fd, buf, sizeof(buf), + &from, &fromlen, + &to, &tolen, + &ifindex); + if (len < 0) { + zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + goto done; + } + + if (PIM_DEBUG_PIM_PACKETS) { + char from_str[100]; + char to_str[100]; + + if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) + sprintf(from_str, ""); + if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) + sprintf(to_str, ""); + + zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)", + len, from_str, to_str, fd, ifindex, ifp->ifindex); + } + +#ifdef PIM_CHECK_RECV_IFINDEX_SANITY + /* ifindex sanity check */ + if (ifindex != (int) ifp->ifindex) { + char from_str[100]; + char to_str[100]; + struct interface *recv_ifp; + + if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) + sprintf(from_str, ""); + if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) + sprintf(to_str, ""); + + recv_ifp = if_lookup_by_index(ifindex); + if (recv_ifp) { + zassert(ifindex == (int) recv_ifp->ifindex); + } + +#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH + zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", + from_str, to_str, fd, + ifindex, recv_ifp ? recv_ifp->name : "", + ifp->ifindex, ifp->name); +#endif + goto done; + } +#endif + + if (pim_pim_packet(ifp, buf, len)) { + goto done; + } + + result = 0; /* good */ + + done: + pim_sock_read_on(ifp); + + if (result) { + ++pim_ifp->pim_ifstat_hello_recvfail; + } + + return result; +} + +static void pim_sock_read_on(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + zassert(ifp->info); + + pim_ifp = ifp->info; + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("Scheduling READ event on PIM socket fd=%d", + pim_ifp->pim_sock_fd); + } + pim_ifp->t_pim_sock_read = 0; + zassert(!pim_ifp->t_pim_sock_read); + THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp, + pim_ifp->pim_sock_fd); +} + +static int pim_sock_open(struct in_addr ifaddr, int ifindex) +{ + int fd; + + fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */); + if (fd < 0) + return -1; + + if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) { + return -2; + } + + return fd; +} + +void pim_ifstat_reset(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + + pim_ifp = ifp->info; + if (!pim_ifp) { + return; + } + + pim_ifp->pim_ifstat_start = pim_time_monotonic_sec(); + pim_ifp->pim_ifstat_hello_sent = 0; + pim_ifp->pim_ifstat_hello_sendfail = 0; + pim_ifp->pim_ifstat_hello_recv = 0; + pim_ifp->pim_ifstat_hello_recvfail = 0; +} + +void pim_sock_reset(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + zassert(ifp->info); + + pim_ifp = ifp->info; + + pim_ifp->primary_address = pim_find_primary_addr(ifp); + + pim_ifp->pim_sock_fd = -1; + pim_ifp->pim_sock_creation = 0; + pim_ifp->t_pim_sock_read = 0; + + pim_ifp->t_pim_hello_timer = 0; + pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; + pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */ + pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY; + pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; + pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC; + pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; + if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) { + PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options); + } + else { + PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options); + } + + /* neighbors without lan_delay */ + pim_ifp->pim_number_of_nonlandelay_neighbors = 0; + pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0; + pim_ifp->pim_neighbors_highest_override_interval_msec = 0; + + /* DR Election */ + pim_ifp->pim_dr_election_last = 0; /* timestamp */ + pim_ifp->pim_dr_election_count = 0; + pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */ + pim_ifp->pim_dr_addr = pim_ifp->primary_address; + + pim_ifstat_reset(ifp); +} + +int pim_msg_send(int fd, + struct in_addr dst, + char *pim_msg, + int pim_msg_size, + const char *ifname) +{ + ssize_t sent; + struct sockaddr_in to; + socklen_t tolen; + + if (PIM_DEBUG_PIM_PACKETS) { + char dst_str[100]; + pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); + zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", + __PRETTY_FUNCTION__, + dst_str, ifname, pim_msg_size, + *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)); + } + +#if 0 + memset(&to, 0, sizeof(to)); +#endif + to.sin_family = AF_INET; + to.sin_addr = dst; +#if 0 + to.sin_port = htons(0); +#endif + tolen = sizeof(to); + + sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen); + if (sent != (ssize_t) pim_msg_size) { + int e = errno; + char dst_str[100]; + pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); + if (sent < 0) { + zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s", + __PRETTY_FUNCTION__, + dst_str, ifname, fd, pim_msg_size, + e, strerror(e)); + } + else { + zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%d", + __PRETTY_FUNCTION__, + dst_str, ifname, fd, + pim_msg_size, sent); + } + return -1; + } + + return 0; +} + +static int hello_send(struct interface *ifp, + uint16_t holdtime) +{ + char pim_msg[PIM_PIM_BUFSIZE_WRITE]; + struct pim_interface *pim_ifp; + int pim_tlv_size; + int pim_msg_size; + + pim_ifp = ifp->info; + + if (PIM_DEBUG_PIM_PACKETS) { + char dst_str[100]; + pim_inet4_dump("", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str)); + zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", + __PRETTY_FUNCTION__, + dst_str, ifp->name, + holdtime, + pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, + PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), + pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, + listcount(ifp->connected)); + } + + pim_tlv_size = pim_hello_build_tlv(ifp->name, + pim_msg + PIM_PIM_MIN_LEN, + sizeof(pim_msg) - PIM_PIM_MIN_LEN, + holdtime, + pim_ifp->pim_dr_priority, + pim_ifp->pim_generation_id, + pim_ifp->pim_propagation_delay_msec, + pim_ifp->pim_override_interval_msec, + PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), + ifp->connected); + if (pim_tlv_size < 0) { + return -1; + } + + pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; + + zassert(pim_msg_size >= PIM_PIM_MIN_LEN); + zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE); + + pim_msg_build_header(pim_msg, pim_msg_size, + PIM_MSG_TYPE_HELLO); + + if (pim_msg_send(pim_ifp->pim_sock_fd, + qpim_all_pim_routers_addr, + pim_msg, + pim_msg_size, + ifp->name)) { + zlog_warn("%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, ifp->name); + return -2; + } + + return 0; +} + +static int pim_hello_send(struct interface *ifp, + uint16_t holdtime) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (hello_send(ifp, holdtime)) { + ++pim_ifp->pim_ifstat_hello_sendfail; + + zlog_warn("Could not send PIM hello on interface %s", + ifp->name); + return -1; + } + + ++pim_ifp->pim_ifstat_hello_sent; + + return 0; +} + +static void hello_resched(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("Rescheduling %d sec hello on interface %s", + pim_ifp->pim_hello_period, ifp->name); + } + THREAD_OFF(pim_ifp->t_pim_hello_timer); + THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer, + on_pim_hello_send, + ifp, pim_ifp->pim_hello_period); +} + +/* + Periodic hello timer + */ +static int on_pim_hello_send(struct thread *t) +{ + struct pim_interface *pim_ifp; + struct interface *ifp; + + zassert(t); + ifp = THREAD_ARG(t); + zassert(ifp); + + pim_ifp = ifp->info; + + /* + * Schedule next hello + */ + pim_ifp->t_pim_hello_timer = 0; + hello_resched(ifp); + + /* + * Send hello + */ + return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); +} + +/* + RFC 4601: 4.3.1. Sending Hello Messages + + Thus, if a router needs to send a Join/Prune or Assert message on an + interface on which it has not yet sent a Hello message with the + currently configured IP address, then it MUST immediately send the + relevant Hello message without waiting for the Hello Timer to + expire, followed by the Join/Prune or Assert message. + */ +void pim_hello_restart_now(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + zassert(ifp); + pim_ifp = ifp->info; + zassert(pim_ifp); + + /* + * Reset next hello timer + */ + hello_resched(ifp); + + /* + * Immediately send hello + */ + pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); +} + +/* + RFC 4601: 4.3.1. Sending Hello Messages + + To allow new or rebooting routers to learn of PIM neighbors quickly, + when a Hello message is received from a new neighbor, or a Hello + message with a new GenID is received from an existing neighbor, a + new Hello message should be sent on this interface after a + randomized delay between 0 and Triggered_Hello_Delay. + */ +void pim_hello_restart_triggered(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + int triggered_hello_delay_msec; + int random_msec; + + zassert(ifp); + pim_ifp = ifp->info; + zassert(pim_ifp); + + triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay; + + if (pim_ifp->t_pim_hello_timer) { + long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer); + if (remain_msec <= triggered_hello_delay_msec) { + /* Rescheduling hello would increase the delay, then it's faster + to just wait for the scheduled periodic hello. */ + return; + } + + THREAD_OFF(pim_ifp->t_pim_hello_timer); + pim_ifp->t_pim_hello_timer = 0; + } + zassert(!pim_ifp->t_pim_hello_timer); + + random_msec = pim_rand_next(0, triggered_hello_delay_msec); + + if (PIM_DEBUG_PIM_EVENTS) { + zlog_debug("Scheduling %d msec triggered hello on interface %s", + random_msec, ifp->name); + } + + THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer, + on_pim_hello_send, + ifp, triggered_hello_delay_msec); +} + +int pim_sock_add(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (pim_ifp->pim_sock_fd >= 0) { + zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s", + pim_ifp->pim_sock_fd, ifp->name); + return -1; + } + + ifaddr = pim_ifp->primary_address; + + pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex); + if (pim_ifp->pim_sock_fd < 0) { + zlog_warn("Could not open PIM socket on interface %s", + ifp->name); + return -2; + } + + pim_ifp->t_pim_sock_read = 0; + pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); + + pim_ifp->pim_generation_id = pim_rand() & (int64_t) 0xFFFFFFFF; + + zlog_info("PIM INTERFACE UP: on interface %s", + ifp->name); + + /* + * Start receiving PIM messages + */ + pim_sock_read_on(ifp); + + /* + * Start sending PIM hello's + */ + pim_hello_restart_triggered(ifp); + + return 0; +} diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h new file mode 100644 index 000000000..a2c8fa582 --- /dev/null +++ b/pimd/pim_pim.h @@ -0,0 +1,71 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_PIM_H +#define PIM_PIM_H + +#include + +#include "if.h" + +#define PIM_PIM_BUFSIZE_READ (20000) +#define PIM_PIM_BUFSIZE_WRITE (20000) + +#define PIM_NEXTHOP_IFINDEX_TAB_SIZE (20) + +#define PIM_DEFAULT_HELLO_PERIOD (30) /* seconds, RFC 4601: 4.11 */ +#define PIM_DEFAULT_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */ +#define PIM_DEFAULT_DR_PRIORITY (1) /* RFC 4601: 4.3.1 */ +#define PIM_DEFAULT_PROPAGATION_DELAY_MSEC (500) /* RFC 4601: 4.11. Timer Values */ +#define PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC (2500) /* RFC 4601: 4.11. Timer Values */ +#define PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION (0) /* boolean */ +#define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */ + +#define PIM_MSG_TYPE_HELLO (0) +#define PIM_MSG_TYPE_JOIN_PRUNE (3) +#define PIM_MSG_TYPE_ASSERT (5) + +#define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg) +#define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg) +#define PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) (((char *)(pim_msg)) + 1) +#define PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) (((char *)(pim_msg)) + 2) + +#define PIM_MSG_HDR_GET_VERSION(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_VERSION(pim_msg)) >> 4) +#define PIM_MSG_HDR_GET_TYPE(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_TYPE(pim_msg)) & 0xF) +#define PIM_MSG_HDR_GET_CHECKSUM(pim_msg) (*(uint16_t*) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)) + +void pim_ifstat_reset(struct interface *ifp); +void pim_sock_reset(struct interface *ifp); +int pim_sock_add(struct interface *ifp); +void pim_sock_delete(struct interface *ifp, const char *delete_message); +void pim_hello_restart_now(struct interface *ifp); +void pim_hello_restart_triggered(struct interface *ifp); + +int pim_pim_packet(struct interface *ifp, char *buf, size_t len); + +int pim_msg_send(int fd, + struct in_addr dst, + char *pim_msg, + int pim_msg_size, + const char *ifname); + +#endif /* PIM_PIM_H */ diff --git a/pimd/pim_rand.c b/pimd/pim_rand.c new file mode 100644 index 000000000..df2a1111e --- /dev/null +++ b/pimd/pim_rand.c @@ -0,0 +1,60 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include "pim_rand.h" +#include "pim_time.h" + +/* Quick and dirty random number generator from NUMERICAL RECIPES IN C: + THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5). */ +/* BEWARE: '_qseed_' is assigned! */ +#define QRANDOM(_qseed_) ((_qseed_) = (((_qseed_) * 1664525L) + 1013904223L)) + +static long qpim_rand_seed; + +void pim_rand_init() +{ + qpim_rand_seed = pim_time_monotonic_sec() ^ getpid(); +} + +long pim_rand() +{ + return QRANDOM(qpim_rand_seed); +} + +int pim_rand_next(int min, int max) +{ + long rand; + + assert(min <= max); + + /* FIXME better random generator ? */ + + rand = QRANDOM(qpim_rand_seed); + if (rand < 0) + rand = -rand; + rand = rand % (1 + max - min) + min; + + assert(rand >= min); + assert(rand <= max); + + return rand; +} diff --git a/pimd/pim_rand.h b/pimd/pim_rand.h new file mode 100644 index 000000000..a1df5054e --- /dev/null +++ b/pimd/pim_rand.h @@ -0,0 +1,30 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_RAND_H +#define PIM_RAND_H + +void pim_rand_init(void); +long pim_rand(void); +int pim_rand_next(int min, int max); + +#endif /* PIM_RAND_H */ diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c new file mode 100644 index 000000000..7fdeecfd5 --- /dev/null +++ b/pimd/pim_rpf.c @@ -0,0 +1,254 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "prefix.h" +#include "memory.h" + +#include "pimd.h" +#include "pim_rpf.h" +#include "pim_pim.h" +#include "pim_str.h" +#include "pim_iface.h" +#include "pim_zlookup.h" +#include "pim_ifchannel.h" + +static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); + +int pim_nexthop_lookup(struct pim_nexthop *nexthop, + struct in_addr addr) +{ + struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; + int num_ifindex; + struct interface *ifp; + int first_ifindex; + + num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, + PIM_NEXTHOP_IFINDEX_TAB_SIZE, + addr, PIM_NEXTHOP_LOOKUP_MAX); + if (num_ifindex < 1) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: could not find nexthop ifindex for address %s", + __FILE__, __PRETTY_FUNCTION__, + addr_str); + return -1; + } + + first_ifindex = nexthop_tab[0].ifindex; + + if (num_ifindex > 1) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", + __FILE__, __PRETTY_FUNCTION__, + num_ifindex, addr_str, first_ifindex); + /* debug warning only, do not return */ + } + + ifp = if_lookup_by_index(first_ifindex); + if (!ifp) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: could not find interface for ifindex %d (address %s)", + __FILE__, __PRETTY_FUNCTION__, + first_ifindex, addr_str); + return -2; + } + + if (!ifp->info) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", + __PRETTY_FUNCTION__, + ifp->name, first_ifindex, addr_str); + /* debug warning only, do not return */ + } + + if (PIM_DEBUG_PIM_TRACE) { + char nexthop_str[100]; + char addr_str[100]; + pim_inet4_dump("", nexthop_tab[0].nexthop_addr, nexthop_str, sizeof(nexthop_str)); + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d", + __FILE__, __PRETTY_FUNCTION__, + nexthop_str, addr_str, + ifp->name, first_ifindex, + nexthop_tab[0].route_metric, + nexthop_tab[0].protocol_distance); + } + + /* update nextop data */ + nexthop->interface = ifp; + nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr; + nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance; + nexthop->mrib_route_metric = nexthop_tab[0].route_metric; + + return 0; +} + +static int nexthop_mismatch(const struct pim_nexthop *nh1, + const struct pim_nexthop *nh2) +{ + return (nh1->interface != nh2->interface) + || + (nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr) + || + (nh1->mrib_metric_preference != nh2->mrib_metric_preference) + || + (nh1->mrib_route_metric != nh2->mrib_route_metric); +} + +enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, + struct in_addr *old_rpf_addr) +{ + struct in_addr save_rpf_addr; + struct pim_nexthop save_nexthop; + struct pim_rpf *rpf = &up->rpf; + + save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */ + save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */ + + if (pim_nexthop_lookup(&rpf->source_nexthop, + up->source_addr)) { + return PIM_RPF_FAILURE; + } + + rpf->rpf_addr = pim_rpf_find_rpf_addr(up); + if (PIM_INADDR_IS_ANY(rpf->rpf_addr)) { + /* RPF'(S,G) not found */ + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s %s: RPF'(%s,%s) not found: won't send join upstream", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str); + /* warning only */ + } + + /* detect change in pim_nexthop */ + if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { + char src_str[100]; + char grp_str[100]; + char nhaddr_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, + rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "", + nhaddr_str, + rpf->source_nexthop.mrib_metric_preference, + rpf->source_nexthop.mrib_route_metric); + /* warning only */ + + pim_upstream_update_join_desired(up); + pim_upstream_update_could_assert(up); + pim_upstream_update_my_assert_metric(up); + } + + /* detect change in RPF_interface(S) */ + if (save_nexthop.interface != rpf->source_nexthop.interface) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, + save_nexthop.interface ? save_nexthop.interface->name : "", + rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""); + /* warning only */ + + pim_upstream_rpf_interface_changed(up, save_nexthop.interface); + } + + /* detect change in RPF'(S,G) */ + if (save_rpf_addr.s_addr != rpf->rpf_addr.s_addr) { + + /* return old rpf to caller ? */ + if (old_rpf_addr) + *old_rpf_addr = save_rpf_addr; + + return PIM_RPF_CHANGED; + } + + return PIM_RPF_OK; +} + +/* + RFC 4601: 4.1.6. State Summarization Macros + + neighbor RPF'(S,G) { + if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) { + return AssertWinner(S, G, RPF_interface(S) ) + } else { + return NBR( RPF_interface(S), MRIB.next_hop( S ) ) + } + } + + RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data + packets should be coming and to which joins should be sent on the RP + tree and SPT, respectively. +*/ +static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) +{ + struct pim_ifchannel *rpf_ch; + struct pim_neighbor *neigh; + struct in_addr rpf_addr; + + if (!up->rpf.source_nexthop.interface) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)", + __PRETTY_FUNCTION__, + src_str, grp_str); + + rpf_addr.s_addr = PIM_NET_INADDR_ANY; + return rpf_addr; + } + + rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface, + up->source_addr, up->group_addr); + if (rpf_ch) { + if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { + return rpf_ch->ifassert_winner; + } + } + + /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */ + + neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface, + up->rpf.source_nexthop.mrib_nexthop_addr); + if (neigh) + rpf_addr = neigh->source_addr; + else + rpf_addr.s_addr = PIM_NET_INADDR_ANY; + + return rpf_addr; +} diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h new file mode 100644 index 000000000..078e89f3e --- /dev/null +++ b/pimd/pim_rpf.h @@ -0,0 +1,36 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_RPF_H +#define PIM_RPF_H + +#include + +#include "pim_upstream.h" +#include "pim_neighbor.h" + +int pim_nexthop_lookup(struct pim_nexthop *nexthop, + struct in_addr addr); +enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, + struct in_addr *old_rpf_addr); + +#endif /* PIM_RPF_H */ diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c new file mode 100644 index 000000000..1b146f6f2 --- /dev/null +++ b/pimd/pim_signals.c @@ -0,0 +1,85 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include +#include "sigevent.h" +#include "log.h" + +#include "pim_signals.h" +#include "pimd.h" + +/* + * Signal handlers + */ + +static void pim_sighup() +{ + zlog_debug ("SIGHUP received, ignoring"); +} + +static void pim_sigint() +{ + zlog_notice("Terminating on signal SIGINT"); + pim_terminate(); + exit(1); +} + +static void pim_sigterm() +{ + zlog_notice("Terminating on signal SIGTERM"); + pim_terminate(); + exit(1); +} + +static void pim_sigusr1() +{ + zlog_debug ("SIGUSR1 received"); + zlog_rotate (NULL); +} + +struct quagga_signal_t pimd_signals[] = +{ + { + .signal = SIGHUP, + .handler = &pim_sighup, + }, + { + .signal = SIGUSR1, + .handler = &pim_sigusr1, + }, + { + .signal = SIGINT, + .handler = &pim_sigint, + }, + { + .signal = SIGTERM, + .handler = &pim_sigterm, + }, +}; + +void pim_signals_init() +{ + signal_init(master, Q_SIGC(pimd_signals), pimd_signals); +} + diff --git a/pimd/pim_signals.h b/pimd/pim_signals.h new file mode 100644 index 000000000..62523c038 --- /dev/null +++ b/pimd/pim_signals.h @@ -0,0 +1,28 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_SIGNALS_H +#define PIM_SIGNALS_H + +void pim_signals_init(void); + +#endif /* PIM_SIGNALS_H */ diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c new file mode 100644 index 000000000..c43cb68e9 --- /dev/null +++ b/pimd/pim_sock.c @@ -0,0 +1,348 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include "pim_mroute.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "log.h" + +#include "pimd.h" +#include "pim_sock.h" +#include "pim_str.h" + +#ifndef MCAST_JOIN_SOURCE_GROUP +#define MCAST_JOIN_SOURCE_GROUP 46 +struct group_source_req +{ + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; +#endif + +int pim_socket_raw(int protocol) +{ + int fd; + + fd = socket(AF_INET, SOCK_RAW, protocol); + if (fd < 0) { + zlog_warn("Could not create raw socket: errno=%d: %s", + errno, strerror(errno)); + return PIM_SOCK_ERR_SOCKET; + } + + return fd; +} + +int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) +{ + int fd; + + fd = pim_socket_raw(protocol); + if (fd < 0) { + zlog_warn("Could not create multicast socket: errno=%d: %s", + errno, strerror(errno)); + return PIM_SOCK_ERR_SOCKET; + } + + /* Needed to obtain destination address from recvmsg() */ + { +#if defined(HAVE_IP_PKTINFO) + /* Linux IP_PKTINFO */ + int opt = 1; + if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { + zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + } +#elif defined(HAVE_IP_RECVDSTADDR) + /* BSD IP_RECVDSTADDR */ + int opt = 1; + if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { + zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + } +#else + zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", + __FILE__, __PRETTY_FUNCTION__); + close(fd); + return PIM_SOCK_ERR_DSTADDR; +#endif + } + + + /* Set router alert (RFC 2113) */ + { + char ra[4]; + ra[0] = 148; + ra[1] = 4; + ra[2] = 0; + ra[3] = 0; + if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) { + zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_RA; + } + } + + { + int reuse = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (void *) &reuse, sizeof(reuse))) { + zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_REUSE; + } + } + + { + const int MTTL = 1; + int ttl = MTTL; + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, + (void *) &ttl, sizeof(ttl))) { + zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", + MTTL, fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_TTL; + } + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + (void *) &loop, sizeof(loop))) { + zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", + loop ? "enable" : "disable", + fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_LOOP; + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, + (void *) &ifaddr, sizeof(ifaddr))) { + zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_IFACE; + } + + { + long flags; + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_NONBLOCK_GETFL; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { + zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return PIM_SOCK_ERR_NONBLOCK_SETFL; + } + } + + return fd; +} + +int pim_socket_join(int fd, struct in_addr group, + struct in_addr ifaddr, int ifindex) +{ + int ret; + +#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + struct ip_mreqn opt; +#else + struct ip_mreq opt; +#endif + + opt.imr_multiaddr = group; + +#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + opt.imr_address = ifaddr; + opt.imr_ifindex = ifindex; +#else + opt.imr_interface = ifaddr; +#endif + + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt)); + if (ret) { + char group_str[100]; + char ifaddr_str[100]; + if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) + sprintf(group_str, ""); + if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) + sprintf(ifaddr_str, ""); + + zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s", + fd, group_str, ifaddr_str, errno, strerror(errno)); + return ret; + } + + if (PIM_DEBUG_TRACE) { + char group_str[100]; + char ifaddr_str[100]; + if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) + sprintf(group_str, ""); + if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) + sprintf(ifaddr_str, ""); + + zlog_debug("Socket fd=%d joined group %s on interface address %s", + fd, group_str, ifaddr_str); + } + + return ret; +} + +int pim_socket_join_source(int fd, int ifindex, + struct in_addr group_addr, + struct in_addr source_addr, + const char *ifname) +{ + struct group_source_req req; + struct sockaddr_in *group_sa = (struct sockaddr_in *) &req.gsr_group; + struct sockaddr_in *source_sa = (struct sockaddr_in *) &req.gsr_source; + + memset(group_sa, 0, sizeof(*group_sa)); + group_sa->sin_family = AF_INET; + group_sa->sin_addr = group_addr; + group_sa->sin_port = htons(0); + + memset(source_sa, 0, sizeof(*source_sa)); + source_sa->sin_family = AF_INET; + source_sa->sin_addr = source_addr; + source_sa->sin_port = htons(0); + + req.gsr_interface = ifindex; + + if (setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, + &req, sizeof(req))) { + int e = errno; + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", + __PRETTY_FUNCTION__, + fd, group_str, source_str, ifindex, ifname, + e, strerror(e)); + return -1; + } + + return 0; +} + +int pim_socket_recvfromto(int fd, char *buf, size_t len, + struct sockaddr_in *from, socklen_t *fromlen, + struct sockaddr_in *to, socklen_t *tolen, + int *ifindex) +{ + struct msghdr msgh; + struct cmsghdr *cmsg; + struct iovec iov; + char cbuf[1000]; + int err; + + memset(&msgh, 0, sizeof(struct msghdr)); + iov.iov_base = buf; + iov.iov_len = len; + msgh.msg_control = cbuf; + msgh.msg_controllen = sizeof(cbuf); + msgh.msg_name = from; + msgh.msg_namelen = fromlen ? *fromlen : 0; + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_flags = 0; + + err = recvmsg(fd, &msgh, 0); + if (err < 0) + return err; + + if (fromlen) + *fromlen = msgh.msg_namelen; + + for (cmsg = CMSG_FIRSTHDR(&msgh); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msgh,cmsg)) { + +#ifdef HAVE_IP_PKTINFO + if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { + struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg); + if (to) + ((struct sockaddr_in *) to)->sin_addr = i->ipi_addr; + if (tolen) + *tolen = sizeof(struct sockaddr_in); + if (ifindex) + *ifindex = i->ipi_ifindex; + break; + } +#endif + +#ifdef HAVE_IP_RECVDSTADDR + if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) { + struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg); + if (to) + ((struct sockaddr_in *) to)->sin_addr = *i; + if (tolen) + *tolen = sizeof(struct sockaddr_in); + break; + } +#endif + +#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX) + if (cmsg->cmsg_type == IP_RECVIF) + if (ifindex) + *ifindex = CMSG_IFINDEX(cmsg); +#endif + + } /* for (cmsg) */ + + return err; /* len */ +} + +int pim_socket_mcastloop_get(int fd) +{ + int loop; + socklen_t loop_len = sizeof(loop); + + if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop, &loop_len)) { + int e = errno; + zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + errno = e; + return PIM_SOCK_ERR_LOOP; + } + + return loop; +} diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h new file mode 100644 index 000000000..e9d5476f6 --- /dev/null +++ b/pimd/pim_sock.h @@ -0,0 +1,52 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_SOCK_H +#define PIM_SOCK_H + +#define PIM_SOCK_ERR_NONE (0) /* No error */ +#define PIM_SOCK_ERR_SOCKET (-1) /* socket() */ +#define PIM_SOCK_ERR_RA (-2) /* Router Alert option */ +#define PIM_SOCK_ERR_REUSE (-3) /* Reuse option */ +#define PIM_SOCK_ERR_TTL (-4) /* TTL option */ +#define PIM_SOCK_ERR_LOOP (-5) /* Loopback option */ +#define PIM_SOCK_ERR_IFACE (-6) /* Outgoing interface option */ +#define PIM_SOCK_ERR_DSTADDR (-7) /* Outgoing interface option */ +#define PIM_SOCK_ERR_NONBLOCK_GETFL (-8) /* Get O_NONBLOCK */ +#define PIM_SOCK_ERR_NONBLOCK_SETFL (-9) /* Set O_NONBLOCK */ + +int pim_socket_raw(int protocol); +int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop); +int pim_socket_join(int fd, struct in_addr group, + struct in_addr ifaddr, int ifindex); +int pim_socket_join_source(int fd, int ifindex, + struct in_addr group_addr, + struct in_addr source_addr, + const char *ifname); +int pim_socket_recvfromto(int fd, char *buf, size_t len, + struct sockaddr_in *from, socklen_t *fromlen, + struct sockaddr_in *to, socklen_t *tolen, + int *ifindex); + +int pim_socket_mcastloop_get(int fd); + +#endif /* PIM_SOCK_H */ diff --git a/pimd/pim_str.c b/pimd/pim_str.c new file mode 100644 index 000000000..7dce7a859 --- /dev/null +++ b/pimd/pim_str.c @@ -0,0 +1,46 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include +#include + +#include + +#include "log.h" + +#include "pim_str.h" + +void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size) +{ + int save_errno = errno; + + if (!inet_ntop(AF_INET, &addr, buf, buf_size)) { + int e = errno; + zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s", + buf_size, e, strerror(e)); + if (onfail) + snprintf(buf, buf_size, "%s", onfail); + } + + errno = save_errno; +} diff --git a/pimd/pim_str.h b/pimd/pim_str.h new file mode 100644 index 000000000..925f17f73 --- /dev/null +++ b/pimd/pim_str.h @@ -0,0 +1,32 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_STR_H +#define PIM_STR_H + +#include +#include +#include + +void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); + +#endif diff --git a/pimd/pim_time.c b/pimd/pim_time.c new file mode 100644 index 000000000..a837e5b00 --- /dev/null +++ b/pimd/pim_time.c @@ -0,0 +1,151 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include +#include + +#include +#include "log.h" +#include "thread.h" + +#include "pim_time.h" + +/* + see man clock_gettime + */ +static int pim_gettime(clockid_t clk_id, struct timeval *tv) +{ + return quagga_gettime(clk_id, tv); +} + +/* + pim_time_monotonic_sec(): + number of seconds since some unspecified starting point +*/ +int64_t pim_time_monotonic_sec() +{ + struct timeval now_tv; + + if (pim_gettime(CLOCK_MONOTONIC, &now_tv)) { + zlog_err("%s: gettime(CLOCK_MONOTONIC) failure: errno=%d: %s", + __PRETTY_FUNCTION__, + errno, strerror(errno)); + return -1; + } + + return now_tv.tv_sec; +} + +/* + pim_time_monotonic_dsec(): + number of deciseconds since some unspecified starting point +*/ +int64_t pim_time_monotonic_dsec() +{ + struct timeval now_tv; + int64_t now_dsec; + + if (pim_gettime(CLOCK_MONOTONIC, &now_tv)) { + zlog_err("%s: gettime(CLOCK_MONOTONIC) failure: errno=%d: %s", + __PRETTY_FUNCTION__, + errno, strerror(errno)); + return -1; + } + + now_dsec = ((int64_t) now_tv.tv_sec) * 10 + ((int64_t) now_tv.tv_usec) / 100000; + + return now_dsec; +} + +int pim_time_mmss(char *buf, int buf_size, long sec) +{ + long mm; + int wr; + + zassert(buf_size >= 5); + + mm = sec / 60; + sec %= 60; + + wr = snprintf(buf, buf_size, "%02ld:%02ld", mm, sec); + + return wr != 8; +} + +static int pim_time_hhmmss(char *buf, int buf_size, long sec) +{ + long hh; + long mm; + int wr; + + zassert(buf_size >= 8); + + hh = sec / 3600; + sec %= 3600; + mm = sec / 60; + sec %= 60; + + wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec); + + return wr != 8; +} + +void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t_timer) +{ + if (t_timer) { + pim_time_mmss(buf, buf_size, + thread_timer_remain_second(t_timer)); + } + else { + snprintf(buf, buf_size, "--:--"); + } +} + +void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t_timer) +{ + if (t_timer) { + pim_time_hhmmss(buf, buf_size, + thread_timer_remain_second(t_timer)); + } + else { + snprintf(buf, buf_size, "--:--:--"); + } +} + +void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec) +{ + zassert(buf_size >= 8); + + pim_time_hhmmss(buf, buf_size, uptime_sec); +} + +long pim_time_timer_remain_msec(struct thread *t_timer) +{ + /* FIXME: Actually fetch msec resolution from thread */ + + /* no timer thread running means timer has expired: return 0 */ + + return t_timer ? + 1000 * thread_timer_remain_second(t_timer) : + 0; +} diff --git a/pimd/pim_time.h b/pimd/pim_time.h new file mode 100644 index 000000000..379eb6cff --- /dev/null +++ b/pimd/pim_time.h @@ -0,0 +1,39 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_TIME_H +#define PIM_TIME_H + +#include + +#include +#include "thread.h" + +int64_t pim_time_monotonic_sec(void); +int64_t pim_time_monotonic_dsec(void); +int pim_time_mmss(char *buf, int buf_size, long sec); +void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t); +void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t); +void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec); +long pim_time_timer_remain_msec(struct thread *t_timer); + +#endif /* PIM_TIME_H */ diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c new file mode 100644 index 000000000..c578a70d7 --- /dev/null +++ b/pimd/pim_tlv.c @@ -0,0 +1,707 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "prefix.h" + +#include "pimd.h" +#include "pim_tlv.h" +#include "pim_str.h" +#include "pim_msg.h" + +char *pim_tlv_append_uint16(char *buf, + const char *buf_pastend, + uint16_t option_type, + uint16_t option_value) +{ + uint16_t option_len = 2; + + if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { + zlog_warn("%s: buffer overflow: left=%d needed=%d", + __PRETTY_FUNCTION__, + buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); + return 0; + } + + *(uint16_t *) buf = htons(option_type); + buf += 2; + *(uint16_t *) buf = htons(option_len); + buf += 2; + *(uint16_t *) buf = htons(option_value); + buf += option_len; + + return buf; +} + +char *pim_tlv_append_2uint16(char *buf, + const char *buf_pastend, + uint16_t option_type, + uint16_t option_value1, + uint16_t option_value2) +{ + uint16_t option_len = 4; + + if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { + zlog_warn("%s: buffer overflow: left=%d needed=%d", + __PRETTY_FUNCTION__, + buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); + return 0; + } + + *(uint16_t *) buf = htons(option_type); + buf += 2; + *(uint16_t *) buf = htons(option_len); + buf += 2; + *(uint16_t *) buf = htons(option_value1); + buf += 2; + *(uint16_t *) buf = htons(option_value2); + buf += 2; + + return buf; +} + +char *pim_tlv_append_uint32(char *buf, + const char *buf_pastend, + uint16_t option_type, + uint32_t option_value) +{ + uint16_t option_len = 4; + + if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { + zlog_warn("%s: buffer overflow: left=%d needed=%d", + __PRETTY_FUNCTION__, + buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); + return 0; + } + + *(uint16_t *) buf = htons(option_type); + buf += 2; + *(uint16_t *) buf = htons(option_len); + buf += 2; + *(uint32_t *) buf = htonl(option_value); + buf += option_len; + + return buf; +} + +#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) + +char *pim_tlv_append_addrlist_ucast(char *buf, + const char *buf_pastend, + struct list *ifconnected) +{ + struct listnode *node; + uint16_t option_len = 0; + + char *curr; + + node = listhead(ifconnected); + + /* Empty address list ? */ + if (!node) { + return buf; + } + + /* Skip first address (primary) */ + node = listnextnode(node); + + /* Scan secondary address list */ + curr = buf + 4; /* skip T and L */ + for (; node; node = listnextnode(node)) { + struct connected *ifc = listgetdata(node); + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + if ((curr + ucast_ipv4_encoding_len) > buf_pastend) { + zlog_warn("%s: buffer overflow: left=%d needed=%d", + __PRETTY_FUNCTION__, + buf_pastend - curr, ucast_ipv4_encoding_len); + return 0; + } + + /* Write encoded unicast IPv4 address */ + *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ + ++curr; + *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ + ++curr; + *(struct in_addr *) curr = p->u.prefix4; + curr += sizeof(struct in_addr); + + option_len += ucast_ipv4_encoding_len; + } + + if (PIM_DEBUG_PIM_TRACE) { + zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %d", + __PRETTY_FUNCTION__, + option_len / ucast_ipv4_encoding_len); + } + + if (option_len < 1) { + /* Empty secondary unicast IPv4 address list */ + return buf; + } + + /* + * Write T and L + */ + *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); + *(uint16_t *) (buf + 2) = htons(option_len); + + return curr; +} + +static int check_tlv_length(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + int correct_len, int option_len) +{ + if (option_len != correct_len) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", + label, tlv_name, + option_len, correct_len, + src_str, ifname); + return -1; + } + + return 0; +} + +static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint16_t new, uint16_t old) +{ + if (PIM_OPTION_IS_SET(options, opt_mask)) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", + label, tlv_name, + new, old, + src_str, ifname); + } +} + +static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint32_t new, uint32_t old) +{ + if (PIM_OPTION_IS_SET(options, opt_mask)) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", + label, tlv_name, + new, old, + src_str, ifname); + } +} + +static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, + const char *ifname, struct in_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint32_t new, uint32_t old) +{ + if (PIM_OPTION_IS_SET(options, opt_mask)) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", + label, tlv_name, + new, old, + src_str, ifname); + } +} + +int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint16_t *hello_option_holdtime, + uint16_t option_len, + const char *tlv_curr) +{ + const char *label = "holdtime"; + + if (check_tlv_length(__PRETTY_FUNCTION__, label, + ifname, src_addr, + sizeof(uint16_t), option_len)) { + return -1; + } + + check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, + ifname, src_addr, + *hello_options, PIM_OPTION_MASK_HOLDTIME, + PIM_TLV_GET_HOLDTIME(tlv_curr), + *hello_option_holdtime); + + PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); + + *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); + + return 0; +} + +int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint16_t *hello_option_propagation_delay, + uint16_t *hello_option_override_interval, + uint16_t option_len, + const char *tlv_curr) +{ + if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", + ifname, src_addr, + sizeof(uint32_t), option_len)) { + return -1; + } + + check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", + ifname, src_addr, + *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, + PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), + *hello_option_propagation_delay); + + PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); + + *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); + if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { + PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); + } + else { + PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); + } + ++tlv_curr; + ++tlv_curr; + *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); + + return 0; +} + +int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint32_t *hello_option_dr_priority, + uint16_t option_len, + const char *tlv_curr) +{ + const char *label = "dr_priority"; + + if (check_tlv_length(__PRETTY_FUNCTION__, label, + ifname, src_addr, + sizeof(uint32_t), option_len)) { + return -1; + } + + check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, + ifname, src_addr, + *hello_options, PIM_OPTION_MASK_DR_PRIORITY, + PIM_TLV_GET_DR_PRIORITY(tlv_curr), + *hello_option_dr_priority); + + PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); + + *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); + + return 0; +} + +int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint32_t *hello_option_generation_id, + uint16_t option_len, + const char *tlv_curr) +{ + const char *label = "generation_id"; + + if (check_tlv_length(__PRETTY_FUNCTION__, label, + ifname, src_addr, + sizeof(uint32_t), option_len)) { + return -1; + } + + check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, + ifname, src_addr, + *hello_options, PIM_OPTION_MASK_GENERATION_ID, + PIM_TLV_GET_GENERATION_ID(tlv_curr), + *hello_option_generation_id); + + PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); + + *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); + + return 0; +} + +int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, + struct prefix *p, + const char *buf, + int buf_size) +{ + const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ + const char *addr; + const char *pastend; + int family; + int type; + + if (buf_size < ucast_encoding_min_len) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s", + __PRETTY_FUNCTION__, + buf_size, ucast_encoding_min_len, + src_str, ifname); + return -1; + } + + addr = buf; + pastend = buf + buf_size; + + family = *(const uint8_t *) addr; + ++addr; + type = *(const uint8_t *) addr; + ++addr; + + switch (family) { + case PIM_MSG_ADDRESS_FAMILY_IPV4: + if (type) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s", + __PRETTY_FUNCTION__, + type, src_str, ifname); + return -2; + } + + if ((addr + sizeof(struct in_addr)) > pastend) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: IPv4 unicast address overflow: left=%d needed=%d from %s on %s", + __PRETTY_FUNCTION__, + pastend - addr, sizeof(struct in_addr), + src_str, ifname); + return -3; + } + + p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ + p->u.prefix4 = *(const struct in_addr *) addr; + addr += sizeof(struct in_addr); + + break; + default: + { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s", + __PRETTY_FUNCTION__, + family, src_str, ifname); + return -4; + } + } + + return addr - buf; +} + +int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, + struct prefix *p, + const char *buf, + int buf_size) +{ + const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ + const char *addr; + const char *pastend; + int family; + int type; + int mask_len; + + if (buf_size < grp_encoding_min_len) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s", + __PRETTY_FUNCTION__, + buf_size, grp_encoding_min_len, + src_str, ifname); + return -1; + } + + addr = buf; + pastend = buf + buf_size; + + family = *(const uint8_t *) addr; + ++addr; + type = *(const uint8_t *) addr; + ++addr; + ++addr; /* skip b_reserved_z fields */ + mask_len = *(const uint8_t *) addr; + ++addr; + + switch (family) { + case PIM_MSG_ADDRESS_FAMILY_IPV4: + if (type) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unknown group address encoding type=%d from %s on %s", + __PRETTY_FUNCTION__, + type, src_str, ifname); + return -2; + } + + if ((addr + sizeof(struct in_addr)) > pastend) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: IPv4 group address overflow: left=%d needed=%d from %s on %s", + __PRETTY_FUNCTION__, + pastend - addr, sizeof(struct in_addr), + src_str, ifname); + return -3; + } + + p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ + p->u.prefix4 = *(const struct in_addr *) addr; + p->prefixlen = mask_len; + + addr += sizeof(struct in_addr); + + break; + default: + { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unknown group address encoding family=%d from %s on %s", + __PRETTY_FUNCTION__, + family, src_str, ifname); + return -4; + } + } + + return addr - buf; +} + +int pim_parse_addr_source(const char *ifname, + struct in_addr src_addr, + struct prefix *p, + uint8_t *flags, + const char *buf, + int buf_size) +{ + const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ + const char *addr; + const char *pastend; + int family; + int type; + int mask_len; + + if (buf_size < src_encoding_min_len) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s", + __PRETTY_FUNCTION__, + buf_size, src_encoding_min_len, + src_str, ifname); + return -1; + } + + addr = buf; + pastend = buf + buf_size; + + family = *(const uint8_t *) addr; + ++addr; + type = *(const uint8_t *) addr; + ++addr; + *flags = *(const uint8_t *) addr; + ++addr; + mask_len = *(const uint8_t *) addr; + ++addr; + + switch (family) { + case PIM_MSG_ADDRESS_FAMILY_IPV4: + if (type) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unknown source address encoding type=%d from %s on %s", + __PRETTY_FUNCTION__, + type, src_str, ifname); + return -2; + } + + if ((addr + sizeof(struct in_addr)) > pastend) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: IPv4 source address overflow: left=%d needed=%d from %s on %s", + __PRETTY_FUNCTION__, + pastend - addr, sizeof(struct in_addr), + src_str, ifname); + return -3; + } + + p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ + p->u.prefix4 = *(const struct in_addr *) addr; + p->prefixlen = mask_len; + + addr += sizeof(struct in_addr); + + break; + default: + { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: unknown source address encoding family=%d from %s on %s", + __PRETTY_FUNCTION__, + family, src_str, ifname); + return -4; + } + } + + return addr - buf; +} + +#define FREE_ADDR_LIST(hello_option_addr_list) \ +{ \ + if (hello_option_addr_list) { \ + list_delete(hello_option_addr_list); \ + hello_option_addr_list = 0; \ + } \ +} + +int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + struct list **hello_option_addr_list, + uint16_t option_len, + const char *tlv_curr) +{ + const char *addr; + const char *pastend; + + zassert(hello_option_addr_list); + + /* + Scan addr list + */ + addr = tlv_curr; + pastend = tlv_curr + option_len; + while (addr < pastend) { + struct prefix tmp; + int addr_offset; + + /* + Parse ucast addr + */ + addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp, + addr, pastend - addr); + if (addr_offset < 1) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", + __PRETTY_FUNCTION__, + src_str, ifname); + FREE_ADDR_LIST(*hello_option_addr_list); + return -1; + } + addr += addr_offset; + + /* + Debug + */ + if (PIM_DEBUG_PIM_TRACE) { + switch (tmp.family) { + case AF_INET: + { + char addr_str[100]; + char src_str[100]; + pim_inet4_dump("", tmp.u.prefix4, addr_str, sizeof(addr_str)); + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", + __PRETTY_FUNCTION__, + *hello_option_addr_list ? + ((int) listcount(*hello_option_addr_list)) : -1, + addr_str, src_str, ifname); + } + break; + default: + { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", + __PRETTY_FUNCTION__, + *hello_option_addr_list ? + ((int) listcount(*hello_option_addr_list)) : -1, + src_str, ifname); + } + } + } + + /* + Exclude neighbor's primary address if incorrectly included in + the secondary address list + */ + if (tmp.family == AF_INET) { + if (tmp.u.prefix4.s_addr == src_addr.s_addr) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: ignoring primary address in secondary list from %s on %s", + __PRETTY_FUNCTION__, + src_str, ifname); + continue; + } + } + + /* + Allocate list if needed + */ + if (!*hello_option_addr_list) { + *hello_option_addr_list = list_new(); + if (!*hello_option_addr_list) { + zlog_err("%s %s: failure: hello_option_addr_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return -2; + } + (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; + } + + /* + Attach addr to list + */ + { + struct prefix *p; + p = prefix_new(); + if (!p) { + zlog_err("%s %s: failure: prefix_new()", + __FILE__, __PRETTY_FUNCTION__); + FREE_ADDR_LIST(*hello_option_addr_list); + return -3; + } + p->family = tmp.family; + p->u.prefix4 = tmp.u.prefix4; + listnode_add(*hello_option_addr_list, p); + } + + } /* while (addr < pastend) */ + + /* + Mark hello option + */ + PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); + + return 0; +} diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h new file mode 100644 index 000000000..9602cb1c7 --- /dev/null +++ b/pimd/pim_tlv.h @@ -0,0 +1,133 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_TLV_H +#define PIM_TLV_H + +#include + +#include "config.h" +#include "if.h" +#include "linklist.h" + +#ifdef HAVE_INTTYPES_H +#include +#endif /* HAVE_INTTYPES_H */ + +#define PIM_MSG_OPTION_TYPE_HOLDTIME (1) +#define PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY (2) +#define PIM_MSG_OPTION_TYPE_DR_PRIORITY (19) +#define PIM_MSG_OPTION_TYPE_GENERATION_ID (20) +#define PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH (21) +#define PIM_MSG_OPTION_TYPE_ADDRESS_LIST (24) + +typedef uint32_t pim_hello_options; +#define PIM_OPTION_MASK_HOLDTIME (1 << 0) /* recv holdtime */ +#define PIM_OPTION_MASK_LAN_PRUNE_DELAY (1 << 1) /* recv lan_prune_delay */ +#define PIM_OPTION_MASK_DR_PRIORITY (1 << 2) /* recv dr_priority */ +#define PIM_OPTION_MASK_GENERATION_ID (1 << 3) /* recv generation_id */ +#define PIM_OPTION_MASK_ADDRESS_LIST (1 << 4) /* recv secondary address list */ +#define PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION (1 << 5) /* T bit value (valid if recv lan_prune_delay) */ + +#define PIM_RPT_BIT_MASK (1 << 0) +#define PIM_WILDCARD_BIT_MASK (1 << 1) + +#define PIM_OPTION_SET(options, option_mask) ((options) |= (option_mask)) +#define PIM_OPTION_UNSET(options, option_mask) ((options) &= ~(option_mask)) +#define PIM_OPTION_IS_SET(options, option_mask) ((options) & (option_mask)) + +#define PIM_TLV_GET_UINT16(buf) ntohs(*(const uint16_t *)(buf)) +#define PIM_TLV_GET_UINT32(buf) ntohl(*(const uint32_t *)(buf)) +#define PIM_TLV_GET_TYPE(buf) PIM_TLV_GET_UINT16(buf) +#define PIM_TLV_GET_LENGTH(buf) PIM_TLV_GET_UINT16(buf) +#define PIM_TLV_GET_HOLDTIME(buf) PIM_TLV_GET_UINT16(buf) +#define PIM_TLV_GET_PROPAGATION_DELAY(buf) (PIM_TLV_GET_UINT16(buf) & 0x7FFF) +#define PIM_TLV_GET_OVERRIDE_INTERVAL(buf) PIM_TLV_GET_UINT16(buf) +#define PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(buf) ((*(const uint8_t *)(buf)) & 0x80) +#define PIM_TLV_GET_DR_PRIORITY(buf) PIM_TLV_GET_UINT32(buf) +#define PIM_TLV_GET_GENERATION_ID(buf) PIM_TLV_GET_UINT32(buf) + +#define PIM_TLV_TYPE_SIZE (2) +#define PIM_TLV_LENGTH_SIZE (2) +#define PIM_TLV_MIN_SIZE (PIM_TLV_TYPE_SIZE + PIM_TLV_LENGTH_SIZE) +#define PIM_TLV_OPTION_SIZE(option_len) (PIM_TLV_MIN_SIZE + (option_len)) + +char *pim_tlv_append_uint16(char *buf, + const char *buf_pastend, + uint16_t option_type, + uint16_t option_value); +char *pim_tlv_append_2uint16(char *buf, + const char *buf_pastend, + uint16_t option_type, + uint16_t option_value1, + uint16_t option_value2); +char *pim_tlv_append_uint32(char *buf, + const char *buf_pastend, + uint16_t option_type, + uint32_t option_value); +char *pim_tlv_append_addrlist_ucast(char *buf, + const char *buf_pastend, + struct list *ifconnected); + +int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint16_t *hello_option_holdtime, + uint16_t option_len, + const char *tlv_curr); +int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint16_t *hello_option_propagation_delay, + uint16_t *hello_option_override_interval, + uint16_t option_len, + const char *tlv_curr); +int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint32_t *hello_option_dr_priority, + uint16_t option_len, + const char *tlv_curr); +int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + uint32_t *hello_option_generation_id, + uint16_t option_len, + const char *tlv_curr); +int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, + pim_hello_options *hello_options, + struct list **hello_option_addr_list, + uint16_t option_len, + const char *tlv_curr); + +int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, + struct prefix *p, + const char *buf, + int buf_size); +int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, + struct prefix *p, + const char *buf, + int buf_size); +int pim_parse_addr_source(const char *ifname, + struct in_addr src_addr, + struct prefix *p, + uint8_t *flags, + const char *buf, + int buf_size); + +#endif /* PIM_TLV_H */ diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c new file mode 100644 index 000000000..b9cf1e52c --- /dev/null +++ b/pimd/pim_upstream.c @@ -0,0 +1,686 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "zebra/rib.h" + +#include "log.h" +#include "zclient.h" +#include "memory.h" +#include "thread.h" +#include "linklist.h" + +#include "pimd.h" +#include "pim_pim.h" +#include "pim_str.h" +#include "pim_time.h" +#include "pim_iface.h" +#include "pim_join.h" +#include "pim_zlookup.h" +#include "pim_upstream.h" +#include "pim_ifchannel.h" +#include "pim_neighbor.h" +#include "pim_rpf.h" +#include "pim_zebra.h" +#include "pim_oil.h" +#include "pim_macro.h" + +static void join_timer_start(struct pim_upstream *up); +static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); + +void pim_upstream_free(struct pim_upstream *up) +{ + XFREE(MTYPE_PIM_UPSTREAM, up); +} + +static void upstream_channel_oil_detach(struct pim_upstream *up) +{ + if (up->channel_oil) { + pim_channel_oil_del(up->channel_oil); + up->channel_oil = 0; + } +} + +void pim_upstream_delete(struct pim_upstream *up) +{ + THREAD_OFF(up->t_join_timer); + + upstream_channel_oil_detach(up); + + /* + notice that listnode_delete() can't be moved + into pim_upstream_free() because the later is + called by list_delete_all_node() + */ + listnode_delete(qpim_upstream_list, up); + + pim_upstream_free(up); +} + +static void send_join(struct pim_upstream *up) +{ + zassert(up->join_state == PIM_UPSTREAM_JOINED); + + + if (PIM_DEBUG_PIM_TRACE) { + if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { + char src_str[100]; + char grp_str[100]; + char rpf_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); + zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s", + __PRETTY_FUNCTION__, + src_str, grp_str, rpf_str); + /* warning only */ + } + } + + /* send Join(S,G) to the current upstream neighbor */ + pim_joinprune_send(up->rpf.source_nexthop.interface, + up->rpf.rpf_addr, + up->source_addr, + up->group_addr, + 1 /* join */); +} + +static int on_join_timer(struct thread *t) +{ + struct pim_upstream *up; + + zassert(t); + up = THREAD_ARG(t); + zassert(up); + + send_join(up); + + up->t_join_timer = 0; + join_timer_start(up); + + return 0; +} + +static void join_timer_start(struct pim_upstream *up) +{ + if (PIM_DEBUG_PIM_EVENTS) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)", + __PRETTY_FUNCTION__, + qpim_t_periodic, + src_str, grp_str); + } + + zassert(!up->t_join_timer); + + THREAD_TIMER_ON(master, up->t_join_timer, + on_join_timer, + up, qpim_t_periodic); +} + +void pim_upstream_join_timer_restart(struct pim_upstream *up) +{ + THREAD_OFF(up->t_join_timer); + join_timer_start(up); +} + +static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up, + int interval_msec) +{ + if (PIM_DEBUG_PIM_EVENTS) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)", + __PRETTY_FUNCTION__, + interval_msec, + src_str, grp_str); + } + + THREAD_OFF(up->t_join_timer); + THREAD_TIMER_MSEC_ON(master, up->t_join_timer, + on_join_timer, + up, interval_msec); +} + +void pim_upstream_join_suppress(struct pim_upstream *up, + struct in_addr rpf_addr, + int holdtime) +{ + long t_joinsuppress_msec; + long join_timer_remain_msec; + + t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), + 1000 * holdtime); + + join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char grp_str[100]; + char rpf_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); + zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, + rpf_str, + join_timer_remain_msec, t_joinsuppress_msec); + } + + if (join_timer_remain_msec < t_joinsuppress_msec) { + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, t_joinsuppress_msec); + } + + pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec); + } +} + +void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, + struct pim_upstream *up, + struct in_addr rpf_addr) +{ + long join_timer_remain_msec; + int t_override_msec; + + join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); + t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); + + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char grp_str[100]; + char rpf_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); + zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec", + debug_label, + src_str, grp_str, rpf_str, + join_timer_remain_msec, t_override_msec); + } + + if (join_timer_remain_msec > t_override_msec) { + if (PIM_DEBUG_PIM_TRACE) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec", + debug_label, + src_str, grp_str, + t_override_msec); + } + + pim_upstream_join_timer_restart_msec(up, t_override_msec); + } +} + +static void forward_on(struct pim_upstream *up) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct listnode *chnode; + struct listnode *chnextnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + struct in_addr ifaddr; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + ifaddr = pim_ifp->primary_address; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + + if (ch->upstream != up) + continue; + + if (pim_macro_chisin_oiflist(ch)) + pim_forward_start(ch); + + } /* scan iface channel list */ + } /* scan iflist */ +} + +static void forward_off(struct pim_upstream *up) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct listnode *chnode; + struct listnode *chnextnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + + if (ch->upstream != up) + continue; + + pim_forward_stop(ch); + + } /* scan iface channel list */ + } /* scan iflist */ +} + +static void pim_upstream_switch(struct pim_upstream *up, + enum pim_upstream_state new_state) +{ + enum pim_upstream_state old_state = up->join_state; + + zassert(old_state != new_state); + + up->join_state = new_state; + up->state_transition = pim_time_monotonic_sec(); + + if (PIM_DEBUG_PIM_EVENTS) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)", + __PRETTY_FUNCTION__, + ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"), + src_str, grp_str); + } + + pim_upstream_update_assert_tracking_desired(up); + + if (new_state == PIM_UPSTREAM_JOINED) { + forward_on(up); + send_join(up); + join_timer_start(up); + } + else { + forward_off(up); + pim_joinprune_send(up->rpf.source_nexthop.interface, + up->rpf.rpf_addr, + up->source_addr, + up->group_addr, + 0 /* prune */); + zassert(up->t_join_timer); + THREAD_OFF(up->t_join_timer); + } + +} + +static struct pim_upstream *pim_upstream_new(struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_upstream *up; + + up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); + if (!up) { + zlog_err("%s: PIM XMALLOC(%d) failure", + __PRETTY_FUNCTION__, sizeof(*up)); + return 0; + } + + up->source_addr = source_addr; + up->group_addr = group_addr; + up->flags = 0; + up->ref_count = 1; + up->t_join_timer = 0; + up->join_state = 0; + up->state_transition = pim_time_monotonic_sec(); + up->channel_oil = 0; + + up->rpf.source_nexthop.interface = 0; + up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY; + up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference; + up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric; + up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY; + + pim_rpf_update(up, 0); + + listnode_add(qpim_upstream_list, up); + + return up; +} + +struct pim_upstream *pim_upstream_find(struct in_addr source_addr, + struct in_addr group_addr) +{ + struct listnode *up_node; + struct pim_upstream *up; + + for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { + if ( + (source_addr.s_addr == up->source_addr.s_addr) && + (group_addr.s_addr == up->group_addr.s_addr) + ) { + return up; + } + } + + return 0; +} + +struct pim_upstream *pim_upstream_add(struct in_addr source_addr, + struct in_addr group_addr) +{ + struct pim_upstream *up; + + up = pim_upstream_find(source_addr, group_addr); + if (up) { + ++up->ref_count; + } + else { + up = pim_upstream_new(source_addr, group_addr); + } + + return up; +} + +void pim_upstream_del(struct pim_upstream *up) +{ + --up->ref_count; + + if (up->ref_count < 1) { + pim_upstream_delete(up); + } +} + +/* + Evaluate JoinDesired(S,G): + + JoinDesired(S,G) is true if there is a downstream (S,G) interface I + in the set: + + inherited_olist(S,G) = + joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) + + JoinDesired(S,G) may be affected by changes in the following: + + pim_ifp->primary_address + pim_ifp->pim_dr_addr + ch->ifassert_winner_metric + ch->ifassert_winner + ch->local_ifmembership + ch->ifjoin_state + ch->upstream->rpf.source_nexthop.mrib_metric_preference + ch->upstream->rpf.source_nexthop.mrib_route_metric + ch->upstream->rpf.source_nexthop.interface + + See also pim_upstream_update_join_desired() below. + */ +int pim_upstream_evaluate_join_desired(struct pim_upstream *up) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct listnode *chnode; + struct listnode *chnextnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + if (ch->upstream != up) + continue; + + if (pim_macro_ch_lost_assert(ch)) + continue; /* keep searching */ + + if (pim_macro_chisin_joins_or_include(ch)) + return 1; /* true */ + } /* scan iface channel list */ + } /* scan iflist */ + + return 0; /* false */ +} + +/* + See also pim_upstream_evaluate_join_desired() above. +*/ +void pim_upstream_update_join_desired(struct pim_upstream *up) +{ + int was_join_desired; /* boolean */ + int is_join_desired; /* boolean */ + + was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags); + + is_join_desired = pim_upstream_evaluate_join_desired(up); + if (is_join_desired) + PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags); + else + PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); + + /* switched from false to true */ + if (is_join_desired && !was_join_desired) { + zassert(up->join_state == PIM_UPSTREAM_NOTJOINED); + pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + return; + } + + /* switched from true to false */ + if (!is_join_desired && was_join_desired) { + zassert(up->join_state == PIM_UPSTREAM_JOINED); + pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED); + return; + } +} + +/* + RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages + Transitions from Joined State + RPF'(S,G) GenID changes + + The upstream (S,G) state machine remains in Joined state. If the + Join Timer is set to expire in more than t_override seconds, reset + it so that it expires after t_override seconds. +*/ +void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) +{ + struct listnode *up_node; + struct listnode *up_nextnode; + struct pim_upstream *up; + + /* + Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr + */ + for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { + + if (PIM_DEBUG_PIM_TRACE) { + char neigh_str[100]; + char src_str[100]; + char grp_str[100]; + char rpf_addr_str[100]; + pim_inet4_dump("", neigh_addr, neigh_str, sizeof(neigh_str)); + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); + zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s", + __PRETTY_FUNCTION__, + neigh_str, src_str, grp_str, + up->join_state == PIM_UPSTREAM_JOINED, + rpf_addr_str); + } + + /* consider only (S,G) upstream in Joined state */ + if (up->join_state != PIM_UPSTREAM_JOINED) + continue; + + /* match RPF'(S,G)=neigh_addr */ + if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr) + continue; + + pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change", + up, neigh_addr); + } +} + + +void pim_upstream_rpf_interface_changed(struct pim_upstream *up, + struct interface *old_rpf_ifp) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct interface *ifp; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + /* search all ifchannels */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + if (ch->upstream != up) + continue; + + if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { + if ( + /* RPF_interface(S) was NOT I */ + (old_rpf_ifp == ch->interface) + && + /* RPF_interface(S) stopped being I */ + (ch->upstream->rpf.source_nexthop.interface != ch->interface) + ) { + assert_action_a5(ch); + } + } /* PIM_IFASSERT_I_AM_LOSER */ + + pim_ifchannel_update_assert_tracking_desired(ch); + } + } +} + +void pim_upstream_update_could_assert(struct pim_upstream *up) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct listnode *chnode; + struct listnode *chnextnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + + if (ch->upstream != up) + continue; + + pim_ifchannel_update_could_assert(ch); + + } /* scan iface channel list */ + } /* scan iflist */ +} + +void pim_upstream_update_my_assert_metric(struct pim_upstream *up) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct listnode *chnode; + struct listnode *chnextnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + + if (ch->upstream != up) + continue; + + pim_ifchannel_update_my_assert_metric(ch); + + } /* scan iface channel list */ + } /* scan iflist */ +} + +static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) +{ + struct listnode *ifnode; + struct listnode *ifnextnode; + struct listnode *chnode; + struct listnode *chnextnode; + struct interface *ifp; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + + /* scan all interfaces */ + for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { + + if (ch->upstream != up) + continue; + + pim_ifchannel_update_assert_tracking_desired(ch); + + } /* scan iface channel list */ + } /* scan iflist */ +} diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h new file mode 100644 index 000000000..5b5182dd4 --- /dev/null +++ b/pimd/pim_upstream.h @@ -0,0 +1,122 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_UPSTREAM_H +#define PIM_UPSTREAM_H + +#include + +#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED (1 << 0) +#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (2 << 0) + +#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) +#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) + +#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) +#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) + +#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) +#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) + +/* + RFC 4601: + + Metric Preference + Preference value assigned to the unicast routing protocol that + provided the route to the multicast source or Rendezvous-Point. + + Metric + The unicast routing table metric associated with the route used to + reach the multicast source or Rendezvous-Point. The metric is in + units applicable to the unicast routing protocol used. +*/ +struct pim_nexthop { + struct interface *interface; /* RPF_interface(S) */ + struct in_addr mrib_nexthop_addr; /* MRIB.next_hop(S) */ + uint32_t mrib_metric_preference; /* MRIB.pref(S) */ + uint32_t mrib_route_metric; /* MRIB.metric(S) */ +}; + +struct pim_rpf { + struct pim_nexthop source_nexthop; + struct in_addr rpf_addr; /* RPF'(S,G) */ +}; + +enum pim_rpf_result { + PIM_RPF_OK = 0, + PIM_RPF_CHANGED, + PIM_RPF_FAILURE +}; + +enum pim_upstream_state { + PIM_UPSTREAM_NOTJOINED, + PIM_UPSTREAM_JOINED +}; + +/* + Upstream (S,G) channel in Joined state + + (S,G) in the "Not Joined" state is not represented + + See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message +*/ +struct pim_upstream { + struct in_addr source_addr; /* (S,G) source key */ + struct in_addr group_addr; /* (S,G) group key */ + uint32_t flags; + struct channel_oil *channel_oil; + + enum pim_upstream_state join_state; + int ref_count; + + struct pim_rpf rpf; + + struct thread *t_join_timer; + int64_t state_transition; /* Record current state uptime */ +}; + +void pim_upstream_free(struct pim_upstream *up); +void pim_upstream_delete(struct pim_upstream *up); +struct pim_upstream *pim_upstream_find(struct in_addr source_addr, + struct in_addr group_addr); +struct pim_upstream *pim_upstream_add(struct in_addr source_addr, + struct in_addr group_addr); +void pim_upstream_del(struct pim_upstream *up); + +int pim_upstream_evaluate_join_desired(struct pim_upstream *up); +void pim_upstream_update_join_desired(struct pim_upstream *up); + +void pim_upstream_join_suppress(struct pim_upstream *up, + struct in_addr rpf_addr, + int holdtime); +void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, + struct pim_upstream *up, + struct in_addr rpf_addr); +void pim_upstream_join_timer_restart(struct pim_upstream *up); +void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr); +void pim_upstream_rpf_interface_changed(struct pim_upstream *up, + struct interface *old_rpf_ifp); + +void pim_upstream_update_could_assert(struct pim_upstream *up); +void pim_upstream_update_my_assert_metric(struct pim_upstream *up); + +#endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_util.c b/pimd/pim_util.c new file mode 100644 index 000000000..5bc8d07ef --- /dev/null +++ b/pimd/pim_util.c @@ -0,0 +1,132 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include "pim_util.h" + +/* + RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) + + If QQIC < 128, QQI = QQIC + If QQIC >= 128, QQI = (mant | 0x10) << (exp + 3) + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |1| exp | mant | + +-+-+-+-+-+-+-+-+ + + Since exp=0..7 then (exp+3)=3..10, then QQI has + one of the following bit patterns: + + exp=0: QQI = 0000.0000.1MMM.M000 + exp=1: QQI = 0000.0001.MMMM.0000 + ... + exp=6: QQI = 001M.MMM0.0000.0000 + exp=7: QQI = 01MM.MM00.0000.0000 + --------- --------- + 0x4 0x0 0x0 0x0 +*/ +uint8_t igmp_msg_encode16to8(uint16_t value) +{ + uint8_t code; + + if (value < 128) { + code = value; + } + else { + uint16_t mask = 0x4000; + uint8_t exp; + uint16_t mant; + for (exp = 7; exp > 0; --exp) { + if (mask & value) + break; + mask >>= 1; + } + mant = 0x000F & (value >> (exp + 3)); + code = ((uint8_t) 1 << 7) | ((uint8_t) exp << 4) | (uint8_t) mant; + } + + return code; +} + +/* + RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) + + If QQIC < 128, QQI = QQIC + If QQIC >= 128, QQI = (mant | 0x10) << (exp + 3) + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |1| exp | mant | + +-+-+-+-+-+-+-+-+ +*/ +uint16_t igmp_msg_decode8to16(uint8_t code) +{ + uint16_t value; + + if (code < 128) { + value = code; + } + else { + uint16_t mant = (code & 0x0F); + uint8_t exp = (code & 0x70) >> 4; + value = (mant | 0x10) << (exp + 3); + } + + return value; +} + +#ifndef PIM_USE_QUAGGA_INET_CHECKSUM +/* + RFC 3376: 4.1.2. Checksum + + The Checksum is the 16-bit one's complement of the one's complement + sum of the whole IGMP message (the entire IP payload). For + computing the checksum, the Checksum field is set to zero. When + receiving packets, the checksum MUST be verified before processing a + packet. [RFC-1071] +*/ +uint16_t pim_inet_checksum(const char *buf, int size) +{ + const uint16_t *ptr; + uint32_t sum; + uint16_t checksum; + + ptr = (const uint16_t *) buf; + sum = 0; + while (size > 1) { + sum += *ptr; + ++ptr; + size -= 2; + } + + /* Add left-over byte, if any */ + if (size > 0) + sum += (uint16_t) *(const uint8_t *) ptr; + + /* Fold 32-bit sum to 16 bits */ + sum = (sum & 0xffff) + (sum >> 16); + + checksum = ~sum; + + return checksum; +} +#endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ diff --git a/pimd/pim_util.h b/pimd/pim_util.h new file mode 100644 index 000000000..0fcdce0c0 --- /dev/null +++ b/pimd/pim_util.h @@ -0,0 +1,41 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_UTIL_H +#define PIM_UTIL_H + +#include + +#include + +#include "checksum.h" + +uint8_t igmp_msg_encode16to8(uint16_t value); +uint16_t igmp_msg_decode8to16(uint8_t code); + +#ifdef PIM_USE_QUAGGA_INET_CHECKSUM +#define pim_inet_checksum(buf,size) in_cksum(buf,size) +#else +uint16_t pim_inet_checksum(const char *buf, int size); +#endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ + +#endif /* PIM_UTIL_H */ diff --git a/pimd/pim_version.c b/pimd/pim_version.c new file mode 100644 index 000000000..fe7e56343 --- /dev/null +++ b/pimd/pim_version.c @@ -0,0 +1,25 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include "pim_version.h" + +const char * const PIMD_VERSION = PIMD_VERSION_STR; diff --git a/pimd/pim_version.h b/pimd/pim_version.h new file mode 100644 index 000000000..796db6638 --- /dev/null +++ b/pimd/pim_version.h @@ -0,0 +1,30 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_VERSION_H +#define PIM_VERSION_H + +#define PIMD_VERSION_STR "0.155" + +const char * const PIMD_VERSION; + +#endif /* PIM_VERSION_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c new file mode 100644 index 000000000..7d69b5b10 --- /dev/null +++ b/pimd/pim_vty.c @@ -0,0 +1,145 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "if.h" +#include "linklist.h" + +#include "pimd.h" +#include "pim_vty.h" +#include "pim_iface.h" +#include "pim_cmd.h" +#include "pim_str.h" + +int pim_debug_config_write(struct vty *vty) +{ + int writes = 0; + + if (PIM_DEBUG_IGMP_EVENTS) { + vty_out(vty, "debug igmp events%s", VTY_NEWLINE); + ++writes; + } + if (PIM_DEBUG_IGMP_PACKETS) { + vty_out(vty, "debug igmp packets%s", VTY_NEWLINE); + ++writes; + } + if (PIM_DEBUG_IGMP_TRACE) { + vty_out(vty, "debug igmp trace%s", VTY_NEWLINE); + ++writes; + } + + if (PIM_DEBUG_PIM_EVENTS) { + vty_out(vty, "debug pim events%s", VTY_NEWLINE); + ++writes; + } + if (PIM_DEBUG_PIM_PACKETS) { + vty_out(vty, "debug pim packets%s", VTY_NEWLINE); + ++writes; + } + if (PIM_DEBUG_PIM_TRACE) { + vty_out(vty, "debug pim trace%s", VTY_NEWLINE); + ++writes; + } + + if (PIM_DEBUG_ZEBRA) { + vty_out(vty, "debug pim zebra%s", VTY_NEWLINE); + ++writes; + } + + return writes; +} + +int pim_global_config_write(struct vty *vty) +{ + int writes = 0; + + if (PIM_MROUTE_IS_ENABLED) { + vty_out(vty, "%s%s", PIM_CMD_IP_MULTICAST_ROUTING, VTY_NEWLINE); + ++writes; + } + + return writes; +} + +int pim_interface_config_write(struct vty *vty) +{ + int writes = 0; + struct listnode *node; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + + /* IF name */ + vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); + writes++; + + if (ifp->info) { + struct pim_interface *pim_ifp = ifp->info; + + /* IF ip pim ssm */ + if (PIM_IF_TEST_PIM(pim_ifp->options)) { + vty_out(vty, " ip pim ssm%s", VTY_NEWLINE); + writes++; + } + + /* IF ip igmp */ + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { + vty_out(vty, " ip igmp%s", VTY_NEWLINE); + writes++; + } + + /* IF ip igmp query-interval */ + vty_out(vty, " %s %d%s", + PIM_CMD_IP_IGMP_QUERY_INTERVAL, + pim_ifp->igmp_default_query_interval, + VTY_NEWLINE); + writes++; + + /* IF ip igmp query-max-response-time */ + vty_out(vty, " %s %d%s", + PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, + pim_ifp->igmp_query_max_response_time_dsec, + VTY_NEWLINE); + writes++; + + /* IF ip igmp join */ + if (pim_ifp->igmp_join_list) { + struct listnode *node; + struct igmp_join *ij; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", ij->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", ij->source_addr, source_str, sizeof(source_str)); + vty_out(vty, " ip igmp join %s %s%s", + group_str, source_str, + VTY_NEWLINE); + writes++; + } + } + } + vty_out(vty, "!%s", VTY_NEWLINE); + } + + return writes; +} diff --git a/pimd/pim_vty.h b/pimd/pim_vty.h new file mode 100644 index 000000000..904ee5530 --- /dev/null +++ b/pimd/pim_vty.h @@ -0,0 +1,32 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_VTY_H +#define PIM_VTY_H + +#include "vty.h" + +int pim_debug_config_write(struct vty *vty); +int pim_global_config_write(struct vty *vty); +int pim_interface_config_write(struct vty *vty); + +#endif /* PIM_VTY_H */ diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c new file mode 100644 index 000000000..d03cc5401 --- /dev/null +++ b/pimd/pim_zebra.c @@ -0,0 +1,1172 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "zebra/rib.h" + +#include "log.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" + +#include "pimd.h" +#include "pim_pim.h" +#include "pim_zebra.h" +#include "pim_iface.h" +#include "pim_str.h" +#include "pim_oil.h" +#include "pim_rpf.h" +#include "pim_time.h" +#include "pim_join.h" +#include "pim_zlookup.h" +#include "pim_ifchannel.h" + +#undef PIM_DEBUG_IFADDR_DUMP +#define PIM_DEBUG_IFADDR_DUMP + +static int fib_lookup_if_vif_index(struct in_addr addr); +static int del_oif(struct channel_oil *channel_oil, + struct interface *oif, + uint32_t proto_mask); + +/* Router-id update message from zebra. */ +static int pim_router_id_update_zebra(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct prefix router_id; + + /* FIXME: actually use router_id for anything ? */ + zebra_router_id_update_read(zclient->ibuf, &router_id); + + return 0; +} + +static int pim_zebra_if_add(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + /* + zebra api adds/dels interfaces using the same call + interface_add_read below, see comments in lib/zclient.c + */ + ifp = zebra_interface_add_read(zclient->ibuf); + if (!ifp) + return 0; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); + } + + if (if_is_operative(ifp)) + pim_if_addr_add_all(ifp); + + return 0; +} + +static int pim_zebra_if_del(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + /* + zebra api adds/dels interfaces using the same call + interface_add_read below, see comments in lib/zclient.c + */ + ifp = zebra_interface_add_read(zclient->ibuf); + if (!ifp) + return 0; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); + } + + if (!if_is_operative(ifp)) + pim_if_addr_del_all(ifp); + + return 0; +} + +static int pim_zebra_if_state_up(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + /* + zebra api notifies interface up/down events by using the same call + interface_add_read below, see comments in lib/zclient.c + */ + ifp = zebra_interface_state_read(zclient->ibuf); + if (!ifp) + return 0; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); + } + + if (if_is_operative(ifp)) { + /* + pim_if_addr_add_all() suffices for bringing up both IGMP and PIM + */ + pim_if_addr_add_all(ifp); + } + + return 0; +} + +static int pim_zebra_if_state_down(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + /* + zebra api notifies interface up/down events by using the same call + interface_add_read below, see comments in lib/zclient.c + */ + ifp = zebra_interface_state_read(zclient->ibuf); + if (!ifp) + return 0; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); + } + + if (!if_is_operative(ifp)) { + /* + pim_if_addr_del_all() suffices for shutting down IGMP, + but not for shutting down PIM + */ + pim_if_addr_del_all(ifp); + + /* + pim_sock_delete() closes the socket, stops read and timer threads, + and kills all neighbors. + */ + pim_sock_delete(ifp, "link down"); + } + + return 0; +} + +#ifdef PIM_DEBUG_IFADDR_DUMP +static void dump_if_address(struct interface *ifp) +{ + struct connected *ifc; + struct listnode *node; + + zlog_debug("%s %s: interface %s addresses:", + __FILE__, __PRETTY_FUNCTION__, + ifp->name); + + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + struct prefix *p = ifc->address; + + if (p->family != AF_INET) + continue; + + zlog_debug("%s %s: interface %s address %s", + __FILE__, __PRETTY_FUNCTION__, + ifp->name, + inet_ntoa(p->u.prefix4)); + } +} +#endif + +static int pim_zebra_if_address_add(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + struct prefix *p; + + zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD); + + /* + zebra api notifies address adds/dels events by using the same call + interface_add_read below, see comments in lib/zclient.c + + zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...) + will add address to interface list by calling + connected_add_by_prefix() + */ + c = zebra_interface_address_read(command, zclient->ibuf); + if (!c) + return 0; + + p = c->address; + if (p->family != AF_INET) + return 0; + + if (PIM_DEBUG_ZEBRA) { + char buf[BUFSIZ]; + prefix2str(p, buf, BUFSIZ); + zlog_debug("%s: %s connected IP address %s flags %u", + __PRETTY_FUNCTION__, + c->ifp->name, buf, c->flags); + +#ifdef PIM_DEBUG_IFADDR_DUMP + dump_if_address(c->ifp); +#endif + } + + pim_if_addr_add(c); + + return 0; +} + +static int pim_zebra_if_address_del(int command, struct zclient *client, + zebra_size_t length) +{ + struct connected *c; + struct prefix *p; + + zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE); + + /* + zebra api notifies address adds/dels events by using the same call + interface_add_read below, see comments in lib/zclient.c + + zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...) + will remove address from interface list by calling + connected_delete_by_prefix() + */ + c = zebra_interface_address_read(command, client->ibuf); + if (!c) + return 0; + + p = c->address; + if (p->family != AF_INET) + return 0; + + if (PIM_DEBUG_ZEBRA) { + char buf[BUFSIZ]; + prefix2str(p, buf, BUFSIZ); + zlog_debug("%s: %s disconnected IP address %s flags %u", + __PRETTY_FUNCTION__, + c->ifp->name, buf, c->flags); + +#ifdef PIM_DEBUG_IFADDR_DUMP + dump_if_address(c->ifp); +#endif + } + + pim_if_addr_del(c); + + return 0; +} + +static void scan_upstream_rpf_cache() +{ + struct listnode *up_node; + struct listnode *up_nextnode; + struct pim_upstream *up; + + for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { + struct in_addr old_rpf_addr; + enum pim_rpf_result rpf_result; + + rpf_result = pim_rpf_update(up, &old_rpf_addr); + if (rpf_result == PIM_RPF_FAILURE) + continue; + + if (rpf_result == PIM_RPF_CHANGED) { + + if (up->join_state == PIM_UPSTREAM_JOINED) { + + /* + RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages + + Transitions from Joined State + + RPF'(S,G) changes not due to an Assert + + The upstream (S,G) state machine remains in Joined + state. Send Join(S,G) to the new upstream neighbor, which is + the new value of RPF'(S,G). Send Prune(S,G) to the old + upstream neighbor, which is the old value of RPF'(S,G). Set + the Join Timer (JT) to expire after t_periodic seconds. + */ + + + /* send Prune(S,G) to the old upstream neighbor */ + pim_joinprune_send(up->rpf.source_nexthop.interface, + old_rpf_addr, + up->source_addr, + up->group_addr, + 0 /* prune */); + + /* send Join(S,G) to the current upstream neighbor */ + pim_joinprune_send(up->rpf.source_nexthop.interface, + up->rpf.rpf_addr, + up->source_addr, + up->group_addr, + 1 /* join */); + + pim_upstream_join_timer_restart(up); + } /* up->join_state == PIM_UPSTREAM_JOINED */ + + /* FIXME can join_desired actually be changed by pim_rpf_update() + returning PIM_RPF_CHANGED ? */ + pim_upstream_update_join_desired(up); + + } /* PIM_RPF_CHANGED */ + + } /* for (qpim_upstream_list) */ + +} + +static void scan_oil() +{ + struct listnode *node; + struct listnode *nextnode; + struct channel_oil *c_oil; + + for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) { + int old_vif_index; + int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin); + if (input_iface_vif_index < 1) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + continue; + } + + if (input_iface_vif_index == c_oil->oil.mfcc_parent) { + /* RPF unchanged */ + continue; + } + + if (PIM_DEBUG_ZEBRA) { + struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); + struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + old_iif ? old_iif->name : "", c_oil->oil.mfcc_parent, + new_iif ? new_iif->name : "", input_iface_vif_index); + } + + /* new iif loops to existing oif ? */ + if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) { + struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); + + if (PIM_DEBUG_ZEBRA) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + new_iif ? new_iif->name : "", input_iface_vif_index); + } + + del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY); + } + + /* update iif vif_index */ + old_vif_index = c_oil->oil.mfcc_parent; + c_oil->oil.mfcc_parent = input_iface_vif_index; + + /* update kernel multicast forwarding cache (MFC) */ + if (pim_mroute_add(&c_oil->oil)) { + /* just log warning */ + struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index); + struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + old_iif ? old_iif->name : "", c_oil->oil.mfcc_parent, + new_iif ? new_iif->name : "", input_iface_vif_index); + continue; + } + + } /* for (qpim_channel_oil_list) */ +} + +static int on_rpf_cache_refresh(struct thread *t) +{ + zassert(t); + zassert(qpim_rpf_cache_refresher); + + qpim_rpf_cache_refresher = 0; + + /* update PIM protocol state */ + scan_upstream_rpf_cache(); + + /* update kernel multicast forwarding cache (MFC) */ + scan_oil(); + + return 0; +} + +static void sched_rpf_cache_refresh() +{ + if (qpim_rpf_cache_refresher) + return; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s: triggering %ld msec timer", + __PRETTY_FUNCTION__, + qpim_rpf_cache_refresh_delay_msec); + } + + THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher, + on_rpf_cache_refresh, + 0, qpim_rpf_cache_refresh_delay_msec); +} + +static int redist_read_ipv4_route(int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + int min_len = 4; + + if (length < min_len) { + zlog_warn("%s %s: short buffer: length=%d min=%d", + __FILE__, __PRETTY_FUNCTION__, + length, min_len); + return -1; + } + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc(s); + api.flags = stream_getc(s); + api.message = stream_getc(s); + + /* IPv4 prefix length. */ + memset(&p, 0, sizeof(struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc(s); + + min_len += + PSIZE(p.prefixlen) + + CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 + + CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 + + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 + + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s", + __FILE__, __PRETTY_FUNCTION__, + length, min_len, + CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", + CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); + } + + if (length < min_len) { + zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s", + __FILE__, __PRETTY_FUNCTION__, + length, min_len, + CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", + CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); + return -1; + } + + /* IPv4 prefix. */ + stream_get(&p.prefix, s, PSIZE(p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { + api.nexthop_num = stream_getc(s); + nexthop.s_addr = stream_get_ipv4(s); + } + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { + api.ifindex_num = stream_getc(s); + ifindex = stream_getl(s); + } + + api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? + api.distance = stream_getc(s) : + 0; + + api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? + stream_getl(s) : + 0; + + switch (command) { + case ZEBRA_IPV4_ROUTE_ADD: + if (PIM_DEBUG_ZEBRA) { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("%s: add %s %s/%d " + "nexthop %s ifindex %ld metric%s %u distance%s %u", + __PRETTY_FUNCTION__, + zebra_route_string(api.type), + inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), + ifindex, + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", + api.metric, + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", + api.distance); + } + break; + case ZEBRA_IPV4_ROUTE_DELETE: + if (PIM_DEBUG_ZEBRA) { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("%s: delete %s %s/%d " + "nexthop %s ifindex %ld metric%s %u distance%s %u", + __PRETTY_FUNCTION__, + zebra_route_string(api.type), + inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), + ifindex, + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", + api.metric, + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", + api.distance); + } + break; + default: + zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command); + return -1; + } + + sched_rpf_cache_refresh(); + + return 0; +} + +void pim_zebra_init() +{ + struct zclient *zclient; + int i; + +#ifdef HAVE_TCP_ZEBRA + zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT); +#else + zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", ZEBRA_SERV_PATH); +#endif + + /* Socket for receiving updates from Zebra daemon */ + zclient = zclient_new(); + + zclient->router_id_update = pim_router_id_update_zebra; + zclient->interface_add = pim_zebra_if_add; + zclient->interface_delete = pim_zebra_if_del; + zclient->interface_up = pim_zebra_if_state_up; + zclient->interface_down = pim_zebra_if_state_down; + zclient->interface_address_add = pim_zebra_if_address_add; + zclient->interface_address_delete = pim_zebra_if_address_del; + zclient->ipv4_route_add = redist_read_ipv4_route; + zclient->ipv4_route_delete = redist_read_ipv4_route; + + zclient_init(zclient, ZEBRA_ROUTE_PIM); + zlog_info("zclient_init cleared redistribution request"); + + zassert(zclient->redist_default == ZEBRA_ROUTE_PIM); + + /* Request all redistribution */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (i == zclient->redist_default) + continue; + zclient->redist[i] = 1; + zlog_info("%s: requesting redistribution for %s (%i)", + __PRETTY_FUNCTION__, zebra_route_string(i), i); + } + + /* Request default information */ + zclient->default_information = 1; + zlog_info("%s: requesting default information redistribution", + __PRETTY_FUNCTION__); + + zlog_notice("%s: zclient update socket initialized", + __PRETTY_FUNCTION__); + + zassert(!qpim_zclient_lookup); + qpim_zclient_lookup = zclient_lookup_new(); + zassert(qpim_zclient_lookup); +} + +void igmp_anysource_forward_start(struct igmp_group *group) +{ + /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ + zassert(group->group_filtermode_isexcl); + zassert(listcount(group->group_source_list) < 1); + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("%s %s: UNIMPLEMENTED", + __FILE__, __PRETTY_FUNCTION__); + } +} + +void igmp_anysource_forward_stop(struct igmp_group *group) +{ + /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ + zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0)); + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("%s %s: UNIMPLEMENTED", + __FILE__, __PRETTY_FUNCTION__); + } +} + +static int fib_lookup_if_vif_index(struct in_addr addr) +{ + struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; + int num_ifindex; + int vif_index; + int first_ifindex; + + num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, + PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, + PIM_NEXTHOP_LOOKUP_MAX); + if (num_ifindex < 1) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: could not find nexthop ifindex for address %s", + __FILE__, __PRETTY_FUNCTION__, + addr_str); + return -1; + } + + first_ifindex = nexthop_tab[0].ifindex; + + if (num_ifindex > 1) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", + __FILE__, __PRETTY_FUNCTION__, + num_ifindex, addr_str, first_ifindex); + /* debug warning only, do not return */ + } + + if (PIM_DEBUG_ZEBRA) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s", + __FILE__, __PRETTY_FUNCTION__, + first_ifindex, ifindex2ifname(first_ifindex), addr_str); + } + + vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex); + + if (vif_index < 1) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s", + __FILE__, __PRETTY_FUNCTION__, + vif_index, addr_str); + return -2; + } + + zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); + + if (vif_index > qpim_mroute_oif_highest_vif_index) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s", + __FILE__, __PRETTY_FUNCTION__, + vif_index, qpim_mroute_oif_highest_vif_index, addr_str); + + zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?", + __FILE__, __PRETTY_FUNCTION__, + ifindex2ifname(vif_index), + vif_index); + + return -3; + } + + return vif_index; +} + +static int add_oif(struct channel_oil *channel_oil, + struct interface *oif, + uint32_t proto_mask) +{ + struct pim_interface *pim_ifp; + int old_ttl; + + zassert(channel_oil); + + pim_ifp = oif->info; + + if (pim_ifp->mroute_vif_index < 1) { + zlog_warn("%s %s: interface %s vif_index=%d < 1", + __FILE__, __PRETTY_FUNCTION__, + oif->name, pim_ifp->mroute_vif_index); + return -1; + } + +#ifdef PIM_ENFORCE_LOOPFREE_MFC + /* + Prevent creating MFC entry with OIF=IIF. + + This is a protection against implementation mistakes. + + PIM protocol implicitely ensures loopfree multicast topology. + + IGMP must be protected against adding looped MFC entries created + by both source and receiver attached to the same interface. See + TODO T22. + */ + if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + proto_mask, oif->name, pim_ifp->mroute_vif_index, + source_str, group_str); + return -2; + } +#endif + + zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); + zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); + + /* Prevent single protocol from subscribing same interface to + channel (S,G) multiple times */ + if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + proto_mask, oif->name, pim_ifp->mroute_vif_index, + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], + source_str, group_str); + return -3; + } + + /* Allow other protocol to request subscription of same interface to + channel (S,G) multiple times, by silently ignoring further + requests */ + if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { + + /* Check the OIF really exists before returning, and only log + warning otherwise */ + if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + proto_mask, oif->name, pim_ifp->mroute_vif_index, + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], + source_str, group_str); + } + + return 0; + } + + old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; + + if (old_ttl > 0) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + oif->name, pim_ifp->mroute_vif_index, + source_str, group_str); + return -4; + } + + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; + + if (pim_mroute_add(&channel_oil->oil)) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + oif->name, pim_ifp->mroute_vif_index, + source_str, group_str); + + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; + return -5; + } + + channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec(); + ++channel_oil->oil_size; + channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; + + return 0; +} + +static int del_oif(struct channel_oil *channel_oil, + struct interface *oif, + uint32_t proto_mask) +{ + struct pim_interface *pim_ifp; + int old_ttl; + + zassert(channel_oil); + + pim_ifp = oif->info; + + zassert(pim_ifp->mroute_vif_index >= 1); + zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); + zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); + + /* Prevent single protocol from unsubscribing same interface from + channel (S,G) multiple times */ + if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + proto_mask, oif->name, pim_ifp->mroute_vif_index, + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], + source_str, group_str); + return -2; + } + + /* Mark that protocol is no longer interested in this OIF */ + channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask; + + /* Allow multiple protocols to unsubscribe same interface from + channel (S,G) multiple times, by silently ignoring requests while + there is at least one protocol interested in the channel */ + if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { + + /* Check the OIF keeps existing before returning, and only log + warning otherwise */ + if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + proto_mask, oif->name, pim_ifp->mroute_vif_index, + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], + source_str, group_str); + } + + return 0; + } + + old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; + + if (old_ttl < 1) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + oif->name, pim_ifp->mroute_vif_index, + source_str, group_str); + return -3; + } + + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; + + if (pim_mroute_add(&channel_oil->oil)) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + oif->name, pim_ifp->mroute_vif_index, + source_str, group_str); + + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; + return -4; + } + + --channel_oil->oil_size; + + if (channel_oil->oil_size < 1) { + if (pim_mroute_del(&channel_oil->oil)) { + /* just log a warning in case of failure */ + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } + + return 0; +} + +void igmp_source_forward_start(struct igmp_source *source) +{ + struct igmp_group *group; + + if (PIM_DEBUG_IGMP_TRACE) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d", + __PRETTY_FUNCTION__, + source_str, group_str, + source->source_group->group_igmp_sock->fd, + source->source_group->group_igmp_sock->interface->name, + IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); + } + + /* Prevent IGMP interface from installing multicast route multiple + times */ + if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { + return; + } + + group = source->source_group; + + if (!source->source_channel_oil) { + struct pim_interface *pim_oif; + int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr); + if (input_iface_vif_index < 1) { + char source_str[100]; + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + return; + } + + /* + Protect IGMP against adding looped MFC entries created by both + source and receiver attached to the same interface. See TODO + T22. + */ + pim_oif = source->source_group->group_igmp_sock->interface->info; + if (!pim_oif) { + zlog_warn("%s: multicast not enabled on oif=%s ?", + __PRETTY_FUNCTION__, + source->source_group->group_igmp_sock->interface->name); + return; + } + if (pim_oif->mroute_vif_index < 1) { + zlog_warn("%s %s: oif=%s vif_index=%d < 1", + __FILE__, __PRETTY_FUNCTION__, + source->source_group->group_igmp_sock->interface->name, + pim_oif->mroute_vif_index); + return; + } + if (input_iface_vif_index == pim_oif->mroute_vif_index) { + /* ignore request for looped MFC entry */ + if (PIM_DEBUG_IGMP_TRACE) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d", + __PRETTY_FUNCTION__, + source_str, group_str, + source->source_group->group_igmp_sock->fd, + source->source_group->group_igmp_sock->interface->name, + input_iface_vif_index); + } + return; + } + + source->source_channel_oil = pim_channel_oil_add(group->group_addr, + source->source_addr, + input_iface_vif_index); + if (!source->source_channel_oil) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + return; + } + } + + if (add_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP)) { + return; + } + + /* + Feed IGMPv3-gathered local membership information into PIM + per-interface (S,G) state. + */ + pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, + source->source_addr, group->group_addr); + + IGMP_SOURCE_DO_FORWARDING(source->source_flags); +} + +void igmp_source_forward_stop(struct igmp_source *source) +{ + struct igmp_group *group; + + if (PIM_DEBUG_IGMP_TRACE) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d", + __PRETTY_FUNCTION__, + source_str, group_str, + source->source_group->group_igmp_sock->fd, + source->source_group->group_igmp_sock->interface->name, + IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); + } + + /* Prevent IGMP interface from removing multicast route multiple + times */ + if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { + return; + } + + group = source->source_group; + + if (del_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP)) { + return; + } + + /* + Feed IGMPv3-gathered local membership information into PIM + per-interface (S,G) state. + */ + pim_ifchannel_local_membership_del(group->group_igmp_sock->interface, + source->source_addr, group->group_addr); + + IGMP_SOURCE_DONT_FORWARDING(source->source_flags); +} + +void pim_forward_start(struct pim_ifchannel *ch) +{ + struct pim_upstream *up = ch->upstream; + + if (PIM_DEBUG_PIM_TRACE) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: (S,G)=(%s,%s) oif=%s", + __PRETTY_FUNCTION__, + source_str, group_str, ch->interface->name); + } + + if (!up->channel_oil) { + int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr); + if (input_iface_vif_index < 1) { + char source_str[100]; + pim_inet4_dump("", up->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + return; + } + + up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr, + input_iface_vif_index); + if (!up->channel_oil) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", up->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", up->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + return; + } + } + + add_oif(up->channel_oil, + ch->interface, + PIM_OIF_FLAG_PROTO_PIM); +} + +void pim_forward_stop(struct pim_ifchannel *ch) +{ + struct pim_upstream *up = ch->upstream; + + if (PIM_DEBUG_PIM_TRACE) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); + zlog_debug("%s: (S,G)=(%s,%s) oif=%s", + __PRETTY_FUNCTION__, + source_str, group_str, ch->interface->name); + } + + if (!up->channel_oil) { + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); + zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL", + __PRETTY_FUNCTION__, + source_str, group_str, ch->interface->name); + + return; + } + + del_oif(up->channel_oil, + ch->interface, + PIM_OIF_FLAG_PROTO_PIM); +} diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h new file mode 100644 index 000000000..e0c9bdcb3 --- /dev/null +++ b/pimd/pim_zebra.h @@ -0,0 +1,40 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_ZEBRA_H +#define PIM_ZEBRA_H + +#include "pim_igmp.h" +#include "pim_ifchannel.h" + +void pim_zebra_init(void); + +void igmp_anysource_forward_start(struct igmp_group *group); +void igmp_anysource_forward_stop(struct igmp_group *group); + +void igmp_source_forward_start(struct igmp_source *source); +void igmp_source_forward_stop(struct igmp_source *source); + +void pim_forward_start(struct pim_ifchannel *ch); +void pim_forward_stop(struct pim_ifchannel *ch); + +#endif /* PIM_ZEBRA_H */ diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c new file mode 100644 index 000000000..98548e79f --- /dev/null +++ b/pimd/pim_zlookup.c @@ -0,0 +1,455 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include "zebra/rib.h" + +#include "log.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" +#include "thread.h" + +#include "pimd.h" +#include "pim_pim.h" +#include "pim_str.h" +#include "pim_zlookup.h" + +extern int zclient_debug; + +static void zclient_lookup_sched(struct zclient *zlookup, int delay); + +/* Connect to zebra for nexthop lookup. */ +static int zclient_lookup_connect(struct thread *t) +{ + struct zclient *zlookup; + + zlookup = THREAD_ARG(t); + zlookup->t_connect = NULL; + + if (zlookup->sock >= 0) { + return 0; + } + +#ifdef HAVE_TCP_ZEBRA + zlog_debug("%s: FIXME blocking connect: zclient_socket()", + __PRETTY_FUNCTION__); + zlookup->sock = zclient_socket(); + if (zlookup->sock < 0) { + zlog_warn("%s: failure connecting TCP socket %s,%d", + __PRETTY_FUNCTION__, "127.0.0.1", ZEBRA_PORT); + } + else if (zclient_debug) { + zlog_notice("%s: connected TCP socket %s,%d", + __PRETTY_FUNCTION__, "127.0.0.1", ZEBRA_PORT); + } +#else + zlog_debug("%s: FIXME blocking connect: zclient_socket_un()", + __PRETTY_FUNCTION__); + zlookup->sock = zclient_socket_un(ZEBRA_SERV_PATH); + if (zlookup->sock < 0) { + zlog_warn("%s: failure connecting UNIX socket %s", + __PRETTY_FUNCTION__, ZEBRA_SERV_PATH); + } + else if (zclient_debug) { + zlog_notice("%s: connected UNIX socket %s", + __PRETTY_FUNCTION__, ZEBRA_SERV_PATH); + } +#endif /* HAVE_TCP_ZEBRA */ + + zassert(!zlookup->t_connect); + if (zlookup->sock < 0) { + /* Since last connect failed, retry within 10 secs */ + zclient_lookup_sched(zlookup, 10); + return -1; + } + + return 0; +} + +/* Schedule connection with delay. */ +static void zclient_lookup_sched(struct zclient *zlookup, int delay) +{ + zassert(!zlookup->t_connect); + + THREAD_TIMER_ON(master, zlookup->t_connect, + zclient_lookup_connect, + zlookup, delay); + + zlog_notice("%s: zclient lookup connection scheduled for %d seconds", + __PRETTY_FUNCTION__, delay); +} + +/* Schedule connection for now. */ +static void zclient_lookup_sched_now(struct zclient *zlookup) +{ + zassert(!zlookup->t_connect); + + zlookup->t_connect = thread_add_event(master, zclient_lookup_connect, + zlookup, 0); + + zlog_notice("%s: zclient lookup immediate connection scheduled", + __PRETTY_FUNCTION__); +} + +/* Schedule reconnection, if needed. */ +static void zclient_lookup_reconnect(struct zclient *zlookup) +{ + if (zlookup->t_connect) { + return; + } + + zclient_lookup_sched_now(zlookup); +} + +struct zclient *zclient_lookup_new() +{ + struct zclient *zlookup; + + zlookup = zclient_new(); + if (!zlookup) { + zlog_err("%s: zclient_new() failure", + __PRETTY_FUNCTION__); + return 0; + } + + zlookup->sock = -1; + zlookup->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ); + zlookup->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ); + zlookup->t_connect = 0; + + zclient_lookup_sched_now(zlookup); + + zlog_notice("%s: zclient lookup socket initialized", + __PRETTY_FUNCTION__); + + return zlookup; +} + +static int zclient_read_nexthop(struct zclient *zlookup, + struct pim_zlookup_nexthop nexthop_tab[], + const int tab_size, + struct in_addr addr) +{ + int num_ifindex = 0; + struct stream *s; + const uint16_t MIN_LEN = 14; /* getc=1 getc=1 getw=2 getipv4=4 getc=1 getl=4 getc=1 */ + uint16_t length, len; + u_char marker; + u_char version; + uint16_t command; + int nbytes; + struct in_addr raddr; + uint8_t distance; + uint32_t metric; + int nexthop_num; + int i; + + if (PIM_DEBUG_ZEBRA) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s: addr=%s", + __PRETTY_FUNCTION__, + addr_str); + } + + s = zlookup->ibuf; + stream_reset(s); + + nbytes = stream_read(s, zlookup->sock, 2); + if (nbytes < 2) { + zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d", + __FILE__, __PRETTY_FUNCTION__, nbytes); + close(zlookup->sock); + zlookup->sock = -1; + zclient_lookup_reconnect(zlookup); + return -1; + } + length = stream_getw(s); + + len = length - 2; + + if (len < MIN_LEN) { + zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", + __FILE__, __PRETTY_FUNCTION__, len, MIN_LEN); + close(zlookup->sock); + zlookup->sock = -1; + zclient_lookup_reconnect(zlookup); + return -2; + } + + nbytes = stream_read(s, zlookup->sock, len); + if (nbytes < (length - 2)) { + zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d", + __FILE__, __PRETTY_FUNCTION__, nbytes, len); + close(zlookup->sock); + zlookup->sock = -1; + zclient_lookup_reconnect(zlookup); + return -3; + } + marker = stream_getc(s); + version = stream_getc(s); + + if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { + zlog_err("%s: socket %d version mismatch, marker %d, version %d", + __func__, zlookup->sock, marker, version); + return -4; + } + + command = stream_getw(s); + if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_V2) { + zlog_err("%s: socket %d command mismatch: %d", + __func__, zlookup->sock, command); + return -5; + } + + raddr.s_addr = stream_get_ipv4(s); + + if (raddr.s_addr != addr.s_addr) { + char addr_str[100]; + char raddr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + pim_inet4_dump("", raddr, raddr_str, sizeof(raddr_str)); + zlog_warn("%s: address mismatch: addr=%s raddr=%s", + __PRETTY_FUNCTION__, + addr_str, raddr_str); + /* warning only */ + } + + distance = stream_getc(s); + metric = stream_getl(s); + nexthop_num = stream_getc(s); + + if (nexthop_num < 1) { + zlog_err("%s: socket %d bad nexthop_num=%d", + __func__, zlookup->sock, nexthop_num); + return -6; + } + + len -= MIN_LEN; + + for (i = 0; i < nexthop_num; ++i) { + enum nexthop_types_t nexthop_type; + + if (len < 1) { + zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d", + __func__, zlookup->sock, len); + return -7; + } + + nexthop_type = stream_getc(s); + --len; + + switch (nexthop_type) { + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + if (num_ifindex >= tab_size) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", + __FILE__, __PRETTY_FUNCTION__, + (num_ifindex + 1), tab_size, addr_str); + return num_ifindex; + } + if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { + if (len < 4) { + zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d", + __func__, zlookup->sock, len); + return -8; + } + nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); + len -= 4; + } + else { + nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY; + } + nexthop_tab[num_ifindex].ifindex = stream_getl(s); + nexthop_tab[num_ifindex].protocol_distance = distance; + nexthop_tab[num_ifindex].route_metric = metric; + ++num_ifindex; + break; + case ZEBRA_NEXTHOP_IPV4: + if (num_ifindex >= tab_size) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", + __FILE__, __PRETTY_FUNCTION__, + (num_ifindex + 1), tab_size, addr_str); + return num_ifindex; + } + nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); + len -= 4; + nexthop_tab[num_ifindex].ifindex = 0; + nexthop_tab[num_ifindex].protocol_distance = distance; + nexthop_tab[num_ifindex].route_metric = metric; + { + char addr_str[100]; + char nexthop_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + pim_inet4_dump("", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str)); + zlog_warn("%s %s: zebra returned recursive nexthop %s for address %s", + __FILE__, __PRETTY_FUNCTION__, + nexthop_str, addr_str); + } + ++num_ifindex; + break; + default: + /* do nothing */ + { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s", + __FILE__, __PRETTY_FUNCTION__, + nexthop_type, addr_str); + } + break; + } + } + + return num_ifindex; +} + +static int zclient_lookup_nexthop_once(struct zclient *zlookup, + struct pim_zlookup_nexthop nexthop_tab[], + const int tab_size, + struct in_addr addr) +{ + struct stream *s; + int ret; + + if (PIM_DEBUG_ZEBRA) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_debug("%s: addr=%s", + __PRETTY_FUNCTION__, + addr_str); + } + + /* Check socket. */ + if (zlookup->sock < 0) { + zlog_err("%s %s: zclient lookup socket is not connected", + __FILE__, __PRETTY_FUNCTION__); + zclient_lookup_reconnect(zlookup); + return -1; + } + + s = zlookup->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_V2); + stream_put_in_addr(s, &addr); + stream_putw_at(s, 0, stream_get_endp(s)); + + ret = writen(zlookup->sock, s->data, stream_get_endp(s)); + if (ret < 0) { + zlog_err("%s %s: writen() failure writing to zclient lookup socket", + __FILE__, __PRETTY_FUNCTION__); + close(zlookup->sock); + zlookup->sock = -1; + zclient_lookup_reconnect(zlookup); + return -2; + } + if (ret == 0) { + zlog_err("%s %s: connection closed on zclient lookup socket", + __FILE__, __PRETTY_FUNCTION__); + close(zlookup->sock); + zlookup->sock = -1; + zclient_lookup_reconnect(zlookup); + return -3; + } + + return zclient_read_nexthop(zlookup, nexthop_tab, + tab_size, addr); +} + +int zclient_lookup_nexthop(struct zclient *zlookup, + struct pim_zlookup_nexthop nexthop_tab[], + const int tab_size, + struct in_addr addr, + int max_lookup) +{ + int lookup; + + for (lookup = 0; lookup < max_lookup; ++lookup) { + int num_ifindex; + int first_ifindex; + struct in_addr nexthop_addr; + + num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab, + PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr); + if (num_ifindex < 1) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s", + __FILE__, __PRETTY_FUNCTION__, + lookup, max_lookup, addr_str); + return -1; + } + + /* + FIXME: Non-recursive nexthop ensured only for first ifindex. + However, recursive route lookup should really be fixed in zebra daemon. + See also TODO T24. + */ + first_ifindex = nexthop_tab[0].ifindex; + nexthop_addr = nexthop_tab[0].nexthop_addr; + if (first_ifindex > 0) { + /* found: first ifindex is non-recursive nexthop */ + + if (lookup > 0) { + /* Report non-recursive success after first lookup */ + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s", + __FILE__, __PRETTY_FUNCTION__, + lookup, max_lookup, first_ifindex, addr_str); + + /* use last address as nexthop address */ + nexthop_tab[0].nexthop_addr = addr; + } + + return num_ifindex; + } + + { + char addr_str[100]; + char nexthop_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + pim_inet4_dump("", nexthop_addr, nexthop_str, sizeof(nexthop_str)); + zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s", + __FILE__, __PRETTY_FUNCTION__, + lookup, max_lookup, nexthop_str, addr_str); + } + + addr = nexthop_addr; /* use nexthop addr for recursive lookup */ + + } /* for (max_lookup) */ + + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", + __FILE__, __PRETTY_FUNCTION__, + lookup, max_lookup, addr_str); + + return -2; +} diff --git a/pimd/pim_zlookup.h b/pimd/pim_zlookup.h new file mode 100644 index 000000000..1f184942c --- /dev/null +++ b/pimd/pim_zlookup.h @@ -0,0 +1,47 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_ZLOOKUP_H +#define PIM_ZLOOKUP_H + +#include + +#include "zclient.h" + +#define PIM_NEXTHOP_LOOKUP_MAX (3) /* max. recursive route lookup */ + +struct pim_zlookup_nexthop { + struct in_addr nexthop_addr; + int ifindex; + uint32_t route_metric; + uint8_t protocol_distance; +}; + +struct zclient *zclient_lookup_new(void); + +int zclient_lookup_nexthop(struct zclient *zlookup, + struct pim_zlookup_nexthop nexthop_tab[], + const int tab_size, + struct in_addr addr, + int max_lookup); + +#endif /* PIM_ZLOOKUP_H */ diff --git a/pimd/pimd.c b/pimd/pimd.c new file mode 100644 index 000000000..cbcd06480 --- /dev/null +++ b/pimd/pimd.c @@ -0,0 +1,125 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "log.h" +#include "memory.h" + +#include "pimd.h" +#include "pim_cmd.h" +#include "pim_iface.h" +#include "pim_zebra.h" +#include "pim_str.h" +#include "pim_oil.h" +#include "pim_pim.h" +#include "pim_upstream.h" +#include "pim_rand.h" +#include "pim_rpf.h" + +const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; +const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; +const char *const PIM_ALL_PIM_ROUTERS = MCAST_ALL_PIM_ROUTERS; +const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; + +struct thread_master *master = 0; +uint32_t qpim_debugs = 0; +int qpim_mroute_socket_fd = -1; +int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */ +struct thread *qpim_mroute_socket_reader = 0; +int qpim_mroute_oif_highest_vif_index = -1; +struct list *qpim_channel_oil_list = 0; +int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ +struct list *qpim_upstream_list = 0; +struct zclient *qpim_zclient_lookup = 0; +struct pim_assert_metric qpim_infinite_assert_metric; +long qpim_rpf_cache_refresh_delay_msec = 10000; +struct thread *qpim_rpf_cache_refresher = 0; +struct in_addr qpim_inaddr_any; + +static void pim_free() +{ + if (qpim_channel_oil_list) + list_free(qpim_channel_oil_list); + + if (qpim_upstream_list) + list_free(qpim_upstream_list); +} + +void pim_init() +{ + pim_rand_init(); + + if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { + zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + PIM_ALL_PIM_ROUTERS, errno, strerror(errno)); + zassert(0); + return; + } + + qpim_channel_oil_list = list_new(); + if (!qpim_channel_oil_list) { + zlog_err("%s %s: failure: channel_oil_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return; + } + qpim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free; + + qpim_upstream_list = list_new(); + if (!qpim_upstream_list) { + zlog_err("%s %s: failure: upstream_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + pim_free(); + return; + } + qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free; + + qpim_mroute_socket_fd = -1; /* mark mroute as disabled */ + qpim_mroute_oif_highest_vif_index = -1; + + zassert(!qpim_debugs); + zassert(!PIM_MROUTE_IS_ENABLED); + + qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY; + + /* + RFC 4601: 4.6.3. Assert Metrics + + assert_metric + infinite_assert_metric() { + return {1,infinity,infinity,0} + } + */ + qpim_infinite_assert_metric.rpt_bit_flag = 1; + qpim_infinite_assert_metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; + qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; + qpim_infinite_assert_metric.ip_address = qpim_inaddr_any; + + pim_if_init(); + pim_cmd_init(); +} + +void pim_terminate() +{ + pim_free(); +} diff --git a/pimd/pimd.conf.sample b/pimd/pimd.conf.sample new file mode 100644 index 000000000..2f4543ecd --- /dev/null +++ b/pimd/pimd.conf.sample @@ -0,0 +1,35 @@ +! +! pimd sample configuration file +! $QuaggaId: $Format:%an, %ai, %h$ $ +! +hostname quagga-pimd-router +password zebra +!enable password zebra +! +!log file pimd.log +log stdout +! +line vty + exec-timeout 60 +! +!debug igmp +!debug pim +!debug pim zebra +! +ip multicast-routing +! +! ! HINTS: +! ! - Enable "ip pim ssm" on the interface directly attached to the +! ! multicast source host (if this is the first-hop router) +! ! - Enable "ip pim ssm" on pim-routers-facing interfaces +! ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces +! ! - In order to inject IGMPv3 local membership information in the +! ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on +! ! the same interface; otherwise PIM won't advertise +! ! IGMPv3-learned membership to other PIM routers +! +interface eth0 + ip pim ssm + ip igmp + +! -x- diff --git a/pimd/pimd.h b/pimd/pimd.h new file mode 100644 index 000000000..10f8518a0 --- /dev/null +++ b/pimd/pimd.h @@ -0,0 +1,121 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIMD_H +#define PIMD_H + +#include + +#include "pim_mroute.h" +#include "pim_assert.h" + +#define PIMD_PROGNAME "pimd" +#define PIMD_DEFAULT_CONFIG "pimd.conf" +#define PIMD_VTY_PORT 2611 +#define PIMD_BUG_ADDRESS "http://savannah.nongnu.org/projects/qpimd" + +#define PIM_IP_HEADER_MIN_LEN (20) +#define PIM_IP_HEADER_MAX_LEN (60) +#define PIM_IP_PROTO_IGMP (2) +#define PIM_IP_PROTO_PIM (103) +#define PIM_IGMP_MIN_LEN (8) +#define PIM_MSG_HEADER_LEN (4) +#define PIM_PIM_MIN_LEN PIM_MSG_HEADER_LEN +#define PIM_PROTO_VERSION (2) + +#define MCAST_ALL_SYSTEMS "224.0.0.1" +#define MCAST_ALL_ROUTERS "224.0.0.2" +#define MCAST_ALL_PIM_ROUTERS "224.0.0.13" +#define MCAST_ALL_IGMP_ROUTERS "224.0.0.22" + +#define PIM_FORCE_BOOLEAN(expr) ((expr) != 0) + +#define PIM_NET_INADDR_ANY (htonl(INADDR_ANY)) +#define PIM_INADDR_IS_ANY(addr) ((addr).s_addr == PIM_NET_INADDR_ANY) /* struct in_addr addr */ +#define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ + +#define PIM_MASK_PIM_EVENTS (1 << 0) +#define PIM_MASK_PIM_PACKETS (1 << 1) +#define PIM_MASK_PIM_TRACE (1 << 2) +#define PIM_MASK_IGMP_EVENTS (1 << 3) +#define PIM_MASK_IGMP_PACKETS (1 << 4) +#define PIM_MASK_IGMP_TRACE (1 << 5) +#define PIM_MASK_ZEBRA (1 << 6) + +const char *const PIM_ALL_SYSTEMS; +const char *const PIM_ALL_ROUTERS; +const char *const PIM_ALL_PIM_ROUTERS; +const char *const PIM_ALL_IGMP_ROUTERS; + +struct thread_master *master; +uint32_t qpim_debugs; +int qpim_mroute_socket_fd; +int64_t qpim_mroute_socket_creation; /* timestamp of creation */ +struct thread *qpim_mroute_socket_reader; +int qpim_mroute_oif_highest_vif_index; +struct list *qpim_channel_oil_list; /* list of struct channel_oil */ +struct in_addr qpim_all_pim_routers_addr; +int qpim_t_periodic; /* Period between Join/Prune Messages */ +struct list *qpim_upstream_list; /* list of struct pim_upstream */ +struct zclient *qpim_zclient_lookup; +struct pim_assert_metric qpim_infinite_assert_metric; +long qpim_rpf_cache_refresh_delay_msec; +struct thread *qpim_rpf_cache_refresher; +struct in_addr qpim_inaddr_any; + +#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) + +#define PIM_MROUTE_IS_ENABLED (qpim_mroute_socket_fd >= 0) +#define PIM_MROUTE_IS_DISABLED (qpim_mroute_socket_fd < 0) + +#define PIM_DEBUG_PIM_EVENTS (qpim_debugs & PIM_MASK_PIM_EVENTS) +#define PIM_DEBUG_PIM_PACKETS (qpim_debugs & PIM_MASK_PIM_PACKETS) +#define PIM_DEBUG_PIM_TRACE (qpim_debugs & PIM_MASK_PIM_TRACE) +#define PIM_DEBUG_IGMP_EVENTS (qpim_debugs & PIM_MASK_IGMP_EVENTS) +#define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) +#define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) +#define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) + +#define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) +#define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) +#define PIM_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE)) + +#define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS) +#define PIM_DO_DEBUG_PIM_PACKETS (qpim_debugs |= PIM_MASK_PIM_PACKETS) +#define PIM_DO_DEBUG_PIM_TRACE (qpim_debugs |= PIM_MASK_PIM_TRACE) +#define PIM_DO_DEBUG_IGMP_EVENTS (qpim_debugs |= PIM_MASK_IGMP_EVENTS) +#define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) +#define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) +#define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) + +#define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) +#define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) +#define PIM_DONT_DEBUG_PIM_TRACE (qpim_debugs &= ~PIM_MASK_PIM_TRACE) +#define PIM_DONT_DEBUG_IGMP_EVENTS (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS) +#define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) +#define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) +#define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) + +void pim_init(void); +void pim_terminate(void); + +#endif /* PIMD_H */ diff --git a/pimd/quagga-bootstrap.sh b/pimd/quagga-bootstrap.sh new file mode 100755 index 000000000..1ad9a121b --- /dev/null +++ b/pimd/quagga-bootstrap.sh @@ -0,0 +1,21 @@ +#! /bin/bash +# +# Bootstrap Quagga autotools for pimd. +# +# Run from quagga's top dir as: +# ./pimd/quagga-bootstrap.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +me=`basename $0` +msg () { + echo >&2 $me: $* +} + +if [ -f ./bootstrap.sh ]; then + msg found ./bootstrap.sh from quagga + ./bootstrap.sh +else + msg missing ./bootstrap.sh from quagga + autoreconf -i --force +fi diff --git a/pimd/quagga-build.sh b/pimd/quagga-build.sh new file mode 100755 index 000000000..2ad476d00 --- /dev/null +++ b/pimd/quagga-build.sh @@ -0,0 +1,10 @@ +#! /bin/bash +# +# Build minimum Quagga needed for pimd. +# +# Run from quagga's top dir as: +# ./pimd/quagga-build.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +./pimd/quagga-memtypes.sh && ./pimd/quagga-bootstrap.sh && ./pimd/quagga-configure.sh && make diff --git a/pimd/quagga-configure.sh b/pimd/quagga-configure.sh new file mode 100755 index 000000000..a1cdd587c --- /dev/null +++ b/pimd/quagga-configure.sh @@ -0,0 +1,10 @@ +#! /bin/bash +# +# Configure for minimum Quagga build needed for pimd. +# +# Run from quagga's top dir as: +# . pimd/quagga-configure.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +./configure --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 diff --git a/pimd/quagga-git-add.sh b/pimd/quagga-git-add.sh new file mode 100755 index 000000000..3824e984e --- /dev/null +++ b/pimd/quagga-git-add.sh @@ -0,0 +1,12 @@ +#! /bin/bash +# +# Add to git new files created by qpimd patch +# +# Run from quagga's top dir as: +# ./pimd/quagga-git-add.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +chmod a+rx pimd/*.sh +git add doc/pimd.8 +git add pimd diff --git a/pimd/quagga-memtypes.sh b/pimd/quagga-memtypes.sh new file mode 100755 index 000000000..e86f414b8 --- /dev/null +++ b/pimd/quagga-memtypes.sh @@ -0,0 +1,22 @@ +#! /bin/bash +# +# Check lib/memtypes.h from Quagga +# +# Run from quagga's top dir as: +# ./pimd/quagga-memtypes.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +me=`basename $0` +msg () { + echo >&2 $me: $* +} + +memtypes_h=lib/memtypes.h +if [ -e $memtypes_h ]; then + memtypes_h_size=`ls -s $memtypes_h | cut -d' ' -f1` + if [ "$memtypes_h_size" -lt 1 ]; then + msg WARNING: removing empty file: $memtypes_h -- awk failed? + rm $memtypes_h + fi +fi diff --git a/pimd/savannah-git-clone.sh b/pimd/savannah-git-clone.sh new file mode 100755 index 000000000..68fd608b3 --- /dev/null +++ b/pimd/savannah-git-clone.sh @@ -0,0 +1,16 @@ +#! /bin/bash +# +# Savannah Developer Git Checkout +# +# Delete remote branch qpimd: git push origin :qpimd +# (git push origin :refs/heads/branch_to_delete) +# Delete remote tag v0.139: git push origin :v0.139 +# (git push origin :refs/tags/tag_to_delete) +# Create remote-tracking branch: git checkout -b pim0.142 origin/pim0.142 +# Rename branch qpimd to pim: git branch -m qpimd pim +# Commit changes: git commit -a +# Send changes: git push --all +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +git clone ssh://evertonm@git.sv.gnu.org/srv/git/qpimd.git quagga diff --git a/ports/Makefile b/ports/Makefile index d085d06ec..86f77bd00 100644 --- a/ports/Makefile +++ b/ports/Makefile @@ -54,5 +54,6 @@ post-install: @echo " ripngd 2603/tcp # RIPngd vty"; @echo " ospfd 2604/tcp # OSPFd vty"; @echo " bgpd 2605/tcp # BGPd vty"; + @echo " pimd 2611/tcp # PIMd vty"; .include diff --git a/ports/pkg/DESCR b/ports/pkg/DESCR index 0c8d01b76..aeb1950e2 100644 --- a/ports/pkg/DESCR +++ b/ports/pkg/DESCR @@ -47,6 +47,7 @@ ripd 2602/tcp # RIPd vty ripngd 2603/tcp # RIPngd vty ospfd 2604/tcp # OSPFd vty bgpd 2605/tcp # BGPd vty +pimd 2611/tcp # PIMd vty I recommend you to add upper list to /etc/services. diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 0ce25ca35..35d691bac 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -48,16 +48,16 @@ %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. -%if "%dist" != "fc2" || "%dist" != "fc3" +%if "%dist" == "fc4" || "%dist" == "fc5" %define quagga_buildreqs %{quagga_buildreqs} texi2html %endif # pam_stack is deprecated in FC5 # default to pam_stack, default should be changed later. -%if "%dist" == "fc4" || "%dist" == "fc3" -%define quagga_pam_source quagga.pam.stack -%else +%if "%dist" == "fc5" %define quagga_pam_source quagga.pam +%else +%define quagga_pam_source quagga.pam.stack %endif ############################################################################ @@ -303,6 +303,9 @@ zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %if %{with_isisd} zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif +%if %{with_pimd} +zebra_spec_add_service pimd 2611/tcp "PIMd vty" +%endif for daemon in %daemon_list ; do /sbin/chkconfig --add ${daemon} diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index effe23384..d6ec9147b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -496,6 +496,17 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, break; } + if (IS_ZEBRA_DEBUG_RIB) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); + zlog_debug("%s: %s/%d: nexthop match %p: %s type=%d sel=%d int=%d", + __func__, buf, rn->p.prefixlen, match, + match ? zebra_route_string(match->type) : "", + match ? match->type : -1, + match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED) : -1, + match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_INTERNAL) : -1); + } + /* If there is no selected route or matched route is EGP, go up tree. */ if (! match @@ -524,7 +535,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, return 1; } - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || + match->type == ZEBRA_ROUTE_KERNEL) { resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) @@ -1042,6 +1054,43 @@ rib_match_ipv6 (struct in6_addr *addr) } #endif /* HAVE_IPV6 */ +static void nexthop_dump(struct nexthop *nexthop, + char *type_str_buf, + int type_str_buf_size, + char *addr_str_buf, + int addr_str_buf_size, + char *via_str_buf, + int via_str_buf_size) +{ + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + snprintf(type_str_buf, type_str_buf_size, "ipv4"); + snprintf(addr_str_buf, addr_str_buf_size, "%s", inet_ntoa(nexthop->gate.ipv4)); + snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifindex ? ifindex2ifname(nexthop->ifindex) : ""); + break; + case NEXTHOP_TYPE_IFINDEX: + snprintf(type_str_buf, type_str_buf_size, "connected"); + snprintf(addr_str_buf, addr_str_buf_size, ""); + snprintf(via_str_buf, via_str_buf_size, "%s", ifindex2ifname(nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + snprintf(type_str_buf, type_str_buf_size, "connected"); + snprintf(addr_str_buf, addr_str_buf_size, ""); + snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + snprintf(type_str_buf, type_str_buf_size, "blackhole"); + snprintf(addr_str_buf, addr_str_buf_size, ""); + snprintf(via_str_buf, via_str_buf_size, "Null0"); + break; + default: + snprintf(type_str_buf, type_str_buf_size, "unknown"); + snprintf(addr_str_buf, addr_str_buf_size, ""); + snprintf(via_str_buf, via_str_buf_size, ""); + } +} + #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -1096,10 +1145,27 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active_ipv4 (rib, nexthop, set, rn)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + { + int nh_active = nexthop_active_ipv4 (rib, nexthop, set, rn); + if (IS_ZEBRA_DEBUG_RIB) { + char type_str_buf[100]; + char addr_str_buf[100]; + char via_str_buf[100]; + nexthop_dump(nexthop, + type_str_buf, sizeof(type_str_buf), + addr_str_buf, sizeof(addr_str_buf), + via_str_buf, sizeof(via_str_buf)); + zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d nexthop_active_ipv4=%d", + __func__, rib, nexthop, + nexthop->type, type_str_buf, + addr_str_buf, via_str_buf, nexthop->ifindex, + nh_active); + } + if (nh_active) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: @@ -1190,8 +1256,23 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; - if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) + new_active = nexthop_active_check (rn, rib, nexthop, set); + if (new_active) rib->nexthop_active_num++; + if (IS_ZEBRA_DEBUG_RIB) { + char type_str_buf[100]; + char addr_str_buf[100]; + char via_str_buf[100]; + nexthop_dump(nexthop, + type_str_buf, sizeof(type_str_buf), + addr_str_buf, sizeof(addr_str_buf), + via_str_buf, sizeof(via_str_buf)); + zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d act=%d total_act=%d", + __func__, rib, nexthop, + nexthop->type, type_str_buf, + addr_str_buf, via_str_buf, nexthop->ifindex, + new_active, rib->nexthop_active_num); + } if (prev_active != new_active || prev_index != nexthop->ifindex) SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); diff --git a/zebra/zserv.c b/zebra/zserv.c index afd722a10..261c49a37 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1,5 +1,6 @@ /* Zebra daemon server routine. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * From 596470f2a410fb58109fd880f04362984ffd7c69 Mon Sep 17 00:00:00 2001 From: Leonard Herve Date: Tue, 11 Aug 2009 15:45:26 -0300 Subject: [PATCH 0460/1342] [pim] pim commands added to vtysh --- pimd/pim_cmd.c | 302 +++++++++++++++++++++++----------------------- pimd/pim_main.c | 25 ++++ pimd/pim_mroute.c | 13 ++ pimd/pim_sock.c | 13 ++ vtysh/Makefile.am | 1 + vtysh/vtysh.c | 2 + vtysh/vtysh.h | 4 +- 7 files changed, 207 insertions(+), 153 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index b1349ed3b..339f9da07 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -54,9 +54,9 @@ static struct cmd_node pim_global_node = { 1 /* vtysh ? yes */ }; -static struct cmd_node pim_interface_node = { +static struct cmd_node interface_node = { INTERFACE_NODE, - "%s(config-if-pim)# ", + "%s(config-if)# ", 1 /* vtysh ? yes */ }; @@ -3767,157 +3767,157 @@ DEFUN (test_pim_receive_upcall, void pim_cmd_init() { - install_node(&pim_global_node, pim_global_config_write); /* PIM_NODE */ - install_node(&pim_interface_node, pim_interface_config_write); /* INTERFACE_NODE */ + install_node (&pim_global_node, pim_global_config_write); /* PIM_NODE */ + install_node (&interface_node, pim_interface_config_write); /* INTERFACE_NODE */ - install_element(CONFIG_NODE, &ip_multicast_routing_cmd); - install_element(CONFIG_NODE, &no_ip_multicast_routing_cmd); + install_element (CONFIG_NODE, &ip_multicast_routing_cmd); + install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd); #if 0 - install_element(CONFIG_NODE, &interface_cmd); /* from if.h */ + install_element (CONFIG_NODE, &interface_cmd); /* from if.h */ #else - install_element(CONFIG_NODE, &pim_interface_cmd); + install_element (CONFIG_NODE, &pim_interface_cmd); #endif - install_element(CONFIG_NODE, &no_interface_cmd); /* from if.h */ - - install_default(INTERFACE_NODE); - install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); - install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd); - install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd); - install_element(INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd); - install_element(INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); - install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); - - install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); - install_element(VIEW_NODE, &show_ip_igmp_parameters_cmd); - install_element(VIEW_NODE, &show_ip_igmp_groups_cmd); - install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); - install_element(VIEW_NODE, &show_ip_igmp_sources_cmd); - install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); - install_element(VIEW_NODE, &show_ip_igmp_querier_cmd); - install_element(VIEW_NODE, &show_ip_pim_assert_cmd); - install_element(VIEW_NODE, &show_ip_pim_assert_internal_cmd); - install_element(VIEW_NODE, &show_ip_pim_assert_metric_cmd); - install_element(VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd); - install_element(VIEW_NODE, &show_ip_pim_dr_cmd); - install_element(VIEW_NODE, &show_ip_pim_hello_cmd); - install_element(VIEW_NODE, &show_ip_pim_interface_cmd); - install_element(VIEW_NODE, &show_ip_pim_join_cmd); - install_element(VIEW_NODE, &show_ip_pim_jp_override_interval_cmd); - install_element(VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd); - install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd); - install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd); - install_element(VIEW_NODE, &show_ip_pim_rpf_cmd); - install_element(VIEW_NODE, &show_ip_pim_secondary_cmd); - install_element(VIEW_NODE, &show_ip_pim_upstream_cmd); - install_element(VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd); - install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); - install_element(VIEW_NODE, &show_ip_multicast_cmd); - install_element(VIEW_NODE, &show_ip_mroute_cmd); - install_element(VIEW_NODE, &show_ip_mroute_count_cmd); - install_element(VIEW_NODE, &show_ip_route_cmd); - install_element(VIEW_NODE, &show_debugging_cmd); - - install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); - install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); - install_element(ENABLE_NODE, &clear_ip_pim_interfaces_cmd); - - install_element(ENABLE_NODE, &show_ip_igmp_interface_cmd); - install_element(ENABLE_NODE, &show_ip_igmp_parameters_cmd); - install_element(ENABLE_NODE, &show_ip_igmp_groups_cmd); - install_element(ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd); - install_element(ENABLE_NODE, &show_ip_igmp_sources_cmd); - install_element(ENABLE_NODE, &show_ip_igmp_sources_retransmissions_cmd); - install_element(ENABLE_NODE, &show_ip_igmp_querier_cmd); - install_element(ENABLE_NODE, &show_ip_pim_address_cmd); - install_element(ENABLE_NODE, &show_ip_pim_assert_cmd); - install_element(ENABLE_NODE, &show_ip_pim_assert_internal_cmd); - install_element(ENABLE_NODE, &show_ip_pim_assert_metric_cmd); - install_element(ENABLE_NODE, &show_ip_pim_assert_winner_metric_cmd); - install_element(ENABLE_NODE, &show_ip_pim_dr_cmd); - install_element(ENABLE_NODE, &show_ip_pim_hello_cmd); - install_element(ENABLE_NODE, &show_ip_pim_interface_cmd); - install_element(ENABLE_NODE, &show_ip_pim_join_cmd); - install_element(ENABLE_NODE, &show_ip_pim_jp_override_interval_cmd); - install_element(ENABLE_NODE, &show_ip_pim_lan_prune_delay_cmd); - install_element(ENABLE_NODE, &show_ip_pim_local_membership_cmd); - install_element(ENABLE_NODE, &show_ip_pim_neighbor_cmd); - install_element(ENABLE_NODE, &show_ip_pim_rpf_cmd); - install_element(ENABLE_NODE, &show_ip_pim_secondary_cmd); - install_element(ENABLE_NODE, &show_ip_pim_upstream_cmd); - install_element(ENABLE_NODE, &show_ip_pim_upstream_join_desired_cmd); - install_element(ENABLE_NODE, &show_ip_pim_upstream_rpf_cmd); - install_element(ENABLE_NODE, &show_ip_multicast_cmd); - install_element(ENABLE_NODE, &show_ip_mroute_cmd); - install_element(ENABLE_NODE, &show_ip_mroute_count_cmd); - install_element(ENABLE_NODE, &show_ip_route_cmd); - install_element(ENABLE_NODE, &show_debugging_cmd); - - install_element(ENABLE_NODE, &test_igmp_receive_report_cmd); - install_element(ENABLE_NODE, &test_pim_receive_assert_cmd); - install_element(ENABLE_NODE, &test_pim_receive_hello_cmd); - install_element(ENABLE_NODE, &test_pim_receive_join_cmd); - install_element(ENABLE_NODE, &test_pim_receive_prune_cmd); - install_element(ENABLE_NODE, &test_pim_receive_upcall_cmd); - - install_element(ENABLE_NODE, &debug_igmp_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_cmd); - install_element(ENABLE_NODE, &undebug_igmp_cmd); - install_element(ENABLE_NODE, &debug_igmp_events_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); - install_element(ENABLE_NODE, &undebug_igmp_events_cmd); - install_element(ENABLE_NODE, &debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &undebug_igmp_packets_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &undebug_igmp_trace_cmd); - install_element(ENABLE_NODE, &debug_pim_cmd); - install_element(ENABLE_NODE, &no_debug_pim_cmd); - install_element(ENABLE_NODE, &undebug_pim_cmd); - install_element(ENABLE_NODE, &debug_pim_events_cmd); - install_element(ENABLE_NODE, &no_debug_pim_events_cmd); - install_element(ENABLE_NODE, &undebug_pim_events_cmd); - install_element(ENABLE_NODE, &debug_pim_packets_cmd); - install_element(ENABLE_NODE, &no_debug_pim_packets_cmd); - install_element(ENABLE_NODE, &undebug_pim_packets_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_cmd); - install_element(ENABLE_NODE, &no_debug_pim_trace_cmd); - install_element(ENABLE_NODE, &undebug_pim_trace_cmd); - install_element(ENABLE_NODE, &debug_pim_zebra_cmd); - install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd); - install_element(ENABLE_NODE, &undebug_pim_zebra_cmd); - - install_element(CONFIG_NODE, &debug_igmp_cmd); - install_element(CONFIG_NODE, &no_debug_igmp_cmd); - install_element(CONFIG_NODE, &undebug_igmp_cmd); - install_element(CONFIG_NODE, &debug_igmp_events_cmd); - install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); - install_element(CONFIG_NODE, &undebug_igmp_events_cmd); - install_element(CONFIG_NODE, &debug_igmp_packets_cmd); - install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); - install_element(CONFIG_NODE, &undebug_igmp_packets_cmd); - install_element(CONFIG_NODE, &debug_igmp_trace_cmd); - install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); - install_element(CONFIG_NODE, &undebug_igmp_trace_cmd); - install_element(CONFIG_NODE, &debug_pim_cmd); - install_element(CONFIG_NODE, &no_debug_pim_cmd); - install_element(CONFIG_NODE, &undebug_pim_cmd); - install_element(CONFIG_NODE, &debug_pim_events_cmd); - install_element(CONFIG_NODE, &no_debug_pim_events_cmd); - install_element(CONFIG_NODE, &undebug_pim_events_cmd); - install_element(CONFIG_NODE, &debug_pim_packets_cmd); - install_element(CONFIG_NODE, &no_debug_pim_packets_cmd); - install_element(CONFIG_NODE, &undebug_pim_packets_cmd); - install_element(CONFIG_NODE, &debug_pim_trace_cmd); - install_element(CONFIG_NODE, &no_debug_pim_trace_cmd); - install_element(CONFIG_NODE, &undebug_pim_trace_cmd); - install_element(CONFIG_NODE, &debug_pim_zebra_cmd); - install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd); - install_element(CONFIG_NODE, &undebug_pim_zebra_cmd); + install_element (CONFIG_NODE, &no_interface_cmd); /* from if.h */ + + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_ip_igmp_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd); + install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_igmp_join_cmd); + install_element (INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd); + install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd); + install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); + install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); + + install_element (VIEW_NODE, &show_ip_igmp_interface_cmd); + install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd); + install_element (VIEW_NODE, &show_ip_igmp_groups_cmd); + install_element (VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); + install_element (VIEW_NODE, &show_ip_igmp_sources_cmd); + install_element (VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); + install_element (VIEW_NODE, &show_ip_igmp_querier_cmd); + install_element (VIEW_NODE, &show_ip_pim_assert_cmd); + install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd); + install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd); + install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd); + install_element (VIEW_NODE, &show_ip_pim_dr_cmd); + install_element (VIEW_NODE, &show_ip_pim_hello_cmd); + install_element (VIEW_NODE, &show_ip_pim_interface_cmd); + install_element (VIEW_NODE, &show_ip_pim_join_cmd); + install_element (VIEW_NODE, &show_ip_pim_jp_override_interval_cmd); + install_element (VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd); + install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd); + install_element (VIEW_NODE, &show_ip_pim_neighbor_cmd); + install_element (VIEW_NODE, &show_ip_pim_rpf_cmd); + install_element (VIEW_NODE, &show_ip_pim_secondary_cmd); + install_element (VIEW_NODE, &show_ip_pim_upstream_cmd); + install_element (VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd); + install_element (VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); + install_element (VIEW_NODE, &show_ip_multicast_cmd); + install_element (VIEW_NODE, &show_ip_mroute_cmd); + install_element (VIEW_NODE, &show_ip_mroute_count_cmd); + install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_debugging_cmd); + + install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); + install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); + install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); + + install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_parameters_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_groups_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_sources_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_sources_retransmissions_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_querier_cmd); + install_element (ENABLE_NODE, &show_ip_pim_address_cmd); + install_element (ENABLE_NODE, &show_ip_pim_assert_cmd); + install_element (ENABLE_NODE, &show_ip_pim_assert_internal_cmd); + install_element (ENABLE_NODE, &show_ip_pim_assert_metric_cmd); + install_element (ENABLE_NODE, &show_ip_pim_assert_winner_metric_cmd); + install_element (ENABLE_NODE, &show_ip_pim_dr_cmd); + install_element (ENABLE_NODE, &show_ip_pim_hello_cmd); + install_element (ENABLE_NODE, &show_ip_pim_interface_cmd); + install_element (ENABLE_NODE, &show_ip_pim_join_cmd); + install_element (ENABLE_NODE, &show_ip_pim_jp_override_interval_cmd); + install_element (ENABLE_NODE, &show_ip_pim_lan_prune_delay_cmd); + install_element (ENABLE_NODE, &show_ip_pim_local_membership_cmd); + install_element (ENABLE_NODE, &show_ip_pim_neighbor_cmd); + install_element (ENABLE_NODE, &show_ip_pim_rpf_cmd); + install_element (ENABLE_NODE, &show_ip_pim_secondary_cmd); + install_element (ENABLE_NODE, &show_ip_pim_upstream_cmd); + install_element (ENABLE_NODE, &show_ip_pim_upstream_join_desired_cmd); + install_element (ENABLE_NODE, &show_ip_pim_upstream_rpf_cmd); + install_element (ENABLE_NODE, &show_ip_multicast_cmd); + install_element (ENABLE_NODE, &show_ip_mroute_cmd); + install_element (ENABLE_NODE, &show_ip_mroute_count_cmd); + install_element (ENABLE_NODE, &show_ip_route_cmd); + install_element (ENABLE_NODE, &show_debugging_cmd); + + install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); + install_element (ENABLE_NODE, &test_pim_receive_assert_cmd); + install_element (ENABLE_NODE, &test_pim_receive_hello_cmd); + install_element (ENABLE_NODE, &test_pim_receive_join_cmd); + install_element (ENABLE_NODE, &test_pim_receive_prune_cmd); + install_element (ENABLE_NODE, &test_pim_receive_upcall_cmd); + + install_element (ENABLE_NODE, &debug_igmp_cmd); + install_element (ENABLE_NODE, &no_debug_igmp_cmd); + install_element (ENABLE_NODE, &undebug_igmp_cmd); + install_element (ENABLE_NODE, &debug_igmp_events_cmd); + install_element (ENABLE_NODE, &no_debug_igmp_events_cmd); + install_element (ENABLE_NODE, &undebug_igmp_events_cmd); + install_element (ENABLE_NODE, &debug_igmp_packets_cmd); + install_element (ENABLE_NODE, &no_debug_igmp_packets_cmd); + install_element (ENABLE_NODE, &undebug_igmp_packets_cmd); + install_element (ENABLE_NODE, &debug_igmp_trace_cmd); + install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd); + install_element (ENABLE_NODE, &undebug_igmp_trace_cmd); + install_element (ENABLE_NODE, &debug_pim_cmd); + install_element (ENABLE_NODE, &no_debug_pim_cmd); + install_element (ENABLE_NODE, &undebug_pim_cmd); + install_element (ENABLE_NODE, &debug_pim_events_cmd); + install_element (ENABLE_NODE, &no_debug_pim_events_cmd); + install_element (ENABLE_NODE, &undebug_pim_events_cmd); + install_element (ENABLE_NODE, &debug_pim_packets_cmd); + install_element (ENABLE_NODE, &no_debug_pim_packets_cmd); + install_element (ENABLE_NODE, &undebug_pim_packets_cmd); + install_element (ENABLE_NODE, &debug_pim_trace_cmd); + install_element (ENABLE_NODE, &no_debug_pim_trace_cmd); + install_element (ENABLE_NODE, &undebug_pim_trace_cmd); + install_element (ENABLE_NODE, &debug_pim_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd); + install_element (ENABLE_NODE, &undebug_pim_zebra_cmd); + + install_element (CONFIG_NODE, &debug_igmp_cmd); + install_element (CONFIG_NODE, &no_debug_igmp_cmd); + install_element (CONFIG_NODE, &undebug_igmp_cmd); + install_element (CONFIG_NODE, &debug_igmp_events_cmd); + install_element (CONFIG_NODE, &no_debug_igmp_events_cmd); + install_element (CONFIG_NODE, &undebug_igmp_events_cmd); + install_element (CONFIG_NODE, &debug_igmp_packets_cmd); + install_element (CONFIG_NODE, &no_debug_igmp_packets_cmd); + install_element (CONFIG_NODE, &undebug_igmp_packets_cmd); + install_element (CONFIG_NODE, &debug_igmp_trace_cmd); + install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd); + install_element (CONFIG_NODE, &undebug_igmp_trace_cmd); + install_element (CONFIG_NODE, &debug_pim_cmd); + install_element (CONFIG_NODE, &no_debug_pim_cmd); + install_element (CONFIG_NODE, &undebug_pim_cmd); + install_element (CONFIG_NODE, &debug_pim_events_cmd); + install_element (CONFIG_NODE, &no_debug_pim_events_cmd); + install_element (CONFIG_NODE, &undebug_pim_events_cmd); + install_element (CONFIG_NODE, &debug_pim_packets_cmd); + install_element (CONFIG_NODE, &no_debug_pim_packets_cmd); + install_element (CONFIG_NODE, &undebug_pim_packets_cmd); + install_element (CONFIG_NODE, &debug_pim_trace_cmd); + install_element (CONFIG_NODE, &no_debug_pim_trace_cmd); + install_element (CONFIG_NODE, &undebug_pim_trace_cmd); + install_element (CONFIG_NODE, &debug_pim_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd); + install_element (CONFIG_NODE, &undebug_pim_zebra_cmd); } diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 1206b5514..3cf1869ca 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -23,6 +23,7 @@ #include #include "log.h" +#include "privs.h" #include "version.h" #include #include "command.h" @@ -61,6 +62,29 @@ struct option longopts[] = { { 0 } }; +/* pimd privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_NET_ADMIN, + ZCAP_SYS_ADMIN, + ZCAP_NET_RAW, +}; + +/* pimd privileges to run with */ +struct zebra_privs_t pimd_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) + .user = QUAGGA_USER, + .group = QUAGGA_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_i = 0 +}; + char* progname; const char *pid_file = PATH_PIMD_PID; @@ -170,6 +194,7 @@ int main(int argc, char** argv, char** envp) { /* * Initializations */ + zprivs_init (&pimd_privs); pim_signals_init(); cmd_init(1); vty_init(master); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index f021abaa3..48213b0b4 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -22,6 +22,7 @@ #include #include "log.h" +#include "privs.h" #include "pimd.h" #include "pim_mroute.h" @@ -30,6 +31,9 @@ #include "pim_iface.h" #include "pim_macro.h" +/* GLOBAL VARS */ +extern struct zebra_privs_t pimd_privs; + static void mroute_read_on(void); static int pim_mroute_set(int fd, int enable) @@ -259,7 +263,16 @@ int pim_mroute_socket_enable() if (PIM_MROUTE_IS_ENABLED) return -1; + if ( pimd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("pim_mroute_socket_enable: could not raise privs, %s", + safe_strerror (errno) ); + fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + + if ( pimd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("pim_mroute_socket_enable: could not lower privs, %s", + safe_strerror (errno) ); + if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", errno, strerror(errno)); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index c43cb68e9..9f3464116 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -33,11 +33,15 @@ #include #include "log.h" +#include "privs.h" #include "pimd.h" #include "pim_sock.h" #include "pim_str.h" +/* GLOBAL VARS */ +extern struct zebra_privs_t pimd_privs; + #ifndef MCAST_JOIN_SOURCE_GROUP #define MCAST_JOIN_SOURCE_GROUP 46 struct group_source_req @@ -52,7 +56,16 @@ int pim_socket_raw(int protocol) { int fd; + if ( pimd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("pim_sockek_raw: could not raise privs, %s", + safe_strerror (errno) ); + fd = socket(AF_INET, SOCK_RAW, protocol); + + if ( pimd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("pim_socket_raw: could not lower privs, %s", + safe_strerror (errno) ); + if (fd < 0) { zlog_warn("Could not create raw socket: errno=%d: %s", errno, strerror(errno)); diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 5c325ec26..f9dea2de6 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -25,6 +25,7 @@ vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \ $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \ $(top_srcdir)/babeld/*.c \ + $(top_srcdir)/pimd/pim_cmd.c \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 89b9b257e..a5e29dc91 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -59,6 +59,8 @@ struct vtysh_client { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH}, { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH}, { .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH}, + { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH}, +>>>>>>> [pim] pim commands added to vtysh }; diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 3cc7bafe0..5d513c8da 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -30,9 +30,9 @@ #define VTYSH_BGPD 0x20 #define VTYSH_ISISD 0x40 #define VTYSH_BABELD 0x80 -#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD -#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD +#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD /* vtysh local configuration file. */ #define VTYSH_DEFAULT_CONFIG "vtysh.conf" From e96f0af2679e3c91518f62b3a86d811cafba1adc Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 11 Aug 2009 15:48:02 -0300 Subject: [PATCH 0461/1342] [pim] Log physical interface up/down [pim] Replace strerror with safe_strerror [pim] Fix PIM socket removal from non-PIM interfaces [pim] show ip igmp querier: left-align Querier string [pim] Version up to 0.157 [pim] Recipe to re-sync with Quagga repository [pim] Build vtysh in development script --- pimd/pim_cmd.c | 42 +++++++++++++++++++------------------- pimd/pim_iface.c | 2 +- pimd/pim_igmp.c | 10 ++++----- pimd/pim_igmpv3.c | 2 +- pimd/pim_mroute.c | 20 +++++++++--------- pimd/pim_pim.c | 12 ++++++++--- pimd/pim_sock.c | 28 ++++++++++++------------- pimd/pim_str.c | 2 +- pimd/pim_time.c | 4 ++-- pimd/pim_version.h | 2 +- pimd/pim_zebra.c | 8 +++++++- pimd/pimd.c | 2 +- pimd/quagga-configure.sh | 2 +- pimd/savannah-git-clone.sh | 11 ++++++++++ 14 files changed, 85 insertions(+), 62 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 339f9da07..c845a8954 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1084,7 +1084,7 @@ static void igmp_show_querier(struct vty *vty) pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer); pim_time_timer_to_hhmmss(other_hhmmss, sizeof(other_hhmmss), igmp->t_other_querier_timer); - vty_out(vty, "%-9s %-15s %7s %10d %11s %11s%s", + vty_out(vty, "%-9s %-15s %-7s %10d %11s %11s%s", ifp->name, inet_ntoa(igmp->ifaddr), igmp->t_igmp_query_timer ? "THIS" : "OTHER", @@ -1871,7 +1871,7 @@ static void show_multicast_interfaces(struct vty *vty) ifp->name, pim_ifp->mroute_vif_index, e, - strerror(e), + safe_strerror(e), VTY_NEWLINE); continue; } @@ -2047,7 +2047,7 @@ static void show_mroute_count(struct vty *vty) source_str, group_str, e, - strerror(e), + safe_strerror(e), VTY_NEWLINE); continue; } @@ -2093,7 +2093,7 @@ DEFUN (show_ip_route, result = inet_pton(AF_INET, addr_str, &addr); if (result <= 0) { vty_out(vty, "Bad unicast address %s: errno=%d: %s%s", - addr_str, errno, strerror(errno), VTY_NEWLINE); + addr_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -2265,7 +2265,7 @@ DEFUN (interface_ip_igmp_join, result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", - group_str, errno, strerror(errno), VTY_NEWLINE); + group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -2274,7 +2274,7 @@ DEFUN (interface_ip_igmp_join, result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", - source_str, errno, strerror(errno), VTY_NEWLINE); + source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -2312,7 +2312,7 @@ DEFUN (interface_no_ip_igmp_join, result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", - group_str, errno, strerror(errno), VTY_NEWLINE); + group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -2321,7 +2321,7 @@ DEFUN (interface_no_ip_igmp_join, result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", - source_str, errno, strerror(errno), VTY_NEWLINE); + source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3168,7 +3168,7 @@ DEFUN (test_igmp_receive_report, result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", - grp_str, errno, strerror(errno), VTY_NEWLINE); + grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3204,7 +3204,7 @@ DEFUN (test_igmp_receive_report, result = inet_pton(AF_INET, src_str, src_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", - src_str, errno, strerror(errno), VTY_NEWLINE); + src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } } @@ -3281,7 +3281,7 @@ DEFUN (test_pim_receive_hello, result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", - neigh_str, errno, strerror(errno), VTY_NEWLINE); + neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3314,7 +3314,7 @@ DEFUN (test_pim_receive_hello, result = inet_pton(AF_INET, sec_str, &sec_addr); if (result <= 0) { vty_out(vty, "Bad neighbor secondary address %s: errno=%d: %s%s", - sec_str, errno, strerror(errno), VTY_NEWLINE); + sec_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3407,7 +3407,7 @@ DEFUN (test_pim_receive_assert, result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", - neigh_str, errno, strerror(errno), VTY_NEWLINE); + neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3416,7 +3416,7 @@ DEFUN (test_pim_receive_assert, result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", - group_str, errno, strerror(errno), VTY_NEWLINE); + group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3425,7 +3425,7 @@ DEFUN (test_pim_receive_assert, result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", - source_str, errno, strerror(errno), VTY_NEWLINE); + source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3523,7 +3523,7 @@ static int recv_joinprune(struct vty *vty, result = inet_pton(AF_INET, neigh_dst_str, &neigh_dst_addr); if (result <= 0) { vty_out(vty, "Bad neighbor destination address %s: errno=%d: %s%s", - neigh_dst_str, errno, strerror(errno), VTY_NEWLINE); + neigh_dst_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3532,7 +3532,7 @@ static int recv_joinprune(struct vty *vty, result = inet_pton(AF_INET, neigh_src_str, &neigh_src_addr); if (result <= 0) { vty_out(vty, "Bad neighbor source address %s: errno=%d: %s%s", - neigh_src_str, errno, strerror(errno), VTY_NEWLINE); + neigh_src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3541,7 +3541,7 @@ static int recv_joinprune(struct vty *vty, result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", - group_str, errno, strerror(errno), VTY_NEWLINE); + group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3550,7 +3550,7 @@ static int recv_joinprune(struct vty *vty, result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", - source_str, errno, strerror(errno), VTY_NEWLINE); + source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3740,7 +3740,7 @@ DEFUN (test_pim_receive_upcall, result = inet_pton(AF_INET, group_str, &msg.im_dst); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", - group_str, errno, strerror(errno), VTY_NEWLINE); + group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } @@ -3749,7 +3749,7 @@ DEFUN (test_pim_receive_upcall, result = inet_pton(AF_INET, source_str, &msg.im_src); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", - source_str, errno, strerror(errno), VTY_NEWLINE); + source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index b4fbaec59..b3df0189c 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1020,7 +1020,7 @@ int pim_if_igmp_join_del(struct interface *ifp, pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s", __PRETTY_FUNCTION__, - ij->sock_fd, group_str, source_str, ifp->name, e, strerror(e)); + ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e)); /* warning only */ } listnode_delete(pim_ifp->igmp_join_list, ij); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index e38ac96a7..b8f25814f 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -65,7 +65,7 @@ static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_optio else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), - PIM_ALL_ROUTERS, errno, strerror(errno)); + PIM_ALL_ROUTERS, errno, safe_strerror(errno)); } } @@ -80,7 +80,7 @@ static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_optio else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), - PIM_ALL_SYSTEMS, errno, strerror(errno)); + PIM_ALL_SYSTEMS, errno, safe_strerror(errno)); } if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) { @@ -91,7 +91,7 @@ static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_optio else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), - PIM_ALL_IGMP_ROUTERS, errno, strerror(errno)); + PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno)); } if (!join) { @@ -949,7 +949,7 @@ static int pim_igmp_read(struct thread *t) &ifindex); if (len < 0) { zlog_warn("Failure receiving IP IGMP packet on fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); goto done; } @@ -1023,7 +1023,7 @@ static void sock_close(struct igmp_sock *igmp) if (close(igmp->fd)) { zlog_err("Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name, - errno, strerror(errno)); + errno, safe_strerror(errno)); } if (PIM_DEBUG_IGMP_TRACE) { diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index f9fa123f1..3ff04c917 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1679,7 +1679,7 @@ void pim_igmp_send_membership_query(struct igmp_group *group, zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%d: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, - e, strerror(e)); + e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%d: sent=%d", diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 48213b0b4..c76ba525b 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -47,7 +47,7 @@ static int pim_mroute_set(int fd, int enable) int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, - fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, strerror(e)); + fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e)); errno = e; return -1; } @@ -209,7 +209,7 @@ static int mroute_read_msg(int fd) rd = read(fd, buf, sizeof(buf)); if (rd < 0) { zlog_warn("%s: failure reading fd=%d: errno=%d: %s", - __PRETTY_FUNCTION__, fd, errno, strerror(errno)); + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); return -2; } @@ -275,13 +275,13 @@ int pim_mroute_socket_enable() if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", - errno, strerror(errno)); + errno, safe_strerror(errno)); return -2; } if (pim_mroute_set(fd, 1)) { zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return -3; } @@ -302,13 +302,13 @@ int pim_mroute_socket_disable() if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s", - qpim_mroute_socket_fd, errno, strerror(errno)); + qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -2; } if (close(qpim_mroute_socket_fd)) { zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", - qpim_mroute_socket_fd, errno, strerror(errno)); + qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -3; } @@ -359,7 +359,7 @@ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, ifaddr_str, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } @@ -387,7 +387,7 @@ int pim_mroute_del_vif(int vif_index) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } @@ -412,7 +412,7 @@ int pim_mroute_add(struct mfcctl *mc) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } @@ -436,7 +436,7 @@ int pim_mroute_del(struct mfcctl *mc) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index bbf67763c..dd78b904c 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -74,7 +74,7 @@ static void sock_close(struct interface *ifp) if (close(pim_ifp->pim_sock_fd)) { zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s", pim_ifp->pim_sock_fd, ifp->name, - errno, strerror(errno)); + errno, safe_strerror(errno)); } pim_ifp->pim_sock_fd = -1; @@ -91,6 +91,12 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message) zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name, delete_message); + if (!ifp->info) { + zlog_err("%s: %s: but PIM not enabled on interface %s (!)", + __PRETTY_FUNCTION__, delete_message, ifp->name); + return; + } + /* RFC 4601: 4.3.1. Sending Hello Messages @@ -266,7 +272,7 @@ static int pim_sock_read(struct thread *t) &ifindex); if (len < 0) { zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); goto done; } @@ -459,7 +465,7 @@ int pim_msg_send(int fd, zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, fd, pim_msg_size, - e, strerror(e)); + e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%d", diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 9f3464116..8e6c559a8 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -68,7 +68,7 @@ int pim_socket_raw(int protocol) if (fd < 0) { zlog_warn("Could not create raw socket: errno=%d: %s", - errno, strerror(errno)); + errno, safe_strerror(errno)); return PIM_SOCK_ERR_SOCKET; } @@ -82,7 +82,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) fd = pim_socket_raw(protocol); if (fd < 0) { zlog_warn("Could not create multicast socket: errno=%d: %s", - errno, strerror(errno)); + errno, safe_strerror(errno)); return PIM_SOCK_ERR_SOCKET; } @@ -93,14 +93,14 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) int opt = 1; if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); } #else zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", @@ -120,7 +120,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) ra[3] = 0; if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) { zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_RA; } @@ -131,7 +131,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse))) { zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_REUSE; } @@ -143,7 +143,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &ttl, sizeof(ttl))) { zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", - MTTL, fd, errno, strerror(errno)); + MTTL, fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_TTL; } @@ -153,7 +153,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) (void *) &loop, sizeof(loop))) { zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", loop ? "enable" : "disable", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_LOOP; } @@ -161,7 +161,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *) &ifaddr, sizeof(ifaddr))) { zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_IFACE; } @@ -172,14 +172,14 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_NONBLOCK_GETFL; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_NONBLOCK_SETFL; } @@ -218,7 +218,7 @@ int pim_socket_join(int fd, struct in_addr group, sprintf(ifaddr_str, ""); zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s", - fd, group_str, ifaddr_str, errno, strerror(errno)); + fd, group_str, ifaddr_str, errno, safe_strerror(errno)); return ret; } @@ -268,7 +268,7 @@ int pim_socket_join_source(int fd, int ifindex, zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", __PRETTY_FUNCTION__, fd, group_str, source_str, ifindex, ifname, - e, strerror(e)); + e, safe_strerror(e)); return -1; } @@ -352,7 +352,7 @@ int pim_socket_mcastloop_get(int fd) &loop, &loop_len)) { int e = errno; zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); errno = e; return PIM_SOCK_ERR_LOOP; } diff --git a/pimd/pim_str.c b/pimd/pim_str.c index 7dce7a859..af5a184d2 100644 --- a/pimd/pim_str.c +++ b/pimd/pim_str.c @@ -37,7 +37,7 @@ void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_ if (!inet_ntop(AF_INET, &addr, buf, buf_size)) { int e = errno; zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s", - buf_size, e, strerror(e)); + buf_size, e, safe_strerror(e)); if (onfail) snprintf(buf, buf_size, "%s", onfail); } diff --git a/pimd/pim_time.c b/pimd/pim_time.c index a837e5b00..63861e5ce 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -49,7 +49,7 @@ int64_t pim_time_monotonic_sec() if (pim_gettime(CLOCK_MONOTONIC, &now_tv)) { zlog_err("%s: gettime(CLOCK_MONOTONIC) failure: errno=%d: %s", __PRETTY_FUNCTION__, - errno, strerror(errno)); + errno, safe_strerror(errno)); return -1; } @@ -68,7 +68,7 @@ int64_t pim_time_monotonic_dsec() if (pim_gettime(CLOCK_MONOTONIC, &now_tv)) { zlog_err("%s: gettime(CLOCK_MONOTONIC) failure: errno=%d: %s", __PRETTY_FUNCTION__, - errno, strerror(errno)); + errno, safe_strerror(errno)); return -1; } diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 796db6638..fc5bca2fa 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.155" +#define PIMD_VERSION_STR "0.157" const char * const PIMD_VERSION; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index d03cc5401..56e4dba16 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -127,6 +127,8 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, if (!ifp) return 0; + zlog_info("INTERFACE UP: %s", ifp->name); + if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, @@ -157,6 +159,8 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, if (!ifp) return 0; + zlog_info("INTERFACE DOWN: %s", ifp->name); + if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, @@ -175,7 +179,9 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, pim_sock_delete() closes the socket, stops read and timer threads, and kills all neighbors. */ - pim_sock_delete(ifp, "link down"); + if (ifp->info) { + pim_sock_delete(ifp, "link down"); + } } return 0; diff --git a/pimd/pimd.c b/pimd/pimd.c index cbcd06480..f255a28f8 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -72,7 +72,7 @@ void pim_init() if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, - PIM_ALL_PIM_ROUTERS, errno, strerror(errno)); + PIM_ALL_PIM_ROUTERS, errno, safe_strerror(errno)); zassert(0); return; } diff --git a/pimd/quagga-configure.sh b/pimd/quagga-configure.sh index a1cdd587c..45d7be086 100755 --- a/pimd/quagga-configure.sh +++ b/pimd/quagga-configure.sh @@ -7,4 +7,4 @@ # # $QuaggaId: $Format:%an, %ai, %h$ $ -./configure --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 +./configure --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 --enable-vtysh diff --git a/pimd/savannah-git-clone.sh b/pimd/savannah-git-clone.sh index 68fd608b3..1aad51bb2 100755 --- a/pimd/savannah-git-clone.sh +++ b/pimd/savannah-git-clone.sh @@ -11,6 +11,17 @@ # Commit changes: git commit -a # Send changes: git push --all # +# Recipe to re-sync with Quagga repository: +# git clone ssh://evertonm@git.sv.gnu.org/srv/git/qpimd.git quagga +# cd quagga +# git checkout master +# git pull git://code.quagga.net/quagga.git master +# git checkout -b pim origin/pim +# git rebase master pim +# # Test, then push back into Savannah repository: +# git push origin :pim ;# delete remote branch pim +# git push --all +# # $QuaggaId: $Format:%an, %ai, %h$ $ git clone ssh://evertonm@git.sv.gnu.org/srv/git/qpimd.git quagga From 236b01556122fba479118797163c44849073ff46 Mon Sep 17 00:00:00 2001 From: Leonard Herve Date: Tue, 11 Aug 2009 15:51:52 -0300 Subject: [PATCH 0462/1342] [pim] igmpv3: specific query interval set to 1 second (RFC 3376 8.8.) [pim] pim messages: encoded source address format with Sparse bit=1 (RFC 4601 4.9.1.) [pim] and Mask Len MUST be equal to 32 [pim] dr election: new traces [pim] fix triggered_hello_delay_msec randomization --- pimd/pim_iface.c | 7 ++++--- pimd/pim_iface.h | 11 ++++++----- pimd/pim_igmp.h | 9 ++++++--- pimd/pim_igmpv3.c | 18 +++++++++--------- pimd/pim_join.c | 26 ++++++++++++++++++++++++++ pimd/pim_msg.c | 2 +- pimd/pim_neighbor.c | 34 +++++++++++++++++++++++++++------- pimd/pim_pim.c | 2 +- 8 files changed, 80 insertions(+), 29 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index b3df0189c..009f87c17 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -85,9 +85,10 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->options = 0; pim_ifp->mroute_vif_index = -1; - pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; - pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; - pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; + pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; + pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; + pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; + pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC; /* RFC 3376: 8.3. Query Response Interval diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 6ce866bad..bc99aafba 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -57,11 +57,12 @@ struct pim_interface { int mroute_vif_index; struct in_addr primary_address; /* remember addr to detect change */ - int igmp_default_robustness_variable; /* IGMPv3 QRV */ - int igmp_default_query_interval; /* IGMPv3 secs between general queries */ - int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs */ - struct list *igmp_socket_list; /* list of struct igmp_sock */ - struct list *igmp_join_list; /* list of struct igmp_join */ + int igmp_default_robustness_variable; /* IGMPv3 QRV */ + int igmp_default_query_interval; /* IGMPv3 secs between general queries */ + int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */ + int igmp_specific_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for specific queries */ + struct list *igmp_socket_list; /* list of struct igmp_sock */ + struct list *igmp_join_list; /* list of struct igmp_join */ int pim_sock_fd; /* PIM socket file descriptor */ struct thread *t_pim_sock_read; /* thread for reading PIM socket */ diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index 656147f27..95e60bf21 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -55,13 +55,16 @@ #define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8) /* RFC 3376: 8.1. Robustness Variable - Default: 2 */ -#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2) +#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2) /* RFC 3376: 8.2. Query Interval - Default: 125 seconds */ -#define IGMP_GENERAL_QUERY_INTERVAL (125) +#define IGMP_GENERAL_QUERY_INTERVAL (125) /* RFC 3376: 8.3. Query Response Interval - Default: 100 deciseconds */ -#define IGMP_QUERY_MAX_RESPONSE_TIME_DSEC (100) +#define IGMP_QUERY_MAX_RESPONSE_TIME_DSEC (100) + +/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */ +#define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10) struct igmp_join { struct in_addr group_addr; diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 3ff04c917..3d3ee7ac8 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1006,7 +1006,7 @@ static void group_retransmit_group(struct igmp_group *group) pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; - lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* @@ -1042,7 +1042,7 @@ static void group_retransmit_group(struct igmp_group *group) 0 /* num_sources_tosend */, group->group_addr /* dst_addr */, group->group_addr /* group_addr */, - pim_ifp->igmp_query_max_response_time_dsec, + pim_ifp->igmp_specific_query_max_response_time_dsec, s_flag, igmp->querier_robustness_variable, igmp->querier_query_interval); @@ -1090,7 +1090,7 @@ static int group_retransmit_sources(struct igmp_group *group, pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; - lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* Scan all group sources */ @@ -1163,7 +1163,7 @@ static int group_retransmit_sources(struct igmp_group *group, num_sources_tosend1, group->group_addr, group->group_addr, - pim_ifp->igmp_query_max_response_time_dsec, + pim_ifp->igmp_specific_query_max_response_time_dsec, 1 /* s_flag */, igmp->querier_robustness_variable, igmp->querier_query_interval); @@ -1205,7 +1205,7 @@ static int group_retransmit_sources(struct igmp_group *group, num_sources_tosend2, group->group_addr, group->group_addr, - pim_ifp->igmp_query_max_response_time_dsec, + pim_ifp->igmp_specific_query_max_response_time_dsec, 0 /* s_flag */, igmp->querier_robustness_variable, igmp->querier_query_interval); @@ -1290,7 +1290,7 @@ static void group_retransmit_timer_on(struct igmp_group *group) igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; - lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; @@ -1359,7 +1359,7 @@ static void source_query_send_by_flag(struct igmp_group *group, pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; - lmqi_msec = 100 * pim_ifp->igmp_query_max_response_time_dsec; + lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* @@ -1519,7 +1519,7 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) pim_ifp = ifp->info; ifname = ifp->name; - lmqi_dsec = pim_ifp->igmp_query_max_response_time_dsec; + lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; lmqc = igmp->querier_robustness_variable; lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ @@ -1554,7 +1554,7 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) pim_ifp = ifp->info; ifname = ifp->name; - lmqi_dsec = pim_ifp->igmp_query_max_response_time_dsec; + lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; lmqc = igmp->querier_robustness_variable; lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index ce4ec4e6c..6b46759a6 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -239,6 +239,19 @@ int pim_joinprune_recv(struct interface *ifp, if (addr_offset < 1) { return -7; } + + /* + RFC 4601: 4.9.1 Encoded Source and Group Address Formats + + Encoded-Source Address + (...) + The mask length MUST be equal to the mask length in bits for the + given Address Family and Encoding Type (32 for IPv4 native and + 128 for IPv6 native). A router SHOULD ignore any messages + received with any other mask length. + */ + if (msg_source_addr.prefixlen!=32) return; + buf += addr_offset; recv_join(ifp, neigh, msg_holdtime, @@ -257,6 +270,19 @@ int pim_joinprune_recv(struct interface *ifp, if (addr_offset < 1) { return -8; } + + /* + RFC 4601: 4.9.1 Encoded Source and Group Address Formats + + Encoded-Source Address + (...) + The mask length MUST be equal to the mask length in bits for the + given Address Family and Encoding Type (32 for IPv4 native and + 128 for IPv6 native). A router SHOULD ignore any messages + received with any other mask length. + */ + if (msg_source_addr.prefixlen!=32) return; + buf += addr_offset; recv_prune(ifp, neigh, msg_holdtime, diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 76f78f8ae..1105eacae 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -98,7 +98,7 @@ char *pim_msg_addr_encode_ipv4_source(char *buf, buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ - buf[2] = '\0'; /* reserved */ + buf[2] = 4; /* reserved = 0 | S bit = 1 | W bit = 0 | R bit = 0 */ buf[3] = 32; /* mask len */ *(struct in_addr *)(buf + 4) = addr; diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 67aa9d088..b4112edf1 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -46,6 +46,10 @@ static void dr_election_by_addr(struct interface *ifp) pim_ifp->pim_dr_addr = pim_ifp->primary_address; + zlog_info("%s on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) { pim_ifp->pim_dr_addr = neigh->source_addr; @@ -66,7 +70,15 @@ static void dr_election_by_pri(struct interface *ifp) pim_ifp->pim_dr_addr = pim_ifp->primary_address; dr_pri = pim_ifp->pim_dr_priority; + zlog_info("%s: dr pri %u on interface %s", + __PRETTY_FUNCTION__, + dr_pri, ifp->name); + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { + zlog_info("%s: neigh pri %u addr %x if dr addr %x", + __PRETTY_FUNCTION__, + neigh->dr_priority, ntohl(neigh->source_addr.s_addr) , ntohl(pim_ifp->pim_dr_addr.s_addr) ); if ( (neigh->dr_priority > dr_pri) || ( @@ -91,6 +103,8 @@ void pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr old_dr_addr; + char dr_old_str[100]; + char dr_new_str[100]; pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_count; @@ -104,16 +118,22 @@ void pim_if_dr_election(struct interface *ifp) dr_election_by_pri(ifp); } - /* DR changed ? */ - if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { - char dr_old_str[100]; - char dr_new_str[100]; - pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); - pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); - zlog_info("%s: DR was %s now is %s on interface %s", + pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); + pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); + zlog_info("%s: DR was %s now is %s on interface %s", __PRETTY_FUNCTION__, dr_old_str, dr_new_str, ifp->name); + /* DR changed ? */ + if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { + /* char dr_old_str[100]; */ + /* char dr_new_str[100]; */ + /* pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); */ + /* pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); */ + /* zlog_info("%s: DR was %s now is %s on interface %s", */ + /* __PRETTY_FUNCTION__, */ + /* dr_old_str, dr_new_str, ifp->name); */ + pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index dd78b904c..9b6dc3592 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -674,7 +674,7 @@ void pim_hello_restart_triggered(struct interface *ifp) THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer, on_pim_hello_send, - ifp, triggered_hello_delay_msec); + ifp, random_msec); } int pim_sock_add(struct interface *ifp) From d12beab1b9ce09c50672adb3c980e64ccd11edb4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 12 Aug 2009 10:52:22 -0300 Subject: [PATCH 0463/1342] [pim] Move encoded source address length check to pim_parse_addr_source --- pimd/pim_igmp.c | 2 +- pimd/pim_join.c | 24 ------------------------ pimd/pim_tlv.c | 20 +++++++++++++++++++- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index b8f25814f..82db37f6b 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -392,7 +392,7 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, /* this is a general query */ /* log that general query should have the s_flag set */ - zlog_warn("General IGMP query v%d from %s on %s: Router-Side Processing flag is clear", + zlog_warn("General IGMP query v%d from %s on %s: Suppress Router-Side Processing flag is clear", query_version, from_str, ifp->name); } else { diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 6b46759a6..aa3aa7898 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -240,18 +240,6 @@ int pim_joinprune_recv(struct interface *ifp, return -7; } - /* - RFC 4601: 4.9.1 Encoded Source and Group Address Formats - - Encoded-Source Address - (...) - The mask length MUST be equal to the mask length in bits for the - given Address Family and Encoding Type (32 for IPv4 native and - 128 for IPv6 native). A router SHOULD ignore any messages - received with any other mask length. - */ - if (msg_source_addr.prefixlen!=32) return; - buf += addr_offset; recv_join(ifp, neigh, msg_holdtime, @@ -271,18 +259,6 @@ int pim_joinprune_recv(struct interface *ifp, return -8; } - /* - RFC 4601: 4.9.1 Encoded Source and Group Address Formats - - Encoded-Source Address - (...) - The mask length MUST be equal to the mask length in bits for the - given Address Family and Encoding Type (32 for IPv4 native and - 128 for IPv6 native). A router SHOULD ignore any messages - received with any other mask length. - */ - if (msg_source_addr.prefixlen!=32) return; - buf += addr_offset; recv_prune(ifp, neigh, msg_holdtime, diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index c578a70d7..fc48c8883 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -559,6 +559,24 @@ int pim_parse_addr_source(const char *ifname, p->u.prefix4 = *(const struct in_addr *) addr; p->prefixlen = mask_len; + /* + RFC 4601: 4.9.1 Encoded Source and Group Address Formats + + Encoded-Source Address + + The mask length MUST be equal to the mask length in bits for + the given Address Family and Encoding Type (32 for IPv4 native + and 128 for IPv6 native). A router SHOULD ignore any messages + received with any other mask length. + */ + if (p->prefixlen != 32) { + char src_str[100]; + pim_inet4_dump("", p->u.prefix4, src_str, sizeof(src_str)); + zlog_warn("%s: IPv4 bad source address mask: %s/%d", + __PRETTY_FUNCTION__, src_str, p->prefixlen); + return -4; + } + addr += sizeof(struct in_addr); break; @@ -569,7 +587,7 @@ int pim_parse_addr_source(const char *ifname, zlog_warn("%s: unknown source address encoding family=%d from %s on %s", __PRETTY_FUNCTION__, family, src_str, ifname); - return -4; + return -5; } } From 613938d48abb863660691641a5761f10402cf3f3 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 13 Aug 2009 15:39:31 -0300 Subject: [PATCH 0464/1342] [pim] RPF cache refresh statistics --- pimd/pim_cmd.c | 30 +++++++++++++++++++++--------- pimd/pim_zebra.c | 10 +++++++++- pimd/pimd.c | 2 ++ pimd/pimd.h | 2 ++ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index c845a8954..df6897e36 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1022,16 +1022,32 @@ static void pim_show_upstream_rpf(struct vty *vty) } } +static void show_rpf_refresh_stats(struct vty *vty) +{ + vty_out(vty, + "RPF Cache Refresh Delay: %ld msecs%s" + "RPF Cache Refresh Timer: %ld msecs%s" + "RPF Cache Refresh Requests: %lld%s" + "RPF Cache Refresh Events: %lld%s", + qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE, + pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE, + qpim_rpf_cache_refresh_requests, VTY_NEWLINE, + qpim_rpf_cache_refresh_events, VTY_NEWLINE); +} + static void pim_show_rpf(struct vty *vty) { struct listnode *up_node; struct pim_upstream *up; + show_rpf_refresh_stats(vty); + + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "Source Group RpfIface RpfAddress RibNextHop Metric Pref%s", VTY_NEWLINE); - for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { char src_str[100]; char grp_str[100]; @@ -1847,7 +1863,7 @@ static void show_multicast_interfaces(struct vty *vty) vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, "Interface Address ifIndex VifIndex PktsIn PktsOut BytesIn BytesOut%s", + vty_out(vty, "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { @@ -1878,7 +1894,7 @@ static void show_multicast_interfaces(struct vty *vty) ifaddr = pim_ifp->primary_address; - vty_out(vty, "%-9s %-15s %7d %8d %6lu %7lu %7lu %8lu%s", + vty_out(vty, "%-9s %-15s %3d %3d %7lu %7lu %10lu %10lu%s", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, @@ -1934,12 +1950,8 @@ DEFUN (show_ip_multicast, VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, "RPF Cache Refresh Delay: %ld msecs%s", - qpim_rpf_cache_refresh_delay_msec, - VTY_NEWLINE); - vty_out(vty, "RPF Cache Refresh Timer: %ld msecs%s", - pim_time_timer_remain_msec(qpim_rpf_cache_refresher), - VTY_NEWLINE); + + show_rpf_refresh_stats(vty); show_multicast_interfaces(vty); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 56e4dba16..9764532b5 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -447,13 +447,21 @@ static int on_rpf_cache_refresh(struct thread *t) /* update kernel multicast forwarding cache (MFC) */ scan_oil(); + ++qpim_rpf_cache_refresh_events; + return 0; } static void sched_rpf_cache_refresh() { - if (qpim_rpf_cache_refresher) + ++qpim_rpf_cache_refresh_requests; + + if (qpim_rpf_cache_refresher) { + /* Refresh timer is already running */ return; + } + + /* Start refresh timer */ if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: triggering %ld msec timer", diff --git a/pimd/pimd.c b/pimd/pimd.c index f255a28f8..e8afe779d 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -54,6 +54,8 @@ struct zclient *qpim_zclient_lookup = 0; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec = 10000; struct thread *qpim_rpf_cache_refresher = 0; +int64_t qpim_rpf_cache_refresh_requests = 0; +int64_t qpim_rpf_cache_refresh_events = 0; struct in_addr qpim_inaddr_any; static void pim_free() diff --git a/pimd/pimd.h b/pimd/pimd.h index 10f8518a0..aaf5faaed 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -80,6 +80,8 @@ struct zclient *qpim_zclient_lookup; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec; struct thread *qpim_rpf_cache_refresher; +int64_t qpim_rpf_cache_refresh_requests; +int64_t qpim_rpf_cache_refresh_events; struct in_addr qpim_inaddr_any; #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) From df4044b2cbe0015d06d25de25e640fca231243dd Mon Sep 17 00:00:00 2001 From: Leonard Herve Date: Fri, 14 Aug 2009 10:38:52 +0200 Subject: [PATCH 0465/1342] Router Alert option for IGMP packets but not for PIM packets --- pimd/pim_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 8e6c559a8..00fc8edab 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -111,8 +111,8 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) } - /* Set router alert (RFC 2113) */ - { + /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. Message Formats)*/ + if (protocol == IPPROTO_IGMP) { char ra[4]; ra[0] = 148; ra[1] = 4; From 942b0fdcc18c3841c6781f6a3f36aa47a604ba1f Mon Sep 17 00:00:00 2001 From: Leonard Herve Date: Fri, 14 Aug 2009 15:49:06 +0200 Subject: [PATCH 0466/1342] [pim] Correction for cross-compilation error with this syntax --- pimd/pim_igmp.c | 6 ++++-- pimd/pim_igmpv3.c | 29 ++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 82db37f6b..a0a4aa815 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -286,6 +286,7 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, struct in_addr group_addr; uint16_t recv_checksum; uint16_t checksum; + int i; group_addr = *(struct in_addr *)(igmp_msg + 4); @@ -419,7 +420,7 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, /* Scan sources in query and lower their timers to LMQT */ struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET); - for (int i = 0; i < recv_num_sources; ++i) { + for (i = 0; i < recv_num_sources; ++i) { struct in_addr src_addr = sources[i]; struct igmp_source *src = igmp_find_source_by_addr(group, src_addr); if (src) { @@ -451,6 +452,7 @@ static int igmp_v3_report(struct igmp_sock *igmp, uint8_t *group_record; uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len; struct interface *ifp = igmp->interface; + int i; if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) { zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d", @@ -485,7 +487,7 @@ static int igmp_v3_report(struct igmp_sock *igmp, group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; /* Scan groups */ - for (int i = 0; i < num_groups; ++i) { + for (i = 0; i < num_groups; ++i) { struct in_addr rec_group; uint8_t *sources; uint8_t *src; diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 3d3ee7ac8..7e76f4427 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -531,6 +531,7 @@ static void allow(struct igmp_sock *igmp, struct in_addr from, struct interface *ifp = igmp->interface; struct pim_interface *pim_ifp; struct igmp_group *group; + int i; pim_ifp = ifp->info; @@ -541,7 +542,7 @@ static void allow(struct igmp_sock *igmp, struct in_addr from, } /* scan received sources */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -580,6 +581,8 @@ void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, static void isex_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { + int i; + /* EXCLUDE mode */ zassert(group->group_filtermode_isexcl); @@ -587,7 +590,7 @@ static void isex_excl(struct igmp_group *group, source_mark_delete_flag(group->group_source_list); /* scan received sources (A) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -621,6 +624,8 @@ static void isex_excl(struct igmp_group *group, static void isex_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { + int i; + /* INCLUDE mode */ zassert(!group->group_filtermode_isexcl); @@ -628,7 +633,7 @@ static void isex_incl(struct igmp_group *group, source_mark_delete_flag(group->group_source_list); /* scan received sources (B) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -702,12 +707,13 @@ static void toin_incl(struct igmp_group *group, { struct igmp_sock *igmp = group->group_igmp_sock; int num_sources_tosend = listcount(group->group_source_list); + int i; /* Set SEND flag for all known sources (A) */ source_mark_send_flag(group->group_source_list); /* Scan received sources (B) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -745,12 +751,13 @@ static void toin_excl(struct igmp_group *group, { struct igmp_sock *igmp = group->group_igmp_sock; int num_sources_tosend; + int i; /* Set SEND flag for X (sources with timer > 0) */ num_sources_tosend = source_mark_send_flag_by_timer(group->group_source_list); /* Scan received sources (A) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -821,6 +828,7 @@ static void toex_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; + int i; zassert(!group->group_filtermode_isexcl); @@ -831,7 +839,7 @@ static void toex_incl(struct igmp_group *group, source_clear_send_flag(group->group_source_list); /* Scan received sources (B) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -878,6 +886,7 @@ static void toex_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; + int i; /* set DELETE flag for all known sources (X,Y) */ source_mark_delete_flag(group->group_source_list); @@ -886,7 +895,7 @@ static void toex_excl(struct igmp_group *group, source_clear_send_flag(group->group_source_list); /* scan received sources (A) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -1392,12 +1401,13 @@ static void block_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; + int i; /* 1. clear off SEND flag from all known sources (X,Y) */ source_clear_send_flag(group->group_source_list); /* 2. scan received sources (A) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; @@ -1438,12 +1448,13 @@ static void block_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; + int i; /* 1. clear off SEND flag from all known sources (B) */ source_clear_send_flag(group->group_source_list); /* 2. scan received sources (A) */ - for (int i = 0; i < num_sources; ++i) { + for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; From bcc4abe09d3faa9b392be2d46e3f6a29b75e46d9 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 17 Aug 2009 18:18:59 -0300 Subject: [PATCH 0467/1342] [pim] More RPF cache refresh statistics --- pimd/pim_cmd.c | 25 +++++++++++++++---------- pimd/pim_zebra.c | 1 + pimd/pimd.c | 1 + pimd/pimd.h | 1 + 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index df6897e36..ea396bcfc 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1022,25 +1022,32 @@ static void pim_show_upstream_rpf(struct vty *vty) } } -static void show_rpf_refresh_stats(struct vty *vty) +static void show_rpf_refresh_stats(struct vty *vty, time_t now) { + char refresh_uptime[10]; + + pim_time_uptime(refresh_uptime, sizeof(refresh_uptime), now - qpim_rpf_cache_refresh_last); + vty_out(vty, "RPF Cache Refresh Delay: %ld msecs%s" "RPF Cache Refresh Timer: %ld msecs%s" "RPF Cache Refresh Requests: %lld%s" - "RPF Cache Refresh Events: %lld%s", + "RPF Cache Refresh Events: %lld%s" + "RPF Cache Refresh Last: %s%s", qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE, pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE, qpim_rpf_cache_refresh_requests, VTY_NEWLINE, - qpim_rpf_cache_refresh_events, VTY_NEWLINE); + qpim_rpf_cache_refresh_events, VTY_NEWLINE, + refresh_uptime, VTY_NEWLINE); } static void pim_show_rpf(struct vty *vty) { struct listnode *up_node; struct pim_upstream *up; + time_t now = pim_time_monotonic_sec(); - show_rpf_refresh_stats(vty); + show_rpf_refresh_stats(vty, now); vty_out(vty, "%s", VTY_NEWLINE); @@ -1079,9 +1086,7 @@ static void igmp_show_querier(struct vty *vty) { struct listnode *node; struct interface *ifp; - time_t now; - - now = pim_time_monotonic_sec(); + time_t now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Querier StartCount Query-Timer Other-Timer%s", VTY_NEWLINE); @@ -1914,15 +1919,15 @@ DEFUN (show_ip_multicast, IP_STR "Multicast global information\n") { + time_t now = pim_time_monotonic_sec(); + if (PIM_MROUTE_IS_ENABLED) { - time_t now; char uptime[10]; vty_out(vty, "Mroute socket descriptor: %d%s", qpim_mroute_socket_fd, VTY_NEWLINE); - now = pim_time_monotonic_sec(); pim_time_uptime(uptime, sizeof(uptime), now - qpim_mroute_socket_creation); vty_out(vty, "Mroute socket uptime: %s%s", uptime, @@ -1951,7 +1956,7 @@ DEFUN (show_ip_multicast, vty_out(vty, "%s", VTY_NEWLINE); - show_rpf_refresh_stats(vty); + show_rpf_refresh_stats(vty, now); show_multicast_interfaces(vty); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 9764532b5..3530434dd 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -447,6 +447,7 @@ static int on_rpf_cache_refresh(struct thread *t) /* update kernel multicast forwarding cache (MFC) */ scan_oil(); + qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; return 0; diff --git a/pimd/pimd.c b/pimd/pimd.c index e8afe779d..f1a084f1a 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -56,6 +56,7 @@ long qpim_rpf_cache_refresh_delay_msec = 10000; struct thread *qpim_rpf_cache_refresher = 0; int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_events = 0; +int64_t qpim_rpf_cache_refresh_last = 0; struct in_addr qpim_inaddr_any; static void pim_free() diff --git a/pimd/pimd.h b/pimd/pimd.h index aaf5faaed..6ee91e7ff 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -82,6 +82,7 @@ long qpim_rpf_cache_refresh_delay_msec; struct thread *qpim_rpf_cache_refresher; int64_t qpim_rpf_cache_refresh_requests; int64_t qpim_rpf_cache_refresh_events; +int64_t qpim_rpf_cache_refresh_last; struct in_addr qpim_inaddr_any; #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) From 5f35a5236435522f49f9a95d3b59009f947b9130 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 20 Aug 2009 11:57:41 -0300 Subject: [PATCH 0468/1342] [pim] show ip pim lan-prune-delay: fix cosmetic alignment --- pimd/pim_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index ea396bcfc..140812c2a 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -797,7 +797,7 @@ static void pim_show_lan_prune_delay(struct vty *vty) pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); - vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u %-15s %s %5u %5u %1u%s", + vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u %-15s %-3s %5u %5u %1u%s", ifp->name, inet_ntoa(ifaddr), pim_ifp->pim_propagation_delay_msec, From 54d6c57db53a626e21766ce608e69f30396a95f0 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 20 Aug 2009 18:31:03 -0300 Subject: [PATCH 0469/1342] [pim] Fixed doc on CAVEAT C7 --- pimd/CAVEATS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/CAVEATS b/pimd/CAVEATS index 7dc950fed..c436d552a 100644 --- a/pimd/CAVEATS +++ b/pimd/CAVEATS @@ -26,7 +26,7 @@ C6 PIM implementation currently does not support IPv6. PIM-SSM requires IGMPv3 for IPv4 and MLDv2 for IPv6. MLDv2 is currently missing. See also CAVEAT C9. -C7 (S,G) Assert state machine (RFC 4601, section 4.6.1) is not +C7 FIXED (S,G) Assert state machine (RFC 4601, section 4.6.1) is not implemented. See also TODO T6. See also CAVEAT C10. C8 It is not possible to disable join suppression in order to From 47afa6e19b69b433c0c0d0b73837118e0a1284cc Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 27 Aug 2009 18:23:02 -0300 Subject: [PATCH 0470/1342] [pim] Version up to 0.158 --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index fc5bca2fa..fa6dd5529 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.157" +#define PIMD_VERSION_STR "0.158" const char * const PIMD_VERSION; From b471196e812d98b3ce42bcc186d3a381080d423a Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 11 Sep 2009 11:15:42 -0300 Subject: [PATCH 0471/1342] [pim] ip mroute show: can display the MFC --- pimd/LINUX_KERNEL_MROUTE_MFC | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pimd/LINUX_KERNEL_MROUTE_MFC b/pimd/LINUX_KERNEL_MROUTE_MFC index 7dc44b0d1..e87e567f9 100644 --- a/pimd/LINUX_KERNEL_MROUTE_MFC +++ b/pimd/LINUX_KERNEL_MROUTE_MFC @@ -19,4 +19,8 @@ Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote cat /proc/net/ip_mr_cache Group Origin Iif Pkts Bytes Wrong Oifs +# iproute2 can display the MFC: +ip mroute show +(2.2.2.2, 239.2.2.2) Iif: eth1 Oifs: eth0 + # -- end-of-file -- From 465185300b26042e1813d53f179616a17154d37a Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 11 Sep 2009 15:05:40 -0300 Subject: [PATCH 0472/1342] [pim] clean-up --- pimd/pim_cmd.c | 1 - pimd/pim_iface.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 140812c2a..5b47f3bbb 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1086,7 +1086,6 @@ static void igmp_show_querier(struct vty *vty) { struct listnode *node; struct interface *ifp; - time_t now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Querier StartCount Query-Timer Other-Timer%s", VTY_NEWLINE); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index bc99aafba..cfdb8eb19 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -110,8 +110,6 @@ void pim_if_init(void); struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); void pim_if_delete(struct interface *ifp); -int pim_if_igmp_listen(struct vty *vty, - struct interface *ifp); void pim_if_addr_add(struct connected *ifc); void pim_if_addr_del(struct connected *ifc); void pim_if_addr_add_all(struct interface *ifp); From 40765fe45f39767ad545ca693fb5985fa90ce4ca Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 30 Sep 2009 17:10:11 -0300 Subject: [PATCH 0473/1342] [pim] Command line tool to test IGMPv3 join. --- pimd/Makefile.am | 10 ++- pimd/pim_igmp_join.c | 61 ++++++++++++++++ pimd/pim_igmp_join.h | 32 +++++++++ pimd/pim_sock.c | 30 +------- pimd/pim_sock.h | 2 + pimd/test_igmpv3_join.c | 149 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+), 30 deletions(-) create mode 100644 pimd/pim_igmp_join.c create mode 100644 pimd/pim_igmp_join.h create mode 100644 pimd/test_igmpv3_join.c diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 80df2e6b8..c722b7ec7 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -44,6 +44,7 @@ INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ noinst_LIBRARIES = libpim.a sbin_PROGRAMS = pimd +bin_PROGRAMS = test_igmpv3_join libpim_a_SOURCES = \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ @@ -51,7 +52,8 @@ libpim_a_SOURCES = \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ - pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c + pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c \ + pim_igmp_join.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ @@ -59,11 +61,15 @@ noinst_HEADERS = \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ - pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h + pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h \ + pim_igmp_join.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) +test_igmpv3_join_SOURCES = \ + test_igmpv3_join.c pim_igmp_join.c + pimd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c new file mode 100644 index 000000000..7183997c5 --- /dev/null +++ b/pimd/pim_igmp_join.c @@ -0,0 +1,61 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include + +#include "pim_igmp_join.h" + +#ifndef MCAST_JOIN_SOURCE_GROUP +#define MCAST_JOIN_SOURCE_GROUP 46 +struct group_source_req +{ + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; +#endif + +int pim_igmp_join_source(int fd, int ifindex, + struct in_addr group_addr, + struct in_addr source_addr) +{ + struct group_source_req req; + struct sockaddr_in *group_sa = (struct sockaddr_in *) &req.gsr_group; + struct sockaddr_in *source_sa = (struct sockaddr_in *) &req.gsr_source; + + memset(group_sa, 0, sizeof(*group_sa)); + group_sa->sin_family = AF_INET; + group_sa->sin_addr = group_addr; + group_sa->sin_port = htons(0); + + memset(source_sa, 0, sizeof(*source_sa)); + source_sa->sin_family = AF_INET; + source_sa->sin_addr = source_addr; + source_sa->sin_port = htons(0); + + req.gsr_interface = ifindex; + + return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, + &req, sizeof(req)); + + return 0; +} diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h new file mode 100644 index 000000000..1127af120 --- /dev/null +++ b/pimd/pim_igmp_join.h @@ -0,0 +1,32 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_IGMP_JOIN_H +#define PIM_IGMP_JOIN_H + +#include + +int pim_igmp_join_source(int fd, int ifindex, + struct in_addr group_addr, + struct in_addr source_addr); + +#endif /* PIM_IGMP_JOIN_H */ diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 00fc8edab..c908e8b83 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -38,20 +38,11 @@ #include "pimd.h" #include "pim_sock.h" #include "pim_str.h" +#include "pim_igmp_join.h" /* GLOBAL VARS */ extern struct zebra_privs_t pimd_privs; -#ifndef MCAST_JOIN_SOURCE_GROUP -#define MCAST_JOIN_SOURCE_GROUP 46 -struct group_source_req -{ - uint32_t gsr_interface; - struct sockaddr_storage gsr_group; - struct sockaddr_storage gsr_source; -}; -#endif - int pim_socket_raw(int protocol) { int fd; @@ -242,24 +233,7 @@ int pim_socket_join_source(int fd, int ifindex, struct in_addr source_addr, const char *ifname) { - struct group_source_req req; - struct sockaddr_in *group_sa = (struct sockaddr_in *) &req.gsr_group; - struct sockaddr_in *source_sa = (struct sockaddr_in *) &req.gsr_source; - - memset(group_sa, 0, sizeof(*group_sa)); - group_sa->sin_family = AF_INET; - group_sa->sin_addr = group_addr; - group_sa->sin_port = htons(0); - - memset(source_sa, 0, sizeof(*source_sa)); - source_sa->sin_family = AF_INET; - source_sa->sin_addr = source_addr; - source_sa->sin_port = htons(0); - - req.gsr_interface = ifindex; - - if (setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, - &req, sizeof(req))) { + if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) { int e = errno; char group_str[100]; char source_str[100]; diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index e9d5476f6..d3557809d 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -23,6 +23,8 @@ #ifndef PIM_SOCK_H #define PIM_SOCK_H +#include + #define PIM_SOCK_ERR_NONE (0) /* No error */ #define PIM_SOCK_ERR_SOCKET (-1) /* socket() */ #define PIM_SOCK_ERR_RA (-2) /* Router Alert option */ diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c new file mode 100644 index 000000000..af93ab603 --- /dev/null +++ b/pimd/test_igmpv3_join.c @@ -0,0 +1,149 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pim_igmp_join.h" + +const char *prog_name = 0; + +static int iface_solve_index(const char *ifname) +{ + struct if_nameindex *ini; + int ifindex = -1; + int i; + + if (!ifname) + return -1; + + ini = if_nameindex(); + if (!ini) { + int err = errno; + fprintf(stderr, + "%s: interface=%s: failure solving index: errno=%d: %s\n", + prog_name, ifname, err, strerror(err)); + errno = err; + return -1; + } + + for (i = 0; ini[i].if_index; ++i) { +#if 0 + fprintf(stderr, + "%s: interface=%s matching against local ifname=%s ifindex=%d\n", + prog_name, ifname, ini[i].if_name, ini[i].if_index); +#endif + if (!strcmp(ini[i].if_name, ifname)) { + ifindex = ini[i].if_index; + break; + } + } + + if_freenameindex(ini); + + return ifindex; +} + +int main(int argc, const char *argv[]) +{ + struct in_addr group_addr; + struct in_addr source_addr; + const char *ifname; + const char *group; + const char *source; + int ifindex; + int result; + int fd; + + prog_name = argv[0]; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + fprintf(stderr, + "%s: could not create socket: socket(): errno=%d: %s\n", + prog_name, errno, strerror(errno)); + exit(1); + } + + if (argc != 4) { + fprintf(stderr, + "usage: %s interface group source\n" + "example: %s eth0 232.1.1.1 1.1.1.1\n", + prog_name, prog_name); + exit(1); + } + + ifname = argv[1]; + group = argv[2]; + source = argv[3]; + + ifindex = iface_solve_index(ifname); + if (ifindex < 0) { + fprintf(stderr, "%s: could not find interface: %s\n", + prog_name, ifname); + exit(1); + } + + result = inet_pton(AF_INET, group, &group_addr); + if (result <= 0) { + fprintf(stderr, "%s: bad group address: %s\n", + prog_name, group); + exit(1); + } + + result = inet_pton(AF_INET, source, &source_addr); + if (result <= 0) { + fprintf(stderr, "%s: bad source address: %s\n", + prog_name, source); + exit(1); + } + + result = pim_igmp_join_source(fd, ifindex, group_addr, source_addr); + if (result) { + fprintf(stderr, + "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s\n", + prog_name, fd, group, source, ifindex, ifname, + errno, strerror(errno)); + exit(1); + } + + printf("%s: joined channel (S,G)=(%s,%s) on interface %s\n", + prog_name, source, group, ifname); + + printf("%s: waiting...\n", prog_name); + + getchar(); + + close(fd); + + printf("%s: left channel (S,G)=(%s,%s) on interface %s\n", + prog_name, source, group, ifname); + + exit(0); +} From 31894370d26de0b91b5c003ca6c592f0a487d60f Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 1 Oct 2009 10:04:02 -0300 Subject: [PATCH 0474/1342] [pim] Hint for test_igmpv3_join command-line utility --- pimd/DEBUG | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pimd/DEBUG b/pimd/DEBUG index aeed9da19..119c46f53 100644 --- a/pimd/DEBUG +++ b/pimd/DEBUG @@ -8,6 +8,18 @@ DEBUG HINTS - Check the multicast packets are not being dropped due to fragmentation problems. + - Two easy options to test IGMPv3 joins from the receiver host: + + 1) Configure pimd on the receiver host with "ip igmp join": + + interface eth0 + ip pim ssm + ip igmp join 239.1.1.1 1.1.1.1 + + 2) Use the test_igmpv3_join command-line utility: + + test_igmpv3_join eth0 239.1.1.1 1.1.1.1 + - The following command generates a 100-kbps multicast stream for channel 1.1.1.1,239.1.1.1 with TTL 10 and 1000-byte payload per UDP packet (to avoid fragmentation): From ccc5d2bb9b7a395375a34cb6a6b703d78e885b1d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 2 Oct 2009 14:50:08 -0300 Subject: [PATCH 0475/1342] [pim] Ref. on LW-MLDv2 --- pimd/TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/pimd/TODO b/pimd/TODO index 7a2ca0b65..6ed98c06e 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -350,6 +350,7 @@ T39 DONE AssertTrackingDesired: flags is not matching evaluation # T40 Lightweight MLDv2 + http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05 http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt http://www.ietf.org/html.charters/mboned-charter.html From 96f91aefc06477e73d0e93008b51fc6e87fa2bc4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 7 Oct 2009 18:41:45 -0300 Subject: [PATCH 0476/1342] [pim] Skeleton for ssmpingd support --- pimd/Makefile.am | 4 +-- pimd/TODO | 3 +++ pimd/pim_cmd.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_cmd.h | 1 + pimd/pim_iface.c | 1 + pimd/pim_iface.h | 1 + pimd/pim_ssmpingd.c | 45 ++++++++++++++++++++++++++++++++++ pimd/pim_ssmpingd.h | 45 ++++++++++++++++++++++++++++++++++ pimd/pimd.c | 5 ++++ pimd/pimd.h | 1 + 10 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 pimd/pim_ssmpingd.c create mode 100644 pimd/pim_ssmpingd.h diff --git a/pimd/Makefile.am b/pimd/Makefile.am index c722b7ec7..57bd31aed 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -53,7 +53,7 @@ libpim_a_SOURCES = \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c \ - pim_igmp_join.c + pim_igmp_join.c pim_ssmpingd.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ @@ -62,7 +62,7 @@ noinst_HEADERS = \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h \ - pim_igmp_join.h + pim_igmp_join.h pim_ssmpingd.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) diff --git a/pimd/TODO b/pimd/TODO index 6ed98c06e..dc2ece5ff 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -354,4 +354,7 @@ T40 Lightweight MLDv2 http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt http://www.ietf.org/html.charters/mboned-charter.html +T41 ssmping + http://www.venaas.no/multicast/ssmping/ + -x- diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 5b47f3bbb..692c2fcc4 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -47,6 +47,7 @@ #include "pim_upstream.h" #include "pim_rpf.h" #include "pim_macro.h" +#include "pim_ssmpingd.h" static struct cmd_node pim_global_node = { PIM_NODE, @@ -2200,6 +2201,63 @@ DEFUN (no_ip_multicast_routing, return CMD_SUCCESS; } +DEFUN (ip_ssmpingd, + ip_ssmpingd_cmd, + "ip ssmpingd [A.B.C.D]", + IP_STR + SSMPINGD_STR + "Source address\n") +{ + int result; + struct in_addr source_addr; + const char *source_str = (argc > 0) ? argv[0] : "0.0.0.0"; + + result = inet_pton(AF_INET, source_str, &source_addr); + if (result <= 0) { + vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", + source_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_ssmpingd_start(source_addr); + if (result) { + vty_out(vty, "%% Failure starting ssmpingd for source %s: %d%s", + source_str, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ssmpingd, + no_ip_ssmpingd_cmd, + "no ip ssmpingd [A.B.C.D]", + NO_STR + IP_STR + SSMPINGD_STR + "Source address\n") +{ + int result; + struct in_addr source_addr; + const char *source_str = (argc > 0) ? argv[0] : "0.0.0.0"; + + result = inet_pton(AF_INET, source_str, &source_addr); + if (result <= 0) { + vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", + source_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_ssmpingd_stop(source_addr); + if (result) { + vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d%s", + source_str, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + DEFUN (interface_ip_igmp, interface_ip_igmp_cmd, "ip igmp", @@ -3788,6 +3846,8 @@ void pim_cmd_init() install_element (CONFIG_NODE, &ip_multicast_routing_cmd); install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd); + install_element (CONFIG_NODE, &ip_ssmpingd_cmd); + install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); #if 0 install_element (CONFIG_NODE, &interface_cmd); /* from if.h */ #else diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index c2bb61bba..f3b2f96ce 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -27,6 +27,7 @@ #define IGMP_STR "IGMP information\n" #define IGMP_GROUP_STR "IGMP groups information\n" #define IGMP_SOURCE_STR "IGMP sources information\n" +#define SSMPINGD_STR "Enable ssmpingd operation\n" #define IFACE_PIM_STR "Enable PIM SSM operation\n" #define IFACE_IGMP_STR "Enable IGMP operation\n" #define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 009f87c17..7806c8050 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -38,6 +38,7 @@ #include "pim_ifchannel.h" #include "pim_rand.h" #include "pim_sock.h" +#include "pim_ssmpingd.h" static void pim_if_igmp_join_del_all(struct interface *ifp); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index cfdb8eb19..0a702c27a 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -29,6 +29,7 @@ #include "vty.h" #include "pim_igmp.h" +#include "pim_upstream.h" #define PIM_IF_MASK_PIM (1 << 0) #define PIM_IF_MASK_IGMP (1 << 1) diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c new file mode 100644 index 000000000..e4b16aa34 --- /dev/null +++ b/pimd/pim_ssmpingd.c @@ -0,0 +1,45 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include "pim_ssmpingd.h" +#include "pim_time.h" +#include "pimd.h" + +void pim_ssmpingd_init() +{ +} + +void pim_ssmpingd_destroy() +{ + if (qpim_ssmpingd_list) + list_free(qpim_ssmpingd_list); +} + +int pim_ssmpingd_start(struct in_addr source_addr) +{ + return 0; +} + +int pim_ssmpingd_stop(struct in_addr source_addr) +{ + return 0; +} diff --git a/pimd/pim_ssmpingd.h b/pimd/pim_ssmpingd.h new file mode 100644 index 000000000..32563aeba --- /dev/null +++ b/pimd/pim_ssmpingd.h @@ -0,0 +1,45 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_SSMPINGD_H +#define PIM_SSMPINGD_H + +#include + +#include "if.h" + +#include "pim_iface.h" + +struct ssmpingd_sock { + int sock_fd; /* socket */ + struct thread *t_sock_read; /* thread for reading socket */ + struct in_addr source; /* source address */ + int64_t creation; /* timestamp of socket creation */ + int64_t requests; /* counter */ +}; + +void pim_ssmpingd_init(void); +void pim_ssmpingd_destroy(void); +int pim_ssmpingd_start(struct in_addr source_addr); +int pim_ssmpingd_stop(struct in_addr source_addr); + +#endif /* PIM_SSMPINGD_H */ diff --git a/pimd/pimd.c b/pimd/pimd.c index f1a084f1a..220604d90 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -35,6 +35,7 @@ #include "pim_upstream.h" #include "pim_rand.h" #include "pim_rpf.h" +#include "pim_ssmpingd.h" const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; @@ -58,9 +59,12 @@ int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_last = 0; struct in_addr qpim_inaddr_any; +struct list *qpim_ssmpingd_list = 0; static void pim_free() { + pim_ssmpingd_destroy(); + if (qpim_channel_oil_list) list_free(qpim_channel_oil_list); @@ -120,6 +124,7 @@ void pim_init() pim_if_init(); pim_cmd_init(); + pim_ssmpingd_init(); } void pim_terminate() diff --git a/pimd/pimd.h b/pimd/pimd.h index 6ee91e7ff..bdf83b439 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -84,6 +84,7 @@ int64_t qpim_rpf_cache_refresh_requests; int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_last; struct in_addr qpim_inaddr_any; +struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) From 824adbea2d8d78f626f32d5b7900121fdebf6937 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 8 Oct 2009 09:16:27 -0300 Subject: [PATCH 0477/1342] [pim] Hooks for ssmpingd support --- lib/memtypes.c | 1 + pimd/pim_cmd.c | 82 +++++++++++- pimd/pim_cmd.h | 4 +- pimd/pim_ssmpingd.c | 304 +++++++++++++++++++++++++++++++++++++++++++- pimd/pim_ssmpingd.h | 2 +- pimd/pim_vty.c | 32 ++++- pimd/pimd.h | 4 + 7 files changed, 418 insertions(+), 11 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index 26e27e72d..4ed1e8955 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -268,6 +268,7 @@ struct memory_list memory_list_pim[] = { MTYPE_PIM_NEIGHBOR, "PIM interface neighbor" }, { MTYPE_PIM_IFCHANNEL, "PIM interface (S,G) state" }, { MTYPE_PIM_UPSTREAM, "PIM upstream (S,G) state" }, + { MTYPE_PIM_SSMPINGD, "PIM sspimgd socket" }, { -1, NULL }, }; diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 692c2fcc4..a4073f50b 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2137,6 +2137,47 @@ DEFUN (show_ip_route, return CMD_SUCCESS; } +static void show_ssmpingd(struct vty *vty) +{ + struct listnode *node; + struct ssmpingd_sock *ss; + time_t now; + + vty_out(vty, "Source Socket Uptime Requests%s", + VTY_NEWLINE); + + if (!qpim_ssmpingd_list) + return; + + now = pim_time_monotonic_sec(); + + for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { + char source_str[100]; + char ss_uptime[10]; + + pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + pim_time_uptime(ss_uptime, sizeof(ss_uptime), now - ss->creation); + + vty_out(vty, "%-15s %6d %8s %8lld%s", + source_str, + ss->sock_fd, + ss_uptime, + ss->requests, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_ssmpingd, + show_ip_ssmpingd_cmd, + "show ip ssmpingd", + SHOW_STR + IP_STR + SHOW_SSMPINGD_STR) +{ + show_ssmpingd(vty); + return CMD_SUCCESS; +} + static void mroute_add_all() { struct listnode *node; @@ -2205,7 +2246,7 @@ DEFUN (ip_ssmpingd, ip_ssmpingd_cmd, "ip ssmpingd [A.B.C.D]", IP_STR - SSMPINGD_STR + CONF_SSMPINGD_STR "Source address\n") { int result; @@ -2234,7 +2275,7 @@ DEFUN (no_ip_ssmpingd, "no ip ssmpingd [A.B.C.D]", NO_STR IP_STR - SSMPINGD_STR + CONF_SSMPINGD_STR "Source address\n") { int result; @@ -3132,6 +3173,36 @@ ALIAS (no_debug_pim_trace, DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) +DEFUN (debug_ssmpingd, + debug_ssmpingd_cmd, + "debug ssmpingd", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_SSMPINGD_STR) +{ + PIM_DO_DEBUG_SSMPINGD; + return CMD_SUCCESS; +} + +DEFUN (no_debug_ssmpingd, + no_debug_ssmpingd_cmd, + "no debug ssmpingd", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_SSMPINGD_STR) +{ + PIM_DONT_DEBUG_SSMPINGD; + return CMD_SUCCESS; +} + +ALIAS (no_debug_ssmpingd, + undebug_ssmpingd_cmd, + "undebug ssmpingd", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_SSMPINGD_STR) + DEFUN (debug_pim_zebra, debug_pim_zebra_cmd, "debug pim zebra", @@ -3897,6 +3968,7 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (VIEW_NODE, &show_ip_mroute_count_cmd); install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); @@ -3965,6 +4037,9 @@ void pim_cmd_init() install_element (ENABLE_NODE, &debug_pim_trace_cmd); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd); install_element (ENABLE_NODE, &undebug_pim_trace_cmd); + install_element (ENABLE_NODE, &debug_ssmpingd_cmd); + install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd); + install_element (ENABLE_NODE, &undebug_ssmpingd_cmd); install_element (ENABLE_NODE, &debug_pim_zebra_cmd); install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd); install_element (ENABLE_NODE, &undebug_pim_zebra_cmd); @@ -3993,6 +4068,9 @@ void pim_cmd_init() install_element (CONFIG_NODE, &debug_pim_trace_cmd); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd); install_element (CONFIG_NODE, &undebug_pim_trace_cmd); + install_element (CONFIG_NODE, &debug_ssmpingd_cmd); + install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd); + install_element (CONFIG_NODE, &undebug_ssmpingd_cmd); install_element (CONFIG_NODE, &debug_pim_zebra_cmd); install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd); install_element (CONFIG_NODE, &undebug_pim_zebra_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index f3b2f96ce..800bfcb4b 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -27,7 +27,8 @@ #define IGMP_STR "IGMP information\n" #define IGMP_GROUP_STR "IGMP groups information\n" #define IGMP_SOURCE_STR "IGMP sources information\n" -#define SSMPINGD_STR "Enable ssmpingd operation\n" +#define CONF_SSMPINGD_STR "Enable ssmpingd operation\n" +#define SHOW_SSMPINGD_STR "ssmpingd operation\n" #define IFACE_PIM_STR "Enable PIM SSM operation\n" #define IFACE_IGMP_STR "Enable IGMP operation\n" #define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" @@ -42,6 +43,7 @@ #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" +#define DEBUG_SSMPINGD_STR "ssmpingd activity\n" #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" #define CLEAR_IP_PIM_STR "PIM clear commands\n" #define MROUTE_STR "IP multicast routing table\n" diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index e4b16aa34..4eb5c8dcf 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -20,26 +20,328 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + +#include "if.h" +#include "log.h" +#include "memory.h" + #include "pim_ssmpingd.h" #include "pim_time.h" +#include "pim_sock.h" +#include "pim_str.h" #include "pimd.h" +static void ssmpingd_read_on(struct ssmpingd_sock *ss); + void pim_ssmpingd_init() { + zassert(!qpim_ssmpingd_list); } void pim_ssmpingd_destroy() { - if (qpim_ssmpingd_list) + if (qpim_ssmpingd_list) { list_free(qpim_ssmpingd_list); + qpim_ssmpingd_list = 0; + } +} + +static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr) +{ + struct listnode *node; + struct ssmpingd_sock *ss; + + if (!qpim_ssmpingd_list) + return 0; + + for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) + if (source_addr.s_addr == ss->source_addr.s_addr) + return ss; + + return 0; +} + +static void ssmpingd_free(struct ssmpingd_sock *ss) +{ + XFREE(MTYPE_PIM_SSMPINGD, ss); +} + +static int ssmpingd_socket(struct in_addr addr, int mttl) +{ + int fd; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + zlog_err("%s: could not create socket: errno=%d: %s", + __PRETTY_FUNCTION__, errno, safe_strerror(errno)); + return -1; + } + + /* Needed to obtain destination address from recvmsg() */ + { +#if defined(HAVE_IP_PKTINFO) + /* Linux IP_PKTINFO */ + int opt = 1; + if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { + zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + fd, errno, safe_strerror(errno)); + } +#elif defined(HAVE_IP_RECVDSTADDR) + /* BSD IP_RECVDSTADDR */ + int opt = 1; + if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { + zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", + fd, errno, safe_strerror(errno)); + } +#else + zlog_err("%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", + __FILE__, __PRETTY_FUNCTION__); + close(fd); + return -1; +#endif + } + + { + int reuse = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (void *) &reuse, sizeof(reuse))) { + zlog_warn("%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, + (void *) &mttl, sizeof(mttl))) { + zlog_warn("%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, mttl, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, + (void *) &addr, sizeof(addr))) { + zlog_warn("%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + + { + long flags; + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + zlog_warn("%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { + zlog_warn("%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + } + + return fd; +} + +static void ssmpingd_delete(struct ssmpingd_sock *ss) +{ + zassert(ss); + zassert(qpim_ssmpingd_list); + + THREAD_OFF(ss->t_sock_read); + + if (close(ss->sock_fd)) { + int e = errno; + char source_str[100]; + pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s", + __PRETTY_FUNCTION__, + ss->sock_fd, source_str, e, safe_strerror(e)); + /* warning only */ + } + + listnode_delete(qpim_ssmpingd_list, ss); + ssmpingd_free(ss); +} + +static int ssmpingd_read_msg(struct ssmpingd_sock *ss) +{ + struct interface *ifp; + struct sockaddr_in from; + struct sockaddr_in to; + socklen_t fromlen = sizeof(from); + socklen_t tolen = sizeof(to); + int ifindex = -1; + char buf[1000]; + int len; + + len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), + &from, &fromlen, + &to, &tolen, + &ifindex); + if (len < 0) { + char source_str[100]; + pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno)); + return -1; + } + + ifp = if_lookup_by_index(ifindex); + + if (PIM_DEBUG_SSMPINGD) { + char source_str[100]; + char from_str[100]; + char to_str[100]; + pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); + pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); + zlog_debug("%s: ssmpingd on source %s: interface %s ifindex=%d received ssmping from %s to %s on fd=%d", + __PRETTY_FUNCTION__, + source_str, + ifp ? ifp->name : "", + ifindex, from_str, to_str, ss->sock_fd); + } + + return 0; +} + +static int ssmpingd_sock_read(struct thread *t) +{ + struct ssmpingd_sock *ss; + int sock_fd; + int result; + + zassert(t); + + ss = THREAD_ARG(t); + zassert(ss); + + sock_fd = THREAD_FD(t); + zassert(sock_fd == ss->sock_fd); + + result = ssmpingd_read_msg(ss); + + /* Keep reading */ + ss->t_sock_read = 0; + ssmpingd_read_on(ss); + + return result; +} + +static void ssmpingd_read_on(struct ssmpingd_sock *ss) +{ + zassert(!ss->t_sock_read); + THREAD_READ_ON(master, ss->t_sock_read, + ssmpingd_sock_read, ss, ss->sock_fd); +} + +static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) +{ + struct ssmpingd_sock *ss; + int sock_fd; + + if (!qpim_ssmpingd_list) { + qpim_ssmpingd_list = list_new(); + if (!qpim_ssmpingd_list) { + zlog_err("%s %s: failure: qpim_ssmpingd_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return 0; + } + qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free; + } + + sock_fd = ssmpingd_socket(source_addr, 64 /* ttl */); + if (sock_fd < 0) { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: ssmpingd_socket() failure for source %s", + __PRETTY_FUNCTION__, source_str); + return 0; + } + + ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss)); + if (!ss) { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_err("%s: XMALLOC(%d) failure for ssmpingd source %s", + __PRETTY_FUNCTION__, + sizeof(*ss), source_str); + close(sock_fd); + return 0; + } + + ss->sock_fd = sock_fd; + ss->t_sock_read = 0; + ss->source_addr = source_addr; + ss->creation = pim_time_monotonic_sec(); + ss->requests = 0; + + listnode_add(qpim_ssmpingd_list, ss); + + ssmpingd_read_on(ss); + + return ss; } int pim_ssmpingd_start(struct in_addr source_addr) { + struct ssmpingd_sock *ss; + + ss = ssmpingd_find(source_addr); + if (ss) { + /* silently ignore request to recreate entry */ + return 0; + } + + { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_info("%s: starting ssmpingd for source %s", + __PRETTY_FUNCTION__, source_str); + } + + ss = ssmpingd_new(source_addr); + if (!ss) { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: ssmpingd_new() failure for source %s", + __PRETTY_FUNCTION__, source_str); + return -1; + } + return 0; } int pim_ssmpingd_stop(struct in_addr source_addr) { + struct ssmpingd_sock *ss; + + ss = ssmpingd_find(source_addr); + if (!ss) { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: could not find ssmpingd for source %s", + __PRETTY_FUNCTION__, source_str); + return -1; + } + + { + char source_str[100]; + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_info("%s: stopping ssmpingd for source %s", + __PRETTY_FUNCTION__, source_str); + } + + ssmpingd_delete(ss); + return 0; } diff --git a/pimd/pim_ssmpingd.h b/pimd/pim_ssmpingd.h index 32563aeba..4bef20b20 100644 --- a/pimd/pim_ssmpingd.h +++ b/pimd/pim_ssmpingd.h @@ -32,7 +32,7 @@ struct ssmpingd_sock { int sock_fd; /* socket */ struct thread *t_sock_read; /* thread for reading socket */ - struct in_addr source; /* source address */ + struct in_addr source_addr; /* source address */ int64_t creation; /* timestamp of socket creation */ int64_t requests; /* counter */ }; diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 7d69b5b10..0b06d0ec5 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -30,6 +30,7 @@ #include "pim_iface.h" #include "pim_cmd.h" #include "pim_str.h" +#include "pim_ssmpingd.h" int pim_debug_config_write(struct vty *vty) { @@ -66,6 +67,11 @@ int pim_debug_config_write(struct vty *vty) ++writes; } + if (PIM_DEBUG_SSMPINGD) { + vty_out(vty, "debug ssmpingd%s", VTY_NEWLINE); + ++writes; + } + return writes; } @@ -78,6 +84,19 @@ int pim_global_config_write(struct vty *vty) ++writes; } + if (qpim_ssmpingd_list) { + struct listnode *node; + struct ssmpingd_sock *ss; + vty_out(vty, "!%s", VTY_NEWLINE); + ++writes; + for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { + char source_str[100]; + pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE); + ++writes; + } + } + return writes; } @@ -91,7 +110,7 @@ int pim_interface_config_write(struct vty *vty) /* IF name */ vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); - writes++; + ++writes; if (ifp->info) { struct pim_interface *pim_ifp = ifp->info; @@ -99,13 +118,13 @@ int pim_interface_config_write(struct vty *vty) /* IF ip pim ssm */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { vty_out(vty, " ip pim ssm%s", VTY_NEWLINE); - writes++; + ++writes; } /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); - writes++; + ++writes; } /* IF ip igmp query-interval */ @@ -113,14 +132,14 @@ int pim_interface_config_write(struct vty *vty) PIM_CMD_IP_IGMP_QUERY_INTERVAL, pim_ifp->igmp_default_query_interval, VTY_NEWLINE); - writes++; + ++writes; /* IF ip igmp query-max-response-time */ vty_out(vty, " %s %d%s", PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); - writes++; + ++writes; /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { @@ -134,11 +153,12 @@ int pim_interface_config_write(struct vty *vty) vty_out(vty, " ip igmp join %s %s%s", group_str, source_str, VTY_NEWLINE); - writes++; + ++writes; } } } vty_out(vty, "!%s", VTY_NEWLINE); + ++writes; } return writes; diff --git a/pimd/pimd.h b/pimd/pimd.h index bdf83b439..a2dc64307 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -60,6 +60,7 @@ #define PIM_MASK_IGMP_PACKETS (1 << 4) #define PIM_MASK_IGMP_TRACE (1 << 5) #define PIM_MASK_ZEBRA (1 << 6) +#define PIM_MASK_SSMPINGD (1 << 7) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; @@ -98,6 +99,7 @@ struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) #define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) +#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) @@ -110,6 +112,7 @@ struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) #define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) +#define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) @@ -118,6 +121,7 @@ struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) #define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) +#define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) void pim_init(void); void pim_terminate(void); From e8c11bbf75c881e3beaadb85d5485161855424a7 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 8 Oct 2009 15:06:32 -0300 Subject: [PATCH 0478/1342] [pim] T41 DONE ssmping support --- pimd/TODO | 13 ++++- pimd/pim_cmd.c | 17 ++++++- pimd/pim_sock.c | 54 ++++++++++++++++++++ pimd/pim_sock.h | 3 ++ pimd/pim_ssmpingd.c | 119 ++++++++++++++++++++++++++++++++++++++++---- pimd/pimd.c | 1 + pimd/pimd.h | 1 + 7 files changed, 195 insertions(+), 13 deletions(-) diff --git a/pimd/TODO b/pimd/TODO index dc2ece5ff..0818d9c14 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -354,7 +354,16 @@ T40 Lightweight MLDv2 http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt http://www.ietf.org/html.charters/mboned-charter.html -T41 ssmping - http://www.venaas.no/multicast/ssmping/ +T41 DONE ssmping support + See http://www.venaas.no/multicast/ssmping/ + + Example: + + debug ssmpingd + + conf t + ip ssmpingd 1.1.1.1 + + show ip ssmpingd -x- diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a4073f50b..eed74927c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2143,7 +2143,7 @@ static void show_ssmpingd(struct vty *vty) struct ssmpingd_sock *ss; time_t now; - vty_out(vty, "Source Socket Uptime Requests%s", + vty_out(vty, "Source Socket Address Port Uptime Requests%s", VTY_NEWLINE); if (!qpim_ssmpingd_list) @@ -2154,13 +2154,25 @@ static void show_ssmpingd(struct vty *vty) for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { char source_str[100]; char ss_uptime[10]; + struct sockaddr_in bind_addr; + int len = sizeof(bind_addr); + char bind_addr_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + + if (pim_socket_getsockname(ss->sock_fd, (struct sockaddr *) &bind_addr, &len)) { + vty_out(vty, "%% Failure reading socket name for ssmpingd source %s on fd=%d%s", + source_str, ss->sock_fd, VTY_NEWLINE); + } + + pim_inet4_dump("", bind_addr.sin_addr, bind_addr_str, sizeof(bind_addr_str)); pim_time_uptime(ss_uptime, sizeof(ss_uptime), now - ss->creation); - vty_out(vty, "%-15s %6d %8s %8lld%s", + vty_out(vty, "%-15s %6d %-15s %5d %8s %8lld%s", source_str, ss->sock_fd, + bind_addr_str, + ntohs(bind_addr.sin_port), ss_uptime, ss->requests, VTY_NEWLINE); @@ -4004,6 +4016,7 @@ void pim_cmd_init() install_element (ENABLE_NODE, &show_ip_mroute_cmd); install_element (ENABLE_NODE, &show_ip_mroute_count_cmd); install_element (ENABLE_NODE, &show_ip_route_cmd); + install_element (ENABLE_NODE, &show_ip_ssmpingd_cmd); install_element (ENABLE_NODE, &show_debugging_cmd); install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index c908e8b83..2e7860542 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -260,6 +260,29 @@ int pim_socket_recvfromto(int fd, char *buf, size_t len, char cbuf[1000]; int err; + /* + * IP_PKTINFO / IP_RECVDSTADDR don't yield sin_port. + * Use getsockname() to get sin_port. + */ + if (to) { + struct sockaddr_in si; + socklen_t si_len = sizeof(si); + + ((struct sockaddr_in *) to)->sin_family = AF_INET; + + if (pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len)) { + ((struct sockaddr_in *) to)->sin_port = ntohs(0); + ((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0); + } + else { + ((struct sockaddr_in *) to)->sin_port = si.sin_port; + ((struct sockaddr_in *) to)->sin_addr = si.sin_addr; + } + + if (tolen) + *tolen = sizeof(si); + } + memset(&msgh, 0, sizeof(struct msghdr)); iov.iov_base = buf; iov.iov_len = len; @@ -291,6 +314,15 @@ int pim_socket_recvfromto(int fd, char *buf, size_t len, *tolen = sizeof(struct sockaddr_in); if (ifindex) *ifindex = i->ipi_ifindex; + + if (to && PIM_DEBUG_PACKETS) { + char to_str[100]; + pim_inet4_dump("", to->sin_addr, to_str, sizeof(to_str)); + zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d", + __PRETTY_FUNCTION__, + to_str, ntohs(to->sin_port)); + } + break; } #endif @@ -302,6 +334,15 @@ int pim_socket_recvfromto(int fd, char *buf, size_t len, ((struct sockaddr_in *) to)->sin_addr = *i; if (tolen) *tolen = sizeof(struct sockaddr_in); + + if (to && PIM_DEBUG_PACKETS) { + char to_str[100]; + pim_inet4_dump("", to->sin_addr, to_str, sizeof(to_str)); + zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d", + __PRETTY_FUNCTION__, + to_str, ntohs(to->sin_port)); + } + break; } #endif @@ -333,3 +374,16 @@ int pim_socket_mcastloop_get(int fd) return loop; } + +int pim_socket_getsockname(int fd, struct sockaddr *name, int *namelen) +{ + if (getsockname(fd, name, namelen)) { + int e = errno; + zlog_warn("Could not get Socket Name for socket fd=%d: errno=%d: %s", + fd, errno, safe_strerror(errno)); + errno = e; + return PIM_SOCK_ERR_NAME; + } + + return PIM_SOCK_ERR_NONE; +} diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index d3557809d..3f026dcdc 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -35,6 +35,7 @@ #define PIM_SOCK_ERR_DSTADDR (-7) /* Outgoing interface option */ #define PIM_SOCK_ERR_NONBLOCK_GETFL (-8) /* Get O_NONBLOCK */ #define PIM_SOCK_ERR_NONBLOCK_SETFL (-9) /* Set O_NONBLOCK */ +#define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */ int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop); @@ -51,4 +52,6 @@ int pim_socket_recvfromto(int fd, char *buf, size_t len, int pim_socket_mcastloop_get(int fd); +int pim_socket_getsockname(int fd, struct sockaddr *name, int *namelen); + #endif /* PIM_SOCK_H */ diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index 4eb5c8dcf..6422cf629 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -32,11 +32,24 @@ #include "pim_str.h" #include "pimd.h" +static const char * const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234"; + +enum { + PIM_SSMPINGD_REQUEST = 'Q', + PIM_SSMPINGD_REPLY = 'A' +}; + static void ssmpingd_read_on(struct ssmpingd_sock *ss); void pim_ssmpingd_init() { + int result; + zassert(!qpim_ssmpingd_list); + + result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP, &qpim_ssmpingd_group_addr); + + zassert(result > 0); } void pim_ssmpingd_destroy() @@ -67,8 +80,9 @@ static void ssmpingd_free(struct ssmpingd_sock *ss) XFREE(MTYPE_PIM_SSMPINGD, ss); } -static int ssmpingd_socket(struct in_addr addr, int mttl) +static int ssmpingd_socket(struct in_addr addr, int port, int mttl) { + struct sockaddr_in sockaddr; int fd; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -78,21 +92,36 @@ static int ssmpingd_socket(struct in_addr addr, int mttl) return -1; } + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr = addr; + sockaddr.sin_port = htons(port); + + if (bind(fd, &sockaddr, sizeof(sockaddr))) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%d) failure: errno=%d: %s", + __PRETTY_FUNCTION__, + fd, addr_str, port, sizeof(sockaddr), + errno, safe_strerror(errno)); + close(fd); + return -1; + } + /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) /* Linux IP_PKTINFO */ int opt = 1; if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { - zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); + zlog_warn("%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { - zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); + zlog_warn("%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #else zlog_err("%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", @@ -121,6 +150,19 @@ static int ssmpingd_socket(struct in_addr addr, int mttl) return -1; } + { + int loop = 0; + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + (void *) &loop, sizeof(loop))) { + zlog_warn("%s: could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, + loop ? "enable" : "disable", + fd, errno, safe_strerror(errno)); + close(fd); + return PIM_SOCK_ERR_LOOP; + } + } + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *) &addr, sizeof(addr))) { zlog_warn("%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", @@ -172,6 +214,34 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss) ssmpingd_free(ss); } +static void ssmpingd_sendto(struct ssmpingd_sock *ss, + const char *buf, + int len, + struct sockaddr_in to) +{ + socklen_t tolen = sizeof(to); + int sent; + + sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT, &to, tolen); + if (sent != len) { + int e = errno; + char to_str[100]; + pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); + if (sent < 0) { + zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s", + __PRETTY_FUNCTION__, + to_str, ntohs(to.sin_port), ss->sock_fd, len, + e, safe_strerror(e)); + } + else { + zlog_warn("%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d", + __PRETTY_FUNCTION__, + to_str, ntohs(to.sin_port), ss->sock_fd, + len, sent); + } + } +} + static int ssmpingd_read_msg(struct ssmpingd_sock *ss) { struct interface *ifp; @@ -183,6 +253,8 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) char buf[1000]; int len; + ++ss->requests; + len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, @@ -197,6 +269,24 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) ifp = if_lookup_by_index(ifindex); + if (buf[0] != PIM_SSMPINGD_REQUEST) { + char source_str[100]; + char from_str[100]; + char to_str[100]; + pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); + pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); + pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); + zlog_warn("%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", + __PRETTY_FUNCTION__, + buf[0], + from_str, ntohs(from.sin_port), + to_str, ntohs(to.sin_port), + ifp ? ifp->name : "", + ifindex, ss->sock_fd, + source_str); + return 0; + } + if (PIM_DEBUG_SSMPINGD) { char source_str[100]; char from_str[100]; @@ -204,13 +294,24 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); - zlog_debug("%s: ssmpingd on source %s: interface %s ifindex=%d received ssmping from %s to %s on fd=%d", + zlog_debug("%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", __PRETTY_FUNCTION__, - source_str, + from_str, ntohs(from.sin_port), + to_str, ntohs(to.sin_port), ifp ? ifp->name : "", - ifindex, from_str, to_str, ss->sock_fd); + ifindex, ss->sock_fd, + source_str); } + buf[0] = PIM_SSMPINGD_REPLY; + + /* unicast reply */ + ssmpingd_sendto(ss, buf, len, from); + + /* multicast reply */ + from.sin_addr = qpim_ssmpingd_group_addr; + ssmpingd_sendto(ss, buf, len, from); + return 0; } @@ -259,7 +360,7 @@ static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free; } - sock_fd = ssmpingd_socket(source_addr, 64 /* ttl */); + sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64); if (sock_fd < 0) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); diff --git a/pimd/pimd.c b/pimd/pimd.c index 220604d90..71b74e972 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -60,6 +60,7 @@ int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_last = 0; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list = 0; +struct in_addr qpim_ssmpingd_group_addr; static void pim_free() { diff --git a/pimd/pimd.h b/pimd/pimd.h index a2dc64307..b42c54cfa 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -86,6 +86,7 @@ int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_last; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ +struct in_addr qpim_ssmpingd_group_addr; #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) From 8bc0b34a2bee1627de04415fe2fddecb3d71e165 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 8 Oct 2009 15:29:59 -0300 Subject: [PATCH 0479/1342] [pim] Sample config for ssmpingd support --- pimd/pimd.conf.sample | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pimd/pimd.conf.sample b/pimd/pimd.conf.sample index 2f4543ecd..67530856b 100644 --- a/pimd/pimd.conf.sample +++ b/pimd/pimd.conf.sample @@ -18,6 +18,12 @@ line vty ! ip multicast-routing ! +! ! You may want to enable ssmpingd for troubleshooting +! ! See http://www.venaas.no/multicast/ssmping/ +! ! +! ip ssmpingd 1.1.1.1 +! ip ssmpingd 2.2.2.2 +! ! ! HINTS: ! ! - Enable "ip pim ssm" on the interface directly attached to the ! ! multicast source host (if this is the first-hop router) From e85a9371c01751273858db94aa5b0f99b11dbf1f Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 8 Oct 2009 16:05:44 -0300 Subject: [PATCH 0480/1342] [pim] ssmpingd commands --- pimd/COMMANDS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 5679e95a7..60a4dbe7a 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -2,6 +2,7 @@ global configuration commands: ip multicast-routing Enable IP multicast forwarding + ip ssmpingd Enable ssmpingd operation interface configuration commands: ip igmp Enable IGMP operation @@ -40,6 +41,7 @@ verification commands: show ip mroute IP multicast routing table show ip mroute count Route and packet count data show ip route IP routing table + show ip ssmpingd ssmpingd operation debug commands: clear ip interfaces Reset interfaces @@ -48,6 +50,7 @@ debug commands: debug igmp IGMP protocol activity debug pim PIM protocol activity debug pim zebra ZEBRA protocol activity + debug ssmpingd ssmpingd activity show debugging State of each debugging option test igmp receive report Test reception of IGMPv3 report test pim receive assert Test reception of PIM assert From 779e220f30ace11acb23ba81ed6eaef51db6f1e4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 16 Oct 2009 08:40:11 -0300 Subject: [PATCH 0481/1342] [pim] Version up to 0.159 --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index fa6dd5529..546ace3b8 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.158" +#define PIMD_VERSION_STR "0.159" const char * const PIMD_VERSION; From 3466dae420942b3a5b342c95d5667e1927409e8a Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 21 Oct 2009 11:33:47 -0200 Subject: [PATCH 0482/1342] [pim] Reference about draft mboned-ssmping --- pimd/TODO | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pimd/TODO b/pimd/TODO index 0818d9c14..1dc561dda 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -355,7 +355,11 @@ T40 Lightweight MLDv2 http://www.ietf.org/html.charters/mboned-charter.html T41 DONE ssmping support - See http://www.venaas.no/multicast/ssmping/ + + See also: + http://www.venaas.no/multicast/ssmping/ + draft-ietf-mboned-ssmping-07 + http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07 Example: From e0b8b9b6e465bc8ae4a416e5297fa682d7feb39e Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 17 Nov 2009 10:17:21 -0200 Subject: [PATCH 0483/1342] [pim] Clean-up log messages --- pimd/pim_hello.c | 2 +- pimd/pim_neighbor.c | 51 ++++++++++++++++++++++----------------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 8b710b8c0..545b3b127 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -197,7 +197,7 @@ int pim_hello_recv(struct interface *ifp, if ((tlv_curr + option_len) > tlv_pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: long PIM hello TLV type=%d length=%d > max=%d from %s on interface %s", + zlog_warn("%s: long PIM hello TLV type=%d length=%d > left=%d from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, tlv_pastend - tlv_curr, src_str, ifp->name); diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index b4112edf1..9013b50c6 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -46,9 +46,11 @@ static void dr_election_by_addr(struct interface *ifp) pim_ifp->pim_dr_addr = pim_ifp->primary_address; - zlog_info("%s on interface %s", - __PRETTY_FUNCTION__, - ifp->name); + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: on interface %s", + __PRETTY_FUNCTION__, + ifp->name); + } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) { @@ -70,15 +72,20 @@ static void dr_election_by_pri(struct interface *ifp) pim_ifp->pim_dr_addr = pim_ifp->primary_address; dr_pri = pim_ifp->pim_dr_priority; - zlog_info("%s: dr pri %u on interface %s", - __PRETTY_FUNCTION__, - dr_pri, ifp->name); - + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: dr pri %u on interface %s", + __PRETTY_FUNCTION__, + dr_pri, ifp->name); + } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { - zlog_info("%s: neigh pri %u addr %x if dr addr %x", - __PRETTY_FUNCTION__, - neigh->dr_priority, ntohl(neigh->source_addr.s_addr) , ntohl(pim_ifp->pim_dr_addr.s_addr) ); + if (PIM_DEBUG_PIM_TRACE) { + zlog_info("%s: neigh pri %u addr %x if dr addr %x", + __PRETTY_FUNCTION__, + neigh->dr_priority, + ntohl(neigh->source_addr.s_addr), + ntohl(pim_ifp->pim_dr_addr.s_addr)); + } if ( (neigh->dr_priority > dr_pri) || ( @@ -103,8 +110,6 @@ void pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr old_dr_addr; - char dr_old_str[100]; - char dr_new_str[100]; pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_count; @@ -118,22 +123,16 @@ void pim_if_dr_election(struct interface *ifp) dr_election_by_pri(ifp); } - pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); - pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); - zlog_info("%s: DR was %s now is %s on interface %s", - __PRETTY_FUNCTION__, - dr_old_str, dr_new_str, ifp->name); - /* DR changed ? */ if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { - /* char dr_old_str[100]; */ - /* char dr_new_str[100]; */ - /* pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); */ - /* pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); */ - /* zlog_info("%s: DR was %s now is %s on interface %s", */ - /* __PRETTY_FUNCTION__, */ - /* dr_old_str, dr_new_str, ifp->name); */ - + char dr_old_str[100]; + char dr_new_str[100]; + pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); + pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); + zlog_info("%s: DR was %s now is %s on interface %s", + __PRETTY_FUNCTION__, + dr_old_str, dr_new_str, ifp->name); + pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); From 627380420e60a4b944646eb1ce2b1552e6e03565 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 18 Nov 2009 10:44:13 -0200 Subject: [PATCH 0484/1342] [pim] Packet dump debugging --- pimd/pim_cmd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_cmd.h | 3 ++ pimd/pim_pim.c | 12 ++++++++ pimd/pim_util.c | 27 ++++++++++++++++++ pimd/pim_util.h | 2 ++ pimd/pim_vty.c | 8 ++++++ pimd/pimd.h | 74 ++++++++++++++++++++++++++--------------------- 7 files changed, 169 insertions(+), 33 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index eed74927c..d42f3bf8d 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3086,6 +3086,10 @@ DEFUN (no_debug_pim, PIM_DONT_DEBUG_PIM_EVENTS; PIM_DONT_DEBUG_PIM_PACKETS; PIM_DONT_DEBUG_PIM_TRACE; + + PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND; + PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV; + return CMD_SUCCESS; } @@ -3155,6 +3159,72 @@ ALIAS (no_debug_pim_packets, DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR) +DEFUN (debug_pim_packetdump_send, + debug_pim_packetdump_send_cmd, + "debug pim packet-dump send", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETDUMP_STR + DEBUG_PIM_PACKETDUMP_SEND_STR) +{ + PIM_DO_DEBUG_PIM_PACKETDUMP_SEND; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_packetdump_send, + no_debug_pim_packetdump_send_cmd, + "no debug pim packet-dump send", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETDUMP_STR + DEBUG_PIM_PACKETDUMP_SEND_STR) +{ + PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim_packetdump_send, + undebug_pim_packetdump_send_cmd, + "undebug pim packet-dump send", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETDUMP_STR + DEBUG_PIM_PACKETDUMP_SEND_STR) + +DEFUN (debug_pim_packetdump_recv, + debug_pim_packetdump_recv_cmd, + "debug pim packet-dump receive", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETDUMP_STR + DEBUG_PIM_PACKETDUMP_RECV_STR) +{ + PIM_DO_DEBUG_PIM_PACKETDUMP_RECV; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_packetdump_recv, + no_debug_pim_packetdump_recv_cmd, + "no debug pim packet-dump receive", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETDUMP_STR + DEBUG_PIM_PACKETDUMP_RECV_STR) +{ + PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV; + return CMD_SUCCESS; +} + +ALIAS (no_debug_pim_packetdump_recv, + undebug_pim_packetdump_recv_cmd, + "undebug pim packet-dump receive", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETDUMP_STR + DEBUG_PIM_PACKETDUMP_RECV_STR) + DEFUN (debug_pim_trace, debug_pim_trace_cmd, "debug pim trace", @@ -4047,6 +4117,12 @@ void pim_cmd_init() install_element (ENABLE_NODE, &debug_pim_packets_cmd); install_element (ENABLE_NODE, &no_debug_pim_packets_cmd); install_element (ENABLE_NODE, &undebug_pim_packets_cmd); + install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd); + install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd); + install_element (ENABLE_NODE, &undebug_pim_packetdump_send_cmd); + install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd); + install_element (ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd); + install_element (ENABLE_NODE, &undebug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &debug_pim_trace_cmd); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd); install_element (ENABLE_NODE, &undebug_pim_trace_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index 800bfcb4b..fd1a62fa5 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -41,6 +41,9 @@ #define DEBUG_PIM_STR "PIM protocol activity\n" #define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" +#define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n" +#define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n" +#define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" #define DEBUG_SSMPINGD_STR "ssmpingd activity\n" diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 9b6dc3592..9595d2d7d 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -169,6 +169,10 @@ int pim_pim_packet(struct interface *ifp, char *buf, size_t len) pim_msg = buf + ip_hlen; pim_msg_len = len - ip_hlen; + if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { + pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len); + } + if (pim_msg_len < PIM_PIM_MIN_LEN) { zlog_warn("PIM message size=%d shorter than minimum=%d", pim_msg_len, PIM_PIM_MIN_LEN); @@ -289,6 +293,10 @@ static int pim_sock_read(struct thread *t) len, from_str, to_str, fd, ifindex, ifp->ifindex); } + if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { + pim_pkt_dump(__PRETTY_FUNCTION__, buf, len); + } + #ifdef PIM_CHECK_RECV_IFINDEX_SANITY /* ifindex sanity check */ if (ifindex != (int) ifp->ifindex) { @@ -456,6 +464,10 @@ int pim_msg_send(int fd, #endif tolen = sizeof(to); + if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { + pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size); + } + sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen); if (sent != (ssize_t) pim_msg_size) { int e = errno; diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 5bc8d07ef..13230c0ca 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -20,6 +20,10 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + +#include "log.h" + #include "pim_util.h" /* @@ -130,3 +134,26 @@ uint16_t pim_inet_checksum(const char *buf, int size) return checksum; } #endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ + +void pim_pkt_dump(const char *label, const char *buf, int size) +{ + char dump_buf[1000]; + int i = 0; + int j = 0; + + for (; i < size; ++i, j += 3) { + int left = sizeof(dump_buf) - j; + if (left < 4) { + if (left > 1) { + strcat(dump_buf + j, "!"); /* mark as truncated */ + } + break; + } + snprintf(dump_buf + j, left, " %02x", buf[i]); + } + + zlog_debug("%s: pkt dump size=%d:%s", + label, + size, + dump_buf); +} diff --git a/pimd/pim_util.h b/pimd/pim_util.h index 0fcdce0c0..5863d5f23 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -38,4 +38,6 @@ uint16_t igmp_msg_decode8to16(uint8_t code); uint16_t pim_inet_checksum(const char *buf, int size); #endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ +void pim_pkt_dump(const char *label, const char *buf, int size); + #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 0b06d0ec5..3a1abf134 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -57,6 +57,14 @@ int pim_debug_config_write(struct vty *vty) vty_out(vty, "debug pim packets%s", VTY_NEWLINE); ++writes; } + if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { + vty_out(vty, "debug pim packet-dump send%s", VTY_NEWLINE); + ++writes; + } + if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { + vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE); + ++writes; + } if (PIM_DEBUG_PIM_TRACE) { vty_out(vty, "debug pim trace%s", VTY_NEWLINE); ++writes; diff --git a/pimd/pimd.h b/pimd/pimd.h index b42c54cfa..1dcd86548 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -53,14 +53,16 @@ #define PIM_INADDR_IS_ANY(addr) ((addr).s_addr == PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ -#define PIM_MASK_PIM_EVENTS (1 << 0) -#define PIM_MASK_PIM_PACKETS (1 << 1) -#define PIM_MASK_PIM_TRACE (1 << 2) -#define PIM_MASK_IGMP_EVENTS (1 << 3) -#define PIM_MASK_IGMP_PACKETS (1 << 4) -#define PIM_MASK_IGMP_TRACE (1 << 5) -#define PIM_MASK_ZEBRA (1 << 6) -#define PIM_MASK_SSMPINGD (1 << 7) +#define PIM_MASK_PIM_EVENTS (1 << 0) +#define PIM_MASK_PIM_PACKETS (1 << 1) +#define PIM_MASK_PIM_PACKETDUMP_SEND (1 << 2) +#define PIM_MASK_PIM_PACKETDUMP_RECV (1 << 3) +#define PIM_MASK_PIM_TRACE (1 << 4) +#define PIM_MASK_IGMP_EVENTS (1 << 5) +#define PIM_MASK_IGMP_PACKETS (1 << 6) +#define PIM_MASK_IGMP_TRACE (1 << 7) +#define PIM_MASK_ZEBRA (1 << 8) +#define PIM_MASK_SSMPINGD (1 << 9) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; @@ -93,36 +95,42 @@ struct in_addr qpim_ssmpingd_group_addr; #define PIM_MROUTE_IS_ENABLED (qpim_mroute_socket_fd >= 0) #define PIM_MROUTE_IS_DISABLED (qpim_mroute_socket_fd < 0) -#define PIM_DEBUG_PIM_EVENTS (qpim_debugs & PIM_MASK_PIM_EVENTS) -#define PIM_DEBUG_PIM_PACKETS (qpim_debugs & PIM_MASK_PIM_PACKETS) -#define PIM_DEBUG_PIM_TRACE (qpim_debugs & PIM_MASK_PIM_TRACE) -#define PIM_DEBUG_IGMP_EVENTS (qpim_debugs & PIM_MASK_IGMP_EVENTS) -#define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) -#define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) -#define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) -#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) +#define PIM_DEBUG_PIM_EVENTS (qpim_debugs & PIM_MASK_PIM_EVENTS) +#define PIM_DEBUG_PIM_PACKETS (qpim_debugs & PIM_MASK_PIM_PACKETS) +#define PIM_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_SEND) +#define PIM_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_RECV) +#define PIM_DEBUG_PIM_TRACE (qpim_debugs & PIM_MASK_PIM_TRACE) +#define PIM_DEBUG_IGMP_EVENTS (qpim_debugs & PIM_MASK_IGMP_EVENTS) +#define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) +#define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) +#define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) +#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) #define PIM_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE)) -#define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS) -#define PIM_DO_DEBUG_PIM_PACKETS (qpim_debugs |= PIM_MASK_PIM_PACKETS) -#define PIM_DO_DEBUG_PIM_TRACE (qpim_debugs |= PIM_MASK_PIM_TRACE) -#define PIM_DO_DEBUG_IGMP_EVENTS (qpim_debugs |= PIM_MASK_IGMP_EVENTS) -#define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) -#define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) -#define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) -#define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) - -#define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) -#define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) -#define PIM_DONT_DEBUG_PIM_TRACE (qpim_debugs &= ~PIM_MASK_PIM_TRACE) -#define PIM_DONT_DEBUG_IGMP_EVENTS (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS) -#define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) -#define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) -#define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) -#define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) +#define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS) +#define PIM_DO_DEBUG_PIM_PACKETS (qpim_debugs |= PIM_MASK_PIM_PACKETS) +#define PIM_DO_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_SEND) +#define PIM_DO_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_RECV) +#define PIM_DO_DEBUG_PIM_TRACE (qpim_debugs |= PIM_MASK_PIM_TRACE) +#define PIM_DO_DEBUG_IGMP_EVENTS (qpim_debugs |= PIM_MASK_IGMP_EVENTS) +#define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) +#define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) +#define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) +#define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) + +#define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) +#define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) +#define PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_SEND) +#define PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_RECV) +#define PIM_DONT_DEBUG_PIM_TRACE (qpim_debugs &= ~PIM_MASK_PIM_TRACE) +#define PIM_DONT_DEBUG_IGMP_EVENTS (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS) +#define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) +#define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) +#define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) +#define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) void pim_init(void); void pim_terminate(void); From 929bb95587fe43db9a904464d973c0605d160644 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 18 Nov 2009 11:55:13 -0200 Subject: [PATCH 0485/1342] [pim] Fix dump byte type --- pimd/pim_util.c | 2 +- pimd/pim_util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 13230c0ca..d97b599c9 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -135,7 +135,7 @@ uint16_t pim_inet_checksum(const char *buf, int size) } #endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ -void pim_pkt_dump(const char *label, const char *buf, int size) +void pim_pkt_dump(const char *label, const uint8_t *buf, int size) { char dump_buf[1000]; int i = 0; diff --git a/pimd/pim_util.h b/pimd/pim_util.h index 5863d5f23..6f5bf2237 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -38,6 +38,6 @@ uint16_t igmp_msg_decode8to16(uint8_t code); uint16_t pim_inet_checksum(const char *buf, int size); #endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ -void pim_pkt_dump(const char *label, const char *buf, int size); +void pim_pkt_dump(const char *label, const uint8_t *buf, int size); #endif /* PIM_UTIL_H */ From 3e92c456b01bb9364a0e68e0124c9ff36edc0b4b Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 18 Nov 2009 16:26:38 -0200 Subject: [PATCH 0486/1342] [pim] test pim receive dump --- pimd/COMMANDS | 1 + pimd/pim_cmd.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 60a4dbe7a..8cfa671ee 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -54,6 +54,7 @@ debug commands: show debugging State of each debugging option test igmp receive report Test reception of IGMPv3 report test pim receive assert Test reception of PIM assert + test pim receive dump Test reception of PIM packet dump test pim receive hello Test reception of PIM hello test pim receive join Test reception of PIM join test pim receive prune Test reception of PIM prune diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index d42f3bf8d..7ccd5cd5f 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3457,6 +3457,97 @@ DEFUN (test_igmp_receive_report, return CMD_SUCCESS; } +DEFUN (test_pim_receive_dump, + test_pim_receive_dump_cmd, + "test pim receive dump INTERFACE A.B.C.D .LINE", + "Test\n" + "Test PIM protocol\n" + "Test PIM message reception\n" + "Test PIM packet dump reception from neighbor\n" + "Interface\n" + "Neighbor address\n" + "Packet dump\n") +{ + char buf[1000]; + char *pim_msg; + struct ip *ip_hdr; + size_t ip_hlen; /* ip header length in bytes */ + int ip_msg_len; + int pim_msg_size; + const char *neigh_str; + struct in_addr neigh_addr; + const char *ifname; + struct interface *ifp; + int argi; + int result; + + /* Find interface */ + ifname = argv[0]; + ifp = if_lookup_by_name(ifname); + if (!ifp) { + vty_out(vty, "No such interface name %s%s", + ifname, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Neighbor address */ + neigh_str = argv[1]; + result = inet_pton(AF_INET, neigh_str, &neigh_addr); + if (result <= 0) { + vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", + neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* + Tweak IP header + */ + ip_hdr = (struct ip *) buf; + ip_hdr->ip_p = PIM_IP_PROTO_PIM; + ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ + ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ + ip_hdr->ip_src = neigh_addr; + ip_hdr->ip_dst = qpim_all_pim_routers_addr; + + /* + Build PIM hello message + */ + pim_msg = buf + ip_hlen; + pim_msg_size = 0; + + /* Scan LINE dump into buffer */ + for (argi = 2; argi < argc; ++argi, ++pim_msg_size) { + const char *hex = argv[argi]; + uint8_t octet = strtol(hex, 0, 16); + int left; + + left = sizeof(buf) - ip_hlen - pim_msg_size; + if (left < 1) { + vty_out(vty, "%% Overflow buf_size=%d buf_left=%d at dump arg %d byte %d value %s=%02x%s", + sizeof(buf), left, argi, argi - 2, hex, octet, VTY_NEWLINE); + return CMD_WARNING; + } + + pim_msg[pim_msg_size] = octet; + } + + ip_msg_len = ip_hlen + pim_msg_size; + + vty_out(vty, "Receiving: buf_size=%d ip_msg_size=%d pim_msg_size=%d%s", + sizeof(buf), ip_msg_len, pim_msg_size, VTY_NEWLINE); + + /* "receive" message */ + + result = pim_pim_packet(ifp, buf, ip_msg_len); + if (result) { + vty_out(vty, "%% pim_pim_packet(len=%d) returned failure: %d%s", + ip_msg_len, result, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + DEFUN (test_pim_receive_hello, test_pim_receive_hello_cmd, "test pim receive hello INTERFACE A.B.C.D <0-65535> <0-65535> <0-65535> <0-32767> <0-65535> <0-1>[LINE]", @@ -4091,6 +4182,7 @@ void pim_cmd_init() install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd); + install_element (ENABLE_NODE, &test_pim_receive_dump_cmd); install_element (ENABLE_NODE, &test_pim_receive_hello_cmd); install_element (ENABLE_NODE, &test_pim_receive_join_cmd); install_element (ENABLE_NODE, &test_pim_receive_prune_cmd); From 42e3078a1e4a0bbb033351ad5a65729a17c1fa19 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 18 Nov 2009 17:19:43 -0200 Subject: [PATCH 0487/1342] [pim] Clean-up --- lib/command.c | 2 ++ lib/vty.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/command.c b/lib/command.c index d1af7fa2f..8870a4211 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2872,6 +2872,7 @@ DEFUN (config_exit, case KEYCHAIN_NODE: case MASC_NODE: case RMAP_NODE: + case PIM_NODE: case VTY_NODE: vty->node = CONFIG_NODE; break; @@ -2929,6 +2930,7 @@ DEFUN (config_end, case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: + case PIM_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; diff --git a/lib/vty.c b/lib/vty.c index 3f08b9e9c..b8db7c894 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -713,6 +713,7 @@ vty_end_config (struct vty *vty) case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: + case PIM_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; @@ -1117,6 +1118,7 @@ vty_stop_input (struct vty *vty) case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: + case PIM_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; From dba7758a7fa712fc712cd3063a2724bb15c92e60 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 19 Nov 2009 10:32:19 -0200 Subject: [PATCH 0488/1342] [pim] test pim receive dump --- pimd/pim_cmd.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 7ccd5cd5f..23ad11f67 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3457,6 +3457,11 @@ DEFUN (test_igmp_receive_report, return CMD_SUCCESS; } +static int hexval(uint8_t ch) +{ + return isdigit(ch) ? (ch - '0') : (10 + tolower(ch) - 'a'); +} + DEFUN (test_pim_receive_dump, test_pim_receive_dump_cmd, "test pim receive dump INTERFACE A.B.C.D .LINE", @@ -3516,19 +3521,40 @@ DEFUN (test_pim_receive_dump, pim_msg_size = 0; /* Scan LINE dump into buffer */ - for (argi = 2; argi < argc; ++argi, ++pim_msg_size) { - const char *hex = argv[argi]; - uint8_t octet = strtol(hex, 0, 16); - int left; - - left = sizeof(buf) - ip_hlen - pim_msg_size; - if (left < 1) { - vty_out(vty, "%% Overflow buf_size=%d buf_left=%d at dump arg %d byte %d value %s=%02x%s", - sizeof(buf), left, argi, argi - 2, hex, octet, VTY_NEWLINE); + for (argi = 2; argi < argc; ++argi) { + const char *str = argv[argi]; + int str_len = strlen(str); + int str_last = str_len - 1; + int i; + + if (str_len % 2) { + vty_out(vty, "%% Uneven hex array arg %d=%s%s", + argi, str, VTY_NEWLINE); return CMD_WARNING; } - pim_msg[pim_msg_size] = octet; + for (i = 0; i < str_last; i += 2) { + uint8_t octet; + int left; + uint8_t h1 = str[i]; + uint8_t h2 = str[i + 1]; + + if (!isxdigit(h1) || !isxdigit(h2)) { + vty_out(vty, "%% Non-hex octet %c%c at hex array arg %d=%s%s", + h1, h2, argi, str, VTY_NEWLINE); + return CMD_WARNING; + } + octet = (hexval(h1) << 4) + hexval(h2); + + left = sizeof(buf) - ip_hlen - pim_msg_size; + if (left < 1) { + vty_out(vty, "%% Overflow buf_size=%d buf_left=%d at hex array arg %d=%s octet %02x%s", + sizeof(buf), left, argi, str, octet, VTY_NEWLINE); + return CMD_WARNING; + } + + pim_msg[pim_msg_size++] = octet; + } } ip_msg_len = ip_hlen + pim_msg_size; From 7c5f50125d9ef099336660330b7432fb848b7e75 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 19 Nov 2009 17:00:23 -0200 Subject: [PATCH 0489/1342] [pim] Fix net/host byte order --- pimd/Makefile.am | 4 ++-- pimd/pim_assert.c | 19 ++++++++++--------- pimd/pim_assert.h | 2 +- pimd/pim_int.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_int.h | 31 +++++++++++++++++++++++++++++++ pimd/pim_tlv.c | 23 ++++++++++++----------- pimd/pim_tlv.h | 16 ++++++++-------- 7 files changed, 108 insertions(+), 31 deletions(-) create mode 100644 pimd/pim_int.c create mode 100644 pimd/pim_int.h diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 57bd31aed..4aae63780 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -53,7 +53,7 @@ libpim_a_SOURCES = \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c \ - pim_igmp_join.c pim_ssmpingd.c + pim_igmp_join.c pim_ssmpingd.c pim_int.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ @@ -62,7 +62,7 @@ noinst_HEADERS = \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h \ - pim_igmp_join.h pim_ssmpingd.h + pim_igmp_join.h pim_ssmpingd.h pim_int.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 0ce0e5d0d..52168d695 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -30,6 +30,7 @@ #include "pim_tlv.h" #include "pim_msg.h" #include "pim_pim.h" +#include "pim_int.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_hello.h" @@ -297,7 +298,7 @@ int pim_assert_recv(struct interface *ifp, Parse assert metric preference */ - msg_metric.metric_preference = ntohl(*(const uint32_t *) curr); + msg_metric.metric_preference = pim_read_uint32_host(curr); msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */ msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */ @@ -308,7 +309,7 @@ int pim_assert_recv(struct interface *ifp, Parse assert route metric */ - msg_metric.route_metric = ntohl(*(const uint32_t *) curr); + msg_metric.route_metric = pim_read_uint32_host(curr); if (PIM_DEBUG_PIM_TRACE) { char neigh_str[100]; @@ -378,7 +379,7 @@ int pim_assert_metric_match(const struct pim_assert_metric *m1, return m1->ip_address.s_addr == m2->ip_address.s_addr; } -int pim_assert_build_msg(char *pim_msg, int buf_size, +int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr, @@ -386,8 +387,8 @@ int pim_assert_build_msg(char *pim_msg, int buf_size, uint32_t route_metric, uint32_t rpt_bit_flag) { - char *buf_pastend = pim_msg + buf_size; - char *pim_msg_curr; + uint8_t *buf_pastend = pim_msg + buf_size; + uint8_t *pim_msg_curr; int pim_msg_size; int remain; @@ -420,13 +421,13 @@ int pim_assert_build_msg(char *pim_msg, int buf_size, } /* Metric preference */ - *((uint32_t *) pim_msg_curr) = htonl(rpt_bit_flag ? - metric_preference | 0x80000000 : - metric_preference); + pim_write_uint32(pim_msg_curr, rpt_bit_flag ? + metric_preference | 0x80000000 : + metric_preference); pim_msg_curr += 4; /* Route metric */ - *((uint32_t *) pim_msg_curr) = htonl(route_metric); + pim_write_uint32(pim_msg_curr, route_metric); pim_msg_curr += 4; /* diff --git a/pimd/pim_assert.h b/pimd/pim_assert.h index 6a8594ce1..feeb91df0 100644 --- a/pimd/pim_assert.h +++ b/pimd/pim_assert.h @@ -58,7 +58,7 @@ int pim_assert_metric_better(const struct pim_assert_metric *m1, int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); -int pim_assert_build_msg(char *pim_msg, int buf_size, +int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr, diff --git a/pimd/pim_int.c b/pimd/pim_int.c new file mode 100644 index 000000000..2ff1a116e --- /dev/null +++ b/pimd/pim_int.c @@ -0,0 +1,44 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include + +#include "pim_int.h" + +uint32_t pim_read_uint32_host(const uint8_t *buf) +{ + uint32_t val; + memcpy(&val, buf, sizeof(val)); + /* val is in netorder */ + val = ntohl(val); + /* val is in hostorder */ + return val; +} + +void pim_write_uint32(uint8_t *buf, uint32_t val_host) +{ + /* val_host is in host order */ + val_host = htonl(val_host); + /* val_host is in netorder */ + memcpy(buf, &val_host, sizeof(val_host)); +} diff --git a/pimd/pim_int.h b/pimd/pim_int.h new file mode 100644 index 000000000..d64b10327 --- /dev/null +++ b/pimd/pim_int.h @@ -0,0 +1,31 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_INT_H +#define PIM_INT_H + +#include + +uint32_t pim_read_uint32_host(const uint8_t *buf); +void pim_write_uint32(uint8_t *buf, uint32_t val_host); + +#endif /* PIM_INT_H */ diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index fc48c8883..16b7e93e5 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -26,12 +26,13 @@ #include "prefix.h" #include "pimd.h" +#include "pim_int.h" #include "pim_tlv.h" #include "pim_str.h" #include "pim_msg.h" -char *pim_tlv_append_uint16(char *buf, - const char *buf_pastend, +char *pim_tlv_append_uint16(uint8_t *buf, + const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value) { @@ -54,8 +55,8 @@ char *pim_tlv_append_uint16(char *buf, return buf; } -char *pim_tlv_append_2uint16(char *buf, - const char *buf_pastend, +char *pim_tlv_append_2uint16(uint8_t *buf, + const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value1, uint16_t option_value2) @@ -81,8 +82,8 @@ char *pim_tlv_append_2uint16(char *buf, return buf; } -char *pim_tlv_append_uint32(char *buf, - const char *buf_pastend, +char *pim_tlv_append_uint32(uint8_t *buf, + const uint8_t *buf_pastend, uint16_t option_type, uint32_t option_value) { @@ -99,7 +100,7 @@ char *pim_tlv_append_uint32(char *buf, buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; - *(uint32_t *) buf = htonl(option_value); + pim_write_uint32(buf, option_value); buf += option_len; return buf; @@ -107,14 +108,14 @@ char *pim_tlv_append_uint32(char *buf, #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) -char *pim_tlv_append_addrlist_ucast(char *buf, - const char *buf_pastend, +char *pim_tlv_append_addrlist_ucast(uint8_t *buf, + const uint8_t *buf_pastend, struct list *ifconnected) { struct listnode *node; uint16_t option_len = 0; - char *curr; + uint8_t *curr; node = listhead(ifconnected); @@ -323,7 +324,7 @@ int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); - + return 0; } diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index 9602cb1c7..5ec3dc43b 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -71,21 +71,21 @@ typedef uint32_t pim_hello_options; #define PIM_TLV_MIN_SIZE (PIM_TLV_TYPE_SIZE + PIM_TLV_LENGTH_SIZE) #define PIM_TLV_OPTION_SIZE(option_len) (PIM_TLV_MIN_SIZE + (option_len)) -char *pim_tlv_append_uint16(char *buf, - const char *buf_pastend, +char *pim_tlv_append_uint16(uint8_t *buf, + const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value); -char *pim_tlv_append_2uint16(char *buf, - const char *buf_pastend, +char *pim_tlv_append_2uint16(uint8_t *buf, + const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value1, uint16_t option_value2); -char *pim_tlv_append_uint32(char *buf, - const char *buf_pastend, +char *pim_tlv_append_uint32(uint8_t *buf, + const uint8_t *buf_pastend, uint16_t option_type, uint32_t option_value); -char *pim_tlv_append_addrlist_ucast(char *buf, - const char *buf_pastend, +char *pim_tlv_append_addrlist_ucast(uint8_t *buf, + const uint8_t *buf_pastend, struct list *ifconnected); int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, From 567f927c39061a0b98caf23381f5eb523f6d5600 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 19 Feb 2010 19:07:00 -0200 Subject: [PATCH 0490/1342] [pim] show ip igmp join --- pimd/COMMANDS | 1 + pimd/pim_cmd.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_iface.c | 18 ++++++++++-- pimd/pim_igmp.h | 1 + pimd/pim_version.h | 2 +- 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 8cfa671ee..56b15dd54 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -14,6 +14,7 @@ interface configuration commands: verification commands: show ip igmp interface IGMP interface information + show ip igmp join IGMP static join information show ip igmp parameters IGMP parameters information show ip igmp groups IGMP groups information show ip igmp groups retransmissions IGMP group retransmission diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 23ad11f67..9553361a1 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -34,6 +34,7 @@ #include "pim_vty.h" #include "pim_mroute.h" #include "pim_str.h" +#include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_sock.h" #include "pim_time.h" @@ -455,6 +456,59 @@ static void igmp_show_interfaces(struct vty *vty) } } +static void igmp_show_interface_join(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + time_t now; + + now = pim_time_monotonic_sec(); + + vty_out(vty, + "Interface Address Source Group Socket Uptime %s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + struct pim_interface *pim_ifp; + struct listnode *join_node; + struct igmp_join *ij; + struct in_addr pri_addr; + char pri_addr_str[100]; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (!pim_ifp->igmp_join_list) + continue; + + pri_addr = pim_find_primary_addr(ifp); + pim_inet4_dump("", pri_addr, pri_addr_str, sizeof(pri_addr_str)); + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, join_node, ij)) { + char group_str[100]; + char source_str[100]; + char uptime[10]; + + pim_time_uptime(uptime, sizeof(uptime), now - ij->sock_creation); + pim_inet4_dump("", ij->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", ij->source_addr, source_str, sizeof(source_str)); + + vty_out(vty, "%-9s %-15s %-15s %-15s %6d %8s%s", + ifp->name, + pri_addr_str, + source_str, + group_str, + ij->sock_fd, + uptime, + VTY_NEWLINE); + } /* for (pim_ifp->igmp_join_list) */ + + } /* for (iflist) */ + +} + static void show_interface_address(struct vty *vty) { struct listnode *ifpnode; @@ -1547,6 +1601,19 @@ DEFUN (show_ip_igmp_interface, return CMD_SUCCESS; } +DEFUN (show_ip_igmp_join, + show_ip_igmp_join_cmd, + "show ip igmp join", + SHOW_STR + IP_STR + IGMP_STR + "IGMP static join information\n") +{ + igmp_show_interface_join(vty); + + return CMD_SUCCESS; +} + DEFUN (show_ip_igmp_groups, show_ip_igmp_groups_cmd, "show ip igmp groups", @@ -4140,6 +4207,7 @@ void pim_cmd_init() install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); install_element (VIEW_NODE, &show_ip_igmp_interface_cmd); + install_element (VIEW_NODE, &show_ip_igmp_join_cmd); install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd); install_element (VIEW_NODE, &show_ip_igmp_groups_cmd); install_element (VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); @@ -4175,6 +4243,7 @@ void pim_cmd_init() install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); + install_element (ENABLE_NODE, &show_ip_igmp_join_cmd); install_element (ENABLE_NODE, &show_ip_igmp_parameters_cmd); install_element (ENABLE_NODE, &show_ip_igmp_groups_cmd); install_element (ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 7806c8050..863cc0396 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -38,6 +38,7 @@ #include "pim_ifchannel.h" #include "pim_rand.h" #include "pim_sock.h" +#include "pim_time.h" #include "pim_ssmpingd.h" static void pim_if_igmp_join_del_all(struct interface *ifp); @@ -917,9 +918,10 @@ static struct igmp_join *igmp_join_new(struct interface *ifp, return 0; } - ij->sock_fd = join_fd; - ij->group_addr = group_addr; - ij->source_addr = source_addr; + ij->sock_fd = join_fd; + ij->group_addr = group_addr; + ij->source_addr = source_addr; + ij->sock_creation = pim_time_monotonic_sec(); listnode_add(pim_ifp->igmp_join_list, ij); @@ -975,6 +977,16 @@ int pim_if_igmp_join_add(struct interface *ifp, return -4; } + { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); + zlog_info("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", + __PRETTY_FUNCTION__, + source_str, group_str, ifp->name); + } + return 0; } diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index 95e60bf21..d45f223ba 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -70,6 +70,7 @@ struct igmp_join { struct in_addr group_addr; struct in_addr source_addr; int sock_fd; + time_t sock_creation; }; struct igmp_sock { diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 546ace3b8..ef75791e7 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.159" +#define PIMD_VERSION_STR "0.160" const char * const PIMD_VERSION; From 9986fb3a25a0432dbd89aa1e319c89691db05bc0 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Feb 2010 09:09:09 -0300 Subject: [PATCH 0491/1342] [pim] TODO T42 Static igmp join fails when loading config at boot time --- pimd/TODO | 27 +++++++++++++++++++++++++++ pimd/pim_iface.c | 6 +++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pimd/TODO b/pimd/TODO index 1dc561dda..0a5617e4a 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -370,4 +370,31 @@ T41 DONE ssmping support show ip ssmpingd +T42 Static igmp join fails when loading config at boot time + + ! Wrong behavior seen at boot time: + ! + 2010/02/22 08:59:00 PIM: igmp_source_forward_start: ignoring request for + looped MFC entry (S,G)=(3.3.3.3,239.3.3.3): igmp_sock=12 oif=eth0 vif_index=2 + + ! Correct behavior seen later: + ! + 2010/02/22 09:03:16 PIM: igmp_source_forward_start: ignoring request for + looped MFC entry (S,G)=(2.2.2.2,239.2.2.2): igmp_sock=17 oif=lo vif_index=1 + + ! To see the wrong message at boot: + ! + debug igmp trace + ! + interface lo + ip igmp + ip igmp join 239.2.2.2 2.2.2.2 + ip igmp join 239.3.3.3 3.3.3.3 + ! + + ! Interfaces indexes: + Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut + eth0 200.202.112.3 2 2 0 0 0 0 + lo 127.0.0.1 1 1 0 0 0 0 + -x- diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 863cc0396..52d4f0d85 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -982,9 +982,9 @@ int pim_if_igmp_join_add(struct interface *ifp, char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); - zlog_info("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", - __PRETTY_FUNCTION__, - source_str, group_str, ifp->name); + zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", + __PRETTY_FUNCTION__, + source_str, group_str, ifp->name); } return 0; From 67faabc18026bf3f8ae6d7ee1df9f2b1729ea06b Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Feb 2010 12:11:11 -0300 Subject: [PATCH 0492/1342] [pim] debug mroute --- pimd/pim_cmd.c | 31 +++++++++++++++++++++++++++++++ pimd/pim_cmd.h | 1 + pimd/pim_vty.c | 5 +++++ pimd/pim_zebra.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ pimd/pimd.h | 4 ++++ 5 files changed, 85 insertions(+) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 9553361a1..2b418cd46 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3131,6 +3131,33 @@ ALIAS (no_debug_igmp_trace, DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) +DEFUN (debug_mroute, + debug_mroute_cmd, + "debug mroute", + DEBUG_STR + DEBUG_MROUTE_STR) +{ + PIM_DO_DEBUG_MROUTE; + return CMD_SUCCESS; +} + +DEFUN (no_debug_mroute, + no_debug_mroute_cmd, + "no debug mroute", + NO_STR + DEBUG_STR + DEBUG_MROUTE_STR) +{ + PIM_DONT_DEBUG_MROUTE; + return CMD_SUCCESS; +} + +ALIAS (no_debug_mroute, + undebug_mroute_cmd, + "undebug mroute", + UNDEBUG_STR + DEBUG_MROUTE_STR) + DEFUN (debug_pim, debug_pim_cmd, "debug pim", @@ -4295,6 +4322,8 @@ void pim_cmd_init() install_element (ENABLE_NODE, &debug_igmp_trace_cmd); install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element (ENABLE_NODE, &undebug_igmp_trace_cmd); + install_element (ENABLE_NODE, &debug_mroute_cmd); + install_element (ENABLE_NODE, &no_debug_mroute_cmd); install_element (ENABLE_NODE, &debug_pim_cmd); install_element (ENABLE_NODE, &no_debug_pim_cmd); install_element (ENABLE_NODE, &undebug_pim_cmd); @@ -4332,6 +4361,8 @@ void pim_cmd_init() install_element (CONFIG_NODE, &debug_igmp_trace_cmd); install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd); install_element (CONFIG_NODE, &undebug_igmp_trace_cmd); + install_element (CONFIG_NODE, &debug_mroute_cmd); + install_element (CONFIG_NODE, &no_debug_mroute_cmd); install_element (CONFIG_NODE, &debug_pim_cmd); install_element (CONFIG_NODE, &no_debug_pim_cmd); install_element (CONFIG_NODE, &undebug_pim_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index fd1a62fa5..d83cbc096 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -38,6 +38,7 @@ #define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n" #define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n" #define DEBUG_IGMP_TRACE_STR "IGMP internal daemon activity\n" +#define DEBUG_MROUTE_STR "PIM interaction with kernel MFC cache\n" #define DEBUG_PIM_STR "PIM protocol activity\n" #define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 3a1abf134..bcace95c9 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -49,6 +49,11 @@ int pim_debug_config_write(struct vty *vty) ++writes; } + if (PIM_DEBUG_MROUTE) { + vty_out(vty, "debug mroute%s", VTY_NEWLINE); + ++writes; + } + if (PIM_DEBUG_PIM_EVENTS) { vty_out(vty, "debug pim events%s", VTY_NEWLINE); ++writes; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 3530434dd..e18b7ac92 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -754,6 +754,17 @@ static int add_oif(struct channel_oil *channel_oil, pim_ifp = oif->info; + if (PIM_DEBUG_MROUTE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + proto_mask, oif->name, pim_ifp->mroute_vif_index); + } + if (pim_ifp->mroute_vif_index < 1) { zlog_warn("%s %s: interface %s vif_index=%d < 1", __FILE__, __PRETTY_FUNCTION__, @@ -860,6 +871,17 @@ static int add_oif(struct channel_oil *channel_oil, ++channel_oil->oil_size; channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; + if (PIM_DEBUG_MROUTE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + proto_mask, oif->name, pim_ifp->mroute_vif_index); + } + return 0; } @@ -878,6 +900,17 @@ static int del_oif(struct channel_oil *channel_oil, zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); + if (PIM_DEBUG_MROUTE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + proto_mask, oif->name, pim_ifp->mroute_vif_index); + } + /* Prevent single protocol from unsubscribing same interface from channel (S,G) multiple times */ if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) { @@ -963,6 +996,17 @@ static int del_oif(struct channel_oil *channel_oil, } } + if (PIM_DEBUG_MROUTE) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str, + proto_mask, oif->name, pim_ifp->mroute_vif_index); + } + return 0; } diff --git a/pimd/pimd.h b/pimd/pimd.h index 1dcd86548..e11d5bad4 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -63,6 +63,7 @@ #define PIM_MASK_IGMP_TRACE (1 << 7) #define PIM_MASK_ZEBRA (1 << 8) #define PIM_MASK_SSMPINGD (1 << 9) +#define PIM_MASK_MROUTE (1 << 10) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; @@ -105,6 +106,7 @@ struct in_addr qpim_ssmpingd_group_addr; #define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) #define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) +#define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) @@ -120,6 +122,7 @@ struct in_addr qpim_ssmpingd_group_addr; #define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) #define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) +#define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) @@ -131,6 +134,7 @@ struct in_addr qpim_ssmpingd_group_addr; #define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) #define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) +#define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE) void pim_init(void); void pim_terminate(void); From 034bd7fe705b03ea4025478650bd3d690bda923f Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 1 Mar 2010 17:00:07 -0300 Subject: [PATCH 0493/1342] [pim] debug mroute --- pimd/COMMANDS | 1 + 1 file changed, 1 insertion(+) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 56b15dd54..1199368b6 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -49,6 +49,7 @@ debug commands: clear ip igmp interfaces Reset IGMP interfaces clear ip pim interfaces Reset PIM interfaces debug igmp IGMP protocol activity + debug mroute PIM interaction with kernel MFC cache debug pim PIM protocol activity debug pim zebra ZEBRA protocol activity debug ssmpingd ssmpingd activity From f9e05e5f2ae7bc8352a0744d4e4b5105b60e74a4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 11 Mar 2010 11:17:33 -0300 Subject: [PATCH 0494/1342] [pim] Version up to 0.161 --- lib/command.c | 2 +- pimd/pim_main.c | 6 ++++++ pimd/pim_time.c | 38 +++++++++++++++++++++++++++++--------- pimd/pim_version.h | 2 +- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/lib/command.c b/lib/command.c index 8870a4211..a789b0f4a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -105,7 +105,7 @@ static struct cmd_node config_node = }; /* Default motd string. */ -static const char *default_motd = +const char *default_motd = "\r\n\ Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ " QUAGGA_COPYRIGHT "\r\n\ diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 3cf1869ca..2efcbb8cf 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -285,6 +285,12 @@ Hello, this is " QUAGGA_PROGNAME " " QUAGGA_VERSION " " PIMD_PROGNAME " " PIMD_V zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif +#ifdef HAVE_CLOCK_MONOTONIC + zlog_notice("HAVE_CLOCK_MONOTONIC"); +#else + zlog_notice("!HAVE_CLOCK_MONOTONIC"); +#endif + /* Initialize zclient "update" and "lookup" sockets */ diff --git a/pimd/pim_time.c b/pimd/pim_time.c index 63861e5ce..a4b1cc466 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -30,12 +30,32 @@ #include "pim_time.h" -/* - see man clock_gettime - */ -static int pim_gettime(clockid_t clk_id, struct timeval *tv) +static int pim_gettime(enum quagga_clkid clkid, struct timeval *tv) +{ + int result; + + result = quagga_gettime(clkid, tv); + if (result) { + zlog_err("%s: quagga_gettime(clkid=%d) failure: errno=%d: %s", + __PRETTY_FUNCTION__, clkid, + errno, safe_strerror(errno)); + } + + return result; +} + +static int gettime_monotonic(struct timeval *tv) { - return quagga_gettime(clk_id, tv); + int result; + + result = pim_gettime(QUAGGA_CLK_MONOTONIC, tv); + if (result) { + zlog_err("%s: pim_gettime(QUAGGA_CLK_MONOTONIC=%d) failure: errno=%d: %s", + __PRETTY_FUNCTION__, CLOCK_MONOTONIC, + errno, safe_strerror(errno)); + } + + return result; } /* @@ -46,8 +66,8 @@ int64_t pim_time_monotonic_sec() { struct timeval now_tv; - if (pim_gettime(CLOCK_MONOTONIC, &now_tv)) { - zlog_err("%s: gettime(CLOCK_MONOTONIC) failure: errno=%d: %s", + if (gettime_monotonic(&now_tv)) { + zlog_err("%s: gettime_monotonic() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; @@ -65,8 +85,8 @@ int64_t pim_time_monotonic_dsec() struct timeval now_tv; int64_t now_dsec; - if (pim_gettime(CLOCK_MONOTONIC, &now_tv)) { - zlog_err("%s: gettime(CLOCK_MONOTONIC) failure: errno=%d: %s", + if (gettime_monotonic(&now_tv)) { + zlog_err("%s: gettime_monotonic() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; diff --git a/pimd/pim_version.h b/pimd/pim_version.h index ef75791e7..2734b7ac9 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.160" +#define PIMD_VERSION_STR "0.161" const char * const PIMD_VERSION; From 0ef36d82d87094b32f71be47a73144459f057db9 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 11 Mar 2010 14:47:42 -0300 Subject: [PATCH 0495/1342] [pim] Work-around improper monotonic clock --- pimd/Makefile.am | 4 ++++ pimd/pim_main.c | 8 ++++++++ pimd/pim_time.c | 39 +++++++++++++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 4aae63780..ef5cffa11 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -27,6 +27,8 @@ # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall +# PIM_USE_QUAGGA_GETTIME: Prefer quagga_gettime +# PIM_GETTIME_USE_GETTIMEOFDAY: Work-around improper monotonic clock PIM_DEFS = #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT @@ -37,6 +39,8 @@ PIM_DEFS += -DPIM_MOTD_VERSION PIM_DEFS += -DPIM_USE_QUAGGA_INET_CHECKSUM PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL +#PIM_DEFS += -DPIM_USE_QUAGGA_GETTIME +PIM_DEFS += -DPIM_GETTIME_USE_GETTIMEOFDAY INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 2efcbb8cf..51e5e360b 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -285,6 +285,14 @@ Hello, this is " QUAGGA_PROGNAME " " QUAGGA_VERSION " " PIMD_PROGNAME " " PIMD_V zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif +#ifdef PIM_FORCE_QUAGGA_REALTIME_STABILISED + zlog_notice("PIM_USE_QUAGGA_GETTIME: using Quagga's quagga_gettime"()); +#endif + +#ifdef PIM_GETTIME_USE_GETTIMEOFDAY + zlog_notice("PIM_GETTIME_USE_GETTIMEOFDAY: work-around improper monotonic clock"); +#endif + #ifdef HAVE_CLOCK_MONOTONIC zlog_notice("HAVE_CLOCK_MONOTONIC"); #else diff --git a/pimd/pim_time.c b/pimd/pim_time.c index a4b1cc466..077196087 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -30,16 +30,31 @@ #include "pim_time.h" -static int pim_gettime(enum quagga_clkid clkid, struct timeval *tv) +static int pim_gettime(int clk_id, struct timeval *tv) { + struct timespec ts; int result; - result = quagga_gettime(clkid, tv); +#ifdef PIM_USE_QUAGGA_GETTIME + result = quagga_gettime(clk_id, tv); if (result) { - zlog_err("%s: quagga_gettime(clkid=%d) failure: errno=%d: %s", - __PRETTY_FUNCTION__, clkid, + zlog_err("%s: quagga_gettime(clk_id=%d) failure: errno=%d: %s", + __PRETTY_FUNCTION__, clk_id, errno, safe_strerror(errno)); } +#else + result = clock_gettime(clk_id, &ts); + if (result) { + zlog_err("%s: clock_gettime(clk_id=%d) failure: errno=%d: %s", + __PRETTY_FUNCTION__, clk_id, + errno, safe_strerror(errno)); + return result; + } + if (tv) { + tv->tv_sec = ts.tv_sec; + tv->tv_usec = 1000 * ts.tv_nsec; + } +#endif return result; } @@ -48,12 +63,28 @@ static int gettime_monotonic(struct timeval *tv) { int result; +#ifdef PIM_GETTIME_USE_GETTIMEOFDAY + result = gettimeofday(tv, 0); + if (result) { + zlog_err("%s: gettimeofday() failure: errno=%d: %s", + __PRETTY_FUNCTION__, + errno, safe_strerror(errno)); + } +#elif defined(PIM_USE_QUAGGA_GETTIME) result = pim_gettime(QUAGGA_CLK_MONOTONIC, tv); if (result) { zlog_err("%s: pim_gettime(QUAGGA_CLK_MONOTONIC=%d) failure: errno=%d: %s", + __PRETTY_FUNCTION__, QUAGGA_CLK_MONOTONIC, + errno, safe_strerror(errno)); + } +#else + result = pim_gettime(CLOCK_MONOTONIC, tv); + if (result) { + zlog_err("%s: pim_gettime(CLOCK_MONOTONIC=%d) failure: errno=%d: %s", __PRETTY_FUNCTION__, CLOCK_MONOTONIC, errno, safe_strerror(errno)); } +#endif return result; } From ff752d431675caed78e7b460b2d9a4845e5b6a73 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 17 Mar 2010 10:34:24 -0300 Subject: [PATCH 0496/1342] [pim] Cosmetic RPF refresh timer display --- pimd/pim_cmd.c | 2 +- pimd/pim_time.c | 8 ++++++++ pimd/pim_time.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 2b418cd46..4e6cb89bd 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1081,7 +1081,7 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now) { char refresh_uptime[10]; - pim_time_uptime(refresh_uptime, sizeof(refresh_uptime), now - qpim_rpf_cache_refresh_last); + pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now, qpim_rpf_cache_refresh_last); vty_out(vty, "RPF Cache Refresh Delay: %ld msecs%s" diff --git a/pimd/pim_time.c b/pimd/pim_time.c index 077196087..7d4581d99 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -190,6 +190,14 @@ void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec) pim_time_hhmmss(buf, buf_size, uptime_sec); } +void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin) +{ + if (begin > 0) + pim_time_uptime(buf, buf_size, now - begin); + else + snprintf(buf, buf_size, "--:--:--"); +} + long pim_time_timer_remain_msec(struct thread *t_timer) { /* FIXME: Actually fetch msec resolution from thread */ diff --git a/pimd/pim_time.h b/pimd/pim_time.h index 379eb6cff..2984d9a8d 100644 --- a/pimd/pim_time.h +++ b/pimd/pim_time.h @@ -34,6 +34,7 @@ int pim_time_mmss(char *buf, int buf_size, long sec); void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t); void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t); void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec); +void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin); long pim_time_timer_remain_msec(struct thread *t_timer); #endif /* PIM_TIME_H */ From fa2e1ee255c6a3be76f74b07cb441c34d4b2583f Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 17 Mar 2010 10:51:34 -0300 Subject: [PATCH 0497/1342] [pim] Uniform format for commands "debug pim packet-dump" and "test pim receive dump" --- pimd/pim_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pimd/pim_util.c b/pimd/pim_util.c index d97b599c9..a7e8234e9 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -141,7 +141,7 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size) int i = 0; int j = 0; - for (; i < size; ++i, j += 3) { + for (; i < size; ++i, j += 2) { int left = sizeof(dump_buf) - j; if (left < 4) { if (left > 1) { @@ -149,10 +149,10 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size) } break; } - snprintf(dump_buf + j, left, " %02x", buf[i]); + snprintf(dump_buf + j, left, "%02x", buf[i]); } - zlog_debug("%s: pkt dump size=%d:%s", + zlog_debug("%s: pkt dump size=%d: %s", label, size, dump_buf); From 55b12ff4602ae802281f76e4cda681104a6cf89d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 15 Apr 2010 15:58:30 -0300 Subject: [PATCH 0498/1342] [pim] PIM route type. --- lib/route_types.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/route_types.txt b/lib/route_types.txt index cebf01fca..1b8560793 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -51,6 +51,7 @@ ZEBRA_ROUTE_OSPF, ospf, ospfd, 'O', 1, 0, "OSPF" ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv6" ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS" ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" +ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM" # HSLS and OLSR both are AFI independent (so: 1, 1), however # we want to disable for them for general Quagga distribution. # This at least makes it trivial for users of these protocols @@ -71,6 +72,7 @@ ZEBRA_ROUTE_OSPF, "Open Shortest Path First (OSPFv2)" ZEBRA_ROUTE_OSPF6, "Open Shortest Path First (IPv6) (OSPFv3)" ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)" ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)" +ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)" ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)" ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)" ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)" From 6d26c37a21f65bd7b4c8a9a272fafd0a07091c98 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 15 Apr 2010 16:22:11 -0300 Subject: [PATCH 0499/1342] [pim] .gitignore --- pimd/.gitignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 pimd/.gitignore diff --git a/pimd/.gitignore b/pimd/.gitignore new file mode 100644 index 000000000..7046d69c8 --- /dev/null +++ b/pimd/.gitignore @@ -0,0 +1,7 @@ +.libs +*.a +*.o +pimd +test_igmpv3_join + + From 05e573de60c0b3f1dd874d306b818f7c0dc12bf7 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 20 Apr 2010 12:20:46 -0300 Subject: [PATCH 0500/1342] [pim] "show ip route" renamed to "show ip rib" --- pimd/COMMANDS | 2 +- pimd/pim_cmd.c | 12 ++++++------ pimd/pim_cmd.h | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 1199368b6..fb09e6c92 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -41,7 +41,7 @@ verification commands: show ip multicast Multicast global information show ip mroute IP multicast routing table show ip mroute count Route and packet count data - show ip route IP routing table + show ip rib IP unicast routing table show ip ssmpingd ssmpingd operation debug commands: diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 4e6cb89bd..60e5a16e6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2159,12 +2159,12 @@ DEFUN (show_ip_mroute_count, return CMD_SUCCESS; } -DEFUN (show_ip_route, - show_ip_route_cmd, - "show ip route A.B.C.D", +DEFUN (show_ip_rib, + show_ip_rib_cmd, + "show ip rib A.B.C.D", SHOW_STR IP_STR - ROUTE_STR + RIB_STR "Unicast address\n") { struct in_addr addr; @@ -4261,7 +4261,7 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_multicast_cmd); install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (VIEW_NODE, &show_ip_mroute_count_cmd); - install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_cmd); @@ -4298,7 +4298,7 @@ void pim_cmd_init() install_element (ENABLE_NODE, &show_ip_multicast_cmd); install_element (ENABLE_NODE, &show_ip_mroute_cmd); install_element (ENABLE_NODE, &show_ip_mroute_count_cmd); - install_element (ENABLE_NODE, &show_ip_route_cmd); + install_element (ENABLE_NODE, &show_ip_rib_cmd); install_element (ENABLE_NODE, &show_ip_ssmpingd_cmd); install_element (ENABLE_NODE, &show_debugging_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index d83cbc096..391046a43 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -51,6 +51,7 @@ #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" #define CLEAR_IP_PIM_STR "PIM clear commands\n" #define MROUTE_STR "IP multicast routing table\n" +#define RIB_STR "IP unicast routing table\n" #define PIM_CMD_NO "no" #define PIM_CMD_IP_MULTICAST_ROUTING "ip multicast-routing" From 4560c44d109a25672bf7ec41adb3c63950c46f3e Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 5 May 2010 14:32:52 -0300 Subject: [PATCH 0501/1342] [pim] Reference to troglobit pimd --- pimd/README | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pimd/README b/pimd/README index e42ceda24..f6bd8ec69 100644 --- a/pimd/README +++ b/pimd/README @@ -131,10 +131,17 @@ RELATED WORK igmprt: An IGMPv3-router implementation - http://www.loria.fr/~lahmadi/igmpv3-router.html - pimd: PIMv2-SM daemon + USC pimd: PIMv2-SM daemon - http://netweb.usc.edu/pim/pimd (URL broken in 2008-12-23) - http://packages.debian.org/source/sid/pimd (from Debian) + troglobit pimd: This is the original USC pimd from + http://netweb.usc.edu/pim/. In January 16, 2010 it was revived + with the intention to collect patches floating around in + Debian, Gentoo, Lintrack and other distribution repositories + and to provide a central point of collaboration. + - http://github.com/troglobit/pimd + zpimd: zpimd is not dependent of zebra or any other routing daemon - ftp://robur.slu.se/pub/Routing/Zebra - http://sunsite2.icm.edu.pl/pub/unix/routing/zpimd From 9f4e191bb0c639a21c69b3d139349040283fa941 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 27 May 2010 10:08:43 -0300 Subject: [PATCH 0502/1342] [pim] Version up to 0.162 --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 2734b7ac9..59db6dcf3 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.161" +#define PIMD_VERSION_STR "0.162" const char * const PIMD_VERSION; From d0d7980b7c71c95fd0ddc491b2e60260c604d04b Mon Sep 17 00:00:00 2001 From: User Date: Thu, 5 Aug 2010 13:26:25 -0700 Subject: [PATCH 0503/1342] [pim] Compile fixes for FreeBSD. --- pimd/pim_igmp_join.c | 6 ++++++ pimd/test_igmpv3_join.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c index 7183997c5..693a42b75 100644 --- a/pimd/pim_igmp_join.c +++ b/pimd/pim_igmp_join.c @@ -20,10 +20,16 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include +#include #include #include "pim_igmp_join.h" +#ifndef SOL_IP +#define SOL_IP IPPROTO_IP +#endif + #ifndef MCAST_JOIN_SOURCE_GROUP #define MCAST_JOIN_SOURCE_GROUP 46 struct group_source_req diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c index af93ab603..fe64fbc00 100644 --- a/pimd/test_igmpv3_join.c +++ b/pimd/test_igmpv3_join.c @@ -25,9 +25,9 @@ #include #include #include -#include #include #include +#include #include #include "pim_igmp_join.h" From 8281793ebaa1953d679c553f552ba0eee2bab758 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 18 Aug 2010 10:05:47 -0300 Subject: [PATCH 0504/1342] [pim] Additional PIM drafts. --- pimd/TODO | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pimd/TODO b/pimd/TODO index 0a5617e4a..3a3330d39 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -396,5 +396,30 @@ T42 Static igmp join fails when loading config at boot time Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut eth0 200.202.112.3 2 2 0 0 0 0 lo 127.0.0.1 1 1 0 0 0 0 + +T43 PIM Neighbor Reduction + https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/ + + "In a transit LAN (no directly connected source or receiver), many + of the PIM procedures don't apply. (...) This proposal describes + a procedure to reduce the amount of neighbors established over a + transit LAN." + +T44 Single Stream Multicast Fast Reroute (SMFR) Method + https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/ + + "This document proposes an IP multicast fast convergence method + based on differentiating primary and backup PIM join." + +T45 RFC5384 - The Join Attribute Format + "This document describes a modification of the Join message that + allows a node to associate attributes with a particular tree." + +T46 PIM Multi-Topology ID (MT-ID) Join-Attribute + http://tools.ietf.org/html/draft-cai-pim-mtid-00 + Depends on T45. + + "This draft introduces a new type of PIM Join Attribute used to + encode the identity of the topology PIM uses for RPF." -x- From b9ef7704a72e3ec52174c2792404b15275ff4681 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 27 Aug 2010 18:11:10 -0300 Subject: [PATCH 0505/1342] [pim] bootstrap from tarball prefers autoreconf -i --- pimd/quagga-bootstrap.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pimd/quagga-bootstrap.sh b/pimd/quagga-bootstrap.sh index 1ad9a121b..4ec443d93 100755 --- a/pimd/quagga-bootstrap.sh +++ b/pimd/quagga-bootstrap.sh @@ -17,5 +17,7 @@ if [ -f ./bootstrap.sh ]; then ./bootstrap.sh else msg missing ./bootstrap.sh from quagga - autoreconf -i --force + #autoreconf -i --force + #bootstrap from tarball prefers autoreconf -i + autoreconf -i fi From eb383d931c2bb54b5b84a827503f62cbf1070ef5 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 27 Aug 2010 18:16:33 -0300 Subject: [PATCH 0506/1342] [pim] Version up to 0.163 --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 59db6dcf3..22888c53d 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.162" +#define PIMD_VERSION_STR "0.163" const char * const PIMD_VERSION; From 5c6979834655fb7244e23b958582d51bb176ce9a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 16 Feb 2012 04:47:56 +0100 Subject: [PATCH 0507/1342] pimd: fix format strings * pim_igmp.c, * pim_igmpv3.c, * pim_pim.c, * pim_tlv.c: use %zu / %zd for size_t/ssize_t * pim_iface.c, * pim_ifchannel.c, * pim_mroute.c, * pim_neighbor.c, * pim_oil.c, * pim_ssmpingd.c, * pim_upstream.c: %zu for size_t * pim_cmd.c: %zu + a few (long long) casts for int64_t * pim_hello.c: %td for ptrdiff_t --- pimd/pim_cmd.c | 14 +++++++------- pimd/pim_hello.c | 2 +- pimd/pim_iface.c | 4 ++-- pimd/pim_ifchannel.c | 2 +- pimd/pim_igmp.c | 8 ++++---- pimd/pim_igmpv3.c | 12 ++++++------ pimd/pim_mroute.c | 2 +- pimd/pim_neighbor.c | 2 +- pimd/pim_oil.c | 4 ++-- pimd/pim_pim.c | 10 +++++----- pimd/pim_ssmpingd.c | 4 ++-- pimd/pim_tlv.c | 16 ++++++++-------- pimd/pim_upstream.c | 2 +- 13 files changed, 41 insertions(+), 41 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 60e5a16e6..c37e9615e 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1091,8 +1091,8 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now) "RPF Cache Refresh Last: %s%s", qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE, pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE, - qpim_rpf_cache_refresh_requests, VTY_NEWLINE, - qpim_rpf_cache_refresh_events, VTY_NEWLINE, + (long long)qpim_rpf_cache_refresh_requests, VTY_NEWLINE, + (long long)qpim_rpf_cache_refresh_events, VTY_NEWLINE, refresh_uptime, VTY_NEWLINE); } @@ -2241,7 +2241,7 @@ static void show_ssmpingd(struct vty *vty) bind_addr_str, ntohs(bind_addr.sin_port), ss_uptime, - ss->requests, + (long long)ss->requests, VTY_NEWLINE); } } @@ -3642,7 +3642,7 @@ DEFUN (test_pim_receive_dump, left = sizeof(buf) - ip_hlen - pim_msg_size; if (left < 1) { - vty_out(vty, "%% Overflow buf_size=%d buf_left=%d at hex array arg %d=%s octet %02x%s", + vty_out(vty, "%% Overflow buf_size=%zu buf_left=%d at hex array arg %d=%s octet %02x%s", sizeof(buf), left, argi, str, octet, VTY_NEWLINE); return CMD_WARNING; } @@ -3653,7 +3653,7 @@ DEFUN (test_pim_receive_dump, ip_msg_len = ip_hlen + pim_msg_size; - vty_out(vty, "Receiving: buf_size=%d ip_msg_size=%d pim_msg_size=%d%s", + vty_out(vty, "Receiving: buf_size=%zu ip_msg_size=%d pim_msg_size=%d%s", sizeof(buf), ip_msg_len, pim_msg_size, VTY_NEWLINE); /* "receive" message */ @@ -3873,7 +3873,7 @@ DEFUN (test_pim_receive_assert, remain = buf_pastend - buf; if (remain < (int) sizeof(struct ip)) { - vty_out(vty, "No room for ip header: buf_size=%d < ip_header_size=%d%s", + vty_out(vty, "No room for ip header: buf_size=%d < ip_header_size=%zu%s", remain, sizeof(struct ip), VTY_NEWLINE); return CMD_WARNING; } @@ -4195,7 +4195,7 @@ DEFUN (test_pim_receive_upcall, result = pim_mroute_msg(-1, (char *) &msg, sizeof(msg)); if (result) { - vty_out(vty, "pim_mroute_msg(len=%d) returned failure: %d%s", + vty_out(vty, "pim_mroute_msg(len=%zu) returned failure: %d%s", sizeof(msg), result, VTY_NEWLINE); return CMD_WARNING; } diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 545b3b127..c942de4d4 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -197,7 +197,7 @@ int pim_hello_recv(struct interface *ifp, if ((tlv_curr + option_len) > tlv_pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: long PIM hello TLV type=%d length=%d > left=%d from %s on interface %s", + zlog_warn("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, tlv_pastend - tlv_curr, src_str, ifp->name); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 52d4f0d85..f0c326617 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -80,7 +80,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); if (!pim_ifp) { - zlog_err("PIM XMALLOC(%d) failure", sizeof(*pim_ifp)); + zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp)); return 0; } @@ -911,7 +911,7 @@ static struct igmp_join *igmp_join_new(struct interface *ifp, char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); - zlog_err("%s: XMALLOC(%d) failure for IGMP group %s source %s on interface %s", + zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, sizeof(*ij), group_str, source_str, ifp->name); close(join_fd); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 7f946cfdc..6ceef4eeb 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -204,7 +204,7 @@ static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp, ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch)); if (!ch) { - zlog_err("%s: PIM XMALLOC(%d) failure", + zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*ch)); return 0; } diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index a0a4aa815..dcb9a9bae 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -679,7 +679,7 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) char to_str[100]; if (len < sizeof(*ip_hdr)) { - zlog_warn("IGMP packet size=%d shorter than minimum=%d", + zlog_warn("IGMP packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); return -1; } @@ -692,7 +692,7 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ if (PIM_DEBUG_IGMP_PACKETS) { - zlog_debug("Recv IP packet from %s to %s on %s: size=%d ip_header_size=%d ip_proto=%d", + zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p); } @@ -703,12 +703,12 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) } if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { - zlog_warn("IP packet header size=%d shorter than minimum=%d", + zlog_warn("IP packet header size=%zu shorter than minimum=%d", ip_hlen, PIM_IP_HEADER_MIN_LEN); return -1; } if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { - zlog_warn("IP packet header size=%d greater than maximum=%d", + zlog_warn("IP packet header size=%zu greater than maximum=%d", ip_hlen, PIM_IP_HEADER_MAX_LEN); return -1; } diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 7e76f4427..f8926524e 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1151,7 +1151,7 @@ static int group_retransmit_sources(struct igmp_group *group, if (num_sources_tosend1 > query_buf1_max_sources) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); - zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%d (max_sources=%d)", + zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)", __PRETTY_FUNCTION__, group_str, igmp->interface->name, num_sources_tosend1, sizeof(query_buf1), query_buf1_max_sources); } @@ -1193,7 +1193,7 @@ static int group_retransmit_sources(struct igmp_group *group, if (num_sources_tosend2 > query_buf2_max_sources) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); - zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%d (max_sources=%d)", + zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)", __PRETTY_FUNCTION__, group_str, igmp->interface->name, num_sources_tosend2, sizeof(query_buf2), query_buf2_max_sources); } @@ -1622,7 +1622,7 @@ void pim_igmp_send_membership_query(struct igmp_group *group, msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2); if (msg_size > query_buf_size) { - zlog_err("%s %s: unable to send: msg_size=%d larger than query_buf_size=%d", + zlog_err("%s %s: unable to send: msg_size=%zd larger than query_buf_size=%d", __FILE__, __PRETTY_FUNCTION__, msg_size, query_buf_size); return; @@ -1662,7 +1662,7 @@ void pim_igmp_send_membership_query(struct igmp_group *group, char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); - zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%d s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x", + zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x", __PRETTY_FUNCTION__, dst_str, ifname, group_str, num_sources, msg_size, s_flag, querier_robustness_variable, @@ -1687,13 +1687,13 @@ void pim_igmp_send_membership_query(struct igmp_group *group, pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); if (sent < 0) { - zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%d: errno=%d: %s", + zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%zd: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, e, safe_strerror(e)); } else { - zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%d: sent=%d", + zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%zd: sent=%zd", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, sent); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index c76ba525b..d88373625 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -201,7 +201,7 @@ static int mroute_read_msg(int fd) int rd; if (((int) sizeof(buf)) < msg_min_size) { - zlog_err("%s: fd=%d: buf size=%d lower than msg_min=%d", + zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d", __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size); return -1; } diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 9013b50c6..0df742213 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -292,7 +292,7 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); if (!neigh) { - zlog_err("%s: PIM XMALLOC(%d) failure", + zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*neigh)); return 0; } diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 2c8b056e1..1aaece3f4 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -69,7 +69,7 @@ static struct channel_oil *channel_oil_new(struct in_addr group_addr, c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); if (!c_oil) { - zlog_err("PIM XCALLOC(%d) failure", sizeof(*c_oil)); + zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); return 0; } @@ -91,7 +91,7 @@ static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr, c_oil = channel_oil_new(group_addr, source_addr, input_vif_index); if (!c_oil) { - zlog_warn("PIM XCALLOC(%d) failure", sizeof(*c_oil)); + zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); return 0; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 9595d2d7d..156081ca0 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -132,7 +132,7 @@ int pim_pim_packet(struct interface *ifp, char *buf, size_t len) } if (len < sizeof(*ip_hdr)) { - zlog_warn("PIM packet size=%d shorter than minimum=%d", + zlog_warn("PIM packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); return -1; } @@ -145,7 +145,7 @@ int pim_pim_packet(struct interface *ifp, char *buf, size_t len) ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ if (PIM_DEBUG_PIM_PACKETS) { - zlog_debug("Recv IP packet from %s to %s on %s: size=%d ip_header_size=%d ip_proto=%d", + zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p); } @@ -156,12 +156,12 @@ int pim_pim_packet(struct interface *ifp, char *buf, size_t len) } if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { - zlog_warn("IP packet header size=%d shorter than minimum=%d", + zlog_warn("IP packet header size=%zu shorter than minimum=%d", ip_hlen, PIM_IP_HEADER_MIN_LEN); return -1; } if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { - zlog_warn("IP packet header size=%d greater than maximum=%d", + zlog_warn("IP packet header size=%zu greater than maximum=%d", ip_hlen, PIM_IP_HEADER_MAX_LEN); return -1; } @@ -480,7 +480,7 @@ int pim_msg_send(int fd, e, safe_strerror(e)); } else { - zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%d", + zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd", __PRETTY_FUNCTION__, dst_str, ifname, fd, pim_msg_size, sent); diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index 6422cf629..652999d43 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -99,7 +99,7 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl) if (bind(fd, &sockaddr, sizeof(sockaddr))) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%d) failure: errno=%d: %s", + zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s", __PRETTY_FUNCTION__, fd, addr_str, port, sizeof(sockaddr), errno, safe_strerror(errno)); @@ -373,7 +373,7 @@ static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); - zlog_err("%s: XMALLOC(%d) failure for ssmpingd source %s", + zlog_err("%s: XMALLOC(%zu) failure for ssmpingd source %s", __PRETTY_FUNCTION__, sizeof(*ss), source_str); close(sock_fd); diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 16b7e93e5..cb6b6540f 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -39,7 +39,7 @@ char *pim_tlv_append_uint16(uint8_t *buf, uint16_t option_len = 2; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%d needed=%d", + zlog_warn("%s: buffer overflow: left=%zd needed=%d", __PRETTY_FUNCTION__, buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); return 0; @@ -64,7 +64,7 @@ char *pim_tlv_append_2uint16(uint8_t *buf, uint16_t option_len = 4; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%d needed=%d", + zlog_warn("%s: buffer overflow: left=%zd needed=%d", __PRETTY_FUNCTION__, buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); return 0; @@ -90,7 +90,7 @@ char *pim_tlv_append_uint32(uint8_t *buf, uint16_t option_len = 4; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%d needed=%d", + zlog_warn("%s: buffer overflow: left=%zd needed=%d", __PRETTY_FUNCTION__, buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); return 0; @@ -137,7 +137,7 @@ char *pim_tlv_append_addrlist_ucast(uint8_t *buf, continue; if ((curr + ucast_ipv4_encoding_len) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%d needed=%d", + zlog_warn("%s: buffer overflow: left=%zd needed=%zu", __PRETTY_FUNCTION__, buf_pastend - curr, ucast_ipv4_encoding_len); return 0; @@ -155,7 +155,7 @@ char *pim_tlv_append_addrlist_ucast(uint8_t *buf, } if (PIM_DEBUG_PIM_TRACE) { - zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %d", + zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %zu", __PRETTY_FUNCTION__, option_len / ucast_ipv4_encoding_len); } @@ -398,7 +398,7 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 unicast address overflow: left=%d needed=%d from %s on %s", + zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); @@ -471,7 +471,7 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 group address overflow: left=%d needed=%d from %s on %s", + zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); @@ -549,7 +549,7 @@ int pim_parse_addr_source(const char *ifname, if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: IPv4 source address overflow: left=%d needed=%d from %s on %s", + zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index b9cf1e52c..6702ca139 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -355,7 +355,7 @@ static struct pim_upstream *pim_upstream_new(struct in_addr source_addr, up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); if (!up) { - zlog_err("%s: PIM XMALLOC(%d) failure", + zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*up)); return 0; } From e269b968fdcd44d7a4043c4e67c3e008f85e7379 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 16 Feb 2012 04:32:08 +0000 Subject: [PATCH 0508/1342] pimd: use socklen_t consistently --- pimd/pim_cmd.c | 2 +- pimd/pim_sock.c | 2 +- pimd/pim_sock.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index c37e9615e..dd06b0705 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2222,7 +2222,7 @@ static void show_ssmpingd(struct vty *vty) char source_str[100]; char ss_uptime[10]; struct sockaddr_in bind_addr; - int len = sizeof(bind_addr); + socklen_t len = sizeof(bind_addr); char bind_addr_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 2e7860542..b80c0a22d 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -375,7 +375,7 @@ int pim_socket_mcastloop_get(int fd) return loop; } -int pim_socket_getsockname(int fd, struct sockaddr *name, int *namelen) +int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) { if (getsockname(fd, name, namelen)) { int e = errno; diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 3f026dcdc..29b5aeedd 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -52,6 +52,6 @@ int pim_socket_recvfromto(int fd, char *buf, size_t len, int pim_socket_mcastloop_get(int fd); -int pim_socket_getsockname(int fd, struct sockaddr *name, int *namelen); +int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen); #endif /* PIM_SOCK_H */ From f8cfeb25e62206aaf940b2aabf6a96c36ad4627d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 16 Feb 2012 04:31:08 +0000 Subject: [PATCH 0509/1342] pimd: fix worst char * <> uint8_t * intermingling --- pimd/pim_assert.c | 6 +-- pimd/pim_assert.h | 2 +- pimd/pim_cmd.c | 22 +++++------ pimd/pim_hello.c | 14 +++---- pimd/pim_hello.h | 4 +- pimd/pim_igmp.c | 4 +- pimd/pim_join.c | 12 +++--- pimd/pim_join.h | 2 +- pimd/pim_msg.c | 20 +++++----- pimd/pim_msg.h | 20 +++++----- pimd/pim_pim.c | 10 ++--- pimd/pim_pim.h | 4 +- pimd/pim_sock.c | 2 +- pimd/pim_sock.h | 2 +- pimd/pim_ssmpingd.c | 4 +- pimd/pim_tlv.c | 90 +++++++++++++++++++++------------------------ pimd/pim_tlv.h | 48 ++++++++++++------------ 17 files changed, 129 insertions(+), 137 deletions(-) diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 52168d695..6b062b77d 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -236,13 +236,13 @@ static int dispatch_assert(struct interface *ifp, int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, - char *buf, int buf_size) + uint8_t *buf, int buf_size) { struct prefix msg_group_addr; struct prefix msg_source_addr; struct pim_assert_metric msg_metric; int offset; - char *curr; + uint8_t *curr; int curr_size; on_trace(__PRETTY_FUNCTION__, ifp, src_addr); @@ -445,7 +445,7 @@ static int pim_assert_do(struct pim_ifchannel *ch, { struct interface *ifp; struct pim_interface *pim_ifp; - char pim_msg[1000]; + uint8_t pim_msg[1000]; int pim_msg_size; ifp = ch->interface; diff --git a/pimd/pim_assert.h b/pimd/pim_assert.h index feeb91df0..bd3fb3e25 100644 --- a/pimd/pim_assert.h +++ b/pimd/pim_assert.h @@ -51,7 +51,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, - char *buf, int buf_size); + uint8_t *buf, int buf_size); int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index dd06b0705..f046801de 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3567,8 +3567,8 @@ DEFUN (test_pim_receive_dump, "Neighbor address\n" "Packet dump\n") { - char buf[1000]; - char *pim_msg; + uint8_t buf[1000]; + uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; @@ -3685,8 +3685,8 @@ DEFUN (test_pim_receive_hello, "Neighbor LAN prune delay T-bit\n" "Neighbor secondary addresses\n") { - char buf[1000]; - char *pim_msg; + uint8_t buf[1000]; + uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; @@ -3810,9 +3810,9 @@ DEFUN (test_pim_receive_assert, "Assert route metric\n" "Assert RPT bit flag\n") { - char buf[1000]; - char *buf_pastend = buf + sizeof(buf); - char *pim_msg; + uint8_t buf[1000]; + uint8_t *buf_pastend = buf + sizeof(buf); + uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; @@ -3921,10 +3921,10 @@ static int recv_joinprune(struct vty *vty, const char *argv[], int src_is_join) { - char buf[1000]; - const char *buf_pastend = buf + sizeof(buf); - char *pim_msg; - char *pim_msg_curr; + uint8_t buf[1000]; + const uint8_t *buf_pastend = buf + sizeof(buf); + uint8_t *pim_msg; + uint8_t *pim_msg_curr; int pim_msg_size; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index c942de4d4..73c50d4fb 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -146,12 +146,12 @@ static void tlv_trace_list(const char *label, const char *tlv_name, int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, - char *tlv_buf, int tlv_buf_size) + uint8_t *tlv_buf, int tlv_buf_size) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; - char *tlv_curr; - char *tlv_pastend; + uint8_t *tlv_curr; + uint8_t *tlv_pastend; pim_hello_options hello_options = 0; /* bit array recording options found */ uint16_t hello_option_holdtime = 0; uint16_t hello_option_propagation_delay = 0; @@ -422,7 +422,7 @@ int pim_hello_recv(struct interface *ifp, } int pim_hello_build_tlv(const char *ifname, - char *tlv_buf, int tlv_buf_size, + uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, @@ -431,9 +431,9 @@ int pim_hello_build_tlv(const char *ifname, int can_disable_join_suppression, struct list *ifconnected) { - char *curr = tlv_buf; - char *pastend = tlv_buf + tlv_buf_size; - char *tmp; + uint8_t *curr = tlv_buf; + uint8_t *pastend = tlv_buf + tlv_buf_size; + uint8_t *tmp; /* * Append options diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h index 90a11ba6a..b5e272d5d 100644 --- a/pimd/pim_hello.h +++ b/pimd/pim_hello.h @@ -29,10 +29,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, - char *tlv_buf, int tlv_buf_size); + uint8_t *tlv_buf, int tlv_buf_size); int pim_hello_build_tlv(const char *ifname, - char *tlv_buf, int tlv_buf_size, + uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index dcb9a9bae..6ad521ca0 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -930,7 +930,7 @@ static int pim_igmp_read(struct thread *t) struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); - char buf[PIM_IGMP_BUFSIZE_READ]; + uint8_t buf[PIM_IGMP_BUFSIZE_READ]; int len; int ifindex = -1; int result = -1; /* defaults to bad */ @@ -995,7 +995,7 @@ static int pim_igmp_read(struct thread *t) } #endif - if (pim_igmp_packet(igmp, buf, len)) { + if (pim_igmp_packet(igmp, (char *)buf, len)) { goto done; } diff --git a/pimd/pim_join.c b/pimd/pim_join.c index aa3aa7898..5230bb6c9 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -107,14 +107,14 @@ static void recv_prune(struct interface *ifp, int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, - char *tlv_buf, int tlv_buf_size) + uint8_t *tlv_buf, int tlv_buf_size) { struct prefix msg_upstream_addr; uint8_t msg_num_groups; uint16_t msg_holdtime; int addr_offset; - char *buf; - char *pastend; + uint8_t *buf; + uint8_t *pastend; int remain; int group; @@ -280,9 +280,9 @@ int pim_joinprune_send(struct interface *ifp, int send_join) { struct pim_interface *pim_ifp; - char pim_msg[1000]; - const char *pastend = pim_msg + sizeof(pim_msg); - char *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */ + uint8_t pim_msg[1000]; + const uint8_t *pastend = pim_msg + sizeof(pim_msg); + uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */ int pim_msg_size; int remain; diff --git a/pimd/pim_join.h b/pimd/pim_join.h index 4d9407be1..37ec0f452 100644 --- a/pimd/pim_join.h +++ b/pimd/pim_join.h @@ -32,7 +32,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, - char *tlv_buf, int tlv_buf_size); + uint8_t *tlv_buf, int tlv_buf_size); int pim_joinprune_send(struct interface *ifp, struct in_addr upstream_addr, diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 1105eacae..7eb63e857 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -27,7 +27,7 @@ #include "pim_msg.h" #include "pim_util.h" -void pim_msg_build_header(char *pim_msg, int pim_msg_size, +void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, uint8_t pim_msg_type) { uint16_t checksum; @@ -50,9 +50,9 @@ void pim_msg_build_header(char *pim_msg, int pim_msg_size, *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum; } -char *pim_msg_addr_encode_ipv4_ucast(char *buf, - int buf_size, - struct in_addr addr) +uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, + int buf_size, + struct in_addr addr) { const int ENCODED_IPV4_UCAST_SIZE = 6; @@ -67,9 +67,9 @@ char *pim_msg_addr_encode_ipv4_ucast(char *buf, return buf + ENCODED_IPV4_UCAST_SIZE; } -char *pim_msg_addr_encode_ipv4_group(char *buf, - int buf_size, - struct in_addr addr) +uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, + int buf_size, + struct in_addr addr) { const int ENCODED_IPV4_GROUP_SIZE = 8; @@ -86,9 +86,9 @@ char *pim_msg_addr_encode_ipv4_group(char *buf, return buf + ENCODED_IPV4_GROUP_SIZE; } -char *pim_msg_addr_encode_ipv4_source(char *buf, - int buf_size, - struct in_addr addr) +uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, + int buf_size, + struct in_addr addr) { const int ENCODED_IPV4_SOURCE_SIZE = 8; diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 228d6a856..a884fc84d 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -37,16 +37,16 @@ */ #define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) -void pim_msg_build_header(char *pim_msg, int pim_msg_size, +void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, uint8_t pim_msg_type); -char *pim_msg_addr_encode_ipv4_ucast(char *buf, - int buf_size, - struct in_addr addr); -char *pim_msg_addr_encode_ipv4_group(char *buf, - int buf_size, - struct in_addr addr); -char *pim_msg_addr_encode_ipv4_source(char *buf, - int buf_size, - struct in_addr addr); +uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, + int buf_size, + struct in_addr addr); +uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, + int buf_size, + struct in_addr addr); +uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, + int buf_size, + struct in_addr addr); #endif /* PIM_MSG_H */ diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 156081ca0..8dd71d668 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -111,13 +111,13 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message) sock_close(ifp); } -int pim_pim_packet(struct interface *ifp, char *buf, size_t len) +int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) { struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ char src_str[100]; char dst_str[100]; - char *pim_msg; + uint8_t *pim_msg; int pim_msg_len; uint8_t pim_version; uint8_t pim_type; @@ -253,7 +253,7 @@ static int pim_sock_read(struct thread *t) struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); - char buf[PIM_PIM_BUFSIZE_READ]; + uint8_t buf[PIM_PIM_BUFSIZE_READ]; int len; int ifindex = -1; int result = -1; /* defaults to bad */ @@ -437,7 +437,7 @@ void pim_sock_reset(struct interface *ifp) int pim_msg_send(int fd, struct in_addr dst, - char *pim_msg, + uint8_t *pim_msg, int pim_msg_size, const char *ifname) { @@ -494,7 +494,7 @@ int pim_msg_send(int fd, static int hello_send(struct interface *ifp, uint16_t holdtime) { - char pim_msg[PIM_PIM_BUFSIZE_WRITE]; + uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE]; struct pim_interface *pim_ifp; int pim_tlv_size; int pim_msg_size; diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index a2c8fa582..6be1a3e68 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -60,11 +60,11 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message); void pim_hello_restart_now(struct interface *ifp); void pim_hello_restart_triggered(struct interface *ifp); -int pim_pim_packet(struct interface *ifp, char *buf, size_t len); +int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); int pim_msg_send(int fd, struct in_addr dst, - char *pim_msg, + uint8_t *pim_msg, int pim_msg_size, const char *ifname); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index b80c0a22d..4816c567e 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -249,7 +249,7 @@ int pim_socket_join_source(int fd, int ifindex, return 0; } -int pim_socket_recvfromto(int fd, char *buf, size_t len, +int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, int *ifindex) diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 29b5aeedd..cfe39ad1e 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -45,7 +45,7 @@ int pim_socket_join_source(int fd, int ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname); -int pim_socket_recvfromto(int fd, char *buf, size_t len, +int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, int *ifindex); diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index 652999d43..fd1eac06e 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -215,7 +215,7 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss) } static void ssmpingd_sendto(struct ssmpingd_sock *ss, - const char *buf, + const uint8_t *buf, int len, struct sockaddr_in to) { @@ -250,7 +250,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); int ifindex = -1; - char buf[1000]; + uint8_t buf[1000]; int len; ++ss->requests; diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index cb6b6540f..4ce9a3d22 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -31,10 +31,10 @@ #include "pim_str.h" #include "pim_msg.h" -char *pim_tlv_append_uint16(uint8_t *buf, - const uint8_t *buf_pastend, - uint16_t option_type, - uint16_t option_value) +uint8_t *pim_tlv_append_uint16(uint8_t *buf, + const uint8_t *buf_pastend, + uint16_t option_type, + uint16_t option_value) { uint16_t option_len = 2; @@ -55,11 +55,11 @@ char *pim_tlv_append_uint16(uint8_t *buf, return buf; } -char *pim_tlv_append_2uint16(uint8_t *buf, - const uint8_t *buf_pastend, - uint16_t option_type, - uint16_t option_value1, - uint16_t option_value2) +uint8_t *pim_tlv_append_2uint16(uint8_t *buf, + const uint8_t *buf_pastend, + uint16_t option_type, + uint16_t option_value1, + uint16_t option_value2) { uint16_t option_len = 4; @@ -82,10 +82,10 @@ char *pim_tlv_append_2uint16(uint8_t *buf, return buf; } -char *pim_tlv_append_uint32(uint8_t *buf, - const uint8_t *buf_pastend, - uint16_t option_type, - uint32_t option_value) +uint8_t *pim_tlv_append_uint32(uint8_t *buf, + const uint8_t *buf_pastend, + uint16_t option_type, + uint32_t option_value) { uint16_t option_len = 4; @@ -108,9 +108,9 @@ char *pim_tlv_append_uint32(uint8_t *buf, #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) -char *pim_tlv_append_addrlist_ucast(uint8_t *buf, - const uint8_t *buf_pastend, - struct list *ifconnected) +uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, + const uint8_t *buf_pastend, + struct list *ifconnected) { struct listnode *node; uint16_t option_len = 0; @@ -243,7 +243,7 @@ int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, - const char *tlv_curr) + const uint8_t *tlv_curr) { const char *label = "holdtime"; @@ -271,7 +271,7 @@ int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, - const char *tlv_curr) + const uint8_t *tlv_curr) { if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", ifname, src_addr, @@ -305,7 +305,7 @@ int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, - const char *tlv_curr) + const uint8_t *tlv_curr) { const char *label = "dr_priority"; @@ -332,7 +332,7 @@ int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, - const char *tlv_curr) + const uint8_t *tlv_curr) { const char *label = "generation_id"; @@ -357,12 +357,12 @@ int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, struct prefix *p, - const char *buf, + const uint8_t *buf, int buf_size) { const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ - const char *addr; - const char *pastend; + const uint8_t *addr; + const uint8_t *pastend; int family; int type; @@ -379,10 +379,8 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, addr = buf; pastend = buf + buf_size; - family = *(const uint8_t *) addr; - ++addr; - type = *(const uint8_t *) addr; - ++addr; + family = *addr++; + type = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: @@ -426,12 +424,12 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, struct prefix *p, - const char *buf, + const uint8_t *buf, int buf_size) { const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ - const char *addr; - const char *pastend; + const uint8_t *addr; + const uint8_t *pastend; int family; int type; int mask_len; @@ -449,13 +447,11 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, addr = buf; pastend = buf + buf_size; - family = *(const uint8_t *) addr; - ++addr; - type = *(const uint8_t *) addr; + family = *addr++; + type = *addr++; ++addr; ++addr; /* skip b_reserved_z fields */ - mask_len = *(const uint8_t *) addr; - ++addr; + mask_len = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: @@ -503,12 +499,12 @@ int pim_parse_addr_source(const char *ifname, struct in_addr src_addr, struct prefix *p, uint8_t *flags, - const char *buf, + const uint8_t *buf, int buf_size) { const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ - const char *addr; - const char *pastend; + const uint8_t *addr; + const uint8_t *pastend; int family; int type; int mask_len; @@ -526,14 +522,10 @@ int pim_parse_addr_source(const char *ifname, addr = buf; pastend = buf + buf_size; - family = *(const uint8_t *) addr; - ++addr; - type = *(const uint8_t *) addr; - ++addr; - *flags = *(const uint8_t *) addr; - ++addr; - mask_len = *(const uint8_t *) addr; - ++addr; + family = *addr++; + type = *addr++; + *flags = *addr++; + mask_len = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: @@ -607,10 +599,10 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, - const char *tlv_curr) + const uint8_t *tlv_curr) { - const char *addr; - const char *pastend; + const uint8_t *addr; + const uint8_t *pastend; zassert(hello_option_addr_list); diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index 5ec3dc43b..b802cf897 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -71,63 +71,63 @@ typedef uint32_t pim_hello_options; #define PIM_TLV_MIN_SIZE (PIM_TLV_TYPE_SIZE + PIM_TLV_LENGTH_SIZE) #define PIM_TLV_OPTION_SIZE(option_len) (PIM_TLV_MIN_SIZE + (option_len)) -char *pim_tlv_append_uint16(uint8_t *buf, - const uint8_t *buf_pastend, - uint16_t option_type, - uint16_t option_value); -char *pim_tlv_append_2uint16(uint8_t *buf, - const uint8_t *buf_pastend, - uint16_t option_type, - uint16_t option_value1, - uint16_t option_value2); -char *pim_tlv_append_uint32(uint8_t *buf, - const uint8_t *buf_pastend, - uint16_t option_type, - uint32_t option_value); -char *pim_tlv_append_addrlist_ucast(uint8_t *buf, - const uint8_t *buf_pastend, - struct list *ifconnected); +uint8_t *pim_tlv_append_uint16(uint8_t *buf, + const uint8_t *buf_pastend, + uint16_t option_type, + uint16_t option_value); +uint8_t *pim_tlv_append_2uint16(uint8_t *buf, + const uint8_t *buf_pastend, + uint16_t option_type, + uint16_t option_value1, + uint16_t option_value2); +uint8_t *pim_tlv_append_uint32(uint8_t *buf, + const uint8_t *buf_pastend, + uint16_t option_type, + uint32_t option_value); +uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, + const uint8_t *buf_pastend, + struct list *ifconnected); int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, - const char *tlv_curr); + const uint8_t *tlv_curr); int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, - const char *tlv_curr); + const uint8_t *tlv_curr); int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, - const char *tlv_curr); + const uint8_t *tlv_curr); int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, - const char *tlv_curr); + const uint8_t *tlv_curr); int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, - const char *tlv_curr); + const uint8_t *tlv_curr); int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, struct prefix *p, - const char *buf, + const uint8_t *buf, int buf_size); int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, struct prefix *p, - const char *buf, + const uint8_t *buf, int buf_size); int pim_parse_addr_source(const char *ifname, struct in_addr src_addr, struct prefix *p, uint8_t *flags, - const char *buf, + const uint8_t *buf, int buf_size); #endif /* PIM_TLV_H */ From 105ad8615da1bcb417e1757ef4787cd2cdbb3cbc Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 16 Feb 2012 04:50:35 +0000 Subject: [PATCH 0510/1342] pimd: fix wtf code * pim_hello.c, * pim_neighbor.c: print pointers as %p * pim_time.c: comment out unused function * pim_zebra.c: wtf --- pimd/pim_hello.c | 4 ++-- pimd/pim_neighbor.c | 4 ++-- pimd/pim_time.c | 2 ++ pimd/pim_zebra.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 73c50d4fb..94e7c945f 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -124,12 +124,12 @@ static void tlv_trace_list(const char *label, const char *tlv_name, if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%x", + zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p", label, src_str, ifname, tlv_name, addr_list ? ((int) listcount(addr_list)) : -1, - (unsigned) addr_list); + (void *) addr_list); } } diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 0df742213..51ce8c9a3 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -689,8 +689,8 @@ void pim_neighbor_update(struct pim_neighbor *neigh, if (neigh->prefix_list == addr_list) { if (addr_list) { - zlog_err("%s: internal error: trying to replace same prefix list=%u", - __PRETTY_FUNCTION__, (unsigned) addr_list); + zlog_err("%s: internal error: trying to replace same prefix list=%p", + __PRETTY_FUNCTION__, (void *) addr_list); } } else { diff --git a/pimd/pim_time.c b/pimd/pim_time.c index 7d4581d99..b884efc7d 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -30,6 +30,7 @@ #include "pim_time.h" +#if 0 static int pim_gettime(int clk_id, struct timeval *tv) { struct timespec ts; @@ -58,6 +59,7 @@ static int pim_gettime(int clk_id, struct timeval *tv) return result; } +#endif static int gettime_monotonic(struct timeval *tv) { diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index e18b7ac92..74a60a5fc 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -548,7 +548,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, } api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? - api.distance = stream_getc(s) : + stream_getc(s) : 0; api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? From 3de4ae90586e4a99ab706c5d3726ef1d5aef95c0 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 13 Feb 2014 14:28:26 -0200 Subject: [PATCH 0511/1342] Define pim_gettime() when PIM_GETTIME_USE_GETTIMEOFDAY is not available. --- pimd/pim_time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_time.c b/pimd/pim_time.c index b884efc7d..fce30c080 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -30,7 +30,7 @@ #include "pim_time.h" -#if 0 +#ifndef PIM_GETTIME_USE_GETTIMEOFDAY static int pim_gettime(int clk_id, struct timeval *tv) { struct timespec ts; From a057a066aa258a0f9cf3ae4946ec66adcd2f28f7 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 17 Jan 2012 23:52:58 +0000 Subject: [PATCH 0512/1342] pimd: extend .gitignore --- pimd/.gitignore | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pimd/.gitignore b/pimd/.gitignore index 7046d69c8..51a2ac87e 100644 --- a/pimd/.gitignore +++ b/pimd/.gitignore @@ -1,7 +1,16 @@ -.libs -*.a -*.o +Makefile +Makefile.in +libpim.a pimd test_igmpv3_join - - +tags +TAGS +.deps +*.o +*.lo +*.la +*.libs +.arch-inventory +.arch-ids +*~ +*.loT From c77f01b9c9056bf39a62911218b308cdb11c4718 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 13 Feb 2014 14:54:43 -0200 Subject: [PATCH 0513/1342] PIM_ZCLIENT_DEBUG enables zclient_socket() / zclient_socket_un() debug --- pimd/pim_zlookup.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 98548e79f..112ff2615 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -51,6 +51,8 @@ static int zclient_lookup_connect(struct thread *t) return 0; } +#ifdef PIM_ZCLIENT_DEBUG + #ifdef HAVE_TCP_ZEBRA zlog_debug("%s: FIXME blocking connect: zclient_socket()", __PRETTY_FUNCTION__); @@ -77,6 +79,17 @@ static int zclient_lookup_connect(struct thread *t) } #endif /* HAVE_TCP_ZEBRA */ +#else + + zlog_debug("%s: FIXME blocking connect: zclient_socket_connect()", + __PRETTY_FUNCTION__); + if (zclient_socket_connect(zlookup) < 0) { + zlog_warn("%s: failure connecting zclient socket", + __PRETTY_FUNCTION__); + } + +#endif /* PIM_ZCLIENT_DEBUG */ + zassert(!zlookup->t_connect); if (zlookup->sock < 0) { /* Since last connect failed, retry within 10 secs */ From 3defeb3465a1f6e7a50d0f2b3d292686bb1449b1 Mon Sep 17 00:00:00 2001 From: Klemen Sladic Date: Fri, 7 Feb 2014 16:23:44 +1300 Subject: [PATCH 0514/1342] fix address assigment --- pimd/pim_cmd.c | 2 +- pimd/pim_igmpv3.c | 3 ++- pimd/pim_msg.c | 6 +++--- pimd/pim_tlv.c | 9 +++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index f046801de..d2f9eb896 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3515,7 +3515,7 @@ DEFUN (test_igmp_receive_report, *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET) = htons(1); /* one group record */ *(uint8_t *) (group_record + IGMP_V3_GROUP_RECORD_TYPE_OFFSET) = record_type; - *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET) = grp_addr; + memcpy(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, &grp_addr, sizeof(struct in_addr)); /* Scan LINE sources */ sources = (struct in_addr *) (group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET); diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index f8926524e..4be52d607 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1649,7 +1649,8 @@ void pim_igmp_send_membership_query(struct igmp_group *group, query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY; query_buf[1] = max_resp_code; *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ - *(struct in_addr *)(query_buf + 4) = group_addr; + memcpy(query_buf+4, &group_addr, sizeof(struct in_addr)); + query_buf[8] = (s_flag << 3) | querier_robustness_variable; query_buf[9] = qqic; *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources); diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 7eb63e857..79ae33ac8 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -62,7 +62,7 @@ uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ - *(struct in_addr *)(buf + 2) = addr; + memcpy(buf+2, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_UCAST_SIZE; } @@ -81,7 +81,7 @@ uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, buf[1] = '\0'; /* native encoding */ buf[2] = '\0'; /* reserved */ buf[3] = 32; /* mask len */ - *(struct in_addr *)(buf + 4) = addr; + memcpy(buf+4, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_GROUP_SIZE; } @@ -100,7 +100,7 @@ uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, buf[1] = '\0'; /* native encoding */ buf[2] = 4; /* reserved = 0 | S bit = 1 | W bit = 0 | R bit = 0 */ buf[3] = 32; /* mask len */ - *(struct in_addr *)(buf + 4) = addr; + memcpy(buf+4, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_SOURCE_SIZE; } diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 4ce9a3d22..962c2b87c 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -148,7 +148,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, ++curr; *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ ++curr; - *(struct in_addr *) curr = p->u.prefix4; + memcpy(curr, &p->u.prefix4, sizeof(struct in_addr)); curr += sizeof(struct in_addr); option_len += ucast_ipv4_encoding_len; @@ -404,7 +404,8 @@ int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ - p->u.prefix4 = *(const struct in_addr *) addr; + memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); + addr += sizeof(struct in_addr); break; @@ -475,7 +476,7 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ - p->u.prefix4 = *(const struct in_addr *) addr; + memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); p->prefixlen = mask_len; addr += sizeof(struct in_addr); @@ -549,7 +550,7 @@ int pim_parse_addr_source(const char *ifname, } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ - p->u.prefix4 = *(const struct in_addr *) addr; + memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); p->prefixlen = mask_len; /* From d4595869045498d830be34403217822f77446ae0 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 13 Feb 2014 19:50:30 -0200 Subject: [PATCH 0515/1342] Parsing fixes. --- pimd/pim_igmp.c | 20 ++++++++++++++------ pimd/pim_join.c | 15 +++++++++++++++ pimd/pim_tlv.c | 12 +++++++----- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 6ad521ca0..03cf3cd1b 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -288,7 +288,8 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, uint16_t checksum; int i; - group_addr = *(struct in_addr *)(igmp_msg + 4); + //group_addr = *(struct in_addr *)(igmp_msg + 4); + memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); ifp = igmp->interface; pim_ifp = ifp->info; @@ -421,8 +422,12 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, /* Scan sources in query and lower their timers to LMQT */ struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET); for (i = 0; i < recv_num_sources; ++i) { - struct in_addr src_addr = sources[i]; - struct igmp_source *src = igmp_find_source_by_addr(group, src_addr); + //struct in_addr src_addr = sources[i]; + //struct igmp_source *src = igmp_find_source_by_addr(group, src_addr); + struct in_addr src_addr; + struct igmp_source *src; + memcpy(&src_addr, sources + i, sizeof(struct in_addr)); + src = igmp_find_source_by_addr(group, src_addr); if (src) { igmp_source_timer_lower_to_lmqt(src); } @@ -506,7 +511,8 @@ static int igmp_v3_report(struct igmp_sock *igmp, rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET]; rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET)); - rec_group = *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET); + //rec_group = *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET); + memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr)); if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s", @@ -599,7 +605,8 @@ static int igmp_v2_report(struct igmp_sock *igmp, __FILE__, __PRETTY_FUNCTION__); } - group_addr = *(struct in_addr *)(igmp_msg + 4); + //group_addr = *(struct in_addr *)(igmp_msg + 4); + memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); @@ -655,7 +662,8 @@ static int igmp_v1_report(struct igmp_sock *igmp, __FILE__, __PRETTY_FUNCTION__); } - group_addr = *(struct in_addr *)(igmp_msg + 4); + //group_addr = *(struct in_addr *)(igmp_msg + 4); + memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 5230bb6c9..9d8e0012e 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -129,6 +129,11 @@ int pim_joinprune_recv(struct interface *ifp, addr_offset = pim_parse_addr_ucast(ifp->name, src_addr, &msg_upstream_addr, buf, pastend - buf); +#if 0 + zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d", + __PRETTY_FUNCTION__, + addr_offset); +#endif if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); @@ -194,6 +199,11 @@ int pim_joinprune_recv(struct interface *ifp, addr_offset = pim_parse_addr_group(ifp->name, src_addr, &msg_group_addr, buf, pastend - buf); +#if 0 + zlog_warn("%s: pim_parse_addr_group addr_offset=%d", + __PRETTY_FUNCTION__, + addr_offset); +#endif if (addr_offset < 1) { return -5; } @@ -236,6 +246,11 @@ int pim_joinprune_recv(struct interface *ifp, &msg_source_addr, &msg_source_flags, buf, pastend - buf); +#if 0 + zlog_warn("%s: pim_parse_addr_source addr_offset=%d", + __PRETTY_FUNCTION__, + addr_offset); +#endif if (addr_offset < 1) { return -7; } diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 962c2b87c..95ee5ab0e 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -450,7 +450,7 @@ int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, family = *addr++; type = *addr++; - ++addr; + //++addr; ++addr; /* skip b_reserved_z fields */ mask_len = *addr++; @@ -533,9 +533,10 @@ int pim_parse_addr_source(const char *ifname, if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown source address encoding type=%d from %s on %s", + zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, - type, src_str, ifname); + type, src_str, ifname, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -2; } @@ -578,9 +579,10 @@ int pim_parse_addr_source(const char *ifname, { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: unknown source address encoding family=%d from %s on %s", + zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, - family, src_str, ifname); + family, src_str, ifname, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -5; } } From 777fe1f2b63c76d0df5c136dbd335bd2718785fb Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 14 Feb 2014 14:16:07 -0200 Subject: [PATCH 0516/1342] Run DR election when hello packet is received. --- pimd/pim_cmd.c | 5 +++-- pimd/pim_iface.c | 2 +- pimd/pim_iface.h | 1 + pimd/pim_neighbor.c | 9 +++++---- pimd/pim_pim.c | 18 +++++++++++++----- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index d2f9eb896..c89f2b5a3 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -563,7 +563,7 @@ static void pim_show_dr(struct vty *vty) "NonPri: Number of neighbors missing DR Priority hello option%s%s", VTY_NEWLINE, VTY_NEWLINE); - vty_out(vty, "Interface Address DR Uptime Elections NonPri%s", VTY_NEWLINE); + vty_out(vty, "Interface Address DR Uptime Elections Changes NonPri%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; @@ -587,12 +587,13 @@ static void pim_show_dr(struct vty *vty) pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_str, sizeof(dr_str)); - vty_out(vty, "%-9s %-15s %-15s %8s %9d %6d%s", + vty_out(vty, "%-9s %-15s %-15s %8s %9d %7d %6d%s", ifp->name, inet_ntoa(ifaddr), dr_str, dr_uptime, pim_ifp->pim_dr_election_count, + pim_ifp->pim_dr_election_changes, pim_ifp->pim_dr_num_nondrpri_neighbors, VTY_NEWLINE); } diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index f0c326617..72626eca3 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -226,7 +226,7 @@ static void pim_addr_change(struct interface *ifp) pim_ifp = ifp->info; zassert(pim_ifp); - pim_if_dr_election(ifp); /* Done TODO T30 */ + pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */ pim_if_update_join_desired(pim_ifp); /* depends on DR */ pim_if_update_could_assert(ifp); /* depends on DR */ pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 0a702c27a..6a2f7c958 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -87,6 +87,7 @@ struct pim_interface { /* DR Election */ int64_t pim_dr_election_last; /* timestamp */ int pim_dr_election_count; + int pim_dr_election_changes; struct in_addr pim_dr_addr; uint32_t pim_dr_priority; /* config */ int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 51ce8c9a3..7d7b43a69 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -132,7 +132,8 @@ void pim_if_dr_election(struct interface *ifp) zlog_info("%s: DR was %s now is %s on interface %s", __PRETTY_FUNCTION__, dr_old_str, dr_new_str, ifp->name); - + + ++pim_ifp->pim_dr_election_changes; pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); @@ -191,7 +192,7 @@ static void update_dr_priority(struct pim_neighbor *neigh, PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ - pim_if_dr_election(neigh->interface); + pim_if_dr_election(neigh->interface); // router's own DR Priority changes } } @@ -226,7 +227,7 @@ static int on_neighbor_timer(struct thread *t) PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ - pim_if_dr_election(ifp); + pim_if_dr_election(ifp); // neighbor times out return 0; } @@ -347,7 +348,7 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ - pim_if_dr_election(neigh->interface); + pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election... /* RFC 4601: 4.3.1. Sending Hello Messages diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 8dd71d668..4fda26ec0 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -208,10 +208,14 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) } if (pim_type == PIM_MSG_TYPE_HELLO) { - return pim_hello_recv(ifp, - ip_hdr->ip_src, - pim_msg + PIM_MSG_HEADER_LEN, - pim_msg_len - PIM_MSG_HEADER_LEN); + int result = pim_hello_recv(ifp, + ip_hdr->ip_src, + pim_msg + PIM_MSG_HEADER_LEN, + pim_msg_len - PIM_MSG_HEADER_LEN); + if (!result) { + pim_if_dr_election(ifp); /* PIM Hello message is received */ + } + return result; } neigh = pim_neighbor_find(ifp, ip_hdr->ip_src); @@ -324,7 +328,10 @@ static int pim_sock_read(struct thread *t) } #endif - if (pim_pim_packet(ifp, buf, len)) { + int fail = pim_pim_packet(ifp, buf, len); + if (fail) { + zlog_warn("%s: pim_pim_packet() return=%d", + __PRETTY_FUNCTION__, fail); goto done; } @@ -429,6 +436,7 @@ void pim_sock_reset(struct interface *ifp) /* DR Election */ pim_ifp->pim_dr_election_last = 0; /* timestamp */ pim_ifp->pim_dr_election_count = 0; + pim_ifp->pim_dr_election_changes = 0; pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */ pim_ifp->pim_dr_addr = pim_ifp->primary_address; From f24200d77a98c8091d23638096faf366e7c6c953 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 14 Feb 2014 16:40:34 -0200 Subject: [PATCH 0517/1342] C18 MFC never recovers from removal of static route to source --- pimd/CAVEATS | 24 +++++++++ pimd/COMMANDS | 2 + pimd/pim_cmd.c | 128 ++++++++++++++++++++++++++++++++-------------- pimd/pim_mroute.c | 6 +++ pimd/pim_zebra.c | 7 ++- pimd/pim_zebra.h | 2 + pimd/pimd.c | 6 +++ pimd/pimd.h | 6 +++ 8 files changed, 141 insertions(+), 40 deletions(-) diff --git a/pimd/CAVEATS b/pimd/CAVEATS index c436d552a..05a439b8a 100644 --- a/pimd/CAVEATS +++ b/pimd/CAVEATS @@ -134,4 +134,28 @@ C16 AMT Draft (mboned-auto-multicast) is not supported. C17 SNMP / RFC 5060 (PIM MIB) is not supported. +C18 MFC never recovers from removal of static route to source + + # route add -host 1.2.3.4 gw 192.168.56.10 + Before removal: + quagga-pimd-router# sh ip mroute + Source Group Proto Input iVifI Output oVifI TTL Uptime + 1.2.3.4 232.1.2.3 I eth1 3 eth0 2 1 00:00:36 + + # route del -host 1.2.3.4 gw 192.168.56.10 + After removal: sh ip mroute --> empty output + + # route add -host 1.2.3.4 gw 192.168.56.10 + After the route is restored: sh ip mroute --> never recovers (empty output) + + At this point, "no ip pim ssm" on the upstream interface (eth0) crashes pimd: + + 2014/02/14 16:30:14 PIM: ifmembership_set: (S,G)=(1.2.3.4,232.1.2.3) membership now is NOINFO on interface eth0 + 2014/02/14 16:30:14 PIM: pim_ifchannel_update_assert_tracking_desired: AssertTrackingDesired(1.2.3.4,232.1.2.3,eth0) changed from 1 to 0 + 2014/02/14 16:30:14 PIM: pim_zebra.c del_oif: nonexistent protocol mask 2 removed OIF eth0 (vif_index=2, min_ttl=0) from channel (S,G)=(1.2.3.4,232.1.2.3) + 2014/02/14 16:30:14 PIM: pim_ifchannel_update_could_assert: CouldAssert(1.2.3.4,232.1.2.3,eth0) changed from 1 to 0 + 2014/02/14 16:30:14 PIM: pim_ifchannel_update_my_assert_metric: my_assert_metric(1.2.3.4,232.1.2.3,eth0) changed from 0,0,0,10.0.2.15 to 1,4294967295,4294967295,0.0.0.0 + 2014/02/14 16:30:14 PIM: pim_zebra.c del_oif: nonexistent protocol mask 1 removed OIF eth0 (vif_index=2, min_ttl=0) from channel (S,G)=(1.2.3.4,232.1.2.3) + 2014/02/14 16:30:14 PIM: Assertion `!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)' failed in file pim_igmpv3.c, line 412, function igmp_source_delete + -x- diff --git a/pimd/COMMANDS b/pimd/COMMANDS index fb09e6c92..6210bb434 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -47,7 +47,9 @@ verification commands: debug commands: clear ip interfaces Reset interfaces clear ip igmp interfaces Reset IGMP interfaces + clear ip mroute Reset multicast routes clear ip pim interfaces Reset PIM interfaces + clear ip pim oil Rescan PIM OIL (output interface list) debug igmp IGMP protocol activity debug mroute PIM interaction with kernel MFC cache debug pim PIM protocol activity diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index c89f2b5a3..25a567fe9 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -49,6 +49,7 @@ #include "pim_rpf.h" #include "pim_macro.h" #include "pim_ssmpingd.h" +#include "pim_zebra.h" static struct cmd_node pim_global_node = { PIM_NODE, @@ -1097,6 +1098,25 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now) refresh_uptime, VTY_NEWLINE); } +static void show_scan_oil_stats(struct vty *vty, time_t now) +{ + char uptime_scan_oil[10]; + char uptime_mroute_add[10]; + char uptime_mroute_del[10]; + + pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now, qpim_scan_oil_last); + pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now, qpim_mroute_add_last); + pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now, qpim_mroute_del_last); + + vty_out(vty, + "Scan OIL - Last: %s Events: %lld%s" + "MFC Add - Last: %s Events: %lld%s" + "MFC Del - Last: %s Events: %lld%s", + uptime_scan_oil, (long long) qpim_scan_oil_events, VTY_NEWLINE, + uptime_mroute_add, (long long) qpim_mroute_add_events, VTY_NEWLINE, + uptime_mroute_del, (long long) qpim_mroute_del_events, VTY_NEWLINE); +} + static void pim_show_rpf(struct vty *vty) { struct listnode *up_node; @@ -1576,6 +1596,57 @@ DEFUN (clear_ip_igmp_interfaces, return CMD_SUCCESS; } +static void mroute_add_all() +{ + struct listnode *node; + struct channel_oil *c_oil; + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + if (pim_mroute_add(&c_oil->oil)) { + /* just log warning */ + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } +} + +static void mroute_del_all() +{ + struct listnode *node; + struct channel_oil *c_oil; + + for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { + if (pim_mroute_del(&c_oil->oil)) { + /* just log warning */ + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } +} + +DEFUN (clear_ip_mroute, + clear_ip_mroute_cmd, + "clear ip mroute", + CLEAR_STR + IP_STR + "Reset multicast routes\n") +{ + mroute_del_all(); + mroute_add_all(); + + return CMD_SUCCESS; +} + DEFUN (clear_ip_pim_interfaces, clear_ip_pim_interfaces_cmd, "clear ip pim interfaces", @@ -1589,6 +1660,19 @@ DEFUN (clear_ip_pim_interfaces, return CMD_SUCCESS; } +DEFUN (clear_ip_pim_oil, + clear_ip_pim_oil_cmd, + "clear ip pim oil", + CLEAR_STR + IP_STR + CLEAR_IP_PIM_STR + "Rescan PIM OIL (output interface list)\n") +{ + pim_scan_oil(); + + return CMD_SUCCESS; +} + DEFUN (show_ip_igmp_interface, show_ip_igmp_interface_cmd, "show ip igmp interface", @@ -2026,6 +2110,10 @@ DEFUN (show_ip_multicast, show_rpf_refresh_stats(vty, now); + vty_out(vty, "%s", VTY_NEWLINE); + + show_scan_oil_stats(vty, now); + show_multicast_interfaces(vty); return CMD_SUCCESS; @@ -2258,44 +2346,6 @@ DEFUN (show_ip_ssmpingd, return CMD_SUCCESS; } -static void mroute_add_all() -{ - struct listnode *node; - struct channel_oil *c_oil; - - for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { - if (pim_mroute_add(&c_oil->oil)) { - /* just log warning */ - char source_str[100]; - char group_str[100]; - pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); - pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); - zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", - __FILE__, __PRETTY_FUNCTION__, - source_str, group_str); - } - } -} - -static void mroute_del_all() -{ - struct listnode *node; - struct channel_oil *c_oil; - - for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { - if (pim_mroute_del(&c_oil->oil)) { - /* just log warning */ - char source_str[100]; - char group_str[100]; - pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); - pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); - zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", - __FILE__, __PRETTY_FUNCTION__, - source_str, group_str); - } - } -} - DEFUN (ip_multicast_routing, ip_multicast_routing_cmd, PIM_CMD_IP_MULTICAST_ROUTING, @@ -4268,7 +4318,9 @@ void pim_cmd_init() install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); + install_element (ENABLE_NODE, &clear_ip_mroute_cmd); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); + install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd); install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); install_element (ENABLE_NODE, &show_ip_igmp_join_cmd); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index d88373625..fa460e28f 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -399,6 +399,9 @@ int pim_mroute_add(struct mfcctl *mc) { int err; + qpim_mroute_add_last = pim_time_monotonic_sec(); + ++qpim_mroute_add_events; + if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); @@ -424,6 +427,9 @@ int pim_mroute_del(struct mfcctl *mc) { int err; + qpim_mroute_del_last = pim_time_monotonic_sec(); + ++qpim_mroute_del_events; + if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 74a60a5fc..820b0efc1 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -353,12 +353,15 @@ static void scan_upstream_rpf_cache() } -static void scan_oil() +void pim_scan_oil() { struct listnode *node; struct listnode *nextnode; struct channel_oil *c_oil; + qpim_scan_oil_last = pim_time_monotonic_sec(); + ++qpim_scan_oil_events; + for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) { int old_vif_index; int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin); @@ -445,7 +448,7 @@ static int on_rpf_cache_refresh(struct thread *t) scan_upstream_rpf_cache(); /* update kernel multicast forwarding cache (MFC) */ - scan_oil(); + pim_scan_oil(); qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index e0c9bdcb3..474e7a2e7 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -28,6 +28,8 @@ void pim_zebra_init(void); +void pim_scan_oil(void); + void igmp_anysource_forward_start(struct igmp_group *group); void igmp_anysource_forward_stop(struct igmp_group *group); diff --git a/pimd/pimd.c b/pimd/pimd.c index 71b74e972..49ddc212a 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -61,6 +61,12 @@ int64_t qpim_rpf_cache_refresh_last = 0; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list = 0; struct in_addr qpim_ssmpingd_group_addr; +int64_t qpim_scan_oil_events = 0; +int64_t qpim_scan_oil_last = 0; +int64_t qpim_mroute_add_events = 0; +int64_t qpim_mroute_add_last = 0; +int64_t qpim_mroute_del_events = 0; +int64_t qpim_mroute_del_last = 0; static void pim_free() { diff --git a/pimd/pimd.h b/pimd/pimd.h index e11d5bad4..099008888 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -90,6 +90,12 @@ int64_t qpim_rpf_cache_refresh_last; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ struct in_addr qpim_ssmpingd_group_addr; +int64_t qpim_scan_oil_events; +int64_t qpim_scan_oil_last; +int64_t qpim_mroute_add_events; +int64_t qpim_mroute_add_last; +int64_t qpim_mroute_del_events; +int64_t qpim_mroute_del_last; #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) From d1a87ee63042225d4b3bf6b4655cd7e0e2b64828 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 14 Feb 2014 16:51:05 -0200 Subject: [PATCH 0518/1342] Fix pim join uptime display. --- pimd/pim_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 25a567fe9..eaf6afe6c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -728,7 +728,7 @@ static void pim_show_join(struct vty *vty) pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); - pim_time_uptime(uptime, sizeof(uptime), now - ch->ifjoin_creation); + pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation); pim_time_timer_to_mmss(expire, sizeof(expire), ch->t_ifjoin_expiry_timer); pim_time_timer_to_mmss(prune, sizeof(prune), From 1f7a2b44687a49e4dab649ce369b5735aa2dd20f Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 1 Apr 2014 18:38:50 -0300 Subject: [PATCH 0519/1342] github repository. --- doc/pimd.8 | 4 ++-- pimd/README | 4 ++-- pimd/github-git-clone.sh | 27 +++++++++++++++++++++++++++ pimd/pimd.h | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) create mode 100755 pimd/github-git-clone.sh diff --git a/doc/pimd.8 b/doc/pimd.8 index b26b11284..3995cfe4a 100644 --- a/doc/pimd.8 +++ b/doc/pimd.8 @@ -100,9 +100,9 @@ production use. .B pimd eats bugs for breakfast. If you have food for the maintainers try -.BI http://savannah.nongnu.org/projects/qpimd +.BI https://github.com/udhos/qpimd .SH AUTHORS See -.BI http://savannah.nongnu.org/projects/qpimd +.BI https://github.com/udhos/qpimd for an accurate list of authors. diff --git a/pimd/README b/pimd/README index f6bd8ec69..1e3f72c83 100644 --- a/pimd/README +++ b/pimd/README @@ -38,7 +38,7 @@ HOME SITE qpimd lives at: - http://savannah.nongnu.org/projects/qpimd + https://github.com/udhos/qpimd PLATFORMS @@ -124,7 +124,7 @@ SUPPORT Please post comments, questions, patches, bug reports at the support site: - http://savannah.nongnu.org/projects/qpimd + https://github.com/udhos/qpimd RELATED WORK diff --git a/pimd/github-git-clone.sh b/pimd/github-git-clone.sh new file mode 100755 index 000000000..ea359b031 --- /dev/null +++ b/pimd/github-git-clone.sh @@ -0,0 +1,27 @@ +#! /bin/bash +# +# Github Developer Git Checkout +# +# Delete remote branch qpimd: git push origin :qpimd +# (git push origin :refs/heads/branch_to_delete) +# Delete remote tag v0.139: git push origin :v0.139 +# (git push origin :refs/tags/tag_to_delete) +# Create remote-tracking branch: git checkout -b pim0.142 origin/pim0.142 +# Rename branch qpimd to pim: git branch -m qpimd pim +# Commit changes: git commit -a +# Send changes: git push --all +# +# Recipe to re-sync with Quagga repository: +# git clone https://github.com/udhos/qpimd +# cd qpimd +# git checkout master +# git pull git clone http://git.sv.gnu.org/r/quagga.git master +# git checkout -b pim origin/pim +# git rebase master pim +# # Test, then push back into Github repository: +# git push origin :pim ;# delete remote branch pim +# git push --all +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +git clone https://github.com/udhos/qpimd diff --git a/pimd/pimd.h b/pimd/pimd.h index 099008888..68b11994e 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -31,7 +31,7 @@ #define PIMD_PROGNAME "pimd" #define PIMD_DEFAULT_CONFIG "pimd.conf" #define PIMD_VTY_PORT 2611 -#define PIMD_BUG_ADDRESS "http://savannah.nongnu.org/projects/qpimd" +#define PIMD_BUG_ADDRESS "https://github.com/udhos/qpimd" #define PIM_IP_HEADER_MIN_LEN (20) #define PIM_IP_HEADER_MAX_LEN (60) From 069a0208ec10fca53676ec187f958037108363a6 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 2 Apr 2014 11:04:52 -0300 Subject: [PATCH 0520/1342] Fixed recipe to re-sync with Quagga repository --- pimd/github-git-clone.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pimd/github-git-clone.sh b/pimd/github-git-clone.sh index ea359b031..ae2362a73 100755 --- a/pimd/github-git-clone.sh +++ b/pimd/github-git-clone.sh @@ -12,10 +12,10 @@ # Send changes: git push --all # # Recipe to re-sync with Quagga repository: -# git clone https://github.com/udhos/qpimd -# cd qpimd +# git clone https://github.com/udhos/qpimd quagga +# cd quagga # git checkout master -# git pull git clone http://git.sv.gnu.org/r/quagga.git master +# git pull http://git.sv.gnu.org/r/quagga.git master # git checkout -b pim origin/pim # git rebase master pim # # Test, then push back into Github repository: From 60353ab4b0857d3f416e315fd81568d9e60205c4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 2 Apr 2014 11:46:45 -0300 Subject: [PATCH 0521/1342] C19 Provision to prevent group mode clash --- pimd/CAVEATS | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pimd/CAVEATS b/pimd/CAVEATS index 05a439b8a..b1f1a0392 100644 --- a/pimd/CAVEATS +++ b/pimd/CAVEATS @@ -158,4 +158,20 @@ C18 MFC never recovers from removal of static route to source 2014/02/14 16:30:14 PIM: pim_zebra.c del_oif: nonexistent protocol mask 1 removed OIF eth0 (vif_index=2, min_ttl=0) from channel (S,G)=(1.2.3.4,232.1.2.3) 2014/02/14 16:30:14 PIM: Assertion `!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)' failed in file pim_igmpv3.c, line 412, function igmp_source_delete +C19 Provision to prevent group mode clash + + Beware group mode clash. A host/application issuing IGMPv2 + any-source joins for a group will disrupt SSM multicast for that + group. + + For instance, support for source-specific static igmp WILL FAIL if + there is host/application issuing IGMPv2 any-source joins for the + same group. + + The reason is the IGMPv2 any-source join forces qpimd to switch + the group mode to ASM (any-source multicast); however, qpimd is + unable to program ASM groups into the kernel; multicast won't + flow. There could be some provision to prevent such a behavior, + but currently there is none. + -x- From 829198800217fe321faa397d21e2d8f99fcaf0dd Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 25 Jun 2014 13:25:17 -0300 Subject: [PATCH 0522/1342] pimd: Rename script with recipe for git cloning --- pimd/{github-git-clone.sh => git-clone-github.sh} | 0 pimd/{savannah-git-clone.sh => git-clone-savannah.sh} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename pimd/{github-git-clone.sh => git-clone-github.sh} (100%) rename pimd/{savannah-git-clone.sh => git-clone-savannah.sh} (100%) diff --git a/pimd/github-git-clone.sh b/pimd/git-clone-github.sh similarity index 100% rename from pimd/github-git-clone.sh rename to pimd/git-clone-github.sh diff --git a/pimd/savannah-git-clone.sh b/pimd/git-clone-savannah.sh similarity index 100% rename from pimd/savannah-git-clone.sh rename to pimd/git-clone-savannah.sh From ff57d3653efe4a1428147204b54cacf3651c4dd0 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 25 Jun 2014 15:54:03 -0300 Subject: [PATCH 0523/1342] pimd: Fixes to build against current quagga. --- configure.ac | 1 + doc/Makefile.am | 2 ++ lib/zclient.c | 2 +- lib/zclient.h | 1 + lib/zebra.h | 16 ++-------------- pimd/Makefile.am | 6 +++++- pimd/pim_main.c | 1 - pimd/pim_signals.c | 5 +++-- 8 files changed, 15 insertions(+), 19 deletions(-) diff --git a/configure.ac b/configure.ac index 7696bd70b..6632e5437 100755 --- a/configure.ac +++ b/configure.ac @@ -1369,6 +1369,7 @@ case "${enable_pimd}" in "no" ) PIMD="";; * ) ;; esac +AM_CONDITIONAL(PIMD, test "x$PIMD" = "xpimd") # XXX Perhaps auto-enable on Solaris, but that's messy for cross builds. case "${enable_solaris}" in diff --git a/doc/Makefile.am b/doc/Makefile.am index 8869c818e..dfc5e402c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -61,6 +61,8 @@ quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ .dia.png: $(DIATOPNG) "$@" $< +man_MANS = + if PIMD man_MANS += pimd.8 endif diff --git a/lib/zclient.c b/lib/zclient.c index 3b5477e90..709d9b983 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -148,7 +148,7 @@ zclient_reset (struct zclient *zclient) #ifdef HAVE_TCP_ZEBRA /* Make socket to zebra daemon. Return zebra socket. */ -static int +int zclient_socket(void) { int sock; diff --git a/lib/zclient.h b/lib/zclient.h index a660bbf19..b0b764440 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -132,6 +132,7 @@ extern void zclient_stop (struct zclient *); extern void zclient_reset (struct zclient *); extern void zclient_free (struct zclient *); +extern int zclient_socket(void); extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); diff --git a/lib/zebra.h b/lib/zebra.h index 67d714cf8..57e591ff5 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -435,20 +435,8 @@ struct in_pktinfo */ #define ZEBRA_HEADER_MARKER 255 -/* Zebra route's types. */ -#define ZEBRA_ROUTE_SYSTEM 0 -#define ZEBRA_ROUTE_KERNEL 1 -#define ZEBRA_ROUTE_CONNECT 2 -#define ZEBRA_ROUTE_STATIC 3 -#define ZEBRA_ROUTE_RIP 4 -#define ZEBRA_ROUTE_RIPNG 5 -#define ZEBRA_ROUTE_OSPF 6 -#define ZEBRA_ROUTE_OSPF6 7 -#define ZEBRA_ROUTE_ISIS 8 -#define ZEBRA_ROUTE_BGP 9 -#define ZEBRA_ROUTE_HSLS 10 -#define ZEBRA_ROUTE_PIM 11 -#define ZEBRA_ROUTE_MAX 12 +/* Zebra route's types are defined in route_types.h */ +#include "route_types.h" /* Note: whenever a new route-type or zserv-command is added the * corresponding {command,route}_types[] table in lib/log.c MUST be diff --git a/pimd/Makefile.am b/pimd/Makefile.am index ef5cffa11..70c5096c6 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -45,7 +45,11 @@ PIM_DEFS += -DPIM_GETTIME_USE_GETTIMEOFDAY INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 -LIBS = @LIBS@ +LIBS = @LIBS@ + +AM_CFLAGS = $(PICFLAGS) +AM_LDFLAGS = $(PILDFLAGS) + noinst_LIBRARIES = libpim.a sbin_PROGRAMS = pimd bin_PROGRAMS = test_igmpv3_join diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 51e5e360b..64d7787d9 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -201,7 +201,6 @@ int main(int argc, char** argv, char** envp) { memory_init(); access_list_init(); pim_init(); - sort_node(); /* * reset zlog default, then will obey configuration file diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c index 1b146f6f2..d1350b08b 100644 --- a/pimd/pim_signals.c +++ b/pimd/pim_signals.c @@ -24,6 +24,7 @@ #include #include "sigevent.h" +#include "memory.h" #include "log.h" #include "pim_signals.h" @@ -58,7 +59,7 @@ static void pim_sigusr1() zlog_rotate (NULL); } -struct quagga_signal_t pimd_signals[] = +static struct quagga_signal_t pimd_signals[] = { { .signal = SIGHUP, @@ -80,6 +81,6 @@ struct quagga_signal_t pimd_signals[] = void pim_signals_init() { - signal_init(master, Q_SIGC(pimd_signals), pimd_signals); + signal_init(master, array_size(pimd_signals), pimd_signals); } From 82e6c730e624e86c00042b64fc32170630b2c18c Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 25 Jun 2014 17:28:04 -0300 Subject: [PATCH 0524/1342] pimd: Reset DR uptime only on actual change --- pimd/pim_neighbor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 7d7b43a69..66d895e9a 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -111,7 +111,6 @@ void pim_if_dr_election(struct interface *ifp) struct pim_interface *pim_ifp = ifp->info; struct in_addr old_dr_addr; - pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_count; old_dr_addr = pim_ifp->pim_dr_addr; @@ -133,6 +132,7 @@ void pim_if_dr_election(struct interface *ifp) __PRETTY_FUNCTION__, dr_old_str, dr_new_str, ifp->name); + pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_changes; pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); From 04c833a1e0fbf063f49ff0b9f837b07456580374 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 19:35:24 -0300 Subject: [PATCH 0525/1342] pimd: Query mrib (SAFI_MULTICAST). --- pimd/pim_zlookup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 112ff2615..1492f7c33 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -230,7 +230,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, } command = stream_getw(s); - if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_V2) { + if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); return -5; @@ -369,7 +369,7 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup, s = zlookup->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_V2); + zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); stream_put_in_addr(s, &addr); stream_putw_at(s, 0, stream_get_endp(s)); From 5c55a496fae5ab089c5009bc4c03084fdeb51f55 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 2 Jul 2014 12:12:16 -0300 Subject: [PATCH 0526/1342] pimd: Cosmetic fix for dr uptime display. --- pimd/pim_cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index eaf6afe6c..90ca07c09 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -582,8 +582,8 @@ static void pim_show_dr(struct vty *vty) ifaddr = pim_ifp->primary_address; - pim_time_uptime(dr_uptime, sizeof(dr_uptime), - now - pim_ifp->pim_dr_election_last); + pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), + now, pim_ifp->pim_dr_election_last); pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_str, sizeof(dr_str)); From f62a19cc281276607b164c99e672d536a012514d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 3 Jul 2014 14:53:44 -0300 Subject: [PATCH 0527/1342] zebra: Export zclient_socket_un(). --- lib/zclient.c | 2 +- lib/zclient.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index 709d9b983..c3a4905f9 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -184,7 +184,7 @@ zclient_socket(void) /* For sockaddr_un. */ #include -static int +int zclient_socket_un (const char *path) { int ret; diff --git a/lib/zclient.h b/lib/zclient.h index b0b764440..6a5e6268c 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -133,6 +133,7 @@ extern void zclient_reset (struct zclient *); extern void zclient_free (struct zclient *); extern int zclient_socket(void); +extern int zclient_socket_un (const char *path); extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); From 2f1df6a58b9f0a278cbdee9fc57f964eef1c7bf7 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 3 Jul 2014 15:37:52 -0300 Subject: [PATCH 0528/1342] pimd: Version up to 0.164 --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 22888c53d..73711367b 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.163" +#define PIMD_VERSION_STR "0.164" const char * const PIMD_VERSION; From 6f40e6b74effb7447854f690a2a4fa9339d8a967 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 11 Jul 2014 14:16:45 -0300 Subject: [PATCH 0529/1342] pimd: Fix compiler warnings. --- pimd/pim_cmd.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 90ca07c09..9363e3c98 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1006,7 +1006,6 @@ static void pim_show_join_desired(struct vty *vty) struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; - struct in_addr me_ifaddr; char src_str[100]; char grp_str[100]; @@ -1020,8 +1019,6 @@ static void pim_show_join_desired(struct vty *vty) if (!pim_ifp) continue; - me_ifaddr = pim_ifp->primary_address; - /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, chnode, ch)) { struct pim_upstream *up = ch->upstream; @@ -1249,9 +1246,6 @@ static void igmp_show_group_retransmission(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; - time_t now; - - now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Group RetTimer Counter RetSrcs%s", VTY_NEWLINE); @@ -1446,9 +1440,6 @@ static void igmp_show_source_retransmission(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; - time_t now; - - now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Group Source Counter%s", VTY_NEWLINE); From 6c1d36a462388039f92b875196c4d1c92ae69644 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 14:15:04 -0300 Subject: [PATCH 0530/1342] pimd: Clean-up. --- pimd/COMMANDS | 11 +++++++++++ pimd/pim_igmpv3.c | 15 --------------- pimd/pim_upstream.c | 3 --- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 6210bb434..425ac8229 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -1,10 +1,15 @@ # $QuaggaId: $Format:%an, %ai, %h$ $ global configuration commands: + pimd: ip multicast-routing Enable IP multicast forwarding ip ssmpingd Enable ssmpingd operation + zebra: + ip mroute Configure static unicast route into MRIB for multicast RPF lookup + interface configuration commands: + pimd: ip igmp Enable IGMP operation ip igmp join IGMP join multicast group ip igmp query-interval <1-1800> IGMP host query interval @@ -13,6 +18,7 @@ interface configuration commands: ip pim ssm Enable PIM SSM operation verification commands: + pimd: show ip igmp interface IGMP interface information show ip igmp join IGMP static join information show ip igmp parameters IGMP parameters information @@ -44,7 +50,11 @@ verification commands: show ip rib IP unicast routing table show ip ssmpingd ssmpingd operation + zebra: + show ip rpf Display RPF information for multicast source + debug commands: + pimd: clear ip interfaces Reset interfaces clear ip igmp interfaces Reset IGMP interfaces clear ip mroute Reset multicast routes @@ -65,6 +75,7 @@ debug commands: test pim receive upcall Test reception of kernel upcall statistics commands: + pimd: show memory pim PIM memory statistics -x- diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 4be52d607..3da1dd1ec 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -529,12 +529,9 @@ static void allow(struct igmp_sock *igmp, struct in_addr from, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct pim_interface *pim_ifp; struct igmp_group *group; int i; - pim_ifp = ifp->info; - /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { @@ -673,14 +670,11 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct pim_interface *pim_ifp; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); - pim_ifp = ifp->info; - /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { @@ -800,14 +794,11 @@ void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct pim_interface *pim_ifp; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); - pim_ifp = ifp->info; - /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { @@ -955,14 +946,11 @@ void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct pim_interface *pim_ifp; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); - pim_ifp = ifp->info; - /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { @@ -1480,14 +1468,11 @@ void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct pim_interface *pim_ifp; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); - pim_ifp = ifp->info; - /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 6702ca139..d02f91548 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -256,7 +256,6 @@ static void forward_on(struct pim_upstream *up) struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; - struct in_addr ifaddr; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { @@ -264,8 +263,6 @@ static void forward_on(struct pim_upstream *up) if (!pim_ifp) continue; - ifaddr = pim_ifp->primary_address; - /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { From e4f2a2bef879d9e7f5c4c80994c44772b09beb59 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 16 Jul 2014 12:19:40 -0300 Subject: [PATCH 0531/1342] pimd: Report first route's metric/distance for recursive RPF lookup. --- pimd/pim_zlookup.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 1492f7c33..be0499e31 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -402,6 +402,8 @@ int zclient_lookup_nexthop(struct zclient *zlookup, int max_lookup) { int lookup; + uint32_t route_metric = 0xFFFFFFFF; + uint8_t protocol_distance = 0xFF; for (lookup = 0; lookup < max_lookup; ++lookup) { int num_ifindex; @@ -418,6 +420,12 @@ int zclient_lookup_nexthop(struct zclient *zlookup, lookup, max_lookup, addr_str); return -1; } + + if (lookup < 1) { + /* this is the non-recursive lookup - save original metric/distance */ + route_metric = nexthop_tab[0].route_metric; + protocol_distance = nexthop_tab[0].protocol_distance; + } /* FIXME: Non-recursive nexthop ensured only for first ifindex. @@ -433,12 +441,18 @@ int zclient_lookup_nexthop(struct zclient *zlookup, /* Report non-recursive success after first lookup */ char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s", + zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, - lookup, max_lookup, first_ifindex, addr_str); + lookup, max_lookup, first_ifindex, addr_str, + nexthop_tab[0].protocol_distance, + nexthop_tab[0].route_metric); /* use last address as nexthop address */ nexthop_tab[0].nexthop_addr = addr; + + /* report original route metric/distance */ + nexthop_tab[0].route_metric = route_metric; + nexthop_tab[0].protocol_distance = protocol_distance; } return num_ifindex; @@ -449,9 +463,11 @@ int zclient_lookup_nexthop(struct zclient *zlookup, char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_addr, nexthop_str, sizeof(nexthop_str)); - zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s", + zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, - lookup, max_lookup, nexthop_str, addr_str); + lookup, max_lookup, nexthop_str, addr_str, + nexthop_tab[0].protocol_distance, + nexthop_tab[0].route_metric); } addr = nexthop_addr; /* use nexthop addr for recursive lookup */ From f6e16b9f3592a3213e94f44b71caa311e0270cd9 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 16 Jul 2014 14:13:47 -0300 Subject: [PATCH 0532/1342] pimd: Document MRIB support. --- pimd/CAVEATS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pimd/CAVEATS b/pimd/CAVEATS index b1f1a0392..ba6426dd0 100644 --- a/pimd/CAVEATS +++ b/pimd/CAVEATS @@ -82,9 +82,9 @@ C11 SSM Mapping is not supported is changed, or when the DNS mapping changes, the router will leave the current sources associated with the joined groups. -C12 MRIB for incongruent unicast/multicast topologies is not supported. - RPF mechanism currently just looks up the information in the - unicast routing table. +C12 FIXED MRIB for incongruent unicast/multicast topologies is not + supported. RPF mechanism currently just looks up the information + in the unicast routing table. See also: RFC5110: 2.2.3. Issue: Overlapping Unicast/Multicast Topology From 306c99eae67a7966a3994be1007f03665eb6682b Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 16 Jul 2014 15:51:37 -0300 Subject: [PATCH 0533/1342] pimd: FIXED C14 T32 Detection of interface primary address changes may fail. --- pimd/CAVEATS | 4 ++-- pimd/TODO | 4 ++-- pimd/pim_iface.c | 37 ++++++++++++++++++++++++++++++++----- pimd/pim_zebra.c | 38 +++++++++++++++++++++++++++++++------- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/pimd/CAVEATS b/pimd/CAVEATS index ba6426dd0..7e2820b3b 100644 --- a/pimd/CAVEATS +++ b/pimd/CAVEATS @@ -109,8 +109,8 @@ C13 Can't detect change of primary address before the actual change. See also pim_sock_delete(). -C14 Detection of interface primary address changes may fail when there - are multiple addresses. +C14 FIXED Detection of interface primary address changes may fail when + there are multiple addresses. See also TODO T32. C15 Changes in interface secondary address list are not immediately diff --git a/pimd/TODO b/pimd/TODO index 3a3330d39..80835e460 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -267,8 +267,8 @@ T31 If an interface changes one of its secondary IP addresses, a Hello See also CAVEAT C15. See also RFC 4601: 4.3.1. Sending Hello Messages -T32 Detection of interface primary address changes may fail when there - are multiple addresses. +T32 FIXED Detection of interface primary address changes may fail when + there are multiple addresses. See also CAVEAT C14. pim_find_primary_addr() should return interface primary address diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 72626eca3..3dee75192 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -286,6 +286,7 @@ static void detect_primary_address_change(struct interface *ifp, { struct pim_interface *pim_ifp; struct in_addr new_prim_addr; + int changed; pim_ifp = ifp->info; if (!pim_ifp) @@ -293,17 +294,20 @@ static void detect_primary_address_change(struct interface *ifp, new_prim_addr = pim_find_primary_addr(ifp); + changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; + if (PIM_DEBUG_ZEBRA) { char new_prim_str[100]; char old_prim_str[100]; pim_inet4_dump("", new_prim_addr, new_prim_str, sizeof(new_prim_str)); pim_inet4_dump("", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str)); - zlog_debug("%s: old primary addr %s, new primary addr %s on interface %s", + zlog_debug("%s: old=%s new=%s on interface %s: %s", __PRETTY_FUNCTION__, - old_prim_str, new_prim_str, ifp->name); + old_prim_str, new_prim_str, ifp->name, + changed ? "changed" : "unchanged"); } - if (new_prim_addr.s_addr != pim_ifp->primary_address.s_addr) { + if (changed) { struct in_addr old_addr = pim_ifp->primary_address; pim_ifp->primary_address = new_prim_addr; @@ -328,6 +332,16 @@ void pim_if_addr_add(struct connected *ifc) if (!if_is_operative(ifp)) return; + if (PIM_DEBUG_ZEBRA) { + char buf[BUFSIZ]; + prefix2str(ifc->address, buf, BUFSIZ); + zlog_debug("%s: %s connected IP address %s %s", + __PRETTY_FUNCTION__, + ifp->name, buf, + CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? + "secondary" : "primary"); + } + ifaddr = ifc->address->u.prefix4; detect_primary_address_change(ifp, __PRETTY_FUNCTION__); @@ -437,6 +451,16 @@ void pim_if_addr_del(struct connected *ifc) ifp = ifc->ifp; zassert(ifp); + if (PIM_DEBUG_ZEBRA) { + char buf[BUFSIZ]; + prefix2str(ifc->address, buf, BUFSIZ); + zlog_debug("%s: %s disconnected IP address %s %s", + __PRETTY_FUNCTION__, + ifp->name, buf, + CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? + "secondary" : "primary"); + } + detect_primary_address_change(ifp, __PRETTY_FUNCTION__); pim_if_addr_del_igmp(ifc); @@ -523,7 +547,7 @@ void pim_if_addr_del_all_pim(struct interface *ifp) } } -static struct in_addr find_first_addr(struct interface *ifp) +static struct in_addr find_first_nonsec_addr(struct interface *ifp) { struct connected *ifc; struct listnode *node; @@ -541,6 +565,9 @@ static struct in_addr find_first_addr(struct interface *ifp) continue; } + if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) + continue; + return p->u.prefix4; } @@ -551,7 +578,7 @@ static struct in_addr find_first_addr(struct interface *ifp) struct in_addr pim_find_primary_addr(struct interface *ifp) { - return find_first_addr(ifp); + return find_first_nonsec_addr(ifp); } /* diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 820b0efc1..f0aa84f0c 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -203,10 +203,12 @@ static void dump_if_address(struct interface *ifp) if (p->family != AF_INET) continue; - zlog_debug("%s %s: interface %s address %s", + zlog_debug("%s %s: interface %s address %s %s", __FILE__, __PRETTY_FUNCTION__, ifp->name, - inet_ntoa(p->u.prefix4)); + inet_ntoa(p->u.prefix4), + CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? + "secondary" : "primary"); } } #endif @@ -238,15 +240,36 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); - zlog_debug("%s: %s connected IP address %s flags %u", + zlog_debug("%s: %s connected IP address %s flags %u %s", __PRETTY_FUNCTION__, - c->ifp->name, buf, c->flags); + c->ifp->name, buf, c->flags, + CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); #endif } + if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { + /* trying to add primary address */ + + struct in_addr primary_addr = pim_find_primary_addr(c->ifp); + if (primary_addr.s_addr != p->u.prefix4.s_addr) { + /* but we had a primary address already */ + + char buf[BUFSIZ]; + char old[100]; + + prefix2str(p, buf, BUFSIZ); + pim_inet4_dump("", primary_addr, old, sizeof(old)); + + zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s", + __PRETTY_FUNCTION__, + c->ifp->name, old, buf); + SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); + } + } + pim_if_addr_add(c); return 0; @@ -279,15 +302,16 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); - zlog_debug("%s: %s disconnected IP address %s flags %u", + zlog_debug("%s: %s disconnected IP address %s flags %u %s", __PRETTY_FUNCTION__, - c->ifp->name, buf, c->flags); + c->ifp->name, buf, c->flags, + CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); #endif } - + pim_if_addr_del(c); return 0; From 075ac8ddbd6aa782619565a97ec474a90f1b6f4c Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 24 Sep 2014 15:18:37 -0300 Subject: [PATCH 0534/1342] pimd: Prevent interfaces' addresses duplication when zebra connection is restored. --- pimd/pim_iface.c | 2 +- pimd/pim_zebra.c | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 3dee75192..8ceecf853 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -565,7 +565,7 @@ static struct in_addr find_first_nonsec_addr(struct interface *ifp) continue; } - if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) + if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) continue; return p->u.prefix4; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index f0aa84f0c..6bef43e90 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -24,6 +24,7 @@ #include "zebra/rib.h" +#include "if.h" #include "log.h" #include "prefix.h" #include "zclient.h" @@ -50,15 +51,32 @@ static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask); +static void reset_iface_addresses() { + struct listnode *ifnode; + struct interface *ifp; + + zlog_warn("%s %s: resetting all interface addresses", + __FILE__, __PRETTY_FUNCTION__); + + for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { + if_connected_reset(ifp); + } +} + /* Router-id update message from zebra. */ static int pim_router_id_update_zebra(int command, struct zclient *zclient, zebra_size_t length) { struct prefix router_id; - /* FIXME: actually use router_id for anything ? */ zebra_router_id_update_read(zclient->ibuf, &router_id); + zlog_info("zebra router id update"); + + /* Prevent interfaces' addresses duplication when zebra connection + is restored */ + reset_iface_addresses(); + return 0; } From d96ab32b6fce23907f0c5f35760a2b7410724d95 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 17:59:13 -0300 Subject: [PATCH 0535/1342] pimd: Update configure recipe. --- pimd/quagga-configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/quagga-configure.sh b/pimd/quagga-configure.sh index 45d7be086..f351cdc9f 100755 --- a/pimd/quagga-configure.sh +++ b/pimd/quagga-configure.sh @@ -7,4 +7,4 @@ # # $QuaggaId: $Format:%an, %ai, %h$ $ -./configure --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 --enable-vtysh +./configure --disable-babeld --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 --enable-vtysh From b24c7fed49a861562bfb713db70ed1db2b89ff42 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 18:00:15 -0300 Subject: [PATCH 0536/1342] zebra_rib: Revert debug hooks. --- zebra/zebra_rib.c | 95 +++++------------------------------------------ 1 file changed, 10 insertions(+), 85 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d6ec9147b..c6dbdec51 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -496,17 +496,6 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, break; } - if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET6_ADDRSTRLEN]; - inet_ntop(rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug("%s: %s/%d: nexthop match %p: %s type=%d sel=%d int=%d", - __func__, buf, rn->p.prefixlen, match, - match ? zebra_route_string(match->type) : "", - match ? match->type : -1, - match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED) : -1, - match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_INTERNAL) : -1); - } - /* If there is no selected route or matched route is EGP, go up tree. */ if (! match @@ -537,6 +526,11 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || match->type == ZEBRA_ROUTE_KERNEL) + /* + || match->type == ZEBRA_ROUTE_KERNEL + This prevents zebra from marking recursive static route as inactive. + See pimd/TODO T26. + */ { resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) @@ -1054,43 +1048,6 @@ rib_match_ipv6 (struct in6_addr *addr) } #endif /* HAVE_IPV6 */ -static void nexthop_dump(struct nexthop *nexthop, - char *type_str_buf, - int type_str_buf_size, - char *addr_str_buf, - int addr_str_buf_size, - char *via_str_buf, - int via_str_buf_size) -{ - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - snprintf(type_str_buf, type_str_buf_size, "ipv4"); - snprintf(addr_str_buf, addr_str_buf_size, "%s", inet_ntoa(nexthop->gate.ipv4)); - snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifindex ? ifindex2ifname(nexthop->ifindex) : ""); - break; - case NEXTHOP_TYPE_IFINDEX: - snprintf(type_str_buf, type_str_buf_size, "connected"); - snprintf(addr_str_buf, addr_str_buf_size, ""); - snprintf(via_str_buf, via_str_buf_size, "%s", ifindex2ifname(nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFNAME: - snprintf(type_str_buf, type_str_buf_size, "connected"); - snprintf(addr_str_buf, addr_str_buf_size, ""); - snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifname); - break; - case NEXTHOP_TYPE_BLACKHOLE: - snprintf(type_str_buf, type_str_buf_size, "blackhole"); - snprintf(addr_str_buf, addr_str_buf_size, ""); - snprintf(via_str_buf, via_str_buf_size, "Null0"); - break; - default: - snprintf(type_str_buf, type_str_buf_size, "unknown"); - snprintf(addr_str_buf, addr_str_buf_size, ""); - snprintf(via_str_buf, via_str_buf_size, ""); - } -} - #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -1145,27 +1102,10 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - { - int nh_active = nexthop_active_ipv4 (rib, nexthop, set, rn); - if (IS_ZEBRA_DEBUG_RIB) { - char type_str_buf[100]; - char addr_str_buf[100]; - char via_str_buf[100]; - nexthop_dump(nexthop, - type_str_buf, sizeof(type_str_buf), - addr_str_buf, sizeof(addr_str_buf), - via_str_buf, sizeof(via_str_buf)); - zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d nexthop_active_ipv4=%d", - __func__, rib, nexthop, - nexthop->type, type_str_buf, - addr_str_buf, via_str_buf, nexthop->ifindex, - nh_active); - } - if (nh_active) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - } + if (nexthop_active_ipv4 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: @@ -1256,23 +1196,8 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; - new_active = nexthop_active_check (rn, rib, nexthop, set); - if (new_active) + if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) rib->nexthop_active_num++; - if (IS_ZEBRA_DEBUG_RIB) { - char type_str_buf[100]; - char addr_str_buf[100]; - char via_str_buf[100]; - nexthop_dump(nexthop, - type_str_buf, sizeof(type_str_buf), - addr_str_buf, sizeof(addr_str_buf), - via_str_buf, sizeof(via_str_buf)); - zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d act=%d total_act=%d", - __func__, rib, nexthop, - nexthop->type, type_str_buf, - addr_str_buf, via_str_buf, nexthop->ifindex, - new_active, rib->nexthop_active_num); - } if (prev_active != new_active || prev_index != nexthop->ifindex) SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); From 2a0ecf21d6c0918da92033fbe4741ede63f108f2 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 18:18:26 -0300 Subject: [PATCH 0537/1342] pimd: Withstand zclient connection restablishment. --- pimd/pim_zebra.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 6bef43e90..e080c04f3 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -51,16 +51,19 @@ static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask); -static void reset_iface_addresses() { +static void zclient_broken(struct zclient *zclient) +{ struct listnode *ifnode; struct interface *ifp; - zlog_warn("%s %s: resetting all interface addresses", + zlog_warn("%s %s: broken zclient connection", __FILE__, __PRETTY_FUNCTION__); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { - if_connected_reset(ifp); + pim_if_addr_del_all(ifp); } + + /* upon return, zclient will discard connected addresses */ } /* Router-id update message from zebra. */ @@ -71,12 +74,6 @@ static int pim_router_id_update_zebra(int command, struct zclient *zclient, zebra_router_id_update_read(zclient->ibuf, &router_id); - zlog_info("zebra router id update"); - - /* Prevent interfaces' addresses duplication when zebra connection - is restored */ - reset_iface_addresses(); - return 0; } @@ -330,7 +327,7 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, #endif } - pim_if_addr_del(c); + pim_if_addr_del(c, 0); return 0; } @@ -659,6 +656,7 @@ void pim_zebra_init() /* Socket for receiving updates from Zebra daemon */ zclient = zclient_new(); + zclient->router_id_update = pim_router_id_update; zclient->router_id_update = pim_router_id_update_zebra; zclient->interface_add = pim_zebra_if_add; zclient->interface_delete = pim_zebra_if_del; From b240297cfea37f7a6608cac9fd2ae4848fe88e3f Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 18:29:29 -0300 Subject: [PATCH 0538/1342] pimd: Detection of interface primary address changes. --- pimd/pim_iface.c | 14 +++++++++----- pimd/pim_iface.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 8ceecf853..fdbb79beb 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -282,6 +282,7 @@ static void on_primary_address_change(struct interface *ifp, } static void detect_primary_address_change(struct interface *ifp, + int force_prim_as_any, const char *caller) { struct pim_interface *pim_ifp; @@ -292,7 +293,10 @@ static void detect_primary_address_change(struct interface *ifp, if (!pim_ifp) return; - new_prim_addr = pim_find_primary_addr(ifp); + if (force_prim_as_any) + new_prim_addr = qpim_inaddr_any; + else + new_prim_addr = pim_find_primary_addr(ifp); changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; @@ -344,7 +348,7 @@ void pim_if_addr_add(struct connected *ifc) ifaddr = ifc->address->u.prefix4; - detect_primary_address_change(ifp, __PRETTY_FUNCTION__); + detect_primary_address_change(ifp, 0, __PRETTY_FUNCTION__); if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; @@ -443,7 +447,7 @@ static void pim_if_addr_del_pim(struct connected *ifc) pim_sock_delete(ifc->ifp, "last address has been removed from interface"); } -void pim_if_addr_del(struct connected *ifc) +void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) { struct interface *ifp; @@ -461,7 +465,7 @@ void pim_if_addr_del(struct connected *ifc) "secondary" : "primary"); } - detect_primary_address_change(ifp, __PRETTY_FUNCTION__); + detect_primary_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); pim_if_addr_del_igmp(ifc); pim_if_addr_del_pim(ifc); @@ -503,7 +507,7 @@ void pim_if_addr_del_all(struct interface *ifp) if (p->family != AF_INET) continue; - pim_if_addr_del(ifc); + pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */); } } diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 6a2f7c958..4b06b9ff2 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -113,7 +113,7 @@ void pim_if_init(void); struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); void pim_if_delete(struct interface *ifp); void pim_if_addr_add(struct connected *ifc); -void pim_if_addr_del(struct connected *ifc); +void pim_if_addr_del(struct connected *ifc, int force_prim_as_any); void pim_if_addr_add_all(struct interface *ifp); void pim_if_addr_del_all(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp); From d96f9ffaeac6ebb5b897c318b82fcb37c3ee81c2 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 22 Jul 2014 14:24:49 -0300 Subject: [PATCH 0539/1342] pimd: Recipe for building without vtysh. --- pimd/quagga-build-no-vtysh.sh | 10 ++++++++++ pimd/quagga-configure-no-vtysh.sh | 10 ++++++++++ pimd/quagga-configure.sh | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100755 pimd/quagga-build-no-vtysh.sh create mode 100755 pimd/quagga-configure-no-vtysh.sh diff --git a/pimd/quagga-build-no-vtysh.sh b/pimd/quagga-build-no-vtysh.sh new file mode 100755 index 000000000..22e084e71 --- /dev/null +++ b/pimd/quagga-build-no-vtysh.sh @@ -0,0 +1,10 @@ +#! /bin/bash +# +# Build minimum Quagga needed for pimd. +# +# Run from quagga's top dir as: +# ./pimd/quagga-build.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +./pimd/quagga-memtypes.sh && ./pimd/quagga-bootstrap.sh && ./pimd/quagga-configure-no-vtysh.sh && make diff --git a/pimd/quagga-configure-no-vtysh.sh b/pimd/quagga-configure-no-vtysh.sh new file mode 100755 index 000000000..72caefb49 --- /dev/null +++ b/pimd/quagga-configure-no-vtysh.sh @@ -0,0 +1,10 @@ +#! /bin/bash +# +# Configure for minimum Quagga build needed for pimd. +# +# Run from quagga's top dir as: +# . pimd/quagga-configure.sh +# +# $QuaggaId: $Format:%an, %ai, %h$ $ + +./configure --disable-babeld --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 diff --git a/pimd/quagga-configure.sh b/pimd/quagga-configure.sh index f351cdc9f..72329eb90 100755 --- a/pimd/quagga-configure.sh +++ b/pimd/quagga-configure.sh @@ -7,4 +7,4 @@ # # $QuaggaId: $Format:%an, %ai, %h$ $ -./configure --disable-babeld --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 --enable-vtysh +tail -1 ./pimd/quagga-configure-no-vtysh.sh --enable-vtysh From ee61109c045f3c9960ec52912ebdbb8998ac63a1 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 22 Jul 2014 14:27:54 -0300 Subject: [PATCH 0540/1342] pimd: Fix comment --- pimd/quagga-build-no-vtysh.sh | 2 +- pimd/quagga-configure-no-vtysh.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/quagga-build-no-vtysh.sh b/pimd/quagga-build-no-vtysh.sh index 22e084e71..7136f6705 100755 --- a/pimd/quagga-build-no-vtysh.sh +++ b/pimd/quagga-build-no-vtysh.sh @@ -3,7 +3,7 @@ # Build minimum Quagga needed for pimd. # # Run from quagga's top dir as: -# ./pimd/quagga-build.sh +# ./pimd/quagga-build-no-vtysh.sh # # $QuaggaId: $Format:%an, %ai, %h$ $ diff --git a/pimd/quagga-configure-no-vtysh.sh b/pimd/quagga-configure-no-vtysh.sh index 72caefb49..b3052dceb 100755 --- a/pimd/quagga-configure-no-vtysh.sh +++ b/pimd/quagga-configure-no-vtysh.sh @@ -3,7 +3,7 @@ # Configure for minimum Quagga build needed for pimd. # # Run from quagga's top dir as: -# . pimd/quagga-configure.sh +# ./pimd/quagga-configure-no-vtysh.sh # # $QuaggaId: $Format:%an, %ai, %h$ $ From 3456a80f5f8e6e44c30453bd92eabf5faf7ab25b Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 22 Jul 2014 14:52:57 -0300 Subject: [PATCH 0541/1342] pimd: clear zclient-update: Reset zclient update connection to zebra daemon --- pimd/COMMANDS | 1 + pimd/pim_cmd.c | 13 +++++++++++++ pimd/pim_zebra.c | 37 ++++++++++++++++++------------------- pimd/pimd.c | 1 + pimd/pimd.h | 1 + 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 425ac8229..2dedea064 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -60,6 +60,7 @@ debug commands: clear ip mroute Reset multicast routes clear ip pim interfaces Reset PIM interfaces clear ip pim oil Rescan PIM OIL (output interface list) + clear zclient-update Reset zclient update connection to zebra daemon debug igmp IGMP protocol activity debug mroute PIM interaction with kernel MFC cache debug pim PIM protocol activity diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 9363e3c98..a49264a3b 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -27,6 +27,7 @@ #include "command.h" #include "if.h" #include "prefix.h" +#include "zclient.h" #include "pimd.h" #include "pim_cmd.h" @@ -1562,6 +1563,17 @@ DEFUN (pim_interface, return CMD_SUCCESS; } +DEFUN (clear_zclient_update, + clear_zclient_update_cmd, + "clear zclient-update", + CLEAR_STR + "Reset zclient update connection to zebra daemon\n") +{ + zclient_reset(qpim_zclient_update); + + return CMD_SUCCESS; +} + DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, "clear ip interfaces", @@ -4312,6 +4324,7 @@ void pim_cmd_init() install_element (ENABLE_NODE, &clear_ip_mroute_cmd); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd); + install_element (ENABLE_NODE, &clear_zclient_update_cmd); install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); install_element (ENABLE_NODE, &show_ip_igmp_join_cmd); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index e080c04f3..44046dbb1 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -644,7 +644,6 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, void pim_zebra_init() { - struct zclient *zclient; int i; #ifdef HAVE_TCP_ZEBRA @@ -654,35 +653,35 @@ void pim_zebra_init() #endif /* Socket for receiving updates from Zebra daemon */ - zclient = zclient_new(); - - zclient->router_id_update = pim_router_id_update; - zclient->router_id_update = pim_router_id_update_zebra; - zclient->interface_add = pim_zebra_if_add; - zclient->interface_delete = pim_zebra_if_del; - zclient->interface_up = pim_zebra_if_state_up; - zclient->interface_down = pim_zebra_if_state_down; - zclient->interface_address_add = pim_zebra_if_address_add; - zclient->interface_address_delete = pim_zebra_if_address_del; - zclient->ipv4_route_add = redist_read_ipv4_route; - zclient->ipv4_route_delete = redist_read_ipv4_route; - - zclient_init(zclient, ZEBRA_ROUTE_PIM); + qpim_zclient_update = zclient_new(); + + qpim_zclient_update->zclient_broken = zclient_broken; + qpim_zclient_update->router_id_update = pim_router_id_update_zebra; + qpim_zclient_update->interface_add = pim_zebra_if_add; + qpim_zclient_update->interface_delete = pim_zebra_if_del; + qpim_zclient_update->interface_up = pim_zebra_if_state_up; + qpim_zclient_update->interface_down = pim_zebra_if_state_down; + qpim_zclient_update->interface_address_add = pim_zebra_if_address_add; + qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del; + qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route; + qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route; + + zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); zlog_info("zclient_init cleared redistribution request"); - zassert(zclient->redist_default == ZEBRA_ROUTE_PIM); + zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM); /* Request all redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (i == zclient->redist_default) + if (i == qpim_zclient_update->redist_default) continue; - zclient->redist[i] = 1; + qpim_zclient_update->redist[i] = 1; zlog_info("%s: requesting redistribution for %s (%i)", __PRETTY_FUNCTION__, zebra_route_string(i), i); } /* Request default information */ - zclient->default_information = 1; + qpim_zclient_update->default_information = 1; zlog_info("%s: requesting default information redistribution", __PRETTY_FUNCTION__); diff --git a/pimd/pimd.c b/pimd/pimd.c index 49ddc212a..855defcc7 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -51,6 +51,7 @@ int qpim_mroute_oif_highest_vif_index = -1; struct list *qpim_channel_oil_list = 0; int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ struct list *qpim_upstream_list = 0; +struct zclient *qpim_zclient_update = 0; struct zclient *qpim_zclient_lookup = 0; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec = 10000; diff --git a/pimd/pimd.h b/pimd/pimd.h index 68b11994e..b0a1b648d 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -80,6 +80,7 @@ struct list *qpim_channel_oil_list; /* list of struct channel_oil * struct in_addr qpim_all_pim_routers_addr; int qpim_t_periodic; /* Period between Join/Prune Messages */ struct list *qpim_upstream_list; /* list of struct pim_upstream */ +struct zclient *qpim_zclient_update; struct zclient *qpim_zclient_lookup; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec; From df838e2abd9727109cba559c6429ee4da82f863c Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 25 Jul 2014 15:38:00 -0300 Subject: [PATCH 0542/1342] pimd: Better assert state transition message. --- pimd/pim_assert.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 6b062b77d..b742223ce 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -66,17 +66,19 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, ch->interface->name); } - { + if (winner_changed) { char src_str[100]; char grp_str[100]; + char was_str[100]; char winner_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", ch->ifassert_winner, was_str, sizeof(was_str)); pim_inet4_dump("", winner, winner_str, sizeof(winner_str)); - zlog_info("%s: (S,G)=(%s,%s) assert winner now is %s on interface %s", + zlog_info("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, - winner_str, ch->interface->name); + was_str, winner_str, ch->interface->name); } ch->ifassert_state = new_state; From cf800dd0f9f2ae58efedc6af4e39ae6c0d99f873 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 19 Aug 2014 12:01:52 -0300 Subject: [PATCH 0543/1342] pimd: Version up. --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 73711367b..68ab76934 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.164" +#define PIMD_VERSION_STR "0.165" const char * const PIMD_VERSION; From 9830ce2ef715a79c691866b83526d1025e47082d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 19 Aug 2014 12:16:11 -0300 Subject: [PATCH 0544/1342] pimd: Why ssm. --- pimd/WHY_SSM | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 pimd/WHY_SSM diff --git a/pimd/WHY_SSM b/pimd/WHY_SSM new file mode 100644 index 000000000..a84697196 --- /dev/null +++ b/pimd/WHY_SSM @@ -0,0 +1,24 @@ +WHY SSM + +Benefis of PIM SSM over PIM SM +------------------------------ + +- SSM consumes minimum link bandwidth +- SSM simplifies multicast address management (specially important for + inter-domain multicast) +- SSM does not suffer instabilities from traffic-driven SPT switchover +- SSM does not use RP. Some RP issues: + - RP is possible point of failure + - RP demands redundancy management + - RP may require PIM dense mode support for RP election + - RP is possible performance bottleneck + - RP may demand lots of extra management + +PIM-SSM drawbacks +----------------- + +- SSM requires IGMPv3 support on receivers +- SSM may be memory intensive when managing (S,G) states for + many-to-many multicast distribution + +--EOF-- From 7cb0d4a384b4964cc53b61549ffdef37fb0d76c5 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 19 Aug 2014 13:44:37 -0300 Subject: [PATCH 0545/1342] pimd: Cisco Documentation for SSM Benefits --- pimd/WHY_SSM | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pimd/WHY_SSM b/pimd/WHY_SSM index a84697196..6ff8f1343 100644 --- a/pimd/WHY_SSM +++ b/pimd/WHY_SSM @@ -6,19 +6,32 @@ Benefis of PIM SSM over PIM SM - SSM consumes minimum link bandwidth - SSM simplifies multicast address management (specially important for inter-domain multicast) + - SSM (S,G) channels easily provide unique per-application addressing + - SSM does not require MSDP between PIM domains - SSM does not suffer instabilities from traffic-driven SPT switchover +- SSM is not suscetible to DoS attack from unwanted sources - SSM does not use RP. Some RP issues: - RP is possible point of failure - RP demands redundancy management - RP may require PIM dense mode support for RP election - RP is possible performance bottleneck - RP may demand lots of extra management +- SSM can be deployed in an existing PIM SM network (only the last hop + routers need to support IGMPv3) +- SSM is easier to deploy and maintain PIM-SSM drawbacks ----------------- -- SSM requires IGMPv3 support on receivers +- SSM requires IGMPv3 support on both receivers and last-hop routers - SSM may be memory intensive when managing (S,G) states for many-to-many multicast distribution +- SSM will keep (S,G) state as long as there are subscriptions from + receivers, even if the source is not actually sending traffic + +Cisco Documentation for SSM Benefits +------------------------------------ + +http://www.cisco.com/c/en/us/td/docs/ios/12_2/ip/configuration/guide/fipr_c/1cfssm.html#wp1000969 --EOF-- From 1f298949bea9e58623eb81f245491dcdb1df8c59 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 21 Aug 2014 15:47:28 -0300 Subject: [PATCH 0546/1342] pimd: -z command-line switch to specify zebra socket path. --- doc/pimd.8 | 17 +++++++++++++++++ lib/zclient.c | 7 ++++++- lib/zclient.h | 1 + pimd/pim_main.c | 10 ++++++++-- pimd/pim_zebra.c | 7 +++++-- pimd/pim_zebra.h | 2 +- pimd/pim_zlookup.c | 23 +++++++++++++---------- 7 files changed, 51 insertions(+), 16 deletions(-) diff --git a/doc/pimd.8 b/doc/pimd.8 index 3995cfe4a..0dd170a2c 100644 --- a/doc/pimd.8 +++ b/doc/pimd.8 @@ -12,6 +12,9 @@ pimd \- a PIM routing for use with Quagga Routing Suite. .B \-i .I pid-file ] [ +.B \-z +.I path +] [ .B \-P .I port-number ] [ @@ -52,6 +55,10 @@ When pimd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart pimd. The likely default is \fB\fI/var/run/pimd.pid\fR. .TP +\fB\-z\fR, \fB\-\-socket \fR\fIpath\fR +Specify the socket path for contacting the zebra daemon. +The likely default is \fB\fI/var/run/zserv.api\fR. +.TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the pimd VTY will listen on. This defaults to 2611, as specified in \fB\fI/etc/services\fR. @@ -80,6 +87,16 @@ The default location of the .B pimd config file. .TP +.BI /var/run/pimd.pid +The default location of the +.B pimd +pid file. +.TP +.BI /var/run/zserv.api +The default location of the +.B zebra +unix socket file. +.TP .BI $(PWD)/pimd.log If the .B pimd diff --git a/lib/zclient.c b/lib/zclient.c index c3a4905f9..936143603 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -229,7 +229,7 @@ zclient_socket_connect (struct zclient *zclient) #ifdef HAVE_TCP_ZEBRA zclient->sock = zclient_socket (); #else - zclient->sock = zclient_socket_un (zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH); + zclient->sock = zclient_socket_un (zclient_serv_path_get()); #endif return zclient->sock; } @@ -1053,6 +1053,11 @@ zclient_event (enum event event, struct zclient *zclient) } } +const char *const zclient_serv_path_get() +{ + return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH; +} + void zclient_serv_path_set (char *path) { diff --git a/lib/zclient.h b/lib/zclient.h index 6a5e6268c..c7d4d2272 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -136,6 +136,7 @@ extern int zclient_socket(void); extern int zclient_socket_un (const char *path); extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); +extern const char *const zclient_serv_path_get (void); /* Send redistribute command to zebra daemon. Do not update zclient state. */ extern int zebra_redistribute_send (int command, struct zclient *, int type); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 64d7787d9..b314df27f 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -98,6 +98,7 @@ Daemon which manages PIM.\n\n\ -d, --daemon Run in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -v, --version Print program version\n\ @@ -125,6 +126,7 @@ int main(int argc, char** argv, char** envp) { int vty_port = -1; int daemon_mode = 0; char *config_file = NULL; + char *zebra_sock_path = NULL; struct thread thread; umask(0027); @@ -138,7 +140,7 @@ int main(int argc, char** argv, char** envp) { while (1) { int opt; - opt = getopt_long (argc, argv, "df:i:A:P:vZh", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:A:P:vZh", longopts, 0); if (opt == EOF) break; @@ -155,6 +157,9 @@ int main(int argc, char** argv, char** envp) { case 'i': pid_file = optarg; break; + case 'z': + zebra_sock_path = optarg; + break; case 'A': vty_addr = optarg; break; @@ -298,10 +303,11 @@ Hello, this is " QUAGGA_PROGNAME " " QUAGGA_VERSION " " PIMD_PROGNAME " " PIMD_V zlog_notice("!HAVE_CLOCK_MONOTONIC"); #endif + /* Initialize zclient "update" and "lookup" sockets */ - pim_zebra_init(); + pim_zebra_init(zebra_sock_path); while (thread_fetch(master, &thread)) thread_call(&thread); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 44046dbb1..321e31712 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -642,14 +642,17 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, return 0; } -void pim_zebra_init() +void pim_zebra_init(char *zebra_sock_path) { int i; + if (zebra_sock_path) + zclient_serv_path_set(zebra_sock_path); + #ifdef HAVE_TCP_ZEBRA zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT); #else - zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", ZEBRA_SERV_PATH); + zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get()); #endif /* Socket for receiving updates from Zebra daemon */ diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 474e7a2e7..d624c8666 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -26,7 +26,7 @@ #include "pim_igmp.h" #include "pim_ifchannel.h" -void pim_zebra_init(void); +void pim_zebra_init(char *zebra_sock_path); void pim_scan_oil(void); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index be0499e31..ed47e6738 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -66,16 +66,19 @@ static int zclient_lookup_connect(struct thread *t) __PRETTY_FUNCTION__, "127.0.0.1", ZEBRA_PORT); } #else - zlog_debug("%s: FIXME blocking connect: zclient_socket_un()", - __PRETTY_FUNCTION__); - zlookup->sock = zclient_socket_un(ZEBRA_SERV_PATH); - if (zlookup->sock < 0) { - zlog_warn("%s: failure connecting UNIX socket %s", - __PRETTY_FUNCTION__, ZEBRA_SERV_PATH); - } - else if (zclient_debug) { - zlog_notice("%s: connected UNIX socket %s", - __PRETTY_FUNCTION__, ZEBRA_SERV_PATH); + { + const char *const path = zclient_serv_path_get(); + zlog_debug("%s: FIXME blocking connect: zclient_socket_un()", + __PRETTY_FUNCTION__); + zlookup->sock = zclient_socket_un(path); + if (zlookup->sock < 0) { + zlog_warn("%s: failure connecting UNIX socket %s", + __PRETTY_FUNCTION__, path); + } + else if (zclient_debug) { + zlog_notice("%s: connected UNIX socket %s", + __PRETTY_FUNCTION__, path); + } } #endif /* HAVE_TCP_ZEBRA */ From 275e24d0ec67f79ae4c5977ea419e1659f9c40ac Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 22 Aug 2014 11:12:23 -0300 Subject: [PATCH 0547/1342] pimd: Fix interface "no ip igmp" should not disrupt PIM. Plus docs updates. --- pimd/DEBUG | 18 +++++++++++++++--- pimd/pim_cmd.c | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pimd/DEBUG b/pimd/DEBUG index 119c46f53..8d64475fd 100644 --- a/pimd/DEBUG +++ b/pimd/DEBUG @@ -8,7 +8,7 @@ DEBUG HINTS - Check the multicast packets are not being dropped due to fragmentation problems. - - Two easy options to test IGMPv3 joins from the receiver host: + - Three easy options to test IGMPv3 joins from the receiver host: 1) Configure pimd on the receiver host with "ip igmp join": @@ -16,15 +16,27 @@ DEBUG HINTS ip pim ssm ip igmp join 239.1.1.1 1.1.1.1 - 2) Use the test_igmpv3_join command-line utility: + 2) Use test_igmpv3_join command-line utility (provided with qpimd): test_igmpv3_join eth0 239.1.1.1 1.1.1.1 + 3) User the Stig Venaas' ssmping utility: + + ssmping -I eth0 1.1.1.1 + + To see multicast responses with ssmping, you will need run on + the host 1.1.1.1 either: + a) Stig Venaas' ssmpingd command-line daemon + OR + b) qpimd built-in ssmpingd service: + conf t + ip ssmpingd 1.1.1.1 + - The following command generates a 100-kbps multicast stream for channel 1.1.1.1,239.1.1.1 with TTL 10 and 1000-byte payload per UDP packet (to avoid fragmentation): - nepim -b 1.1.1.1 -c 239.1.1.1 -T 10 -W 1000 -r 100k -a 1d + nepim -M -b 1.1.1.1 -c 239.1.1.1 -T 10 -W 1000 -r 100k -a 1d - Remotely you can receive that stream by running: diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a49264a3b..8b5197788 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2481,7 +2481,7 @@ DEFUN (interface_no_ip_igmp, pim_if_membership_clear(ifp); - pim_if_addr_del_all(ifp); + pim_if_addr_del_all_igmp(ifp); if (!PIM_IF_TEST_PIM(pim_ifp->options)) { pim_if_delete(ifp); From 3edadebed3f29383cc8d5825a9ef2fed5431235d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 22 Aug 2014 14:29:31 -0300 Subject: [PATCH 0548/1342] pimd: Clarifications on debug hints. --- pimd/DEBUG | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/pimd/DEBUG b/pimd/DEBUG index 8d64475fd..72fb8264b 100644 --- a/pimd/DEBUG +++ b/pimd/DEBUG @@ -32,17 +32,30 @@ DEBUG HINTS conf t ip ssmpingd 1.1.1.1 - - The following command generates a 100-kbps multicast stream for - channel 1.1.1.1,239.1.1.1 with TTL 10 and 1000-byte payload per UDP - packet (to avoid fragmentation): + - Using nepim to generate multicast stream from 1.1.1.1 to 239.1.1.1: + + Notices: - nepim -M -b 1.1.1.1 -c 239.1.1.1 -T 10 -W 1000 -r 100k -a 1d + a) The host unicast address 1.1.1.1 must be reachable from the + receiver. - - Remotely you can receive that stream by running: + b) nepim tool requires the receiver must be started *before* the + sender. - nepim -j 1.1.1.1+239.1.1.1@eth0 + First: Start a receiver for that stream by running: + + nepim -q -6 -j 1.1.1.1+239.1.1.1@eth0 (Remember of enabling both "ip pim ssm" and "ip igmp" under eth0.) + Second: Start the sender at host 1.1.1.1. + + The following command generates a 100-kbps multicast stream for + channel 1.1.1.1,239.1.1.1 with TTL 10 and 1000-byte payload per UDP + packet (to avoid fragmentation): + + nepim -6 -M -b 1.1.1.1 -c 239.1.1.1 -T 10 -W 1000 -r 100k -a 1d + + SAMPLE DEBUG COMMANDS From bb61be2e5acd272d4e1467406bc13e5b56b8ef66 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 22 Aug 2014 15:40:02 -0300 Subject: [PATCH 0549/1342] pimd: Replace assert with warning. --- pimd/pim_igmpv3.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 3da1dd1ec..24db40ba6 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -408,8 +408,19 @@ void igmp_source_delete(struct igmp_source *source) source_timer_off(group, source); igmp_source_forward_stop(source); - /* make sure forwarding is disabled */ - zassert(!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); + /* sanity check that forwarding has been disabled */ + if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { + char group_str[100]; + char source_str[100]; + pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); + pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s", + __PRETTY_FUNCTION__, + source_str, group_str, + group->group_igmp_sock->fd, + group->group_igmp_sock->interface->name); + /* warning only */ + } source_channel_oil_detach(source); From c1b228c5cfd589b3fee5c0cbe1564f38df57f7f6 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 27 Aug 2014 15:27:26 -0300 Subject: [PATCH 0550/1342] pimd: Reduce informative mandatory logging. --- pimd/pim_assert.c | 56 +++++++++++++++++++++++--------------------- pimd/pim_ifchannel.c | 56 ++++++++++++++++++++++---------------------- pimd/pim_neighbor.c | 17 ++++++++------ pimd/pim_rpf.c | 54 +++++++++++++++++++++++------------------- pimd/pim_zebra.c | 20 ++++++++++------ 5 files changed, 110 insertions(+), 93 deletions(-) diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index b742223ce..ad21e08ef 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -53,33 +53,35 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric, &winner_metric); - if (ch->ifassert_state != new_state) { - char src_str[100]; - char grp_str[100]; - pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); - pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); - zlog_info("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s", - __PRETTY_FUNCTION__, - src_str, grp_str, - pim_ifchannel_ifassert_name(ch->ifassert_state), - pim_ifchannel_ifassert_name(new_state), - ch->interface->name); - } + if (PIM_DEBUG_PIM_EVENTS) { + if (ch->ifassert_state != new_state) { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + pim_ifchannel_ifassert_name(ch->ifassert_state), + pim_ifchannel_ifassert_name(new_state), + ch->interface->name); + } - if (winner_changed) { - char src_str[100]; - char grp_str[100]; - char was_str[100]; - char winner_str[100]; - pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); - pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); - pim_inet4_dump("", ch->ifassert_winner, was_str, sizeof(was_str)); - pim_inet4_dump("", winner, winner_str, sizeof(winner_str)); - zlog_info("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s", - __PRETTY_FUNCTION__, - src_str, grp_str, - was_str, winner_str, ch->interface->name); - } + if (winner_changed) { + char src_str[100]; + char grp_str[100]; + char was_str[100]; + char winner_str[100]; + pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", ch->ifassert_winner, was_str, sizeof(was_str)); + pim_inet4_dump("", winner, winner_str, sizeof(winner_str)); + zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + was_str, winner_str, ch->interface->name); + } + } /* PIM_DEBUG_PIM_EVENTS */ ch->ifassert_state = new_state; ch->ifassert_winner = winner; @@ -655,7 +657,7 @@ int assert_action_a1(struct pim_ifchannel *ch) char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); - zlog_warn("%s: (S,G)=(%s,%s) multicast no enabled on interface %s", + zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -1; /* must return since pim_ifp is used below */ diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 6ceef4eeb..e253a0ea9 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -286,16 +286,16 @@ static void ifmembership_set(struct pim_ifchannel *ch, if (ch->local_ifmembership == membership) return; - { + /* if (PIM_DEBUG_PIM_EVENTS) */ { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); - zlog_info("%s: (S,G)=(%s,%s) membership now is %s on interface %s", - __PRETTY_FUNCTION__, - src_str, grp_str, - membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO", - ch->interface->name); + zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, + membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO", + ch->interface->name); } ch->local_ifmembership = membership; @@ -787,15 +787,15 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) if (new_couldassert == old_couldassert) return; - { + if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); - zlog_info("%s: CouldAssert(%s,%s,%s) changed from %d to %d", - __PRETTY_FUNCTION__, - src_str, grp_str, ch->interface->name, - old_couldassert, new_couldassert); + zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name, + old_couldassert, new_couldassert); } if (new_couldassert) { @@ -829,7 +829,7 @@ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric)) return; - { + if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; char old_addr_str[100]; @@ -838,17 +838,17 @@ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str)); pim_inet4_dump("", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str)); - zlog_info("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", - __PRETTY_FUNCTION__, - src_str, grp_str, ch->interface->name, - ch->ifassert_my_metric.rpt_bit_flag, - ch->ifassert_my_metric.metric_preference, - ch->ifassert_my_metric.route_metric, - old_addr_str, - my_metric_new.rpt_bit_flag, - my_metric_new.metric_preference, - my_metric_new.route_metric, - new_addr_str); + zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name, + ch->ifassert_my_metric.rpt_bit_flag, + ch->ifassert_my_metric.metric_preference, + ch->ifassert_my_metric.route_metric, + old_addr_str, + my_metric_new.rpt_bit_flag, + my_metric_new.metric_preference, + my_metric_new.route_metric, + new_addr_str); } ch->ifassert_my_metric = my_metric_new; @@ -867,15 +867,15 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch) if (new_atd == old_atd) return; - { + if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); - zlog_info("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d", - __PRETTY_FUNCTION__, - src_str, grp_str, ch->interface->name, - old_atd, new_atd); + zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d", + __PRETTY_FUNCTION__, + src_str, grp_str, ch->interface->name, + old_atd, new_atd); } if (new_atd) { diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 66d895e9a..9404cec13 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -124,13 +124,16 @@ void pim_if_dr_election(struct interface *ifp) /* DR changed ? */ if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { - char dr_old_str[100]; - char dr_new_str[100]; - pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); - pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); - zlog_info("%s: DR was %s now is %s on interface %s", - __PRETTY_FUNCTION__, - dr_old_str, dr_new_str, ifp->name); + + /* if (PIM_DEBUG_PIM_EVENTS) */ { + char dr_old_str[100]; + char dr_new_str[100]; + pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); + pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); + zlog_debug("%s: DR was %s now is %s on interface %s", + __PRETTY_FUNCTION__, + dr_old_str, dr_new_str, ifp->name); + } pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_changes; diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 7fdeecfd5..dedc60a55 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -150,20 +150,23 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, /* detect change in pim_nexthop */ if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { - char src_str[100]; - char grp_str[100]; - char nhaddr_str[100]; - pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); - pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); - pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str)); - zlog_warn("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d", - __FILE__, __PRETTY_FUNCTION__, - src_str, grp_str, - rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "", - nhaddr_str, - rpf->source_nexthop.mrib_metric_preference, - rpf->source_nexthop.mrib_route_metric); - /* warning only */ + + /* if (PIM_DEBUG_PIM_EVENTS) */ { + char src_str[100]; + char grp_str[100]; + char nhaddr_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str)); + zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, + rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "", + nhaddr_str, + rpf->source_nexthop.mrib_metric_preference, + rpf->source_nexthop.mrib_route_metric); + /* warning only */ + } pim_upstream_update_join_desired(up); pim_upstream_update_could_assert(up); @@ -172,16 +175,19 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, /* detect change in RPF_interface(S) */ if (save_nexthop.interface != rpf->source_nexthop.interface) { - char src_str[100]; - char grp_str[100]; - pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); - pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); - zlog_warn("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s", - __FILE__, __PRETTY_FUNCTION__, - src_str, grp_str, - save_nexthop.interface ? save_nexthop.interface->name : "", - rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""); - /* warning only */ + + /* if (PIM_DEBUG_PIM_EVENTS) */ { + char src_str[100]; + char grp_str[100]; + pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); + pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); + zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str, + save_nexthop.interface ? save_nexthop.interface->name : "", + rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""); + /* warning only */ + } pim_upstream_rpf_interface_changed(up, save_nexthop.interface); } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 321e31712..4cef422ec 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -670,7 +670,9 @@ void pim_zebra_init(char *zebra_sock_path) qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route; zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); - zlog_info("zclient_init cleared redistribution request"); + if (PIM_DEBUG_PIM_TRACE) { + zlog_info("zclient_init cleared redistribution request"); + } zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM); @@ -679,18 +681,22 @@ void pim_zebra_init(char *zebra_sock_path) if (i == qpim_zclient_update->redist_default) continue; qpim_zclient_update->redist[i] = 1; - zlog_info("%s: requesting redistribution for %s (%i)", - __PRETTY_FUNCTION__, zebra_route_string(i), i); + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: requesting redistribution for %s (%i)", + __PRETTY_FUNCTION__, zebra_route_string(i), i); + } } /* Request default information */ qpim_zclient_update->default_information = 1; - zlog_info("%s: requesting default information redistribution", - __PRETTY_FUNCTION__); - - zlog_notice("%s: zclient update socket initialized", + if (PIM_DEBUG_PIM_TRACE) { + zlog_info("%s: requesting default information redistribution", __PRETTY_FUNCTION__); + zlog_notice("%s: zclient update socket initialized", + __PRETTY_FUNCTION__); + } + zassert(!qpim_zclient_lookup); qpim_zclient_lookup = zclient_lookup_new(); zassert(qpim_zclient_lookup); From 8852dba7737d85f9ff37c38358a4c92006c9a92e Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 28 Aug 2014 16:02:11 -0300 Subject: [PATCH 0551/1342] pimd: React as secondary address change for any address change --- pimd/CAVEATS | 1 + pimd/TODO | 1 + pimd/pim_iface.c | 72 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/pimd/CAVEATS b/pimd/CAVEATS index 7e2820b3b..9f07bda66 100644 --- a/pimd/CAVEATS +++ b/pimd/CAVEATS @@ -115,6 +115,7 @@ C14 FIXED Detection of interface primary address changes may fail when C15 Changes in interface secondary address list are not immediately detected. + See also detect_secondary_address_change See also TODO T31. C16 AMT Draft (mboned-auto-multicast) is not supported. diff --git a/pimd/TODO b/pimd/TODO index 80835e460..2308573b8 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -264,6 +264,7 @@ T30 DONE Run interface DR election when primary address changes T31 If an interface changes one of its secondary IP addresses, a Hello message with an updated Address_List option and a non-zero HoldTime should be sent immediately. + See also detect_secondary_address_change See also CAVEAT C15. See also RFC 4601: 4.3.1. Sending Hello Messages diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index fdbb79beb..770bd4e00 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -273,17 +273,20 @@ static void on_primary_address_change(struct interface *ifp, } pim_ifp = ifp->info; + if (!pim_ifp) { + return; + } - if (pim_ifp) { - if (PIM_IF_TEST_PIM(pim_ifp->options)) { - pim_addr_change(ifp); - } + if (!PIM_IF_TEST_PIM(pim_ifp->options)) { + return; } + + pim_addr_change(ifp); } -static void detect_primary_address_change(struct interface *ifp, - int force_prim_as_any, - const char *caller) +static int detect_primary_address_change(struct interface *ifp, + int force_prim_as_any, + const char *caller) { struct pim_interface *pim_ifp; struct in_addr new_prim_addr; @@ -291,7 +294,7 @@ static void detect_primary_address_change(struct interface *ifp, pim_ifp = ifp->info; if (!pim_ifp) - return; + return 0; if (force_prim_as_any) new_prim_addr = qpim_inaddr_any; @@ -317,6 +320,55 @@ static void detect_primary_address_change(struct interface *ifp, on_primary_address_change(ifp, caller, old_addr, new_prim_addr); } + + return changed; +} + +static void detect_secondary_address_change(struct interface *ifp, + const char *caller) +{ + struct pim_interface *pim_ifp; + int changed; + + pim_ifp = ifp->info; + if (!pim_ifp) + return; + + changed = 1; /* true */ + zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", + __PRETTY_FUNCTION__, ifp->name); + + if (PIM_DEBUG_ZEBRA) { + zlog_debug("%s: on interface %s: %s", + __PRETTY_FUNCTION__, + ifp->name, changed ? "changed" : "unchanged"); + } + + if (!changed) { + return; + } + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) { + return; + } + + pim_addr_change(ifp); +} + +static void detect_address_change(struct interface *ifp, + int force_prim_as_any, + const char *caller) +{ + int prim_changed; + + prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller); + if (prim_changed) { + /* no need to detect secondary change because + the reaction would be the same */ + return; + } + + detect_secondary_address_change(ifp, caller); } void pim_if_addr_add(struct connected *ifc) @@ -348,7 +400,7 @@ void pim_if_addr_add(struct connected *ifc) ifaddr = ifc->address->u.prefix4; - detect_primary_address_change(ifp, 0, __PRETTY_FUNCTION__); + detect_address_change(ifp, 0, __PRETTY_FUNCTION__); if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; @@ -465,7 +517,7 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) "secondary" : "primary"); } - detect_primary_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); + detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); pim_if_addr_del_igmp(ifc); pim_if_addr_del_pim(ifc); From f80f8aa34b88c4e97654bca62b43605a3d029d92 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 29 Aug 2014 14:55:30 -0300 Subject: [PATCH 0552/1342] pimd: Troubleshooting script. --- pimd/TROUBLESHOOTING | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 pimd/TROUBLESHOOTING diff --git a/pimd/TROUBLESHOOTING b/pimd/TROUBLESHOOTING new file mode 100644 index 000000000..7d1f52de8 --- /dev/null +++ b/pimd/TROUBLESHOOTING @@ -0,0 +1,33 @@ +TROUBLESHOOTING + +# Check kernel mcast cache +# On Linux: +ip mroute show + +! qpimd on last-hop router +! . attached to mcast receiver +! . runnning both PIM-SSM and IGMPv3 +! +show ip mroute (kernel mcast programming is correct?) +show ip pim upstream (we joined our upstream?) +show ip pim neighbor (upstream is neighbor?) +show ip pim interface (pim enabled on interfaces?) +show ip multicast (multicast enabled at all?) +show ip rib SRC (unicast route towards source?) + +show ip igmp sources (receiver joined on interface?) +show ip igmp interface (igmp enabled on receiver interface?) + +! qpimd on intermmediate routers +! . may be attached to mcast source +! . runnning only PIM-SSM, not IGMPv3 +! +show ip mroute (kernel mcast programming is correct?) +show ip pim upstream (we joined our upstream?) +show ip pim join (downstream joined us?) +show ip pim neighbor (downstream is neighbor?) +show ip pim interface (pim enabled on interfaces?) +show ip multicast (multicast enabled at all?) +show ip rib SRC (unicast route towards source?) + +--EOF-- From 629e30bb436ce2231c47a38e1a5c5ac1c72beefa Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 29 Aug 2014 16:10:08 -0300 Subject: [PATCH 0553/1342] pimd: Version up. --- pimd/pim_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_version.h b/pimd/pim_version.h index 68ab76934..ef9f370c7 100644 --- a/pimd/pim_version.h +++ b/pimd/pim_version.h @@ -23,7 +23,7 @@ #ifndef PIM_VERSION_H #define PIM_VERSION_H -#define PIMD_VERSION_STR "0.165" +#define PIMD_VERSION_STR "0.166" const char * const PIMD_VERSION; From 93911267a3105931fbaee62dabf7cc444466a6c2 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 11:10:58 -0300 Subject: [PATCH 0554/1342] pimd: Remove unused pim checksum in favour of quagga's version. --- pimd/Makefile.am | 2 -- pimd/pim_cmd.c | 2 +- pimd/pim_igmp.c | 4 ++-- pimd/pim_igmpv3.c | 2 +- pimd/pim_main.c | 4 ---- pimd/pim_msg.c | 2 +- pimd/pim_pim.c | 2 +- pimd/pim_util.c | 37 ------------------------------------- pimd/pim_util.h | 6 ------ 9 files changed, 6 insertions(+), 55 deletions(-) diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 70c5096c6..9345460d0 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -22,7 +22,6 @@ # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging # PIM_MOTD_VERSION: Includes pimd version in default MOTD -# PIM_USE_QUAGGA_INET_CHECKSUM: Prefer Quagga inet checksum # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries @@ -36,7 +35,6 @@ PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH PIM_DEFS += -DPIM_ZCLIENT_DEBUG PIM_DEFS += -DPIM_MOTD_VERSION -PIM_DEFS += -DPIM_USE_QUAGGA_INET_CHECKSUM PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL #PIM_DEFS += -DPIM_USE_QUAGGA_GETTIME diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 8b5197788..eaf209ce7 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3590,7 +3590,7 @@ DEFUN (test_igmp_receive_report, igmp_msg_len = IGMP_V3_MSG_MIN_SIZE + (num_sources << 4); /* v3 report for one single group record */ /* compute checksum */ - *(uint16_t *)(igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = pim_inet_checksum(igmp_msg, igmp_msg_len); + *(uint16_t *)(igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = in_cksum(igmp_msg, igmp_msg_len); /* "receive" message */ diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 03cf3cd1b..a54463fac 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -299,7 +299,7 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; - checksum = pim_inet_checksum(igmp_msg, igmp_msg_len); + checksum = in_cksum(igmp_msg, igmp_msg_len); if (checksum != recv_checksum) { zlog_warn("Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x", query_version, from_str, ifp->name, recv_checksum, checksum); @@ -470,7 +470,7 @@ static int igmp_v3_report(struct igmp_sock *igmp, /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; - checksum = pim_inet_checksum(igmp_msg, igmp_msg_len); + checksum = in_cksum(igmp_msg, igmp_msg_len); if (checksum != recv_checksum) { zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x", from_str, ifp->name, recv_checksum, checksum); diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 24db40ba6..b95adb6fc 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1651,7 +1651,7 @@ void pim_igmp_send_membership_query(struct igmp_group *group, query_buf[9] = qqic; *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources); - checksum = pim_inet_checksum(query_buf, msg_size); + checksum = in_cksum(query_buf, msg_size); *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = checksum; if (PIM_DEBUG_IGMP_PACKETS) { diff --git a/pimd/pim_main.c b/pimd/pim_main.c index b314df27f..768ac08c2 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -281,10 +281,6 @@ Hello, this is " QUAGGA_PROGNAME " " QUAGGA_VERSION " " PIMD_PROGNAME " " PIMD_V #endif #endif -#ifdef PIM_USE_QUAGGA_INET_CHECKSUM - zlog_notice("PIM_USE_QUAGGA_INET_CHECKSUM: using Quagga's builtin checksum"); -#endif - #ifdef PIM_UNEXPECTED_KERNEL_UPCALL zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 79ae33ac8..8ead7ce64 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -46,7 +46,7 @@ void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, */ *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; - checksum = pim_inet_checksum(pim_msg, pim_msg_size); + checksum = in_cksum(pim_msg, pim_msg_size); *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 4fda26ec0..fb6c3acb9 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -194,7 +194,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) /* for computing checksum */ *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; - checksum = pim_inet_checksum(pim_msg, pim_msg_len); + checksum = in_cksum(pim_msg, pim_msg_len); if (checksum != pim_checksum) { zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", ifp->name, pim_checksum, checksum); diff --git a/pimd/pim_util.c b/pimd/pim_util.c index a7e8234e9..fdfed2bf2 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -98,43 +98,6 @@ uint16_t igmp_msg_decode8to16(uint8_t code) return value; } -#ifndef PIM_USE_QUAGGA_INET_CHECKSUM -/* - RFC 3376: 4.1.2. Checksum - - The Checksum is the 16-bit one's complement of the one's complement - sum of the whole IGMP message (the entire IP payload). For - computing the checksum, the Checksum field is set to zero. When - receiving packets, the checksum MUST be verified before processing a - packet. [RFC-1071] -*/ -uint16_t pim_inet_checksum(const char *buf, int size) -{ - const uint16_t *ptr; - uint32_t sum; - uint16_t checksum; - - ptr = (const uint16_t *) buf; - sum = 0; - while (size > 1) { - sum += *ptr; - ++ptr; - size -= 2; - } - - /* Add left-over byte, if any */ - if (size > 0) - sum += (uint16_t) *(const uint8_t *) ptr; - - /* Fold 32-bit sum to 16 bits */ - sum = (sum & 0xffff) + (sum >> 16); - - checksum = ~sum; - - return checksum; -} -#endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ - void pim_pkt_dump(const char *label, const uint8_t *buf, int size) { char dump_buf[1000]; diff --git a/pimd/pim_util.h b/pimd/pim_util.h index 6f5bf2237..a8613e2b9 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -32,12 +32,6 @@ uint8_t igmp_msg_encode16to8(uint16_t value); uint16_t igmp_msg_decode8to16(uint8_t code); -#ifdef PIM_USE_QUAGGA_INET_CHECKSUM -#define pim_inet_checksum(buf,size) in_cksum(buf,size) -#else -uint16_t pim_inet_checksum(const char *buf, int size); -#endif /* PIM_USE_QUAGGA_INET_CHECKSUM */ - void pim_pkt_dump(const char *label, const uint8_t *buf, int size); #endif /* PIM_UTIL_H */ From 3d62667ab0e8e7ee6e17e883b144e25ee84c4545 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 11:24:36 -0300 Subject: [PATCH 0555/1342] pimd: Remove reference to external doc. --- pimd/WHY_SSM | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pimd/WHY_SSM b/pimd/WHY_SSM index 6ff8f1343..2e8c966f1 100644 --- a/pimd/WHY_SSM +++ b/pimd/WHY_SSM @@ -29,9 +29,4 @@ PIM-SSM drawbacks - SSM will keep (S,G) state as long as there are subscriptions from receivers, even if the source is not actually sending traffic -Cisco Documentation for SSM Benefits ------------------------------------- - -http://www.cisco.com/c/en/us/td/docs/ios/12_2/ip/configuration/guide/fipr_c/1cfssm.html#wp1000969 - --EOF-- From 74b4fad93e89df358441b1b3b23282aaca8c80b8 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 12:06:53 -0300 Subject: [PATCH 0556/1342] pimd: Remove motd tweaking. --- lib/command.c | 2 +- pimd/Makefile.am | 2 -- pimd/pim_main.c | 13 ------------- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/command.c b/lib/command.c index a789b0f4a..8870a4211 100644 --- a/lib/command.c +++ b/lib/command.c @@ -105,7 +105,7 @@ static struct cmd_node config_node = }; /* Default motd string. */ -const char *default_motd = +static const char *default_motd = "\r\n\ Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ " QUAGGA_COPYRIGHT "\r\n\ diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 9345460d0..3b8a0e173 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -21,7 +21,6 @@ # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging -# PIM_MOTD_VERSION: Includes pimd version in default MOTD # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries @@ -34,7 +33,6 @@ PIM_DEFS = PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH PIM_DEFS += -DPIM_ZCLIENT_DEBUG -PIM_DEFS += -DPIM_MOTD_VERSION PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL #PIM_DEFS += -DPIM_USE_QUAGGA_GETTIME diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 768ac08c2..68cfe2189 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -46,7 +46,6 @@ extern int zclient_debug; #endif extern struct host host; -extern const char *default_motd; char config_default[] = SYSCONFDIR PIMD_DEFAULT_CONFIG; @@ -246,18 +245,6 @@ int main(int argc, char** argv, char** envp) { zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting, VTY interface at port TCP %d", QUAGGA_VERSION, PIMD_VERSION, vty_port); -#ifdef PIM_MOTD_VERSION - /* Tweak default MOTD to include pimd version */ - zlog_notice("PIM_MOTD_VERSION: adding pimd version to default MOTD"); - if (host.motd == default_motd) { - host.motd = - "\r\n\ -Hello, this is " QUAGGA_PROGNAME " " QUAGGA_VERSION " " PIMD_PROGNAME " " PIMD_VERSION_STR "\r\n\ -" QUAGGA_COPYRIGHT "\r\n\ -\r\n"; - } -#endif - #ifdef PIM_DEBUG_BYDEFAULT zlog_notice("PIM_DEBUG_BYDEFAULT: Enabling all debug commands"); PIM_DO_DEBUG_PIM_EVENTS; From a089db4a0678cc1bbbf003bbda2561c03760badc Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 12:08:05 -0300 Subject: [PATCH 0557/1342] pimd: Fix log about PIM_USE_QUAGGA_GETTIME. --- pimd/pim_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 68cfe2189..0ae4ae9c2 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -272,7 +272,7 @@ int main(int argc, char** argv, char** envp) { zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif -#ifdef PIM_FORCE_QUAGGA_REALTIME_STABILISED +#ifdef PIM_USE_QUAGGA_GETTIME zlog_notice("PIM_USE_QUAGGA_GETTIME: using Quagga's quagga_gettime"()); #endif From 4d330a2719fd684739a16c6aa3be6632bc3745a2 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 12:15:55 -0300 Subject: [PATCH 0558/1342] pimd: Remove conflict marker. --- vtysh/vtysh.c | 1 - 1 file changed, 1 deletion(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index a5e29dc91..984f8d39b 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -60,7 +60,6 @@ struct vtysh_client { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH}, { .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH}, { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH}, ->>>>>>> [pim] pim commands added to vtysh }; From 679fab42343381f609527166f48dbf9ba19f3aab Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Thu, 18 Sep 2014 14:54:07 -0300 Subject: [PATCH 0559/1342] pimd: Simplify gettime-related code. --- pimd/Makefile.am | 4 ---- pimd/pim_main.c | 8 -------- pimd/pim_time.c | 47 ----------------------------------------------- 3 files changed, 59 deletions(-) diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 3b8a0e173..7173a231a 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -25,8 +25,6 @@ # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall -# PIM_USE_QUAGGA_GETTIME: Prefer quagga_gettime -# PIM_GETTIME_USE_GETTIMEOFDAY: Work-around improper monotonic clock PIM_DEFS = #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT @@ -35,8 +33,6 @@ PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY PIM_DEFS += -DPIM_ZCLIENT_DEBUG PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL -#PIM_DEFS += -DPIM_USE_QUAGGA_GETTIME -PIM_DEFS += -DPIM_GETTIME_USE_GETTIMEOFDAY INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 0ae4ae9c2..c646356ae 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -272,14 +272,6 @@ int main(int argc, char** argv, char** envp) { zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif -#ifdef PIM_USE_QUAGGA_GETTIME - zlog_notice("PIM_USE_QUAGGA_GETTIME: using Quagga's quagga_gettime"()); -#endif - -#ifdef PIM_GETTIME_USE_GETTIMEOFDAY - zlog_notice("PIM_GETTIME_USE_GETTIMEOFDAY: work-around improper monotonic clock"); -#endif - #ifdef HAVE_CLOCK_MONOTONIC zlog_notice("HAVE_CLOCK_MONOTONIC"); #else diff --git a/pimd/pim_time.c b/pimd/pim_time.c index fce30c080..097b470ba 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -30,63 +30,16 @@ #include "pim_time.h" -#ifndef PIM_GETTIME_USE_GETTIMEOFDAY -static int pim_gettime(int clk_id, struct timeval *tv) -{ - struct timespec ts; - int result; - -#ifdef PIM_USE_QUAGGA_GETTIME - result = quagga_gettime(clk_id, tv); - if (result) { - zlog_err("%s: quagga_gettime(clk_id=%d) failure: errno=%d: %s", - __PRETTY_FUNCTION__, clk_id, - errno, safe_strerror(errno)); - } -#else - result = clock_gettime(clk_id, &ts); - if (result) { - zlog_err("%s: clock_gettime(clk_id=%d) failure: errno=%d: %s", - __PRETTY_FUNCTION__, clk_id, - errno, safe_strerror(errno)); - return result; - } - if (tv) { - tv->tv_sec = ts.tv_sec; - tv->tv_usec = 1000 * ts.tv_nsec; - } -#endif - - return result; -} -#endif - static int gettime_monotonic(struct timeval *tv) { int result; -#ifdef PIM_GETTIME_USE_GETTIMEOFDAY result = gettimeofday(tv, 0); if (result) { zlog_err("%s: gettimeofday() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); } -#elif defined(PIM_USE_QUAGGA_GETTIME) - result = pim_gettime(QUAGGA_CLK_MONOTONIC, tv); - if (result) { - zlog_err("%s: pim_gettime(QUAGGA_CLK_MONOTONIC=%d) failure: errno=%d: %s", - __PRETTY_FUNCTION__, QUAGGA_CLK_MONOTONIC, - errno, safe_strerror(errno)); - } -#else - result = pim_gettime(CLOCK_MONOTONIC, tv); - if (result) { - zlog_err("%s: pim_gettime(CLOCK_MONOTONIC=%d) failure: errno=%d: %s", - __PRETTY_FUNCTION__, CLOCK_MONOTONIC, - errno, safe_strerror(errno)); - } -#endif return result; } From 96b6dfe98793549aca6a7cc77eaf0957b1168ed2 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 15:47:52 -0300 Subject: [PATCH 0560/1342] pim: Remove connected addresses on loss of zebra connection. --- pimd/pim_zebra.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 4cef422ec..b9b4dab1c 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -63,7 +63,9 @@ static void zclient_broken(struct zclient *zclient) pim_if_addr_del_all(ifp); } - /* upon return, zclient will discard connected addresses */ + /* discard connected addresses because zclient lib will reassign + them upon reconnection */ + if_connected_reset_all(); } /* Router-id update message from zebra. */ From bbb8a18bb5570ff59cf71b46793465828af1fcf3 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Sep 2014 14:05:55 -0300 Subject: [PATCH 0561/1342] zebra_rib: Revert work-around for zebra marking recursive static route as inactive. --- zebra/zebra_rib.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c6dbdec51..effe23384 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -524,13 +524,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, return 1; } - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || - match->type == ZEBRA_ROUTE_KERNEL) - /* - || match->type == ZEBRA_ROUTE_KERNEL - This prevents zebra from marking recursive static route as inactive. - See pimd/TODO T26. - */ + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) From ea537be5278398cd8c32f8046e4789e613420916 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Sep 2014 14:30:10 -0300 Subject: [PATCH 0562/1342] pimd: Remove debuggging for zclient TCP/UNIX sockets. --- pimd/pim_zlookup.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index ed47e6738..7433f1b81 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -51,48 +51,11 @@ static int zclient_lookup_connect(struct thread *t) return 0; } -#ifdef PIM_ZCLIENT_DEBUG - -#ifdef HAVE_TCP_ZEBRA - zlog_debug("%s: FIXME blocking connect: zclient_socket()", - __PRETTY_FUNCTION__); - zlookup->sock = zclient_socket(); - if (zlookup->sock < 0) { - zlog_warn("%s: failure connecting TCP socket %s,%d", - __PRETTY_FUNCTION__, "127.0.0.1", ZEBRA_PORT); - } - else if (zclient_debug) { - zlog_notice("%s: connected TCP socket %s,%d", - __PRETTY_FUNCTION__, "127.0.0.1", ZEBRA_PORT); - } -#else - { - const char *const path = zclient_serv_path_get(); - zlog_debug("%s: FIXME blocking connect: zclient_socket_un()", - __PRETTY_FUNCTION__); - zlookup->sock = zclient_socket_un(path); - if (zlookup->sock < 0) { - zlog_warn("%s: failure connecting UNIX socket %s", - __PRETTY_FUNCTION__, path); - } - else if (zclient_debug) { - zlog_notice("%s: connected UNIX socket %s", - __PRETTY_FUNCTION__, path); - } - } -#endif /* HAVE_TCP_ZEBRA */ - -#else - - zlog_debug("%s: FIXME blocking connect: zclient_socket_connect()", - __PRETTY_FUNCTION__); if (zclient_socket_connect(zlookup) < 0) { zlog_warn("%s: failure connecting zclient socket", __PRETTY_FUNCTION__); } -#endif /* PIM_ZCLIENT_DEBUG */ - zassert(!zlookup->t_connect); if (zlookup->sock < 0) { /* Since last connect failed, retry within 10 secs */ From 1a9352a7487531578a0db9ca86c2647f8e304ca4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Sep 2014 14:33:34 -0300 Subject: [PATCH 0563/1342] zclient: Revert lib export of zclient_socket()/zclient_socket_un(). --- lib/zclient.c | 4 ++-- lib/zclient.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 936143603..41ecbb61d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -148,7 +148,7 @@ zclient_reset (struct zclient *zclient) #ifdef HAVE_TCP_ZEBRA /* Make socket to zebra daemon. Return zebra socket. */ -int +static int zclient_socket(void) { int sock; @@ -184,7 +184,7 @@ zclient_socket(void) /* For sockaddr_un. */ #include -int +static int zclient_socket_un (const char *path) { int ret; diff --git a/lib/zclient.h b/lib/zclient.h index c7d4d2272..d0c5450b7 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -132,8 +132,6 @@ extern void zclient_stop (struct zclient *); extern void zclient_reset (struct zclient *); extern void zclient_free (struct zclient *); -extern int zclient_socket(void); -extern int zclient_socket_un (const char *path); extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); extern const char *const zclient_serv_path_get (void); From 8f4a59aaffd90ac820601fdf69accc8f6c953a1c Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Sep 2014 15:51:11 -0300 Subject: [PATCH 0564/1342] pimd: Revert accidental removal of show_memory_isis_cmd(). --- lib/memory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/memory.c b/lib/memory.c index 28bbdc119..3b87fcc24 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -569,6 +569,7 @@ memory_init (void) install_element (ENABLE_NODE, &show_memory_bgp_cmd); install_element (ENABLE_NODE, &show_memory_ospf_cmd); install_element (ENABLE_NODE, &show_memory_ospf6_cmd); + install_element (ENABLE_NODE, &show_memory_isis_cmd); install_element (ENABLE_NODE, &show_memory_pim_cmd); } From 05a49cea19d861ceec67ce6402264d353bb3b290 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Sep 2014 16:14:27 -0300 Subject: [PATCH 0565/1342] zebra: mrib: Remove non-standard copyright line. --- lib/zebra.h | 1 - zebra/zserv.c | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/zebra.h b/lib/zebra.h index 57e591ff5..a4e02148d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -1,6 +1,5 @@ /* Zebra common header. Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro - Portions Copyright (c) 2008 Everton da Silva Marques This file is part of GNU Zebra. diff --git a/zebra/zserv.c b/zebra/zserv.c index 261c49a37..afd722a10 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1,6 +1,5 @@ /* Zebra daemon server routine. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro - * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * From d8410a0242ab055b96708c5b33358916330bc85a Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 23 Sep 2014 16:14:49 -0300 Subject: [PATCH 0566/1342] pimd: Remove non-standard copyright line. --- lib/command.h | 1 - lib/log.c | 1 - lib/log.h | 1 - lib/memory.c | 1 - lib/memtypes.c | 2 -- lib/thread.h | 1 - 6 files changed, 7 deletions(-) diff --git a/lib/command.h b/lib/command.h index 5156dbf13..8eb0cbd96 100644 --- a/lib/command.h +++ b/lib/command.h @@ -1,7 +1,6 @@ /* * Zebra configuration command interface routine * Copyright (C) 1997, 98 Kunihiro Ishiguro - * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * diff --git a/lib/log.c b/lib/log.c index abfd35bc5..f02e4c736 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1,7 +1,6 @@ /* * Logging of zebra * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro - * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * diff --git a/lib/log.h b/lib/log.h index d9f1ecaae..77cd53bc2 100644 --- a/lib/log.h +++ b/lib/log.h @@ -1,7 +1,6 @@ /* * Zebra logging funcions. * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro - * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * diff --git a/lib/memory.c b/lib/memory.c index 3b87fcc24..84daeeef9 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -1,7 +1,6 @@ /* * Memory management routine * Copyright (C) 1998 Kunihiro Ishiguro - * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * diff --git a/lib/memtypes.c b/lib/memtypes.c index 4ed1e8955..1a0c11fee 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -1,6 +1,4 @@ /* - * Portions Copyright (c) 2008 Everton da Silva Marques - * * Memory type definitions. This file is parsed by memtypes.awk to extract * MTYPE_ and memory_list_.. information in order to autogenerate * memtypes.h. diff --git a/lib/thread.h b/lib/thread.h index 4856dec74..43ffbf603 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -1,6 +1,5 @@ /* Thread management routine header. * Copyright (C) 1998 Kunihiro Ishiguro - * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * From 05c6dcdf8cd8e50681de76cc787f46389a7b9238 Mon Sep 17 00:00:00 2001 From: Savannah SR#108542 Date: Thu, 25 Sep 2014 14:52:18 -0300 Subject: [PATCH 0567/1342] pimd: Fix invalid memory read when receiving a V1 or V2 query. https://savannah.nongnu.org/support/index.php?108542 --- pimd/pim_igmp.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index a54463fac..4fd3edcb8 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -280,9 +280,9 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, { struct interface *ifp; struct pim_interface *pim_ifp; - uint8_t resv_s_qrv; - uint8_t s_flag; - uint8_t qrv; + uint8_t resv_s_qrv = 0; + uint8_t s_flag = 0; + uint8_t qrv = 0; struct in_addr group_addr; uint16_t recv_checksum; uint16_t checksum; @@ -336,18 +336,20 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, pim_igmp_other_querier_timer_on(igmp); } - /* - RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) + if (query_version == 3) { + /* + RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) - Routers adopt the QRV value from the most recently received Query - as their own [Robustness Variable] value, unless that most - recently received QRV was zero, in which case the receivers use - the default [Robustness Variable] value specified in section 8.1 - or a statically configured value. - */ - resv_s_qrv = igmp_msg[8]; - qrv = 7 & resv_s_qrv; - igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable; + Routers adopt the QRV value from the most recently received Query + as their own [Robustness Variable] value, unless that most + recently received QRV was zero, in which case the receivers use + the default [Robustness Variable] value specified in section 8.1 + or a statically configured value. + */ + resv_s_qrv = igmp_msg[8]; + qrv = 7 & resv_s_qrv; + igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable; + } /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) @@ -357,7 +359,7 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, Interval] value, unless that most recently received QQI was zero, in which case the receiving routers use the default. */ - if (igmp->t_other_querier_timer) { + if (igmp->t_other_querier_timer && query_version == 3) { /* other querier present */ uint8_t qqic; uint16_t qqi; @@ -386,7 +388,17 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version, General queries don't trigger timer update. */ - s_flag = (1 << 3) & resv_s_qrv; + if (query_version == 3) { + s_flag = (1 << 3) & resv_s_qrv; + } + else { + /* Neither V1 nor V2 have this field. Pimd should really go into + * a compatibility mode here and run as V2 (or V1) but it doesn't + * so for now, lets just set the flag to suppress these timer updates. + */ + s_flag = 1; + } + if (!s_flag) { /* s_flag is clear */ From ecc1fb93419e0f9d9297f0417bee0b697ce24dec Mon Sep 17 00:00:00 2001 From: Savannah SR#108542 Date: Thu, 25 Sep 2014 14:41:43 -0300 Subject: [PATCH 0568/1342] pimd: Fix igmp_source_forward_stop called when IGMP forwarding flag is not set in oif_flags. https://savannah.nongnu.org/support/index.php?108542 --- pimd/pim_zebra.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b9b4dab1c..ff62bec86 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -1192,11 +1192,25 @@ void igmp_source_forward_stop(struct igmp_source *source) group = source->source_group; - if (del_oif(source->source_channel_oil, + /* + It appears that in certain circumstances that + igmp_source_forward_stop is called when IGMP forwarding + was not enabled in oif_flags for this outgoing interface. + Possibly because of multiple calls. When that happens, we + enter the below if statement and this function returns early + which in turn triggers the calling function to assert. + Making the call to del_oif and ignoring the return code + fixes the issue without ill effect, similar to + pim_forward_stop below. + */ + /*if (del_oif(source->source_channel_oil, group->group_igmp_sock->interface, PIM_OIF_FLAG_PROTO_IGMP)) { return; - } + }*/ + del_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP); /* Feed IGMPv3-gathered local membership information into PIM From 6ab3e2f5759db58469ceb1702df1bc3d18f7a952 Mon Sep 17 00:00:00 2001 From: Savannah SR#108542 Date: Thu, 25 Sep 2014 16:59:38 -0300 Subject: [PATCH 0569/1342] pimd: Fix attempted out of bounds read when deleteing an interface. https://savannah.nongnu.org/support/index.php?108542 --- pimd/pim_zebra.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index ff62bec86..fd525ae60 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -113,8 +113,14 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, /* zebra api adds/dels interfaces using the same call interface_add_read below, see comments in lib/zclient.c + + comments in lib/zclient.c seem to indicate that calling + zebra_interface_add_read is the correct call, but that + results in an attemted out of bounds read which causes + pimd to assert. Other clients use zebra_interface_state_read + and it appears to work just fine. */ - ifp = zebra_interface_add_read(zclient->ibuf); + ifp = zebra_interface_state_read(zclient->ibuf); if (!ifp) return 0; @@ -138,7 +144,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, /* zebra api notifies interface up/down events by using the same call - interface_add_read below, see comments in lib/zclient.c + zebra_interface_state_read below, see comments in lib/zclient.c */ ifp = zebra_interface_state_read(zclient->ibuf); if (!ifp) @@ -170,7 +176,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, /* zebra api notifies interface up/down events by using the same call - interface_add_read below, see comments in lib/zclient.c + zebra_interface_state_read below, see comments in lib/zclient.c */ ifp = zebra_interface_state_read(zclient->ibuf); if (!ifp) From e324ddc5c73b2e2fb1c450a5fe927aa336e568e6 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 29 Sep 2014 17:59:02 -0300 Subject: [PATCH 0570/1342] pimd: sh ip multicast: Display zclient sockets. --- pimd/pim_cmd.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index eaf209ce7..cc15a09ca 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2093,6 +2093,22 @@ DEFUN (show_ip_multicast, VTY_NEWLINE); } + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "Zclient update socket: "); + if (qpim_zclient_update) { + vty_out(vty, "%d%s", qpim_zclient_update->sock, VTY_NEWLINE); + } + else { + vty_out(vty, "%s", VTY_NEWLINE); + } + vty_out(vty, "Zclient lookup socket: "); + if (qpim_zclient_lookup) { + vty_out(vty, "%d%s", qpim_zclient_lookup->sock, VTY_NEWLINE); + } + else { + vty_out(vty, "%s", VTY_NEWLINE); + } + vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Current highest VifIndex: %d%s", qpim_mroute_oif_highest_vif_index, From 8150beed9a4f50a72696a65c1f40889ab65ad7ff Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 29 Sep 2014 17:58:30 -0300 Subject: [PATCH 0571/1342] pimd: Explicitly restart zclient update connection. --- pimd/pim_zebra.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index fd525ae60..c4a6f7a8c 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -66,6 +66,8 @@ static void zclient_broken(struct zclient *zclient) /* discard connected addresses because zclient lib will reassign them upon reconnection */ if_connected_reset_all(); + + zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); /* reconnect */ } /* Router-id update message from zebra. */ @@ -677,11 +679,12 @@ void pim_zebra_init(char *zebra_sock_path) qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route; qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route; - zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); if (PIM_DEBUG_PIM_TRACE) { zlog_info("zclient_init cleared redistribution request"); } + zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); + zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM); /* Request all redistribution */ From a59f21b1a58f121aac466710f32b557a4c75061d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 30 Sep 2014 17:23:56 -0300 Subject: [PATCH 0572/1342] pimd: Update lookup zclient counter for connection failures. --- pimd/pim_zlookup.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 7433f1b81..2e71dc4ef 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -52,8 +52,12 @@ static int zclient_lookup_connect(struct thread *t) } if (zclient_socket_connect(zlookup) < 0) { - zlog_warn("%s: failure connecting zclient socket", - __PRETTY_FUNCTION__); + ++zlookup->fail; + zlog_warn("%s: failure connecting zclient socket: failures=%d", + __PRETTY_FUNCTION__, zlookup->fail); + } + else { + zlookup->fail = 0; /* reset counter on connection */ } zassert(!zlookup->t_connect); @@ -101,6 +105,19 @@ static void zclient_lookup_reconnect(struct zclient *zlookup) zclient_lookup_sched_now(zlookup); } +static void zclient_lookup_failed(struct zclient *zlookup) +{ + if (zlookup->sock >= 0) { + if (close(zlookup->sock)) { + zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, zlookup->sock, + errno, safe_strerror(errno)); + } + zlookup->sock = -1; + } + + zclient_lookup_reconnect(zlookup); +} + struct zclient *zclient_lookup_new() { struct zclient *zlookup; @@ -159,9 +176,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, if (nbytes < 2) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d", __FILE__, __PRETTY_FUNCTION__, nbytes); - close(zlookup->sock); - zlookup->sock = -1; - zclient_lookup_reconnect(zlookup); + zclient_lookup_failed(zlookup); return -1; } length = stream_getw(s); @@ -171,9 +186,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, if (len < MIN_LEN) { zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", __FILE__, __PRETTY_FUNCTION__, len, MIN_LEN); - close(zlookup->sock); - zlookup->sock = -1; - zclient_lookup_reconnect(zlookup); + zclient_lookup_failed(zlookup); return -2; } @@ -181,9 +194,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, if (nbytes < (length - 2)) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d", __FILE__, __PRETTY_FUNCTION__, nbytes, len); - close(zlookup->sock); - zlookup->sock = -1; - zclient_lookup_reconnect(zlookup); + zclient_lookup_failed(zlookup); return -3; } marker = stream_getc(s); @@ -329,7 +340,7 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup, if (zlookup->sock < 0) { zlog_err("%s %s: zclient lookup socket is not connected", __FILE__, __PRETTY_FUNCTION__); - zclient_lookup_reconnect(zlookup); + zclient_lookup_failed(zlookup); return -1; } @@ -343,17 +354,13 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup, if (ret < 0) { zlog_err("%s %s: writen() failure writing to zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); - close(zlookup->sock); - zlookup->sock = -1; - zclient_lookup_reconnect(zlookup); + zclient_lookup_failed(zlookup); return -2; } if (ret == 0) { zlog_err("%s %s: connection closed on zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); - close(zlookup->sock); - zlookup->sock = -1; - zclient_lookup_reconnect(zlookup); + zclient_lookup_failed(zlookup); return -3; } From 199f85ade39f751dd493fe011107736c9b168953 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 30 Sep 2014 16:50:40 -0300 Subject: [PATCH 0573/1342] pimd: Revert: Explicitly restart zclient update connection. --- pimd/pim_zebra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index c4a6f7a8c..68aee687f 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -66,8 +66,6 @@ static void zclient_broken(struct zclient *zclient) /* discard connected addresses because zclient lib will reassign them upon reconnection */ if_connected_reset_all(); - - zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); /* reconnect */ } /* Router-id update message from zebra. */ From ddc6659dd0f05b304ef579dcee6ac803e1a4b6d2 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 30 Sep 2014 16:49:36 -0300 Subject: [PATCH 0574/1342] pimd: sh ip multicast: Display zclient socket fail counter. --- pimd/pim_cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index cc15a09ca..076b7baa6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2096,14 +2096,16 @@ DEFUN (show_ip_multicast, vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Zclient update socket: "); if (qpim_zclient_update) { - vty_out(vty, "%d%s", qpim_zclient_update->sock, VTY_NEWLINE); + vty_out(vty, "%d failures=%d%s", qpim_zclient_update->sock, + qpim_zclient_update->fail, VTY_NEWLINE); } else { vty_out(vty, "%s", VTY_NEWLINE); } vty_out(vty, "Zclient lookup socket: "); if (qpim_zclient_lookup) { - vty_out(vty, "%d%s", qpim_zclient_lookup->sock, VTY_NEWLINE); + vty_out(vty, "%d failures=%d%s", qpim_zclient_lookup->sock, + qpim_zclient_lookup->fail, VTY_NEWLINE); } else { vty_out(vty, "%s", VTY_NEWLINE); From 24e3a9b5ff17553d20a2f9e4ce2a61b5012cd0f6 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 30 Sep 2014 19:14:19 -0300 Subject: [PATCH 0575/1342] pimd: Report del_oif() failure within igmp_source_forward_stop(). --- pimd/pim_igmpv3.c | 4 ++++ pimd/pim_zebra.c | 29 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index b95adb6fc..3baddbfae 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -388,6 +388,10 @@ static void source_channel_oil_detach(struct igmp_source *source) } } +/* + igmp_source_delete: stop fowarding, and delete the source + igmp_source_forward_stop: stop fowarding, but keep the source +*/ void igmp_source_delete(struct igmp_source *source) { struct igmp_group *group; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 68aee687f..fbc7c16ec 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -1073,6 +1073,7 @@ static int del_oif(struct channel_oil *channel_oil, void igmp_source_forward_start(struct igmp_source *source) { struct igmp_group *group; + int result; if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; @@ -1158,9 +1159,12 @@ void igmp_source_forward_start(struct igmp_source *source) } } - if (add_oif(source->source_channel_oil, - group->group_igmp_sock->interface, - PIM_OIF_FLAG_PROTO_IGMP)) { + result = add_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP); + if (result) { + zlog_warn("%s: add_oif() failed with return=%d", + __func__, result); return; } @@ -1174,9 +1178,14 @@ void igmp_source_forward_start(struct igmp_source *source) IGMP_SOURCE_DO_FORWARDING(source->source_flags); } +/* + igmp_source_forward_stop: stop fowarding, but keep the source + igmp_source_delete: stop fowarding, and delete the source + */ void igmp_source_forward_stop(struct igmp_source *source) { struct igmp_group *group; + int result; if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; @@ -1210,14 +1219,14 @@ void igmp_source_forward_stop(struct igmp_source *source) fixes the issue without ill effect, similar to pim_forward_stop below. */ - /*if (del_oif(source->source_channel_oil, - group->group_igmp_sock->interface, - PIM_OIF_FLAG_PROTO_IGMP)) { + result = del_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP); + if (result) { + zlog_warn("%s: del_oif() failed with return=%d", + __func__, result); return; - }*/ - del_oif(source->source_channel_oil, - group->group_igmp_sock->interface, - PIM_OIF_FLAG_PROTO_IGMP); + } /* Feed IGMPv3-gathered local membership information into PIM From 21d1e26dcb4dc290fd0fe05618cbc96c67f85ffe Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Wed, 1 Oct 2014 18:34:04 -0300 Subject: [PATCH 0576/1342] pimd: show ip pim lan-prune-delay: Cosmetic. --- pimd/pim_cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 076b7baa6..eae7dc31c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -831,7 +831,7 @@ static void pim_show_lan_prune_delay(struct vty *vty) "T=t_bit LPD=lan_prune_delay_hello_option%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - vty_out(vty, "Interface Address PrDly OvInt NoDly HiDly HiInt T Neighbor LPD PrDly OvInt T%s", VTY_NEWLINE); + vty_out(vty, "Interface Address PrDly OvInt NoDly HiDly HiInt T | Neighbor LPD PrDly OvInt T%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; @@ -855,7 +855,7 @@ static void pim_show_lan_prune_delay(struct vty *vty) pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); - vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u %-15s %-3s %5u %5u %1u%s", + vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u | %-15s %-3s %5u %5u %1u%s", ifp->name, inet_ntoa(ifaddr), pim_ifp->pim_propagation_delay_msec, From ed14fa00758a156b108854bb35bc5077654f080d Mon Sep 17 00:00:00 2001 From: "Balaji.G" Date: Wed, 8 Oct 2014 01:11:31 -0300 Subject: [PATCH 0577/1342] pimd: Addition of Hello & Join-Prune message debug commands Separate "debug pim packets hello and Join-Prune" added to enable hello and Join-Prune debugs specifically --- pimd/pim_cmd.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++-- pimd/pim_cmd.h | 2 ++ pimd/pim_hello.c | 4 ++-- pimd/pim_pim.c | 2 +- pimd/pimd.h | 8 +++++++ 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index eae7dc31c..6176fe558 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3302,7 +3302,30 @@ DEFUN (debug_pim_packets, DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR) { - PIM_DO_DEBUG_PIM_PACKETS; + PIM_DO_DEBUG_PIM_PACKETS; + vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (debug_pim_packets_filter, + debug_pim_packets_filter_cmd, + "debug pim packets (hello|joins)", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETS_STR + DEBUG_PIM_HELLO_PACKETS_STR + DEBUG_PIM_J_P_PACKETS_STR) +{ + if (strncmp(argv[0],"h",1) == 0) + { + PIM_DO_DEBUG_PIM_HELLO; + vty_out (vty, "PIM Hello debugging is on %s", VTY_NEWLINE); + } + else if (strncmp(argv[0],"j",1) == 0) + { + PIM_DO_DEBUG_PIM_J_P; + vty_out (vty, "PIM Join/Prune debugging is on %s", VTY_NEWLINE); + } return CMD_SUCCESS; } @@ -3312,12 +3335,38 @@ DEFUN (no_debug_pim_packets, NO_STR DEBUG_STR DEBUG_PIM_STR - DEBUG_PIM_PACKETS_STR) + DEBUG_PIM_PACKETS_STR + DEBUG_PIM_HELLO_PACKETS_STR + DEBUG_PIM_J_P_PACKETS_STR) { PIM_DONT_DEBUG_PIM_PACKETS; + vty_out (vty, "PIM Packet debugging is off %s", VTY_NEWLINE); return CMD_SUCCESS; } +DEFUN (no_debug_pim_packets_filter, + no_debug_pim_packets_filter_cmd, + "no debug pim packets (hello|joins)", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_PACKETS_STR + DEBUG_PIM_HELLO_PACKETS_STR + DEBUG_PIM_J_P_PACKETS_STR) +{ + if (strncmp(argv[0],"h",1) == 0) + { + PIM_DONT_DEBUG_PIM_HELLO; + vty_out (vty, "PIM Hello debugging is off %s", VTY_NEWLINE); + } + else if (strncmp(argv[0],"j",1) == 0) + { + PIM_DONT_DEBUG_PIM_J_P; + vty_out (vty, "PIM Join/Prune debugging is off %s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + ALIAS (no_debug_pim_packets, undebug_pim_packets_cmd, "undebug pim packets", @@ -4406,7 +4455,9 @@ void pim_cmd_init() install_element (ENABLE_NODE, &no_debug_pim_events_cmd); install_element (ENABLE_NODE, &undebug_pim_events_cmd); install_element (ENABLE_NODE, &debug_pim_packets_cmd); + install_element (ENABLE_NODE, &debug_pim_packets_filter_cmd); install_element (ENABLE_NODE, &no_debug_pim_packets_cmd); + install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd); install_element (ENABLE_NODE, &undebug_pim_packets_cmd); install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd); @@ -4445,7 +4496,9 @@ void pim_cmd_init() install_element (CONFIG_NODE, &no_debug_pim_events_cmd); install_element (CONFIG_NODE, &undebug_pim_events_cmd); install_element (CONFIG_NODE, &debug_pim_packets_cmd); + install_element (CONFIG_NODE, &debug_pim_packets_filter_cmd); install_element (CONFIG_NODE, &no_debug_pim_packets_cmd); + install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd); install_element (CONFIG_NODE, &undebug_pim_packets_cmd); install_element (CONFIG_NODE, &debug_pim_trace_cmd); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index 391046a43..c50374009 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -42,6 +42,8 @@ #define DEBUG_PIM_STR "PIM protocol activity\n" #define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" +#define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n" +#define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n" #define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n" #define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n" #define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 94e7c945f..128578318 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -204,7 +204,7 @@ int pim_hello_recv(struct interface *ifp, FREE_ADDR_LIST_THEN_RETURN(-2); } - if (PIM_DEBUG_PIM_TRACE) { + if (PIM_DEBUG_PIM_TRACE || PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", @@ -262,7 +262,7 @@ int pim_hello_recv(struct interface *ifp, } break; case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: - if (PIM_DEBUG_PIM_TRACE) { + if (PIM_DEBUG_PIM_TRACE || PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index fb6c3acb9..04823c21e 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -509,7 +509,7 @@ static int hello_send(struct interface *ifp, pim_ifp = ifp->info; - if (PIM_DEBUG_PIM_PACKETS) { + if (PIM_DEBUG_PIM_PACKETS || PIM_DEBUG_PIM_HELLO) { char dst_str[100]; pim_inet4_dump("", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", diff --git a/pimd/pimd.h b/pimd/pimd.h index b0a1b648d..22a29220d 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -64,6 +64,8 @@ #define PIM_MASK_ZEBRA (1 << 8) #define PIM_MASK_SSMPINGD (1 << 9) #define PIM_MASK_MROUTE (1 << 10) +#define PIM_MASK_PIM_HELLO (1 << 11) +#define PIM_MASK_PIM_J_P (1 << 12) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; @@ -114,6 +116,8 @@ int64_t qpim_mroute_del_last; #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) #define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE) +#define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO) +#define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) @@ -130,6 +134,8 @@ int64_t qpim_mroute_del_last; #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) #define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) #define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE) +#define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO) +#define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) @@ -142,6 +148,8 @@ int64_t qpim_mroute_del_last; #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) #define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE) +#define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO) +#define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P) void pim_init(void); void pim_terminate(void); From d632689579bbcbfb5f38c3faf05ad675e002c059 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 19 Jan 2015 16:50:24 -0200 Subject: [PATCH 0578/1342] pimd: Fix configuration file reading upon startup Without the fix, qpimd issues this error message: pim_if_add_vif: ifindex=0 < 1 on interface swp1 It happens because in pim_main.c:main() we are initializing zebra with pim_zebra_init() after we read in the configuration with vty_read_config(). See also: https://github.com/udhos/qpimd/issues/3 --- pimd/pim_main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index c646356ae..b57f88113 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -216,6 +216,11 @@ int main(int argc, char** argv, char** envp) { zlog_default->maxlvl[ZLOG_DEST_STDOUT] = ZLOG_DISABLED; #endif + /* + Initialize zclient "update" and "lookup" sockets + */ + pim_zebra_init(zebra_sock_path); + zlog_notice("Loading configuration - begin"); /* Get configuration file. */ @@ -278,12 +283,6 @@ int main(int argc, char** argv, char** envp) { zlog_notice("!HAVE_CLOCK_MONOTONIC"); #endif - - /* - Initialize zclient "update" and "lookup" sockets - */ - pim_zebra_init(zebra_sock_path); - while (thread_fetch(master, &thread)) thread_call(&thread); From 85385f7eeee14d529065db7b863478c3ba455dd4 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 19 Jan 2015 18:25:45 -0200 Subject: [PATCH 0579/1342] pimd: Log ifindex found for an interface when zebra lib reports a new connected address. --- pimd/pim_iface.c | 12 ++++++------ pimd/pim_pim.c | 4 ++-- pimd/pim_zebra.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 770bd4e00..ecf9ef6bc 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -388,12 +388,12 @@ void pim_if_addr_add(struct connected *ifc) if (!if_is_operative(ifp)) return; - if (PIM_DEBUG_ZEBRA) { + /* if (PIM_DEBUG_ZEBRA) */ { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); - zlog_debug("%s: %s connected IP address %s %s", + zlog_debug("%s: %s ifindex=%d connected IP address %s %s", __PRETTY_FUNCTION__, - ifp->name, buf, + ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } @@ -507,12 +507,12 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ifp = ifc->ifp; zassert(ifp); - if (PIM_DEBUG_ZEBRA) { + /* if (PIM_DEBUG_ZEBRA) */ { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); - zlog_debug("%s: %s disconnected IP address %s %s", + zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s", __PRETTY_FUNCTION__, - ifp->name, buf, + ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 04823c21e..f6f4c9535 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -725,8 +725,8 @@ int pim_sock_add(struct interface *ifp) pim_ifp->pim_generation_id = pim_rand() & (int64_t) 0xFFFFFFFF; - zlog_info("PIM INTERFACE UP: on interface %s", - ifp->name); + zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", + ifp->name, ifp->ifindex); /* * Start receiving PIM messages diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index fbc7c16ec..f1840245f 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -150,7 +150,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, if (!ifp) return 0; - zlog_info("INTERFACE UP: %s", ifp->name); + zlog_info("INTERFACE UP: %s ifindex=%d", ifp->name, ifp->ifindex); if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", @@ -182,7 +182,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, if (!ifp) return 0; - zlog_info("INTERFACE DOWN: %s", ifp->name); + zlog_info("INTERFACE DOWN: %s ifindex=%d", ifp->name, ifp->ifindex); if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", From 1b47764f50cc074ba795d2b4477a3bc2372a8d9b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:15:34 +0100 Subject: [PATCH 0580/1342] redhat: revert non-pim changes in .spec No idea what weird Fedora magic this does... if it's needed, it can be pushed separately from pimd. Signed-off-by: David Lamparter --- redhat/quagga.spec.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 35d691bac..75835bbe9 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -48,16 +48,16 @@ %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. -%if "%dist" == "fc4" || "%dist" == "fc5" +%if "%dist" != "fc2" || "%dist" != "fc3" %define quagga_buildreqs %{quagga_buildreqs} texi2html %endif # pam_stack is deprecated in FC5 # default to pam_stack, default should be changed later. -%if "%dist" == "fc5" -%define quagga_pam_source quagga.pam -%else +%if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack +%else +%define quagga_pam_source quagga.pam %endif ############################################################################ From b3c6afe9fdc8c65d71abde3a2f26525b87189297 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:32:28 +0100 Subject: [PATCH 0581/1342] Revert "pimd: Revert: Explicitly restart zclient update connection." This reverts commit 199f85ade39f751dd493fe011107736c9b168953. This depends on the zebra reconnect changes, which we're not picking up at this point. Signed-off-by: David Lamparter --- pimd/pim_zebra.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index f1840245f..63d029b2e 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -66,6 +66,8 @@ static void zclient_broken(struct zclient *zclient) /* discard connected addresses because zclient lib will reassign them upon reconnection */ if_connected_reset_all(); + + zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); /* reconnect */ } /* Router-id update message from zebra. */ From a2805de2b25383695f38a3ebbefe75e26a5e9aba Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:33:26 +0100 Subject: [PATCH 0582/1342] Revert "pimd: Explicitly restart zclient update connection." This reverts commit 8150beed9a4f50a72696a65c1f40889ab65ad7ff. This depends on the zebra reconnect changes, which we're not picking up at this point. Signed-off-by: David Lamparter --- pimd/pim_zebra.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 63d029b2e..8d015737e 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -66,8 +66,6 @@ static void zclient_broken(struct zclient *zclient) /* discard connected addresses because zclient lib will reassign them upon reconnection */ if_connected_reset_all(); - - zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); /* reconnect */ } /* Router-id update message from zebra. */ @@ -679,12 +677,11 @@ void pim_zebra_init(char *zebra_sock_path) qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route; qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route; + zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); if (PIM_DEBUG_PIM_TRACE) { zlog_info("zclient_init cleared redistribution request"); } - zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); - zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM); /* Request all redistribution */ From 5d5af78a1b9310c0c2290f81ee8abc12d5376500 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:33:59 +0100 Subject: [PATCH 0583/1342] Revert "pim: Remove connected addresses on loss of zebra connection." This reverts commit 96b6dfe98793549aca6a7cc77eaf0957b1168ed2. This depends on the zebra reconnect changes, which we're not picking up at this point. Signed-off-by: David Lamparter --- pimd/pim_zebra.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 8d015737e..43c80c8b9 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -63,9 +63,7 @@ static void zclient_broken(struct zclient *zclient) pim_if_addr_del_all(ifp); } - /* discard connected addresses because zclient lib will reassign - them upon reconnection */ - if_connected_reset_all(); + /* upon return, zclient will discard connected addresses */ } /* Router-id update message from zebra. */ From bb7feff0af6c8519df45a4f40f06cdd819fe70d0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:40:25 +0100 Subject: [PATCH 0584/1342] Revert "pimd: clear zclient-update: Reset zclient update connection to zebra daemon" This reverts commit 3456a80f5f8e6e44c30453bd92eabf5faf7ab25b. Conflicts: pimd/pim_zebra.c This depends on the zebra reconnect changes, which we're not picking up at this point. This revert is partial, only bumping out the reconnect-related changes. Signed-off-by: David Lamparter --- pimd/COMMANDS | 1 - pimd/pim_cmd.c | 12 ------------ pimd/pim_zebra.c | 1 - 3 files changed, 14 deletions(-) diff --git a/pimd/COMMANDS b/pimd/COMMANDS index 2dedea064..425ac8229 100644 --- a/pimd/COMMANDS +++ b/pimd/COMMANDS @@ -60,7 +60,6 @@ debug commands: clear ip mroute Reset multicast routes clear ip pim interfaces Reset PIM interfaces clear ip pim oil Rescan PIM OIL (output interface list) - clear zclient-update Reset zclient update connection to zebra daemon debug igmp IGMP protocol activity debug mroute PIM interaction with kernel MFC cache debug pim PIM protocol activity diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 6176fe558..6b2ac6646 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1563,17 +1563,6 @@ DEFUN (pim_interface, return CMD_SUCCESS; } -DEFUN (clear_zclient_update, - clear_zclient_update_cmd, - "clear zclient-update", - CLEAR_STR - "Reset zclient update connection to zebra daemon\n") -{ - zclient_reset(qpim_zclient_update); - - return CMD_SUCCESS; -} - DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, "clear ip interfaces", @@ -4391,7 +4380,6 @@ void pim_cmd_init() install_element (ENABLE_NODE, &clear_ip_mroute_cmd); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd); - install_element (ENABLE_NODE, &clear_zclient_update_cmd); install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); install_element (ENABLE_NODE, &show_ip_igmp_join_cmd); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 43c80c8b9..6f241d596 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -664,7 +664,6 @@ void pim_zebra_init(char *zebra_sock_path) /* Socket for receiving updates from Zebra daemon */ qpim_zclient_update = zclient_new(); - qpim_zclient_update->zclient_broken = zclient_broken; qpim_zclient_update->router_id_update = pim_router_id_update_zebra; qpim_zclient_update->interface_add = pim_zebra_if_add; qpim_zclient_update->interface_delete = pim_zebra_if_del; From 60b815eb26c4e94e07524a508433e6f66a6d6183 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:53:46 +0100 Subject: [PATCH 0585/1342] vtysh: add missing pimd define Signed-off-by: David Lamparter --- vtysh/vtysh.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 5d513c8da..1681a71ae 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -30,6 +30,7 @@ #define VTYSH_BGPD 0x20 #define VTYSH_ISISD 0x40 #define VTYSH_BABELD 0x80 +#define VTYSH_PIMD 0x100 #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD From 7d924b422ffdeb37027ac979c6a62d845499fab8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 07:00:06 +0100 Subject: [PATCH 0586/1342] doc: list pimd.8 in EXTRA_DIST Signed-off-by: David Lamparter --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index dfc5e402c..bb7e87a18 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -109,7 +109,7 @@ endif EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ - ripngd.8 vtysh.1 watchquagga.8 zebra.8 \ + ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) From 143637198e333f0c822766b38f9d8cfe75c04e21 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 07:26:03 +0100 Subject: [PATCH 0587/1342] tests: fix tests for 1a211cb (missing well-known) Fix tests/aspathtest.c again, this time by including a NEXT_HOP attribute (which is out of correct order with AS_PATH, but that doesn't matter here.) This satisfies bgp_attr_check(), which after 1a211cb refuses updates without nexthop attribute. Fixes: 1a211cb ("one more fix for tightening of check for missing well-known attributes") Cc: Paul Jakma Signed-off-by: David Lamparter --- tests/aspath_test.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 71a310222..0aa3e47e7 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -457,8 +457,11 @@ static struct test_segment { BGP_ATTR_FLAG_TRANS, \ BGP_ATTR_ORIGIN, \ 1, \ - BGP_ORIGIN_EGP -#define COMMON_ATTR_SIZE 4 + BGP_ORIGIN_EGP, \ + BGP_ATTR_FLAG_TRANS, \ + BGP_ATTR_NEXT_HOP, \ + 4, 192, 0, 2, 0 +#define COMMON_ATTR_SIZE 11 /* */ static struct aspath_tests { From cb4fc59c8a0f9df81109d38acbeaab5627e361f5 Mon Sep 17 00:00:00 2001 From: Milan Kocian Date: Mon, 1 Dec 2014 12:48:25 +0000 Subject: [PATCH 0588/1342] bgpd: fix negative values in output Negative value in output of ecommunities (and as numbers) seems odd :-). This patch fixes it. And add minor formating modification, better for big as numbers. Signed-off-by: Milan Kocian Signed-off-by: David Lamparter --- bgpd/bgp_ecommunity.c | 6 +++--- bgpd/bgp_vty.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 8a326a8bb..482e76b74 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -688,7 +688,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) eas.val = (*pnt++ << 8); eas.val |= (*pnt++); - len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix, + len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix, eas.as, eas.val ); str_pnt += len; first = 0; @@ -703,7 +703,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) eas.val |= (*pnt++ << 8); eas.val |= (*pnt++); - len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix, + len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix, eas.as, eas.val); str_pnt += len; first = 0; @@ -715,7 +715,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) eip.val = (*pnt++ << 8); eip.val |= (*pnt++); - len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix, + len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix, inet_ntoa (eip.ip), eip.val); str_pnt += len; first = 0; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ca44774ac..e6a36605f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6937,7 +6937,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) int len; /* Header string for each address family. */ - static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd"; + static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd"; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { @@ -8302,7 +8302,7 @@ bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient, vty_out (vty, "4 "); - vty_out (vty, "%11d ", rsclient->as); + vty_out (vty, "%10u ", rsclient->as); rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]); if ( rmname && strlen (rmname) > 13 ) @@ -8347,7 +8347,7 @@ bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp, int count = 0; /* Header string for each address family. */ - static char header[] = "Neighbor V AS Export-Policy Import-Policy Up/Down State"; + static char header[] = "Neighbor V AS Export-Policy Import-Policy Up/Down State"; for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, peer)) { From 86ce951e349fd08d1ba2c66f5f6d07756689422a Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Thu, 8 Jan 2015 01:39:18 +0000 Subject: [PATCH 0589/1342] ospfd: set O-bit in the option of all DD packets If opaque-capability is enabled, we must set the O-bit in the option field of all DD packets. Changing the option field of DD packets may cause the peer to reset the state back to ExStart. Signed-off-by: Feng Lu Signed-off-by: David Lamparter --- ospfd/ospf_packet.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 36aa8958a..98b1af3bf 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3143,22 +3143,7 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, options = OPTIONS (oi); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) - { - if (IS_SET_DD_I (nbr->dd_flags) - || CHECK_FLAG (nbr->options, OSPF_OPTION_O)) - /* - * Set O-bit in the outgoing DD packet for capablity negotiation, - * if one of following case is applicable. - * - * 1) WaitTimer expiration event triggered the neighbor state to - * change to Exstart, but no (valid) DD packet has received - * from the neighbor yet. - * - * 2) At least one DD packet with O-bit on has received from the - * neighbor. - */ - SET_FLAG (options, OSPF_OPTION_O); - } + SET_FLAG (options, OSPF_OPTION_O); #endif /* HAVE_OPAQUE_LSA */ stream_putc (s, options); From 92cff4f7cd7e805e6689e73e63029aaccd145eca Mon Sep 17 00:00:00 2001 From: Lu Feng Date: Thu, 8 Jan 2015 01:21:02 +0000 Subject: [PATCH 0590/1342] isisd: fix crash on changing the circuit type of a passive interface Signed-off-by: Feng Lu Signed-off-by: David Lamparter --- isisd/isis_events.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 3887b7c5a..96d5762d3 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -280,26 +280,29 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) return; } - switch (circuit->is_type) + if (! circuit->is_passive) { - case IS_LEVEL_1: - if (newtype == IS_LEVEL_2) - circuit_resign_level (circuit, 1); - circuit_commence_level (circuit, 2); - break; - case IS_LEVEL_1_AND_2: - if (newtype == IS_LEVEL_1) - circuit_resign_level (circuit, 2); - else - circuit_resign_level (circuit, 1); - break; - case IS_LEVEL_2: - if (newtype == IS_LEVEL_1) - circuit_resign_level (circuit, 2); - circuit_commence_level (circuit, 1); - break; - default: - break; + switch (circuit->is_type) + { + case IS_LEVEL_1: + if (newtype == IS_LEVEL_2) + circuit_resign_level (circuit, 1); + circuit_commence_level (circuit, 2); + break; + case IS_LEVEL_1_AND_2: + if (newtype == IS_LEVEL_1) + circuit_resign_level (circuit, 2); + else + circuit_resign_level (circuit, 1); + break; + case IS_LEVEL_2: + if (newtype == IS_LEVEL_1) + circuit_resign_level (circuit, 2); + circuit_commence_level (circuit, 1); + break; + default: + break; + } } circuit->is_type = newtype; From 3c28aaf437d8d473adb89c5e74574a61a9ea7cc6 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Wed, 28 Jan 2015 18:09:30 +0000 Subject: [PATCH 0591/1342] isisd: match adjacency with source of hellos isis_pdu.c: match adjacency with source of hellos, check for source ID on receiving hello If an adjacency exists, check the adjacency is with the same router as the source of the hellos. In case a mismatch is detected, bring down the adjacency and let the next hellos trigger creating the new adjacency. Signed-off-by: Amritha Nambiar Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 8d8a5e001..166dd7c09 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -566,6 +566,17 @@ process_p2p_hello (struct isis_circuit *circuit) * the circuit */ adj = circuit->u.p2p.neighbor; + /* If an adjacency exists, check it is with the source of the hello + * packets */ + if (adj) + { + if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) + { + zlog_debug("hello source and adjacency do not match, set adj down\n"); + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "adj do not exist"); + return 0; + } + } if (!adj || adj->level != hdr->circuit_t) { if (!adj) From 9481374d4ff7cfbc6274954bff8b0e4c52578911 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 24 Apr 2014 20:22:53 +0200 Subject: [PATCH 0592/1342] zebra: factor out rib debug logs Introduces a logging function that takes a struct route_node * argument, and prefixes log output with that node's prefix. While this removes some duplication, it will also later be useful for srcdest route nodes. Behaviour before and after the patch should be exactly identical. Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 114 +++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 245011ebf..4ee1a84c8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -75,6 +75,37 @@ static const struct /* Vector for routing table. */ static vector vrf_vector; +static void +_rnode_zlog(const char *_func, struct route_node *rn, int priority, + const char *msgfmt, ...) +{ + char buf[INET6_ADDRSTRLEN + 4], *bptr; + char msgbuf[512]; + va_list ap; + + va_start(ap, msgfmt); + vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap); + va_end(ap); + + if (rn) + { + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); + bptr = buf + strlen(buf); + snprintf(bptr, buf + sizeof(buf) - bptr, "/%d", rn->p.prefixlen); + } + else + { + snprintf(buf, sizeof(buf), "{(route_node *) NULL}"); + } + + zlog (NULL, priority, "%s: %s: %s", _func, buf, msgbuf); +} + +#define rnode_debug(node, ...) \ + _rnode_zlog(__func__, node, LOG_DEBUG, __VA_ARGS__) +#define rnode_info(node, ...) \ + _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) + /* * vrf_table_create */ @@ -1209,7 +1240,6 @@ int rib_gc_dest (struct route_node *rn) { rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; dest = rib_dest_from_rnode (rn); if (!dest) @@ -1219,11 +1249,7 @@ rib_gc_dest (struct route_node *rn) return 0; if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); - zlog_debug ("%s: %s/%d: removing dest from table", __func__, - buf, rn->p.prefixlen); - } + rnode_debug (rn, "removing dest from table"); dest->rnode = NULL; XFREE (MTYPE_RIB_DEST, dest); @@ -1248,16 +1274,12 @@ rib_process (struct route_node *rn) int installed = 0; struct nexthop *nexthop = NULL, *tnexthop; int recursing; - char buf[INET6_ADDRSTRLEN]; rib_table_info_t *info; assert (rn); info = rn->table->info; - if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - RNODE_FOREACH_RIB_SAFE (rn, rib, next) { /* Currently installed rib. */ @@ -1275,8 +1297,7 @@ rib_process (struct route_node *rn) if (rib != fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, - buf, rn->p.prefixlen, rn, rib); + rnode_debug (rn, "rn %p, removing rib %p", rn, rib); rib_unlink (rn, rib); } else @@ -1350,8 +1371,8 @@ rib_process (struct route_node *rn) if (select && select == fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", - __func__, buf, rn->p.prefixlen, select, fib); + rnode_debug (rn, "Updating existing route, select %p, fib %p", + select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { zfpm_trigger_update (rn, "updating existing route"); @@ -1395,8 +1416,7 @@ rib_process (struct route_node *rn) if (fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, - buf, rn->p.prefixlen, fib); + rnode_debug (rn, "Removing existing route, fib %p", fib); zfpm_trigger_update (rn, "removing existing route"); @@ -1416,8 +1436,7 @@ rib_process (struct route_node *rn) if (select) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, - rn->p.prefixlen, select); + rnode_debug (rn, "Adding route, select %p", select); zfpm_trigger_update (rn, "new route selected"); @@ -1434,14 +1453,13 @@ rib_process (struct route_node *rn) if (del) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf, - rn->p.prefixlen, del, rn); + rnode_debug (rn, "Deleting fib %p, rn %p", del, rn); rib_unlink (rn, del); } end: if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); + rnode_debug (rn, "rn %p dequeued", rn); /* * Check if the dest can be deleted now. @@ -1525,10 +1543,6 @@ static void rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) { struct rib *rib; - char buf[INET6_ADDRSTRLEN]; - - if (IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); RNODE_FOREACH_RIB (rn, rib) { @@ -1539,8 +1553,8 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) RIB_ROUTE_QUEUED (qindex))) { if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", - __func__, buf, rn->p.prefixlen, rn, qindex); + rnode_debug (rn, "rn %p is already queued in sub-queue %u", + rn, qindex); continue; } @@ -1550,8 +1564,8 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) mq->size++; if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", - __func__, buf, rn->p.prefixlen, rn, qindex); + rnode_debug (rn, "queued rn %p into sub-queue %u", + rn, qindex); } } @@ -1559,11 +1573,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { - char buf[INET_ADDRSTRLEN]; assert (zebra && rn); - - if (IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); /* Pointless to queue a route_node with no RIB entries to add or remove */ if (!rnode_to_ribs (rn)) @@ -1575,7 +1585,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) } if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); + rnode_info (rn, "work queue added"); assert (zebra); @@ -1599,7 +1609,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) rib_meta_queue_add (zebra->mq, rn); if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); + rnode_debug (rn, "rn %p queued", rn); return; } @@ -1696,25 +1706,17 @@ rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; assert (rib && rn); if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, - buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, rib %p", rn, rib); dest = rib_dest_from_rnode (rn); if (!dest) { if (IS_ZEBRA_DEBUG_RIB) - { - zlog_debug ("%s: %s/%d: adding dest to table", __func__, - buf, rn->p.prefixlen); - } + rnode_debug (rn, "adding dest to table"); dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t)); route_lock_node (rn); /* rn route table reference */ @@ -1741,12 +1743,8 @@ rib_addnode (struct route_node *rn, struct rib *rib) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", - __func__, buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, un-removed rib %p", rn, rib); + UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); return; } @@ -1765,17 +1763,12 @@ rib_addnode (struct route_node *rn, struct rib *rib) static void rib_unlink (struct route_node *rn, struct rib *rib) { - char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, rib %p", - __func__, buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, rib %p", rn, rib); dest = rib_dest_from_rnode (rn); @@ -1799,12 +1792,7 @@ static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) - { - char buf[INET6_ADDRSTRLEN]; - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, - buf, rn->p.prefixlen, rn, rib); - } + rnode_debug (rn, "rn %p, rib %p, removing", rn, rib); SET_FLAG (rib->status, RIB_ENTRY_REMOVED); rib_queue_add (&zebrad, rn); } From ab2ba612320e011abbb1011823b66afc35859081 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:02:13 +0100 Subject: [PATCH 0593/1342] zebra: identify MRIB on debug messages since the same code handles both URIB and MRIB, the debug messages can get rather confusing if the RIB isn't identified. Mark the MRIB in debug messages so we can distinguish that. Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 4ee1a84c8..8354513c5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -89,9 +89,12 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, if (rn) { + rib_table_info_t *info = rn->table->info; + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); bptr = buf + strlen(buf); - snprintf(bptr, buf + sizeof(buf) - bptr, "/%d", rn->p.prefixlen); + snprintf(bptr, buf + sizeof(buf) - bptr, "/%d%s", rn->p.prefixlen, + info->safi == SAFI_MULTICAST ? " (MRIB)" : ""); } else { From 3dea1780c98ab3717c9c61f401b66a9c08a23661 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 22 Sep 2014 19:35:51 -0300 Subject: [PATCH 0594/1342] zebra: add rib_match_ipv4_safi() This is the same as rib_lookup_ipv4(), without the SAFI hardcoded. Cc: Balaji G Cc: Everton Marques Signed-off-by: David Lamparter --- zebra/rib.h | 1 + zebra/zebra_rib.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/zebra/rib.h b/zebra/rib.h index d3a83c68a..13011e26e 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -419,6 +419,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, u_int32_t, safi_t safi); extern struct rib *rib_match_ipv4 (struct in_addr); +extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8354513c5..5b9b00ed6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -781,6 +781,63 @@ rib_match_ipv4 (struct in_addr addr) return NULL; } +struct rib * +rib_match_ipv4_safi (struct in_addr addr, safi_t safi) +{ + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop, *tnewhop; + int recursing; + + /* Lookup table. */ + table = vrf_table (AFI_IP, safi, 0); + if (! table) + return 0; + + rn = route_node_match_ipv4 (table, &addr); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + RNODE_FOREACH_RIB (rn, match) + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} + struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p) { From f9b9234bae058a7d152c51c318997c459f54e59d Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 21 Nov 2014 15:57:45 -0800 Subject: [PATCH 0595/1342] zebra: point rib_match_ipv4() to ._safi() Since rib_match_ipv4() is just rib_match_ipv4_safi() for SAFI_UNICAST, the former can be removed and pointed to the latter instead. Cc: Balaji G Cc: Everton Marques Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 59 +---------------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b9b00ed6..469c10b21 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -721,64 +721,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct rib * rib_match_ipv4 (struct in_addr addr) { - struct prefix_ipv4 p; - struct route_table *table; - struct route_node *rn; - struct rib *match; - struct nexthop *newhop, *tnewhop; - int recursing; - - /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); - if (! table) - return 0; - - memset (&p, 0, sizeof (struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = addr; - - rn = route_node_match (table, (struct prefix *) &p); - - while (rn) - { - route_unlock_node (rn); - - /* Pick up selected route. */ - RNODE_FOREACH_RIB (rn, match) - { - if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) - continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; - } - - /* If there is no selected route or matched route is EGP, go up - tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) - { - do { - rn = rn->parent; - } while (rn && rn->info == NULL); - if (rn) - route_lock_node (rn); - } - else - { - if (match->type == ZEBRA_ROUTE_CONNECT) - /* Directly point connected route. */ - return match; - else - { - for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) - if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) - return match; - return NULL; - } - } - } - return NULL; + return rib_match_ipv4_safi (addr, SAFI_UNICAST); } struct rib * From 4e5275befee4acd91edd835a0b037cc2161ff834 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 1 Jul 2014 15:15:52 -0300 Subject: [PATCH 0596/1342] zebra: add ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB This adds a new zapi call "ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB" performing a Multicast RPF lookup for a given source. Details of the lookup behaviour are left to the zebra side of things. Note: this is non-reactive, as in, only delivers a snapshot of the state at a particular point in time. There's no push notification of changes happening to the RIB. This combines the following 3 original patches: - zebra: add zsend_ipv4_nexthop_lookup_mrib() - zserv: Query mrib (SAFI_MULTICAST). - zebra: Cleanups to zebra_rib. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- lib/zebra.h | 3 +- zebra/zserv.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/lib/zebra.h b/lib/zebra.h index b289a19e1..a4e02148d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -425,7 +425,8 @@ struct in_pktinfo #define ZEBRA_ROUTER_ID_DELETE 21 #define ZEBRA_ROUTER_ID_UPDATE 22 #define ZEBRA_HELLO 23 -#define ZEBRA_MESSAGE_MAX 24 +#define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24 +#define ZEBRA_MESSAGE_MAX 25 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new diff --git a/zebra/zserv.c b/zebra/zserv.c index ca17c2c6d..89eb266a1 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -599,6 +599,89 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) return zebra_server_send_message(client); } +/* + Modified version of zsend_ipv4_nexthop_lookup(): + Query unicast rib if nexthop is not found on mrib. + Returns both route metric and protocol distance. +*/ +static int +zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + + /* Lookup nexthop. */ + rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST); + + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); + + if (!rib) { + /* Retry lookup with unicast rib */ + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST); + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: %s rib entry found.", __func__, rib ? "Matching" : "No matching"); + } + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + /* Fill in result. */ + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); + stream_put_in_addr (s, &addr); + + if (rib) + { + stream_putc (s, rib->distance); + stream_putl (s, rib->metric); + num = 0; + nump = stream_get_endp(s); /* remember position for nexthop_num */ + stream_putc (s, 0); /* reserve room for nexthop_num */ + /* 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) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + default: + /* do nothing */ + break; + } + num++; + } + + stream_putc_at (s, nump, num); /* store nexthop_num */ + } + else + { + stream_putc (s, 0); /* distance */ + stream_putl (s, 0); /* metric */ + stream_putc (s, 0); /* nexthop_num */ + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + return zebra_server_send_message(client); +} + static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) { @@ -920,6 +1003,16 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) return zsend_ipv4_nexthop_lookup (client, addr); } +/* MRIB Nexthop lookup for IPv4. */ +static int +zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length) +{ + struct in_addr addr; + + addr.s_addr = stream_get_ipv4 (client->ibuf); + return zsend_ipv4_nexthop_lookup_mrib (client, addr); +} + /* Nexthop lookup for IPv4. */ static int zread_ipv4_import_lookup (struct zserv *client, u_short length) @@ -1352,6 +1445,9 @@ zebra_client_read (struct thread *thread) case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; + case ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB: + zread_ipv4_nexthop_lookup_mrib (client, length); + break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); From 83d711234a22a2e7996905667468b0276e5b2c57 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Fri, 19 Sep 2014 16:39:34 -0300 Subject: [PATCH 0597/1342] zebra: mrib: Include BGP routes in RPF lookups The rib_match_ipv4() function was previously used only for iBGP recursive nexthop lookups, which ignore eBGP routes. This is not desirable for PIM RPF lookups, which may well use an eBGP route. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 2 +- zebra/zebra_rib.c | 7 +++---- zebra/zserv.c | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 13011e26e..aef715008 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -419,7 +419,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, u_int32_t, safi_t safi); extern struct rib *rib_match_ipv4 (struct in_addr); -extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi); +extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 469c10b21..f4a915542 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -721,11 +721,11 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct rib * rib_match_ipv4 (struct in_addr addr) { - return rib_match_ipv4_safi (addr, SAFI_UNICAST); + return rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); } struct rib * -rib_match_ipv4_safi (struct in_addr addr, safi_t safi) +rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) { struct route_table *table; struct route_node *rn; @@ -755,8 +755,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi) /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP))) { do { rn = rn->parent; diff --git a/zebra/zserv.c b/zebra/zserv.c index 89eb266a1..1b6931593 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -612,16 +612,17 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr) unsigned long nump; u_char num; struct nexthop *nexthop; + int skip_bgp = 0; /* bool */ /* Lookup nexthop. */ - rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST); + rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); if (!rib) { /* Retry lookup with unicast rib */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: %s rib entry found.", __func__, rib ? "Matching" : "No matching"); } From f598cf7ecc8dd72dca08e97eb766e5ccaabe3424 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 22 Nov 2014 14:44:20 -0800 Subject: [PATCH 0598/1342] zebra: kill rib_match_ipv4() Since this function is internal to zebra, there is no reason to keep this one-line indirect wrapper to rib_match_ipv4_safi() around. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 1 - zebra/zebra_rib.c | 6 ------ zebra/zserv.c | 4 ++-- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index aef715008..d40b17e81 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -418,7 +418,6 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, u_int32_t, safi_t safi); -extern struct rib *rib_match_ipv4 (struct in_addr); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f4a915542..08ce96452 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -718,12 +718,6 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } #endif /* HAVE_IPV6 */ -struct rib * -rib_match_ipv4 (struct in_addr addr) -{ - return rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); -} - struct rib * rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) { diff --git a/zebra/zserv.c b/zebra/zserv.c index 1b6931593..e9236deca 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -539,8 +539,8 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) u_char num; struct nexthop *nexthop; - /* Lookup nexthop. */ - rib = rib_match_ipv4 (addr); + /* Lookup nexthop - eBGP excluded */ + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); /* Get output stream. */ s = client->obuf; From 33d86db3df7052da33990b47ad5a171dad6df691 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Mon, 14 Jul 2014 11:19:00 -0300 Subject: [PATCH 0599/1342] zebra: mrib: static route support With the MRIB being independent from the Unicast RIB, there's currently now way to add static routes to the MRIB. Address that by adding a separate set of commands for MRIB static routes. Combines these original patches: - zebra: mrib: ip mroute command to add unicast route to MRIB for multicast RPF. - zebra: mrib: no ip mroute: Fix removal of static multicast RPF route. - zebra: mrib: remove unused static_add/delete_ipv4 - zebra: Cleanups to zebra_rib. - pimd: Merge pim-only branch. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 10 +++--- zebra/zebra_rib.c | 30 ++++++++-------- zebra/zebra_vty.c | 87 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 36 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index d40b17e81..5eedfde6f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -430,12 +430,12 @@ extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); extern int -static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id); - +static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char flags, u_char distance, + u_int32_t vrf_id); extern int -static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char distance, u_int32_t vrf_id); +static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char distance, u_int32_t vrf_id); #ifdef HAVE_IPV6 extern int diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 08ce96452..a07036e59 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2276,14 +2276,14 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Install static route into rib. */ static void -static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) +static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) { struct rib *rib; struct route_node *rn; struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return; @@ -2368,7 +2368,7 @@ static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) /* Uninstall static route from RIB. */ static void -static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) +static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) { struct route_node *rn; struct rib *rib; @@ -2376,7 +2376,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return; @@ -2427,10 +2427,10 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) route_unlock_node (rn); } -/* Add static route into static route configuration. */ int -static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id) +static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char flags, u_char distance, + u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2441,7 +2441,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + stable = vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2475,7 +2475,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, /* Distance changed. */ if (update) - static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); + static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); @@ -2517,15 +2517,14 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, si->next = cp; /* Install into rib. */ - static_install_ipv4 (p, si); + static_install_ipv4 (safi, p, si); return 1; } -/* Delete static route from static route configuration. */ int -static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char distance, u_int32_t vrf_id) +static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char distance, u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2533,7 +2532,7 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + stable = vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2565,7 +2564,7 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, } /* Install into rib. */ - static_uninstall_ipv4 (p, si); + static_uninstall_ipv4 (safi, p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -2586,7 +2585,6 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, return 1; } - #ifdef HAVE_IPV6 static int rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 9d6c1dddb..6802eceb5 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -30,11 +30,14 @@ #include "zebra/zserv.h" -/* General fucntion for static route. */ +static int do_show_ip_route(struct vty *vty, safi_t safi); + +/* General function for static route. */ static int -zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, - const char *mask_str, const char *gate_str, - const char *flag_str, const char *distance_str) +zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, + const char *dest_str, const char *mask_str, + const char *gate_str, const char *flag_str, + const char *distance_str) { int ret; u_char distance; @@ -81,9 +84,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, return CMD_WARNING; } if (add_cmd) - static_add_ipv4 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); + static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); else - static_delete_ipv4 (&p, NULL, NULL, distance, 0); + static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, 0); return CMD_SUCCESS; } @@ -107,9 +110,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, if (gate_str == NULL) { if (add_cmd) - static_add_ipv4 (&p, NULL, NULL, flag, distance, 0); + static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, 0); else - static_delete_ipv4 (&p, NULL, NULL, distance, 0); + static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, 0); return CMD_SUCCESS; } @@ -123,13 +126,58 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, ifname = gate_str; if (add_cmd) - static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, distance, 0); + static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, 0); else - static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); + static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, 0); return CMD_SUCCESS; } +static int +zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, + const char *mask_str, const char *gate_str, + const char *flag_str, const char *distance_str) +{ + return zebra_static_ipv4_safi(vty, SAFI_UNICAST, add_cmd, dest_str, mask_str, gate_str, flag_str, distance_str); +} + +/* Static unicast routes for multicast RPF lookup. */ +DEFUN (ip_mroute, + ip_mroute_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n") +{ + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, argv[2]); +} + +DEFUN (no_ip_mroute, + no_ip_mroute_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n") +{ + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, argv[2]); +} + +DEFUN (show_ip_rpf, + show_ip_rpf_cmd, + "show ip rpf", + SHOW_STR + IP_STR + "Display RPF information for multicast source\n") +{ + return do_show_ip_route(vty, SAFI_MULTICAST); +} + /* Static route configuration. */ DEFUN (ip_route, ip_route_cmd, @@ -788,12 +836,16 @@ DEFUN (show_ip_route, IP_STR "IP routing table\n") { + return do_show_ip_route(vty, SAFI_UNICAST); +} + +static int do_show_ip_route(struct vty *vty, safi_t safi) { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return CMD_SUCCESS; @@ -1195,7 +1247,7 @@ DEFUN (show_ip_route_summary_prefix, /* Write IPv4 static route configuration. */ static int -static_config_ipv4 (struct vty *vty) +static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) { struct route_node *rn; struct static_ipv4 *si; @@ -1205,14 +1257,14 @@ static_config_ipv4 (struct vty *vty) write = 0; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0); + stable = vrf_static_table (AFI_IP, safi, 0); if (! stable) return -1; for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { - vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4), + vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); switch (si->type) @@ -2146,7 +2198,8 @@ zebra_ip_config (struct vty *vty) { int write = 0; - write += static_config_ipv4 (vty); + write += static_config_ipv4 (vty, SAFI_UNICAST, "ip route"); + write += static_config_ipv4 (vty, SAFI_MULTICAST, "ip mroute"); #ifdef HAVE_IPV6 write += static_config_ipv6 (vty); #endif /* HAVE_IPV6 */ @@ -2185,6 +2238,8 @@ zebra_vty_init (void) install_node (&ip_node, zebra_ip_config); install_node (&protocol_node, config_write_protocol); + install_element (CONFIG_NODE, &ip_mroute_cmd); + install_element (CONFIG_NODE, &no_ip_mroute_cmd); install_element (CONFIG_NODE, &ip_protocol_cmd); install_element (CONFIG_NODE, &no_ip_protocol_cmd); install_element (VIEW_NODE, &show_ip_protocol_cmd); @@ -2233,6 +2288,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (ENABLE_NODE, &show_ip_mroute_cmd); + install_element (VIEW_NODE, &show_ip_rpf_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_cmd); #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); From a76681b66746a8b1cbaea7032044b93958473aa1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:03:53 +0100 Subject: [PATCH 0600/1342] zebra: fix optional distance on static mrib route Unfortunately, the quagga CLI parser doesn't support [<1-255>]. Fix by working around with an alias. Replaces the following commits: - zebra: mrib: [no] ip mroute - require distance. - zebra: mrib: [no] ip mroute - make distance optional. (Rewritten as alias) Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6802eceb5..69245a54a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -142,9 +142,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, } /* Static unicast routes for multicast RPF lookup. */ -DEFUN (ip_mroute, - ip_mroute_cmd, - "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", +DEFUN (ip_mroute_dist, + ip_mroute_dist_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -152,12 +152,22 @@ DEFUN (ip_mroute, "Nexthop interface name\n" "Distance\n") { - return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, argv[2]); + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], + NULL, argc > 2 ? argv[2] : NULL); } -DEFUN (no_ip_mroute, - no_ip_mroute_cmd, - "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) [<1-255>]", +ALIAS (ip_mroute_dist, + ip_mroute_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n") + +DEFUN (no_ip_mroute_dist, + no_ip_mroute_dist_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -165,9 +175,20 @@ DEFUN (no_ip_mroute, "Nexthop interface name\n" "Distance\n") { - return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, argv[2]); + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], + NULL, argc > 2 ? argv[2] : NULL); } +ALIAS (no_ip_mroute_dist, + no_ip_mroute_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", + NO_STR + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n") + DEFUN (show_ip_rpf, show_ip_rpf_cmd, "show ip rpf", @@ -2239,7 +2260,9 @@ zebra_vty_init (void) install_node (&protocol_node, config_write_protocol); install_element (CONFIG_NODE, &ip_mroute_cmd); + install_element (CONFIG_NODE, &ip_mroute_dist_cmd); install_element (CONFIG_NODE, &no_ip_mroute_cmd); + install_element (CONFIG_NODE, &no_ip_mroute_dist_cmd); install_element (CONFIG_NODE, &ip_protocol_cmd); install_element (CONFIG_NODE, &no_ip_protocol_cmd); install_element (VIEW_NODE, &show_ip_protocol_cmd); From 7ce9e6a3e8f0318656c1e619f48f3935e41638f1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 12 Jan 2015 07:05:06 +0100 Subject: [PATCH 0601/1342] zebra: dummy kernel "install" multicast routes This is a followup to 9511633 ("zebra: MBGP routes should not be installed in the kernel"), which was correct in disabling MRIB routes being installed in the kernel, yet broke the MRIB since now routes were never marked as active. Hence, push down the check into the kernel install functions, so that the routes are still marked active. At the same time, the FPM calls get a check each since otherwise we'd bump the FPM interface on MRIB updates. Fixes: 9511633 ("zebra: MBGP routes should not be installed in the kernel") Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/zebra_rib.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a07036e59..b4ea2424c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1124,8 +1124,16 @@ rib_install_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; struct nexthop *nexthop, *tnexthop; + rib_table_info_t *info = rn->table->info; int recursing; + if (info->safi != SAFI_UNICAST) + { + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return; + } + /* * Make sure we update the FPM any time we send new information to * the kernel. @@ -1157,8 +1165,16 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; struct nexthop *nexthop, *tnexthop; + rib_table_info_t *info = rn->table->info; int recursing; + if (info->safi != SAFI_UNICAST) + { + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return ret; + } + /* * Make sure we update the FPM any time we send new information to * the kernel. @@ -1187,9 +1203,12 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) static void rib_uninstall (struct route_node *rn, struct rib *rib) { + rib_table_info_t *info = rn->table->info; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { - zfpm_trigger_update (rn, "rib_uninstall"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "rib_uninstall"); redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) @@ -1306,9 +1325,6 @@ rib_process (struct route_node *rn) if (! nexthop_active_update (rn, rib, 0)) continue; - if (info->safi == SAFI_MULTICAST) - continue; - /* Infinit distance. */ if (rib->distance == DISTANCE_INFINITY) continue; @@ -1371,7 +1387,8 @@ rib_process (struct route_node *rn) select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { - zfpm_trigger_update (rn, "updating existing route"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "updating existing route"); redistribute_delete (&rn->p, select); if (! RIB_SYSTEM_ROUTE (select)) @@ -1414,7 +1431,8 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Removing existing route, fib %p", fib); - zfpm_trigger_update (rn, "removing existing route"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "removing existing route"); redistribute_delete (&rn->p, fib); if (! RIB_SYSTEM_ROUTE (fib)) @@ -1434,7 +1452,8 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Adding route, select %p", select); - zfpm_trigger_update (rn, "new route selected"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "new route selected"); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); @@ -3267,6 +3286,7 @@ static void rib_close_table (struct route_table *table) { struct route_node *rn; + rib_table_info_t *info = table->info; struct rib *rib; if (table) @@ -3276,7 +3296,8 @@ rib_close_table (struct route_table *table) if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) continue; - zfpm_trigger_update (rn, NULL); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); From 24480d426046e46fbcec098be1147650d6d3ff50 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:09:36 +0100 Subject: [PATCH 0602/1342] zebra: return route_node from rib_match_ipv4_safi The multicast code needs to know the route_node in addition to the rib entry in order to perform distance or prefix-length comparisons. Add it as optional "out" pointer parameter. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 3 ++- zebra/zebra_rib.c | 21 ++++++++++++++------- zebra/zserv.c | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 5eedfde6f..347fadb0d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -418,7 +418,8 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, u_int32_t, safi_t safi); -extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp); +extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, + int skip_bgp, struct route_node **rn_out); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b4ea2424c..abef90fb9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -719,7 +719,8 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, #endif /* HAVE_IPV6 */ struct rib * -rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) +rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, + struct route_node **rn_out) { struct route_table *table; struct route_node *rn; @@ -759,16 +760,22 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp) } else { - if (match->type == ZEBRA_ROUTE_CONNECT) - /* Directly point connected route. */ - return match; - else + if (match->type != ZEBRA_ROUTE_CONNECT) { + int found = 0; for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) - return match; - return NULL; + { + found = 1; + break; + } + if (!found) + return NULL; } + + if (rn_out) + *rn_out = rn; + return match; } } return NULL; diff --git a/zebra/zserv.c b/zebra/zserv.c index e9236deca..e678f3a32 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -540,7 +540,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL); /* Get output stream. */ s = client->obuf; @@ -615,7 +615,7 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr) int skip_bgp = 0; /* bool */ /* Lookup nexthop. */ - rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp); + rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, NULL); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); From bd0781296703cf2eddebced34258a1897a03b535 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 6 Jan 2015 19:53:24 +0100 Subject: [PATCH 0603/1342] zebra: make MRIB lookup behaviour switchable depending on the usage scenario (and availability of multitopology IGP protocols, which is currently zero in Quagga), different approaches of Multicast RPF lookups are useful. Reference behaviours from commercial vendors are urib-only/mrib-only (Juniper, depending on inet.2 availability) and lowest-distance (Cisco). As we are currently without MT IGP support, mrib-first seems the most useful default for Quagga. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/rib.h | 17 +++++++++++ zebra/zebra_rib.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_vty.c | 76 ++++++++++++++++++++++++++++++++++++++++++++--- zebra/zserv.c | 22 ++++---------- 4 files changed, 169 insertions(+), 21 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 347fadb0d..94a74194f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -373,6 +373,21 @@ typedef struct rib_tables_iter_t_ rib_tables_iter_state_t state; } rib_tables_iter_t; +/* RPF lookup behaviour */ +enum multicast_mode +{ + MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */ + MCAST_MRIB_ONLY, /* MRIB only */ + MCAST_URIB_ONLY, /* URIB only */ + MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */ + MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */ + MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */ + /* on equal value, MRIB wins for last 2 */ +}; + +extern void multicast_mode_ipv4_set (enum multicast_mode mode); +extern enum multicast_mode multicast_mode_ipv4_get (void); + extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); @@ -420,6 +435,8 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, struct route_node **rn_out); +extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, + struct route_node **rn_out); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index abef90fb9..effe23384 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -75,6 +75,9 @@ static const struct /* Vector for routing table. */ static vector vrf_vector; +/* RPF lookup behaviour */ +static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; + static void _rnode_zlog(const char *_func, struct route_node *rn, int priority, const char *msgfmt, ...) @@ -781,6 +784,78 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, return NULL; } +struct rib * +rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) +{ + struct rib *rib = NULL, *mrib = NULL, *urib = NULL; + struct route_node *m_rn = NULL, *u_rn = NULL; + int skip_bgp = 0; /* bool */ + + switch (ipv4_multicast_mode) + { + case MCAST_MRIB_ONLY: + return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out); + case MCAST_URIB_ONLY: + return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out); + case MCAST_NO_CONFIG: + case MCAST_MIX_MRIB_FIRST: + rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + if (!mrib) + rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + break; + case MCAST_MIX_DISTANCE: + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + if (mrib && urib) + rib = urib->distance < mrib->distance ? urib : mrib; + else if (mrib) + rib = mrib; + else if (urib) + rib = urib; + break; + case MCAST_MIX_PFXLEN: + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + if (mrib && urib) + rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; + else if (mrib) + rib = mrib; + else if (urib) + rib = urib; + break; + } + + if (rn_out) + *rn_out = (rib == mrib) ? m_rn : u_rn; + + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[BUFSIZ]; + inet_ntop (AF_INET, &addr, buf, BUFSIZ); + + zlog_debug("%s: %s: found %s, using %s", + __func__, buf, + mrib ? (urib ? "MRIB+URIB" : "MRIB") : + urib ? "URIB" : "nothing", + rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none"); + } + return rib; +} + +void +multicast_mode_ipv4_set (enum multicast_mode mode) +{ + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("%s: multicast lookup mode set (%d)", __func__, mode); + ipv4_multicast_mode = mode; +} + +enum multicast_mode +multicast_mode_ipv4_get (void) +{ + return ipv4_multicast_mode; +} + struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 69245a54a..f00e35eff 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -189,6 +189,62 @@ ALIAS (no_ip_mroute_dist, "Nexthop address\n" "Nexthop interface name\n") +DEFUN (ip_multicast_mode, + ip_multicast_mode_cmd, + "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", + IP_STR + "Multicast options\n" + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + if (!strncmp (argv[0], "u", 1)) + multicast_mode_ipv4_set (MCAST_URIB_ONLY); + else if (!strncmp (argv[0], "mrib-o", 6)) + multicast_mode_ipv4_set (MCAST_MRIB_ONLY); + else if (!strncmp (argv[0], "mrib-t", 6)) + multicast_mode_ipv4_set (MCAST_MIX_MRIB_FIRST); + else if (!strncmp (argv[0], "low", 3)) + multicast_mode_ipv4_set (MCAST_MIX_DISTANCE); + else if (!strncmp (argv[0], "lon", 3)) + multicast_mode_ipv4_set (MCAST_MIX_PFXLEN); + else + { + vty_out (vty, "Invalid mode specified%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_multicast_mode, + no_ip_multicast_mode_cmd, + "no ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", + NO_STR + IP_STR + "Multicast options\n" + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + multicast_mode_ipv4_set (MCAST_NO_CONFIG); + return CMD_SUCCESS; +} + +ALIAS (no_ip_multicast_mode, + no_ip_multicast_mode_noarg_cmd, + "no ip multicast rpf-lookup-mode", + NO_STR + IP_STR + "Multicast options\n" + "RPF lookup behavior\n") + DEFUN (show_ip_rpf, show_ip_rpf_cmd, "show ip rpf", @@ -2228,10 +2284,19 @@ zebra_ip_config (struct vty *vty) return write; } -/* ip protocol configuration write function */ -static int config_write_protocol(struct vty *vty) -{ +static int config_write_vty(struct vty *vty) +{ int i; + enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get (); + + if (ipv4_multicast_mode != MCAST_NO_CONFIG) + vty_out (vty, "ip multicast rpf-lookup-mode %s%s", + ipv4_multicast_mode == MCAST_URIB_ONLY ? "urib-only" : + ipv4_multicast_mode == MCAST_MRIB_ONLY ? "mrib-only" : + ipv4_multicast_mode == MCAST_MIX_MRIB_FIRST ? "mrib-then-urib" : + ipv4_multicast_mode == MCAST_MIX_DISTANCE ? "lower-distance" : + "longer-prefix", + VTY_NEWLINE); for (i=0;iobuf; @@ -1009,9 +995,11 @@ static int zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length) { struct in_addr addr; + struct rib *rib; addr.s_addr = stream_get_ipv4 (client->ibuf); - return zsend_ipv4_nexthop_lookup_mrib (client, addr); + rib = rib_match_ipv4_multicast (addr, NULL); + return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib); } /* Nexthop lookup for IPv4. */ From 3b02fe84aae567c56ef63e74cdb0dc63c66e2968 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 22 Jan 2015 19:12:35 +0100 Subject: [PATCH 0604/1342] zebra: add "show ip rpf" to get result of RPF lookup Checking what route exactly a RPF lookup for a given source uses is essential for an administrator to debug multicast routing issues. This command provides exactly that, using the multicst RPF lookup function and printing out its result to the CLI. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 52 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index f00e35eff..29c01c3ca 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -31,6 +31,8 @@ #include "zebra/zserv.h" static int do_show_ip_route(struct vty *vty, safi_t safi); +static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, + int mcast); /* General function for static route. */ static int @@ -255,6 +257,36 @@ DEFUN (show_ip_rpf, return do_show_ip_route(vty, SAFI_MULTICAST); } +DEFUN (show_ip_rpf_addr, + show_ip_rpf_addr_cmd, + "show ip rpf A.B.C.D", + SHOW_STR + IP_STR + "Display RPF information for multicast source\n" + "IP multicast source address (e.g. 10.0.0.0)\n") +{ + struct in_addr addr; + struct route_node *rn; + struct rib *rib; + int ret; + + ret = inet_aton (argv[0], &addr); + if (ret == 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rib = rib_match_ipv4_multicast (addr, &rn); + + if (rib) + vty_show_ip_route_detail (vty, rn, 1); + else + vty_out (vty, "%% No match for RPF lookup%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + /* Static route configuration. */ DEFUN (ip_route, ip_route_cmd, @@ -655,7 +687,7 @@ DEFUN (no_ip_protocol, /* New RIB. Detailed information for IPv4 route. */ 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, int mcast) { struct rib *rib; struct nexthop *nexthop, *tnexthop; @@ -663,8 +695,16 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) RNODE_FOREACH_RIB (rn, rib) { - vty_out (vty, "Routing entry for %s/%d%s", - inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + const char *mcast_info; + if (mcast) + { + rib_table_info_t *info = rn->table->info; + mcast_info = (info->safi == SAFI_MULTICAST) + ? " using Multicast RIB" + : " using Unicast RIB"; + } + vty_out (vty, "Routing entry for %s/%d%s%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, mcast_info, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); @@ -1092,7 +1132,7 @@ DEFUN (show_ip_route_addr, return CMD_WARNING; } - vty_show_ip_route_detail (vty, rn); + vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); @@ -1132,7 +1172,7 @@ DEFUN (show_ip_route_prefix, return CMD_WARNING; } - vty_show_ip_route_detail (vty, rn); + vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); @@ -2381,6 +2421,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_rpf_cmd); install_element (ENABLE_NODE, &show_ip_rpf_cmd); + install_element (VIEW_NODE, &show_ip_rpf_addr_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_addr_cmd); #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); From 863f20c326758c8a97e0a7a41c87355b66c4012d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 27 Jan 2015 20:24:15 +0100 Subject: [PATCH 0605/1342] zebra: mark multicast commands experimental depending on feedback from actually having these commands in a released version, we may want to adjust them. Thus, mark them as experimental so users are aware of this. Cc: Everton Marques Cc: Balaji G Signed-off-by: David Lamparter --- lib/vty.h | 8 ++++++++ zebra/zebra_vty.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/lib/vty.h b/lib/vty.h index 4d6048c95..f31f4b5d6 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -217,6 +217,14 @@ do { } \ } while (0) +#define VTY_WARN_EXPERIMENTAL() \ +do { \ + vty_out (vty, "%% WARNING: this command is experimental. Both its name and" \ + " parameters may%s%% change in a future version of Quagga," \ + " possibly breaking your configuration!%s", \ + VTY_NEWLINE, VTY_NEWLINE); \ +} while (0) + /* Exported variables */ extern char integrate_default[]; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 29c01c3ca..598b40de9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -154,6 +154,7 @@ DEFUN (ip_mroute_dist, "Nexthop interface name\n" "Distance\n") { + VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, argc > 2 ? argv[2] : NULL); } @@ -177,6 +178,7 @@ DEFUN (no_ip_mroute_dist, "Nexthop interface name\n" "Distance\n") { + VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, argc > 2 ? argv[2] : NULL); } @@ -203,6 +205,8 @@ DEFUN (ip_multicast_mode, "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") { + VTY_WARN_EXPERIMENTAL(); + if (!strncmp (argv[0], "u", 1)) multicast_mode_ipv4_set (MCAST_URIB_ONLY); else if (!strncmp (argv[0], "mrib-o", 6)) @@ -254,6 +258,7 @@ DEFUN (show_ip_rpf, IP_STR "Display RPF information for multicast source\n") { + VTY_WARN_EXPERIMENTAL(); return do_show_ip_route(vty, SAFI_MULTICAST); } @@ -270,6 +275,8 @@ DEFUN (show_ip_rpf_addr, struct rib *rib; int ret; + VTY_WARN_EXPERIMENTAL(); + ret = inet_aton (argv[0], &addr); if (ret == 0) { From 3a27aae7e479b2fa09cc9f27c439b9dfdb383364 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 30 Jan 2015 01:44:25 +0100 Subject: [PATCH 0606/1342] doc: zebra multicast RIB commands Signed-off-by: David Lamparter --- doc/main.texi | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/doc/main.texi b/doc/main.texi index a6bf0d1c9..810866aa1 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -10,6 +10,7 @@ different routing protocols. * Invoking zebra:: Running the program * Interface Commands:: Commands for zebra interfaces * Static Route Commands:: Commands for adding static routes +* Multicast RIB Commands:: Commands for controlling MRIB behavior * zebra Route Filtering:: Commands for zebra route filtering * zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY @@ -185,6 +186,81 @@ and later). After setting @var{tableno} with this command, static routes defined after this are added to the specified table. @end deffn +@node Multicast RIB Commands +@section Multicast RIB Commands + +The Multicast RIB provides a separate table of unicast destinations which +is used for Multicast Reverse Path Forwarding decisions. It is used with +a multicast source's IP address, hence contains not multicast group +addresses but unicast addresses. + +This table is fully separate from the default unicast table. However, +RPF lookup can include the unicast table. + +WARNING: RPF lookup results are non-responsive in this version of Quagga, +i.e. multicast routing does not actively react to changes in underlying +unicast topology! + +@deffn Command {ip multicast rpf-lookup-mode @var{mode}} {} +@deffnx Command {no ip multicast rpf-lookup-mode [@var{mode}]} {} + +@var{mode} sets the method used to perform RPF lookups. Supported modes: + +@table @samp +@item urib-only +Performs the lookup on the Unicast RIB. The Multicast RIB is never used. +@item mrib-only +Performs the lookup on the Multicast RIB. The Unicast RIB is never used. +@item mrib-then-urib +Tries to perform the lookup on the Multicast RIB. If any route is found, +that route is used. Otherwise, the Unicast RIB is tried. +@item lower-distance +Performs a lookup on the Multicast RIB and Unicast RIB each. The result +with the lower administrative distance is used; if they're equal, the +Multicast RIB takes precedence. +@item longer-prefix +Performs a lookup on the Multicast RIB and Unicast RIB each. The result +with the longer prefix length is used; if they're equal, the +Multicast RIB takes precedence. +@end table + +WARNING: Unreachable routes do not receive special treatment and do not +cause fallback to a second lookup. +@end deffn + +@deffn Command {show ip rpf @var{addr}} {} + +Performs a Multicast RPF lookup, as configured with +@command{ip multicast rpf-lookup-mode @var{mode}}. @var{addr} specifies +the multicast source address to look up. + +@example +> show ip rpf 192.0.2.1 +Routing entry for 192.0.2.0/24 using Unicast RIB + Known via "kernel", distance 0, metric 0, best + * 198.51.100.1, via eth0 +@end example + +Indicates that a multicast source lookup for 192.0.2.1 would use an +Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. +@end deffn + +@deffn Command {show ip rpf} {} + +Prints the entire Multicast RIB. Note that this is independent of the +configured RPF lookup mode, the Multicast RIB may be printed yet not +used at all. +@end deffn + +@deffn Command {ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} +@deffnx Command {no ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} + +Adds a static route entry to the Multicast RIB. This performs exactly as +the @command{ip route} command, except that it inserts the route in the +Multicast RIB instead of the Unicast RIB. +@end deffn + + @node zebra Route Filtering @section zebra Route Filtering Zebra supports @command{prefix-list} and @command{route-map} to match From 7397217e9dbc7384951ea146c0f9ca5784f6561e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 2 Feb 2015 03:00:22 +0100 Subject: [PATCH 0607/1342] doc: explain rpf lookup default mode Reported-by: Alexis Rosen Signed-off-by: David Lamparter --- doc/main.texi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/main.texi b/doc/main.texi index 810866aa1..4c11d2440 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -224,6 +224,11 @@ with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. @end table +The @code{mrib-then-urib} setting is the default behavior if nothing is +configured. If this is the desired behavior, it should be explicitly +configured to make the configuration immune against possible changes in +what the default behavior is. + WARNING: Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. @end deffn From 77ef0ace6b178601a0649ecf88c12c8203c9e077 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Feb 2015 06:24:41 +0100 Subject: [PATCH 0608/1342] build: enable pimd in test script Signed-off-by: David Lamparter --- buildtest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildtest.sh b/buildtest.sh index de638f562..4859bf4a0 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -4,7 +4,7 @@ # builds some git commit of Quagga in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-ipv6 --enable-ripngd --enable-ospf6d --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld" +basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-ipv6 --enable-ripngd --enable-ospf6d --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld --enable-pimd" configs_base="gcc|$basecfg" From 369b973e42f2b4f00a02e3ca8a1c6f1b252cf4ae Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 10 Feb 2015 11:00:30 +0100 Subject: [PATCH 0609/1342] build: Quagga 0.99.24-rc1 this is not a full release version, so neither release notes nor documentation are updated yet. Also, signing the tag with my private GPG key instead of the Quagga one. Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6632e5437..a01c9a7b5 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.23, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.24-rc1, [https://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) From 79f74962d20fa2c90df5a57335fc3b5e19bfeccf Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 20:22:55 +0200 Subject: [PATCH 0610/1342] build: remove bogus/deprecated inet_* tests These actually break configure on FreeBSD very subtly, because inet_aton and __inet_aton are both detected, and then later other tests get warnings about HAVE_INET_ATON being defined twice. That said, they're incorrect to begin with since they detect alternative functions but there is nothing in place to actually use these alternates. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 7 ------- 1 file changed, 7 deletions(-) diff --git a/configure.ac b/configure.ac index a01c9a7b5..73cbda9c8 100755 --- a/configure.ac +++ b/configure.ac @@ -1406,13 +1406,6 @@ AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON,,inet_pton)]) AC_CHECK_LIB(crypt, crypt) AC_CHECK_LIB(resolv, res_init) -dnl --------------------------------------------------- -dnl BSD/OS 4.1 define inet_XtoY function as __inet_XtoY -dnl --------------------------------------------------- -AC_CHECK_FUNC(__inet_ntop, AC_DEFINE(HAVE_INET_NTOP,,__inet_ntop)) -AC_CHECK_FUNC(__inet_pton, AC_DEFINE(HAVE_INET_PTON,,__inet_pton)) -AC_CHECK_FUNC(__inet_aton, AC_DEFINE(HAVE_INET_ATON,,__inet_aton)) - dnl --------------------------- dnl check system has PCRE regexp dnl --------------------------- From 2e5ca49758543cde69d98f4a6a7b39486e88311d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 20:54:31 +0200 Subject: [PATCH 0611/1342] build: remove Linux non-netlink config This path is deprecated, completely untested, likely broken and will not be maintained. Kill it with fire. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 50 +-------- zebra/Makefile.am | 7 +- zebra/if_proc.c | 248 -------------------------------------------- zebra/rtread_proc.c | 175 ------------------------------- 4 files changed, 8 insertions(+), 472 deletions(-) delete mode 100644 zebra/if_proc.c delete mode 100644 zebra/rtread_proc.c diff --git a/configure.ac b/configure.ac index 73cbda9c8..f46673c41 100755 --- a/configure.ac +++ b/configure.ac @@ -226,10 +226,6 @@ AC_ARG_ENABLE(solaris, [ --enable-solaris build solaris]) AC_ARG_ENABLE(bgp-announce, [ --disable-bgp-announce, turn off BGP route announcement]) -AC_ARG_ENABLE(netlink, -[ --enable-netlink force to use Linux netlink interface]) -AC_ARG_ENABLE(broken-aliases, -[ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X]) AC_ARG_ENABLE(snmp, [ --enable-snmp=ARG enable SNMP support (smux or agentx)]) AC_ARG_WITH(libpam, @@ -308,15 +304,6 @@ if test "${enable_fpm}" = "yes"; then AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) fi -if test "${enable_broken_aliases}" = "yes"; then - if test "${enable_netlink}" = "yes" - then - AC_MSG_FAILURE([Sorry you can not use netlink with broken aliases]) - fi - AC_DEFINE(HAVE_BROKEN_ALIASES,,Broken Alias) - enable_netlink=no -fi - if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi @@ -814,21 +801,10 @@ dnl Determine routing get and set method dnl ------------------------------------ AC_MSG_CHECKING(zebra between kernel interface method) if test x"$opsys" = x"gnu-linux"; then - if test "${enable_netlink}" = "yes";then - AC_MSG_RESULT(netlink) - RT_METHOD=rt_netlink.o - AC_DEFINE(HAVE_NETLINK,,netlink) - netlink=yes - elif test "${enable_netlink}" = "no"; then - AC_MSG_RESULT(ioctl) - RT_METHOD=rt_ioctl.o - netlink=no - else - AC_MSG_RESULT(netlink) - RT_METHOD=rt_netlink.o - AC_DEFINE(HAVE_NETLINK,,netlink) - netlink=yes - fi + AC_MSG_RESULT(netlink) + RT_METHOD=rt_netlink.o + AC_DEFINE(HAVE_NETLINK,,netlink) + netlink=yes elif test x"$opsys" = x"sol2-6";then AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" @@ -941,12 +917,11 @@ AC_CACHE_CHECK([route read method], [quagga_cv_rtread_method], [if test "x$netlink" = xyes; then quagga_cv_rtread_method="netlink" else -for quagga_cv_rtread_method in /proc/net/route /dev/ip /dev/null; +for quagga_cv_rtread_method in /dev/ip /dev/null; do test x`ls $quagga_cv_rtread_method 2>/dev/null` = x"$quagga_cv_rtread_method" && break done case $quagga_cv_rtread_method in - "/proc/net/route") quagga_cv_rtread_method="proc";; "/dev/ip") case "$host" in *-freebsd*) quagga_cv_rtread_method="sysctl";; @@ -1063,21 +1038,6 @@ if test $ac_cv_have_decl_TCP_MD5SIG = no; then AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)]) fi -dnl ----------------------- -dnl check proc file system. -dnl ----------------------- -if test "$netlink" != yes; then - if test -r /proc/net/dev; then - AC_DEFINE(HAVE_PROC_NET_DEV,,/proc/net/dev) - IF_PROC=if_proc.o - fi - if test -r /proc/net/if_inet6; then - AC_DEFINE(HAVE_PROC_NET_IF_INET6,,/proc/net/if_inet6) - IF_PROC=if_proc.o - fi -fi -AC_SUBST(IF_PROC) - dnl ----------------------------- dnl check ipforward detect method dnl ----------------------------- diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 0591a555c..4a76317ed 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -9,14 +9,13 @@ LIBCAP = @LIBCAP@ ipforward = @IPFORWARD@ if_method = @IF_METHOD@ -if_proc = @IF_PROC@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ other_method = @OTHER_METHOD@ ioctl_method = @IOCTL_METHOD@ -otherobj = $(ioctl_method) $(ipforward) $(if_method) $(if_proc) \ +otherobj = $(ioctl_method) $(ipforward) $(if_method) \ $(rt_method) $(rtread_method) $(kernel_method) $(other_method) if HAVE_NETLINK @@ -51,10 +50,10 @@ testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) zebra_DEPENDENCIES = $(otherobj) -EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c if_proc.c \ +EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ if_sysctl.c ipforward_aix.c ipforward_ews.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ - rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \ + rt_socket.c rtread_netlink.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ ioctl.c ioctl_solaris.c \ GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB diff --git a/zebra/if_proc.c b/zebra/if_proc.c deleted file mode 100644 index 2dbc47261..000000000 --- a/zebra/if_proc.c +++ /dev/null @@ -1,248 +0,0 @@ -/* Interface name and statistics get function using proc file system - * Copyright (C) 1999 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -#include "if.h" -#include "prefix.h" -#include "log.h" - -#include "zebra/ioctl.h" -#include "zebra/connected.h" -#include "zebra/interface.h" - -/* Proc filesystem one line buffer. */ -#define PROCBUFSIZ 1024 - -/* Path to device proc file system. */ -#ifndef _PATH_PROC_NET_DEV -#define _PATH_PROC_NET_DEV "/proc/net/dev" -#endif /* _PATH_PROC_NET_DEV */ - -/* Return statistics data pointer. */ -static char * -interface_name_cut (char *buf, char **name) -{ - char *stat; - - /* Skip white space. Line will include header spaces. */ - while (*buf == ' ') - buf++; - *name = buf; - - /* Cut interface name. */ - stat = strrchr (buf, ':'); - *stat++ = '\0'; - - return stat; -} - -/* Fetch each statistics field. */ -static int -ifstat_dev_fields (int version, char *buf, struct interface *ifp) -{ - switch (version) - { - case 3: - sscanf(buf, - "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", - &ifp->stats.rx_bytes, - &ifp->stats.rx_packets, - &ifp->stats.rx_errors, - &ifp->stats.rx_dropped, - &ifp->stats.rx_fifo_errors, - &ifp->stats.rx_frame_errors, - &ifp->stats.rx_compressed, - &ifp->stats.rx_multicast, - - &ifp->stats.tx_bytes, - &ifp->stats.tx_packets, - &ifp->stats.tx_errors, - &ifp->stats.tx_dropped, - &ifp->stats.tx_fifo_errors, - &ifp->stats.collisions, - &ifp->stats.tx_carrier_errors, - &ifp->stats.tx_compressed); - break; - case 2: - sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", - &ifp->stats.rx_bytes, - &ifp->stats.rx_packets, - &ifp->stats.rx_errors, - &ifp->stats.rx_dropped, - &ifp->stats.rx_fifo_errors, - &ifp->stats.rx_frame_errors, - - &ifp->stats.tx_bytes, - &ifp->stats.tx_packets, - &ifp->stats.tx_errors, - &ifp->stats.tx_dropped, - &ifp->stats.tx_fifo_errors, - &ifp->stats.collisions, - &ifp->stats.tx_carrier_errors); - ifp->stats.rx_multicast = 0; - break; - case 1: - sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", - &ifp->stats.rx_packets, - &ifp->stats.rx_errors, - &ifp->stats.rx_dropped, - &ifp->stats.rx_fifo_errors, - &ifp->stats.rx_frame_errors, - - &ifp->stats.tx_packets, - &ifp->stats.tx_errors, - &ifp->stats.tx_dropped, - &ifp->stats.tx_fifo_errors, - &ifp->stats.collisions, - &ifp->stats.tx_carrier_errors); - ifp->stats.rx_bytes = 0; - ifp->stats.tx_bytes = 0; - ifp->stats.rx_multicast = 0; - break; - } - return 0; -} - -/* Update interface's statistics. */ -void -ifstat_update_proc (void) -{ - FILE *fp; - char buf[PROCBUFSIZ]; - int version; - struct interface *ifp; - char *stat; - char *name; - - /* Open /proc/net/dev. */ - fp = fopen (_PATH_PROC_NET_DEV, "r"); - if (fp == NULL) - { - zlog_warn ("Can't open proc file %s: %s", - _PATH_PROC_NET_DEV, safe_strerror (errno)); - return; - } - - /* Drop header lines. */ - fgets (buf, PROCBUFSIZ, fp); - fgets (buf, PROCBUFSIZ, fp); - - /* To detect proc format veresion, parse second line. */ - if (strstr (buf, "compressed")) - version = 3; - else if (strstr (buf, "bytes")) - version = 2; - else - version = 1; - - /* Update each interface's statistics. */ - while (fgets (buf, PROCBUFSIZ, fp) != NULL) - { - stat = interface_name_cut (buf, &name); - ifp = if_get_by_name (name); - ifstat_dev_fields (version, stat, ifp); - } - fclose(fp); - return; -} - -/* Interface structure allocation by proc filesystem. */ -int -interface_list_proc () -{ - FILE *fp; - char buf[PROCBUFSIZ]; - struct interface *ifp; - char *name; - - /* Open /proc/net/dev. */ - fp = fopen (_PATH_PROC_NET_DEV, "r"); - if (fp == NULL) - { - zlog_warn ("Can't open proc file %s: %s", - _PATH_PROC_NET_DEV, safe_strerror (errno)); - return -1; - } - - /* Drop header lines. */ - fgets (buf, PROCBUFSIZ, fp); - fgets (buf, PROCBUFSIZ, fp); - - /* Only allocate interface structure. Other jobs will be done in - if_ioctl.c. */ - while (fgets (buf, PROCBUFSIZ, fp) != NULL) - { - interface_name_cut (buf, &name); - ifp = if_get_by_name (name); - if_add_update (ifp); - } - fclose(fp); - return 0; -} - -#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) - -#ifndef _PATH_PROC_NET_IF_INET6 -#define _PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6" -#endif /* _PATH_PROC_NET_IF_INET6 */ - -int -ifaddr_proc_ipv6 () -{ - FILE *fp; - char buf[PROCBUFSIZ]; - int n; - char addr[33]; - char ifname[21]; - int ifindex, plen, scope, status; - struct interface *ifp; - struct prefix_ipv6 p; - - /* Open proc file system. */ - fp = fopen (_PATH_PROC_NET_IF_INET6, "r"); - if (fp == NULL) - { - zlog_warn ("Can't open proc file %s: %s", - _PATH_PROC_NET_IF_INET6, safe_strerror (errno)); - return -1; - } - - /* Get interface's IPv6 address. */ - while (fgets (buf, PROCBUFSIZ, fp) != NULL) - { - n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", - addr, &ifindex, &plen, &scope, &status, ifname); - if (n != 6) - continue; - - ifp = if_get_by_name (ifname); - - /* Fetch interface's IPv6 address. */ - str2in6_addr (addr, &p.prefix); - p.prefixlen = plen; - - connected_add_ipv6 (ifp, 0, &p.prefix, p.prefixlen, NULL, ifname); - } - fclose (fp); - return 0; -} -#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c deleted file mode 100644 index 07e8491ad..000000000 --- a/zebra/rtread_proc.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Kernel routing readup by /proc filesystem - * Copyright (C) 1997 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -#include "prefix.h" -#include "log.h" -#include "if.h" -#include "rib.h" - -#include "zebra/zserv.h" -#include "zebra/rt.h" - -/* Proc file system to read IPv4 routing table. */ -#ifndef _PATH_PROCNET_ROUTE -#define _PATH_PROCNET_ROUTE "/proc/net/route" -#endif /* _PATH_PROCNET_ROUTE */ - -/* Proc file system to read IPv6 routing table. */ -#ifndef _PATH_PROCNET_ROUTE6 -#define _PATH_PROCNET_ROUTE6 "/proc/net/ipv6_route" -#endif /* _PATH_PROCNET_ROUTE6 */ - -/* To read interface's name */ -#define INTERFACE_NAMSIZ 20 - -/* Reading buffer for one routing entry. */ -#define RT_BUFSIZ 1024 - -/* Kernel routing table read up by /proc filesystem. */ -static int -proc_route_read (void) -{ - FILE *fp; - char buf[RT_BUFSIZ]; - char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9]; - int flags, refcnt, use, metric, mtu, window, rtt; - - /* Open /proc filesystem */ - fp = fopen (_PATH_PROCNET_ROUTE, "r"); - if (fp == NULL) - { - zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, safe_strerror (errno)); - return -1; - } - - /* Drop first label line. */ - fgets (buf, RT_BUFSIZ, fp); - - while (fgets (buf, RT_BUFSIZ, fp) != NULL) - { - int n; - struct prefix_ipv4 p; - struct in_addr tmpmask; - struct in_addr gateway; - u_char zebra_flags = 0; - - n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d", - iface, dest, gate, &flags, &refcnt, &use, &metric, - mask, &mtu, &window, &rtt); - if (n != 11) - { - zlog_warn ("can't read all of routing information\n"); - continue; - } - if (! (flags & RTF_UP)) - continue; - if (! (flags & RTF_GATEWAY)) - continue; - - if (flags & RTF_DYNAMIC) - zebra_flags |= ZEBRA_FLAG_SELFROUTE; - - p.family = AF_INET; - sscanf (dest, "%lX", (unsigned long *)&p.prefix); - sscanf (mask, "%lX", (unsigned long *)&tmpmask); - p.prefixlen = ip_masklen (tmpmask); - sscanf (gate, "%lX", (unsigned long *)&gateway); - - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST); - } - - fclose (fp); - return 0; -} - -#ifdef HAVE_IPV6 -static int -proc_ipv6_route_read () -{ - FILE *fp; - char buf [RT_BUFSIZ]; - - /* Open /proc filesystem */ - fp = fopen (_PATH_PROCNET_ROUTE6, "r"); - if (fp == NULL) - { - zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6, - safe_strerror (errno)); - return -1; - } - - /* There is no title line, so we don't drop first line. */ - while (fgets (buf, RT_BUFSIZ, fp) != NULL) - { - int n; - char dest[33], src[33], gate[33]; - char iface[INTERFACE_NAMSIZ]; - int dest_plen, src_plen; - int metric, use, refcnt, flags; - struct prefix_ipv6 p; - struct in6_addr gateway; - u_char zebra_flags = 0; - - /* Linux 2.1.x write this information at net/ipv6/route.c - rt6_info_node () */ - n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s", - dest, &dest_plen, src, &src_plen, gate, - &metric, &use, &refcnt, &flags, iface); - - if (n != 10) - { - /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */ - continue; - } - - if (! (flags & RTF_UP)) - continue; - if (! (flags & RTF_GATEWAY)) - continue; - - if (flags & RTF_DYNAMIC) - zebra_flags |= ZEBRA_FLAG_SELFROUTE; - - p.family = AF_INET6; - str2in6_addr (dest, &p.prefix); - str2in6_addr (gate, &gateway); - p.prefixlen = dest_plen; - - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, - metric, 0); - } - - fclose (fp); - return 0; -} -#endif /* HAVE_IPV6 */ - -void -route_read (void) -{ - proc_route_read (); -#ifdef HAVE_IPV6 - proc_ipv6_route_read (); -#endif /* HAVE_IPV6 */ -} From 0f048b90b5d6e4bd185913945b68dd254126eb9f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 21:01:32 +0200 Subject: [PATCH 0612/1342] build: remove AIX, NEC EWS and IRIX Valar morghulis. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 29 +----------- lib/zebra.h | 14 ------ zebra/Makefile.am | 7 ++- zebra/interface.h | 4 -- zebra/ipforward_aix.c | 64 -------------------------- zebra/ipforward_ews.c | 60 ------------------------- zebra/ipforward_sysctl.c | 2 +- zebra/mtu_kvm.c | 97 ---------------------------------------- 8 files changed, 5 insertions(+), 272 deletions(-) delete mode 100644 zebra/ipforward_aix.c delete mode 100644 zebra/ipforward_ews.c delete mode 100644 zebra/mtu_kvm.c diff --git a/configure.ac b/configure.ac index f46673c41..b9001b37a 100755 --- a/configure.ac +++ b/configure.ac @@ -605,23 +605,10 @@ case "$host" in opsys=gnu-linux AC_DEFINE(GNU_LINUX,,GNU Linux) ;; - *-nec-sysv4*) - AC_CHECK_LIB(nsl, gethostbyname) - AC_CHECK_LIB(socket, socket) - ;; *-openbsd*) opsys=openbsd AC_DEFINE(OPEN_BSD,,OpenBSD) ;; - *-bsdi*) - opsys=bsdi - OTHER_METHOD="mtu_kvm.o" - AC_CHECK_LIB(kvm, main) - ;; - *-irix6.5) - opsys=irix - AC_DEFINE(IRIX_65,,IRIX 6.5) - ;; esac AC_SYS_LARGEFILE @@ -813,10 +800,6 @@ elif test x"$opsys" = x"sol8";then AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" -elif test "$opsys" = "irix" ; then - AC_MSG_RESULT(Route socket) - KERNEL_METHOD="kernel_socket.o" - RT_METHOD="rt_socket.o" else AC_TRY_RUN([#include #include @@ -842,7 +825,6 @@ main () fi AC_SUBST(RT_METHOD) AC_SUBST(KERNEL_METHOD) -AC_SUBST(OTHER_METHOD) AM_CONDITIONAL([HAVE_NETLINK], [test "x$netlink" = "xyes"]) dnl -------------------------- @@ -949,9 +931,6 @@ elif test "$opsys" = "sol8";then AC_MSG_RESULT(Solaris GLIF) IF_METHOD=if_ioctl_solaris.o IOCTL_METHOD=ioctl_solaris.o -elif test "$opsys" = "irix" ; then - AC_MSG_RESULT(IRIX) - IF_METHOD=if_ioctl.o elif test "$opsys" = "openbsd";then AC_MSG_RESULT(openbsd) IF_METHOD=if_ioctl.o @@ -1058,7 +1037,6 @@ case $quagga_cv_ipforward_method in "/proc/net/snmp") quagga_cv_ipforward_method="proc";; "/dev/ip") case "$host" in - *-nec-sysv4*) quagga_cv_ipforward_method="ews";; *-freebsd*) quagga_cv_ipforward_method="sysctl";; *) quagga_cv_ipforward_method="solaris";; esac;; @@ -1125,12 +1103,7 @@ dnl --------- AC_DEFINE(NRL,1,NRL) RIPNGD="ripngd" OSPF6D="ospf6d" - if test x"$opsys" = x"bsdi";then - AC_DEFINE(BSDI_NRL,,BSDI) - AC_MSG_RESULT(BSDI_NRL) - else - AC_MSG_RESULT(NRL) - fi + AC_MSG_RESULT(NRL) dnl ------------------------------------ dnl Solaris 9, 10 and potentially higher dnl ------------------------------------ diff --git a/lib/zebra.h b/lib/zebra.h index a4e02148d..a5ed20e40 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -244,20 +244,6 @@ typedef int socklen_t; #include #endif /* HAVE_GLIBC_BACKTRACE */ -#ifdef BSDI_NRL - -#ifdef HAVE_NETINET6_IN6_H -#include -#endif /* HAVE_NETINET6_IN6_H */ - -#ifdef NRL -#include -#endif /* NRL */ - -#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL - -#endif /* BSDI_NRL */ - /* Local includes: */ #if !(defined(__GNUC__) || defined(VTYSH_EXTRACT_PL)) #define __attribute__(x) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 4a76317ed..8e3c99bae 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -12,11 +12,10 @@ if_method = @IF_METHOD@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ -other_method = @OTHER_METHOD@ ioctl_method = @IOCTL_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) \ - $(rt_method) $(rtread_method) $(kernel_method) $(other_method) + $(rt_method) $(rtread_method) $(kernel_method) if HAVE_NETLINK othersrc = zebra_fpm_netlink.c @@ -51,10 +50,10 @@ testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) zebra_DEPENDENCIES = $(otherobj) EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ - if_sysctl.c ipforward_aix.c ipforward_ews.c ipforward_proc.c \ + if_sysctl.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_sysctl.c \ - rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ + rtread_getmsg.c kernel_socket.c kernel_netlink.c \ ioctl.c ioctl_solaris.c \ GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB diff --git a/zebra/interface.h b/zebra/interface.h index 7a05348ca..2f3b7b93f 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -236,8 +236,4 @@ extern int interface_list_proc (void); extern int ifaddr_proc_ipv6 (void); #endif /* HAVE_PROC_NET_IF_INET6 */ -#ifdef BSDI -extern int if_kvm_get_mtu (struct interface *); -#endif /* BSDI */ - #endif /* _ZEBRA_INTERFACE_H */ diff --git a/zebra/ipforward_aix.c b/zebra/ipforward_aix.c deleted file mode 100644 index c79e7f1c7..000000000 --- a/zebra/ipforward_aix.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ipforward value get function for aix. - * Copyright (C) 1997 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -int -ipforward () -{ - int fd, ret; - int af = AF_INET; - char netopt[] = "ipforwarding"; - struct optreq oq; - - fd = socket(af, SOCK_DGRAM, 0); - if (fd < 0) { - /* need logging here */ - return -1; - } - - strcpy (oq.name, netopt); - oq.getnext = 0; - - ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq); - close(fd); - - if (ret < 0) { - /* need logging here */ - return -1; - } - - ret = atoi (oq.data); - return ret; -} - -int -ipforward_on () -{ - ; -} - -int -ipforward_off () -{ - ; -} diff --git a/zebra/ipforward_ews.c b/zebra/ipforward_ews.c deleted file mode 100644 index c872000a8..000000000 --- a/zebra/ipforward_ews.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Ipforward value get function for NEC EWS. - * Copyright (C) 1997 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -int -ipforward () -{ - int fd; - char buf[BUFSIZ]; - struct mioc_rksym rks; - - fd = open ("/dev/kmem", O_RDWR); - if (fd < 0) { - /* need logging here */ - return -1; - } - - rks.mirk_symname = "ipforwarding"; - rks.mirk_buf = buf; - rks.mirk_buflen = sizeof (int); - - if (ioctl (fd, MIOC_READKSYM, &rks) < 0) { - /* need logging here */ - return -1; - } - close (fd); - return *(int *)buf; -} - -int -ipforward_on () -{ - ; -} - -int -ipforward_off () -{ - ; -} diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c index 185aee3ee..882441826 100644 --- a/zebra/ipforward_sysctl.c +++ b/zebra/ipforward_sysctl.c @@ -106,7 +106,7 @@ int mib_ipv6[MIB_SIZ] = { CTL_NET, PF_INET6, -#if defined(KAME) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL) +#if defined(KAME) || defined(NRL) IPPROTO_IPV6, IPV6CTL_FORWARDING #else /* NOT KAME */ diff --git a/zebra/mtu_kvm.c b/zebra/mtu_kvm.c deleted file mode 100644 index d37bb9bb7..000000000 --- a/zebra/mtu_kvm.c +++ /dev/null @@ -1,97 +0,0 @@ -/* MTU get using kvm_read. - * Copyright (C) 1999 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -#include -#include -#include - -#include "if.h" - -/* get interface MTU to use kvm_read */ -void -if_kvm_get_mtu (struct interface *ifp) -{ - kvm_t *kvmd; - struct ifnet ifnet; - unsigned long ifnetaddr; - int len; - - char ifname[IFNAMSIZ]; - char tname[INTERFACE_NAMSIZ + 1]; - char buf[_POSIX2_LINE_MAX]; - - struct nlist nl[] = - { - {"_ifnet"}, - {""} - }; - - ifp->mtu6 = ifp->mtu = -1; - - kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf); - - if (kvmd == NULL) - return ; - - kvm_nlist(kvmd, nl); - - ifnetaddr = nl[0].n_value; - - if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0) - { - kvm_close (kvmd); - return ; - } - - while(ifnetaddr != 0) - { - if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0) - { - kvm_close (kvmd); - return ; - } - - if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0) - { - kvm_close (kvmd); - return ; - } - - len = snprintf (tname, INTERFACE_NAMSIZ + 1, - "%s%d", ifname, ifnet.if_unit); - - if (strncmp (tname, ifp->name, len) == 0) - break; - - ifnetaddr = (u_long)ifnet.if_next; - } - - kvm_close (kvmd); - - if (ifnetaddr == 0) - { - return ; - } - - ifp->mtu6 = ifp->mtu = ifnet.if_mtu; -} From 6d6df30386423518b5daef93c2f047b4140f85f4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 21:12:37 +0200 Subject: [PATCH 0613/1342] build: remove INRIA, NRL and MUSICA IPv6 quirks Valar dohaeris. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- bgpd/bgp_network.c | 4 ++-- configure.ac | 39 +-------------------------------------- lib/sockunion.c | 7 +------ lib/vty.c | 11 +++-------- ospf6d/ospf6d.h | 6 ------ ripngd/ripngd.c | 8 ++++---- zebra/connected.c | 2 +- zebra/ipforward_sysctl.c | 6 +----- zebra/rt_socket.c | 5 ----- zebra/zebra_rib.c | 4 ++-- 10 files changed, 15 insertions(+), 77 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index c0527447a..cea430cce 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -488,7 +488,7 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) } /* IPv6 supported version of BGP server socket setup. */ -#if defined (HAVE_IPV6) && ! defined (NRL) +#ifdef HAVE_IPV6 int bgp_socket (unsigned short port, const char *address) { @@ -588,7 +588,7 @@ bgp_socket (unsigned short port, const char *address) } return sock; } -#endif /* HAVE_IPV6 && !NRL */ +#endif /* HAVE_IPV6 */ void bgp_close (void) diff --git a/configure.ac b/configure.ac index b9001b37a..6684946a0 100755 --- a/configure.ac +++ b/configure.ac @@ -1054,21 +1054,10 @@ AC_MSG_CHECKING(whether does this OS have IPv6 stack) if test "${enable_ipv6}" = "no"; then AC_MSG_RESULT(disabled) else -dnl ---------- -dnl INRIA IPv6 -dnl ---------- - if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then - zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6,1,INRIA IPv6) - AC_DEFINE(INRIA_IPV6,1,INRIA IPv6) - RIPNGD="ripngd" - OSPF6D="ospf6d" - LIB_IPV6="" - AC_MSG_RESULT(INRIA IPv6) dnl --------- dnl KAME IPv6 dnl --------- - elif grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then + if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes AC_DEFINE(HAVE_IPV6,1,KAME IPv6) AC_DEFINE(KAME,1,KAME IPv6) @@ -1078,32 +1067,6 @@ dnl --------- LIB_IPV6="-L/usr/local/v6/lib -linet6" fi AC_MSG_RESULT(KAME) -dnl ------------------------- -dnl MUSICA IPv6 -dnl default host check -dnl It is not used by Kheops -dnl ------------------------- - elif grep MUSICA /usr/include6/netinet6/in6.h >/dev/null 2>&1; then - zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6,1,Musicia IPv6) - AC_DEFINE(MUSICA,1,Musica IPv6 stack) - AC_DEFINE(KAME,1,KAME IPv6 stack) - RIPNGD="ripngd" - OSPF6D="ospf6d" - if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then - LIB_IPV6="-L/usr/local/v6/lib -linet6" - fi - AC_MSG_RESULT(MUSICA) -dnl --------- -dnl NRL check -dnl --------- - elif grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then - zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6,1,NRL IPv6) - AC_DEFINE(NRL,1,NRL) - RIPNGD="ripngd" - OSPF6D="ospf6d" - AC_MSG_RESULT(NRL) dnl ------------------------------------ dnl Solaris 9, 10 and potentially higher dnl ------------------------------------ diff --git a/lib/sockunion.c b/lib/sockunion.c index 5dcf72563..1a355d3b3 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -304,13 +304,8 @@ sockunion_connect (int fd, union sockunion *peersu, unsigned short port, { #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */ -#ifdef MUSICA - su.sin6.sin6_scope_id = ifindex; -#endif #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */ -#ifndef MUSICA SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); -#endif } #endif /* KAME */ break; @@ -394,7 +389,7 @@ sockunion_bind (int sock, union sockunion *su, unsigned short port, #endif /* SIN6_LEN */ if (su_addr == NULL) { -#if defined(LINUX_IPV6) || defined(NRL) +#ifdef LINUX_IPV6 memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr)); #else su->sin6.sin6_addr = in6addr_any; diff --git a/lib/vty.c b/lib/vty.c index b8db7c894..750f8856e 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1775,7 +1775,7 @@ vty_accept (struct thread *thread) return 0; } -#if defined(HAVE_IPV6) && !defined(NRL) +#ifdef HAVE_IPV6 static void vty_serv_sock_addrinfo (const char *hostname, unsigned short port) { @@ -1840,7 +1840,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) freeaddrinfo (ainfo_save); } -#else /* HAVE_IPV6 && ! NRL */ +#else /* HAVE_IPV6 */ /* Make vty server socket. */ static void @@ -1908,7 +1908,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) /* Add vty server event. */ vty_event (VTY_SERV, accept_sock, NULL); } -#endif /* HAVE_IPV6 && ! NRL */ +#endif /* HAVE_IPV6 */ #ifdef VTYSH /* For sockaddr_un. */ @@ -2143,12 +2143,7 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path) { #ifdef HAVE_IPV6 -#ifdef NRL - vty_serv_sock_family (addr, port, AF_INET); - vty_serv_sock_family (addr, port, AF_INET6); -#else /* ! NRL */ vty_serv_sock_addrinfo (addr, port); -#endif /* NRL*/ #else /* ! HAVE_IPV6 */ vty_serv_sock_family (addr,port, AF_INET); #endif /* HAVE_IPV6 */ diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 78ae1a14b..4122b3093 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -30,12 +30,6 @@ /* global variables */ extern struct thread_master *master; -#ifdef INRIA_IPV6 -#ifndef IPV6_PKTINFO -#define IPV6_PKTINFO IPV6_RECVPKTINFO -#endif /* IPV6_PKTINFO */ -#endif /* INRIA_IPV6 */ - /* Historical for KAME. */ #ifndef IPV6_JOIN_GROUP #ifdef IPV6_ADD_MEMBERSHIP diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 941c3a068..2dbbf9e10 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -928,7 +928,7 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; -#if defined (MUSICA) || defined (LINUX) +#ifdef LINUX /* XXX As long as the RIPng redistribution is applied to all the connected * routes, one needs to filter the ::/96 prefixes. * However it could be a wanted case, it will be removed soon. @@ -936,7 +936,7 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) return; -#endif /* MUSICA or LINUX */ +#endif /* LINUX */ rp = route_node_get (ripng->table, (struct prefix *) p); rinfo = rp->info; @@ -1025,7 +1025,7 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; -#if defined (MUSICA) || defined (LINUX) +#ifdef LINUX /* XXX As long as the RIPng redistribution is applied to all the connected * routes, one needs to filter the ::/96 prefixes. * However it could be a wanted case, it will be removed soon. @@ -1033,7 +1033,7 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) return; -#endif /* MUSICA or LINUX */ +#endif /* LINUX */ rp = route_node_lookup (ripng->table, (struct prefix *) p); diff --git a/zebra/connected.c b/zebra/connected.c index c4f87f4cb..2db981b38 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -347,7 +347,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) /* Apply mask to the network. */ apply_mask_ipv6 (&p); -#if ! defined (MUSICA) && ! defined (LINUX) +#ifndef LINUX /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */ if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c index 882441826..57ed18578 100644 --- a/zebra/ipforward_sysctl.c +++ b/zebra/ipforward_sysctl.c @@ -23,10 +23,6 @@ #include "privs.h" #include "zebra/ipforward.h" -#ifdef NRL -#include -#endif /* NRL */ - #include "log.h" #define MIB_SIZ 4 @@ -106,7 +102,7 @@ int mib_ipv6[MIB_SIZ] = { CTL_NET, PF_INET6, -#if defined(KAME) || defined(NRL) +#if defined(KAME) IPPROTO_IPV6, IPV6CTL_FORWARDING #else /* NOT KAME */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 90ed73d0b..cde71ef47 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -254,13 +254,8 @@ sin6_masklen (struct in6_addr mask) char *p, *lim; int len; -#if defined (INRIA) - if (IN_ANYADDR6 (mask)) - return sizeof (long); -#else /* ! INRIA */ if (IN6_IS_ADDR_UNSPECIFIED (&mask)) return sizeof (long); -#endif /* ! INRIA */ sin6.sin6_addr = mask; len = sizeof (struct sockaddr_in6); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index effe23384..31469ca75 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2692,11 +2692,11 @@ rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, int table) { if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) { -#if defined (MUSICA) || defined (LINUX) +#ifdef LINUX /* IN6_IS_ADDR_V4COMPAT(&p->prefix) */ if (p->prefixlen == 96) return 0; -#endif /* MUSICA */ +#endif /* LINUX */ return 1; } if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) From 86a82e99aa3728d78a1ec65b60a2162914cd7519 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 21:26:36 +0200 Subject: [PATCH 0614/1342] zebra, ripngd: remove ::/64 special-casing In the 90ies, IPv4 was believed to exist within IPv6, with some kernels implementing this belief in code... Our code here is keyed to "#ifdef LINUX", yet no Linux from the past 10 years had this, making the code completely useless. FreeBSD 10.0 does in fact have a "::/96 via ::1 dev lo0 reject" route. IMHO we shouldn't mess with that, the admin can filter as neccessary anyway. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu [DL: slightly adjusted commit message to remove misunderstanding] Acked-by: Paul Jakma --- ripngd/ripngd.c | 18 ------------------ zebra/zebra_rib.c | 25 ------------------------- 2 files changed, 43 deletions(-) diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 2dbbf9e10..8c20a7a2b 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -928,15 +928,6 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; -#ifdef LINUX - /* XXX As long as the RIPng redistribution is applied to all the connected - * routes, one needs to filter the ::/96 prefixes. - * However it could be a wanted case, it will be removed soon. - */ - if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || - (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) - return; -#endif /* LINUX */ rp = route_node_get (ripng->table, (struct prefix *) p); rinfo = rp->info; @@ -1025,15 +1016,6 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; -#ifdef LINUX - /* XXX As long as the RIPng redistribution is applied to all the connected - * routes, one needs to filter the ::/96 prefixes. - * However it could be a wanted case, it will be removed soon. - */ - if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || - (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) - return; -#endif /* LINUX */ rp = route_node_lookup (ripng->table, (struct prefix *) p); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 31469ca75..0750e6eb6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2687,27 +2687,6 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, } #ifdef HAVE_IPV6 -static int -rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, int table) -{ - if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) { -#ifdef LINUX - /* IN6_IS_ADDR_V4COMPAT(&p->prefix) */ - if (p->prefixlen == 96) - return 0; -#endif /* LINUX */ - return 1; - } - if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) - && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate)) - { - kernel_delete_ipv6_old (p, gate, ifindex, 0, table); - return 1; - } - return 0; -} - int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, @@ -2734,10 +2713,6 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) distance = 200; - /* Filter bogus route. */ - if (rib_bogus_ipv6 (type, p, gate, ifindex, 0)) - return 0; - /* Lookup route node.*/ rn = route_node_get (table, (struct prefix *) p); From 51bdebad99fe813d1b7104543b352f0e39b1c8dc Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 21:28:50 +0200 Subject: [PATCH 0615/1342] zebra: remove kernel_delete_ipv6_old() The only user of this was rib_bogus_ipv6(), which was removed in the previous commit. Good riddance. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- zebra/kernel_null.c | 4 ---- zebra/rt.h | 2 -- zebra/rt_ioctl.c | 8 -------- zebra/rt_netlink.c | 9 --------- zebra/rt_socket.c | 16 ---------------- 5 files changed, 39 deletions(-) diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 29c7881b9..4cd43db48 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -43,10 +43,6 @@ int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } int kernel_delete_ipv6 (struct prefix *a, struct rib *b) { return 0; } #endif -int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, - unsigned int index, int flags, int table) -{ return 0; } - int kernel_add_route (struct prefix_ipv4 *a, struct in_addr *b, int c, int d) { return 0; } diff --git a/zebra/rt.h b/zebra/rt.h index 8bfe5a429..7faa127b8 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -36,8 +36,6 @@ extern int kernel_address_delete_ipv4 (struct interface *, struct connected *); #ifdef HAVE_IPV6 extern int kernel_add_ipv6 (struct prefix *, struct rib *); extern int kernel_delete_ipv6 (struct prefix *, struct rib *); -extern int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, - unsigned int index, int flags, int table); #endif /* HAVE_IPV6 */ diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c index e175d1e27..553f222c7 100644 --- a/zebra/rt_ioctl.c +++ b/zebra/rt_ioctl.c @@ -517,12 +517,4 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6); } - -/* Delete IPv6 route from the kernel. */ -int -kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, - unsigned int index, int flags, int table) -{ - return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags); -} #endif /* HAVE_IPV6 */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 12dbd1ad5..2350070c6 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1855,15 +1855,6 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); } - -/* Delete IPv6 route from the kernel. */ -int -kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, - unsigned int index, int flags, int table) -{ - return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, - dest->prefixlen, gate, index, flags, table); -} #endif /* HAVE_IPV6 */ /* Interface address modification. */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index cde71ef47..63470adcb 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -474,20 +474,4 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib) return route; } - -/* Delete IPv6 route from the kernel. */ -int -kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, - unsigned int index, int flags, int table) -{ - int route; - - if (zserv_privs.change(ZPRIVS_RAISE)) - zlog (NULL, LOG_ERR, "Can't raise privileges"); - route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags); - if (zserv_privs.change(ZPRIVS_LOWER)) - zlog (NULL, LOG_ERR, "Can't lower privileges"); - - return route; -} #endif /* HAVE_IPV6 */ From 29ed622f3dc32816236a89de6fce323e3b092cf0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 21:42:25 +0200 Subject: [PATCH 0616/1342] build: remove ancient Linux/BSD IPv6 cruft IPv6 functions in a separate library... yeah, right. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 82 +++++++---------------------------------------- zebra/Makefile.am | 5 ++- 2 files changed, 14 insertions(+), 73 deletions(-) diff --git a/configure.ac b/configure.ac index 6684946a0..ac7eccb01 100755 --- a/configure.ac +++ b/configure.ac @@ -1059,91 +1059,33 @@ dnl KAME IPv6 dnl --------- if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6,1,KAME IPv6) AC_DEFINE(KAME,1,KAME IPv6) - RIPNGD="ripngd" - OSPF6D="ospf6d" - if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then - LIB_IPV6="-L/usr/local/v6/lib -linet6" - fi AC_MSG_RESULT(KAME) dnl ------------------------------------ dnl Solaris 9, 10 and potentially higher dnl ------------------------------------ elif test x"$opsys" = x"sol8"; then zebra_cv_ipv6=yes; - AC_DEFINE(HAVE_IPV6, 1, IPv6) AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6) - RIPNGD="ripngd" - OSPF6D="ospf6d" AC_MSG_RESULT(Solaris IPv6) dnl ---------- dnl Linux IPv6 dnl ---------- - elif test "${enable_ipv6}" = "yes"; then - AC_EGREP_CPP(yes, [ - #include - /* 2.1.128 or later */ - #if LINUX_VERSION_CODE >= 0x020180 - yes - #endif], - [zebra_cv_ipv6=yes - zebra_cv_linux_ipv6=yes - AC_MSG_RESULT(Linux IPv6)]) - else - if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" - then - zebra_cv_ipv6=yes - zebra_cv_linux_ipv6=yes - AC_MSG_RESULT(Linux IPv6) - fi - fi - - if test "$zebra_cv_linux_ipv6" = "yes";then - AC_MSG_CHECKING(whether libc has IPv6 support) - AC_TRY_LINK([#include - ],[ int a; a = (int) in6addr_any.s6_addr[0]; if (a != 12345) return a; ], - [AC_MSG_RESULT(yes) - zebra_cv_ipv6=yes - zebra_cv_linux_ipv6=yes], - [AC_MSG_RESULT(no) - zebra_cv_ipv6=no - zebra_cv_linux_ipv6=no]) - fi - - if test "$zebra_cv_linux_ipv6" = "yes";then - AC_MSG_CHECKING(for GNU libc >= 2.1) - AC_DEFINE(HAVE_IPV6,1,Linux IPv6) + elif test x"$opsys" = x"gnu-linux"; then + zebra_cv_ipv6=yes AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) - - AC_EGREP_CPP(yes, [ -#include -#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 - yes -#endif], - [glibc=yes - AC_MSG_RESULT(yes)], - AC_MSG_RESULT(no) - ) - RIPNGD="ripngd" - OSPF6D="ospf6d" - if test "$glibc" != "yes"; then - if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then - INCLUDES="-I/usr/inet6/include" - LIB_IPV6="-L/usr/inet6/lib -linet6" - fi - fi + AC_MSG_RESULT(Linux IPv6) + else + AC_MSG_RESULT(Unknown OS) fi +fi -dnl ----------------------- -dnl Set IPv6 related values -dnl ----------------------- - LIBS="$LIB_IPV6 $LIBS" - AC_SUBST(LIB_IPV6) - - if test x"$RIPNGD" = x""; then - AC_MSG_RESULT(IPv4 only) - fi +if test x"$zebra_cv_ipv6" = x"yes"; then + AC_DEFINE(HAVE_IPV6,1,IPv6) + RIPNGD="ripngd" + OSPF6D="ospf6d" +elif test x"${enable_ipv6}" = x"yes"; then + AC_MSG_ERROR([--enable-ipv6 given but IPv6 stack unknown]) fi dnl ------------------ diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 8e3c99bae..002b4f2af 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -4,7 +4,6 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 -LIB_IPV6 = @LIB_IPV6@ LIBCAP = @LIBCAP@ ipforward = @IPFORWARD@ @@ -43,9 +42,9 @@ noinst_HEADERS = \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h -zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) +zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) -testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) +testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) zebra_DEPENDENCIES = $(otherobj) From 39b233f0d789a6b5273c3dd279f17a67c718ea1a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 21:49:18 +0200 Subject: [PATCH 0617/1342] zebra: remove rt_ioctl kernel interface None of the BSDs uses ioctls to set routes anymore. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 28 +-- zebra/Makefile.am | 2 +- zebra/rt_ioctl.c | 520 ---------------------------------------------- 3 files changed, 2 insertions(+), 548 deletions(-) delete mode 100644 zebra/rt_ioctl.c diff --git a/configure.ac b/configure.ac index ac7eccb01..4465a0846 100755 --- a/configure.ac +++ b/configure.ac @@ -792,36 +792,10 @@ if test x"$opsys" = x"gnu-linux"; then RT_METHOD=rt_netlink.o AC_DEFINE(HAVE_NETLINK,,netlink) netlink=yes -elif test x"$opsys" = x"sol2-6";then - AC_MSG_RESULT(Route socket) - KERNEL_METHOD="kernel_socket.o" - RT_METHOD="rt_socket.o" -elif test x"$opsys" = x"sol8";then +else AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" -else - AC_TRY_RUN([#include -#include -#include - -main () -{ - int ac_sock; - - ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); - if (ac_sock < 0 && errno == EINVAL) - exit (1); - exit (0); -}], - [KERNEL_METHOD=kernel_socket.o - RT_METHOD=rt_socket.o - AC_MSG_RESULT(socket)], - [RT_METHOD=rt_ioctl.o - AC_MSG_RESULT(ioctl)], - [KERNEL_METHOD=kernel_socket.o - RT_METHOD=rt_socket.o - AC_MSG_RESULT(socket)]) fi AC_SUBST(RT_METHOD) AC_SUBST(KERNEL_METHOD) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 002b4f2af..045897ad7 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -50,7 +50,7 @@ zebra_DEPENDENCIES = $(otherobj) EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ if_sysctl.c ipforward_proc.c \ - ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ + ipforward_solaris.c ipforward_sysctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c \ ioctl.c ioctl_solaris.c \ diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c deleted file mode 100644 index 553f222c7..000000000 --- a/zebra/rt_ioctl.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * kernel routing table update by ioctl(). - * Copyright (C) 1997, 98 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -#include "prefix.h" -#include "log.h" -#include "if.h" - -#include "zebra/zserv.h" -#include "zebra/rib.h" -#include "zebra/debug.h" -#include "zebra/rt.h" - -/* Initialize of kernel interface. There is no kernel communication - support under ioctl(). So this is dummy stub function. */ -void -kernel_init (void) -{ - return; -} - -/* Dummy function of routing socket. */ -static void -kernel_read (int sock) -{ - return; -} - -#if 0 -/* Initialization prototype of struct sockaddr_in. */ -static struct sockaddr_in sin_proto = -{ -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sizeof (struct sockaddr_in), -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - AF_INET, 0, {0}, {0} -}; -#endif /* 0 */ - -/* Solaris has ortentry. */ -#ifdef HAVE_OLD_RTENTRY -#define rtentry ortentry -#endif /* HAVE_OLD_RTENTRY */ - -/* Interface to ioctl route message. */ -int -kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate, - int index, int flags) -{ - int ret; - int sock; - struct rtentry rtentry; - struct sockaddr_in sin_dest, sin_mask, sin_gate; - - memset (&rtentry, 0, sizeof (struct rtentry)); - - /* Make destination. */ - memset (&sin_dest, 0, sizeof (struct sockaddr_in)); - sin_dest.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_dest.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sin_dest.sin_addr = dest->prefix; - - /* Make gateway. */ - if (gate) - { - memset (&sin_gate, 0, sizeof (struct sockaddr_in)); - sin_gate.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sin_gate.sin_addr = *gate; - } - - memset (&sin_mask, 0, sizeof (struct sockaddr_in)); - sin_mask.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - masklen2ip (dest->prefixlen, &sin_mask.sin_addr); - - /* Set destination address, mask and gateway.*/ - memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); - if (gate) - memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); -#ifndef SUNOS_5 - memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); -#endif /* SUNOS_5 */ - - /* Routing entry flag set. */ - if (dest->prefixlen == 32) - rtentry.rt_flags |= RTF_HOST; - - if (gate && gate->s_addr != INADDR_ANY) - rtentry.rt_flags |= RTF_GATEWAY; - - rtentry.rt_flags |= RTF_UP; - - /* Additional flags */ - rtentry.rt_flags |= flags; - - - /* For tagging route. */ - /* rtentry.rt_flags |= RTF_DYNAMIC; */ - - /* Open socket for ioctl. */ - sock = socket (AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - { - zlog_warn ("can't make socket\n"); - return -1; - } - - /* Send message by ioctl(). */ - ret = ioctl (sock, SIOCADDRT, &rtentry); - if (ret < 0) - { - switch (errno) - { - case EEXIST: - close (sock); - return ZEBRA_ERR_RTEXIST; - break; - case ENETUNREACH: - close (sock); - return ZEBRA_ERR_RTUNREACH; - break; - case EPERM: - close (sock); - return ZEBRA_ERR_EPERM; - break; - } - - close (sock); - zlog_warn ("write : %s (%d)", safe_strerror (errno), errno); - return 1; - } - close (sock); - - return ret; -} - -/* Interface to ioctl route message. */ -static int -kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family) -{ - int ret; - int sock; - struct rtentry rtentry; - struct sockaddr_in sin_dest, sin_mask, sin_gate; - struct nexthop *nexthop, *tnexthop; - int recursing; - int nexthop_num = 0; - struct interface *ifp; - - memset (&rtentry, 0, sizeof (struct rtentry)); - - /* Make destination. */ - memset (&sin_dest, 0, sizeof (struct sockaddr_in)); - sin_dest.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_dest.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sin_dest.sin_addr = p->u.prefix4; - - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - { - SET_FLAG (rtentry.rt_flags, RTF_REJECT); - - if (cmd == SIOCADDRT) - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - /* 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; - } - - memset (&sin_gate, 0, sizeof (struct sockaddr_in)); - - /* Make gateway. */ - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - if ((cmd == SIOCADDRT - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - || (cmd == SIOCDELRT - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) - { - if (nexthop->type == NEXTHOP_TYPE_IPV4 || - nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - { - sin_gate.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - 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) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - nexthop_num++; - break; - } - } - - /* If there is no useful nexthop then return. */ - if (nexthop_num == 0) - { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("netlink_route_multipath(): No useful nexthop."); - return 0; - } - - skip: - - memset (&sin_mask, 0, sizeof (struct sockaddr_in)); - sin_mask.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_mask.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - masklen2ip (p->prefixlen, &sin_mask.sin_addr); - - /* Set destination address, mask and gateway.*/ - memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); - - if (rtentry.rt_flags & RTF_GATEWAY) - memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); - -#ifndef SUNOS_5 - memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); -#endif /* SUNOS_5 */ - - /* Metric. It seems metric minus one value is installed... */ - rtentry.rt_metric = rib->metric; - - /* Routing entry flag set. */ - if (p->prefixlen == 32) - rtentry.rt_flags |= RTF_HOST; - - rtentry.rt_flags |= RTF_UP; - - /* Additional flags */ - /* rtentry.rt_flags |= flags; */ - - /* For tagging route. */ - /* rtentry.rt_flags |= RTF_DYNAMIC; */ - - /* Open socket for ioctl. */ - sock = socket (AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - { - zlog_warn ("can't make socket\n"); - return -1; - } - - /* Send message by ioctl(). */ - ret = ioctl (sock, cmd, &rtentry); - if (ret < 0) - { - switch (errno) - { - case EEXIST: - close (sock); - return ZEBRA_ERR_RTEXIST; - break; - case ENETUNREACH: - close (sock); - return ZEBRA_ERR_RTUNREACH; - break; - case EPERM: - close (sock); - return ZEBRA_ERR_EPERM; - break; - } - - close (sock); - zlog_warn ("write : %s (%d)", safe_strerror (errno), errno); - return ret; - } - close (sock); - - return ret; -} - -int -kernel_add_ipv4 (struct prefix *p, struct rib *rib) -{ - return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET); -} - -int -kernel_delete_ipv4 (struct prefix *p, struct rib *rib) -{ - return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET); -} - -#ifdef HAVE_IPV6 - -/* Below is hack for GNU libc definition and Linux 2.1.X header. */ -#undef RTF_DEFAULT -#undef RTF_ADDRCONF - -#include - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 -/* struct in6_rtmsg will be declared in net/route.h. */ -#else -#include -#endif - -static int -kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate, - int index, int flags) -{ - int ret; - int sock; - struct in6_rtmsg rtm; - - memset (&rtm, 0, sizeof (struct in6_rtmsg)); - - rtm.rtmsg_flags |= RTF_UP; - rtm.rtmsg_metric = 1; - memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr)); - rtm.rtmsg_dst_len = dest->prefixlen; - - /* We need link local index. But this should be done caller... - if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) - { - index = if_index_address (&rtm.rtmsg_gateway); - rtm.rtmsg_ifindex = index; - } - else - rtm.rtmsg_ifindex = 0; - */ - - rtm.rtmsg_flags |= RTF_GATEWAY; - - /* For tagging route. */ - /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ - - memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr)); - - if (index) - rtm.rtmsg_ifindex = index; - else - rtm.rtmsg_ifindex = 0; - - rtm.rtmsg_metric = 1; - - sock = socket (AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) - { - zlog_warn ("can't make socket\n"); - return -1; - } - - /* Send message via ioctl. */ - ret = ioctl (sock, type, &rtm); - if (ret < 0) - { - zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", - safe_strerror(errno)); - ret = errno; - close (sock); - return ret; - } - close (sock); - - return ret; -} - -static int -kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib, - int family) -{ - int ret; - int sock; - struct in6_rtmsg rtm; - struct nexthop *nexthop, *tnexthop; - int recursing; - int nexthop_num = 0; - - memset (&rtm, 0, sizeof (struct in6_rtmsg)); - - rtm.rtmsg_flags |= RTF_UP; - rtm.rtmsg_metric = rib->metric; - memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr)); - rtm.rtmsg_dst_len = p->prefixlen; - - /* We need link local index. But this should be done caller... - if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) - { - index = if_index_address (&rtm.rtmsg_gateway); - rtm.rtmsg_ifindex = index; - } - else - rtm.rtmsg_ifindex = 0; - */ - - rtm.rtmsg_flags |= RTF_GATEWAY; - - /* For tagging route. */ - /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ - - /* Make gateway. */ - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - if ((cmd == SIOCADDRT - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - || (cmd == SIOCDELRT - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) - { - 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) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - nexthop_num++; - break; - } - } - - /* If there is no useful nexthop then return. */ - if (nexthop_num == 0) - { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("netlink_route_multipath(): No useful nexthop."); - return 0; - } - - sock = socket (AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) - { - zlog_warn ("can't make socket\n"); - return -1; - } - - /* Send message via ioctl. */ - ret = ioctl (sock, cmd, &rtm); - if (ret < 0) - { - zlog_warn ("can't %s ipv6 route: %s\n", - cmd == SIOCADDRT ? "add" : "delete", - safe_strerror(errno)); - ret = errno; - close (sock); - return ret; - } - close (sock); - - return ret; -} - -int -kernel_add_ipv6 (struct prefix *p, struct rib *rib) -{ - return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6); -} - -int -kernel_delete_ipv6 (struct prefix *p, struct rib *rib) -{ - return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6); -} -#endif /* HAVE_IPV6 */ From e8d0d24e7ac5e5ffdee04128b08a6004fdb831ba Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 22:07:41 +0200 Subject: [PATCH 0618/1342] build: remove --enable-solaris parameter This switch controlled descending into the solaris/ subdirectory, which contains package descriptions and init scripts. If they're not appropriate, they'd better be removed outright. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 4465a0846..1583fb681 100755 --- a/configure.ac +++ b/configure.ac @@ -222,8 +222,6 @@ AC_ARG_ENABLE(isisd, [ --enable-isisd build isisd]) AC_ARG_ENABLE(pimd, [ --enable-pimd build pimd]) -AC_ARG_ENABLE(solaris, -[ --enable-solaris build solaris]) AC_ARG_ENABLE(bgp-announce, [ --disable-bgp-announce, turn off BGP route announcement]) AC_ARG_ENABLE(snmp, @@ -576,6 +574,7 @@ case "$host" in AC_DEFINE(SUNOS_5, 1, SunOS 5) AC_CHECK_LIB(xnet, main) CURSES=-lcurses + SOLARIS="solaris" ;; [*-sunos5.[8-9]] \ | [*-sunos5.1[0-9]] \ @@ -594,12 +593,14 @@ case "$host" in AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality]) ]) CURSES=-lcurses + SOLARIS="solaris" ;; *-sunos5* | *-solaris2*) AC_DEFINE(SUNOS_5,,SunOS 5, Unknown SunOS) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) CURSES=-lcurses + SOLARIS="solaris" ;; *-linux*) opsys=gnu-linux @@ -1183,13 +1184,6 @@ case "${enable_pimd}" in esac AM_CONDITIONAL(PIMD, test "x$PIMD" = "xpimd") -# XXX Perhaps auto-enable on Solaris, but that's messy for cross builds. -case "${enable_solaris}" in - "yes") SOLARIS="solaris";; - "no" ) SOLARIS="";; - * ) ;; -esac - if test "${enable_bgp_announce}" = "no";then AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra) else From b6fa76098d127f5641a7dda0dee21f06ca167edb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 22:15:59 +0200 Subject: [PATCH 0619/1342] build: harmonize configure help strings Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- configure.ac | 84 ++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/configure.ac b/configure.ac index 1583fb681..0fd4db1dc 100755 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ AC_ARG_VAR([GAWK],[GNU AWK]) dnl default is to match previous behavior exampledir=${sysconfdir} AC_ARG_ENABLE([exampledir], - AC_HELP_STRING([--enable-exampledir], + AS_HELP_STRING([--enable-exampledir], [specify alternate directory for examples]), exampledir="$enableval",) dnl XXX add --exampledir to autoconf standard directory list somehow @@ -42,7 +42,7 @@ dnl default is to match previous behavior pkgsrcrcdir="" pkgsrcdir="" AC_ARG_ENABLE([pkgsrcrcdir], - AC_HELP_STRING([--enable-pkgsrcrcdir], + AS_HELP_STRING([--enable-pkgsrcrcdir], [specify directory for rc.d scripts]), pkgsrcrcdir="$enableval"; pkgsrcdir="pkgsrc",) dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow @@ -197,85 +197,85 @@ AC_ARG_WITH(pkg-git-version, AS_HELP_STRING([--with-pkg-git-version], [add git information to MOTD and build version string]), [ test "x$withval" != "xno" && with_pkg_git_version="yes" ]) AC_ARG_ENABLE(vtysh, -[ --enable-vtysh include integrated vty shell for Quagga]) + AS_HELP_STRING([--enable-vtysh], [include integrated vty shell for Quagga])) AC_ARG_ENABLE(ipv6, -[ --disable-ipv6 turn off IPv6 related features and daemons]) + AS_HELP_STRING([--disable-ipv6], [turn off IPv6 related features and daemons])) AC_ARG_ENABLE(doc, -[ --disable-doc do not build docs]) + AS_HELP_STRING([--disable-doc], [do not build docs])) AC_ARG_ENABLE(zebra, -[ --disable-zebra do not build zebra daemon]) + AS_HELP_STRING([--disable-zebra], [do not build zebra daemon])) AC_ARG_ENABLE(bgpd, -[ --disable-bgpd do not build bgpd]) + AS_HELP_STRING([--disable-bgpd], [do not build bgpd])) AC_ARG_ENABLE(ripd, -[ --disable-ripd do not build ripd]) + AS_HELP_STRING([--disable-ripd], [do not build ripd])) AC_ARG_ENABLE(ripngd, -[ --disable-ripngd do not build ripngd]) + AS_HELP_STRING([--disable-ripngd], [do not build ripngd])) AC_ARG_ENABLE(ospfd, -[ --disable-ospfd do not build ospfd]) + AS_HELP_STRING([--disable-ospfd], [do not build ospfd])) AC_ARG_ENABLE(ospf6d, -[ --disable-ospf6d do not build ospf6d]) + AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) AC_ARG_ENABLE(babeld, -[ --disable-babeld do not build babeld]) + AS_HELP_STRING([--disable-babeld], [do not build babeld])) AC_ARG_ENABLE(watchquagga, -[ --disable-watchquagga do not build watchquagga]) + AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) AC_ARG_ENABLE(isisd, -[ --enable-isisd build isisd]) + AS_HELP_STRING([--enable-isisd], [build isisd])) AC_ARG_ENABLE(pimd, -[ --enable-pimd build pimd]) + AS_HELP_STRING([--enable-pimd], [build pimd])) AC_ARG_ENABLE(bgp-announce, -[ --disable-bgp-announce, turn off BGP route announcement]) + AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement])) AC_ARG_ENABLE(snmp, -[ --enable-snmp=ARG enable SNMP support (smux or agentx)]) + AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)])) AC_ARG_WITH(libpam, -[ --with-libpam use libpam for PAM support in vtysh]) + AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh])) AC_ARG_ENABLE(tcp-zebra, -[ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon]) + AS_HELP_STRING([--enable-tcp-zebra], [enable TCP/IP socket connection between zebra and protocol daemon])) AC_ARG_ENABLE(opaque-lsa, - AC_HELP_STRING([--disable-opaque-lsa],[do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370)])) + AS_HELP_STRING([--disable-opaque-lsa],[do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370)])) AC_ARG_ENABLE(ospfapi, -[ --disable-ospfapi do not build OSPFAPI to access the OSPF LSA Database]) + AS_HELP_STRING([--disable-ospfapi], [do not build OSPFAPI to access the OSPF LSA Database])) AC_ARG_ENABLE(ospfclient, -[ --disable-ospfclient do not build OSPFAPI client for OSPFAPI, - (this is the default if --disable-ospfapi is set)]) + AS_HELP_STRING([--disable-ospfclient], [do not build OSPFAPI client for OSPFAPI, + (this is the default if --disable-ospfapi is set)])) AC_ARG_ENABLE(ospf-te, - AC_HELP_STRING([--disable-ospf-te],[disable Traffic Engineering Extension to OSPF])) + AS_HELP_STRING([--disable-ospf-te],[disable Traffic Engineering Extension to OSPF])) AC_ARG_ENABLE(multipath, -[ --enable-multipath=ARG enable multipath function, ARG must be digit]) + AS_HELP_STRING([--enable-multipath=ARG], [enable multipath function, ARG must be digit])) AC_ARG_ENABLE(user, - AC_HELP_STRING([--enable-user=user], [user to run Quagga suite as (default quagga)])) + AS_HELP_STRING([--enable-user=USER], [user to run Quagga suite as (default quagga)])) AC_ARG_ENABLE(group, - AC_HELP_STRING([--enable-group=group], [group to run Quagga suite as (default quagga)])) + AS_HELP_STRING([--enable-group=GROUP], [group to run Quagga suite as (default quagga)])) AC_ARG_ENABLE(vty_group, -[ --enable-vty-group=ARG set vty sockets to have specified group as owner]) + AS_HELP_STRING([--enable-vty-group=ARG], [set vty sockets to have specified group as owner])) AC_ARG_ENABLE(configfile_mask, -[ --enable-configfile-mask=ARG set mask for config files]) + AS_HELP_STRING([--enable-configfile-mask=ARG], [set mask for config files])) AC_ARG_ENABLE(logfile_mask, -[ --enable-logfile-mask=ARG set mask for log files]) + AS_HELP_STRING([--enable-logfile-mask=ARG], [set mask for log files])) AC_ARG_ENABLE(rtadv, -[ --disable-rtadv disable IPV6 router advertisement feature]) + AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature])) AC_ARG_ENABLE(irdp, -[ --enable-irdp enable IRDP server support in zebra]) + AS_HELP_STRING([--enable-irdp], [enable IRDP server support in zebra])) AC_ARG_ENABLE(isis_topology, -[ --enable-isis-topology enable IS-IS topology generator]) + AS_HELP_STRING([--enable-isis-topology], [enable IS-IS topology generator])) AC_ARG_ENABLE(capabilities, -[ --disable-capabilities disable using POSIX capabilities]) + AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities])) AC_ARG_ENABLE(rusage, -[ --disable-rusage disable using getrusage]) + AS_HELP_STRING([--disable-rusage], [disable using getrusage])) AC_ARG_ENABLE(gcc_ultra_verbose, -[ --enable-gcc-ultra-verbose enable ultra verbose GCC warnings]) + AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings])) AC_ARG_ENABLE(linux24_tcp_md5, -[ --enable-linux24-tcp-md5 enable support for old, Linux-2.4 RFC2385 patch]) + AS_HELP_STRING([--enable-linux24-tcp-md5], [enable support for old, Linux-2.4 RFC2385 patch])) AC_ARG_ENABLE(gcc-rdynamic, -[ --enable-gcc-rdynamic enable linking with -rdynamic for better backtraces (default if gcc)]) + AS_HELP_STRING([--enable-gcc-rdynamic], [enable linking with -rdynamic for better backtraces (default if gcc)])) AC_ARG_ENABLE(backtrace, -[ --disable-backtrace, disable crash backtraces (default autodetect)]) + AS_HELP_STRING([--disable-backtrace,], [disable crash backtraces (default autodetect)])) AC_ARG_ENABLE(time-check, -[ --disable-time-check disable slow thread warning messages]) + AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages])) AC_ARG_ENABLE(pcreposix, -[ --enable-pcreposix enable using PCRE Posix libs for regex functions]) + AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE(fpm, -[ --enable-fpm enable Forwarding Plane Manager support]) + AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" From 237aac56960575f6ad2451ba2796d94bd5ae4b33 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 28 Jun 2014 22:23:10 +0200 Subject: [PATCH 0620/1342] build: get rid of INCLUDES, use AM_CPPFLAGS INCLUDES in configure.ac was not used at all, and INCLUDES in Makefile.am is supposed to be AM_CPPFLAGS these days. Reduces warnings spewed during bootstrap/autoreconf. Signed-off-by: David Lamparter Acked-by: Greg Troxel Acked-by: Feng Lu Acked-by: Paul Jakma --- babeld/Makefile.am | 2 +- bgpd/Makefile.am | 2 +- configure.ac | 2 -- isisd/Makefile.am | 2 +- isisd/topology/Makefile.am | 5 +---- lib/Makefile.am | 2 +- ospf6d/Makefile.am | 2 +- ospfclient/Makefile.am | 2 +- ospfd/Makefile.am | 2 +- pimd/Makefile.am | 2 +- ripd/Makefile.am | 2 +- ripngd/Makefile.am | 2 +- tests/Makefile.am | 2 +- vtysh/Makefile.am | 2 +- watchquagga/Makefile.am | 2 +- zebra/Makefile.am | 2 +- 16 files changed, 15 insertions(+), 20 deletions(-) diff --git a/babeld/Makefile.am b/babeld/Makefile.am index af1201a71..13922d0f4 100644 --- a/babeld/Makefile.am +++ b/babeld/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 9928734ee..42f1f488c 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/configure.ac b/configure.ac index 0fd4db1dc..715f35d86 100755 --- a/configure.ac +++ b/configure.ac @@ -1203,7 +1203,6 @@ AC_SUBST(ISISD) AC_SUBST(PIMD) AC_SUBST(SOLARIS) AC_SUBST(VTYSH) -AC_SUBST(INCLUDES) AC_SUBST(CURSES) AC_SUBST(OSPFCLIENT) AC_SUBST(OSPFAPI) @@ -1598,7 +1597,6 @@ source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} make : ${MAKE-make} -includes : ${INCLUDES} linker flags : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${quagga_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` diff --git a/isisd/Makefile.am b/isisd/Makefile.am index 4e9b2441e..dba681b11 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/isisd/topology/Makefile.am b/isisd/topology/Makefile.am index ccd2e7174..fe73ae5c6 100644 --- a/isisd/topology/Makefile.am +++ b/isisd/topology/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) @@ -18,7 +18,4 @@ libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.la noinst_HEADERS = \ spgrid.h -depend: - @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c - ## File dependency. diff --git a/lib/Makefile.am b/lib/Makefile.am index bd2109292..5a806183c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index 726ce543e..d30ce5819 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index 0f37aa988..09d2ba860 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -1,6 +1,6 @@ ## Automake.am for OSPF API client -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 4e1a4fe9f..4160bfccc 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 7173a231a..f13debd9d 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -34,7 +34,7 @@ PIM_DEFS += -DPIM_ZCLIENT_DEBUG PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ diff --git a/ripd/Makefile.am b/ripd/Makefile.am index b0bc7a875..65a626dd6 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index de5bebaef..9bd14ba0b 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/tests/Makefile.am b/tests/Makefile.am index 8a086d0b6..1fe28c70f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -13,7 +13,7 @@ EXTRA_DIST = \ testcommands.in \ testcommands.refout -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index f9dea2de6..a66615beb 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with Automake to create Makefile.in -INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" LIBS = @LIBS@ @CURSES@ @LIBPAM@ diff --git a/watchquagga/Makefile.am b/watchquagga/Makefile.am index badaa5b5d..9256006c8 100644 --- a/watchquagga/Makefile.am +++ b/watchquagga/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with Automake to create Makefile.in -INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" AM_CFLAGS = $(PICFLAGS) diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 045897ad7..480879179 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. -INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 From 7fe17e6975f4c4dd359364177a1d73ed770d6cd4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 22 Nov 2014 10:31:33 -0800 Subject: [PATCH 0621/1342] build: remove --disable-ipv6 Building with IPv6 disabled tends to break rather often and sprinkles ugly #ifdefs around the code. All that only to support systems where the C library doesn't have IPv6 capability. The year now being 2015, if this is a problem the thing to fix is the C library. The implication of this patch is that future patches need not care about HAVE_IPV6 = 0 and may remove ifdefs gratuitously. This patch doesn't remove these ifdefs to not create unneccessary churn. Signed-off-by: David Lamparter Acked-by: Paul Jakma --- buildtest.sh | 10 ++-------- configure.ac | 28 +++++----------------------- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/buildtest.sh b/buildtest.sh index 4859bf4a0..3bc25f232 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -4,22 +4,16 @@ # builds some git commit of Quagga in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-ipv6 --enable-ripngd --enable-ospf6d --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld --enable-pimd" +basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld --enable-pimd" configs_base="gcc|$basecfg" -configs_nov6="gcc|$basecfg" -configs_nov6="${configs_nov6/enable-ipv6/disable-ipv6}" -configs_nov6="${configs_nov6/enable-ospf6d/disable-ospf6d}" -configs_nov6="${configs_nov6/enable-ripngd/disable-ripngd}" -configs_nov6="${configs_nov6/enable-babeld/disable-babeld}" - configs_ext="gcc|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology" configs_snmp="gcc|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology --enable-snmp" configs_clang="clang|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology" configs_icc="icc|$basecfg --enable-opaque-lsa --enable-ospf-te --enable-ospfclient --enable-isis-topology" -defconfigs="base nov6 ext" +defconfigs="base ext" net-snmp-config --version &> /dev/null && defconfigs="$defconfigs snmp" clang --version &> /dev/null && defconfigs="$defconfigs clang" icc --version &> /dev/null && defconfigs="$defconfigs icc" diff --git a/configure.ac b/configure.ac index 715f35d86..33a1cd067 100755 --- a/configure.ac +++ b/configure.ac @@ -198,8 +198,6 @@ AC_ARG_WITH(pkg-git-version, [ test "x$withval" != "xno" && with_pkg_git_version="yes" ]) AC_ARG_ENABLE(vtysh, AS_HELP_STRING([--enable-vtysh], [include integrated vty shell for Quagga])) -AC_ARG_ENABLE(ipv6, - AS_HELP_STRING([--disable-ipv6], [turn off IPv6 related features and daemons])) AC_ARG_ENABLE(doc, AS_HELP_STRING([--disable-doc], [do not build docs])) AC_ARG_ENABLE(zebra, @@ -1026,51 +1024,37 @@ dnl ---------- dnl IPv6 check dnl ---------- AC_MSG_CHECKING(whether does this OS have IPv6 stack) -if test "${enable_ipv6}" = "no"; then - AC_MSG_RESULT(disabled) -else dnl --------- dnl KAME IPv6 dnl --------- if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then - zebra_cv_ipv6=yes AC_DEFINE(KAME,1,KAME IPv6) AC_MSG_RESULT(KAME) dnl ------------------------------------ dnl Solaris 9, 10 and potentially higher dnl ------------------------------------ elif test x"$opsys" = x"sol8"; then - zebra_cv_ipv6=yes; AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6) AC_MSG_RESULT(Solaris IPv6) dnl ---------- dnl Linux IPv6 dnl ---------- elif test x"$opsys" = x"gnu-linux"; then - zebra_cv_ipv6=yes AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) AC_MSG_RESULT(Linux IPv6) else - AC_MSG_RESULT(Unknown OS) + AC_MSG_ERROR([Failed to detect IPv6 stack]) fi -fi -if test x"$zebra_cv_ipv6" = x"yes"; then - AC_DEFINE(HAVE_IPV6,1,IPv6) - RIPNGD="ripngd" - OSPF6D="ospf6d" -elif test x"${enable_ipv6}" = x"yes"; then - AC_MSG_ERROR([--enable-ipv6 given but IPv6 stack unknown]) -fi +dnl this is unconditial, for compatibility +AC_DEFINE(HAVE_IPV6,1,IPv6) dnl ------------------ dnl IPv6 header checks dnl ------------------ -if test "x${zebra_cv_ipv6}" = "xyes"; then AC_CHECK_HEADERS([netinet6/in6.h netinet/in6_var.h netinet/icmp6.h \ netinet6/in6_var.h netinet6/nd6.h], [], [], QUAGGA_INCLUDES) -fi m4_define([QUAGGA_INCLUDES],dnl QUAGGA_INCLUDES @@ -1157,16 +1141,14 @@ fi AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") case "${enable_ripngd}" in - "yes") RIPNGD="ripngd";; "no" ) RIPNGD="";; - * ) ;; + * ) RIPNGD="ripngd";; esac AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd") case "${enable_ospf6d}" in - "yes") OSPF6D="ospf6d";; "no" ) OSPF6D="";; - * ) ;; + * ) OSPF6D="ospf6d";; esac AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d") From 85c63b844df4a295a64f37573e0ba08a7cc63659 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 22 Nov 2014 10:31:44 -0800 Subject: [PATCH 0622/1342] tests: remove --disable-ipv6 With --disable-ipv6 gone, the IPv6 detection logic in the tests is not needed anymore either. Signed-off-by: David Lamparter Acked-by: Paul Jakma --- tests/bgpd.tests/testbgpcap.exp | 6 +++--- tests/bgpd.tests/testbgpmpattr.exp | 14 +++++++------- tests/config/unix.exp | 20 -------------------- 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/tests/bgpd.tests/testbgpcap.exp b/tests/bgpd.tests/testbgpcap.exp index 1bbdfd12f..2572623f0 100644 --- a/tests/bgpd.tests/testbgpcap.exp +++ b/tests/bgpd.tests/testbgpcap.exp @@ -8,10 +8,10 @@ spawn "./testbgpcap" # proc simpletest { start } { simpletest "MP4: MP IP/Uni" -simpletest_nov6 "MPv6: MP IPv6/Uni" +simpletest "MPv6: MP IPv6/Uni" simpletest "MP2: MP IP/Multicast" -simpletest_nov6 "MP3: MP IP6/MPLS-labeled VPN" -simpletest_nov6 "MP5: MP IP6/MPLS-VPN" +simpletest "MP3: MP IP6/MPLS-labeled VPN" +simpletest "MP5: MP IP6/MPLS-VPN" simpletest "MP6: MP IP4/MPLS-laveled VPN" simpletest "MP8: MP unknown AFI/SAFI" simpletest "MP-short: MP IP4/Unicast, length too short (< minimum)" diff --git a/tests/bgpd.tests/testbgpmpattr.exp b/tests/bgpd.tests/testbgpmpattr.exp index 93355ad7a..646bbe506 100644 --- a/tests/bgpd.tests/testbgpmpattr.exp +++ b/tests/bgpd.tests/testbgpmpattr.exp @@ -7,10 +7,10 @@ spawn "./testbgpmpattr" # proc simpletest { start } { -simpletest_nov6 "IPv6: IPV6 MP Reach, global nexthop, 1 NLRI" -simpletest_nov6 "IPv6-2: IPV6 MP Reach, global nexthop, 2 NLRIs" -simpletest_nov6 "IPv6-default: IPV6 MP Reach, global nexthop, 2 NLRIs + default" -simpletest_nov6 "IPv6-lnh: IPV6 MP Reach, global+local nexthops, 2 NLRIs + default" +simpletest "IPv6: IPV6 MP Reach, global nexthop, 1 NLRI" +simpletest "IPv6-2: IPV6 MP Reach, global nexthop, 2 NLRIs" +simpletest "IPv6-default: IPV6 MP Reach, global nexthop, 2 NLRIs + default" +simpletest "IPv6-lnh: IPV6 MP Reach, global+local nexthops, 2 NLRIs + default" simpletest "IPv6-nhlen: IPV6 MP Reach, inappropriate nexthop length" simpletest "IPv6-nhlen2: IPV6 MP Reach, invalid nexthop length" simpletest "IPv6-nhlen3: IPV6 MP Reach, nexthop length overflow" @@ -21,9 +21,9 @@ simpletest "IPv4-nhlen: IPv4 MP Reach, nexthop lenth overflow" simpletest "IPv4-nlrilen: IPv4 MP Reach, nlri lenth overflow" simpletest "IPv4-MLVPN: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs" simpletest "IPv6-bug: IPv6, global nexthop, 1 default NLRI" -simpletest_nov6 "IPv6-unreach: IPV6 MP Unreach, 1 NLRI" -simpletest_nov6 "IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs" -simpletest_nov6 "IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default" +simpletest "IPv6-unreach: IPV6 MP Unreach, 1 NLRI" +simpletest "IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs" +simpletest "IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default" simpletest "IPv6-unreach-nlri: IPV6 MP Unreach, NLRI bitlen overflow" simpletest "IPv4-unreach: IPv4 MP Unreach, 2 NLRIs + default" simpletest "IPv4-unreach-nlrilen: IPv4 MP Unreach, nlri length overflow" diff --git a/tests/config/unix.exp b/tests/config/unix.exp index b41f072cc..2f6bceadb 100644 --- a/tests/config/unix.exp +++ b/tests/config/unix.exp @@ -8,16 +8,6 @@ # be part of the output... #set color 1 -set config_h [open "../config.h" "r"] -set config_h_text [read $config_h] -close $config_h -set i [string first "#define HAVE_IPV6" $config_h_text] -if { $i >= 0 } { - set have_ipv6 1 -} else { - set have_ipv6 0 -} -send_user "IPv6 enabled: $have_ipv6\n" set xfail 0 proc onesimple { test_name match } { @@ -110,13 +100,3 @@ proc simpletest { start } { onetest "$start" "" "$start" } -proc simpletest_nov6 { start } { - global have_ipv6 - global xfail - - set xfail [expr 1-$have_ipv6] - onetest "$start" "" "$start" - set xfail 0 -} - - From 7abd87529499e5d76435213e2590838c5e320a9a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 22 Nov 2014 10:43:29 -0800 Subject: [PATCH 0623/1342] build: track config args Record the ./configure arguments used and make them user-visible. Signed-off-by: David Lamparter Acked-by: Paul Jakma --- configure.ac | 2 ++ lib/command.c | 3 +++ lib/version.h.in | 2 ++ 3 files changed, 7 insertions(+) diff --git a/configure.ac b/configure.ac index 33a1cd067..5a3f81696 100755 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,8 @@ AC_PREREQ(2.53) AC_INIT(Quagga, 0.99.24-rc1, [https://bugzilla.quagga.net]) +CONFIG_ARGS="$*" +AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) diff --git a/lib/command.c b/lib/command.c index 8870a4211..831778957 100644 --- a/lib/command.c +++ b/lib/command.c @@ -181,6 +181,7 @@ print_version (const char *progname) { printf ("%s version %s\n", progname, QUAGGA_VERSION); printf ("%s\n", QUAGGA_COPYRIGHT); + printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS); } @@ -2951,6 +2952,8 @@ DEFUN (show_version, vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"", VTY_NEWLINE); vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE); + vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE, + QUAGGA_CONFIG_ARGS, VTY_NEWLINE); return CMD_SUCCESS; } diff --git a/lib/version.h.in b/lib/version.h.in index 7e9985f00..aef1d090b 100644 --- a/lib/version.h.in +++ b/lib/version.h.in @@ -45,6 +45,8 @@ #define QUAGGA_COPYRIGHT "Copyright 1996-2005 Kunihiro Ishiguro, et al." +#define QUAGGA_CONFIG_ARGS "@CONFIG_ARGS@" + pid_t pid_output (const char *); #ifndef HAVE_DAEMON From f16195c173f8e2e17ea35f143b6ffcd50c0619fb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 28 Nov 2014 08:40:58 +0100 Subject: [PATCH 0624/1342] doc: fix some warnings Signed-off-by: David Lamparter Acked-by: Paul Jakma --- doc/Makefile.am | 2 +- doc/basic.texi | 6 +++--- doc/quagga.texi | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index bb7e87a18..11eca73ff 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -44,7 +44,7 @@ info_TEXINFOS = quagga.texi # because it cant just work from the png's directly it seems - contrary # to the documentation... quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) - $(TEXI2PDF) -o "$@" $< + $(TEXI2PDF) -o "$@" $< || true quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ diff --git a/doc/basic.texi b/doc/basic.texi index b3b23ca99..0f7bec9c2 100644 --- a/doc/basic.texi +++ b/doc/basic.texi @@ -15,8 +15,8 @@ The following sections discuss commands common to all the routing daemons. @menu -* Terminal Mode Commands:: Common commands used in a VTY * Config Commands:: Commands used in config files +* Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons @end menu @@ -580,8 +580,8 @@ Move up to previous line in the history buffer. @kindex @key{TAB} Use command line completion by typing @key{TAB}. -@item -@kindex ? +@item ? +@kindex @key{?} You can use command line help by typing @code{help} at the beginning of the line. Typing @kbd{?} at any point in the line will show possible completions. diff --git a/doc/quagga.texi b/doc/quagga.texi index af82e5153..836507109 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -2,9 +2,9 @@ @c %**start of header @setfilename quagga.info -@settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @c Set variables - sourced from defines.texi @include defines.texi +@settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @c %**end of header @c automake will automatically generate version.texi From 656a2c0724f0978d9cc5cf892f0373e808639288 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 9 Feb 2015 11:36:10 +0100 Subject: [PATCH 0625/1342] build: enable isisd by default Most distributors enable it anyway, and it's not THAT broken anymore to mandate disabling it by default. Signed-off-by: David Lamparter Acked-by: Paul Jakma --- configure.ac | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 5a3f81696..20d21f671 100755 --- a/configure.ac +++ b/configure.ac @@ -219,7 +219,7 @@ AC_ARG_ENABLE(babeld, AC_ARG_ENABLE(watchquagga, AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) AC_ARG_ENABLE(isisd, - AS_HELP_STRING([--enable-isisd], [build isisd])) + AS_HELP_STRING([--disable-isisd], [do not build isisd])) AC_ARG_ENABLE(pimd, AS_HELP_STRING([--enable-pimd], [build pimd])) AC_ARG_ENABLE(bgp-announce, @@ -331,7 +331,7 @@ if test "${enable_irdp}" = "yes"; then AC_DEFINE(HAVE_IRDP,, IRDP ) fi -if test "${enable_isisd}" = "yes" && test "${enable_isis_topology}" = yes; then +if test "${enable_isisd}" != "no" && test "${enable_isis_topology}" = yes; then AC_DEFINE(TOPOLOGY_GENERATE,,Enable IS-IS topology generator code) ISIS_TOPOLOGY_INCLUDES="-I\$(srcdir)/topology" ISIS_TOPOLOGY_DIR="topology" @@ -1155,9 +1155,8 @@ esac AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d") case "${enable_isisd}" in - "yes") ISISD="isisd";; "no" ) ISISD="";; - * ) ;; + * ) ISISD="isisd";; esac AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") From cc81308148271aeed2277e16885ddca7e2d5bb9b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 10 Feb 2015 11:39:39 +0100 Subject: [PATCH 0626/1342] build: enable AM_SILENT_RULES This shuts up make by default (can be reversed with "make V=1" or --disable-silent-rules). This is useful since warnings and error messages become more visible with less noise. Tested on Linux with GNU make and FreeBSD with system's BSD make. Signed-off-by: David Lamparter Acked-by: Paul Jakma --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 20d21f671..eeb242023 100755 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,7 @@ AC_CANONICAL_HOST() AC_CANONICAL_TARGET() AM_INIT_AUTOMAKE(1.6) +AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS(config.h) AC_PATH_PROG(PERL, perl) From b8a893c38e97377b2a2582b1621b988e55811412 Mon Sep 17 00:00:00 2001 From: Brian Bennett Date: Tue, 17 Feb 2015 22:32:22 +0000 Subject: [PATCH 0627/1342] build: Extend ip_mreq hack to DragonFlyBSD and SunOS This extends the ip_mreq hack to DragonFlyBSD and SunOS. This has been in pkgsrc for some time. I've cleaned up the pkgsrc patch a little and am submitting it upstream. Credit is due to pkgsrc maintainers. Tested on SmartOS (illumos). Fixes: #819 Signed-off-by: Greg Troxel Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index eeb242023..75a48e4d3 100755 --- a/configure.ac +++ b/configure.ac @@ -929,7 +929,7 @@ AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES) AC_MSG_CHECKING([for BSD struct ip_mreq hack]) AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H #include -#endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) +#endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__DragonFly__) || defined(__sun) return (0); #else #error No support for BSD struct ip_mreq hack detected From 75a3cf6cf69f6ab940f8421b0f79b2b1f689b904 Mon Sep 17 00:00:00 2001 From: Brian Bennett Date: Tue, 17 Feb 2015 23:26:12 +0000 Subject: [PATCH 0628/1342] solaris: fix SMF manifest dependency model and start method Resolves an issue where quagga daemons restart in an infinite loop. Quagga daemons declare a dependency on zebra that requires a restart of the daemon when zebra restarts and they explicitly restart zebra, which again triggers their own restart. Restarting zebra when other daemons are started is explicitly removed, leaving dependency management up to SMF rather than handling it in the start method. solaris/quagga.init.in: Remove calls to routeadm_zebra_enable, and the routeadm_zebra_enable function. solaris/quagga.xml.in: Set dependency zebra grouping to require_all. Fixes: #818 Signed-off-by: Greg Troxel Signed-off-by: David Lamparter --- solaris/quagga.init.in | 26 -------------------------- solaris/quagga.xml.in | 12 +++++++----- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/solaris/quagga.init.in b/solaris/quagga.init.in index 00426241b..ee3a987f3 100755 --- a/solaris/quagga.init.in +++ b/solaris/quagga.init.in @@ -146,31 +146,6 @@ routeadm_daemon_args () { echo ${args} } -# certain daemons need zebra -routeadm_zebra_enable () { - - if [ "$DAEMON" = "zebra" ]; then - return - fi - - enable_zebra=`/usr/bin/svcprop -p \ - routing/enable_zebra $SMF_FMRI 2> /dev/null` - if [ "$enable_zebra" != "false" ]; then - zenabled=`/usr/bin/svcprop -p general/enabled zebra:quagga` - zenabledt=`/usr/bin/svcprop -p general_ovr/enabled zebra:quagga` - if [ "$zenabled" = "true" -o "$zenabledt" = "true" ]; then - /usr/sbin/svcadm disable zebra:quagga - /usr/sbin/svcadm enable -st zebra:quagga - else - /usr/sbin/svcadm enable -st zebra:quagga - fi - if [ "$?" != "0" ]; then - echo "Could not enable zebra:quagga" - exit $SMF_EXIT_ERR_FATAL - fi - fi -} - # Include smf functions, if available. If not, define smf_present to indicate # there is no SMF. Should allow this script to work pre-S10. if [ -f "$SMFINCLUDE" ] ; then @@ -247,7 +222,6 @@ esac if [ smf_present -a -f "$ROUTEADMINCLUDE" ]; then handle_routeadm_upgrade $DAEMON; DAEMON_ARGS=`routeadm_daemon_args`; - routeadm_zebra_enable $DAEMON; else if [ $# -gt 0 ] ; then shift diff --git a/solaris/quagga.xml.in b/solaris/quagga.xml.in index 50c52c226..60427b06e 100644 --- a/solaris/quagga.xml.in +++ b/solaris/quagga.xml.in @@ -21,6 +21,8 @@ Copyright 2007 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. + Copyright 2015 Joyent, Inc. + ident "@(#)quagga.xml 1.0 05/03/15 SMI" --> @@ -189,7 +191,7 @@ @@ -320,7 +322,7 @@ @@ -449,7 +451,7 @@ @@ -580,7 +582,7 @@ @@ -715,7 +717,7 @@ From 4c421215a0330b96d85879810558d40027a96ca6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 2 Mar 2015 06:42:11 +0100 Subject: [PATCH 0629/1342] zebra: print "no link-detect" The default for this is slated to change, so let's print the current default value for preexisting configurations. Signed-off-by: David Lamparter --- zebra/interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/interface.c b/zebra/interface.c index 7e1d3dd86..0271061e7 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1579,6 +1579,8 @@ if_config_write (struct vty *vty) if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) vty_out(vty, " link-detect%s", VTY_NEWLINE); + else + vty_out(vty, " no link-detect%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (ifp->connected, addrnode, ifc)) { From f191f1e6d64e9f2cefacc91023a2359d037fea79 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 00:50:57 +0100 Subject: [PATCH 0630/1342] release: 0.99.24 --- NEWS | 30 ++++++++++++++++++++++++++++++ configure.ac | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 57cc99f07..8f9dd7a11 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,35 @@ Note: this file lists major user-visible changes only. +* Changes in Quagga 0.99.24 + +User-visible changes: +- [pimd] New daemon: pimd provides IPv4 PIM-SSM multicast routing. +- [bgpd] New feature: "next-hop-self all" to override nexthop on iBGP route + reflector setups. +- [bgpd] route-maps have a new action "set ipv6 next-hop peer-address" +- [bgpd] route-maps have a new action "set as-path prepend last-as" +- [bgpd] Update validity checking (particularly MP-BGP / IPv6 routes) was + touched up significantly. Please report possible bugs. +- [ripd] New feature: RIP for IPv4 now supports equal-cost multipath (ECMP) +- [zebra] Multicast RIB support has been extended. It still is IPv4 only. +- [zebra] "no link-detect" is now printed in configurations since it won't + be the default anymore soon. To retain current behaviour, re-save your + configuration after updating to 0.99.24. + +Distributor-visible changes: +- --enable-pimd is added to enable pimd. It is considered experimental, though + unless the distribution target is embedded systems with little flash, there + is no reason to not include it in packages. +- --disable-ipv6 no longer exists as an option. It's 2015, your C library + really needs to have IPv6 support by now. +- --disable-netlink no longer exists as an option. It didn't work anyway. +- --disable-solaris no longer exists as an option. It only controlled some + init scripts. +- --enable-isisd is now the default. +- mrlg.cgi is no longer included (it was severely outdated). It can be found + independently at http://mrlg.op-sec.us/ +- build on Linux with the musl C library should now work + * Changes in Quagga 0.99.23 Known issues: diff --git a/configure.ac b/configure.ac index 75a48e4d3..4d52eefaa 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.24-rc1, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.24, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From d8d54ab78d915921a88a8707426e307aed3c323e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 07:30:19 +0100 Subject: [PATCH 0631/1342] build: tag version as 0.99.25-dev Signed-off-by: David Lamparter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4d52eefaa..2c72cff89 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.24, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.25-dev, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From 5cd0e5c659d0ae7840748e83cd9f340568fa4204 Mon Sep 17 00:00:00 2001 From: Brian Bennett Date: Tue, 17 Feb 2015 23:24:15 +0000 Subject: [PATCH 0632/1342] lib: Fix POSIX capabilities on SunOS platforms When using POSIX capabilities on SunOS the capabilities are too restricitve resulting in quagga processes not being able to read their own config files. Credit goes to Oracle where this patch was originally authored and included in OpenSolaris. lib/privs.c: Include additional capabilities, better checking of missing capabilities. Fixes: #820 Acked-by: Greg Troxel Signed-off-by: David Lamparter --- lib/privs.c | 76 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/lib/privs.c b/lib/privs.c index e182543a6..f7269f4ac 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -2,7 +2,7 @@ * Zebra privileges. * * Copyright (C) 2003 Paul Jakma. - * Copyright (C) 2005 Sun Microsystems, Inc. + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * * This file is part of GNU Zebra. * @@ -348,6 +348,26 @@ zprivs_caps_terminate (void) * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1 */ +static pset_t * +zprivs_caps_minimal () +{ + pset_t *minimal; + + if ((minimal = priv_str_to_set("basic", ",", NULL)) == NULL) + { + fprintf (stderr, "%s: couldn't get basic set!\n", __func__); + exit (1); + } + + /* create a minimal privilege set from the basic set */ + (void) priv_delset(minimal, PRIV_PROC_EXEC); + (void) priv_delset(minimal, PRIV_PROC_INFO); + (void) priv_delset(minimal, PRIV_PROC_SESSION); + (void) priv_delset(minimal, PRIV_FILE_LINK_ANY); + + return minimal; +} + /* convert zebras privileges to system capabilities */ static pset_t * zcaps2sys (zebra_capabilities_t *zcaps, int num) @@ -376,26 +396,34 @@ zcaps2sys (zebra_capabilities_t *zcaps, int num) int zprivs_change_caps (zebra_privs_ops_t op) { + pset_t *privset; /* should be no possibility of being called without valid caps */ assert (zprivs_state.syscaps_p); if (!zprivs_state.syscaps_p) + { + fprintf (stderr, "%s: Eek, missing privileged caps!", __func__); + exit (1); + } + + assert (zprivs_state.caps); + if (!zprivs_state.caps) { fprintf (stderr, "%s: Eek, missing caps!", __func__); exit (1); } - - /* to raise: copy original permitted into our working effective set - * to lower: just clear the working effective set + + /* to raise: copy original permitted as our working effective set + * to lower: copy regular effective set stored in zprivs_state.caps */ if (op == ZPRIVS_RAISE) - priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps); + privset = zprivs_state.syscaps_p; else if (op == ZPRIVS_LOWER) - priv_emptyset (zprivs_state.caps); + privset = zprivs_state.caps; else return -1; - if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0) + if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0) return -1; return 0; @@ -423,15 +451,15 @@ zprivs_state_caps (void) } else { - if (priv_isemptyset (effective) == B_TRUE) + if (priv_isequalset (effective, zprivs_state.syscaps_p)) + result = ZPRIVS_RAISED; + else if (priv_isequalset (effective, zprivs_state.caps)) result = ZPRIVS_LOWERED; else - result = ZPRIVS_RAISED; + result = ZPRIVS_UNKNOWN; } - if (effective) - priv_freeset (effective); - + priv_freeset (effective); return result; } @@ -439,7 +467,7 @@ static void zprivs_caps_init (struct zebra_privs_t *zprivs) { pset_t *basic; - pset_t *empty; + pset_t *minimal; /* the specified sets */ zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); @@ -467,14 +495,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) priv_union (basic, zprivs_state.syscaps_p); priv_freeset (basic); - /* we need an empty set for 'effective', potentially for inheritable too */ - if ( (empty = priv_allocset()) == NULL) - { - fprintf (stderr, "%s: couldn't get empty set!\n", __func__); - exit (1); - } - priv_emptyset (empty); - /* Hey kernel, we know about privileges! * this isn't strictly required, use of setppriv should have same effect */ @@ -517,16 +537,19 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) exit (1); } - /* now clear the effective set and we're ready to go */ - if (setppriv (PRIV_SET, PRIV_EFFECTIVE, empty)) + /* we need a minimal basic set for 'effective', potentially for inheritable too */ + minimal = zprivs_caps_minimal(); + + /* now set the effective set with a subset of basic privileges */ + if (setppriv (PRIV_SET, PRIV_EFFECTIVE, minimal)) { fprintf (stderr, "%s: error setting effective set!, %s\n", __func__, safe_strerror (errno) ); exit (1); } - /* we'll use this as our working-storage privset */ - zprivs_state.caps = empty; + /* we'll use the minimal set as our working-storage privset */ + zprivs_state.caps = minimal; /* set methods for the caller to use */ zprivs->change = zprivs_change_caps; @@ -538,8 +561,7 @@ zprivs_caps_terminate (void) { assert (zprivs_state.caps); - /* clear all capabilities */ - priv_emptyset (zprivs_state.caps); + /* clear all capabilities by using working-storage privset */ setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps); setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps); setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps); From b7cce958649775600458f2fb3a8d33fc84683d26 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 7 Mar 2015 08:40:48 +0100 Subject: [PATCH 0633/1342] zebra: don't print uninitialized string (3b02fe8) This crept in as part of the MRIB improvements and I missed the compiler warning between other noise. Unfortunately, printing an uninitialised variable can in fact make zebra crash, so this is not trivial. Fixes: 3b02fe8 ("zebra: add "show ip rpf" to get result of RPF lookup") Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 598b40de9..1e39ebdd0 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -702,7 +702,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) RNODE_FOREACH_RIB (rn, rib) { - const char *mcast_info; + const char *mcast_info = ""; if (mcast) { rib_table_info_t *info = rn->table->info; From ec62e1438ece9af0546f9028aa1403f2c84bf177 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 7 Mar 2015 08:40:56 +0100 Subject: [PATCH 0634/1342] build: list actual release procedure As in a few other places in HACKING.tex, the text doesn't quite reflect reality. Add the actual release procedure including a few more steps, and warn about autoconf's subdirectory behaviour. Signed-off-by: David Lamparter --- HACKING.tex | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/HACKING.tex b/HACKING.tex index 54931d121..6b27ebfb9 100644 --- a/HACKING.tex +++ b/HACKING.tex @@ -308,16 +308,36 @@ \section{RELEASE PROCEDURE} build: \begin{verbatim} - git-clone git:///code.quagga.net/quagga.git quagga - git-archive --remote=git://code.quagga.net/quagga.git \ - --prefix=quagga-release/ master | tar -xf - - cd quagga-release + vim configure.ac + git commit -m "release: 0.99.99.99" + git tag -u 54CD2E60 quagga-0.99.99.99 + git push savannah tag quagga-0.99.99.99 + + git archive --prefix=quagga-release/ quagga-0.99.99.99 | tar xC /tmp + git log quagga-0.99.99.98..quagga-0.99.99.99 > \ + /tmp/quagga-release/quagga-0.99.99.99.changelog.txt + cd /tmp/quagga-release autoreconf -i ./configure make - make dist + make dist-gzip + + gunzip < quagga-0.99.99.99.tar.gz > quagga-0.99.99.99.tar + xz -6e < quagga-0.99.99.99.tar > quagga-0.99.99.99.tar.xz + gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar + + scp quagga-0.99.99.99.* username@dl.sv.nongnu.org:/releases/quagga \end{verbatim} + + Do NOT do this in a subdirectory of the Quagga sources, autoconf will think + it's a sub-package and fail to include neccessary files. + +\item Add the version number on https://bugzilla.quagga.net/, under + Administration, Products, "Quagga", Edit versions, Add a version. +\item Edit the wiki on https://wiki.quagga.net/wiki/index.php/Release\_status +\item Post a news entry on Savannah +\item Send a mail to quagga-dev and quagga-users \end{itemize} The tarball which `make dist' creates is the tarball to be released! The From 941789e470199df4f612368f669ecc0fd096fb9a Mon Sep 17 00:00:00 2001 From: Greg Troxel Date: Mon, 23 Mar 2015 15:16:29 -0400 Subject: [PATCH 0635/1342] Fix alignment assumptions on non-RT_ROUNDUP platforms. The comment said that apple uses int and BSD traditionally used long, but the code was backwards. This fixes apple to be int, and otherwise long. That should make FreeBSD, which aligns to long, work correctly, even without using SA_SIZE. --- zebra/kernel_socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 1518c1ab4..75534916a 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -78,9 +78,9 @@ extern struct zebra_t zebrad; /* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */ #ifdef __APPLE__ -#define ROUNDUP_TYPE long -#else #define ROUNDUP_TYPE int +#else +#define ROUNDUP_TYPE long #endif #define ROUNDUP(a) \ From aa7dbb1067b7d02e1354fe1e5664ccb7d259d649 Mon Sep 17 00:00:00 2001 From: Balaji Date: Mon, 16 Mar 2015 16:55:26 +0000 Subject: [PATCH 0636/1342] bgpd: Configured suppress value cannot be less than the reuse value in bgp dampening RFC 2439, Section 4.2; the values pair up for hysteresis. Signed-off-by: Balaji.G Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e7357e544..f84a72dca 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -11976,6 +11976,14 @@ DEFUN (bgp_damp_set, } bgp = vty->index; + + if (suppress < reuse) + { + vty_out (vty, "Suppress value cannot be less than reuse value %s", + VTY_NEWLINE); + return 0; + } + return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty), half, reuse, suppress, max); } From 06bd420d4646333bc7ed9964e348f19a942fcfe2 Mon Sep 17 00:00:00 2001 From: Balaji Date: Mon, 16 Mar 2015 16:55:29 +0000 Subject: [PATCH 0637/1342] bgpd: Display of configured dampening parameters Function to display configured bgp dampening parameters. Signed-off-by: Balaji.G [DL: formatting adjustments] Signed-off-by: David Lamparter --- bgpd/bgp_damp.c | 33 +++++++++++++++++++++++++++++++++ bgpd/bgp_damp.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 0ffafb7a0..dd6c759f1 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -639,3 +639,36 @@ bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo, return bgp_get_reuse_time (penalty, timebuf, len); } + +int +bgp_show_dampening_parameters (struct vty *vty, afi_t afi, safi_t safi) +{ + struct bgp *bgp; + bgp = bgp_get_default(); + + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + { + vty_out (vty, "Half-life time: %ld min%s", + damp->half_life / 60, VTY_NEWLINE); + vty_out (vty, "Reuse penalty: %d%s", + damp->reuse_limit, VTY_NEWLINE); + vty_out (vty, "Suppress penalty: %d%s", + damp->suppress_value, VTY_NEWLINE); + vty_out (vty, "Max suppress time: %ld min%s", + damp->max_suppress_time / 60, VTY_NEWLINE); + vty_out (vty, "Max supress penalty: %u%s", + damp->ceiling, VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + } + else + vty_out (vty, "dampening not enabled for %s%s", + afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); + + return CMD_SUCCESS; +} diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h index e1d319b56..16fd36715 100644 --- a/bgpd/bgp_damp.h +++ b/bgpd/bgp_damp.h @@ -144,4 +144,6 @@ extern void bgp_damp_info_vty (struct vty *, struct bgp_info *); extern const char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *, char *, size_t); +extern int bgp_show_dampening_parameters (struct vty *vty, afi_t, safi_t); + #endif /* _QUAGGA_BGP_DAMP_H */ From ef008d2f8dc8f7160d8a3d24a15f2fad79ef3242 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:48:11 +0100 Subject: [PATCH 0638/1342] *: use long long to print time_t Since we can't assume time_t to be long, int, or even long long, this consistently uses %lld/long long (or %llu/unsigned long long in a few cases) to print time_t/susecond_t values. This should fix a bunch of warnings, on NetBSD in particular. (Unfortunately, there seems to be no "PRId64" style printing macro for time_t...) Signed-off-by: David Lamparter --- babeld/babeld.c | 4 ++-- bgpd/bgp_damp.c | 10 +++++----- isisd/isis_adjacency.c | 3 ++- isisd/isis_spf.c | 9 +++++---- isisd/isisd.c | 4 ++-- ospf6d/ospf6_spf.c | 9 +++++---- ospf6d/ospf6_top.c | 5 +++-- ospf6d/ospf6d.h | 26 +++++++++++++------------- ospfd/ospf_ase.c | 4 ++-- ospfd/ospf_dump.c | 8 ++++---- watchquagga/watchquagga.c | 10 ++++++---- 11 files changed, 49 insertions(+), 43 deletions(-) diff --git a/babeld/babeld.c b/babeld/babeld.c index 1ae3f042c..eaa91b74c 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -328,8 +328,8 @@ babel_main_loop(struct thread *thread) /* if there is no timeout, we must wait. */ if(timeval_compare(&tv, &babel_now) > 0) { timeval_minus(&tv, &tv, &babel_now); - debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs", - tv.tv_sec * 1000 + tv.tv_usec / 1000); + debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs", + tv.tv_sec * 1000LL + tv.tv_usec / 1000LL); /* it happens often to have less than 1 ms, it's bad. */ timeval_add_msec(&tv, &tv, 300); babel_set_timer(&tv); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 0ffafb7a0..1da1e6968 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -529,15 +529,15 @@ bgp_config_write_damp (struct vty *vty) && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) - vty_out (vty, " bgp dampening %ld%s", - bgp_damp_cfg.half_life/60, + vty_out (vty, " bgp dampening %lld%s", + bgp_damp_cfg.half_life/60LL, VTY_NEWLINE); else - vty_out (vty, " bgp dampening %ld %d %d %ld%s", - bgp_damp_cfg.half_life/60, + vty_out (vty, " bgp dampening %lld %d %d %lld%s", + bgp_damp_cfg.half_life/60LL, bgp_damp_cfg.reuse_limit, bgp_damp_cfg.suppress_value, - bgp_damp_cfg.max_suppress_time/60, + bgp_damp_cfg.max_suppress_time/60LL, VTY_NEWLINE); } diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 414885fc4..a3524362e 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -396,7 +396,8 @@ isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail) vty_out (vty, "%-13s", adj_state2string (adj->adj_state)); now = time (NULL); if (adj->last_upd) - vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now); + vty_out (vty, "%-9llu", + (unsigned long long)adj->last_upd + adj->hold_time - now); else vty_out (vty, "- "); vty_out (vty, "%-10s", snpa_print (adj->snpa)); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index fd93efa65..a4cbba6bf 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1456,8 +1456,8 @@ isis_spf_schedule6 (struct isis_area *area, int level) assert (area->is_type & level); if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", - area->area_tag, level, diff); + zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago", + area->area_tag, level, (long long)diff); if (spftree->pending) return ISIS_OK; @@ -1476,8 +1476,9 @@ isis_spf_schedule6 (struct isis_area *area, int level) area->min_spf_interval[1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) - zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", - area->area_tag, level, area->min_spf_interval[level-1] - diff); + zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now", + area->area_tag, level, + (long long)(area->min_spf_interval[level-1] - diff)); spftree->pending = 1; diff --git a/isisd/isisd.c b/isisd/isisd.c index ce6a26214..24315572f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1297,8 +1297,8 @@ DEFUN (show_isis_summary, vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); - vty_out (vty, " last run duration : %u msec%s", - spftree->last_run_duration, VTY_NEWLINE); + vty_out (vty, " last run duration : %llu msec%s", + (unsigned long long)spftree->last_run_duration, VTY_NEWLINE); vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index d0e9101b8..47a655c17 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -601,11 +601,12 @@ ospf6_spf_calculation_thread (struct thread *t) ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf)); if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) - zlog_debug ("SPF runtime: %ld sec %ld usec", - runtime.tv_sec, runtime.tv_usec); + zlog_debug ("SPF runtime: %lld sec %lld usec", + (long long)runtime.tv_sec, (long long)runtime.tv_usec); - zlog_info("SPF processing: # Areas: %d, SPF runtime: %ld sec %ld usec, " - "Reason: %s\n", areas_processed, runtime.tv_sec, runtime.tv_usec, + zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, " + "Reason: %s\n", areas_processed, + (long long)runtime.tv_sec, (long long)runtime.tv_usec, rbuf); ospf6->last_spf_reason = ospf6->spf_reason; ospf6_reset_spf_reason(ospf6); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index e4e6f17a2..7fffba83d 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -663,8 +663,9 @@ ospf6_show (struct vty *vty, struct ospf6 *o) timerstring(&result, buf, sizeof(buf)); ospf6_spf_reason_string(o->last_spf_reason, rbuf, sizeof(rbuf)); vty_out(vty, "last executed %s ago, reason %s%s", buf, rbuf, VNL); - vty_out (vty, " Last SPF duration %ld sec %ld usec%s", - o->ts_spf_duration.tv_sec, o->ts_spf_duration.tv_usec, VNL); + vty_out (vty, " Last SPF duration %lld sec %lld usec%s", + (long long)o->ts_spf_duration.tv_sec, + (long long)o->ts_spf_duration.tv_usec, VNL); } else vty_out(vty, "has not been run$%s", VNL); diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 4122b3093..9e2efb41d 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -71,19 +71,19 @@ extern struct thread_master *master; } \ } while (0) #endif /*timersub*/ -#define timerstring(tv, buf, size) \ - do { \ - if ((tv)->tv_sec / 60 / 60 / 24) \ - snprintf (buf, size, "%ldd%02ld:%02ld:%02ld", \ - (tv)->tv_sec / 60 / 60 / 24, \ - (tv)->tv_sec / 60 / 60 % 24, \ - (tv)->tv_sec / 60 % 60, \ - (tv)->tv_sec % 60); \ - else \ - snprintf (buf, size, "%02ld:%02ld:%02ld", \ - (tv)->tv_sec / 60 / 60 % 24, \ - (tv)->tv_sec / 60 % 60, \ - (tv)->tv_sec % 60); \ +#define timerstring(tv, buf, size) \ + do { \ + if ((tv)->tv_sec / 60 / 60 / 24) \ + snprintf (buf, size, "%lldd%02lld:%02lld:%02lld", \ + (tv)->tv_sec / 60LL / 60 / 24, \ + (tv)->tv_sec / 60LL / 60 % 24, \ + (tv)->tv_sec / 60LL % 60, \ + (tv)->tv_sec % 60LL); \ + else \ + snprintf (buf, size, "%02lld:%02lld:%02lld", \ + (tv)->tv_sec / 60LL / 60 % 24, \ + (tv)->tv_sec / 60LL % 60, \ + (tv)->tv_sec % 60LL); \ } while (0) #define timerstring_local(tv, buf, size) \ do { \ diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 8aedc8088..04240c15a 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -679,8 +679,8 @@ ospf_ase_calculate_timer (struct thread *t) quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time); - zlog_info ("SPF Processing Time(usecs): External Routes: %ld\n", - (stop_time.tv_sec - start_time.tv_sec)*1000000L+ + zlog_info ("SPF Processing Time(usecs): External Routes: %lld\n", + (stop_time.tv_sec - start_time.tv_sec)*1000000LL+ (stop_time.tv_usec - start_time.tv_usec)); } return 0; diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index ebcc717ff..2e4e69dc1 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -299,13 +299,13 @@ ospf_timeval_dump (struct timeval *t, char *buf, size_t size) else if (d) snprintf (buf, size, "%1ldd%02ldh%02ldm", d, h, m); else if (h) - snprintf (buf, size, "%ldh%02ldm%02lds", h, m, t->tv_sec); + snprintf (buf, size, "%ldh%02ldm%02lds", h, m, (long)t->tv_sec); else if (m) - snprintf (buf, size, "%ldm%02lds", m, t->tv_sec); + snprintf (buf, size, "%ldm%02lds", m, (long)t->tv_sec); else if (ms) - snprintf (buf, size, "%ld.%03lds", t->tv_sec, ms); + snprintf (buf, size, "%ld.%03lds", (long)t->tv_sec, ms); else - snprintf (buf, size, "%ld usecs", t->tv_usec); + snprintf (buf, size, "%ld usecs", (long)t->tv_usec); return buf; } diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index c1c889210..c34816c21 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -381,7 +381,7 @@ restart_kill(struct thread *t_kill) time_elapsed(&delay,&restart->time); zlog_warn("Warning: %s %s child process %d still running after " "%ld seconds, sending signal %d", - restart->what,restart->name,(int)restart->pid,delay.tv_sec, + restart->what,restart->name,(int)restart->pid, (long)delay.tv_sec, (restart->kills ? SIGKILL : SIGTERM)); kill(-restart->pid,(restart->kills ? SIGKILL : SIGTERM)); restart->kills++; @@ -654,15 +654,17 @@ handle_read(struct thread *t_read) { dmn->state = DAEMON_UP; zlog_warn("%s state -> up : echo response received after %ld.%06ld " - "seconds", dmn->name,delay.tv_sec,delay.tv_usec); + "seconds", dmn->name, + (long)delay.tv_sec, (long)delay.tv_usec); } else zlog_warn("%s: slow echo response finally received after %ld.%06ld " - "seconds", dmn->name,delay.tv_sec,delay.tv_usec); + "seconds", dmn->name, + (long)delay.tv_sec, (long)delay.tv_usec); } else if (gs.loglevel > LOG_DEBUG+1) zlog_debug("%s: echo response received after %ld.%06ld seconds", - dmn->name,delay.tv_sec,delay.tv_usec); + dmn->name, (long)delay.tv_sec, (long)delay.tv_usec); SET_READ_HANDLER(dmn); if (dmn->t_wakeup) From eed3c48d3a7d2dae2cae2f2f250deffb843754a6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:51:53 +0100 Subject: [PATCH 0639/1342] *: use void * for printing pointers On higher warning levels, compilers expect %p printf arguments to be void *. Since format string / argument warnings can be useful otherwise, let's get rid of this noise by sprinkling casts to void * over printf calls. Signed-off-by: David Lamparter --- bgpd/bgp_aspath.c | 2 +- bgpd/bgp_vty.c | 2 +- isisd/isis_spf.c | 4 ++-- lib/buffer.c | 3 ++- lib/stream.c | 2 +- lib/zclient.c | 2 +- ospf6d/ospf6_intra.c | 7 +++--- ospf6d/ospf6_lsa.c | 2 +- ospf6d/ospf6_route.c | 29 +++++++++++++---------- ospf6d/ospf6_spf.c | 2 +- ospfd/ospf_apiserver.c | 16 ++++++++----- ospfd/ospf_flood.c | 5 ++-- ospfd/ospf_lsa.c | 42 ++++++++++++++++---------------- ospfd/ospf_lsdb.c | 2 +- ospfd/ospf_packet.c | 7 +++--- ospfd/ospf_spf.c | 4 ++-- ospfd/ospf_te.c | 2 +- zebra/zebra_rib.c | 54 +++++++++++++++++++++++------------------- 18 files changed, 103 insertions(+), 84 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index cfa9bc145..191a9e7bb 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1913,7 +1913,7 @@ aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) as = (struct aspath *) backet->data; - vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt); + vty_out (vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt); vty_out (vty, "%s%s", as->str, VTY_NEWLINE); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e6a36605f..00d766d61 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8235,7 +8235,7 @@ community_show_all_iterator (struct hash_backet *backet, struct vty *vty) struct community *com; com = (struct community *) backet->data; - vty_out (vty, "[%p] (%ld) %s%s", backet, com->refcnt, + vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, com->refcnt, community_str (com), VTY_NEWLINE); } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index a4cbba6bf..28525ce6a 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1072,8 +1072,8 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level, { zlog_warn ("ISIS-Spf: No lsp (%p) found from root " "to L%d DR %s on %s (ID %d)", - lsp, level, rawlspid_print (lsp_id), - circuit->interface->name, circuit->circuit_id); + (void *)lsp, level, rawlspid_print (lsp_id), + circuit->interface->name, circuit->circuit_id); continue; } isis_spf_process_pseudo_lsp (spftree, lsp, diff --git a/lib/buffer.c b/lib/buffer.c index 45e2e1c50..b689549ed 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -322,7 +322,8 @@ buffer_flush_window (struct buffer *b, int fd, int width, int height, /* This should absolutely never occur. */ zlog_err("%s: corruption detected: iov_small overflowed; " "head %p, tail %p, head->next %p", - __func__, b->head, b->tail, b->head->next); + __func__, (void *)b->head, (void *)b->tail, + (void *)b->head->next); iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov)); memcpy(iov, small_iov, sizeof(small_iov)); } diff --git a/lib/stream.c b/lib/stream.c index c6f20c85b..e13da08bc 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -53,7 +53,7 @@ */ #define STREAM_WARN_OFFSETS(S) \ zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \ - (S), \ + (void *)(S), \ (unsigned long) (S)->size, \ (unsigned long) (S)->getp, \ (unsigned long) (S)->endp)\ diff --git a/lib/zclient.c b/lib/zclient.c index 41ecbb61d..963c7052d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -919,7 +919,7 @@ zclient_read (struct thread *thread) length -= ZEBRA_HEADER_SIZE; if (zclient_debug) - zlog_debug("zclient 0x%p command 0x%x \n", zclient, command); + zlog_debug("zclient 0x%p command 0x%x \n", (void *)zclient, command); switch (command) { diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 4ad7521e9..1ef0b5355 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1495,7 +1495,8 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter) zlog_info ("Brouter: %s via area %s", brouter_name, area_name); zlog_info (" memory: prev: %p this: %p next: %p parent rnode: %p", - brouter->prev, brouter, brouter->next, brouter->rnode); + (void *)brouter->prev, (void *)brouter, (void *)brouter->next, + (void *)brouter->rnode); zlog_info (" type: %d prefix: %s installed: %s changed: %s", brouter->type, destination, installed, changed); zlog_info (" lock: %d flags: %s%s%s%s", brouter->lock, @@ -1543,7 +1544,7 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) IS_OSPF6_DEBUG_ROUTE (MEMORY)) { zlog_info ("%p: mark as removing: area %s brouter %s", - brouter, oa->name, brouter_name); + (void *)brouter, oa->name, brouter_name); ospf6_brouter_debug_print (brouter); } } @@ -1575,7 +1576,7 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) IS_OSPF6_DEBUG_ROUTE (MEMORY)) { zlog_info ("%p: transfer: area %s brouter %s", - brouter, oa->name, brouter_name); + (void *)brouter, oa->name, brouter_name); ospf6_brouter_debug_print (brouter); } } diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 8eeb99595..b4348f466 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -494,7 +494,7 @@ ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) vty_out (vty, "Lock: %d %s", lsa->lock, VNL); vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); vty_out (vty, "Threads: Expire: 0x%p, Refresh: 0x%p %s", - lsa->expire, lsa->refresh, VNL); + (void *)lsa->expire, (void *)lsa->refresh, VNL); vty_out (vty, "%s", VNL); return; } diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 9e6b33e54..30927737a 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -374,7 +374,7 @@ ospf6_route_add (struct ospf6_route *route, if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table), - table, route, buf); + (void *)table, (void *)route, buf); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf); @@ -408,7 +408,8 @@ ospf6_route_add (struct ospf6_route *route, { if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: needless update of %p", - ospf6_route_table_name (table), table, route, old); + ospf6_route_table_name (table), + (void *)table, (void *)route, (void *)old); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: needless update", ospf6_route_table_name (table)); @@ -422,7 +423,8 @@ ospf6_route_add (struct ospf6_route *route, if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: update of %p", - ospf6_route_table_name (table), table, route, old); + ospf6_route_table_name (table), + (void *)table, (void *)route, (void *)old); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: update", ospf6_route_table_name (table)); @@ -463,7 +465,8 @@ ospf6_route_add (struct ospf6_route *route, { if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: another path: prev %p, next %p", - ospf6_route_table_name (table), table, route, prev, next); + ospf6_route_table_name (table), + (void *)table, (void *)route, (void *)prev, (void *)next); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: another path found", ospf6_route_table_name (table)); @@ -488,7 +491,8 @@ ospf6_route_add (struct ospf6_route *route, SET_FLAG (route->flag, OSPF6_ROUTE_BEST); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route add %p: replacing previous best: %p", - ospf6_route_table_name (table), table, route, next); + ospf6_route_table_name (table), + (void *)table, (void *)route, (void *)next); } route->installed = now; @@ -510,7 +514,7 @@ ospf6_route_add (struct ospf6_route *route, /* Else, this is the brand new route regarding to the prefix */ if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: brand new route", - ospf6_route_table_name (table), table, route); + ospf6_route_table_name (table), (void *)table, (void *)route); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: brand new route", ospf6_route_table_name (table)); @@ -589,7 +593,8 @@ ospf6_route_remove (struct ospf6_route *route, if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route remove %p: %s", - ospf6_route_table_name (table), table, route, buf); + ospf6_route_table_name (table), + (void *)table, (void *)route, buf); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), buf); @@ -661,8 +666,8 @@ ospf6_route_head (struct ospf6_route_table *table) if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route head: %p<-[%p]->%p", - ospf6_route_table_name (table), table, - route->prev, route, route->next); + ospf6_route_table_name (table), (void *)table, + (void *)route->prev, (void *)route, (void *)route->next); return route; } @@ -674,8 +679,8 @@ ospf6_route_next (struct ospf6_route *route) if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route next: %p<-[%p]->%p", - ospf6_route_table_name (route->table), route->table, - route->prev, route, route->next); + ospf6_route_table_name (route->table), (void *)route->table, + (void *)route->prev, (void *)route, (void *)route->next); ospf6_route_unlock (route); if (next) @@ -874,7 +879,7 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"), VNL); vty_out (vty, "Memory: prev: %p this: %p next: %p%s", - route->prev, route, route->next, VNL); + (void *)route->prev, (void *)route, (void *)route->next, VNL); /* Path section */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 47a655c17..88e128536 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -639,7 +639,7 @@ ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason) { if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF: calculation timer is already scheduled: %p", - ospf6->t_spf_calc); + (void *)ospf6->t_spf_calc); return; } diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index db1ccda72..92f68f75f 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -244,7 +244,8 @@ static int ospf_apiserver_new_lsa_hook (struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("API: Put LSA(%p)[%s] into reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total); + zlog_debug ("API: Put LSA(%p)[%s] into reserve, total=%ld", (void *)lsa, + dump_lsa_key (lsa), lsa->lsdb->total); return 0; } @@ -252,7 +253,8 @@ static int ospf_apiserver_del_lsa_hook (struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("API: Get LSA(%p)[%s] from reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total); + zlog_debug ("API: Get LSA(%p)[%s] from reserve, total=%ld", (void *)lsa, + dump_lsa_key (lsa), lsa->lsdb->total); return 0; } @@ -395,7 +397,8 @@ ospf_apiserver_free (struct ospf_apiserver *apiserv) listnode_delete (apiserver_list, apiserv); if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("API: Delete apiserv(%p), total#(%d)", apiserv, apiserver_list->count); + zlog_debug ("API: Delete apiserv(%p), total#(%d)", + (void *)apiserv, apiserver_list->count); /* And free instance. */ XFREE (MTYPE_OSPF_APISERVER, apiserv); @@ -755,7 +758,8 @@ ospf_apiserver_accept (struct thread *thread) #endif /* USE_ASYNC_READ */ if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("API: New apiserv(%p), total#(%d)", apiserv, apiserver_list->count); + zlog_debug ("API: New apiserv(%p), total#(%d)", + (void *)apiserv, apiserver_list->count); return 0; } @@ -944,7 +948,7 @@ ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserv, if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Add LSA-type(%d)/Opaque-type(%d) into" " apiserv(%p), total#(%d)", - lsa_type, opaque_type, apiserv, + lsa_type, opaque_type, (void *)apiserv, listcount (apiserv->opaque_types)); return 0; @@ -976,7 +980,7 @@ ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserv, if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Del LSA-type(%d)/Opaque-type(%d)" " from apiserv(%p), total#(%d)", - lsa_type, opaque_type, apiserv, + lsa_type, opaque_type, (void *)apiserv, listcount (apiserv->opaque_types)); return 0; diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index d18314a9d..c0b362285 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -244,7 +244,7 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, zlog_debug ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), - current, + (void *)current, dump_lsa_key (new)); lsa_ack_flag = 0; @@ -584,7 +584,8 @@ ospf_flood_through_area (struct ospf_area *area, * for the link on which the LSA has received. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi); + zlog_debug ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", + (void *)lsa->oi, (void *)oi); continue; } #endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 94c31c9f1..f032601a3 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -248,7 +248,7 @@ ospf_lsa_dup (struct ospf_lsa *lsa) new->refresh_list = -1; if (IS_DEBUG_OSPF (lsa, LSA)) - zlog_debug ("LSA: duplicated %p (new: %p)", lsa, new); + zlog_debug ("LSA: duplicated %p (new: %p)", (void *)lsa, (void *)new); return new; } @@ -260,7 +260,7 @@ ospf_lsa_free (struct ospf_lsa *lsa) assert (lsa->lock == 0); if (IS_DEBUG_OSPF (lsa, LSA)) - zlog_debug ("LSA: freed %p", lsa); + zlog_debug ("LSA: freed %p", (void *)lsa); /* Delete LSA data. */ if (lsa->data != NULL) @@ -336,7 +336,7 @@ ospf_lsa_data_free (struct lsa_header *lsah) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("LSA[Type%d:%s]: data freed %p", - lsah->type, inet_ntoa (lsah->id), lsah); + lsah->type, inet_ntoa (lsah->id), (void *)lsah); XFREE (MTYPE_OSPF_LSA_DATA, lsah); } @@ -888,7 +888,7 @@ ospf_router_lsa_originate (struct ospf_area *area) if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate router-LSA %p", - new->data->type, inet_ntoa (new->data->id), new); + new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } @@ -1123,7 +1123,7 @@ ospf_network_lsa_update (struct ospf_interface *oi) if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate network-LSA %p", - new->data->type, inet_ntoa (new->data->id), new); + new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } @@ -1300,7 +1300,7 @@ ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate summary-LSA %p", - new->data->type, inet_ntoa (new->data->id), new); + new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } @@ -1443,7 +1443,7 @@ ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p", - new->data->type, inet_ntoa (new->data->id), new); + new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } @@ -2075,7 +2075,7 @@ ospf_external_lsa_originate (struct ospf *ospf, struct external_info *ei) if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate AS-external-LSA %p", - new->data->type, inet_ntoa (new->data->id), new); + new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } @@ -2260,7 +2260,8 @@ ospf_external_lsa_refresh_default (struct ospf *ospf) if (lsa) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", lsa); + zlog_debug ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", + (void *)lsa); ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); } else @@ -2687,7 +2688,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, { zlog_debug ("ospf_lsa_install() Premature Aging " "lsa 0x%p, seqnum 0x%x", - lsa, ntohl(lsa->data->ls_seqnum)); + (void *)lsa, ntohl(lsa->data->ls_seqnum)); ospf_lsa_header_dump (lsa->data); } } @@ -2790,9 +2791,9 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, { if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("LSA[Type%d:%s]: Install LSA 0x%p, MaxAge", - new->data->type, - inet_ntoa (new->data->id), - lsa); + new->data->type, + inet_ntoa (new->data->id), + (void *)lsa); ospf_lsa_maxage (ospf, lsa); } @@ -2879,7 +2880,7 @@ ospf_maxage_lsa_remover (struct thread *thread) if (CHECK_FLAG (lsa->flags, OSPF_LSA_PREMATURE_AGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("originating new lsa for lsa 0x%p\n", lsa); + zlog_debug ("originating new lsa for lsa 0x%p\n", (void *)lsa); ospf_lsa_refresh (ospf, lsa); } @@ -2946,7 +2947,7 @@ ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list", - lsa->data->type, inet_ntoa (lsa->data->id), lsa); + lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa); return; } @@ -2961,7 +2962,8 @@ ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[%s]: found LSA (%p) in table for LSA %p %d", - dump_lsa_key (lsa), rn->info, lsa, lsa_prefix.prefixlen); + dump_lsa_key (lsa), rn->info, (void *)lsa, + lsa_prefix.prefixlen); route_unlock_node (rn); } else @@ -3691,7 +3693,7 @@ ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh:%s]: ospf_refresher_register_lsa(): " "setting refresh_list on lsa %p (slod %d)", - inet_ntoa (lsa->data->id), lsa, index); + inet_ntoa (lsa->data->id), (void *)lsa, index); } } @@ -3762,9 +3764,9 @@ ospf_lsa_refresh_walker (struct thread *t) { if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh:%s]: ospf_lsa_refresh_walker(): " - "refresh lsa %p (slot %d)", - inet_ntoa (lsa->data->id), lsa, i); - + "refresh lsa %p (slot %d)", + inet_ntoa (lsa->data->id), (void *)lsa, i); + assert (lsa->lock > 0); list_delete_node (refresh_list, node); lsa->refresh_list = -1; diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index f7cf60fd0..b92e7494a 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -158,7 +158,7 @@ ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) if (lsa) zlog_warn ("LSA[Type%d:%s]: LSA %p, lsa->lsdb %p", lsa->data->type, inet_ntoa (lsa->data->id), - lsa, lsa->lsdb); + (void *)lsa, (void *)lsa->lsdb); return; } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 98b1af3bf..b97e3a79b 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1681,7 +1681,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, if (IS_DEBUG_OSPF_EVENT) zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update", - lsa->data->type, inet_ntoa (lsa->data->id), lsa); + lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa); listnode_add (lsas, lsa); } @@ -1762,7 +1762,8 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, #define DISCARD_LSA(L,N) {\ if (IS_DEBUG_OSPF_EVENT) \ - zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \ + zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p" \ + " Type-%d", N, (void *)lsa, (int) lsa->data->type); \ ospf_lsa_discard (L); \ continue; } @@ -1947,7 +1948,7 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, ospf_lsa_flush_area(lsa,out_if->area); if(IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d", - lsa, (int) lsa->data->type); + (void *)lsa, (int) lsa->data->type); ospf_lsa_discard (lsa); Flag = 1; } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 1fe8ab4b4..6205b3e5f 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1014,7 +1014,7 @@ ospf_spf_dump (struct vertex *v, int i) for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) { zlog_debug (" nexthop %p %s %s", - parent->nexthop, + (void *)parent->nexthop, inet_ntoa (parent->nexthop->router), parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) : "NULL"); @@ -1444,7 +1444,7 @@ ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer is already scheduled: %p", - ospf->t_spf_calc); + (void *)ospf->t_spf_calc); return; } diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index c605ce68d..bcb89630a 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -556,7 +556,7 @@ ospf_mpls_te_new_if (struct interface *ifp) if (lookup_linkparams_by_ifp (ifp) != NULL) { - zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp); + zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", (void *)ifp); rc = 0; /* Do nothing here. */ goto out; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0750e6eb6..cc7f48fa5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -78,7 +78,7 @@ static vector vrf_vector; /* RPF lookup behaviour */ static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; -static void +static void __attribute__((format (printf, 4, 5))) _rnode_zlog(const char *_func, struct route_node *rn, int priority, const char *msgfmt, ...) { @@ -1394,8 +1394,9 @@ rib_process (struct route_node *rn) if (rib != fib) { if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "rn %p, removing rib %p", rn, rib); - rib_unlink (rn, rib); + rnode_debug (rn, "rn %p, removing rib %p", + (void *)rn, (void *)rib); + rib_unlink (rn, rib); } else del = rib; @@ -1466,7 +1467,7 @@ rib_process (struct route_node *rn) { if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Updating existing route, select %p, fib %p", - select, fib); + (void *)select, (void *)fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { if (info->safi == SAFI_UNICAST) @@ -1511,7 +1512,7 @@ rib_process (struct route_node *rn) if (fib) { if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Removing existing route, fib %p", fib); + rnode_debug (rn, "Removing existing route, fib %p", (void *)fib); if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "removing existing route"); @@ -1532,7 +1533,7 @@ rib_process (struct route_node *rn) if (select) { if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Adding route, select %p", select); + rnode_debug (rn, "Adding route, select %p", (void *)select); if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "new route selected"); @@ -1550,13 +1551,13 @@ rib_process (struct route_node *rn) if (del) { if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Deleting fib %p, rn %p", del, rn); + rnode_debug (rn, "Deleting fib %p, rn %p", (void *)del, (void *)rn); rib_unlink (rn, del); } end: if (IS_ZEBRA_DEBUG_RIB_Q) - rnode_debug (rn, "rn %p dequeued", rn); + rnode_debug (rn, "rn %p dequeued", (void *)rn); /* * Check if the dest can be deleted now. @@ -1651,7 +1652,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) { if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "rn %p is already queued in sub-queue %u", - rn, qindex); + (void *)rn, qindex); continue; } @@ -1662,7 +1663,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "queued rn %p into sub-queue %u", - rn, qindex); + (void *)rn, qindex); } } @@ -1676,7 +1677,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) if (!rnode_to_ribs (rn)) { zlog_debug ("%s: called for route_node (%p, %d) with no ribs", - __func__, rn, rn->lock); + __func__, (void *)rn, rn->lock); zlog_backtrace(LOG_DEBUG); return; } @@ -1706,7 +1707,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) rib_meta_queue_add (zebra->mq, rn); if (IS_ZEBRA_DEBUG_RIB_Q) - rnode_debug (rn, "rn %p queued", rn); + rnode_debug (rn, "rn %p queued", (void *)rn); return; } @@ -1807,7 +1808,7 @@ rib_link (struct route_node *rn, struct rib *rib) assert (rib && rn); if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "rn %p, rib %p", rn, rib); + rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); dest = rib_dest_from_rnode (rn); if (!dest) @@ -1840,7 +1841,7 @@ rib_addnode (struct route_node *rn, struct rib *rib) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "rn %p, un-removed rib %p", rn, rib); + rnode_debug (rn, "rn %p, un-removed rib %p", (void *)rn, (void *)rib); UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); return; @@ -1865,7 +1866,7 @@ rib_unlink (struct route_node *rn, struct rib *rib) assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "rn %p, rib %p", rn, rib); + rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); dest = rib_dest_from_rnode (rn); @@ -1889,7 +1890,7 @@ static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "rn %p, rib %p, removing", rn, rib); + rnode_debug (rn, "rn %p, rib %p, removing", (void *)rn, (void *)rib); SET_FLAG (rib->status, RIB_ENTRY_REMOVED); rib_queue_add (&zebrad, rn); } @@ -1983,14 +1984,16 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Link new rib to node.*/ if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib); + zlog_debug ("%s: calling rib_addnode (%p, %p)", + __func__, (void *)rn, (void *)rib); rib_addnode (rn, rib); /* Free implicit route.*/ if (same) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, rn, rib); + zlog_debug ("%s: calling rib_delnode (%p, %p)", + __func__, (void *)rn, (void *)rib); rib_delnode (rn, same); } @@ -2012,7 +2015,8 @@ void _rib_dump (const char * func, int recursing; inet_ntop (p->family, &p->u.prefix, straddr, INET6_ADDRSTRLEN); - zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr, p->prefixlen); + zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, (void *)rib, + straddr, p->prefixlen); zlog_debug ( "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", @@ -2097,8 +2101,8 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) ( "%s: rn %p, rib %p: %s, %s", __func__, - rn, - rib, + (void *)rn, + (void *)rib, (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") ); @@ -2210,7 +2214,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", - __func__, rn, rib); + __func__, (void *)rn, (void *)rib); rib_dump (p, rib); } @@ -2220,7 +2224,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", - __func__, rn, same); + __func__, (void *)rn, (void *)same); rib_dump (p, same); } rib_delnode (rn, same); @@ -2771,7 +2775,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", - __func__, rn, rib); + __func__, (void *)rn, (void *)rib); rib_dump (p, rib); } @@ -2781,7 +2785,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", - __func__, rn, same); + __func__, (void *)rn, (void *)same); rib_dump (p, same); } rib_delnode (rn, same); From b7d5021bfa161f797cbfb1e92bf5b94327fb1b71 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:53:18 +0100 Subject: [PATCH 0640/1342] *: remove stray extra semicolons Some places had extra semicolons where none belong. Remove them. Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 2 +- bgpd/bgp_table.h | 2 +- isisd/isisd.c | 8 ++++---- lib/table.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 857781fea..be3c2eec2 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3163,7 +3163,7 @@ ALIAS (set_aspath_prepend, "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" - "Number of times to insert"); + "Number of times to insert") DEFUN (no_set_aspath_prepend, no_set_aspath_prepend_cmd, diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 04a1d379e..209a18c92 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -55,7 +55,7 @@ struct bgp_node * @see bgp_node_to_rnode * @see bgp_node_from_rnode */ - ROUTE_NODE_FIELDS; + ROUTE_NODE_FIELDS struct bgp_adj_out *adj_out; diff --git a/isisd/isisd.c b/isisd/isisd.c index 24315572f..898dfd23d 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1601,7 +1601,7 @@ ALIAS (area_passwd_md5, "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n"); + "Send and check PDUs on receiving\n") DEFUN (area_passwd_clear, area_passwd_clear_cmd, @@ -1659,7 +1659,7 @@ ALIAS (area_passwd_clear, "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n"); + "Send and check PDUs on receiving\n") DEFUN (no_area_passwd, no_area_passwd_cmd, @@ -1739,7 +1739,7 @@ ALIAS (domain_passwd_md5, "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n"); + "Send and check PDUs on receiving\n") DEFUN (domain_passwd_clear, domain_passwd_clear_cmd, @@ -1797,7 +1797,7 @@ ALIAS (domain_passwd_clear, "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n"); + "Send and check PDUs on receiving\n") DEFUN (no_domain_passwd, no_domain_passwd_cmd, diff --git a/lib/table.h b/lib/table.h index ab357a074..ab7eb68ce 100644 --- a/lib/table.h +++ b/lib/table.h @@ -92,7 +92,7 @@ struct route_table /* Each routing entry. */ struct route_node { - ROUTE_NODE_FIELDS; + ROUTE_NODE_FIELDS #define l_left link[0] #define l_right link[1] From 21401f3215be26dcb0f787105f5907745498e966 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:55:26 +0100 Subject: [PATCH 0641/1342] *: fix signedness mix-ups Signed-off-by: David Lamparter --- bgpd/bgp_aspath.c | 2 +- isisd/isis_bpf.c | 7 ++++--- isisd/isis_lsp.c | 2 +- isisd/isis_pdu.c | 8 ++++---- isisd/isis_pfpacket.c | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 191a9e7bb..0aec3ef1c 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1378,7 +1378,7 @@ static struct aspath * aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) { struct assegment *assegment = aspath->segments; - int i; + unsigned i; if (assegment && assegment->type == type) { diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 4d5b16513..f6176ef70 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -301,13 +301,14 @@ int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { struct ether_header *eth; - int written, buflen; + ssize_t written; + size_t buflen; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN; if (buflen > sizeof (sock_buff)) { - zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than " - "output pdu size %d on circuit %s", + zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than " + "output pdu size %zu on circuit %s", sizeof (sock_buff), buflen, circuit->interface->name); return ISIS_WARNING; } diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index f2a7923d5..83dc604ce 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -379,7 +379,7 @@ lsp_auth_update (struct isis_lsp *lsp) /* Compute autentication value */ hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu), (unsigned char *) &passwd->passwd, passwd->len, - (caddr_t) &hmac_md5_hash); + (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 166dd7c09..557dc0102 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -204,7 +204,7 @@ authentication_check (struct isis_passwd *remote, struct isis_passwd *local, /* Compute the digest */ hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream), (unsigned char *) &(local->passwd), local->len, - (caddr_t) &digest); + (unsigned char *) &digest); /* Copy back the authentication value after the check */ memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3, remote->passwd, ISIS_AUTH_MD5_SIZE); @@ -2469,7 +2469,7 @@ send_hello (struct isis_circuit *circuit, int level) hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, - (caddr_t) &hmac_md5_hash); + (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); @@ -2656,7 +2656,7 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp(circuit->snd_stream), (unsigned char *) &passwd->passwd, passwd->len, - (caddr_t) &hmac_md5_hash); + (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); @@ -2992,7 +2992,7 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp(circuit->snd_stream), (unsigned char *) &passwd->passwd, passwd->len, - (caddr_t) &hmac_md5_hash); + (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 4bc8717a9..463f55967 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -54,8 +54,8 @@ u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; -static char discard_buff[8192]; -static char sock_buff[8192]; +static uint8_t discard_buff[8192]; +static uint8_t sock_buff[8192]; /* * if level is 0 we are joining p2p multicast From 388f8857eb81ef75014060976776523a58a99389 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:55:54 +0100 Subject: [PATCH 0642/1342] *: add missing includes Some places, particularly headers, were spewing warnings since they don't include neccessary other headers to get struct/enum definitions. Signed-off-by: David Lamparter --- isisd/isis_circuit.h | 2 ++ lib/distribute.h | 1 + lib/smux.h | 2 ++ ospf6d/ospf6_interface.c | 1 + ospf6d/ospf6_neighbor.c | 1 + ospf6d/ospf6_snmp.c | 2 ++ vtysh/vtysh_user.c | 1 + zebra/if_sysctl.c | 1 + 8 files changed, 11 insertions(+) diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 7ed481dc2..d86fee040 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -23,6 +23,8 @@ #ifndef ISIS_CIRCUIT_H #define ISIS_CIRCUIT_H +#include "vty.h" + #define CIRCUIT_MAX 255 struct password diff --git a/lib/distribute.h b/lib/distribute.h index 5072016fd..a2ffffd5f 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -24,6 +24,7 @@ #include #include "if.h" +#include "filter.h" /* Disctirubte list types. */ enum distribute_type diff --git a/lib/smux.h b/lib/smux.h index 72b4eaf09..02e963099 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -25,6 +25,8 @@ #include #include +#include "thread.h" + /* Structures here are mostly compatible with UCD SNMP 4.1.1 */ #define MATCH_FAILED (-1) #define MATCH_SUCCEEDED 0 diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 772caff7f..7c2d46fe0 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -40,6 +40,7 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_spf.h" +#include "ospf6_snmp.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_interface = 0; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index f20c83b9f..4e637970f 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -38,6 +38,7 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_flood.h" +#include "ospf6_snmp.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_neighbor = 0; diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 4be8be04b..5d10ce639 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -40,6 +40,8 @@ #include "ospf6_interface.h" #include "ospf6_message.h" #include "ospf6_neighbor.h" +#include "ospf6_abr.h" +#include "ospf6_asbr.h" #include "ospf6d.h" #include "ospf6_snmp.h" diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 58676c10c..8f2cf4220 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -37,6 +37,7 @@ #include "memory.h" #include "linklist.h" #include "command.h" +#include "vtysh_user.h" #ifdef USE_PAM static struct pam_conv conv = diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index 5e8099647..ffa6927d6 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -29,6 +29,7 @@ #include "memory.h" #include "ioctl.h" #include "log.h" +#include "interface.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" From ab90fc04a57b7b1d93ccddb8c9fbbf339a7ffc4c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:07:25 +0100 Subject: [PATCH 0643/1342] *: add/cleanup initialisers There were some (inconsequential) warnings about uninitialised use of variables. Also, in one case, sub-structs were mixed in initialisation, which doesn't quite work as intended. Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 2 +- lib/command.c | 2 +- ospfd/ospf_spf.c | 2 +- ripngd/ripngd.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index be3c2eec2..95f1dff40 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -131,7 +131,7 @@ route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { union sockunion *su; - union sockunion su_def = { .sa.sa_family = AF_INET, + union sockunion su_def = { .sin.sin_family = AF_INET, .sin.sin_addr.s_addr = INADDR_ANY }; struct peer_group *group; struct peer *peer; diff --git a/lib/command.c b/lib/command.c index 831778957..f20065f13 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1353,7 +1353,7 @@ cmd_matcher_match_multiple(struct cmd_matcher *matcher, enum match_type multiple_match; unsigned int multiple_index; const char *word; - const char *arg; + const char *arg = NULL; struct cmd_token *word_token; enum match_type word_match; diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 6205b3e5f..58a39921a 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -590,7 +590,7 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) { - struct in_addr nexthop; + struct in_addr nexthop = { .s_addr = 0 }; /* If the destination is a router which connects to the calculating router via a Point-to-MultiPoint diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 8c20a7a2b..82e381816 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -236,7 +236,7 @@ ripng_recv_packet (int sock, u_char *buf, int bufsize, struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; - struct in6_addr dst; + struct in6_addr dst = { .s6_addr = { 0 } }; /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this point I can't determine size of cmsghdr */ From b1672ce858cc9c16fd7cc67b673aa241d9583a59 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 19 Apr 2015 15:17:02 +0200 Subject: [PATCH 0644/1342] bgpd: fix ecommunity_token initialiser This pulls up ecommunity_token_unknown to be the first enum value (at 0), and uses that as initialiser to get rid of the uninitialised use warning. Signed-off-by: David Lamparter --- bgpd/bgp_ecommunity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 482e76b74..04957d41c 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -281,10 +281,10 @@ ecommunity_finish (void) /* Extended Communities token enum. */ enum ecommunity_token { + ecommunity_token_unknown = 0, ecommunity_token_rt, ecommunity_token_soo, ecommunity_token_val, - ecommunity_token_unknown }; /* Get next Extended Communities token from the string. */ @@ -511,7 +511,7 @@ struct ecommunity * ecommunity_str2com (const char *str, int type, int keyword_included) { struct ecommunity *ecom = NULL; - enum ecommunity_token token; + enum ecommunity_token token = ecommunity_token_unknown; struct ecommunity_val eval; int keyword = 0; From d43f8b39b075fe60e0c8fdb33b07b284d3fae503 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:54:54 +0100 Subject: [PATCH 0645/1342] bgpd, zebra: fix struct/pointer sizeof mixups Two places were taking sizeof(pointer) instead of the sizeof(struct), while performing operations on the struct. Both are initialisation functions; I guess we haven't seen fallout since they weren't critical. Fix anyway. [v2: fix mistake that actually broke bgpd RS workqueue init] Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 5 +++-- zebra/router-id.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e7357e544..cd2737c8b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1666,9 +1666,10 @@ bgp_process_queue_init (void) bm->process_main_queue->spec.max_retries = 0; bm->process_main_queue->spec.hold = 50; - memcpy (bm->process_rsclient_queue, bm->process_main_queue, - sizeof (struct work_queue *)); bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient; + bm->process_rsclient_queue->spec.del_item_data = &bgp_processq_del; + bm->process_rsclient_queue->spec.max_retries = 0; + bm->process_rsclient_queue->spec.hold = 50; } void diff --git a/zebra/router-id.c b/zebra/router-id.c index 94a294199..bfafc2727 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -245,8 +245,8 @@ router_id_init (void) install_element (CONFIG_NODE, &router_id_cmd); install_element (CONFIG_NODE, &no_router_id_cmd); - memset (rid_all_sorted_list, 0, sizeof (rid_all_sorted_list)); - memset (rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list)); + memset (rid_all_sorted_list, 0, sizeof (*rid_all_sorted_list)); + memset (rid_lo_sorted_list, 0, sizeof (*rid_lo_sorted_list)); memset (&rid_user_assigned, 0, sizeof (rid_user_assigned)); rid_all_sorted_list->cmp = router_id_cmp; From 94bad67cd8fe7ad023a40547a1153a414d70fa0a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:52:22 +0100 Subject: [PATCH 0646/1342] bgpd: don't use #ifdef inside macro args Using #ifdef inside preprocessor macro argument lists is not guaranteed to work. In reality it mostly does, but we don't need these ifdefs for HAVE_IPV6 anymore, so let's get rid of the warning nonetheless. Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 59 +----------------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cd2737c8b..1ea4d2169 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7906,19 +7906,13 @@ ALIAS (show_ip_bgp_ipv4_community, DEFUN (show_bgp_view_afi_safi_community_all, show_bgp_view_afi_safi_community_all_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", -#else - "show bgp view WORD ipv4 (unicast|multicast) community", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") @@ -7935,31 +7929,20 @@ DEFUN (show_bgp_view_afi_safi_community_all, return CMD_WARNING; } -#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; -#endif return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); } DEFUN (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -7971,32 +7954,20 @@ DEFUN (show_bgp_view_afi_safi_community, int afi; int safi; -#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); -#endif } ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community2_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -8011,19 +7982,13 @@ ALIAS (show_bgp_view_afi_safi_community, ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community3_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -8042,19 +8007,13 @@ ALIAS (show_bgp_view_afi_safi_community, ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community4_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -10200,19 +10159,13 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", -#else - "show bgp view WORD ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" @@ -10226,24 +10179,14 @@ DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, int in; struct peer *peer; -#ifdef HAVE_IPV6 - peer = peer_lookup_in_view (vty, argv[0], argv[3]); -#else - peer = peer_lookup_in_view (vty, argv[0], argv[2]); -#endif + peer = peer_lookup_in_view (vty, argv[0], argv[3]); if (! peer) return CMD_WARNING; -#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0; -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - in = (strncmp (argv[3], "r", 1) == 0) ? 1 : 0; -#endif return peer_adj_routes (vty, peer, afi, safi, in); } From 8c9cd85631b77fac0bc30ffb9f23b29c466d31c4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 19 Apr 2015 14:40:02 +0200 Subject: [PATCH 0647/1342] bgpd: random() returns long bgpd was using unsigned to store a probability value to be used with random(). That, however, returns long, running into some warnings (and worst case, if RAND_MAX > UINT_MAX, won't work correctly. Just use long to shuffle the value around. Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 95f1dff40..33f802c16 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -826,12 +826,12 @@ route_match_probability (void *rule, struct prefix *prefix, r = (long) rand(); #endif - switch (*(unsigned *) rule) + switch (*(long *) rule) { case 0: break; case RAND_MAX: return RMAP_MATCH; default: - if (r < *(unsigned *) rule) + if (r < *(long *) rule) { return RMAP_MATCH; } @@ -843,7 +843,7 @@ route_match_probability (void *rule, struct prefix *prefix, static void * route_match_probability_compile (const char *arg) { - unsigned *lobule; + long *lobule; unsigned perc; #if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 @@ -853,7 +853,7 @@ route_match_probability_compile (const char *arg) #endif perc = atoi (arg); - lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); + lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (long)); switch (perc) { From 1250dc7834a1ba52cfd5195f68d24f22fd9c41b0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:56:35 +0100 Subject: [PATCH 0648/1342] isisd: don't use POSIX reserved y1/yn names y1 and yn are POSIX standard names for Bessel functions. For consistency, just rename all of these variables from "y" to "yy". Signed-off-by: David Lamparter --- isisd/topology/spgrid.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/isisd/topology/spgrid.c b/isisd/topology/spgrid.c index 611b67279..40147fb5b 100644 --- a/isisd/topology/spgrid.c +++ b/isisd/topology/spgrid.c @@ -50,8 +50,8 @@ long X, /* horizontal size of grid */ long x, y, - y1, y2, yp, - dl, dx, xn, yn, count, + yy1, yy2, yyp, + dl, dx, xn, yyn, count, *mess; double n; @@ -670,12 +670,12 @@ gen_spgrid_topology (struct vty *vty, struct list *topology) for ( k = ax; k > 0; k -- ) { - y1 = nrand ( Y ); + yy1 = nrand ( Y ); do - y2 = nrand ( Y ); - while ( y2 == y1 ); - i = NODE ( x, y1 ); - j = NODE ( x, y2 ); + yy2 = nrand ( Y ); + while ( yy2 == yy1 ); + i = NODE ( x, yy1 ); + j = NODE ( x, yy2 ); l = am + nrand ( al ); print_arc (vty, topology, i, j, l ); } @@ -711,13 +711,13 @@ gen_spgrid_topology (struct vty *vty, struct list *topology) dx = xn - x; if ( ip_f ) { - yp = nrand(Y-y); - yn = mess[ yp ]; - mess[ yp ] = mess[ Y - y - 1 ]; + yyp = nrand(Y-y); + yyn = mess[ yyp ]; + mess[ yyp ] = mess[ Y - y - 1 ]; } else - yn = y; - j = NODE ( xn, yn ); + yyn = y; + j = NODE ( xn, yyn ); l = im + nrand ( il ); if ( in != 0 ) l *= (long) ( in * dx ); From 6db3ef65c7683069609b5ceb29bdaab49ca09f48 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:07:43 +0100 Subject: [PATCH 0649/1342] isisd: fix minor & vs. && mix-up apparently we were displaying all IPv6 reachabilities as external. Signed-off-by: David Lamparter --- isisd/isis_lsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 83dc604ce..4c09e7928 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -950,7 +950,7 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) memcpy (in6.s6_addr, ipv6_reach->prefix, PSIZE (ipv6_reach->prefix_len)); inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ); - if ((ipv6_reach->control_info && + if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s", ntohl (ipv6_reach->metric), From f50ee93d12f8213a048a04fcf7d73e12662288e5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 07:13:38 +0100 Subject: [PATCH 0650/1342] isisd: assorted fixes (unused variables, static) This just mops up a few warnings in isisd. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 1 - isisd/isis_lsp.c | 4 ++-- isisd/isis_pfpacket.c | 6 ++---- isisd/isis_tlv.c | 4 +--- isisd/isis_zebra.c | 6 +++--- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 3d9fb4739..4f7e2ce9c 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1342,7 +1342,6 @@ DEFUN (no_ipv6_router_isis, { struct interface *ifp; struct isis_area *area; - struct listnode *node; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 4c09e7928..88593de70 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -2396,7 +2396,7 @@ static int top_lsp_refresh (struct thread *thread) { struct isis_lsp *lsp; - u_int16_t rem_lifetime, refresh_time; + u_int16_t rem_lifetime; lsp = THREAD_ARG (thread); assert (lsp); @@ -2420,7 +2420,7 @@ top_lsp_refresh (struct thread *thread) rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); - refresh_time = lsp_refresh_time (lsp, rem_lifetime); + /* refresh_time = lsp_refresh_time (lsp, rem_lifetime); */ THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, lsp->area->lsp_refresh[0]); diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 463f55967..d20226458 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -323,7 +323,6 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) /* we need to do the LLC in here because of P2P circuits, which will * not need it */ - int written = 1; struct sockaddr_ll sa; stream_set_getp (circuit->snd_stream, 0); @@ -356,7 +355,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) iov[1].iov_base = circuit->snd_stream->data; iov[1].iov_len = stream_get_endp (circuit->snd_stream); - written = sendmsg (circuit->fd, &msg, 0); + sendmsg (circuit->fd, &msg, 0); return ISIS_OK; } @@ -364,7 +363,6 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { - int written = 1; struct sockaddr_ll sa; stream_set_getp (circuit->snd_stream, 0); @@ -381,7 +379,7 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level) /* lets try correcting the protocol */ sa.sll_protocol = htons (0x00FE); - written = sendto (circuit->fd, circuit->snd_stream->data, + sendto (circuit->fd, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream), 0, (struct sockaddr *) &sa, sizeof (struct sockaddr_ll)); diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index bbfa5d812..4fca072d9 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -115,7 +115,6 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, struct ipv6_reachability *ipv6_reach; int prefix_octets; #endif /* HAVE_IPV6 */ - u_char virtual; int value_len, retval = ISIS_OK; u_char *start = stream, *pnt = stream, *endpnt; @@ -179,7 +178,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, * | Virtual Flag | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ - virtual = *pnt; /* FIXME: what is the use for this? */ + /* virtual = *pnt; FIXME: what is the use for this? */ pnt++; value_len++; /* +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -926,7 +925,6 @@ tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream) struct prefix_ipv4 *ipv4; u_char value[255]; u_char *pos = value; - int retval; for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4)) { diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 2df746291..1ba0100d4 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -318,7 +318,7 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix, } #ifdef HAVE_IPV6 -void +static void isis_zebra_route_add_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { @@ -519,8 +519,8 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, struct stream *stream; struct zapi_ipv4 api; struct prefix_ipv4 p; - unsigned long ifindex; - struct in_addr nexthop; + unsigned long ifindex __attribute__ ((unused)); + struct in_addr nexthop __attribute__ ((unused)); stream = zclient->ibuf; memset (&p, 0, sizeof (struct prefix_ipv4)); From 01da6176b88fe59b3c6ceaf3630df88046c83159 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 10 Apr 2015 09:10:11 +0200 Subject: [PATCH 0651/1342] isisd: fix size_t confusions isisd had a few places that mixed up size_t vs. unsigned long, and %zd vs. %ld. Clean out. Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 557dc0102..2178d9551 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1264,7 +1264,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " - "cirID %u, length %ld", + "cirID %u, length %zd", circuit->area->area_tag, level, snpa_print (ssnpa), circuit->interface->name, circuit_t2string (circuit->is_type), @@ -2321,7 +2321,7 @@ send_hello (struct isis_circuit *circuit, int level) struct isis_lan_hello_hdr hello_hdr; struct isis_p2p_hello_hdr p2p_hello_hdr; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - unsigned long len_pointer, length, auth_tlv_offset = 0; + size_t len_pointer, length, auth_tlv_offset = 0; u_int32_t interval; int retval; @@ -2479,16 +2479,14 @@ send_hello (struct isis_circuit *circuit, int level) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld", + zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, - /* FIXME: use %z when we stop supporting old compilers. */ length); } else { - zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld", + zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %zd", circuit->area->area_tag, circuit->interface->name, - /* FIXME: use %z when we stop supporting old compilers. */ length); } if (isis->debugs & DEBUG_PACKET_DUMP) @@ -2801,7 +2799,7 @@ send_csnp (struct isis_circuit *circuit, int level) if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", + zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) @@ -3050,7 +3048,7 @@ send_psnp (int level, struct isis_circuit *circuit) if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld", + zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); From 60a4601e2270920958e221fbffd7b0743f498d3c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:56:05 +0100 Subject: [PATCH 0652/1342] isisd: remove unused process_is_hello() The code uses process_lan_hello() or process_p2p_hello(). The unused process_is_hello() seems to be a leftover generic version. Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 83 ------------------------------------------------ 1 file changed, 83 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 2178d9551..02b50bf48 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1974,89 +1974,6 @@ process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa) return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa); } -/* - * Process ISH - * ISO - 10589 - * Section 8.2.2 - Receiving ISH PDUs by an intermediate system - * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid - * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59 - * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00 - * 0x03 0x00 0x81 0x01 0xcc - */ -static int -process_is_hello (struct isis_circuit *circuit) -{ - struct isis_adjacency *adj; - int retval = ISIS_OK; - u_char neigh_len; - u_char *sysid; - - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string (circuit->is_type), circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->rcv_stream), - stream_get_endp (circuit->rcv_stream)); - } - - /* In this point in time we are not yet able to handle is_hellos - * on lan - Sorry juniper... - */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - return retval; - - neigh_len = stream_getc (circuit->rcv_stream); - sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN; - adj = circuit->u.p2p.neighbor; - if (!adj) - { - /* 8.2.2 */ - adj = isis_new_adj (sysid, NULL, 0, circuit); - if (adj == NULL) - return ISIS_ERROR; - - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - adj->sys_type = ISIS_SYSTYPE_UNKNOWN; - circuit->u.p2p.neighbor = adj; - } - /* 8.2.2 a) */ - if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid, - ISIS_SYS_ID_LEN)) - { - /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */ - /* 8.2.2 a) 2) delete the adj */ - XFREE (MTYPE_ISIS_ADJACENCY, adj); - /* 8.2.2 a) 3) create a new adj */ - adj = isis_new_adj (sysid, NULL, 0, circuit); - if (adj == NULL) - return ISIS_ERROR; - - /* 8.2.2 a) 3) i */ - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - /* 8.2.2 a) 3) ii */ - adj->sys_type = ISIS_SYSTYPE_UNKNOWN; - /* 8.2.2 a) 4) quite meaningless */ - } - /* 8.2.2 b) ignore on condition */ - if ((adj->adj_state == ISIS_ADJ_INITIALIZING) && - (adj->sys_type == ISIS_SYSTYPE_IS)) - { - /* do nothing */ - } - else - { - /* 8.2.2 c) respond with a p2p IIH */ - send_hello (circuit, 1); - } - /* 8.2.2 d) type is IS */ - adj->sys_type = ISIS_SYSTYPE_IS; - /* 8.2.2 e) FIXME: Circuit type of? */ - - return retval; -} - /* * PDU Dispatcher */ From 52f02b47685bc823c4c75560175a27aab0bd6709 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 10 Apr 2015 09:14:30 +0200 Subject: [PATCH 0653/1342] zebra, isisd: cast to unsigned char for ctypes ctype.h macros take int as arguments, but expect arguments to be in unsigned char's range. Even though it probably works, this isn't correct on systems that have a signed char type. Cast explicitly. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 2 +- zebra/rtadv.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 4f7e2ce9c..fdff819ca 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -397,7 +397,7 @@ isis_circuit_id_gen (struct interface *ifp) */ for (i = 0; i < strlen (ifp->name); i++) { - if (isdigit(ifp->name[i])) + if (isdigit((unsigned char)ifp->name[i])) { if (start < 0) { diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 21ca6da99..9a3fd265d 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -1201,7 +1201,8 @@ DEFUN (ipv6_nd_prefix, if (argc > 1) { - if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0) + if ((isdigit((unsigned char)argv[1][0])) + || strncmp (argv[1], "i", 1) == 0) { if ( strncmp (argv[1], "i", 1) == 0) rp.AdvValidLifetime = UINT32_MAX; From 872b0dc0537b62503d98bafd3075553795c847cb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:57:49 +0100 Subject: [PATCH 0654/1342] zebra: remove unused netlink_route()/kernel_rtm_ipv6() kernel_delete_ipv6_old(), removed in 51bdeba a little while ago, was the last user of netlink_route() and kernel_rtm_ipv6(). Everything else uses the _multipath variants of these functions. Signed-off-by: David Lamparter --- zebra/rt_netlink.c | 74 ---------------------------------------------- zebra/rt_socket.c | 61 -------------------------------------- 2 files changed, 135 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2350070c6..7e4107297 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1368,80 +1368,6 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) return netlink_parse_info (netlink_talk_filter, nl); } -/* Routing table change via netlink interface. */ -static int -netlink_route (int cmd, int family, void *dest, int length, void *gate, - int index, int zebra_flags, int table) -{ - int ret; - int bytelen; - struct sockaddr_nl snl; - int discard; - - struct - { - struct nlmsghdr n; - struct rtmsg r; - char buf[NL_PKT_BUF_SIZE]; - } req; - - memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); - - bytelen = (family == AF_INET ? 4 : 16); - - req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - req.n.nlmsg_type = cmd; - req.r.rtm_family = family; - req.r.rtm_table = table; - req.r.rtm_dst_len = length; - req.r.rtm_protocol = RTPROT_ZEBRA; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - - if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE) - || (zebra_flags & ZEBRA_FLAG_REJECT)) - discard = 1; - else - discard = 0; - - if (cmd == RTM_NEWROUTE) - { - if (discard) - { - if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) - req.r.rtm_type = RTN_BLACKHOLE; - else if (zebra_flags & ZEBRA_FLAG_REJECT) - req.r.rtm_type = RTN_UNREACHABLE; - else - assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ - } - else - req.r.rtm_type = RTN_UNICAST; - } - - if (dest) - addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); - - if (!discard) - { - if (gate) - addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen); - if (index > 0) - addattr32 (&req.n, sizeof req, RTA_OIF, index); - } - - /* Destination netlink address. */ - memset (&snl, 0, sizeof snl); - snl.nl_family = AF_NETLINK; - - /* Talk to netlink socket. */ - ret = netlink_talk (&req.n, &netlink_cmd); - if (ret < 0) - return -1; - - return 0; -} - /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 63470adcb..d8c947c67 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -269,67 +269,6 @@ sin6_masklen (struct in6_addr mask) return len; } -/* Interface between zebra message and rtm message. */ -static int -kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, - struct in6_addr *gate, int index, int flags) -{ - struct sockaddr_in6 *mask; - struct sockaddr_in6 sin_dest, sin_mask, sin_gate; - - memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); - sin_dest.sin6_family = AF_INET6; -#ifdef SIN6_LEN - sin_dest.sin6_len = sizeof (struct sockaddr_in6); -#endif /* SIN6_LEN */ - - memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); - - memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); - sin_gate.sin6_family = AF_INET6; -#ifdef SIN6_LEN - sin_gate.sin6_len = sizeof (struct sockaddr_in6); -#endif /* SIN6_LEN */ - - sin_dest.sin6_addr = dest->prefix; - - if (gate) - memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr)); - - /* Under kame set interface index to link local address. */ -#ifdef KAME - -#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ - do { \ - (a).s6_addr[2] = ((i) >> 8) & 0xff; \ - (a).s6_addr[3] = (i) & 0xff; \ - } while (0) - - if (gate && IN6_IS_ADDR_LINKLOCAL(gate)) - SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index); -#endif /* KAME */ - - if (gate && dest->prefixlen == 128) - mask = NULL; - else - { - masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr); - sin_mask.sin6_family = AF_INET6; -#ifdef SIN6_LEN - sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); -#endif /* SIN6_LEN */ - mask = &sin_mask; - } - - return rtm_write (message, - (union sockunion *) &sin_dest, - (union sockunion *) mask, - gate ? (union sockunion *)&sin_gate : NULL, - index, - flags, - 0); -} - /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, From 48ab06b43040bb27d267bb165eedf9e496eb865b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 07:05:39 +0100 Subject: [PATCH 0655/1342] zebra: use prototypes/includes in rt_netlink Signed-off-by: David Lamparter --- zebra/if_netlink.c | 5 ++--- zebra/rt_netlink.h | 3 +++ zebra/rtread_netlink.c | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 86bd8ffe4..87014160c 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -23,12 +23,11 @@ #include #include "zebra/zserv.h" - -extern int interface_lookup_netlink (void); +#include "rt_netlink.h" /* Interface information read by netlink. */ void interface_list (void) { - interface_lookup_netlink (); + interface_lookup_netlink (); } diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 0facd49e0..d8f9db856 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -41,6 +41,9 @@ extern const char * nl_rtproto_to_str (u_char rtproto); +extern int interface_lookup_netlink (void); +extern int netlink_route_read (void); + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RT_NETLINK_H */ diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 066e84433..7abbc590a 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -23,8 +23,7 @@ #include #include "zebra/zserv.h" - -extern void netlink_route_read (void); +#include "rt_netlink.h" void route_read (void) { From 7e92322cfcc6c062acae3b550f90d36fe40763f1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 21:04:20 +0100 Subject: [PATCH 0656/1342] zebra: use SA_SIZE for RT_ROUNDUP on FreeBSD FreeBSD provides SA_SIZE (and none of the other options to infer padded size of a struct sockaddr). Just define SAROUNDUP to SA_SIZE if it is available. This also drops a superfluous-looking extra macro branch which would require ROUNDUP. It seemed redundant to my eyes, but I have no idea what odd things might have triggered addition of this in the first place... Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 1518c1ab4..5eb92d92f 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -58,6 +58,12 @@ extern struct zebra_t zebrad; * Because of these varying conventions, the only sane approach is for * the header to define some flavor of ROUNDUP macro. */ + +#if defined(SA_SIZE) +/* SAROUNDUP is the only thing we need, and SA_SIZE provides that */ +#define SAROUNDUP(a) SA_SIZE(a) +#else /* !SA_SIZE */ + #if defined(RT_ROUNDUP) #define ROUNDUP(a) RT_ROUNDUP(a) #endif /* defined(RT_ROUNDUP) */ @@ -114,6 +120,8 @@ extern struct zebra_t zebrad; ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr))) #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ +#endif /* !SA_SIZE */ + /* * We use a call to an inline function to copy (PNT) to (DEST) * 1. Calculating the length of the copy requires an #ifdef to determine @@ -1114,15 +1122,6 @@ rtm_write (int message, msg.rtm.rtm_flags |= RTF_REJECT; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN -#define SOCKADDRSET(X,R) \ - if (msg.rtm.rtm_addrs & (R)) \ - { \ - int len = ROUNDUP ((X)->sa.sa_len); \ - memcpy (pnt, (caddr_t)(X), len); \ - pnt += len; \ - } -#else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ @@ -1130,7 +1129,6 @@ rtm_write (int message, memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ pnt = (caddr_t) msg.buf; From 3e9e2c9fb66895df42159b98a3743e25399760df Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 10 Apr 2015 09:14:58 +0200 Subject: [PATCH 0657/1342] zebra: static int inline -> static inline int The BSD socket kernel interface had some weird ordering of function attribute keywords. ("static int inline foobar()") Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5eb92d92f..6a9892e2d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -129,7 +129,7 @@ extern struct zebra_t zebrad; * 2. So the compiler doesn't complain when DEST is NULL, which is only true * when we are skipping the copy and incrementing to the next SA */ -static void inline +static inline void rta_copy (union sockunion *dest, caddr_t src) { int len; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN @@ -279,7 +279,7 @@ int routing_sock = -1; /* #define DEBUG */ /* Supported address family check. */ -static int inline +static inline int af_check (int family) { if (family == AF_INET) From a3466abd93f83424f9f83e56282e42188e1f94ce Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:14:46 +0100 Subject: [PATCH 0658/1342] zebra: clean up misc_null pragmas The no-op alternatives provided in misc_null trigger a few warnings since they provide functions / use pragmas without prototypes. Signed-off-by: David Lamparter --- zebra/misc_null.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/zebra/misc_null.c b/zebra/misc_null.c index b4416e635..18977d2f8 100644 --- a/zebra/misc_null.c +++ b/zebra/misc_null.c @@ -27,16 +27,27 @@ #include "zebra/interface.h" #include "zebra/zebra_fpm.h" -void ifstat_update_proc (void) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA -#pragma weak rtadv_config_write = ifstat_update_proc -#pragma weak irdp_config_write = ifstat_update_proc -#pragma weak ifstat_update_sysctl = ifstat_update_proc +void _quagga_noop (void); +void _quagga_noop (void) { return; } +#pragma weak rtadv_config_write = _quagga_noop +#pragma weak irdp_config_write = _quagga_noop +#ifdef HAVE_NET_RT_IFLIST +#pragma weak ifstat_update_sysctl = _quagga_noop +#endif +#ifdef HAVE_PROC_NET_DEV +#pragma weak ifstat_update_proc = _quagga_noop +#endif #else void rtadv_config_write (struct vty *vty, struct interface *ifp) { return; } void irdp_config_write (struct vty *vty, struct interface *ifp) { return; } +#ifdef HAVE_PROC_NET_DEV +void ifstat_update_proc (void) { return; } +#endif +#ifdef HAVE_NET_RT_IFLIST void ifstat_update_sysctl (void) { return; } #endif +#endif void zfpm_trigger_update (struct route_node *rn, const char *reason) From e070452d981f58d60d79d7b4b38c93fb034c49b3 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 10:41:21 +0100 Subject: [PATCH 0659/1342] pimd: mask unused zclient_broken() this function is used by the currently not present zclient reconnect code. It'll be unmasked again when that code hits master. Signed-off-by: David Lamparter --- pimd/pim_zebra.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 6f241d596..129cbe4fb 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -51,6 +51,7 @@ static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask); +#if 0 static void zclient_broken(struct zclient *zclient) { struct listnode *ifnode; @@ -65,6 +66,7 @@ static void zclient_broken(struct zclient *zclient) /* upon return, zclient will discard connected addresses */ } +#endif /* Router-id update message from zebra. */ static int pim_router_id_update_zebra(int command, struct zclient *zclient, From a2c7f4bd869bd232eb12896ff65a510d6716d2b9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 21:03:52 +0100 Subject: [PATCH 0660/1342] pimd: cast to sockaddr_in to sockaddr While glibc seems to have something in the system headers that prevents this from triggering a warning, FreeBSD doesn't. Fix the warning. Signed-off-by: David Lamparter --- pimd/pim_igmpv3.c | 3 ++- pimd/pim_pim.c | 3 ++- pimd/pim_ssmpingd.c | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 3baddbfae..3657f2f94 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1680,7 +1680,8 @@ void pim_igmp_send_membership_query(struct igmp_group *group, #endif tolen = sizeof(to); - sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, &to, tolen); + sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, + (struct sockaddr *)&to, tolen); if (sent != (ssize_t) msg_size) { int e = errno; char dst_str[100]; diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index f6f4c9535..f8ac650d2 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -476,7 +476,8 @@ int pim_msg_send(int fd, pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size); } - sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen); + sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, + (struct sockaddr *)&to, tolen); if (sent != (ssize_t) pim_msg_size) { int e = errno; char dst_str[100]; diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index fd1eac06e..82e0722a7 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -96,7 +96,7 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl) sockaddr.sin_addr = addr; sockaddr.sin_port = htons(port); - if (bind(fd, &sockaddr, sizeof(sockaddr))) { + if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s", @@ -222,7 +222,8 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss, socklen_t tolen = sizeof(to); int sent; - sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT, &to, tolen); + sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT, + (struct sockaddr *)&to, tolen); if (sent != len) { int e = errno; char to_str[100]; From c7879ea62fb38999a86ca9cbabbdeca18785e135 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 06:37:20 +0100 Subject: [PATCH 0661/1342] pimd: cast ioctl values when printing them ioctl values might be int or long, cast them to unsigned long for consistent printing. (They're long on FreeBSD, but were printed with %d.) Signed-off-by: David Lamparter --- pimd/pim_cmd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 6b2ac6646..13812cd85 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2031,8 +2031,8 @@ static void show_multicast_interfaces(struct vty *vty) if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) { int e = errno; vty_out(vty, - "ioctl(SIOCGETVIFCNT=%d) failure for interface %s vif_index=%d: errno=%d: %s%s", - SIOCGETVIFCNT, + "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s%s", + (unsigned long)SIOCGETVIFCNT, ifp->name, pim_ifp->mroute_vif_index, e, @@ -2225,8 +2225,8 @@ static void show_mroute_count(struct vty *vty) if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { int e = errno; vty_out(vty, - "ioctl(SIOCGETSGCNT=%d) failure for (S,G)=(%s,%s): errno=%d: %s%s", - SIOCGETSGCNT, + "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s%s", + (unsigned long)SIOCGETSGCNT, source_str, group_str, e, From 81a4e85442e2011a47bbb25e8301dc40ec4ed9b6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:56:48 +0100 Subject: [PATCH 0662/1342] lib: silence type range warning in macro While splitting up the CLI input macro is a bit annoying, this seems to be the least annoying way to get rid of the "< 0" comparison warning for unsigned long. Signed-off-by: David Lamparter --- lib/keychain.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/keychain.c b/lib/keychain.c index 762c46298..8a2fdd2ed 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -381,18 +381,22 @@ key_str2time (const char *time_str, const char *day_str, const char *month_str, NULL }; -#define GET_LONG_RANGE(V,STR,MIN,MAX) \ +#define _GET_LONG_RANGE(V,STR,MMCOND) \ { \ unsigned long tmpl; \ char *endptr = NULL; \ tmpl = strtoul ((STR), &endptr, 10); \ if (*endptr != '\0' || tmpl == ULONG_MAX) \ return -1; \ - if ( tmpl < (MIN) || tmpl > (MAX)) \ + if (MMCOND) \ return -1; \ (V) = tmpl; \ } - +#define GET_LONG_RANGE(V,STR,MIN,MAX) \ + _GET_LONG_RANGE(V,STR,tmpl < (MIN) || tmpl > (MAX)) +#define GET_LONG_RANGE0(V,STR,MAX) \ + _GET_LONG_RANGE(V,STR,tmpl > (MAX)) + /* Check hour field of time_str. */ colon = strchr (time_str, ':'); if (colon == NULL) @@ -400,7 +404,7 @@ key_str2time (const char *time_str, const char *day_str, const char *month_str, *colon = '\0'; /* Hour must be between 0 and 23. */ - GET_LONG_RANGE (hour, time_str, 0, 23); + GET_LONG_RANGE0 (hour, time_str, 23); /* Check min field of time_str. */ time_str = colon + 1; @@ -410,7 +414,7 @@ key_str2time (const char *time_str, const char *day_str, const char *month_str, *colon = '\0'; /* Min must be between 0 and 59. */ - GET_LONG_RANGE (min, time_str, 0, 59); + GET_LONG_RANGE0 (min, time_str, 59); /* Check sec field of time_str. */ time_str = colon + 1; @@ -418,7 +422,7 @@ key_str2time (const char *time_str, const char *day_str, const char *month_str, return -1; /* Sec must be between 0 and 59. */ - GET_LONG_RANGE (sec, time_str, 0, 59); + GET_LONG_RANGE0 (sec, time_str, 59); /* Check day_str. Day must be <1-31>. */ GET_LONG_RANGE (day, day_str, 1, 31); From fd8f6ebb4c6b9e5364b98d2b5fd345d1dcc08824 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:57:02 +0100 Subject: [PATCH 0663/1342] lib: use const consistently for zserv path The global variable is missing its const, but the accessor function has a meaningless extra const in exchange... Signed-off-by: David Lamparter --- lib/zclient.c | 4 ++-- lib/zclient.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 963c7052d..1e05d6dde 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -41,7 +41,7 @@ static void zclient_event (enum event, struct zclient *); extern struct thread_master *master; -char *zclient_serv_path = NULL; +const char *zclient_serv_path = NULL; /* This file local debug flag. */ int zclient_debug = 0; @@ -1053,7 +1053,7 @@ zclient_event (enum event event, struct zclient *zclient) } } -const char *const zclient_serv_path_get() +const char *zclient_serv_path_get() { return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH; } diff --git a/lib/zclient.h b/lib/zclient.h index d0c5450b7..a51b3defd 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -134,7 +134,7 @@ extern void zclient_free (struct zclient *); extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); -extern const char *const zclient_serv_path_get (void); +extern const char *zclient_serv_path_get (void); /* Send redistribute command to zebra daemon. Do not update zclient state. */ extern int zebra_redistribute_send (int command, struct zclient *, int type); From 71f55f38cb3dd804176e7f382f52b75ddcd437de Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:08:05 +0100 Subject: [PATCH 0664/1342] lib, vtysh: reduce unneccessary C extension usage We're only supporting GCC, Clang and ICC; but there's no reason to use nonstandard C constructs if they don't actually provide any benefit. Signed-off-by: David Lamparter --- lib/buffer.c | 2 +- vtysh/vtysh_main.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/buffer.c b/lib/buffer.c index b689549ed..ee9310100 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -148,7 +148,7 @@ buffer_add (struct buffer *b) { struct buffer_data *d; - d = XMALLOC(MTYPE_BUFFER_DATA, offsetof(struct buffer_data, data[b->size])); + d = XMALLOC(MTYPE_BUFFER_DATA, offsetof(struct buffer_data, data) + b->size); d->cp = d->sp = 0; d->next = NULL; diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 48958f0f3..893c1a1c1 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -202,9 +202,12 @@ static void log_it(const char *line) { time_t t = time(NULL); struct tm *tmp = localtime(&t); - char *user = getenv("USER") ? : "boot"; + const char *user = getenv("USER"); char tod[64]; + if (!user) + user = "boot"; + strftime(tod, sizeof tod, "%Y%m%d-%H:%M.%S", tmp); fprintf(logfile, "%s:%s %s\n", tod, user, line); From 33b9663a89b5ec319986de0673764d2a18ec8725 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 08:57:25 +0100 Subject: [PATCH 0665/1342] watchquagga: break excessively long help string watchquagga's command line help string exceeds the ISO C maximum string length (4095 characters). Just break it in two. Signed-off-by: David Lamparter --- watchquagga/watchquagga.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index c34816c21..d92803d7e 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -215,7 +215,8 @@ usage(const char *progname, int status) if (status != 0) fprintf(stderr, "Try `%s --help' for more information.\n", progname); else - printf("Usage : %s [OPTION...] ...\n\n\ + { + printf("Usage : %s [OPTION...] ...\n\n\ Watchdog program to monitor status of quagga daemons and try to restart\n\ them if they are down or unresponsive. It determines whether a daemon is\n\ up based on whether it can connect to the daemon's vty unix stream socket.\n\ @@ -259,8 +260,12 @@ the -m and -M options allow you to control the minimum delay between\n\ restart commands. The minimum restart delay is recalculated each time\n\ a restart is attempted: if the time since the last restart attempt exceeds\n\ twice the -M value, then the restart delay is set to the -m value.\n\ -Otherwise, the interval is doubled (but capped at the -M value).\n\n\ -Options:\n\ +Otherwise, the interval is doubled (but capped at the -M value).\n\n", + progname,mode_str[0],progname,mode_str[1],progname,mode_str[2], + progname,mode_str[3],progname,mode_str[4],progname,mode_str[2], + mode_str[3]); + + printf("Options:\n\ -d, --daemon Run in daemon mode. In this mode, error messages are sent\n\ to syslog instead of stdout.\n\ -S, --statedir Set the vty socket directory (default is %s)\n\ @@ -318,12 +323,12 @@ Options:\n\ it with a space. This is an ugly hack to circumvent problems\n\ passing command-line arguments with embedded spaces.\n\ -v, --version Print program version\n\ --h, --help Display this help and exit\n\ -", progname,mode_str[0],progname,mode_str[1],progname,mode_str[2], -progname,mode_str[3],progname,mode_str[4],progname,mode_str[2],mode_str[3], -VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG, -DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART, -DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT,DEFAULT_PIDFILE); +-h, --help Display this help and exit\n", + VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG, + DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART, + DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT, + DEFAULT_PIDFILE); + } return status; } From 0de0138a9146074f268245193e45c9376d998722 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 10:30:27 +0100 Subject: [PATCH 0666/1342] ospf6d: use existing union, avoid strict-aliasing There are preexisting fields u.lp.id and u.lp.adv_router in struct prefix that do the same thing as these type-punning pointer derefs. Use these and shut up the strict-aliasing warnings. Signed-off-by: David Lamparter --- ospf6d/ospf6_route.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index c0dcf9f1f..42eb69ea8 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -239,16 +239,15 @@ extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0) #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) -/* XXX: This gives GCC heartburn aboutbreaking aliasing rules. */ #define ospf6_linkstate_prefix_adv_router(x) \ - (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) + ((x)->u.lp.id.s_addr) #define ospf6_linkstate_prefix_id(x) \ - (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) + ((x)->u.lp.adv_router.s_addr) #define ADV_ROUTER_IN_PREFIX(x) \ - (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) + ((x)->u.lp.id.s_addr) #define ID_IN_PREFIX(x) \ - (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) + ((x)->u.lp.adv_router.s_addr) /* Function prototype */ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, From 72c69d434840598a158747ba9f69dad536f96cea Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:08:20 +0100 Subject: [PATCH 0667/1342] ospf6d: oi->cost is uint32, not short Signed-off-by: David Lamparter --- ospf6d/ospf6_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 7c2d46fe0..c9c90117b 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -914,7 +914,7 @@ ospf6_interface_show (struct vty *vty, struct interface *ifp) "disabled" : "enabled", VNL); inet_ntop (AF_INET, &oi->area->area_id, strbuf, sizeof (strbuf)); - vty_out (vty, " Area ID %s, Cost %hu%s", strbuf, oi->cost, + vty_out (vty, " Area ID %s, Cost %u%s", strbuf, oi->cost, VNL); } else From 3cf4053a9e832408fad33a8246ecbd189f23a956 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 19 Apr 2015 14:54:03 +0200 Subject: [PATCH 0668/1342] ospf6d: fix pointer arithmetic warning caddr_t was signed; this buffer size comparison is better done in unsigned. Signed-off-by: David Lamparter --- ospf6d/ospf6_intra.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 1ef0b5355..6606c96d9 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -234,9 +234,9 @@ ospf6_router_lsa_originate (struct thread *thread) /* Multiple Router-LSA instance according to size limit setting */ if ( (oa->router_lsa_size_limit != 0) - && ((caddr_t) lsdesc + sizeof (struct ospf6_router_lsdesc) - - /* XXX warning: comparison between signed and unsigned */ - (caddr_t) buffer > oa->router_lsa_size_limit)) + && ((size_t)((char *)lsdesc - buffer) + + sizeof (struct ospf6_router_lsdesc) + > oa->router_lsa_size_limit)) { if ((caddr_t) lsdesc == (caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)) From a91a3bac14976c04bf22b20c7e4bada787ec79b1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:06:51 +0100 Subject: [PATCH 0669/1342] vtysh: don't use '\0' as NULL for some reason, the vty code was using '\0' in place of NULL. Signed-off-by: David Lamparter --- lib/vty.c | 6 +++--- vtysh/vtysh.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 750f8856e..d623b8533 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -870,7 +870,7 @@ vty_complete_command (struct vty *vty) /* In case of 'help \t'. */ if (isspace ((int) vty->buf[vty->length - 1])) - vector_set (vline, '\0'); + vector_set (vline, NULL); matched = cmd_complete_command (vline, vty, &ret); @@ -985,11 +985,11 @@ vty_describe_command (struct vty *vty) if (vline == NULL) { vline = vector_init (1); - vector_set (vline, '\0'); + vector_set (vline, NULL); } else if (isspace ((int) vty->buf[vty->length - 1])) - vector_set (vline, '\0'); + vector_set (vline, NULL); describe = cmd_describe_command (vline, vty, &ret); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 984f8d39b..5490b3357 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -563,11 +563,11 @@ vtysh_rl_describe (void) if (vline == NULL) { vline = vector_init (1); - vector_set (vline, '\0'); + vector_set (vline, NULL); } else if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) - vector_set (vline, '\0'); + vector_set (vline, NULL); describe = cmd_describe_command (vline, vty, &ret); @@ -657,7 +657,7 @@ command_generator (const char *text, int state) return NULL; if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) - vector_set (vline, '\0'); + vector_set (vline, NULL); matched = cmd_complete_command (vline, vty, &complete_status); } From a9eb9063071437f5cde3b78adf273b428c49d378 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 07:07:01 +0100 Subject: [PATCH 0670/1342] vtysh: fix function prototypes This makes a whole bunch of vtysh functions static, fixes prototypes for a few more, and masks user_free() and user_write_config() (both unused.) Signed-off-by: David Lamparter --- vtysh/vtysh.c | 6 +++--- vtysh/vtysh_config.c | 18 +++++++++--------- vtysh/vtysh_main.c | 8 ++++---- vtysh/vtysh_user.c | 18 +++++++++++------- vtysh/vtysh_user.h | 3 ++- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5490b3357..d64b4e00a 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -251,7 +251,7 @@ vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) } } -void +static void vtysh_exit_ripd_only (void) { if (ripd_client) @@ -547,7 +547,7 @@ vtysh_config_from_file (struct vty *vty, FILE *fp) } /* We don't care about the point of the cursor when '?' is typed. */ -int +static int vtysh_rl_describe (void) { int ret; @@ -821,7 +821,7 @@ static struct cmd_node keychain_key_node = extern struct cmd_node vty_node; /* When '^Z' is received from vty, move down to the enable mode. */ -int +static int vtysh_end (void) { switch (vty->node) diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index f9cb6a79b..1ddaac05c 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -47,19 +47,19 @@ struct config struct list *config_top; -int +static int line_cmp (char *c1, char *c2) { return strcmp (c1, c2); } -void +static void line_del (char *line) { XFREE (MTYPE_VTYSH_CONFIG_LINE, line); } -struct config * +static struct config * config_new () { struct config *config; @@ -67,13 +67,13 @@ config_new () return config; } -int +static int config_cmp (struct config *c1, struct config *c2) { return strcmp (c1->name, c2->name); } -void +static void config_del (struct config* config) { list_delete (config->line); @@ -82,7 +82,7 @@ config_del (struct config* config) XFREE (MTYPE_VTYSH_CONFIG, config); } -struct config * +static struct config * config_get (int index, const char *line) { struct config *config; @@ -121,13 +121,13 @@ config_get (int index, const char *line) return config; } -void +static void config_add_line (struct list *config, const char *line) { listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); } -void +static void config_add_line_uniq (struct list *config, const char *line) { struct listnode *node, *nnode; @@ -141,7 +141,7 @@ config_add_line_uniq (struct list *config, const char *line) listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); } -void +static void vtysh_config_parse_line (const char *line) { char c; diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 893c1a1c1..d24367092 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -63,7 +63,7 @@ struct thread_master *master; FILE *logfile; /* SIGTSTP handler. This function care user's ^Z input. */ -void +static void sigtstp (int sig) { /* Execute "end" command. */ @@ -84,7 +84,7 @@ sigtstp (int sig) } /* SIGINT handler. This function care user's ^Z input. */ -void +static void sigint (int sig) { /* Check this process is not child process. */ @@ -121,7 +121,7 @@ vtysh_signal_set (int signo, void (*func)(int)) } /* Initialization of signal handles. */ -void +static void vtysh_signal_init () { vtysh_signal_set (SIGINT, sigint); @@ -168,7 +168,7 @@ struct option longopts[] = }; /* Read a string, and return a pointer to it. Returns NULL on EOF. */ -char * +static char * vtysh_rl_gets () { HIST_ENTRY *last; diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 8f2cf4220..e1c611cee 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -99,19 +99,21 @@ struct vtysh_user struct list *userlist; -struct vtysh_user * +static struct vtysh_user * user_new () { return XCALLOC (0, sizeof (struct vtysh_user)); } -void +#if 0 +static void user_free (struct vtysh_user *user) { XFREE (0, user); } +#endif -struct vtysh_user * +static struct vtysh_user * user_lookup (const char *name) { struct listnode *node, *nnode; @@ -125,7 +127,8 @@ user_lookup (const char *name) return NULL; } -void +#if 0 +static void user_config_write () { struct listnode *node, *nnode; @@ -137,8 +140,9 @@ user_config_write () printf (" username %s nopassword\n", user->name); } } +#endif -struct vtysh_user * +static struct vtysh_user * user_get (const char *name) { struct vtysh_user *user; @@ -167,7 +171,7 @@ DEFUN (username_nopassword, } int -vtysh_auth () +vtysh_auth (void) { struct vtysh_user *user; struct passwd *passwd; @@ -188,7 +192,7 @@ vtysh_auth () } void -vtysh_user_init () +vtysh_user_init (void) { userlist = list_new (); install_element (CONFIG_NODE, &username_nopassword_cmd); diff --git a/vtysh/vtysh_user.h b/vtysh/vtysh_user.h index 8d0a4cf6a..c485c23f0 100644 --- a/vtysh/vtysh_user.h +++ b/vtysh/vtysh_user.h @@ -22,6 +22,7 @@ #ifndef _VTYSH_USER_H #define _VTYSH_USER_H -int vtysh_auth (); +int vtysh_auth (void); +void vtysh_user_init (void); #endif /* _VTYSH_USER_H */ From 6769f43de9d595b935f2ebf1cae1428e1d1a3a5f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 07:18:24 +0100 Subject: [PATCH 0671/1342] vtysh: drop unused variables & RETSIGTYPE Drop unused return values in vtysh. Also gets rid of the rather funny prototyping of signal setup in vtysh - which as a side effect makes it not need AC_TYPE_SIGNAL in configure.ac anymore. It wasn't used sensibly to begin with... Signed-off-by: David Lamparter --- configure.ac | 1 - vtysh/vtysh.c | 15 ++++++--------- vtysh/vtysh_main.c | 10 ++-------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index 2c72cff89..efece9cd1 100755 --- a/configure.ac +++ b/configure.ac @@ -422,7 +422,6 @@ dnl AC_TYPE_PID_T AC_TYPE_UID_T AC_TYPE_MODE_T AC_TYPE_SIZE_T -AC_TYPE_SIGNAL AC_STRUCT_TM dnl ------------------------- diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index d64b4e00a..fbbc88d0f 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1713,7 +1713,6 @@ DEFUN (vtysh_write_terminal, "Write to terminal\n") { u_int i; - int ret; char line[] = "write terminal\n"; FILE *fp = NULL; @@ -1735,7 +1734,7 @@ DEFUN (vtysh_write_terminal, vty_out (vty, "!%s", VTY_NEWLINE); for (i = 0; i < array_size(vtysh_client); i++) - ret = vtysh_client_config (&vtysh_client[i], line); + vtysh_client_config (&vtysh_client[i], line); /* Integrate vtysh specific configuration. */ vtysh_config_write (); @@ -1783,7 +1782,6 @@ static int write_config_integrated(void) { u_int i; - int ret; char line[] = "write terminal\n"; FILE *fp; char *integrate_sav = NULL; @@ -1809,7 +1807,7 @@ write_config_integrated(void) } for (i = 0; i < array_size(vtysh_client); i++) - ret = vtysh_client_config (&vtysh_client[i], line); + vtysh_client_config (&vtysh_client[i], line); vtysh_config_dump (fp); @@ -1948,7 +1946,6 @@ static int execute_command (const char *command, int argc, const char *arg1, const char *arg2) { - int ret; pid_t pid; int status; @@ -1967,13 +1964,13 @@ execute_command (const char *command, int argc, const char *arg1, switch (argc) { case 0: - ret = execlp (command, command, (const char *)NULL); + execlp (command, command, (const char *)NULL); break; case 1: - ret = execlp (command, command, arg1, (const char *)NULL); + execlp (command, command, arg1, (const char *)NULL); break; case 2: - ret = execlp (command, command, arg1, arg2, (const char *)NULL); + execlp (command, command, arg1, arg2, (const char *)NULL); break; } @@ -1985,7 +1982,7 @@ execute_command (const char *command, int argc, const char *arg1, { /* This is parent. */ execute_flag = 1; - ret = wait4 (pid, &status, 0, NULL); + wait4 (pid, &status, 0, NULL); execute_flag = 0; } return 0; diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index d24367092..aa7d02187 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -98,10 +98,9 @@ sigint (int sig) /* Signale wrapper for vtysh. We don't use sigevent because * vtysh doesn't use threads. TODO */ -RETSIGTYPE * +static void vtysh_signal_set (int signo, void (*func)(int)) { - int ret; struct sigaction sig; struct sigaction osig; @@ -112,12 +111,7 @@ vtysh_signal_set (int signo, void (*func)(int)) sig.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ - ret = sigaction (signo, &sig, &osig); - - if (ret < 0) - return (SIG_ERR); - else - return (osig.sa_handler); + sigaction (signo, &sig, &osig); } /* Initialization of signal handles. */ From dfee58f1d41a2e36c7f5f38a3ef5712224131824 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 4 Mar 2015 06:44:57 +0100 Subject: [PATCH 0672/1342] snmp: fix warnings batch-fix all warnings that come up when enabling AgentX SNMP support. Signed-off-by: David Lamparter --- lib/smux.h | 6 +++--- lib/snmp.c | 2 +- ospf6d/ospf6_snmp.c | 1 - ospfd/ospf_snmp.c | 12 ++++++------ ripd/rip_snmp.c | 6 +++--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/smux.h b/lib/smux.h index 02e963099..dc91cac71 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -55,8 +55,8 @@ struct trap_object /* Declare SMUX return value. */ #define SNMP_LOCAL_VARIABLES \ - static long snmp_int_val; \ - static struct in_addr snmp_in_addr_val; + static long snmp_int_val __attribute__ ((unused)); \ + static struct in_addr snmp_in_addr_val __attribute__ ((unused)); #define SNMP_INTEGER(V) \ ( \ @@ -108,7 +108,7 @@ extern int smux_trap (struct variable *, size_t, const struct trap_object *, size_t, u_char); -extern int oid_compare (oid *, int, oid *, int); +extern int oid_compare (const oid *, int, const oid *, int); extern void oid2in_addr (oid [], int, struct in_addr *); extern void *oid_copy (void *, const void *, size_t); extern void oid_copy_addr (oid [], struct in_addr *, int); diff --git a/lib/snmp.c b/lib/snmp.c index 79595a1ea..f6f9845e2 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -30,7 +30,7 @@ #define min(A,B) ((A) < (B) ? (A) : (B)) int -oid_compare (oid *o1, int o1_len, oid *o2, int o2_len) +oid_compare (const oid *o1, int o1_len, const oid *o2, int o2_len) { int i; diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 5d10ce639..ef44e4c94 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -628,7 +628,6 @@ ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int len; oid *offset; int offsetlen; - char a[16], b[16], c[16]; struct ospf6_area *oa; struct listnode *node; struct interface *iif; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 7f7b15786..9f9177694 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -986,7 +986,7 @@ ospfLsdbLookup (struct variable *v, oid *name, size_t *length, offsetlen = *length - v->namelen; len = offsetlen; - if (len > IN_ADDR_SIZE) + if (len > (int)IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, area_id); @@ -1026,7 +1026,7 @@ ospfLsdbLookup (struct variable *v, oid *name, size_t *length, else { ls_id_next = 0; - if (len > IN_ADDR_SIZE) + if (len > (int)IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, ls_id); @@ -1042,7 +1042,7 @@ ospfLsdbLookup (struct variable *v, oid *name, size_t *length, else { router_id_next = 0; - if (len > IN_ADDR_SIZE) + if (len > (int)IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, router_id); @@ -1152,7 +1152,7 @@ ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length, { oid *offset; int offsetlen; - unsigned int len; + int len; struct ospf *ospf; struct ospf_area *area; struct ospf_area_range *range; @@ -1193,7 +1193,7 @@ ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length, offsetlen = *length - v->namelen; len = offsetlen; - if (len > IN_ADDR_SIZE) + if (len > (int)IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, area_id); @@ -1215,7 +1215,7 @@ ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length, if (len < 0) len = 0; - if (len > IN_ADDR_SIZE) + if (len > (int)IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, range_net); diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 2df815b03..2c7cd2c12 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -295,7 +295,7 @@ rip2PeerLookup (struct variable *v, oid name[], size_t *length, peer = rip_peer_lookup (addr); - if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) + if (peer->domain == (int)name[v->namelen + sizeof (struct in_addr)]) return peer; return NULL; @@ -311,8 +311,8 @@ rip2PeerLookup (struct variable *v, oid name[], size_t *length, peer = rip_peer_lookup (addr); if (peer) { - if ((len < sizeof (struct in_addr) + 1) || - (peer->domain > name[v->namelen + sizeof (struct in_addr)])) + if ((len < (int)sizeof (struct in_addr) + 1) || + (peer->domain > (int)name[v->namelen + sizeof (struct in_addr)])) { oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); From d689d1a0c69726330d69b2dd412fdb8dcb23394b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 13:54:30 +0100 Subject: [PATCH 0673/1342] bgpd: fix SNMP write support This code - dating back to the initial import in 2002 - probably never worked. Calling asn_parse_int seems to always have been wrong, and in the meantime, there no longer is a "struct variable *" argument for write_method. If anyone tried to use it, it'd probably have crashed. (I didn't try.) Fix this up so it actually works. It's the only place in Quagga where a SNMP write is actually supported, so it's an odd one out anyway, but heh. Signed-off-by: David Lamparter --- bgpd/bgp_snmp.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 79aaa03a6..0f4aeec8b 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -337,38 +337,42 @@ bgp_peer_lookup_next (struct in_addr *src) return NULL; } +/* 1.3.6.1.2.1.15.3.1.x = 10 */ +#define PEERTAB_NAMELEN 10 + static struct peer * bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { struct peer *peer = NULL; + size_t namelen = v ? v->namelen : PEERTAB_NAMELEN; int len; if (exact) { /* Check the length. */ - if (*length - v->namelen != sizeof (struct in_addr)) + if (*length - namelen != sizeof (struct in_addr)) return NULL; - oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); + oid2in_addr (name + namelen, IN_ADDR_SIZE, addr); peer = peer_lookup_addr_ipv4 (addr); return peer; } else { - len = *length - v->namelen; + len = *length - namelen; if (len > 4) len = 4; - oid2in_addr (name + v->namelen, len, addr); + oid2in_addr (name + namelen, len, addr); peer = bgp_peer_lookup_next (addr); if (peer == NULL) return NULL; - oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); - *length = sizeof (struct in_addr) + v->namelen; + oid_copy_addr (name + namelen, addr, sizeof (struct in_addr)); + *length = sizeof (struct in_addr) + namelen; return peer; } @@ -379,14 +383,12 @@ bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, static int write_bgpPeerTable (int action, u_char *var_val, u_char var_val_type, size_t var_val_len, - u_char *statP, oid *name, size_t length, - struct variable *v) + u_char *statP, oid *name, size_t length) { struct in_addr addr; struct peer *peer; long intval; - size_t bigsize = SNMP_MAX_LEN; - + if (var_val_type != ASN_INTEGER) { return SNMP_ERR_WRONGTYPE; @@ -396,21 +398,21 @@ write_bgpPeerTable (int action, u_char *var_val, return SNMP_ERR_WRONGLENGTH; } - if (! asn_parse_int(var_val, &bigsize, &var_val_type, - &intval, sizeof(long))) - { - return SNMP_ERR_WRONGENCODING; - } + intval = *(long *)var_val; memset (&addr, 0, sizeof (struct in_addr)); - peer = bgpPeerTable_lookup (v, name, &length, &addr, 1); + peer = bgpPeerTable_lookup (NULL, name, &length, &addr, 1); if (! peer) return SNMP_ERR_NOSUCHNAME; - printf ("val: %ld\n", intval); + if (action != SNMP_MSG_INTERNAL_SET_COMMIT) + return SNMP_ERR_NOERROR; - switch (v->magic) + zlog_info ("%s: SNMP write .%ld = %ld", + peer->host, (long)name[PEERTAB_NAMELEN - 1], intval); + + switch (name[PEERTAB_NAMELEN - 1]) { case BGPPEERADMINSTATUS: #define BGP_PeerAdmin_stop 1 From 53780e30c90ae393467afaf3ccff9e3791df5133 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:07:09 +0100 Subject: [PATCH 0674/1342] bgpd: drop unused static variable Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index be316daa6..5c832edcd 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -72,7 +72,6 @@ static const struct message attr_flag_str[] = /* bgp_attr_flags_diagnose() relies on this bit being last in this list */ { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, }; -static const size_t attr_flag_str_max = array_size(attr_flag_str); static struct hash *cluster_hash; From 3a7e83c2387885075c9ecf1912dd6c9399c6947a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 09:55:51 +0100 Subject: [PATCH 0675/1342] build: determine CFLAGS more intelligently Instead of hardcoding some compiler detection, this just checks which CFLAGS actually work with the compiler specified by the user. Signed-off-by: David Lamparter --- configure.ac | 106 ++++++++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/configure.ac b/configure.ac index efece9cd1..b11c989bf 100755 --- a/configure.ac +++ b/configure.ac @@ -86,20 +86,7 @@ else fi AM_CONDITIONAL([HAVE_LATEX], [test "x$HAVE_LATEX" = "xtrue"]) -dnl ------------------------------------------------------------------ -dnl Intel compiler check. Although Intel tries really hard to make icc -dnl look like gcc, there are some differences. It's very verbose with -dnl -Wall and it doesn't support the individual -W options. -dnl ------------------------------------------------------------------ -if test "x${GCC}" = "xyes" ; then - COMPILER="GCC" - AC_MSG_CHECKING([whether we are using the Intel compiler]) - AC_EGREP_CPP([^__INTEL_COMPILER], [__INTEL_COMPILER], - [AC_MSG_RESULT([no])], - [COMPILER="ICC" - AC_MSG_RESULT([yes])] - ) -else +if test "x${GCC}" != "xyes" ; then AC_MSG_CHECKING([whether we are using SunPro compiler]) AC_EGREP_CPP([^__SUNPRO_C.*0x5(7|8|9)], ["__SUNPRO_C" __SUNPRO_C], [AC_MSG_RESULT([no])], @@ -115,41 +102,73 @@ dnl already, eg "-O2 -g" for gcc, "-g" for others dnl (Wall is gcc specific... have to make sure dnl gcc is being used before setting it) dnl -dnl Intel icc 8.0 also sets __GNUC__, -dnl but doesn't support all these fancy -W options. -dnl Intel compiler warnings we ignore: -dnl 279: controlling expression is constant. -dnl 869: parameter "xxx" was never referenced - to avoid massive warnings -dnl about "self", "vty", "argc" and "argv" never referenced in DEFUN -dnl macro. -dnl 981: operands are evaluated in unspecified order. -dnl dnl Sun Studio 10 / SunPro 5.7 is also supported, dnl so lets set some sane CFLAGS for it. dnl --------------------------------------------- +AC_USE_SYSTEM_EXTENSIONS() +AC_DEFUN([AC_C_FLAG], [{ + AC_LANG_PUSH(C) + ac_c_flag_save="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_MSG_CHECKING([[whether $CC supports $1]]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]])], + [ + AC_MSG_RESULT([yes]) + m4_if([$3], [], [], [ + CFLAGS="$ac_c_flag_save" + $3 + ]) + ], [ + CFLAGS="$ac_c_flag_save" + AC_MSG_RESULT([no]) + $2 + ]) + AC_LANG_POP(C) + }]) + AC_MSG_CHECKING([whether to set a default CFLAGS]) if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in - "ICC") - CFLAGS="-Os -g -Wall" - AC_MSG_RESULT([Intel default]) - ;; - "GCC") - CFLAGS="-Os -fno-omit-frame-pointer -g -std=gnu99 -Wall" - CFLAGS="${CFLAGS} -Wsign-compare -Wpointer-arith" - CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" - CFLAGS="${CFLAGS} -Wmissing-prototypes -Wmissing-declarations" - CFLAGS="${CFLAGS} -Wchar-subscripts -Wcast-qual" - # TODO: conditionally addd -Wpacked if handled - AC_MSG_RESULT([gcc default]) - ;; "SUNPRO") - CFLAGS="-xO4 -v -g -xspace -xcode=pic32 -xstrconst -xc99" - AC_MSG_RESULT([SunPro default]) - ;; + CFLAGS="-xO4 -v -g -xspace -xcode=pic32 -xstrconst -xc99" + AC_MSG_RESULT([SunPro default]) + ;; *) - AC_MSG_RESULT([unknown compiler]) + AC_MSG_RESULT([autodetecting]) + + AC_C_FLAG([-diag-error 10006]) + AC_C_FLAG([-std=gnu99]) + AC_C_FLAG([-g]) + AC_C_FLAG([-Os], [ + AC_C_FLAG([-O2]) + ]) + AC_C_FLAG([-fno-omit-frame-pointer]) + AC_C_FLAG([-Wall]) + AC_C_FLAG([-Wextra]) + AC_C_FLAG([-Wmissing-prototypes]) + AC_C_FLAG([-Wmissing-declarations]) + AC_C_FLAG([-Wpointer-arith]) + AC_C_FLAG([-Wbad-function-cast]) + AC_C_FLAG([-Wwrite-strings]) + if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then + AC_C_FLAG([-Wcast-qual]) + AC_C_FLAG([-Wstrict-prototypes]) + AC_C_FLAG([-Wmissing-noreturn]) + AC_C_FLAG([-Wmissing-format-attribute]) + AC_C_FLAG([-Wunreachable-code]) + AC_C_FLAG([-Wpacked]) + AC_C_FLAG([-Wpadded]) + else + AC_C_FLAG([-Wno-unused-result]) + fi + AC_C_FLAG([-Wno-unused-parameter]) + AC_C_FLAG([-Wno-missing-field-initializers]) + # ICC emits a broken warning for const char *x = a ? "b" : "c"; + # for some reason the string consts get 'promoted' to char *, + # triggering a const to non-const conversion warning. + AC_C_FLAG([-diag-disable 3179]) ;; esac else @@ -278,13 +297,6 @@ AC_ARG_ENABLE(pcreposix, AC_ARG_ENABLE(fpm, AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) -if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then - CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" - CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" - CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" - CFLAGS="${CFLAGS} -Wpacked -Wpadded" -fi - if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then LDFLAGS="${LDFLAGS} -rdynamic" From c0bedebfe9ca1a1ded02f1f481762dd41defa63e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 3 Mar 2015 10:00:43 +0100 Subject: [PATCH 0676/1342] build: add --enable-werror This allows enabling -Werror in a consistent way. Note that this is different from just specifiying it in CFLAGS, since that would either break configure tests (if done on ./configure), or would override configure's CFLAGS (if done on make). Using --enable-werror instead provides a new WERROR variable that is additionally used during make with a consistent set of warning flags. The tests/ directory is exempt. (Rationale being, better to have more tests than pedantically complain about them.) Signed-off-by: David Lamparter --- babeld/Makefile.am | 2 +- bgpd/Makefile.am | 2 +- buildtest.sh | 2 +- configure.ac | 7 +++++++ isisd/Makefile.am | 2 +- lib/Makefile.am | 1 + ospf6d/Makefile.am | 2 +- ospfclient/Makefile.am | 1 + ospfd/Makefile.am | 1 + pimd/Makefile.am | 2 +- ripd/Makefile.am | 2 +- ripngd/Makefile.am | 2 +- vtysh/Makefile.am | 2 +- watchquagga/Makefile.am | 2 +- zebra/Makefile.am | 2 +- 15 files changed, 21 insertions(+), 11 deletions(-) diff --git a/babeld/Makefile.am b/babeld/Makefile.am index 13922d0f4..d34e180b0 100644 --- a/babeld/Makefile.am +++ b/babeld/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbabel.a diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 42f1f488c..92fa10cd4 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbgp.a diff --git a/buildtest.sh b/buildtest.sh index 3bc25f232..3dd8ed821 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -4,7 +4,7 @@ # builds some git commit of Quagga in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld --enable-pimd" +basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld --enable-pimd --enable-werror" configs_base="gcc|$basecfg" diff --git a/configure.ac b/configure.ac index b11c989bf..a82470cd0 100755 --- a/configure.ac +++ b/configure.ac @@ -175,6 +175,11 @@ else AC_MSG_RESULT([CFLAGS supplied by user]) fi +if test x"${enable_werror}" = x"yes" ; then + WERROR="-Werror" +fi +AC_SUBST(WERROR) + dnl -------------- dnl Check programs dnl -------------- @@ -296,6 +301,8 @@ AC_ARG_ENABLE(pcreposix, AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE(fpm, AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) +AC_ARG_ENABLE(werror, + AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then diff --git a/isisd/Makefile.am b/isisd/Makefile.am index dba681b11..4e67b228f 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -6,7 +6,7 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libisis.a diff --git a/lib/Makefile.am b/lib/Makefile.am index 5a806183c..56837d869 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CFLAGS = $(WERROR) DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index d30ce5819..cbd850f33 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libospf6.a diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index 09d2ba860..c4f0da834 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -1,6 +1,7 @@ ## Automake.am for OSPF API client AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CFLAGS = $(WERROR) lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 4160bfccc..40f2cfe55 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +AM_CFLAGS = $(WERROR) DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 diff --git a/pimd/Makefile.am b/pimd/Makefile.am index f13debd9d..816afb90f 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -39,7 +39,7 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libpim.a diff --git a/ripd/Makefile.am b/ripd/Makefile.am index 65a626dd6..34c5f183a 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = librip.a diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index 9bd14ba0b..0487459bb 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libripng.a diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index a66615beb..0cc6d5ba0 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -5,7 +5,7 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" LIBS = @LIBS@ @CURSES@ @LIBPAM@ -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) bin_PROGRAMS = vtysh diff --git a/watchquagga/Makefile.am b/watchquagga/Makefile.am index 9256006c8..939ecd710 100644 --- a/watchquagga/Makefile.am +++ b/watchquagga/Makefile.am @@ -3,7 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) sbin_PROGRAMS = watchquagga diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 480879179..7dcbd6607 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -20,7 +20,7 @@ if HAVE_NETLINK othersrc = zebra_fpm_netlink.c endif -AM_CFLAGS = $(PICFLAGS) +AM_CFLAGS = $(PICFLAGS) $(WERROR) AM_LDFLAGS = $(PILDFLAGS) sbin_PROGRAMS = zebra From 940b19911209d8ad2ea326c4a46e0fb044568edc Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 21 Apr 2015 09:45:06 +0200 Subject: [PATCH 0677/1342] pimd: fix out of tree build pimd/Makefile.am was missing srcdir/lib from its include paths, breaking out-of-tree build regarding route_types.h Signed-off-by: David Lamparter --- pimd/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 816afb90f..b82613a80 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -34,7 +34,7 @@ PIM_DEFS += -DPIM_ZCLIENT_DEBUG PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ From 4b6c33282973c9e1545a519f2a51bda3cf42ae21 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 21 Apr 2015 09:47:57 +0200 Subject: [PATCH 0678/1342] zebra: silence zebra_serv_un unused warning zebra_serv_un() is unused if --enable-tcp-zebra is given. Signed-off-by: David Lamparter --- zebra/zserv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index afd722a10..432c31824 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1558,7 +1558,7 @@ zebra_serv () zebra_event (ZEBRA_SERV, accept_sock, NULL); } -#endif /* HAVE_TCP_ZEBRA */ +#else /* HAVE_TCP_ZEBRA */ /* For sockaddr_un. */ #include @@ -1624,6 +1624,7 @@ zebra_serv_un (const char *path) zebra_event (ZEBRA_SERV, sock, NULL); } +#endif /* HAVE_TCP_ZEBRA */ static void From c313895dec3c176584d99f7b8684ddc3f9141d88 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 21 Apr 2015 10:02:23 +0200 Subject: [PATCH 0679/1342] tests: fix warnings While I don't see -Werror being used on tests anytime soon, there's no reason to keep the warnings in tests unfixed. Signed-off-by: David Lamparter --- tests/Makefile.am | 4 ++-- tests/bgp_mp_attr_test.c | 2 +- tests/bgp_mpath_test.c | 2 +- tests/ecommunity_test.c | 2 +- tests/heavy-thread.c | 2 ++ tests/heavy-wq.c | 2 ++ tests/heavy.c | 2 ++ tests/main.c | 2 +- tests/test-checksum.c | 35 ---------------------------------- tests/test-segv.c | 2 +- tests/test-sig.c | 6 +++--- tests/test-timer-correctness.c | 9 ++++++--- tests/tests.h | 31 ++++++++++++++++++++++++++++++ 13 files changed, 53 insertions(+), 48 deletions(-) create mode 100644 tests/tests.h diff --git a/tests/Makefile.am b/tests/Makefile.am index 1fe28c70f..b5420710a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -36,14 +36,14 @@ check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythrea test-commands-defun.c: ../vtysh/vtysh_cmd.c sed \ - -e '/"vtysh.h"/d' \ + -e 's/"vtysh\.h"/"tests.h"/' \ -e 's/vtysh_init_cmd/test_init_cmd/' \ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ < ../vtysh/vtysh_cmd.c \ > test-commands-defun.c BUILT_SOURCES = test-commands-defun.c -noinst_HEADERS = prng.h +noinst_HEADERS = prng.h tests.h testsig_SOURCES = test-sig.c testsegv_SOURCES = test-segv.c diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 5f0e733dd..d649e14d7 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -545,7 +545,7 @@ main (void) return -1; peer = peer_create_accept (bgp); - peer->host = "foo"; + peer->host = (char *)"foo"; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index 3d0ecb78b..359475374 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -252,7 +252,7 @@ run_bgp_mp_list (testcase_t *t) bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); - for (i = 0, mp_node = listhead(&mp_list); i < test_mp_list_info_count; + for (i = 0, mp_node = mp_list.head; i < test_mp_list_info_count; i++, mp_node = listnextnode(mp_node)) { info = listgetdata(mp_node); diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c index cd1681d55..f12aa71cc 100644 --- a/tests/ecommunity_test.c +++ b/tests/ecommunity_test.c @@ -132,7 +132,7 @@ parse_test (struct test_segment *t) printf ("%s: %s\n", t->name, t->desc); - ecom = ecommunity_parse (t->data, t->len); + ecom = ecommunity_parse ((u_int8_t *)t->data, t->len); printf ("ecom: %s\nvalidating...:\n", ecommunity_str (ecom)); diff --git a/tests/heavy-thread.c b/tests/heavy-thread.c index cd3a3b9d0..c2e71c17d 100644 --- a/tests/heavy-thread.c +++ b/tests/heavy-thread.c @@ -37,6 +37,8 @@ #include "memory.h" #include "log.h" +#include "tests.h" + extern struct thread_master *master; enum diff --git a/tests/heavy-wq.c b/tests/heavy-wq.c index e5f688c21..2f133cc5d 100644 --- a/tests/heavy-wq.c +++ b/tests/heavy-wq.c @@ -36,6 +36,8 @@ #include "workqueue.h" #include +#include "tests.h" + extern struct thread_master *master; static struct work_queue *heavy_wq; diff --git a/tests/heavy.c b/tests/heavy.c index 577a4816f..9af46c88f 100644 --- a/tests/heavy.c +++ b/tests/heavy.c @@ -36,6 +36,8 @@ #include "memory.h" #include +#include "tests.h" + enum { ITERS_FIRST = 0, diff --git a/tests/main.c b/tests/main.c index 5e7bdcb15..5396c7d50 100644 --- a/tests/main.c +++ b/tests/main.c @@ -52,7 +52,7 @@ DEFUN (daemon_exit, } static int timer_count; -int +static int test_timer (struct thread *thread) { int *count = THREAD_ARG(thread); diff --git a/tests/test-checksum.c b/tests/test-checksum.c index 9672e95a1..b6741f305 100644 --- a/tests/test-checksum.c +++ b/tests/test-checksum.c @@ -46,41 +46,6 @@ typedef uint16_t testoff_t; /* Fletcher Checksum -- Refer to RFC1008. */ #define MODX 4102 -/* Accumulator phase of checksum */ -static -struct acc_vals -accumulate (u_char *buffer, testsz_t len, testoff_t off) -{ - u_int8_t *p; - u_int16_t *csum; - int i, partial_len; - struct acc_vals ret; - - csum = (u_int16_t *) (buffer + off); - *(csum) = 0; - - p = buffer; - ret.c0 = 0; - ret.c1 = 0; - - while (len != 0) - { - partial_len = MIN(len, MODX); - - for (i = 0; i < partial_len; i++) - { - ret.c0 = ret.c0 + *(p++); - ret.c1 += ret.c0; - } - - ret.c0 = ret.c0 % 255; - ret.c1 = ret.c1 % 255; - - len -= partial_len; - } - return ret; -} - /* The final reduction phase. * This one should be the original ospfd version */ diff --git a/tests/test-segv.c b/tests/test-segv.c index 55bd25a59..1b851fc36 100644 --- a/tests/test-segv.c +++ b/tests/test-segv.c @@ -35,7 +35,7 @@ struct quagga_signal_t sigs[] = struct thread_master *master; -int +static int threadfunc (struct thread *thread) { int *null = NULL; diff --git a/tests/test-sig.c b/tests/test-sig.c index 7415d7ae6..f24da965c 100644 --- a/tests/test-sig.c +++ b/tests/test-sig.c @@ -22,19 +22,19 @@ #include "lib/log.h" #include "lib/memory.h" -void +static void sighup (void) { printf ("processed hup\n"); } -void +static void sigusr1 (void) { printf ("processed usr1\n"); } -void +static void sigusr2 (void) { printf ("processed usr2\n"); diff --git a/tests/test-timer-correctness.c b/tests/test-timer-correctness.c index 94c8f1df2..47c0b7376 100644 --- a/tests/test-timer-correctness.c +++ b/tests/test-timer-correctness.c @@ -140,8 +140,9 @@ int main(int argc, char **argv) interval_msec = prng_rand(prng) % 5000; arg = XMALLOC(MTYPE_TMP, TIMESTR_LEN + 1); timers[i] = thread_add_timer_msec(master, timer_func, arg, interval_msec); - ret = snprintf(arg, TIMESTR_LEN + 1, "%ld.%06ld", - timers[i]->u.sands.tv_sec, timers[i]->u.sands.tv_usec); + ret = snprintf(arg, TIMESTR_LEN + 1, "%lld.%06lld", + (long long)timers[i]->u.sands.tv_sec, + (long long)timers[i]->u.sands.tv_usec); assert(ret > 0); assert((size_t)ret < TIMESTR_LEN + 1); timers_pending++; @@ -180,7 +181,9 @@ int main(int argc, char **argv) ret = snprintf(expected_buf + expected_buf_pos, expected_buf_len - expected_buf_pos, - "%ld.%06ld\n", alarms[i]->tv_sec, alarms[i]->tv_usec); + "%lld.%06lld\n", + (long long)alarms[i]->tv_sec, + (long long)alarms[i]->tv_usec); assert(ret > 0); expected_buf_pos += ret; assert(expected_buf_pos < expected_buf_len); diff --git a/tests/tests.h b/tests/tests.h new file mode 100644 index 000000000..a528e55f0 --- /dev/null +++ b/tests/tests.h @@ -0,0 +1,31 @@ +/* + * Test wrappers common header file + * + * Copyright (C) 2015 by David Lamparter, + * for Open Source Routing./ NetDEF, Inc. + * + * 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 _QUAGGA_TESTS_H +#define _QUAGGA_TESTS_H + +extern void test_init (void); +extern void test_init_cmd (void); + +#endif /* _QUAGGA_TESTS_H */ From 6ed810d986df5d843c89166fee6b73a71222b7bd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 21 Apr 2015 10:13:07 +0200 Subject: [PATCH 0680/1342] *: fix more initialisers (for BSD) FreeBSD and NetBSD spew a few more warnings about variable initialisers. Found with OSR's/NetDEF's fancy new CI system. Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 4 ++-- ripngd/ripngd.c | 2 +- zebra/ioctl.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 33f802c16..416a3e511 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -131,8 +131,8 @@ route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { union sockunion *su; - union sockunion su_def = { .sin.sin_family = AF_INET, - .sin.sin_addr.s_addr = INADDR_ANY }; + union sockunion su_def = { .sin = { .sin_family = AF_INET, + .sin_addr.s_addr = INADDR_ANY } }; struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 82e381816..4c0b67dfc 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -1317,7 +1317,7 @@ ripng_read (struct thread *thread) int sock; struct sockaddr_in6 from; struct ripng_packet *packet; - unsigned int ifindex; + unsigned int ifindex = 0; struct interface *ifp; int hoplimit = -1; diff --git a/zebra/ioctl.c b/zebra/ioctl.c index d783b0a38..f7a7ff40b 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -52,7 +52,7 @@ if_ioctl (u_long request, caddr_t buffer) { int sock; int ret; - int err; + int err = 0; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); @@ -85,7 +85,7 @@ if_ioctl_ipv6 (u_long request, caddr_t buffer) { int sock; int ret; - int err; + int err = 0; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); From 193e78f2460a537695e34368a29fc5cd02e4e1f5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 21 Apr 2015 10:42:30 +0200 Subject: [PATCH 0681/1342] zebra: fix NetBSD interface stats printf "format '%qu' expects type 'long long unsigned int', but argument 3 has type '__uint64_t'" Move to %llu, which is more standard. Signed-off-by: David Lamparter --- zebra/interface.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 0271061e7..54d8b1038 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -836,24 +836,29 @@ if_dump_vty (struct vty *vty, struct interface *ifp) #ifdef HAVE_NET_RT_IFLIST #if defined (__bsdi__) || defined (__NetBSD__) /* Statistics print out using sysctl (). */ - vty_out (vty, " input packets %qu, bytes %qu, dropped %qu," - " multicast packets %qu%s", - ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, - ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, - VTY_NEWLINE); - - vty_out (vty, " input errors %qu%s", - ifp->stats.ifi_ierrors, VTY_NEWLINE); - - vty_out (vty, " output packets %qu, bytes %qu, multicast packets %qu%s", - ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, - ifp->stats.ifi_omcasts, VTY_NEWLINE); - - vty_out (vty, " output errors %qu%s", - ifp->stats.ifi_oerrors, VTY_NEWLINE); - - vty_out (vty, " collisions %qu%s", - ifp->stats.ifi_collisions, VTY_NEWLINE); + vty_out (vty, " input packets %llu, bytes %llu, dropped %llu," + " multicast packets %llu%s", + (unsigned long long)ifp->stats.ifi_ipackets, + (unsigned long long)ifp->stats.ifi_ibytes, + (unsigned long long)ifp->stats.ifi_iqdrops, + (unsigned long long)ifp->stats.ifi_imcasts, + VTY_NEWLINE); + + vty_out (vty, " input errors %llu%s", + (unsigned long long)ifp->stats.ifi_ierrors, VTY_NEWLINE); + + vty_out (vty, " output packets %llu, bytes %llu," + " multicast packets %llu%s", + (unsigned long long)ifp->stats.ifi_opackets, + (unsigned long long)ifp->stats.ifi_obytes, + (unsigned long long)ifp->stats.ifi_omcasts, + VTY_NEWLINE); + + vty_out (vty, " output errors %llu%s", + (unsigned long long)ifp->stats.ifi_oerrors, VTY_NEWLINE); + + vty_out (vty, " collisions %llu%s", + (unsigned long long)ifp->stats.ifi_collisions, VTY_NEWLINE); #else /* Statistics print out using sysctl (). */ vty_out (vty, " input packets %lu, bytes %lu, dropped %lu," From e691c3bb972c0baf610d9e210ce20ea6546e1de0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 21 Apr 2015 10:46:13 +0200 Subject: [PATCH 0682/1342] *: assorted warning fixes A few warnings slipped through the cracks... Signed-off-by: David Lamparter --- ospf6d/ospf6_lsa.c | 4 ++-- pimd/pim_int.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index b4348f466..3f008d3d9 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -807,8 +807,8 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) for (i = 0; i < MIN (size, sizeof (buf)); i++) { - if (! islower (h->name[i])) - buf[i] = tolower (h->name[i]); + if (! islower ((unsigned char)h->name[i])) + buf[i] = tolower ((unsigned char)h->name[i]); else buf[i] = h->name[i]; } diff --git a/pimd/pim_int.c b/pimd/pim_int.c index 2ff1a116e..0bdd772ff 100644 --- a/pimd/pim_int.c +++ b/pimd/pim_int.c @@ -22,6 +22,7 @@ #include #include +#include #include "pim_int.h" From 5bcbc3f58870bd28ab1deadfff75bf59d62db021 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 29 Oct 2014 10:33:17 +0000 Subject: [PATCH 0683/1342] gdb: Add a directory of files with gdb macros * gdb/: Directory to contain files with GDB macros. Organised by topic into separate files. * gdb/lib.txt: General OS API and Quagga lib macros: (def_ntohs) convert big-endian short to host order. (def_ntohl) convert big-endian long to host order. (walk_route_table_next) Walk to next route_node in a table, according to given top and current node arguments. (walk_route_table) walk the given route table dumping non-null info pointers, from the given root node. (dump_timeval) timeval to human readable output (dump_s_addr) Print IP address of given pointer to a (struct in_addr).s_addr (dump_s6_addr) Ditto for IPv6. (dump_prefix4) Dump a Quagga (struct prefix_ipv4 *) (dump_prefix6) Dump (struct prefix_ipv6 *) (dump_prefix) Dump a (struct prefix *). (rn_next_{down,up}) left-down and up-and-right walks of a route_table from a given route_node. * gdb/ospfd.txt: ospfd specific gdb macros, depends on gdb/lib.txt (dump_ospf_lsa_flags) LSA flags to text. (dump_ospf_lsa_data) dump the data of a (struct lsa_header *) argument. (dump_ospf_lsa) Dump the details of a (struct ospf_lsa *) (walk_ospf_lsdb) Go through an LSDB, rooted at the given (struct route_node *), and dump LSA details. (ospf_backbone_lsdb_top) Get the LSDB top pointer for the given LSA type. --- gdb/lib.txt | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/ospf.txt | 137 ++++++++++++++++++++++++ 2 files changed, 432 insertions(+) create mode 100644 gdb/lib.txt create mode 100644 gdb/ospf.txt diff --git a/gdb/lib.txt b/gdb/lib.txt new file mode 100644 index 000000000..b703808b4 --- /dev/null +++ b/gdb/lib.txt @@ -0,0 +1,295 @@ +# GDB macros for use with Quagga. +# +# Macros in this file are not daemon specific. E.g., OS or Quagga library +# APIs. +# +# The macro file can be loaded with 'source '. They can then be +# called by the user. Macros that explore more complicated structs generally +# take pointer arguments. +# +# E.g.: +# +# (gdb) source ~paul/code/quagga/gdb/lib.txt +# (gdb) break bgp_packet.c:613 +# Breakpoint 3 at 0x7fa883033a32: file bgp_packet.c, line 613. +# (gdb) cont +# ... +# (gdb) cont +# Breakpoint 3, bgp_write_packet (peer=0x7fa885199080) at bgp_packet.c:614 +# 614 if (CHECK_FLAG (adv->binfo->peer->cap,PEER_CAP_RESTART_RCV) +# (gdb) dump_prefix4 &adv->rn->p +# IPv4:10.1.1.0/24 +# (gdb) dump_prefix &adv->rn->p +# IPv4:10.1.1.0/24 +# + + +define def_ntohs + set $data = (char *)$arg0 + set $i = 0 + + set $_ = $data[$i++] << 8 + set $_ += $data[$i++] +end +document def_ntohs +Read a 2-byte short at the given pointed to area as big-endian and +return it in $_ + +Argument: Pointer to a 2-byte, big-endian short word. +Returns: Integer value of that word in $_ +end + +define def_ntohl + set $data = (char *)$arg0 + set $i = 0 + + set $_ = $data[$i++] << 24 + set $_ += $data[$i++] << 16 + set $_ += $data[$i++] << 8 + set $_ += $data[$i++] +end +document def_ntohl +Read a 4-byte integer at the given pointed to area as big-endian and +return it in $_ + +Argument: Pointer to a big-endian 4-byte word. +Returns: Integer value of that word in $_ +end + +# NB: This is in more complicated iterative form, rather than more +# conventional and simpler recursive form, because GDB has a recursion limit +# on macro calls (I think). +define walk_route_table_next + # callee saves + set $_top = $top + set $_node = $node + set $_prevl = $prevl + + set $top = (struct route_node *)$arg0 + set $node = (struct route_node *)$arg1 + set $prevl = $node + + # first try left + #echo try left\n + set $node = $prevl->link[0] + + # otherwise try right + if ($node == 0) + #echo left null, try right\n + set $node = $prevl->link[1] + end + + # otherwise go up, till we find the first right that + # we havn't been to yet + if ($node == 0) + set $node = $prevl + while ($node != $top) + #echo right null, try up and right\n + + set $prevl = $node + set $parent = $node->parent + set $node = $parent->link[1] + + if ($node != 0 && $node != $prevl) + #echo found node \n + loop_break + end + + #echo go up\n + set $node = $parent + end + end + + #printf "next node: 0x%x\n", $node + + set $_ = $node + + set $top = $_top + set $node = $_node + set $prevl = $_prevl +end +document walk_route_table_next +Return the next node to visit in the given route_table (or subset of) and +the given current node. + +Arguments: +1st: (struct route_node *) to the top of the route_table to walk +2nd: (struct route_node *) to the current node + +Returns: The (struct route_node *) for the next to visit in $_ +end + +define walk_route_table + set $_visited = $visited + set $_node = $node + set $top = $_top + + set $node = (struct route_node *)$arg0 + set $top = (struct route_node *)$arg0 + set $visited = 0 + + while ($node != 0) + printf "Node: 0x%x", $node + + if ($node->info != 0) + printf "\tinfo: 0x%x", $node->info + set $visited = $visited + 1 + end + + printf "\n" + + walk_route_table_next $top $node + set $node = $_ + + # we've gotten back to the top, finish + if ($node == $top) + set $node = 0 + end + end + printf "Visited: %u\n", $visited + + set $top = $_top + set $visited = $_visited + set $node = $_node +end + +document walk_route_table +Walk through a routing table (or subset thereof) and dump all the non-null +(struct route_node *)->info pointers. + +Argument: A lib/thread.h::(struct route_node *) pointing to the route_node +under which all data should be dumped +end + +define dump_timeval + set $tv = (struct timeval *)$arg0 + set $day = 3600*24 + + if $tv->tv_sec > $day + printf "%d days, ", $tv->tv_sec / $day + end + if $tv->tv_sec > 3600 + printf "%dh", $tv->tv_sec / 3600 + end + if ($tv->tv_sec % 3600) > 60 + printf "%dm", ($tv->tv_sec % 3600) / 60 + end + printf "%d", $tv->tv_sec % 3600 % 60 + if $tv->tv_usec != 0 + printf ".%06d", $tv->tv_usec + end + printf "s" +end +document dump_timeval +Human readable dump of a (struct timeval *) argument +end + +define dump_s_addr + set $addr = (char *)$arg0 + + printf "%d.%d.%d.%d", $addr[0], $addr[1], $addr[2], $addr[3] +end + +define dump_s6_addr + set $a6 = (char *)$arg0 + set $field = 0 + + while ($field < 16) + set $i1 = $field++ + set $i2 = $field++ + + printf "%x%x", $a6[$i1], $a6[$i2] + + if ($field > 2 && ($field % 4 == 0)) + printf ":" + end + end +end +document dump_s6_addr +Interpret the memory starting at given address as an IPv6 s6_addr and +print in human readable form. +end + +define dump_prefix4 + set $p = (struct prefix *) $arg0 + echo IPv4: + dump_s_addr &($p->u.prefix4) + printf "/%d\n", $p->prefixlen +end +document dump_prefix4 +Textual dump of a (struct prefix4 *) argument. +end + +define dump_prefix6 + set $p = (struct prefix *) $arg0 + echo IPv6: + dump_s6_addr &($p->u.prefix6) + printf "/%d\n", $p->prefixlen +end +document dump_prefix6 +Textual dump of a (struct prefix6 *) argument. +end + +define dump_prefix + set $p = $arg0 + + if ($p->family == 2) + dump_prefix4 $p + end + if ($p->family == 10) + dump_prefix6 $p + end +end +document dump_prefix +Human readable dump of a (struct prefix *) argument. +end + +define rn_next_down + set $node = $arg0 + while ($node != 0) + print/x $node + if ($node->link[0] != 0) + set $node = $node->link[0] + else + set $node = $node->link[1] + end + end +end + +document rn_next_down +Walk left-down a given route table, dumping locations of route_nodes + +Argument: A single (struct route_node *). +end + +define rn_next_up + set $top = (struct route_node *)$arg0 + set $node = (struct route_node *)$arg1 + + while ($node != $top) + echo walk up\n + + set $prevl = $node + set $parent = $node->parent + set $node = $parent->link[1] + + if ($node != 0 && $node != $prevl) + echo found a node\n + loop_break + end + + echo going up\n + set $node = $parent + end + output/x $node + echo \n +end + +document rn_next_up +Walk up-and-right from the given route_node to the next valid route_node +which is not the given "top" route_node + +Arguments: +1st: A (struct route_node *) to the top of the route table. +2nd: The (struct route_node *) to walk up from +end diff --git a/gdb/ospf.txt b/gdb/ospf.txt new file mode 100644 index 000000000..984104b85 --- /dev/null +++ b/gdb/ospf.txt @@ -0,0 +1,137 @@ +# GDB macros for use with Quagga. +# +# Macros in this file are specific to ospfd/. Definitions here depend on the +# lib.txt macros file, which must also be loaed. +# +# The macro file can be loaded with 'source '. They can then be +# called by the user. Macros that explore more complicated structs generally +# take pointer arguments. + +define dump_ospf_lsa_flags + set $flags = $arg0 + + printf "%u: ", $flags + + if $flags & 0x1 + echo Self, + end + if $flags & 0x2 + echo Self-checked, + end + if $flags & 0x4 + echo Recvd, + end + if $flags & 0x8 + echo Apprvd, + end + if $flags & 0x10 + echo Discard, + end + if $flags & 0x20 + echo Local-Xlt, + end + if $flags & 0x40 + echo Premature-Aged, + end + if $flags & 0x40 + echo In-Maxage, + end + echo \n +end + +define dump_ospf_lsa_data + set $lsad = (struct lsa_header *)$arg0 + + echo ID / AdvRtr: \t\t + dump_s_addr &$lsad->id.s_addr + echo \ : \ + dump_s_addr &$lsad->adv_router.s_addr + echo \n + + def_ntohs &$lsad->ls_age + printf "Type: %2u Age: %4u,", $lsad->type, $_ + + def_ntohs &$lsad->length + printf " length: %2u", $_ + + def_ntohl &$lsad->ls_seqnum + printf " Seqnum: 0x%08x", $_ + + def_ntohs &$lsad->checksum + printf " csum: 0x%04x\n", $_ + + # return the age + def_ntohs &$lsad->ls_age +end + +define dump_ospf_lsa + set $lsa = (struct ospf_lsa *)$arg0 + + #print/x *$lsa + + dump_ospf_lsa_data $lsa->data + + set $relage = $_ + (relative_time.tv_sec - $lsa->tv_recv.tv_sec) + printf "Relative age: %4u\n", $relage + + dump_ospf_lsa_flags $lsa->flags + + echo tv_recv: \ + dump_timeval &$lsa->tv_recv + echo \ tv_orig: \ + dump_timeval &$lsa->tv_orig + echo \n + + printf "lock %2u", $lsa->lock + printf " stat %2d", $lsa->stat + printf " rtx count: %u", $lsa->retransmit_counter + printf " rfsh list: %d", $lsa->refresh_list + printf "\n\n" +end + +define walk_ospf_lsdb + set $node = (struct route_node *)$arg0 + set $top = (struct route_node *)$arg0 + set $visited = 0 + + while ($node != 0) + set $prevl = $node + + if ($node->info != 0) + dump_ospf_lsa $node->info + set $visited = $visited + 1 + end + + walk_route_table_next $top $node + set $node = $_ + + # we've gotten back to the top, finish + if ($node == $top) + set $node = 0 + end + end + printf "Visited: %u\n", $visited +end + +document walk_ospf_lsdb +Walk through an OSPF LSDB (or subset thereof) and dump all the LSAs +contained there-in. + +Argument: A (struct route_node *) pointing to the top of the +LSDB route-table which should be dumped. +end + +define ospf_backbone_lsdb_top + set $type = $arg0 + + set $ospf = ospf_master->ospf->head->data + + output/x ((struct ospf *)$ospf)->backbone->lsdb->type[$type]->db->top + echo \n +end +document ospf_backbone_lsdb_top +Dump location of the LSDB in the backbone area for the given LSA type + +Argument: Integer LSA type +end + From f0996123fe12a0b5ea66b00475066474f48c84a0 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 27 Oct 2014 15:09:38 +0000 Subject: [PATCH 0684/1342] HACKING: Fix spelling mistakes Acked-by: Vincent Jardin --- HACKING.tex | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/HACKING.tex b/HACKING.tex index 6b27ebfb9..57235b160 100644 --- a/HACKING.tex +++ b/HACKING.tex @@ -57,7 +57,7 @@ \section{GUIDELINES FOR HACKING ON QUAGGA} See line 2 of HACKING.tex, the source for this document, for an example. This placeholder string will be expanded out by the `git archive' commands, -wihch is used to generate the tar archives for snapshots and releases. +which is used to generate the tar archives for snapshots and releases. Please document fully the proper use of a new function in the header file in which it is declared. And please consult existing headers for @@ -73,7 +73,7 @@ \section{GUIDELINES FOR HACKING ON QUAGGA} an orderly manner. If at all possible, try to retain the old deprecated interface as is, or functionally equivalent. Make a note of when the interface was deprecated and guard the deprecated interface definitions in -the header file, ie: +the header file, i.e.: \begin{verbatim} /* Deprecated: 20050406 */ @@ -172,9 +172,9 @@ \section{COMPILE-TIME CONDITIONAL CODE} Please think very carefully before making code conditional at compile time, as it increases maintenance burdens and user confusion. In particular, -please avoid gratuitious --enable-\ldots switches to the configure script - +please avoid gratuitous --enable-\ldots switches to the configure script - typically code should be good enough to be in Quagga, or it shouldn't be -there at all. +there at all. When code must be compile-time conditional, try have the compiler make it conditional rather than the C pre-processor - so that it will still be @@ -256,7 +256,7 @@ \section{COMMIT MESSAGES} This itemised commit messages allows reviewers to have confidence that the author has self-reviewed every line of the patch, as well as providing reviewers a clear index of which changes are intended, and descriptions for -them (C-to-english descriptions are not desireable - some discretion is +them (C-to-english descriptions are not desirable - some discretion is useful). For short patches, a per-function/file break-down may be redundant. For longer patches, such a break-down may be essential. A contrived example (where the general discussion is obviously somewhat @@ -299,7 +299,7 @@ \section{HACKING THE BUILD SYSTEM} \section{RELEASE PROCEDURE} \begin{itemize} -\item Tag the apppropriate commit with a release tag (follow existing +\item Tag the appropriate commit with a release tag (follow existing conventions). [This enables recreating the release, and is just good CM practice.] @@ -388,7 +388,7 @@ \section{GIT COMMIT SUBMISSION} \label{sec:git-submission} The preferred method for submitting changes is to provide git commits via a -publically-accessible git repository, which the maintainers can easily pull. +publicly-accessible git repository, which the maintainers can easily pull. The commits should be in a branch based off the Quagga.net master - a "feature branch". Ideally there should be no commits to this branch other @@ -440,8 +440,8 @@ \section{PATCH SUBMISSION} \item Do not make gratuitous changes to whitespace. See the w and b arguments to diff. -\item Changes should be arranged so that the least contraversial and most - trivial are first, and the most complex or more contraversial are +\item Changes should be arranged so that the least controversial and most + trivial are first, and the most complex or more controversial are last. This will maximise how many the Quagga maintainers can merge, even if some other commits need further work. @@ -473,7 +473,7 @@ \section{PATCH APPLICATION} \item Only apply patches that meet the submission guidelines. \item If the patch might break something, issue a call for testing on the - mailinglist. + mailing-list. \item Give an appropriate commit message (see above), and use the --author argument to git-commit, if required, to ensure proper attribution (you From 4da670b7a9aacf552aa11c4d4f6d994b312ada89 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 27 Oct 2014 15:14:06 +0000 Subject: [PATCH 0685/1342] HACKING: Use space char for indentation. * HACKING.tex: Whitespace/indent section is probably out of date. Rephrase. Remove the editor recommendations, as I don't know what would be correct. Acked-by: Vincent Jardin --- HACKING.tex | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/HACKING.tex b/HACKING.tex index 57235b160..be86ae18d 100644 --- a/HACKING.tex +++ b/HACKING.tex @@ -21,23 +21,12 @@ \section{GUIDELINES FOR HACKING ON QUAGGA} GNU coding standards apply. Indentation follows the result of -invoking GNU indent (as of 2.2.8a) with no arguments. Note that this -uses tabs instead of spaces where possible for leading whitespace, and -assumes that tabs are every 8 columns. Do not attempt to redefine the -location of tab stops. Note also that some indentation does not -follow GNU style. This is a historical accident, and we generally -only clean up whitespace when code is unmaintainable due to whitespace -issues, to minimise merging conflicts. - -For GNU emacs, use indentation style ``gnu''. - -For Vim, use the following lines (note that tabs are at 8, and that -softtabstop sets the indentation level): - -set tabstop=8 -set softtabstop=2 -set shiftwidth=2 -set noexpandtab +invoking GNU indent (as of 2.2.8a) with the --nut argument. + +Originally, tabs were used instead of spaces, with tabs are every 8 columns. +However, tab's interoperability issues mean space characters are now preferred for +new changes. We generally only clean up whitespace when code is unmaintainable +due to whitespace issues, to minimise merging conflicts. Be particularly careful not to break platforms/protocols that you cannot test. From 491417ac6383e2ea557951b24eb7bd3fffb69394 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Thu, 23 Apr 2015 15:36:55 -0700 Subject: [PATCH 0686/1342] isisd: fix crash on processing own p2p hello isis_pdu.c : isisd crashes if router's own p2p hello packets get processed thereby creating an adjacecncy with itself. Asserts at isis_find_vertex. So discard own p2p IIH PDU and avoid creating adjacency with self. This would also fix duplicate systemID on an interface. These checks already exists for IS-IS LAN Level 1/2 Hello PDU in process_lan_hello, but not for point-to-point IIH PDUs. Signed-off-by: Amritha Nambiar Signed-off-by: David Lamparter --- isisd/isis_pdu.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 02b50bf48..7c04f44a1 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -561,6 +561,17 @@ process_p2p_hello (struct isis_circuit *circuit) return ISIS_WARNING; } + /* + * it's own p2p IIH PDU - discard + */ + if (!memcmp (hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) + { + zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded", + circuit->area->area_tag); + free_tlvs (&tlvs); + return ISIS_WARNING; + } + /* * My interpertation of the ISO, if no adj exists we will create one for * the circuit From e38545bb2cd155306fd78223e0c579117fcfae90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:42:59 +0300 Subject: [PATCH 0687/1342] zebra: fix build with rtadv disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we get warning on rtadv_init() prototype not being defined when compiling rtadv.c (as dummy stub is provided always). Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- zebra/rtadv.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 8cb933e0b..1e1aec9ac 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -59,7 +59,6 @@ struct rtadv_prefix }; extern void rtadv_config_write (struct vty *, struct interface *); -extern void rtadv_init (void); /* RFC4584 Extension to Sockets API for Mobile IPv6 */ @@ -101,4 +100,6 @@ extern const char *rtadv_pref_strs[]; #endif /* RTADV */ +extern void rtadv_init (void); + #endif /* _ZEBRA_RTADV_H */ From b40e178af12570467f0116d6b1684cb1b961e407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:43:00 +0300 Subject: [PATCH 0688/1342] zebra: fix rtadv check for non-glibc linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Default RTADV enabled for non-glibc linux (fixes check for musl libc). Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- zebra/interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/interface.h b/zebra/interface.h index 2f3b7b93f..0f081f6b3 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -38,7 +38,7 @@ #define IF_ZEBRA_SHUTDOWN_ON 1 /* Router advertisement feature. */ -#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) +#if (defined(LINUX_IPV6) && (!defined(__GLIBC__) || defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) #ifdef HAVE_RTADV #define RTADV #endif From 81b139bdd530adda045d22a4daf0054b89703dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:43:01 +0300 Subject: [PATCH 0689/1342] lib: constify sockunion api MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add const to read-only api calls. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/sockunion.c | 22 +++++++++++----------- lib/sockunion.h | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/sockunion.c b/lib/sockunion.c index 1a355d3b3..5e6cf6860 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -116,7 +116,7 @@ inet_ntop (int family, const void *addrptr, char *strptr, size_t len) #endif /* ! HAVE_INET_NTOP */ const char * -inet_sutop (union sockunion *su, char *str) +inet_sutop (const union sockunion *su, char *str) { switch (su->sa.sa_family) { @@ -163,7 +163,7 @@ str2sockunion (const char *str, union sockunion *su) } const char * -sockunion2str (union sockunion *su, char *buf, size_t len) +sockunion2str (const union sockunion *su, char *buf, size_t len) { if (su->sa.sa_family == AF_INET) return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); @@ -207,7 +207,7 @@ sockunion_normalise_mapped (union sockunion *su) /* Return socket of sockunion. */ int -sockunion_socket (union sockunion *su) +sockunion_socket (const union sockunion *su) { int sock; @@ -237,7 +237,7 @@ sockunion_accept (int sock, union sockunion *su) /* Return sizeof union sockunion. */ static int -sockunion_sizeof (union sockunion *su) +sockunion_sizeof (const union sockunion *su) { int ret; @@ -258,7 +258,7 @@ sockunion_sizeof (union sockunion *su) /* return sockunion structure : this function should be revised. */ static const char * -sockunion_log (union sockunion *su, char *buf, size_t len) +sockunion_log (const union sockunion *su, char *buf, size_t len) { switch (su->sa.sa_family) { @@ -282,7 +282,7 @@ sockunion_log (union sockunion *su, char *buf, size_t len) 0 : connect success 1 : connect is in progress */ enum connect_result -sockunion_connect (int fd, union sockunion *peersu, unsigned short port, +sockunion_connect (int fd, const union sockunion *peersu, unsigned short port, unsigned int ifindex) { int ret; @@ -547,7 +547,7 @@ sockopt_v6only (int family, int sock) /* If same family and same prefix return 1. */ int -sockunion_same (union sockunion *su1, union sockunion *su2) +sockunion_same (const union sockunion *su1, const union sockunion *su2) { int ret = 0; @@ -666,7 +666,7 @@ sockunion_getpeername (int fd) /* Print sockunion structure */ static void __attribute__ ((unused)) -sockunion_print (union sockunion *su) +sockunion_print (const union sockunion *su) { if (su == NULL) return; @@ -705,7 +705,7 @@ sockunion_print (union sockunion *su) #ifdef HAVE_IPV6 static int -in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2) +in6addr_cmp (const struct in6_addr *addr1, const struct in6_addr *addr2) { unsigned int i; u_char *p1, *p2; @@ -725,7 +725,7 @@ in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2) #endif /* HAVE_IPV6 */ int -sockunion_cmp (union sockunion *su1, union sockunion *su2) +sockunion_cmp (const union sockunion *su1, const union sockunion *su2) { if (su1->sa.sa_family > su2->sa.sa_family) return 1; @@ -750,7 +750,7 @@ sockunion_cmp (union sockunion *su1, union sockunion *su2) /* Duplicate sockunion. */ union sockunion * -sockunion_dup (union sockunion *su) +sockunion_dup (const union sockunion *su) { union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); memcpy (dup, su, sizeof (union sockunion)); diff --git a/lib/sockunion.h b/lib/sockunion.h index b9f351424..2c79fb5c6 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -84,9 +84,9 @@ enum connect_result /* Prototypes. */ extern int str2sockunion (const char *, union sockunion *); -extern const char *sockunion2str (union sockunion *, char *, size_t); -extern int sockunion_cmp (union sockunion *, union sockunion *); -extern int sockunion_same (union sockunion *, union sockunion *); +extern const char *sockunion2str (const union sockunion *, char *, size_t); +extern int sockunion_cmp (const union sockunion *, const union sockunion *); +extern int sockunion_same (const union sockunion *, const union sockunion *); extern union sockunion *sockunion_str2su (const char *str); extern int sockunion_accept (int sock, union sockunion *); @@ -99,14 +99,14 @@ extern int sockunion_bind (int sock, union sockunion *, extern int sockopt_ttl (int family, int sock, int ttl); extern int sockopt_minttl (int family, int sock, int minttl); extern int sockopt_cork (int sock, int onoff); -extern int sockunion_socket (union sockunion *su); -extern const char *inet_sutop (union sockunion *su, char *str); -extern enum connect_result sockunion_connect (int fd, union sockunion *su, +extern int sockunion_socket (const union sockunion *su); +extern const char *inet_sutop (const union sockunion *su, char *str); +extern enum connect_result sockunion_connect (int fd, const union sockunion *su, unsigned short port, unsigned int); extern union sockunion *sockunion_getsockname (int); extern union sockunion *sockunion_getpeername (int); -extern union sockunion *sockunion_dup (union sockunion *); +extern union sockunion *sockunion_dup (const union sockunion *); extern void sockunion_free (union sockunion *); #ifndef HAVE_INET_NTOP From 10bac80195cf5a781da6e4415e6580fd7080f734 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 5 May 2015 11:10:20 +0200 Subject: [PATCH 0690/1342] lib/cli: reduce strcmp in CLI hot paths Er, no idea how anyone could ever have thought that it would be a good idea to have a zillion of strcmp() calls in the CLI's active paths, just to compare against things like "A.B.C.D". Reduces 40k prefix list load time from 1.65s to 1.23s (1.34:1). Acked-by: Paul Jakma [v2: killed CMDS_* macros] Signed-off-by: David Lamparter --- lib/command.c | 284 ++++++++++++++++++++++++++++---------------------- lib/command.h | 26 +++-- 2 files changed, 174 insertions(+), 136 deletions(-) diff --git a/lib/command.c b/lib/command.c index f20065f13..922e7b581 100644 --- a/lib/command.c +++ b/lib/command.c @@ -506,6 +506,25 @@ format_parser_read_word(struct format_parser_state *state) token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); token->type = TOKEN_TERMINAL; + if (cmd[0] == '[') + token->terminal = TERMINAL_OPTION; + else if ((cmd[0] >= 'A' && cmd[0] <= 'Z') || (cmd[0] == '<')) + token->terminal = TERMINAL_VARIABLE; + else if (cmd[0] == '.') + token->terminal = TERMINAL_VARARG; + else if (cmd[0] == '<') + token->terminal = TERMINAL_RANGE; + else if (strcmp (cmd, "A.B.C.D") == 0) + token->terminal = TERMINAL_IPV4; + else if (strcmp (cmd, "A.B.C.D/M") == 0) + token->terminal = TERMINAL_IPV4_PREFIX; + else if (strcmp (cmd, "X:X::X:X") == 0) + token->terminal = TERMINAL_IPV6; + else if (strcmp (cmd, "X:X::X:X/M") == 0) + token->terminal = TERMINAL_IPV6_PREFIX; + else + token->terminal = TERMINAL_LITERAL; + token->cmd = cmd; token->desc = format_parser_desc_str(state); vector_set(state->curvect, token); @@ -1171,59 +1190,61 @@ cmd_word_match(struct cmd_token *token, if (!word) return no_match; - if (CMD_VARARG(str)) - { - return vararg_match; - } - else if (CMD_RANGE(str)) - { - if (cmd_range_match(str, word)) - return range_match; - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6(str)) - { - match_type = cmd_ipv6_match(word); - if ((filter == FILTER_RELAXED && match_type != no_match) - || (filter == FILTER_STRICT && match_type == exact_match)) - return ipv6_match; - } - else if (CMD_IPV6_PREFIX(str)) - { - match_type = cmd_ipv6_prefix_match(word); - if ((filter == FILTER_RELAXED && match_type != no_match) - || (filter == FILTER_STRICT && match_type == exact_match)) - return ipv6_prefix_match; - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4(str)) - { - match_type = cmd_ipv4_match(word); - if ((filter == FILTER_RELAXED && match_type != no_match) - || (filter == FILTER_STRICT && match_type == exact_match)) - return ipv4_match; - } - else if (CMD_IPV4_PREFIX(str)) + switch (token->terminal) { - match_type = cmd_ipv4_prefix_match(word); - if ((filter == FILTER_RELAXED && match_type != no_match) + case TERMINAL_VARARG: + return vararg_match; + + case TERMINAL_RANGE: + if (cmd_range_match(str, word)) + return range_match; + break; + + case TERMINAL_IPV6: + match_type = cmd_ipv6_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) || (filter == FILTER_STRICT && match_type == exact_match)) - return ipv4_prefix_match; - } - else if (CMD_OPTION(str) || CMD_VARIABLE(str)) - { - return extend_match; - } - else - { - if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word))) - { - if (!strcmp(str, word)) - return exact_match; - return partly_match; - } - if (filter == FILTER_STRICT && !strcmp(str, word)) - return exact_match; + return ipv6_match; + break; + + case TERMINAL_IPV6_PREFIX: + match_type = cmd_ipv6_prefix_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv6_prefix_match; + break; + + case TERMINAL_IPV4: + match_type = cmd_ipv4_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv4_match; + break; + + case TERMINAL_IPV4_PREFIX: + match_type = cmd_ipv4_prefix_match(word); + if ((filter == FILTER_RELAXED && match_type != no_match) + || (filter == FILTER_STRICT && match_type == exact_match)) + return ipv4_prefix_match; + break; + + case TERMINAL_OPTION: + case TERMINAL_VARIABLE: + return extend_match; + + case TERMINAL_LITERAL: + if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word))) + { + if (!strcmp(str, word)) + return exact_match; + return partly_match; + } + if (filter == FILTER_STRICT && !strcmp(str, word)) + return exact_match; + break; + + default: + assert (0); } return no_match; @@ -1307,7 +1328,7 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher, if (!cmd_matcher_words_left(matcher)) { - if (CMD_OPTION(token->cmd)) + if (token->terminal == TERMINAL_OPTION) return MATCHER_OK; /* missing optional args are NOT pushed as NULL */ else return MATCHER_INCOMPLETE; @@ -1320,9 +1341,9 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher, /* We have to record the input word as argument if it matched * against a variable. */ - if (CMD_VARARG(token->cmd) - || CMD_VARIABLE(token->cmd) - || CMD_OPTION(token->cmd)) + if (token->terminal == TERMINAL_VARARG + || token->terminal == TERMINAL_VARIABLE + || token->terminal == TERMINAL_OPTION) { if (push_argument(argc, argv, word)) return MATCHER_EXCEED_ARGC_MAX; @@ -1333,7 +1354,7 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher, matcher->word_index++; /* A vararg token should consume all left over words as arguments */ - if (CMD_VARARG(token->cmd)) + if (token->terminal == TERMINAL_VARARG) while (cmd_matcher_words_left(matcher)) { word = cmd_matcher_get_word(matcher); @@ -1564,9 +1585,9 @@ cmd_matcher_build_keyword_args(struct cmd_matcher *matcher, { word_token = vector_slot(keyword_vector, j); if ((word_token->type == TOKEN_TERMINAL - && (CMD_VARARG(word_token->cmd) - || CMD_VARIABLE(word_token->cmd) - || CMD_OPTION(word_token->cmd))) + && (word_token->terminal == TERMINAL_VARARG + || word_token->terminal == TERMINAL_VARIABLE + || word_token->terminal == TERMINAL_OPTION)) || word_token->type == TOKEN_MULTIPLE) { if (push_argument(argc, argv, NULL)) @@ -1852,12 +1873,14 @@ is_cmd_ambiguous (vector cmd_vector, switch (type) { case exact_match: - if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) + if (!(cmd_token->terminal == TERMINAL_OPTION + || cmd_token->terminal == TERMINAL_VARIABLE) && strcmp (command, str) == 0) match++; break; case partly_match: - if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) + if (!(cmd_token->terminal == TERMINAL_OPTION + || cmd_token->terminal == TERMINAL_VARIABLE) && strncmp (command, str, strlen (command)) == 0) { if (matched && strcmp (matched, str) != 0) @@ -1879,7 +1902,7 @@ is_cmd_ambiguous (vector cmd_vector, break; #ifdef HAVE_IPV6 case ipv6_match: - if (CMD_IPV6 (str)) + if (cmd_token->terminal == TERMINAL_IPV6) match++; break; case ipv6_prefix_match: @@ -1893,7 +1916,7 @@ is_cmd_ambiguous (vector cmd_vector, break; #endif /* HAVE_IPV6 */ case ipv4_match: - if (CMD_IPV4 (str)) + if (cmd_token->terminal == TERMINAL_IPV4) match++; break; case ipv4_prefix_match: @@ -1906,7 +1929,8 @@ is_cmd_ambiguous (vector cmd_vector, } break; case extend_match: - if (CMD_OPTION (str) || CMD_VARIABLE (str)) + if (cmd_token->terminal == TERMINAL_OPTION + || cmd_token->terminal == TERMINAL_VARIABLE) match++; break; case no_match: @@ -1922,12 +1946,23 @@ is_cmd_ambiguous (vector cmd_vector, /* If src matches dst return dst string, otherwise return NULL */ static const char * -cmd_entry_function (const char *src, const char *dst) +cmd_entry_function (const char *src, struct cmd_token *token) { + const char *dst = token->cmd; + /* Skip variable arguments. */ - if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) || - CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst)) - return NULL; + switch (token->terminal) + { + case TERMINAL_OPTION: + case TERMINAL_VARIABLE: + case TERMINAL_VARARG: + case TERMINAL_IPV4: + case TERMINAL_IPV4_PREFIX: + case TERMINAL_RANGE: + return NULL; + default: + break; + } /* In case of 'command \t', given src is NULL string. */ if (src == NULL) @@ -1944,65 +1979,63 @@ cmd_entry_function (const char *src, const char *dst) /* This version will return the dst string always if it is CMD_VARIABLE for '?' key processing */ static const char * -cmd_entry_function_desc (const char *src, const char *dst) +cmd_entry_function_desc (const char *src, struct cmd_token *token) { - if (CMD_VARARG (dst)) - return dst; - - if (CMD_RANGE (dst)) - { - if (cmd_range_match (dst, src)) - return dst; - else - return NULL; - } - -#ifdef HAVE_IPV6 - if (CMD_IPV6 (dst)) - { - if (cmd_ipv6_match (src)) - return dst; - else - return NULL; - } - - if (CMD_IPV6_PREFIX (dst)) - { - if (cmd_ipv6_prefix_match (src)) - return dst; - else - return NULL; - } -#endif /* HAVE_IPV6 */ + const char *dst = token->cmd; - if (CMD_IPV4 (dst)) + switch (token->terminal) { - if (cmd_ipv4_match (src)) - return dst; - else - return NULL; - } - - if (CMD_IPV4_PREFIX (dst)) - { - if (cmd_ipv4_prefix_match (src)) - return dst; - else - return NULL; + case TERMINAL_VARARG: + return dst; + + case TERMINAL_RANGE: + if (cmd_range_match (dst, src)) + return dst; + else + return NULL; + + case TERMINAL_IPV6: + if (cmd_ipv6_match (src)) + return dst; + else + return NULL; + + case TERMINAL_IPV6_PREFIX: + if (cmd_ipv6_prefix_match (src)) + return dst; + else + return NULL; + + case TERMINAL_IPV4: + if (cmd_ipv4_match (src)) + return dst; + else + return NULL; + + case TERMINAL_IPV4_PREFIX: + if (cmd_ipv4_prefix_match (src)) + return dst; + else + return NULL; + + /* Optional or variable commands always match on '?' */ + case TERMINAL_OPTION: + case TERMINAL_VARIABLE: + return dst; + + case TERMINAL_LITERAL: + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + else + return NULL; + + default: + assert(0); } - - /* Optional or variable commands always match on '?' */ - if (CMD_OPTION (dst) || CMD_VARIABLE (dst)) - return dst; - - /* In case of 'command \t', given src is NULL string. */ - if (src == NULL) - return dst; - - if (strncmp (src, dst, strlen (src)) == 0) - return dst; - else - return NULL; } /** @@ -2217,7 +2250,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) struct cmd_token *token = vector_slot(match_vector, j); const char *string; - string = cmd_entry_function_desc(command, token->cmd); + string = cmd_entry_function_desc(command, token); if (string && desc_unique_string(matchvec, string)) vector_set(matchvec, token); } @@ -2419,7 +2452,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) { if ((string = cmd_entry_function (vector_slot (vline, index), - token->cmd))) + token))) if (cmd_unique_string (matchvec, string)) vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); } @@ -4007,6 +4040,7 @@ cmd_init (int terminal) { command_cr = XSTRDUP(MTYPE_CMD_TOKENS, ""); token_cr.type = TOKEN_TERMINAL; + token_cr.terminal = TERMINAL_LITERAL; token_cr.cmd = command_cr; token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, ""); diff --git a/lib/command.h b/lib/command.h index 8eb0cbd96..3a95df93a 100644 --- a/lib/command.h +++ b/lib/command.h @@ -151,10 +151,25 @@ enum cmd_token_type TOKEN_KEYWORD, }; +enum cmd_terminal_type +{ + _TERMINAL_BUG = 0, + TERMINAL_LITERAL, + TERMINAL_OPTION, + TERMINAL_VARIABLE, + TERMINAL_VARARG, + TERMINAL_RANGE, + TERMINAL_IPV4, + TERMINAL_IPV4_PREFIX, + TERMINAL_IPV6, + TERMINAL_IPV6_PREFIX, +}; + /* Command description structure. */ struct cmd_token { enum cmd_token_type type; + enum cmd_terminal_type terminal; /* Used for type == MULTIPLE */ vector multiple; /* vector of cmd_token, type == FINAL */ @@ -437,17 +452,6 @@ struct cmd_token #endif /* VTYSH_EXTRACT_PL */ -/* Some macroes */ -#define CMD_OPTION(S) ((S[0]) == '[') -#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) -#define CMD_VARARG(S) ((S[0]) == '.') -#define CMD_RANGE(S) ((S[0] == '<')) - -#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) -#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) -#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) -#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) - /* Common descriptions. */ #define SHOW_STR "Show running system information\n" #define IP_STR "IP information\n" From e1bcd4741c24ff990a9413ead9a9e37b80153046 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 19 Sep 2014 16:41:10 +0100 Subject: [PATCH 0691/1342] ospfd: Make ospf_passive_interface_update calls friendly to static analysis * ospf_vty.c: ({no_}ospf_passive_interface_addr_cmd) To a static analyser, the call to ospf_passive_interface_update can look like uninitialised memory in addr might be read from. It won't be, as ospf_passive_interface_update only reads addr if params != IF_DEF_PARAMS, but not clear. Split up the helper into the two cases to make it clear. --- ospfd/ospf_vty.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 72493a201..2fcdedc1e 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -254,9 +254,9 @@ ospf_passive_interface_default (struct ospf *ospf, u_char newval) } static void -ospf_passive_interface_update (struct ospf *ospf, struct interface *ifp, - struct in_addr addr, - struct ospf_if_params *params, u_char value) +ospf_passive_interface_update_addr (struct ospf *ospf, struct interface *ifp, + struct ospf_if_params *params, u_char value, + struct in_addr addr) { u_char dflt; @@ -276,7 +276,14 @@ ospf_passive_interface_update (struct ospf *ospf, struct interface *ifp, ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } - else +} + +static void +ospf_passive_interface_update (struct ospf *ospf, struct interface *ifp, + struct ospf_if_params *params, u_char value) +{ + params->passive_interface = value; + if (params == IF_DEF_PARAMS (ifp)) { if (value != ospf->passive_interface_default) SET_IF_PARAM (params, passive_interface); @@ -320,8 +327,11 @@ DEFUN (ospf_passive_interface, params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); + ospf_passive_interface_update_addr (ospf, ifp, params, + OSPF_IF_PASSIVE, addr); } - ospf_passive_interface_update (ospf, ifp, addr, params, OSPF_IF_PASSIVE); + + ospf_passive_interface_update (ospf, ifp, params, OSPF_IF_PASSIVE); /* XXX We should call ospf_if_set_multicast on exactly those * interfaces for which the passive property changed. It is too much @@ -397,9 +407,11 @@ DEFUN (no_ospf_passive_interface, params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; + ospf_passive_interface_update_addr (ospf, ifp, params, OSPF_IF_ACTIVE, + addr); } - ospf_passive_interface_update (ospf, ifp, addr, params, OSPF_IF_ACTIVE); - + ospf_passive_interface_update (ospf, ifp, params, OSPF_IF_ACTIVE); + /* XXX We should call ospf_if_set_multicast on exactly those * interfaces for which the passive property changed. It is too much * work to determine this set, so we do this for every interface. From e30677a5537f67e37938954cf7347e9a9c0b922d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 20 Jan 2015 15:45:36 +0000 Subject: [PATCH 0692/1342] ospfd: Remove the blocking of opaque LSAs origination & flooding 'optimisation' * Opaque support contains some kind of hack/optimisation to origination/flooding to suppress some origins/floods until an opaque LS Acks are received. Previous versions of the code have already been shown to have bugs in them (see e16fd8a5, e.g.). It seems over-complex and fragile, plus its conceptually the wrong place to try implement flooding hacks that, AFAICT, do not depend particularly on the semantics of opaque LSA. Nuke. Tested-by: Olivier Dugeon --- ospfd/ospf_flood.c | 10 --- ospfd/ospf_opaque.c | 205 +------------------------------------------- ospfd/ospf_opaque.h | 20 ----- ospfd/ospf_packet.c | 9 +- ospfd/ospf_vty.c | 4 +- ospfd/ospfd.h | 3 - 6 files changed, 6 insertions(+), 245 deletions(-) diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index c0b362285..0e42ff54e 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -430,16 +430,6 @@ ospf_flood_through_interface (struct ospf_interface *oi, zlog_debug ("Skip this neighbor: Not Opaque-capable."); continue; } - - if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (oi->ospf->opaque) - && IS_LSA_SELF (lsa) - && onbr->state == NSM_Full) - { - /* Small attempt to reduce unnecessary retransmission. */ - if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("Skip this neighbor: Initial flushing done."); - continue; - } } #endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index ecb28ffe3..d449c9507 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1311,13 +1311,7 @@ ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) zlog_debug ("ospf_opaque_lsa_originate_schedule: Not operational."); goto out; /* This is not an error. */ } - if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_opaque_lsa_originate_schedule: Under blockade."); - goto out; /* This is not an error, too. */ - } - + if (delay0 != NULL) delay = *delay0; @@ -1759,13 +1753,7 @@ ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Not operational."); goto out; /* This is not an error. */ } - if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Under blockade."); - goto out; /* This is not an error, too. */ - } - + /* Generate a dummy lsa to be passed for a lookup function. */ lsa = pseudo_lsa (oi, area, lsa_type, opaque_type); @@ -2126,12 +2114,6 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) *------------------------------------------------------------------------*/ static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); -#ifdef BUGGY_UNLOCK -static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); -static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); -static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); -static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); -#endif /* BUGGY_UNLOCK */ void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas) @@ -2240,13 +2222,10 @@ ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; - u_char before; - + if ((top = oi_to_top (nbr->oi)) == NULL) return; - before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque); - /* * Since these LSA entries are not yet installed into corresponding * LSDB, just flush them without calling ospf_ls_maxage() afterward. @@ -2255,196 +2234,20 @@ ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: - SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AREA_LSA: - SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AS_LSA: - SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); ospf_flood_through_as (top, NULL/*inbr*/, lsa); break; default: zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type); return; } - - ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ - - if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Block Opaque-LSA origination: OFF -> ON"); - } -} - -void -ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) -{ - struct ospf *top; - int delay; - struct ospf_interface *oi; - struct listnode *node, *nnode; - - if ((top = oi_to_top (nbr->oi)) == NULL) - return; - - if (!IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) - return; - - switch (lsa->data->type) - { - case OSPF_OPAQUE_LINK_LSA: - if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) - UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); - /* BUGGY_UNLOCK: ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); */ - /* Callback function... */ - break; - case OSPF_OPAQUE_AREA_LSA: - if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) - UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); - /* BUGGY_UNLOCK: ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); */ - /* Callback function... */ - break; - case OSPF_OPAQUE_AS_LSA: - if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) - UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); - /* BUGGY_UNLOCK: ospf_opaque_type11_lsa_rxmt_nbr_check (top); */ - /* Callback function... */ - break; - default: - zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type); - return; - } - - if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) - return; /* Blocking still in progress. */ - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Block Opaque-LSA origination: ON -> OFF"); - - if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) - return; /* Opaque capability condition must have changed. */ - - /* Ok, let's start origination of Opaque-LSAs. */ - delay = OSPF_MIN_LS_INTERVAL; - - for (ALL_LIST_ELEMENTS (top->oiflist, node, nnode, oi)) - { - if (! ospf_if_is_enable (oi) - || ospf_nbr_count_opaque_capable (oi) == 0) - continue; - - ospf_opaque_lsa_originate_schedule (oi, &delay); - } - - return; -} - -#ifdef BUGGY_UNLOCK -static void -ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) -{ - unsigned long n; - - n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA); - if (n == 0) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi)); - - UNSET_FLAG (oi->area->ospf->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); - } - return; -} - -static void -ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area) -{ - struct listnode *node; - struct ospf_interface *oi; - unsigned long n = 0; - - for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) - { - if (area->area_id.s_addr != OSPF_AREA_BACKBONE - && oi->type == OSPF_IFTYPE_VIRTUALLINK) - continue; - - n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA); - if (n > 0) - break; - } - - if (n == 0) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id)); - - UNSET_FLAG (area->ospf->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); - } - - return; -} - -static void -ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top) -{ - struct listnode *node; - struct ospf_interface *oi; - unsigned long n = 0; - - for (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi)) - { - switch (oi->type) - { - case OSPF_IFTYPE_VIRTUALLINK: - continue; - default: - break; - } - - n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA); - if (n > 0) - goto out; - } - - if (n == 0) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Self-originated type-11 Opaque-LSAs: Flush completed"); - - UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); - } - -out: - return; -} - -static unsigned long -ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) -{ - struct route_node *rn; - struct ospf_neighbor *nbr; - struct ospf *top; - unsigned long n = 0; - - for (rn = route_top (nbrs); rn; rn = route_next (rn)) - { - if ((nbr = rn->info) == NULL) - continue; - if ((top = oi_to_top (nbr->oi)) == NULL) - continue; - if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id)) - continue; - n += ospf_ls_retransmit_count_self (nbr, lsa_type); - } - - return n; + ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ } -#endif /* BUGGY_UNLOCK */ /*------------------------------------------------------------------------* * Followings are util functions; probably be used by Opaque-LSAs only... diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index 227306456..077da6274 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -31,23 +31,6 @@ (type) == OSPF_OPAQUE_AREA_LSA || \ (type) == OSPF_OPAQUE_AS_LSA) -/* - * Usage of Opaque-LSA administrative flags in "struct ospf". - * - * 7 6 5 4 3 2 1 0 - * +---+---+---+---+---+---+---+---+ - * |///|///|///|///|B11|B10|B09| O | - * +---+---+---+---+---+---+---+---+ - * |<--------->| A - * | +--- Operation status (operational = 1) - * +----------- Blocking status for each LSA type - */ - -#define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \ - CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \ - OPAQUE_BLOCK_TYPE_10_LSA_BIT | \ - OPAQUE_BLOCK_TYPE_11_LSA_BIT)) - /* * Opaque LSA's link state ID is redefined as follows. * @@ -156,9 +139,6 @@ extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); -extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, - struct ospf_lsa *lsa); - extern void htonf (float *src, float *dst); extern void ntohf (float *src, float *dst); extern struct ospf *oi_to_top (struct ospf_interface *oi); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b97e3a79b..d59765372 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2125,14 +2125,7 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh, lsr = ospf_ls_retransmit_lookup (nbr, lsa); if (lsr != NULL && ospf_lsa_more_recent (lsr, lsa) == 0) - { -#ifdef HAVE_OPAQUE_LSA - if (IS_OPAQUE_LSA (lsr->data->type)) - ospf_opaque_ls_ack_received (nbr, lsr); -#endif /* HAVE_OPAQUE_LSA */ - - ospf_ls_retransmit_delete (nbr, lsr); - } + ospf_ls_retransmit_delete (nbr, lsr); lsa->data = NULL; ospf_lsa_discard (lsa); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 2fcdedc1e..d57eb41d0 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2723,11 +2723,9 @@ DEFUN (show_ip_ospf, CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE) ? "enabled" : "disabled", VTY_NEWLINE); #ifdef HAVE_OPAQUE_LSA - vty_out (vty, " OpaqueCapability flag is %s%s%s", + vty_out (vty, " OpaqueCapability flag is %s%s", CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? "enabled" : "disabled", - IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf->opaque) ? - " (origination blocked)" : "", VTY_NEWLINE); #endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index bf70d0227..06841b83c 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -135,9 +135,6 @@ struct ospf /* Opaque-LSA administrative flags. */ u_char opaque; #define OPAQUE_OPERATION_READY_BIT (1 << 0) -#define OPAQUE_BLOCK_TYPE_09_LSA_BIT (1 << 1) -#define OPAQUE_BLOCK_TYPE_10_LSA_BIT (1 << 2) -#define OPAQUE_BLOCK_TYPE_11_LSA_BIT (1 << 3) #endif /* HAVE_OPAQUE_LSA */ /* RFC3137 stub router. Configured time to stay stub / max-metric */ From 4584c239201037648abf1a6615186f9cdeb86b23 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 13 Apr 2015 09:50:00 +0200 Subject: [PATCH 0693/1342] bgpd: speed up "no-hit" withdraws for routeservers This accelerates handling of incoming Withdraw messages for routes that don't exist in the table to begin with. Cisco IOS 12.4(24)T4 has a bug in this regard - it sends withdraws instead of doing nothing for prefixes that are filtered. Pulling up the adj_in removal in Quagga should have no ill effect, but we can avoid the costly iteration over all rsclients if there was no adj_in entry. Performance impact of this change on routeserver with 3 buggy peers, startup/sync time: before patch: 143.12 seconds (user cpu) after patch: 7.01 seconds (user cpu) Many thanks to Nick Hilliard & INEX for providing real-world test data! Signed-off-by: David Lamparter Acked-by: Paul Jakma --- bgpd/bgp_advertise.c | 5 +++-- bgpd/bgp_advertise.h | 2 +- bgpd/bgp_route.c | 30 +++++++++++++++++++++--------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index e0fa58d46..be9b4801f 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -361,7 +361,7 @@ bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) XFREE (MTYPE_BGP_ADJ_IN, bai); } -void +int bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) { struct bgp_adj_in *adj; @@ -371,10 +371,11 @@ bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) break; if (! adj) - return; + return 0; bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); + return 1; } void diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 2cf2a29b2..adbbe3074 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -133,7 +133,7 @@ extern int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t, struct bgp_node *); extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *); -extern void bgp_adj_in_unset (struct bgp_node *, struct peer *); +extern int bgp_adj_in_unset (struct bgp_node *, struct peer *); extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *); extern struct bgp_advertise * diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 34cb7c0c5..34ba1abe6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2431,6 +2431,27 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, bgp = peer->bgp; + /* Lookup node. */ + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); + + /* Cisco IOS 12.4(24)T4 on session establishment sends withdraws for all + * routes that are filtered. This tanks out Quagga RS pretty badly due to + * the iteration over all RS clients. + * Since we need to remove the entry from adj_in anyway, do that first and + * if there was no entry, we don't need to do anything more. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) + && peer != bgp->peer_self) + if (!bgp_adj_in_unset (rn, peer)) + { + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_DEBUG, "%s withdrawing route %s/%d " + "not in adj-in", peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + bgp_unlock_node (rn); + return 0; + } + /* Process the withdraw for each RS-client. */ for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { @@ -2445,15 +2466,6 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); - /* Lookup node. */ - rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); - - /* If peer is soft reconfiguration enabled. Record input packet for - further calculation. */ - if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) - && peer != bgp->peer_self) - bgp_adj_in_unset (rn, peer); - /* Lookup withdrawn route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) From e66cbd10d52a79fd61acab9d615683eebdbf1df5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 13 Apr 2015 10:21:34 +0200 Subject: [PATCH 0694/1342] lib: hide internal prefix list structures These are about to be touched and there's no point in other code touching into prefix list's internas. Add some isolation. Signed-off-by: David Lamparter --- lib/Makefile.am | 3 ++ lib/plist.c | 25 ++++------------ lib/plist.h | 26 ++--------------- lib/plist_int.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++ ospfd/ospf_zebra.c | 4 +-- 5 files changed, 84 insertions(+), 45 deletions(-) create mode 100644 lib/plist_int.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 56837d869..fc0231230 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -30,6 +30,9 @@ pkginclude_HEADERS = \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ workqueue.h route_types.h libospf.h +noinst_HEADERS = \ + plist_int.h + EXTRA_DIST = \ regex.c regex-gnu.h \ queue.h \ diff --git a/lib/plist.c b/lib/plist.c index 610755608..bdc31e8f8 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -30,25 +30,7 @@ #include "stream.h" #include "log.h" -/* Each prefix-list's entry. */ -struct prefix_list_entry -{ - int seq; - - int le; - int ge; - - enum prefix_list_type type; - - int any; - struct prefix prefix; - - unsigned long refcnt; - unsigned long hitcnt; - - struct prefix_list_entry *next; - struct prefix_list_entry *prev; -}; +#include "plist_int.h" /* List of struct prefix_list. */ struct prefix_list_list @@ -125,6 +107,11 @@ prefix_master_get (afi_t afi) return NULL; } +const char *prefix_list_name (struct prefix_list *plist) +{ + return plist->name; +} + /* Lookup prefix_list from list of prefix_list by name. */ struct prefix_list * prefix_list_lookup (afi_t afi, const char *name) diff --git a/lib/plist.h b/lib/plist.h index fb3168a6e..1e621ff81 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -31,30 +31,7 @@ enum prefix_list_type PREFIX_PERMIT, }; -enum prefix_name_type -{ - PREFIX_TYPE_STRING, - PREFIX_TYPE_NUMBER -}; - -struct prefix_list -{ - char *name; - char *desc; - - struct prefix_master *master; - - enum prefix_name_type type; - - int count; - int rangecount; - - struct prefix_list_entry *head; - struct prefix_list_entry *tail; - - struct prefix_list *next; - struct prefix_list *prev; -}; +struct prefix_list; struct orf_prefix { @@ -70,6 +47,7 @@ extern void prefix_list_reset (void); extern void prefix_list_add_hook (void (*func) (struct prefix_list *)); extern void prefix_list_delete_hook (void (*func) (struct prefix_list *)); +extern const char *prefix_list_name (struct prefix_list *); extern struct prefix_list *prefix_list_lookup (afi_t, const char *); extern enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); diff --git a/lib/plist_int.h b/lib/plist_int.h new file mode 100644 index 000000000..64595797e --- /dev/null +++ b/lib/plist_int.h @@ -0,0 +1,71 @@ +/* + * Prefix list internal definitions. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _QUAGGA_PLIST_INT_H +#define _QUAGGA_PLIST_INT_H + +enum prefix_name_type +{ + PREFIX_TYPE_STRING, + PREFIX_TYPE_NUMBER +}; + +struct prefix_list +{ + char *name; + char *desc; + + struct prefix_master *master; + + enum prefix_name_type type; + + int count; + int rangecount; + + struct prefix_list_entry *head; + struct prefix_list_entry *tail; + + struct prefix_list *next; + struct prefix_list *prev; +}; + +/* Each prefix-list's entry. */ +struct prefix_list_entry +{ + int seq; + + int le; + int ge; + + enum prefix_list_type type; + + int any; + struct prefix prefix; + + unsigned long refcnt; + unsigned long hitcnt; + + struct prefix_list_entry *next; + struct prefix_list_entry *prev; +}; + +#endif /* _QUAGGA_PLIST_INT_H */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index b6d3260b4..bdb5193ab 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1126,7 +1126,7 @@ ospf_prefix_list_update (struct prefix_list *plist) { /* Update filter-list in. */ if (PREFIX_NAME_IN (area)) - if (strcmp (PREFIX_NAME_IN (area), plist->name) == 0) + if (strcmp (PREFIX_NAME_IN (area), prefix_list_name (plist)) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area)); @@ -1135,7 +1135,7 @@ ospf_prefix_list_update (struct prefix_list *plist) /* Update filter-list out. */ if (PREFIX_NAME_OUT (area)) - if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0) + if (strcmp (PREFIX_NAME_OUT (area), prefix_list_name (plist)) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); From c9c06d0d8cbc766374c43328e91b7a87f93e9c62 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 13 Apr 2015 10:21:35 +0200 Subject: [PATCH 0695/1342] lib: straighten out ORF prefix list support BGP ORF prefix lists are in a separate namespace; this was previously hooked up with a special-purpose AFI value. This is a little kludgy for extension, hence this splits it off. Signed-off-by: David Lamparter Acked-by: Paul Jakma --- bgpd/bgp_fsm.c | 2 +- bgpd/bgp_packet.c | 6 +- bgpd/bgpd.c | 2 +- lib/plist.c | 151 ++++++++++++++++------------------------------ lib/plist.h | 5 +- 5 files changed, 59 insertions(+), 107 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 112c34a19..d261bb598 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -545,7 +545,7 @@ bgp_stop (struct peer *peer) /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); - prefix_bgp_orf_remove_all (orf_name); + prefix_bgp_orf_remove_all (afi, orf_name); } /* Reset keepalive and holdtime */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 14fd6e51e..18114ad5e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2146,7 +2146,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host); - prefix_bgp_orf_remove_all (name); + prefix_bgp_orf_remove_all (afi, name); break; } ok = ((size_t)(p_end - p_pnt) >= sizeof(u_int32_t)) ; @@ -2207,12 +2207,12 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Received misformatted prefixlist ORF." " Remove All pfxlist", peer->host); - prefix_bgp_orf_remove_all (name); + prefix_bgp_orf_remove_all (afi, name); break; } } peer->orf_plist[afi][safi] = - prefix_list_lookup (AFI_ORF_PREFIX, name); + prefix_bgp_orf_lookup (afi, name); } stream_forward_getp (s, orf_len); } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d72708e4a..4de854e4e 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -595,7 +595,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) /* Clear ORF info */ peer->orf_plist[afi][safi] = NULL; sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); - prefix_bgp_orf_remove_all (orf_name); + prefix_bgp_orf_remove_all (afi, orf_name); /* Set default neighbor send-community. */ if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) diff --git a/lib/plist.c b/lib/plist.c index bdc31e8f8..f9e626d8b 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -84,8 +84,18 @@ static struct prefix_master prefix_master_ipv6 = #endif /* HAVE_IPV6*/ /* Static structure of BGP ORF prefix_list's master. */ -static struct prefix_master prefix_master_orf = -{ +static struct prefix_master prefix_master_orf_v4 = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; + +/* Static structure of BGP ORF prefix_list's master. */ +static struct prefix_master prefix_master_orf_v6 = +{ {NULL, NULL}, {NULL, NULL}, 1, @@ -94,16 +104,12 @@ static struct prefix_master prefix_master_orf = }; static struct prefix_master * -prefix_master_get (afi_t afi) +prefix_master_get (afi_t afi, int orf) { if (afi == AFI_IP) - return &prefix_master_ipv4; -#ifdef HAVE_IPV6 - else if (afi == AFI_IP6) - return &prefix_master_ipv6; -#endif /* HAVE_IPV6 */ - else if (afi == AFI_ORF_PREFIX) - return &prefix_master_orf; + return orf ? &prefix_master_orf_v4 : &prefix_master_ipv4; + if (afi == AFI_IP6) + return orf ? &prefix_master_orf_v6 : &prefix_master_ipv6; return NULL; } @@ -113,8 +119,8 @@ const char *prefix_list_name (struct prefix_list *plist) } /* Lookup prefix_list from list of prefix_list by name. */ -struct prefix_list * -prefix_list_lookup (afi_t afi, const char *name) +static struct prefix_list * +prefix_list_lookup_do (afi_t afi, int orf, const char *name) { struct prefix_list *plist; struct prefix_master *master; @@ -122,7 +128,7 @@ prefix_list_lookup (afi_t afi, const char *name) if (name == NULL) return NULL; - master = prefix_master_get (afi); + master = prefix_master_get (afi, orf); if (master == NULL) return NULL; @@ -137,6 +143,18 @@ prefix_list_lookup (afi_t afi, const char *name) return NULL; } +struct prefix_list * +prefix_list_lookup (afi_t afi, const char *name) +{ + return prefix_list_lookup_do (afi, 0, name); +} + +struct prefix_list * +prefix_bgp_orf_lookup (afi_t afi, const char *name) +{ + return prefix_list_lookup_do (afi, 1, name); +} + static struct prefix_list * prefix_list_new (void) { @@ -170,7 +188,7 @@ prefix_list_entry_free (struct prefix_list_entry *pentry) /* Insert new prefix list to list of prefix_list. Each prefix_list is sorted by the name. */ static struct prefix_list * -prefix_list_insert (afi_t afi, const char *name) +prefix_list_insert (afi_t afi, int orf, const char *name) { unsigned int i; long number; @@ -179,7 +197,7 @@ prefix_list_insert (afi_t afi, const char *name) struct prefix_list_list *list; struct prefix_master *master; - master = prefix_master_get (afi); + master = prefix_master_get (afi, orf); if (master == NULL) return NULL; @@ -260,14 +278,14 @@ prefix_list_insert (afi_t afi, const char *name) } static struct prefix_list * -prefix_list_get (afi_t afi, const char *name) +prefix_list_get (afi_t afi, int orf, const char *name) { struct prefix_list *plist; - plist = prefix_list_lookup (afi, name); + plist = prefix_list_lookup_do (afi, orf, name); if (plist == NULL) - plist = prefix_list_insert (afi, name); + plist = prefix_list_insert (afi, orf, name); return plist; } @@ -733,7 +751,7 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, lenum = 0; /* Get prefix_list with name. */ - plist = prefix_list_get (afi, name); + plist = prefix_list_get (afi, 0, name); /* Make prefix entry. */ pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any); @@ -988,7 +1006,7 @@ vty_show_prefix_list (struct vty *vty, afi_t afi, const char *name, struct prefix_master *master; int seqnum = 0; - master = prefix_master_get (afi); + master = prefix_master_get (afi, 0); if (master == NULL) return CMD_WARNING; @@ -1106,7 +1124,7 @@ vty_clear_prefix_list (struct vty *vty, afi_t afi, const char *name, int ret; struct prefix p; - master = prefix_master_get (afi); + master = prefix_master_get (afi, 0); if (master == NULL) return CMD_WARNING; @@ -1561,7 +1579,7 @@ DEFUN (ip_prefix_list_description, { struct prefix_list *plist; - plist = prefix_list_get (AFI_IP, argv[0]); + plist = prefix_list_get (AFI_IP, 0, argv[0]); if (plist->desc) { @@ -2157,7 +2175,7 @@ DEFUN (ipv6_prefix_list_description, { struct prefix_list *plist; - plist = prefix_list_get (AFI_IP6, argv[0]); + plist = prefix_list_get (AFI_IP6, 0, argv[0]); if (plist->desc) { @@ -2352,7 +2370,7 @@ config_write_prefix_afi (afi_t afi, struct vty *vty) struct prefix_master *master; int write = 0; - master = prefix_master_get (afi); + master = prefix_master_get (afi, 0); if (master == NULL) return 0; @@ -2495,7 +2513,7 @@ prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp, if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128)) orfp->le = 0; - plist = prefix_list_get (AFI_ORF_PREFIX, name); + plist = prefix_list_get (afi, 1, name); if (! plist) return CMD_WARNING; @@ -2529,11 +2547,11 @@ prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp, } void -prefix_bgp_orf_remove_all (char *name) +prefix_bgp_orf_remove_all (afi_t afi, char *name) { struct prefix_list *plist; - plist = prefix_list_lookup (AFI_ORF_PREFIX, name); + plist = prefix_bgp_orf_lookup (afi, name); if (plist) prefix_list_delete (plist); } @@ -2545,7 +2563,7 @@ prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name) struct prefix_list *plist; struct prefix_list_entry *pentry; - plist = prefix_list_lookup (AFI_ORF_PREFIX, name); + plist = prefix_bgp_orf_lookup (afi, name); if (! plist) return 0; @@ -2577,13 +2595,13 @@ prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name) } static void -prefix_list_reset_orf (void) +prefix_list_reset_afi (afi_t afi, int orf) { struct prefix_list *plist; struct prefix_list *next; struct prefix_master *master; - master = prefix_master_get (AFI_ORF_PREFIX); + master = prefix_master_get (afi, orf); if (master == NULL) return; @@ -2623,38 +2641,6 @@ config_write_prefix_ipv4 (struct vty *vty) return config_write_prefix_afi (AFI_IP, vty); } -static void -prefix_list_reset_ipv4 (void) -{ - struct prefix_list *plist; - struct prefix_list *next; - struct prefix_master *master; - - master = prefix_master_get (AFI_IP); - if (master == NULL) - return; - - for (plist = master->num.head; plist; plist = next) - { - next = plist->next; - prefix_list_delete (plist); - } - for (plist = master->str.head; plist; plist = next) - { - next = plist->next; - prefix_list_delete (plist); - } - - assert (master->num.head == NULL); - assert (master->num.tail == NULL); - - assert (master->str.head == NULL); - assert (master->str.tail == NULL); - - master->seqnum = 1; - master->recent = NULL; -} - static void prefix_list_init_ipv4 (void) { @@ -2732,38 +2718,6 @@ config_write_prefix_ipv6 (struct vty *vty) return config_write_prefix_afi (AFI_IP6, vty); } -static void -prefix_list_reset_ipv6 (void) -{ - struct prefix_list *plist; - struct prefix_list *next; - struct prefix_master *master; - - master = prefix_master_get (AFI_IP6); - if (master == NULL) - return; - - for (plist = master->num.head; plist; plist = next) - { - next = plist->next; - prefix_list_delete (plist); - } - for (plist = master->str.head; plist; plist = next) - { - next = plist->next; - prefix_list_delete (plist); - } - - assert (master->num.head == NULL); - assert (master->num.tail == NULL); - - assert (master->str.head == NULL); - assert (master->str.tail == NULL); - - master->seqnum = 1; - master->recent = NULL; -} - static void prefix_list_init_ipv6 (void) { @@ -2839,9 +2793,8 @@ prefix_list_init () void prefix_list_reset () { - prefix_list_reset_ipv4 (); -#ifdef HAVE_IPV6 - prefix_list_reset_ipv6 (); -#endif /* HAVE_IPV6 */ - prefix_list_reset_orf (); + prefix_list_reset_afi (AFI_IP, 0); + prefix_list_reset_afi (AFI_IP6, 0); + prefix_list_reset_afi (AFI_IP, 1); + prefix_list_reset_afi (AFI_IP6, 1); } diff --git a/lib/plist.h b/lib/plist.h index 1e621ff81..aa14e74be 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -23,8 +23,6 @@ #ifndef _QUAGGA_PLIST_H #define _QUAGGA_PLIST_H -#define AFI_ORF_PREFIX 65535 - enum prefix_list_type { PREFIX_DENY, @@ -51,11 +49,12 @@ extern const char *prefix_list_name (struct prefix_list *); extern struct prefix_list *prefix_list_lookup (afi_t, const char *); extern enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); +extern struct prefix_list *prefix_bgp_orf_lookup (afi_t, const char *); extern struct stream * prefix_bgp_orf_entry (struct stream *, struct prefix_list *, u_char, u_char, u_char); extern int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int); -extern void prefix_bgp_orf_remove_all (char *); +extern void prefix_bgp_orf_remove_all (afi_t, char *); extern int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *); #endif /* _QUAGGA_PLIST_H */ From 1416293f9d8f09cb792ce0ff9b734bff71697909 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 12 May 2015 17:18:04 +0200 Subject: [PATCH 0696/1342] lib: fix "reduce strcmp in CLI" fallout (10bac801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In "lib/cli: reduce strcmp in CLI hot paths", I failed to notice that CMD_VARIABLE as a boolean test covers a superset of the other types of variables. Thus, the patch broke processing of IP/IPv6/Integer range parameters in the CLI. Fix by some reordering and introducing TERMINAL_RECORD macro (which marks whether a given terminal type is a parameter) to be used in places where the check is really for all kinds of variables. Reported-by: Timo Teräs Tested-by: Martin Winter Signed-off-by: David Lamparter --- lib/command.c | 49 ++++++++++++++++--------------------------------- lib/command.h | 3 +++ 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/lib/command.c b/lib/command.c index 922e7b581..c70391d74 100644 --- a/lib/command.c +++ b/lib/command.c @@ -506,15 +506,7 @@ format_parser_read_word(struct format_parser_state *state) token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); token->type = TOKEN_TERMINAL; - if (cmd[0] == '[') - token->terminal = TERMINAL_OPTION; - else if ((cmd[0] >= 'A' && cmd[0] <= 'Z') || (cmd[0] == '<')) - token->terminal = TERMINAL_VARIABLE; - else if (cmd[0] == '.') - token->terminal = TERMINAL_VARARG; - else if (cmd[0] == '<') - token->terminal = TERMINAL_RANGE; - else if (strcmp (cmd, "A.B.C.D") == 0) + if (strcmp (cmd, "A.B.C.D") == 0) token->terminal = TERMINAL_IPV4; else if (strcmp (cmd, "A.B.C.D/M") == 0) token->terminal = TERMINAL_IPV4_PREFIX; @@ -522,6 +514,14 @@ format_parser_read_word(struct format_parser_state *state) token->terminal = TERMINAL_IPV6; else if (strcmp (cmd, "X:X::X:X/M") == 0) token->terminal = TERMINAL_IPV6_PREFIX; + else if (cmd[0] == '[') + token->terminal = TERMINAL_OPTION; + else if (cmd[0] == '.') + token->terminal = TERMINAL_VARARG; + else if (cmd[0] == '<') + token->terminal = TERMINAL_RANGE; + else if (cmd[0] >= 'A' && cmd[0] <= 'Z') + token->terminal = TERMINAL_VARIABLE; else token->terminal = TERMINAL_LITERAL; @@ -1341,9 +1341,7 @@ cmd_matcher_match_terminal(struct cmd_matcher *matcher, /* We have to record the input word as argument if it matched * against a variable. */ - if (token->terminal == TERMINAL_VARARG - || token->terminal == TERMINAL_VARIABLE - || token->terminal == TERMINAL_OPTION) + if (TERMINAL_RECORD (token->terminal)) { if (push_argument(argc, argv, word)) return MATCHER_EXCEED_ARGC_MAX; @@ -1585,9 +1583,7 @@ cmd_matcher_build_keyword_args(struct cmd_matcher *matcher, { word_token = vector_slot(keyword_vector, j); if ((word_token->type == TOKEN_TERMINAL - && (word_token->terminal == TERMINAL_VARARG - || word_token->terminal == TERMINAL_VARIABLE - || word_token->terminal == TERMINAL_OPTION)) + && TERMINAL_RECORD (word_token->terminal)) || word_token->type == TOKEN_MULTIPLE) { if (push_argument(argc, argv, NULL)) @@ -1873,14 +1869,12 @@ is_cmd_ambiguous (vector cmd_vector, switch (type) { case exact_match: - if (!(cmd_token->terminal == TERMINAL_OPTION - || cmd_token->terminal == TERMINAL_VARIABLE) + if (!TERMINAL_RECORD (cmd_token->terminal) && strcmp (command, str) == 0) match++; break; case partly_match: - if (!(cmd_token->terminal == TERMINAL_OPTION - || cmd_token->terminal == TERMINAL_VARIABLE) + if (!TERMINAL_RECORD (cmd_token->terminal) && strncmp (command, str, strlen (command)) == 0) { if (matched && strcmp (matched, str) != 0) @@ -1929,8 +1923,7 @@ is_cmd_ambiguous (vector cmd_vector, } break; case extend_match: - if (cmd_token->terminal == TERMINAL_OPTION - || cmd_token->terminal == TERMINAL_VARIABLE) + if (TERMINAL_RECORD (cmd_token->terminal)) match++; break; case no_match: @@ -1951,18 +1944,8 @@ cmd_entry_function (const char *src, struct cmd_token *token) const char *dst = token->cmd; /* Skip variable arguments. */ - switch (token->terminal) - { - case TERMINAL_OPTION: - case TERMINAL_VARIABLE: - case TERMINAL_VARARG: - case TERMINAL_IPV4: - case TERMINAL_IPV4_PREFIX: - case TERMINAL_RANGE: - return NULL; - default: - break; - } + if (TERMINAL_RECORD (token->terminal)) + return NULL; /* In case of 'command \t', given src is NULL string. */ if (src == NULL) diff --git a/lib/command.h b/lib/command.h index 3a95df93a..a36a524a0 100644 --- a/lib/command.h +++ b/lib/command.h @@ -165,6 +165,9 @@ enum cmd_terminal_type TERMINAL_IPV6_PREFIX, }; +/* argument to be recorded on argv[] if it's not a literal */ +#define TERMINAL_RECORD(t) ((t) >= TERMINAL_OPTION) + /* Command description structure. */ struct cmd_token { From f1fc327c7eb00634d2c2b08c2a6f6e44a626ef04 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 13 May 2015 12:44:50 +0200 Subject: [PATCH 0697/1342] lib: assert(0) still needs a return assert(0) is not guaranteed to not return since assert() in general can be optimised out when building without debug / with optimisation. This breaks the build in clang, which warns/errors about the missing return. Signed-off-by: David Lamparter --- lib/command.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/command.c b/lib/command.c index c70391d74..8ae27de92 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2018,6 +2018,7 @@ cmd_entry_function_desc (const char *src, struct cmd_token *token) default: assert(0); + return NULL; } } From 219cdc95d93eda93240d472814ef4aa8bd36b039 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 23 Jan 2015 16:43:49 +0000 Subject: [PATCH 0698/1342] ospfd: Remove another odd flooding hack in opaque LSA code * ospf_opaque.c: (ospf_opaque_adjust_lsreq) Odd hack to general OSPF database exchange but made to act only on opaque LSAs. It's either covering up bugs in the flooding code or its wrong. If it's covering up bugs, those would affect all LSAs and should be fixed at a lower layer in ospfd, indeed perhaps those bugs are long fixed anyway (?). Alternatively, it's just plain wrong. Nuke. (ospf_opaque_exclude_lsa_from_lsreq) helper to above, nuke. * ospf_packet.c: Nuke call to ospf_opaque_adjust_lsreq. Tested-by: olivier.dugeon@orange.com --- ospfd/ospf_opaque.c | 108 -------------------------------------------- ospfd/ospf_opaque.h | 2 - ospfd/ospf_packet.c | 15 ------ 3 files changed, 125 deletions(-) diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index d449c9507..f584fc71f 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -2109,114 +2109,6 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) return; } -/*------------------------------------------------------------------------* - * Followings are control functions to block origination after restart. - *------------------------------------------------------------------------*/ - -static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); - -void -ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas) -{ - struct ospf *top; - struct ospf_area *area; - struct ospf_interface *oi; - struct listnode *node1, *nnode1; - struct listnode *node2, *nnode2; - struct ospf_lsa *lsa; - - if ((top = oi_to_top (nbr->oi)) == NULL) - goto out; - - /* - * If an instance of self-originated Opaque-LSA is found in the given - * LSA list, and it is not installed to LSDB yet, exclude it from the - * list "nbr->ls_req". In this way, it is assured that an LSReq message, - * which might be sent in the process of flooding, will not request for - * the LSA to be flushed immediately; otherwise, depending on timing, - * an LSUpd message will carry instances of target LSAs with MaxAge, - * while other LSUpd message might carry old LSA instances (non-MaxAge). - * Obviously, the latter would trigger miserable situations that repeat - * installation and removal of unwanted LSAs indefinitely. - */ - for (ALL_LIST_ELEMENTS (lsas, node1, nnode1, lsa)) - { - /* Filter out unwanted LSAs. */ - if (! IS_OPAQUE_LSA (lsa->data->type)) - continue; - if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id)) - continue; - - /* - * Don't touch an LSA which has MaxAge; two possible cases. - * - * 1) This LSA has originally flushed by myself (received LSUpd - * message's router-id is equal to my router-id), and flooded - * back by an opaque-capable router. - * - * 2) This LSA has expired in an opaque-capable router and thus - * flushed by the router. - */ - if (IS_LSA_MAXAGE (lsa)) - continue; - - /* If the LSA has installed in the LSDB, nothing to do here. */ - if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL) - continue; - - /* Ok, here we go. */ - switch (lsa->data->type) - { - case OSPF_OPAQUE_LINK_LSA: - oi = nbr->oi; - ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); - break; - case OSPF_OPAQUE_AREA_LSA: - area = nbr->oi->area; - for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) - ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); - break; - case OSPF_OPAQUE_AS_LSA: - for (ALL_LIST_ELEMENTS (top->oiflist, node2, nnode2, oi)) - ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); - break; - default: - break; - } - } - -out: - return; -} - -static void -ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, - struct ospf_neighbor *inbr, - struct ospf_lsa *lsa) -{ - struct route_node *rn; - struct ospf_neighbor *onbr; - struct ospf_lsa *ls_req; - - for (rn = route_top (nbrs); rn; rn = route_next (rn)) - { - if ((onbr = rn->info) == NULL) - continue; - if (onbr == inbr) - continue; - if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL) - continue; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa)); - - ospf_ls_request_delete (onbr, ls_req); -/* ospf_check_nbr_loading (onbr);*//* XXX */ - } - - return; -} - void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index 077da6274..b9490a0ff 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -134,8 +134,6 @@ extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa); extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); -extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, - struct list *lsas); extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index d59765372..587484f2a 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1745,21 +1745,6 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, */ lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size); -#ifdef HAVE_OPAQUE_LSA - /* - * If self-originated Opaque-LSAs that have flooded before restart - * are contained in the received LSUpd message, corresponding LSReq - * messages to be sent may have to be modified. - * To eliminate possible race conditions such that flushing and normal - * updating for the same LSA would take place alternately, this trick - * must be done before entering to the loop below. - */ - /* XXX: Why is this Opaque specific? Either our core code is deficient - * and this should be fixed generally, or Opaque is inventing strawman - * problems */ - ospf_opaque_adjust_lsreq (nbr, lsas); -#endif /* HAVE_OPAQUE_LSA */ - #define DISCARD_LSA(L,N) {\ if (IS_DEBUG_OSPF_EVENT) \ zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p" \ From 336724d628be71022f80cfe3dfb34274ad95ec14 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 11 May 2015 15:13:31 +0100 Subject: [PATCH 0699/1342] babeld: Remove babeld from Quagga This commit removes babeld from Quagga because the Quagga project is unable to meet the wishes of the babeld authors. --- Makefile.am | 4 +- babeld/.gitignore | 7 - babeld/LICENCE | 36 - babeld/Makefile.am | 29 - babeld/babel_filter.c | 124 --- babeld/babel_filter.h | 49 -- babeld/babel_interface.c | 1022 ------------------------ babeld/babel_interface.h | 152 ---- babeld/babel_main.c | 529 ------------- babeld/babel_main.h | 57 -- babeld/babel_zebra.c | 378 --------- babeld/babel_zebra.h | 50 -- babeld/babeld.c | 728 ----------------- babeld/babeld.conf.sample | 30 - babeld/babeld.h | 141 ---- babeld/kernel.c | 314 -------- babeld/kernel.h | 69 -- babeld/message.c | 1561 ------------------------------------- babeld/message.h | 111 --- babeld/neighbour.c | 343 -------- babeld/neighbour.h | 66 -- babeld/net.c | 239 ------ babeld/net.h | 44 -- babeld/resend.c | 330 -------- babeld/resend.h | 77 -- babeld/route.c | 1019 ------------------------ babeld/route.h | 135 ---- babeld/source.c | 180 ----- babeld/source.h | 67 -- babeld/util.c | 445 ----------- babeld/util.h | 165 ---- babeld/xroute.c | 237 ------ babeld/xroute.h | 59 -- configure.ac | 14 +- doc/Makefile.am | 2 +- doc/babeld.texi | 118 --- doc/ipv6.texi | 2 +- doc/quagga.texi | 2 - 38 files changed, 5 insertions(+), 8930 deletions(-) delete mode 100644 babeld/.gitignore delete mode 100644 babeld/LICENCE delete mode 100644 babeld/Makefile.am delete mode 100644 babeld/babel_filter.c delete mode 100644 babeld/babel_filter.h delete mode 100644 babeld/babel_interface.c delete mode 100644 babeld/babel_interface.h delete mode 100644 babeld/babel_main.c delete mode 100644 babeld/babel_main.h delete mode 100644 babeld/babel_zebra.c delete mode 100644 babeld/babel_zebra.h delete mode 100644 babeld/babeld.c delete mode 100644 babeld/babeld.conf.sample delete mode 100644 babeld/babeld.h delete mode 100644 babeld/kernel.c delete mode 100644 babeld/kernel.h delete mode 100644 babeld/message.c delete mode 100644 babeld/message.h delete mode 100644 babeld/neighbour.c delete mode 100644 babeld/neighbour.h delete mode 100644 babeld/net.c delete mode 100644 babeld/net.h delete mode 100644 babeld/resend.c delete mode 100644 babeld/resend.h delete mode 100644 babeld/route.c delete mode 100644 babeld/route.h delete mode 100644 babeld/source.c delete mode 100644 babeld/source.h delete mode 100644 babeld/util.c delete mode 100644 babeld/util.h delete mode 100644 babeld/xroute.c delete mode 100644 babeld/xroute.h delete mode 100644 doc/babeld.texi diff --git a/Makefile.am b/Makefile.am index 405142f85..d2efb20eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \ +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests -DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ +DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd diff --git a/babeld/.gitignore b/babeld/.gitignore deleted file mode 100644 index 8384763a6..000000000 --- a/babeld/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -* -!*.c -!*.h -!LICENCE -!Makefile.am -!babeld.conf.sample -!.gitignore \ No newline at end of file diff --git a/babeld/LICENCE b/babeld/LICENCE deleted file mode 100644 index 9da569dc2..000000000 --- a/babeld/LICENCE +++ /dev/null @@ -1,36 +0,0 @@ -Code in this directory is made available under the following licence: - - --------------------------------------------------------------------------- - Copyright (c) 2007, 2008 by Juliusz Chroboczek - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - --------------------------------------------------------------------------- - -The code also makes calls to and links with the "libzebra" code of Quagga, -in the lib/ directory of this project, which is subject to the GPL licence -as given in the top-level COPYING file included with Quagga. - -Contributors to the code in babeld/ are asked to make their work available -under the same MIT/X11 licence as given immediately above. Please indicate -your assent to this by updating this file and appending the appropriate - - Copyright , - -line to the existing copyright assertion lines in the MIT/X11 licence text -above in this file. diff --git a/babeld/Makefile.am b/babeld/Makefile.am deleted file mode 100644 index d34e180b0..000000000 --- a/babeld/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) - -noinst_LIBRARIES = libbabel.a -sbin_PROGRAMS = babeld - -libbabel_a_SOURCES = \ - babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ - route.c xroute.c message.c resend.c babel_interface.c babeld.c \ - babel_filter.c - -noinst_HEADERS = \ - babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ - route.h xroute.h message.h resend.h babel_interface.h babeld.h \ - babel_filter.h babel_main.h - -babeld_SOURCES = \ - babel_main.c $(libbabel_a_SOURCES) - -babeld_LDADD = ../lib/libzebra.la @LIBCAP@ - -examplesdir = $(exampledir) -dist_examples_DATA = babeld.conf.sample diff --git a/babeld/babel_filter.c b/babeld/babel_filter.c deleted file mode 100644 index 191a9f77e..000000000 --- a/babeld/babel_filter.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "babel_filter.h" -#include "vty.h" -#include "filter.h" -#include "log.h" -#include "plist.h" -#include "distribute.h" -#include "util.h" - -int -babel_filter(int output, const unsigned char *prefix, unsigned short plen, - unsigned int ifindex) -{ - struct interface *ifp = if_lookup_by_index(ifindex); - babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL; - struct prefix p; - struct distribute *dist; - struct access_list *alist; - struct prefix_list *plist; - int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN; - int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN; - - p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; - if (p.family == AF_INET) - uchar_to_inaddr(&p.u.prefix4, prefix); - else - uchar_to_in6addr(&p.u.prefix6, prefix); - - if (babel_ifp != NULL && babel_ifp->list[filter]) { - if (access_list_apply (babel_ifp->list[filter], &p) - == FILTER_DENY) { - debugf(BABEL_DEBUG_FILTER, - "%s/%d filtered by distribute in", - p.family == AF_INET ? - inet_ntoa(p.u.prefix4) : - inet6_ntoa (p.u.prefix6), - p.prefixlen); - return INFINITY; - } - } - if (babel_ifp != NULL && babel_ifp->prefix[filter]) { - if (prefix_list_apply (babel_ifp->prefix[filter], &p) - == PREFIX_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p.family == AF_INET ? - inet_ntoa(p.u.prefix4) : - inet6_ntoa (p.u.prefix6), - p.prefixlen); - return INFINITY; - } - } - - /* All interface filter check. */ - dist = distribute_lookup (NULL); - if (dist) { - if (dist->list[distribute]) { - alist = access_list_lookup (AFI_IP6, dist->list[distribute]); - - if (alist) { - if (access_list_apply (alist, &p) == FILTER_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p.family == AF_INET ? - inet_ntoa(p.u.prefix4) : - inet6_ntoa (p.u.prefix6), - p.prefixlen); - return INFINITY; - } - } - } - if (dist->prefix[distribute]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); - if (plist) { - if (prefix_list_apply (plist, &p) == PREFIX_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p.family == AF_INET ? - inet_ntoa(p.u.prefix4) : - inet6_ntoa (p.u.prefix6), - p.prefixlen); - return INFINITY; - } - } - } - } - return 0; -} diff --git a/babeld/babel_filter.h b/babeld/babel_filter.h deleted file mode 100644 index 73722e0a3..000000000 --- a/babeld/babel_filter.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABELD_BABEL_FILTER_H -#define BABELD_BABEL_FILTER_H - -#include -#include "prefix.h" -#include "babel_interface.h" - -int babel_filter(int output, const unsigned char *prefix, unsigned short plen, - unsigned int index); - -#endif /* BABELD_BABEL_FILTER_H */ diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c deleted file mode 100644 index ace28127f..000000000 --- a/babeld/babel_interface.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "memory.h" -#include "log.h" -#include "command.h" -#include "prefix.h" -#include "vector.h" -#include "distribute.h" - -#include "babel_main.h" -#include "util.h" -#include "kernel.h" -#include "babel_interface.h" -#include "message.h" -#include "route.h" -#include "babel_zebra.h" -#include "neighbour.h" -#include "route.h" -#include "xroute.h" - - -#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0) - -static int babel_enable_if_lookup (const char *ifname); -static int babel_enable_if_add (const char *ifname); -static int babel_enable_if_delete (const char *ifname); -static int interface_recalculate(struct interface *ifp); -static int interface_reset(struct interface *ifp); -static int babel_if_new_hook (struct interface *ifp); -static int babel_if_delete_hook (struct interface *ifp); -static int interface_config_write (struct vty *vty); -static babel_interface_nfo * babel_interface_allocate (void); -static void babel_interface_free (babel_interface_nfo *bi); - - -static vector babel_enable_if; /* enable interfaces (by cmd). */ -static struct cmd_node babel_interface_node = /* babeld's interface node. */ -{ - INTERFACE_NODE, - "%s(config-if)# ", - 1 /* VTYSH */ -}; - - -int -babel_interface_up (int cmd, struct zclient *client, zebra_size_t length) -{ - struct stream *s = NULL; - struct interface *ifp = NULL; - - debugf(BABEL_DEBUG_IF, "receive a 'interface up'"); - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s); /* it updates iflist */ - - if (ifp == NULL) { - return 0; - } - - interface_recalculate(ifp); - return 0; -} - -int -babel_interface_down (int cmd, struct zclient *client, zebra_size_t length) -{ - struct stream *s = NULL; - struct interface *ifp = NULL; - - debugf(BABEL_DEBUG_IF, "receive a 'interface down'"); - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s); /* it updates iflist */ - - if (ifp == NULL) { - return 0; - } - - interface_reset(ifp); - return 0; -} - -int -babel_interface_add (int cmd, struct zclient *client, zebra_size_t length) -{ - struct interface *ifp = NULL; - - debugf(BABEL_DEBUG_IF, "receive a 'interface add'"); - - /* read and add the interface in the iflist. */ - ifp = zebra_interface_add_read (zclient->ibuf); - - if (ifp == NULL) { - return 0; - } - - interface_recalculate(ifp); - return 0; -} - -int -babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length) -{ - struct interface *ifp; - struct stream *s; - - debugf(BABEL_DEBUG_IF, "receive a 'interface delete'"); - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s); /* it updates iflist */ - - if (ifp == NULL) - return 0; - - if (IS_ENABLE(ifp)) - interface_reset(ifp); - - /* To support pseudo interface do not free interface structure. */ - /* if_delete(ifp); */ - ifp->ifindex = IFINDEX_INTERNAL; - - return 0; -} - -int -babel_interface_address_add (int cmd, struct zclient *client, - zebra_size_t length) -{ - babel_interface_nfo *babel_ifp; - struct connected *ifc; - struct prefix *prefix; - - debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); - - ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, - zclient->ibuf); - - if (ifc == NULL) - return 0; - - prefix = ifc->address; - - if (prefix->family == AF_INET) { - flush_interface_routes(ifc->ifp, 0); - babel_ifp = babel_get_if_nfo(ifc->ifp); - if (babel_ifp->ipv4 == NULL) { - babel_ifp->ipv4 = malloc(4); - if (babel_ifp->ipv4 == NULL) { - zlog_err("not einough memory"); - } else { - memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4); - } - } - } - - send_request(ifc->ifp, NULL, 0); - send_update(ifc->ifp, 0, NULL, 0); - - return 0; -} - -int -babel_interface_address_delete (int cmd, struct zclient *client, - zebra_size_t length) -{ - babel_interface_nfo *babel_ifp; - struct connected *ifc; - struct prefix *prefix; - - debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); - - ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, - zclient->ibuf); - - if (ifc == NULL) - return 0; - - prefix = ifc->address; - - if (prefix->family == AF_INET) { - flush_interface_routes(ifc->ifp, 0); - babel_ifp = babel_get_if_nfo(ifc->ifp); - if (babel_ifp->ipv4 != NULL - && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) { - free(babel_ifp->ipv4); - babel_ifp->ipv4 = NULL; - } - } - - send_request(ifc->ifp, NULL, 0); - send_update(ifc->ifp, 0, NULL, 0); - - return 0; -} - -/* Lookup function. */ -static int -babel_enable_if_lookup (const char *ifname) -{ - unsigned int i; - char *str; - - for (i = 0; i < vector_active (babel_enable_if); i++) - if ((str = vector_slot (babel_enable_if, i)) != NULL) - if (strcmp (str, ifname) == 0) - return i; - return -1; -} - -/* Add interface to babel_enable_if. */ -static int -babel_enable_if_add (const char *ifname) -{ - int ret; - struct interface *ifp = NULL; - - ret = babel_enable_if_lookup (ifname); - if (ret >= 0) - return -1; - - vector_set (babel_enable_if, strdup (ifname)); - - ifp = if_lookup_by_name(ifname); - if (ifp != NULL) - interface_recalculate(ifp); - - return 1; -} - -/* Delete interface from babel_enable_if. */ -static int -babel_enable_if_delete (const char *ifname) -{ - int babel_enable_if_index; - char *str; - struct interface *ifp = NULL; - - babel_enable_if_index = babel_enable_if_lookup (ifname); - if (babel_enable_if_index < 0) - return -1; - - str = vector_slot (babel_enable_if, babel_enable_if_index); - free (str); - vector_unset (babel_enable_if, babel_enable_if_index); - - ifp = if_lookup_by_name(ifname); - if (ifp != NULL) - interface_reset(ifp); - - return 1; -} - -/* [Babel Command] Babel enable on specified interface or matched network. */ -DEFUN (babel_network, - babel_network_cmd, - "network IF_OR_ADDR", - "Enable Babel protocol on specified interface or network.\n" - "Interface or address") -{ - int ret; - struct prefix p; - - ret = str2prefix (argv[0], &p); - - /* Given string is: */ - if (ret) /* an IPv4 or v6 network */ - return CMD_ERR_NO_MATCH; /* not implemented yet */ - else /* an interface name */ - ret = babel_enable_if_add (argv[0]); - - if (ret < 0) { - vty_out (vty, "There is same network configuration %s%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -/* [Babel Command] Babel enable on specified interface or matched network. */ -DEFUN (no_babel_network, - no_babel_network_cmd, - "no network IF_OR_ADDR", - NO_STR - "Disable Babel protocol on specified interface or network.\n" - "Interface or address") -{ - int ret; - struct prefix p; - - ret = str2prefix (argv[0], &p); - - /* Given string is: */ - if (ret) /* an IPv4 or v6 network */ - return CMD_ERR_NO_MATCH; /* not implemented yet */ - else /* an interface name */ - ret = babel_enable_if_delete (argv[0]); - - if (ret < 0) { - vty_out (vty, "can't find network %s%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -/* There are a number of interface parameters that must be changed when - an interface becomes wired/wireless. In Quagga, they cannot be - configured separately. */ - -static void -babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired) -{ - if(wired) { - babel_ifp->flags |= BABEL_IF_WIRED; - babel_ifp->cost = 96; - babel_ifp->flags &= ~BABEL_IF_LQ; - } else { - babel_ifp->flags &= ~BABEL_IF_WIRED; - babel_ifp->cost = 256; - babel_ifp->flags |= BABEL_IF_LQ; - } - -} - -/* [Interface Command] Tell the interface is wire. */ -DEFUN (babel_set_wired, - babel_set_wired_cmd, - "babel wired", - "Babel interface commands\n" - "Enable wired optimisations") -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - - ifp = vty->index; - babel_ifp = babel_get_if_nfo(ifp); - - assert (babel_ifp != NULL); - babel_set_wired_internal(babel_ifp, 1); - return CMD_SUCCESS; -} - -/* [Interface Command] Tell the interface is wireless (default). */ -DEFUN (babel_set_wireless, - babel_set_wireless_cmd, - "babel wireless", - "Babel interface commands\n" - "Disable wired optimiations (assume wireless)") -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - - ifp = vty->index; - babel_ifp = babel_get_if_nfo(ifp); - - assert (babel_ifp != NULL); - babel_set_wired_internal(babel_ifp, 0); - return CMD_SUCCESS; -} - -/* [Interface Command] Enable split horizon. */ -DEFUN (babel_split_horizon, - babel_split_horizon_cmd, - "babel split-horizon", - "Babel interface commands\n" - "Enable split horizon processing") -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - - ifp = vty->index; - babel_ifp = babel_get_if_nfo(ifp); - - assert (babel_ifp != NULL); - babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON; - return CMD_SUCCESS; -} - -/* [Interface Command] Disable split horizon (default). */ -DEFUN (no_babel_split_horizon, - no_babel_split_horizon_cmd, - "no babel split-horizon", - NO_STR - "Babel interface commands\n" - "Disable split horizon processing") -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - - ifp = vty->index; - babel_ifp = babel_get_if_nfo(ifp); - - assert (babel_ifp != NULL); - babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON; - return CMD_SUCCESS; -} - -/* [Interface Command]. */ -DEFUN (babel_set_hello_interval, - babel_set_hello_interval_cmd, - "babel hello-interval <20-655340>", - "Babel interface commands\n" - "Time between scheduled hellos\n" - "Milliseconds\n") -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - int interval; - - VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); - - ifp = vty->index; - babel_ifp = babel_get_if_nfo(ifp); - assert (babel_ifp != NULL); - - babel_ifp->hello_interval = interval; - return CMD_SUCCESS; -} - -/* [Interface Command]. */ -DEFUN (babel_set_update_interval, - babel_set_update_interval_cmd, - "babel update-interval <20-655340>", - "Babel interface commands\n" - "Time between scheduled updates\n" - "Milliseconds\n") -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - int interval; - - VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); - - ifp = vty->index; - babel_ifp = babel_get_if_nfo(ifp); - assert (babel_ifp != NULL); - - babel_ifp->update_interval = interval; - return CMD_SUCCESS; -} - -/* This should be no more than half the hello interval, so that hellos - aren't sent late. The result is in milliseconds. */ -unsigned -jitter(babel_interface_nfo *babel_ifp, int urgent) -{ - unsigned interval = babel_ifp->hello_interval; - if(urgent) - interval = MIN(interval, 100); - else - interval = MIN(interval, 4000); - return roughly(interval) / 4; -} - -unsigned -update_jitter(babel_interface_nfo *babel_ifp, int urgent) -{ - unsigned interval = babel_ifp->hello_interval; - if(urgent) - interval = MIN(interval, 100); - else - interval = MIN(interval, 4000); - return roughly(interval); -} - -/* calculate babeld's specific datas of an interface (change when the interface - change) */ -static int -interface_recalculate(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - unsigned char *tmp = NULL; - int mtu, rc; - struct ipv6_mreq mreq; - - if (!IS_ENABLE(ifp)) - return -1; - - if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) { - interface_reset(ifp); - return -1; - } - - babel_ifp->flags |= BABEL_IF_IS_UP; - - mtu = MIN(ifp->mtu, ifp->mtu6); - - /* We need to be able to fit at least two messages into a packet, - so MTUs below 116 require lower layer fragmentation. */ - /* In IPv6, the minimum MTU is 1280, and every host must be able - to reassemble up to 1500 bytes, but I'd rather not rely on this. */ - if(mtu < 128) { - debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).", - mtu, ifp->name, ifp->ifindex); - mtu = 128; - } - - /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ - babel_ifp->bufsize = mtu - sizeof(packet_header) - 60; - tmp = babel_ifp->sendbuf; - babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize); - if(babel_ifp->sendbuf == NULL) { - zlog_err("Couldn't reallocate sendbuf."); - free(tmp); - babel_ifp->bufsize = 0; - return -1; - } - tmp = NULL; - - resize_receive_buffer(mtu); - - memset(&mreq, 0, sizeof(mreq)); - memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); - mreq.ipv6mr_interface = ifp->ifindex; - - rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, - (char*)&mreq, sizeof(mreq)); - if(rc < 0) { - zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s", - ifp->name, safe_strerror(errno)); - /* This is probably due to a missing link-local address, - so down this interface, and wait until the main loop - tries to up it again. */ - interface_reset(ifp); - return -1; - } - - set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); - set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); - send_hello(ifp); - send_request(ifp, NULL, 0); - - update_interface_metric(ifp); - - debugf(BABEL_DEBUG_COMMON, - "Upped interface %s (%s, cost=%d, channel=%d%s).", - ifp->name, - (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", - babel_ifp->cost, - babel_ifp->channel, - babel_ifp->ipv4 ? ", IPv4" : ""); - - if(rc > 0) - send_update(ifp, 0, NULL, 0); - - return 1; -} - -/* Reset the interface as it was new: it's not removed from the interface list, - and may be considered as a upped interface. */ -static int -interface_reset(struct interface *ifp) -{ - int rc; - struct ipv6_mreq mreq; - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - - if (!(babel_ifp->flags & BABEL_IF_IS_UP)) - return 0; - - debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name); - babel_ifp->flags &= ~BABEL_IF_IS_UP; - - flush_interface_routes(ifp, 0); - babel_ifp->buffered = 0; - babel_ifp->bufsize = 0; - free(babel_ifp->sendbuf); - babel_ifp->num_buffered_updates = 0; - babel_ifp->update_bufsize = 0; - if(babel_ifp->buffered_updates) - free(babel_ifp->buffered_updates); - babel_ifp->buffered_updates = NULL; - babel_ifp->sendbuf = NULL; - - if(ifp->ifindex > 0) { - memset(&mreq, 0, sizeof(mreq)); - memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); - mreq.ipv6mr_interface = ifp->ifindex; - rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - (char*)&mreq, sizeof(mreq)); - if(rc < 0) - zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s", - ifp->name, safe_strerror(errno)); - } - - update_interface_metric(ifp); - - debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).", - ifp->name, - (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", - babel_ifp->cost, - babel_ifp->ipv4 ? ", IPv4" : ""); - - return 1; -} - -/* Send retraction to all, and reset all interfaces statistics. */ -void -babel_interface_close_all(void) -{ - struct interface *ifp = NULL; - struct listnode *linklist_node = NULL; - - FOR_ALL_INTERFACES(ifp, linklist_node) { - if(!if_up(ifp)) - continue; - send_wildcard_retraction(ifp); - /* Make sure that we expire quickly from our neighbours' - association caches. */ - send_hello_noupdate(ifp, 10); - flushbuf(ifp); - usleep(roughly(1000)); - gettime(&babel_now); - } - FOR_ALL_INTERFACES(ifp, linklist_node) { - if(!if_up(ifp)) - continue; - /* Make sure they got it. */ - send_wildcard_retraction(ifp); - send_hello_noupdate(ifp, 1); - flushbuf(ifp); - usleep(roughly(10000)); - gettime(&babel_now); - interface_reset(ifp); - } -} - -/* return "true" if address is one of our ipv6 addresses */ -int -is_interface_ll_address(struct interface *ifp, const unsigned char *address) -{ - struct connected *connected; - struct listnode *node; - - if(!if_up(ifp)) - return 0; - - FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) { - if(connected->address->family == AF_INET6 && - memcmp(&connected->address->u.prefix6, address, 16) == 0) - return 1; - } - - return 0; -} - -static void -show_babel_interface_sub (struct vty *vty, struct interface *ifp) -{ - int is_up; - babel_interface_nfo *babel_ifp; - - vty_out (vty, "%s is %s%s", ifp->name, - ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE); - vty_out (vty, " ifindex %u, MTU %u bytes %s%s", - ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE); - - if (babel_enable_if_lookup (ifp->name) < 0) - { - vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE); - return; - } - if (!is_up) - { - vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE); - return; - } - babel_ifp = babel_get_if_nfo (ifp); - vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE); - vty_out (vty, " Operating mode is \"%s\"%s", - CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE); - vty_out (vty, " Split horizon mode is %s%s", - CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE); - vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE); - vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE); -} - -DEFUN (show_babel_interface, - show_babel_interface_cmd, - "show babel interface [INTERFACE]", - SHOW_STR - IP_STR - "Babel information\n" - "Interface information\n" - "Interface name\n") -{ - struct interface *ifp; - struct listnode *node; - - if (argc == 0) - { - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) - show_babel_interface_sub (vty, ifp); - return CMD_SUCCESS; - } - if ((ifp = if_lookup_by_name (argv[0])) == NULL) - { - vty_out (vty, "No such interface name%s", VTY_NEWLINE); - return CMD_WARNING; - } - show_babel_interface_sub (vty, ifp); - return CMD_SUCCESS; -} - -static void -show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh) -{ - vty_out (vty, - "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s", - format_address(neigh->address), - neigh->ifp->name, - neigh->reach, - neighbour_rxcost(neigh), - neigh->txcost, - if_up(neigh->ifp) ? "" : " (down)", - VTY_NEWLINE); -} - -DEFUN (show_babel_neighbour, - show_babel_neighbour_cmd, - "show babel neighbour [INTERFACE]", - SHOW_STR - IP_STR - "Babel information\n" - "Print neighbours\n" - "Interface name\n") -{ - struct neighbour *neigh; - struct interface *ifp; - - if (argc == 0) { - FOR_ALL_NEIGHBOURS(neigh) { - show_babel_neighbour_sub(vty, neigh); - } - return CMD_SUCCESS; - } - if ((ifp = if_lookup_by_name (argv[0])) == NULL) - { - vty_out (vty, "No such interface name%s", VTY_NEWLINE); - return CMD_WARNING; - } - FOR_ALL_NEIGHBOURS(neigh) { - if(ifp->ifindex == neigh->ifp->ifindex) { - show_babel_neighbour_sub(vty, neigh); - } - } - return CMD_SUCCESS; -} - -static void -show_babel_routes_sub (struct babel_route *route, void *closure) -{ - struct vty *vty = (struct vty*) closure; - const unsigned char *nexthop = - memcmp(route->nexthop, route->neigh->address, 16) == 0 ? - NULL : route->nexthop; - char channels[100]; - - if(route->channels[0] == 0) - channels[0] = '\0'; - else { - int k, j = 0; - snprintf(channels, 100, " chan ("); - j = strlen(channels); - for(k = 0; k < DIVERSITY_HOPS; k++) { - if(route->channels[k] == 0) - break; - if(k > 0) - channels[j++] = ','; - snprintf(channels + j, 100 - j, "%d", route->channels[k]); - j = strlen(channels); - } - snprintf(channels + j, 100 - j, ")"); - if(k == 0) - channels[0] = '\0'; - } - - vty_out(vty, - "%s metric %d refmetric %d id %s seqno %d%s age %d " - "via %s neigh %s%s%s%s%s", - format_prefix(route->src->prefix, route->src->plen), - route_metric(route), route->refmetric, - format_eui64(route->src->id), - (int)route->seqno, - channels, - (int)(babel_now.tv_sec - route->time), - route->neigh->ifp->name, - format_address(route->neigh->address), - nexthop ? " nexthop " : "", - nexthop ? format_address(nexthop) : "", - route->installed ? " (installed)" : - route_feasible(route) ? " (feasible)" : "", - VTY_NEWLINE); -} - -static void -show_babel_xroutes_sub (struct xroute *xroute, void *closure) -{ - struct vty *vty = (struct vty *) closure; - vty_out(vty, "%s metric %d (exported)%s", - format_prefix(xroute->prefix, xroute->plen), - xroute->metric, - VTY_NEWLINE); -} - -DEFUN (show_babel_database, - show_babel_database_cmd, - "show babel database", - SHOW_STR - IP_STR - "Babel information\n" - "Database information\n" - "No attributes\n") -{ - for_all_routes(show_babel_routes_sub, vty); - for_all_xroutes(show_babel_xroutes_sub, vty); - return CMD_SUCCESS; -} - -DEFUN (show_babel_parameters, - show_babel_parameters_cmd, - "show babel parameters", - SHOW_STR - IP_STR - "Babel information\n" - "Configuration information\n" - "No attributes\n") -{ - vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE); - show_babel_main_configuration(vty); - vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE); - config_show_distribute(vty); - - return CMD_SUCCESS; -} - -void -babel_if_init () -{ - /* initialize interface list */ - if_init(); - if_add_hook (IF_NEW_HOOK, babel_if_new_hook); - if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook); - - babel_enable_if = vector_init (1); - - /* install interface node and commands */ - install_element (CONFIG_NODE, &interface_cmd); - install_element (CONFIG_NODE, &no_interface_cmd); - install_node (&babel_interface_node, interface_config_write); - install_default(INTERFACE_NODE); - install_element(INTERFACE_NODE, &interface_cmd); - install_element(INTERFACE_NODE, &no_interface_cmd); - - install_element(BABEL_NODE, &babel_network_cmd); - install_element(BABEL_NODE, &no_babel_network_cmd); - install_element(INTERFACE_NODE, &babel_split_horizon_cmd); - install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd); - install_element(INTERFACE_NODE, &babel_set_wired_cmd); - install_element(INTERFACE_NODE, &babel_set_wireless_cmd); - install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); - install_element(INTERFACE_NODE, &babel_set_update_interval_cmd); - - /* "show babel ..." commands */ - install_element(VIEW_NODE, &show_babel_interface_cmd); - install_element(ENABLE_NODE, &show_babel_interface_cmd); - install_element(VIEW_NODE, &show_babel_neighbour_cmd); - install_element(ENABLE_NODE, &show_babel_neighbour_cmd); - install_element(VIEW_NODE, &show_babel_database_cmd); - install_element(ENABLE_NODE, &show_babel_database_cmd); - install_element(VIEW_NODE, &show_babel_parameters_cmd); - install_element(ENABLE_NODE, &show_babel_parameters_cmd); -} - -/* hooks: functions called respectively when struct interface is - created or deleted. */ -static int -babel_if_new_hook (struct interface *ifp) -{ - ifp->info = babel_interface_allocate(); - return 0; -} - -static int -babel_if_delete_hook (struct interface *ifp) -{ - babel_interface_free(ifp->info); - ifp->info = NULL; - return 0; -} - -/* Output an "interface" section for each of the known interfaces with -babeld-specific statement lines where appropriate. */ -static int -interface_config_write (struct vty *vty) -{ - struct listnode *node; - struct interface *ifp; - int write = 0; - - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { - vty_out (vty, "interface %s%s", ifp->name, - VTY_NEWLINE); - if (ifp->desc) - vty_out (vty, " description %s%s", ifp->desc, - VTY_NEWLINE); - if (IS_ENABLE (ifp)) - { - babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); - /* wireless/no split-horizon is the default */ - if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) - { - vty_out (vty, " babel wired%s", VTY_NEWLINE); - write++; - } - if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) - { - vty_out (vty, " babel split-horizon%s", VTY_NEWLINE); - write++; - } - if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL) - { - vty_out (vty, " babel hello-interval %u%s", babel_ifp->hello_interval, VTY_NEWLINE); - write++; - } - if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL) - { - vty_out (vty, " babel update-interval %u%s", babel_ifp->update_interval, VTY_NEWLINE); - write++; - } - } - vty_out (vty, "!%s", VTY_NEWLINE); - write++; - } - return write; -} - -/* Output a "network" statement line for each of the enabled interfaces. */ -int -babel_enable_if_config_write (struct vty * vty) -{ - unsigned int i, lines = 0; - char *str; - - for (i = 0; i < vector_active (babel_enable_if); i++) - if ((str = vector_slot (babel_enable_if, i)) != NULL) - { - vty_out (vty, " network %s%s", str, VTY_NEWLINE); - lines++; - } - return lines; -} - -/* functions to allocate or free memory for a babel_interface_nfo, filling - needed fields */ -static babel_interface_nfo * -babel_interface_allocate (void) -{ - babel_interface_nfo *babel_ifp; - babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); - if(babel_ifp == NULL) - return NULL; - - /* Here are set the default values for an interface. */ - memset(babel_ifp, 0, sizeof(babel_interface_nfo)); - /* All flags are unset */ - babel_ifp->bucket_time = babel_now.tv_sec; - babel_ifp->bucket = BUCKET_TOKENS_MAX; - babel_ifp->hello_seqno = (random() & 0xFFFF); - babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL; - babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL; - babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; - babel_set_wired_internal(babel_ifp, 0); - - return babel_ifp; -} - -static void -babel_interface_free (babel_interface_nfo *babel_ifp) -{ - XFREE(MTYPE_BABEL_IF, babel_ifp); -} diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h deleted file mode 100644 index 94fd8e5d7..000000000 --- a/babeld/babel_interface.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABEL_INTERFACE_H -#define BABEL_INTERFACE_H - -#include -#include "zclient.h" -#include "vty.h" - -#define CONFIG_DEFAULT 0 -#define CONFIG_NO 1 -#define CONFIG_YES 2 - -/* babeld interface informations */ -struct babel_interface { - unsigned short flags; /* see below */ - unsigned short cost; - int channel; - struct timeval hello_timeout; - struct timeval update_timeout; - struct timeval flush_timeout; - struct timeval update_flush_timeout; - unsigned char *ipv4; - int buffered; - int bufsize; - char have_buffered_hello; - char have_buffered_id; - char have_buffered_nh; - char have_buffered_prefix; - unsigned char buffered_id[16]; - unsigned char buffered_nh[4]; - unsigned char buffered_prefix[16]; - unsigned char *sendbuf; - struct buffered_update *buffered_updates; - int num_buffered_updates; - int update_bufsize; - time_t bucket_time; - unsigned int bucket; - time_t last_update_time; - unsigned short hello_seqno; - unsigned hello_interval; - unsigned update_interval; - - /* For filter type slot. */ -#define BABEL_FILTER_IN 0 -#define BABEL_FILTER_OUT 1 -#define BABEL_FILTER_MAX 2 - struct access_list *list[BABEL_FILTER_MAX]; /* Access-list. */ - struct prefix_list *prefix[BABEL_FILTER_MAX]; /* Prefix-list. */ -}; - -typedef struct babel_interface babel_interface_nfo; -static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) -{ - return ((babel_interface_nfo*) ifp->info); -} - -/* babel_interface_nfo flags */ -#define BABEL_IF_IS_UP (1 << 0) -#define BABEL_IF_WIRED (1 << 1) -#define BABEL_IF_SPLIT_HORIZON (1 << 2) -#define BABEL_IF_LQ (1 << 3) -#define BABEL_IF_FARAWAY (1 << 4) - -/* Only INTERFERING can appear on the wire. */ -#define BABEL_IF_CHANNEL_UNKNOWN 0 -#define BABEL_IF_CHANNEL_INTERFERING 255 -#define BABEL_IF_CHANNEL_NONINTERFERING -2 - -static inline int -if_up(struct interface *ifp) -{ - return (if_is_operative(ifp) && - ifp->connected != NULL && - (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP)); -} - -/* types: - struct interface _ifp, struct listnode node */ -#define FOR_ALL_INTERFACES(_ifp, _node) \ - for(ALL_LIST_ELEMENTS_RO(iflist, _node, _ifp)) - -/* types: - struct interface *ifp, struct connected *_connected, struct listnode *node */ -#define FOR_ALL_INTERFACES_ADDRESSES(ifp, _connected, _node) \ - for(ALL_LIST_ELEMENTS_RO(ifp->connected, _node, _connected)) - -struct buffered_update { - unsigned char id[8]; - unsigned char prefix[16]; - unsigned char plen; - unsigned char pad[3]; -}; - - -/* init function */ -void babel_if_init(void); - -/* Callback functions for zebra client */ -int babel_interface_up (int, struct zclient *, zebra_size_t); -int babel_interface_down (int, struct zclient *, zebra_size_t); -int babel_interface_add (int, struct zclient *, zebra_size_t); -int babel_interface_delete (int, struct zclient *, zebra_size_t); -int babel_interface_address_add (int, struct zclient *, zebra_size_t); -int babel_interface_address_delete (int, struct zclient *, zebra_size_t); - -unsigned jitter(babel_interface_nfo *, int); -unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); -/* return "true" if "address" is one of our ipv6 addresses */ -int is_interface_ll_address(struct interface *ifp, const unsigned char *address); -/* Send retraction to all, and reset all interfaces statistics. */ -void babel_interface_close_all(void); -extern int babel_enable_if_config_write (struct vty *); - - -#endif diff --git a/babeld/babel_main.c b/babeld/babel_main.c deleted file mode 100644 index 529c3f295..000000000 --- a/babeld/babel_main.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* include zebra library */ -#include -#include "getopt.h" -#include "if.h" -#include "log.h" -#include "thread.h" -#include "privs.h" -#include "sigevent.h" -#include "version.h" -#include "command.h" -#include "vty.h" -#include "memory.h" - -#include "babel_main.h" -#include "babeld.h" -#include "util.h" -#include "kernel.h" -#include "babel_interface.h" -#include "neighbour.h" -#include "route.h" -#include "xroute.h" -#include "message.h" -#include "resend.h" -#include "babel_zebra.h" - - -static void babel_init (int argc, char **argv); -static char *babel_get_progname(char *argv_0); -static void babel_fail(void); -static void babel_init_random(void); -static void babel_replace_by_null(int fd); -static void babel_init_signals(void); -static void babel_exit_properly(void); -static void babel_save_state_file(void); - - -struct thread_master *master; /* quagga's threads handler */ -struct timeval babel_now; /* current time */ - -unsigned char myid[8]; /* unique id (mac address of an interface) */ -int debug = 0; - -int resend_delay = -1; -static const char *pidfile = PATH_BABELD_PID; - -const unsigned char zeroes[16] = {0}; -const unsigned char ones[16] = - {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - -static const char *state_file = DAEMON_VTY_DIR "/babel-state"; - -unsigned char protocol_group[16]; /* babel's link-local multicast address */ -int protocol_port; /* babel's port */ -int protocol_socket = -1; /* socket: communicate with others babeld */ - -static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; -static char *babel_config_file = NULL; -static char *babel_vty_addr = NULL; -static int babel_vty_port = BABEL_VTY_PORT; - -/* Babeld options. */ -struct option longopts[] = -{ - { "daemon", no_argument, NULL, 'd'}, - { "config_file", required_argument, NULL, 'f'}, - { "pid_file", required_argument, NULL, 'i'}, - { "socket", required_argument, NULL, 'z'}, - { "help", no_argument, NULL, 'h'}, - { "vty_addr", required_argument, NULL, 'A'}, - { "vty_port", required_argument, NULL, 'P'}, - { "user", required_argument, NULL, 'u'}, - { "group", required_argument, NULL, 'g'}, - { "version", no_argument, NULL, 'v'}, - { 0 } -}; - -/* babeld privileges */ -static zebra_capabilities_t _caps_p [] = -{ - ZCAP_NET_RAW, - ZCAP_BIND -}; -static struct zebra_privs_t babeld_privs = -{ -#if defined(QUAGGA_USER) - .user = QUAGGA_USER, -#endif -#if defined QUAGGA_GROUP - .group = QUAGGA_GROUP, -#endif -#ifdef VTY_GROUP - .vty_group = VTY_GROUP, -#endif - .caps_p = _caps_p, - .cap_num_p = 2, - .cap_num_i = 0 -}; - - -int -main(int argc, char **argv) -{ - struct thread thread; - /* and print banner too */ - babel_init(argc, argv); - while (thread_fetch (master, &thread)) { - thread_call (&thread); - } - return 0; -} - -static void -babel_usage (char *progname, int status) -{ - if (status != 0) - fprintf (stderr, "Try `%s --help' for more information.\n", progname); - else - { - printf ("Usage : %s [OPTION...]\n\ -Daemon which manages Babel routing protocol.\n\n\ --d, --daemon Runs in daemon mode\n\ --f, --config_file Set configuration file name\n\ --i, --pid_file Set process identifier file name\n\ --z, --socket Set path of zebra socket\n\ --A, --vty_addr Set vty's bind address\n\ --P, --vty_port Set vty's port number\n\ --u, --user User to run as\n\ --g, --group Group to run as\n\ --v, --version Print program version\n\ --h, --help Display this help and exit\n\ -\n\ -Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); - } - exit (status); -} - -/* make initialisations witch don't need infos about kernel(interfaces, etc.) */ -static void -babel_init(int argc, char **argv) -{ - int rc, opt; - int do_daemonise = 0; - char *progname = NULL; - - /* Set umask before anything for security */ - umask (0027); - progname = babel_get_progname(argv[0]); - - /* set default log (lib/log.h) */ - zlog_default = openzlog(progname, ZLOG_BABEL, - LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); - /* set log destination as stdout until the config file is read */ - zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); - - babel_init_random(); - - /* set the Babel's default link-local multicast address and Babel's port */ - parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); - protocol_port = 6696; - - /* get options */ - while(1) { - opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0); - if(opt < 0) - break; - - switch(opt) { - case 0: - break; - case 'd': - do_daemonise = -1; - break; - case 'f': - babel_config_file = optarg; - break; - case 'i': - pidfile = optarg; - break; - case 'z': - zclient_serv_path_set (optarg); - break; - case 'A': - babel_vty_addr = optarg; - break; - case 'P': - babel_vty_port = atoi (optarg); - if (babel_vty_port <= 0 || babel_vty_port > 0xffff) - babel_vty_port = BABEL_VTY_PORT; - break; - case 'u': - babeld_privs.user = optarg; - break; - case 'g': - babeld_privs.group = optarg; - break; - case 'v': - print_version (progname); - exit (0); - break; - case 'h': - babel_usage (progname, 0); - break; - default: - babel_usage (progname, 1); - break; - } - } - - /* create the threads handler */ - master = thread_master_create (); - - /* Library inits. */ - zprivs_init (&babeld_privs); - babel_init_signals(); - cmd_init (1); - vty_init (master); - memory_init (); - - resend_delay = BABEL_DEFAULT_RESEND_DELAY; - - babel_replace_by_null(STDIN_FILENO); - - if (do_daemonise && daemonise() < 0) { - zlog_err("daemonise: %s", safe_strerror(errno)); - exit (1); - } - - /* write pid file */ - if (pid_output(pidfile) < 0) { - zlog_err("error while writing pidfile"); - exit (1); - }; - - /* init some quagga's dependencies, and babeld's commands */ - babeld_quagga_init(); - /* init zebra client's structure and it's commands */ - /* this replace kernel_setup && kernel_setup_socket */ - babelz_zebra_init (); - - /* Get zebra configuration file. */ - zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); - vty_read_config (babel_config_file, babel_config_default); - - /* Create VTY socket */ - vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH); - - /* init buffer */ - rc = resize_receive_buffer(1500); - if(rc < 0) - babel_fail(); - - schedule_neighbours_check(5000, 1); - - zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port); -} - -/* return the progname (without path, example: "./x/progname" --> "progname") */ -static char * -babel_get_progname(char *argv_0) { - char *p = strrchr (argv_0, '/'); - return (p ? ++p : argv_0); -} - -static void -babel_fail(void) -{ - exit(1); -} - -/* initialize random value, and set 'babel_now' by the way. */ -static void -babel_init_random(void) -{ - gettime(&babel_now); - int rc; - unsigned int seed; - - rc = read_random_bytes(&seed, sizeof(seed)); - if(rc < 0) { - zlog_err("read(random): %s", safe_strerror(errno)); - seed = 42; - } - - seed ^= (babel_now.tv_sec ^ babel_now.tv_usec); - srandom(seed); -} - -/* - close fd, and replace it by "/dev/null" - exit if error - */ -static void -babel_replace_by_null(int fd) -{ - int fd_null; - int rc; - - fd_null = open("/dev/null", O_RDONLY); - if(fd_null < 0) { - zlog_err("open(null): %s", safe_strerror(errno)); - exit(1); - } - - rc = dup2(fd_null, fd); - if(rc < 0) { - zlog_err("dup2(null, 0): %s", safe_strerror(errno)); - exit(1); - } - - close(fd_null); -} - -/* - Load the state file: check last babeld's running state, usefull in case of - "/etc/init.d/babeld restart" - */ -void -babel_load_state_file(void) -{ - int fd; - int rc; - - fd = open(state_file, O_RDONLY); - if(fd < 0 && errno != ENOENT) - zlog_err("open(babel-state: %s)", safe_strerror(errno)); - rc = unlink(state_file); - if(fd >= 0 && rc < 0) { - zlog_err("unlink(babel-state): %s", safe_strerror(errno)); - /* If we couldn't unlink it, it's probably stale. */ - close(fd); - fd = -1; - } - if(fd >= 0) { - char buf[100]; - char buf2[100]; - int s; - long t; - rc = read(fd, buf, 99); - if(rc < 0) { - zlog_err("read(babel-state): %s", safe_strerror(errno)); - } else { - buf[rc] = '\0'; - rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t); - if(rc == 3 && s >= 0 && s <= 0xFFFF) { - unsigned char sid[8]; - rc = parse_eui64(buf2, sid); - if(rc < 0) { - zlog_err("Couldn't parse babel-state."); - } else { - struct timeval realnow; - debugf(BABEL_DEBUG_COMMON, - "Got %s %d %ld from babel-state.", - format_eui64(sid), s, t); - gettimeofday(&realnow, NULL); - if(memcmp(sid, myid, 8) == 0) - myseqno = seqno_plus(s, 1); - else - zlog_err("ID mismatch in babel-state. id=%s; old=%s", - format_eui64(myid), - format_eui64(sid)); - } - } else { - zlog_err("Couldn't parse babel-state."); - } - } - close(fd); - fd = -1; - } -} - -static void -babel_sigexit(void) -{ - zlog_notice("Terminating on signal"); - - babel_exit_properly(); -} - -static void -babel_sigusr1 (void) -{ - zlog_rotate (NULL); -} - -static void -babel_init_signals(void) -{ - static struct quagga_signal_t babel_signals[] = - { - { - .signal = SIGUSR1, - .handler = &babel_sigusr1, - }, - { - .signal = SIGINT, - .handler = &babel_sigexit, - }, - { - .signal = SIGTERM, - .handler = &babel_sigexit, - }, - }; - - signal_init (master, array_size(babel_signals), babel_signals); -} - -static void -babel_exit_properly(void) -{ - debugf(BABEL_DEBUG_COMMON, "Exiting..."); - usleep(roughly(10000)); - gettime(&babel_now); - - /* Uninstall and flush all routes. */ - debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); - flush_all_routes(); - babel_interface_close_all(); - babel_zebra_close_connexion(); - babel_save_state_file(); - debugf(BABEL_DEBUG_COMMON, "Remove pid file."); - if(pidfile) - unlink(pidfile); - debugf(BABEL_DEBUG_COMMON, "Done."); - - exit(0); -} - -static void -babel_save_state_file(void) -{ - int fd; - int rc; - - debugf(BABEL_DEBUG_COMMON, "Save state file."); - fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644); - if(fd < 0) { - zlog_err("creat(babel-state): %s", safe_strerror(errno)); - unlink(state_file); - } else { - struct timeval realnow; - char buf[100]; - gettimeofday(&realnow, NULL); - rc = snprintf(buf, 100, "%s %d %ld\n", - format_eui64(myid), (int)myseqno, - (long)realnow.tv_sec); - if(rc < 0 || rc >= 100) { - zlog_err("write(babel-state): overflow."); - unlink(state_file); - } else { - rc = write(fd, buf, rc); - if(rc < 0) { - zlog_err("write(babel-state): %s", safe_strerror(errno)); - unlink(state_file); - } - fsync(fd); - } - close(fd); - } -} - -void -show_babel_main_configuration (struct vty *vty) -{ - vty_out(vty, - "pid file = %s%s" - "state file = %s%s" - "configuration file = %s%s" - "protocol informations:%s" - " multicast address = %s%s" - " port = %d%s" - "vty address = %s%s" - "vty port = %d%s" - "id = %s%s" - "allow_duplicates = %s%s" - "kernel_metric = %d%s", - pidfile, VTY_NEWLINE, - state_file, VTY_NEWLINE, - babel_config_file ? babel_config_file : babel_config_default, - VTY_NEWLINE, - VTY_NEWLINE, - format_address(protocol_group), VTY_NEWLINE, - protocol_port, VTY_NEWLINE, - babel_vty_addr ? babel_vty_addr : "None", - VTY_NEWLINE, - babel_vty_port, VTY_NEWLINE, - format_eui64(myid), VTY_NEWLINE, - format_bool(allow_duplicates), VTY_NEWLINE, - kernel_metric, VTY_NEWLINE); -} diff --git a/babeld/babel_main.h b/babeld/babel_main.h deleted file mode 100644 index a4038decb..000000000 --- a/babeld/babel_main.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "vty.h" - -extern struct timeval babel_now; /* current time */ -extern struct thread_master *master; /* quagga's threads handler */ -extern int debug; -extern int resend_delay; - -extern unsigned char myid[8]; - -extern const unsigned char zeroes[16], ones[16]; - -extern int protocol_port; -extern unsigned char protocol_group[16]; -extern int protocol_socket; -extern int kernel_socket; -extern int max_request_hopcount; - -void babel_load_state_file(void); -void show_babel_main_configuration (struct vty *vty); diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c deleted file mode 100644 index 75a1e6a84..000000000 --- a/babeld/babel_zebra.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* quagga's includes */ -#include -#include "command.h" -#include "zclient.h" -#include "stream.h" - -/* babel's includes*/ -#include "babel_zebra.h" -#include "babel_interface.h" -#include "xroute.h" -#include "util.h" - -void babelz_zebra_init(void); - - -/* we must use a pointer because of zclient.c's functions (new, free). */ -struct zclient *zclient; -static int zebra_config_write (struct vty *vty); - -/* Debug types */ -static struct { - int type; - int str_min_len; - const char *str; -} debug_type[] = { - {BABEL_DEBUG_COMMON, 1, "common"}, - {BABEL_DEBUG_KERNEL, 1, "kernel"}, - {BABEL_DEBUG_FILTER, 1, "filter"}, - {BABEL_DEBUG_TIMEOUT, 1, "timeout"}, - {BABEL_DEBUG_IF, 1, "interface"}, - {BABEL_DEBUG_ROUTE, 1, "route"}, - {BABEL_DEBUG_ALL, 1, "all"}, - {0, 0, NULL} -}; - -/* Zebra node structure. */ -struct cmd_node zebra_node = -{ - ZEBRA_NODE, - "%s(config-router)# ", - 1 /* vtysh? yes */ -}; - - -/* Zebra route add and delete treatment (ipv6). */ -static int -babel_zebra_read_ipv6 (int command, struct zclient *zclient, - zebra_size_t length) -{ - struct stream *s; - struct zapi_ipv6 api; - unsigned long ifindex = -1; - struct in6_addr nexthop; - struct prefix_ipv6 prefix; - - s = zclient->ibuf; - ifindex = 0; - memset (&nexthop, 0, sizeof (struct in6_addr)); - memset (&api, 0, sizeof(struct zapi_ipv6)); - memset (&prefix, 0, sizeof (struct prefix_ipv6)); - - /* Type, flags, message. */ - api.type = stream_getc (s); - api.flags = stream_getc (s); - api.message = stream_getc (s); - - /* IPv6 prefix. */ - prefix.family = AF_INET6; - prefix.prefixlen = stream_getc (s); - stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); - - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc (s); - stream_get (&nexthop, s, sizeof(nexthop)); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; - - if (command == ZEBRA_IPV6_ROUTE_ADD) - babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop); - else - babel_ipv6_route_delete(&api, &prefix, ifindex); - - return 0; -} - -static int -babel_zebra_read_ipv4 (int command, struct zclient *zclient, - zebra_size_t length) -{ - struct stream *s; - struct zapi_ipv4 api; - unsigned long ifindex = -1; - struct in_addr nexthop; - struct prefix_ipv4 prefix; - - s = zclient->ibuf; - ifindex = 0; - memset (&nexthop, 0, sizeof (struct in_addr)); - memset (&api, 0, sizeof(struct zapi_ipv4)); - memset (&prefix, 0, sizeof (struct prefix_ipv4)); - - /* Type, flags, message. */ - api.type = stream_getc (s); - api.flags = stream_getc (s); - api.message = stream_getc (s); - - /* IPv6 prefix. */ - prefix.family = AF_INET; - prefix.prefixlen = stream_getc (s); - stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); - - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc (s); - stream_get (&nexthop, s, sizeof(nexthop)); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; - - if (command == ZEBRA_IPV6_ROUTE_ADD) { - babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop); - } else { - babel_ipv4_route_delete(&api, &prefix, ifindex); - } - - return 0; -} - -/* [Babel Command] */ -DEFUN (babel_redistribute_type, - babel_redistribute_type_cmd, - "redistribute " QUAGGA_REDIST_STR_BABELD, - "Redistribute\n" - QUAGGA_REDIST_HELP_STR_BABELD) -{ - int type; - - type = proto_redistnum(AFI_IP6, argv[0]); - - if (type < 0) - type = proto_redistnum(AFI_IP, argv[0]); - - if (type < 0) { - vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); - return CMD_SUCCESS; -} - -/* [Babel Command] */ -DEFUN (no_babel_redistribute_type, - no_babel_redistribute_type_cmd, - "no redistribute " QUAGGA_REDIST_STR_BABELD, - NO_STR - "Redistribute\n" - QUAGGA_REDIST_HELP_STR_BABELD) -{ - int type; - - type = proto_redistnum(AFI_IP6, argv[0]); - - if (type < 0) - type = proto_redistnum(AFI_IP, argv[0]); - - if (type < 0) { - vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); - /* perhaps should we remove xroutes having the same type... */ - return CMD_SUCCESS; -} - -#ifndef NO_DEBUG -/* [Babel Command] */ -DEFUN (debug_babel, - debug_babel_cmd, - "debug babel (common|kernel|filter|timeout|interface|route|all)", - "Enable debug messages for specific or all part.\n" - "Babel information\n" - "Common messages (default)\n" - "Kernel messages\n" - "Filter messages\n" - "Timeout messages\n" - "Interface messages\n" - "Route messages\n" - "All messages\n") -{ - int i; - - for(i = 0; debug_type[i].str != NULL; i++) { - if (strncmp (debug_type[i].str, argv[0], - debug_type[i].str_min_len) == 0) { - debug |= debug_type[i].type; - return CMD_SUCCESS; - } - } - - vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); - - return CMD_WARNING; -} - -/* [Babel Command] */ -DEFUN (no_debug_babel, - no_debug_babel_cmd, - "no debug babel (common|kernel|filter|timeout|interface|route|all)", - NO_STR - "Disable debug messages for specific or all part.\n" - "Babel information\n" - "Common messages (default)\n" - "Kernel messages\n" - "Filter messages\n" - "Timeout messages\n" - "Interface messages\n" - "Route messages\n" - "All messages\n") -{ - int i; - - for (i = 0; debug_type[i].str; i++) { - if (strncmp(debug_type[i].str, argv[0], - debug_type[i].str_min_len) == 0) { - debug &= ~debug_type[i].type; - return CMD_SUCCESS; - } - } - - vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); - - return CMD_WARNING; -} -#endif /* NO_DEBUG */ - -/* Output "debug" statement lines, if necessary. */ -int -debug_babel_config_write (struct vty * vty) -{ -#ifdef NO_DEBUG - return 0; -#else - int i, lines = 0; - - if (debug == BABEL_DEBUG_ALL) - { - vty_out (vty, "debug babel all%s", VTY_NEWLINE); - lines++; - } - else - for (i = 0; debug_type[i].str != NULL; i++) - if - ( - debug_type[i].type != BABEL_DEBUG_ALL - && CHECK_FLAG (debug, debug_type[i].type) - ) - { - vty_out (vty, "debug babel %s%s", debug_type[i].str, VTY_NEWLINE); - lines++; - } - if (lines) - { - vty_out (vty, "!%s", VTY_NEWLINE); - lines++; - } - return lines; -#endif /* NO_DEBUG */ -} - -void babelz_zebra_init(void) -{ - zclient = zclient_new(); - zclient_init(zclient, ZEBRA_ROUTE_BABEL); - - zclient->interface_add = babel_interface_add; - zclient->interface_delete = babel_interface_delete; - zclient->interface_up = babel_interface_up; - zclient->interface_down = babel_interface_down; - zclient->interface_address_add = babel_interface_address_add; - zclient->interface_address_delete = babel_interface_address_delete; - zclient->ipv4_route_add = babel_zebra_read_ipv4; - zclient->ipv4_route_delete = babel_zebra_read_ipv4; - zclient->ipv6_route_add = babel_zebra_read_ipv6; - zclient->ipv6_route_delete = babel_zebra_read_ipv6; - - install_node (&zebra_node, zebra_config_write); - install_element(BABEL_NODE, &babel_redistribute_type_cmd); - install_element(BABEL_NODE, &no_babel_redistribute_type_cmd); - install_element(ENABLE_NODE, &debug_babel_cmd); - install_element(ENABLE_NODE, &no_debug_babel_cmd); - install_element(CONFIG_NODE, &debug_babel_cmd); - install_element(CONFIG_NODE, &no_debug_babel_cmd); -} - -static int -zebra_config_write (struct vty *vty) -{ - if (! zclient->enable) - { - vty_out (vty, "no router zebra%s", VTY_NEWLINE); - return 1; - } - else if (! zclient->redist[ZEBRA_ROUTE_BABEL]) - { - vty_out (vty, "router zebra%s", VTY_NEWLINE); - vty_out (vty, " no redistribute babel%s", VTY_NEWLINE); - return 1; - } - return 0; -} - -void -babel_zebra_close_connexion(void) -{ - zclient_stop(zclient); -} diff --git a/babeld/babel_zebra.h b/babeld/babel_zebra.h deleted file mode 100644 index 99601aa7c..000000000 --- a/babeld/babel_zebra.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABEL_ZEBRA_H -#define BABEL_ZEBRA_H - -#include "vty.h" - -extern struct zclient *zclient; - -void babelz_zebra_init(void); -void babel_zebra_close_connexion(void); -extern int debug_babel_config_write (struct vty *); - -#endif diff --git a/babeld/babeld.c b/babeld/babeld.c deleted file mode 100644 index eaa91b74c..000000000 --- a/babeld/babeld.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "command.h" -#include "prefix.h" -#include "memory.h" -#include "memtypes.h" -#include "table.h" -#include "distribute.h" -#include "prefix.h" -#include "filter.h" -#include "plist.h" - -#include "babel_main.h" -#include "babeld.h" -#include "util.h" -#include "net.h" -#include "kernel.h" -#include "babel_interface.h" -#include "neighbour.h" -#include "route.h" -#include "message.h" -#include "resend.h" -#include "babel_filter.h" -#include "babel_zebra.h" - - -static int babel_init_routing_process(struct thread *thread); -static void babel_get_myid(void); -static void babel_initial_noise(void); -static int babel_read_protocol (struct thread *thread); -static int babel_main_loop(struct thread *thread); -static void babel_set_timer(struct timeval *timeout); -static void babel_fill_with_next_timeout(struct timeval *tv); - - -/* Informations relative to the babel running daemon. */ -static struct babel *babel_routing_process = NULL; -static unsigned char *receive_buffer = NULL; -static int receive_buffer_size = 0; - -/* timeouts */ -struct timeval check_neighbours_timeout; -static time_t expiry_time; -static time_t source_expiry_time; - -/* Babel node structure. */ -static struct cmd_node cmd_babel_node = -{ - .node = BABEL_NODE, - .prompt = "%s(config-router)# ", - .vtysh = 1, -}; - -/* print current babel configuration on vty */ -static int -babel_config_write (struct vty *vty) -{ - int lines = 0; - int i; - - /* list enabled debug modes */ - lines += debug_babel_config_write (vty); - - if (!babel_routing_process) - return lines; - vty_out (vty, "router babel%s", VTY_NEWLINE); - if (resend_delay != BABEL_DEFAULT_RESEND_DELAY) - { - vty_out (vty, " babel resend-delay %u%s", resend_delay, VTY_NEWLINE); - lines++; - } - /* list enabled interfaces */ - lines = 1 + babel_enable_if_config_write (vty); - /* list redistributed protocols */ - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default && zclient->redist[i]) - { - vty_out (vty, " redistribute %s%s", zebra_route_string (i), VTY_NEWLINE); - lines++; - } - - return lines; -} - - -static int -babel_create_routing_process (void) -{ - assert (babel_routing_process == NULL); - - /* Allocaste Babel instance. */ - babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel)); - - /* Initialize timeouts */ - gettime(&babel_now); - expiry_time = babel_now.tv_sec + roughly(30); - source_expiry_time = babel_now.tv_sec + roughly(300); - - /* Make socket for Babel protocol. */ - protocol_socket = babel_socket(protocol_port); - if (protocol_socket < 0) { - zlog_err("Couldn't create link local socket: %s", safe_strerror(errno)); - goto fail; - } - - /* Threads. */ - babel_routing_process->t_read = - thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); - /* wait a little: zebra will announce interfaces, addresses, routes... */ - babel_routing_process->t_update = - thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L); - return 0; - -fail: - XFREE(MTYPE_BABEL, babel_routing_process); - babel_routing_process = NULL; - return -1; -} - -/* thread reading entries form others babel daemons */ -static int -babel_read_protocol (struct thread *thread) -{ - int rc; - struct interface *ifp = NULL; - struct sockaddr_in6 sin6; - struct listnode *linklist_node = NULL; - - assert(babel_routing_process != NULL); - assert(protocol_socket >= 0); - - rc = babel_recv(protocol_socket, - receive_buffer, receive_buffer_size, - (struct sockaddr*)&sin6, sizeof(sin6)); - if(rc < 0) { - if(errno != EAGAIN && errno != EINTR) { - zlog_err("recv: %s", safe_strerror(errno)); - } - } else { - FOR_ALL_INTERFACES(ifp, linklist_node) { - if(!if_up(ifp)) - continue; - if(ifp->ifindex == sin6.sin6_scope_id) { - parse_packet((unsigned char*)&sin6.sin6_addr, ifp, - receive_buffer, rc); - break; - } - } - } - - /* re-add thread */ - babel_routing_process->t_read = - thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); - return 0; -} - -/* Zebra will give some information, especially about interfaces. This function - must be call with a litte timeout wich may give zebra the time to do his job, - making these inits have sense. */ -static int -babel_init_routing_process(struct thread *thread) -{ - myseqno = (random() & 0xFFFF); - babel_get_myid(); - babel_load_state_file(); - debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); - babel_initial_noise(); - babel_main_loop(thread);/* this function self-add to the t_update thread */ - return 0; -} - -/* fill "myid" with an unique id (only if myid != {0}). */ -static void -babel_get_myid(void) -{ - struct interface *ifp = NULL; - struct listnode *linklist_node = NULL; - int rc; - int i; - - /* if we already have an id (from state file), we return. */ - if (memcmp(myid, zeroes, 8) != 0) { - return; - } - - FOR_ALL_INTERFACES(ifp, linklist_node) { - /* ifp->ifindex is not necessarily valid at this point */ - int ifindex = if_nametoindex(ifp->name); - if(ifindex > 0) { - unsigned char eui[8]; - rc = if_eui64(ifp->name, ifindex, eui); - if(rc < 0) - continue; - memcpy(myid, eui, 8); - return; - } - } - - /* We failed to get a global EUI64 from the interfaces we were given. - Let's try to find an interface with a MAC address. */ - for(i = 1; i < 256; i++) { - char buf[IF_NAMESIZE], *ifname; - unsigned char eui[8]; - ifname = if_indextoname(i, buf); - if(ifname == NULL) - continue; - rc = if_eui64(ifname, i, eui); - if(rc < 0) - continue; - memcpy(myid, eui, 8); - return; - } - - zlog_err("Warning: couldn't find router id -- using random value."); - - rc = read_random_bytes(myid, 8); - if(rc < 0) { - zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno)); - exit(1); - } - /* Clear group and global bits */ - myid[0] &= ~3; -} - -/* Make some noise so that others notice us, and send retractions in - case we were restarted recently */ -static void -babel_initial_noise(void) -{ - struct interface *ifp = NULL; - struct listnode *linklist_node = NULL; - - FOR_ALL_INTERFACES(ifp, linklist_node) { - if(!if_up(ifp)) - continue; - /* Apply jitter before we send the first message. */ - usleep(roughly(10000)); - gettime(&babel_now); - send_hello(ifp); - send_wildcard_retraction(ifp); - } - - FOR_ALL_INTERFACES(ifp, linklist_node) { - if(!if_up(ifp)) - continue; - usleep(roughly(10000)); - gettime(&babel_now); - send_hello(ifp); - send_wildcard_retraction(ifp); - send_self_update(ifp); - send_request(ifp, NULL, 0); - flushupdates(ifp); - flushbuf(ifp); - } -} - -/* Delete all the added babel routes, make babeld only speak to zebra. */ -static void -babel_clean_routing_process() -{ - flush_all_routes(); - babel_interface_close_all(); - - /* cancel threads */ - if (babel_routing_process->t_read != NULL) { - thread_cancel(babel_routing_process->t_read); - } - if (babel_routing_process->t_update != NULL) { - thread_cancel(babel_routing_process->t_update); - } - - XFREE(MTYPE_BABEL, babel_routing_process); - babel_routing_process = NULL; -} - -/* Function used with timeout. */ -static int -babel_main_loop(struct thread *thread) -{ - struct timeval tv; - struct interface *ifp = NULL; - struct listnode *linklist_node = NULL; - - while(1) { - gettime(&babel_now); - - /* timeouts --------------------------------------------------------- */ - /* get the next timeout */ - babel_fill_with_next_timeout(&tv); - /* if there is no timeout, we must wait. */ - if(timeval_compare(&tv, &babel_now) > 0) { - timeval_minus(&tv, &tv, &babel_now); - debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs", - tv.tv_sec * 1000LL + tv.tv_usec / 1000LL); - /* it happens often to have less than 1 ms, it's bad. */ - timeval_add_msec(&tv, &tv, 300); - babel_set_timer(&tv); - return 0; - } - - gettime(&babel_now); - - /* update database -------------------------------------------------- */ - if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) { - int msecs; - msecs = check_neighbours(); - msecs = MAX(msecs, 10); - schedule_neighbours_check(msecs, 1); - } - - if(babel_now.tv_sec >= expiry_time) { - expire_routes(); - expire_resend(); - expiry_time = babel_now.tv_sec + roughly(30); - } - - if(babel_now.tv_sec >= source_expiry_time) { - expire_sources(); - source_expiry_time = babel_now.tv_sec + roughly(300); - } - - FOR_ALL_INTERFACES(ifp, linklist_node) { - babel_interface_nfo *babel_ifp = NULL; - if(!if_up(ifp)) - continue; - babel_ifp = babel_get_if_nfo(ifp); - if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0) - send_hello(ifp); - if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0) - send_update(ifp, 0, NULL, 0); - if(timeval_compare(&babel_now, - &babel_ifp->update_flush_timeout) >= 0) - flushupdates(ifp); - } - - if(resend_time.tv_sec != 0) { - if(timeval_compare(&babel_now, &resend_time) >= 0) - do_resend(); - } - - if(unicast_flush_timeout.tv_sec != 0) { - if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0) - flush_unicast(1); - } - - FOR_ALL_INTERFACES(ifp, linklist_node) { - babel_interface_nfo *babel_ifp = NULL; - if(!if_up(ifp)) - continue; - babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->flush_timeout.tv_sec != 0) { - if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0) - flushbuf(ifp); - } - } - } - - assert(0); /* this line should never be reach */ -} - -static void -printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname) -{ - static struct timeval curr_tv; - static char buffer[200]; - static const char *curr_tag = NULL; - - switch (cmd) { - case 0: /* reset timeval */ - curr_tv = *tv; - if(ifname != NULL) { - snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); - curr_tag = buffer; - } else { - curr_tag = tag; - } - break; - case 1: /* take the min */ - if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */ - break; - } - if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec && - tv->tv_usec < curr_tv.tv_usec)) { - curr_tv = *tv; - if(ifname != NULL) { - snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); - curr_tag = buffer; - } else { - curr_tag = tag; - } - } - break; - case 2: /* print message */ - debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag); - break; - default: - break; - } -} - -static void -babel_fill_with_next_timeout(struct timeval *tv) -{ -#if (defined NO_DEBUG) -#define printIfMin(a,b,c,d) -#else -#define printIfMin(a,b,c,d) \ - if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);} - - struct interface *ifp = NULL; - struct listnode *linklist_node = NULL; - - *tv = check_neighbours_timeout; - printIfMin(tv, 0, "check_neighbours_timeout", NULL); - timeval_min_sec(tv, expiry_time); - printIfMin(tv, 1, "expiry_time", NULL); - timeval_min_sec(tv, source_expiry_time); - printIfMin(tv, 1, "source_expiry_time", NULL); - timeval_min(tv, &resend_time); - printIfMin(tv, 1, "resend_time", NULL); - FOR_ALL_INTERFACES(ifp, linklist_node) { - babel_interface_nfo *babel_ifp = NULL; - if(!if_up(ifp)) - continue; - babel_ifp = babel_get_if_nfo(ifp); - timeval_min(tv, &babel_ifp->flush_timeout); - printIfMin(tv, 1, "flush_timeout", ifp->name); - timeval_min(tv, &babel_ifp->hello_timeout); - printIfMin(tv, 1, "hello_timeout", ifp->name); - timeval_min(tv, &babel_ifp->update_timeout); - printIfMin(tv, 1, "update_timeout", ifp->name); - timeval_min(tv, &babel_ifp->update_flush_timeout); - printIfMin(tv, 1, "update_flush_timeout",ifp->name); - } - timeval_min(tv, &unicast_flush_timeout); - printIfMin(tv, 1, "unicast_flush_timeout", NULL); - printIfMin(tv, 2, NULL, NULL); -#undef printIfMin -#endif -} - -/* set the t_update thread of the babel routing process to be launch in - 'timeout' (approximate at the milisecond) */ -static void -babel_set_timer(struct timeval *timeout) -{ - long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; - if (babel_routing_process->t_update != NULL) { - thread_cancel(babel_routing_process->t_update); - } - babel_routing_process->t_update = - thread_add_timer_msec(master, &babel_main_loop, NULL, msecs); -} - -/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */ -void -schedule_neighbours_check(int msecs, int override) -{ - struct timeval timeout; - - timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2)); - if(override) - check_neighbours_timeout = timeout; - else - timeval_min(&check_neighbours_timeout, &timeout); -} - -int -resize_receive_buffer(int size) -{ - if(size <= receive_buffer_size) - return 0; - - if(receive_buffer == NULL) { - receive_buffer = malloc(size); - if(receive_buffer == NULL) { - zlog_err("malloc(receive_buffer): %s", safe_strerror(errno)); - return -1; - } - receive_buffer_size = size; - } else { - unsigned char *new; - new = realloc(receive_buffer, size); - if(new == NULL) { - zlog_err("realloc(receive_buffer): %s", safe_strerror(errno)); - return -1; - } - receive_buffer = new; - receive_buffer_size = size; - } - return 1; -} - -static void -babel_distribute_update (struct distribute *dist) -{ - struct interface *ifp; - babel_interface_nfo *babel_ifp; - struct access_list *alist; - struct prefix_list *plist; - - if (! dist->ifname) - return; - - ifp = if_lookup_by_name (dist->ifname); - if (ifp == NULL) - return; - - babel_ifp = babel_get_if_nfo(ifp); - - if (dist->list[DISTRIBUTE_IN]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); - if (alist) - babel_ifp->list[BABEL_FILTER_IN] = alist; - else - babel_ifp->list[BABEL_FILTER_IN] = NULL; - } else { - babel_ifp->list[BABEL_FILTER_IN] = NULL; - } - - if (dist->list[DISTRIBUTE_OUT]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); - if (alist) - babel_ifp->list[BABEL_FILTER_OUT] = alist; - else - babel_ifp->list[BABEL_FILTER_OUT] = NULL; - } else { - babel_ifp->list[BABEL_FILTER_OUT] = NULL; - } - - if (dist->prefix[DISTRIBUTE_IN]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); - if (plist) - babel_ifp->prefix[BABEL_FILTER_IN] = plist; - else - babel_ifp->prefix[BABEL_FILTER_IN] = NULL; - } else { - babel_ifp->prefix[BABEL_FILTER_IN] = NULL; - } - - if (dist->prefix[DISTRIBUTE_OUT]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); - if (plist) - babel_ifp->prefix[BABEL_FILTER_OUT] = plist; - else - babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; - } else { - babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; - } -} - -static void -babel_distribute_update_interface (struct interface *ifp) -{ - struct distribute *dist; - - dist = distribute_lookup (ifp->name); - if (dist) - babel_distribute_update (dist); -} - -/* Update all interface's distribute list. */ -static void -babel_distribute_update_all (struct prefix_list *notused) -{ - struct interface *ifp; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) - babel_distribute_update_interface (ifp); -} - -static void -babel_distribute_update_all_wrapper (struct access_list *notused) -{ - babel_distribute_update_all(NULL); -} - - -/* [Command] */ -DEFUN (router_babel, - router_babel_cmd, - "router babel", - "Enable a routing process\n" - "Make Babel instance command\n" - "No attributes\n") -{ - int ret; - - vty->node = BABEL_NODE; - - if (!babel_routing_process) { - ret = babel_create_routing_process (); - - /* Notice to user we couldn't create Babel. */ - if (ret < 0) { - zlog_warn ("can't create Babel"); - return CMD_WARNING; - } - } - - return CMD_SUCCESS; -} - -/* [Command] */ -DEFUN (no_router_babel, - no_router_babel_cmd, - "no router babel", - NO_STR - "Disable a routing process\n" - "Remove Babel instance command\n" - "No attributes\n") -{ - if(babel_routing_process) - babel_clean_routing_process(); - return CMD_SUCCESS; -} - -/* [Babel Command] */ -DEFUN (babel_set_resend_delay, - babel_set_resend_delay_cmd, - "babel resend-delay <20-655340>", - "Babel commands\n" - "Time before resending a message\n" - "Milliseconds\n") -{ - int interval; - - VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); - - resend_delay = interval; - return CMD_SUCCESS; -} - -void -babeld_quagga_init(void) -{ - - install_node(&cmd_babel_node, &babel_config_write); - - install_element(CONFIG_NODE, &router_babel_cmd); - install_element(CONFIG_NODE, &no_router_babel_cmd); - - install_default(BABEL_NODE); - install_element(BABEL_NODE, &babel_set_resend_delay_cmd); - - babel_if_init(); - - /* Access list install. */ - access_list_init (); - access_list_add_hook (babel_distribute_update_all_wrapper); - access_list_delete_hook (babel_distribute_update_all_wrapper); - - /* Prefix list initialize.*/ - prefix_list_init (); - prefix_list_add_hook (babel_distribute_update_all); - prefix_list_delete_hook (babel_distribute_update_all); - - /* Distribute list install. */ - distribute_list_init (BABEL_NODE); - distribute_list_add_hook (babel_distribute_update); - distribute_list_delete_hook (babel_distribute_update); -} - -/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */ - -int -input_filter(const unsigned char *id, - const unsigned char *prefix, unsigned short plen, - const unsigned char *neigh, unsigned int ifindex) -{ - return babel_filter(0, prefix, plen, ifindex); -} - -int -output_filter(const unsigned char *id, const unsigned char *prefix, - unsigned short plen, unsigned int ifindex) -{ - return babel_filter(1, prefix, plen, ifindex); -} - -/* There's no redistribute filter in Quagga -- the zebra daemon does its - own filtering. */ -int -redistribute_filter(const unsigned char *prefix, unsigned short plen, - unsigned int ifindex, int proto) -{ - return 0; -} - diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample deleted file mode 100644 index a4924ec7b..000000000 --- a/babeld/babeld.conf.sample +++ /dev/null @@ -1,30 +0,0 @@ -debug babel common -!debug babel kernel -!debug babel filter -!debug babel timeout -!debug babel interface -!debug babel route -!debug babel all - -router babel -! network wlan0 -! network eth0 -! redistribute kernel -! no redistribute static - -! The defaults are fine for a wireless interface - -!interface wlan0 - -! A few optimisation tweaks are optional but recommended on a wired interface -! Disable link quality estimation, enable split horizon processing, and -! increase the hello and update intervals. - -!interface eth0 -! babel wired -! babel split-horizon -! babel hello-interval 12000 -! babel update-interval 36000 - -! log file /var/log/quagga/babeld.log -log stdout diff --git a/babeld/babeld.h b/babeld/babeld.h deleted file mode 100644 index b19ae0f2d..000000000 --- a/babeld/babeld.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABEL_BABELD_H -#define BABEL_BABELD_H - -#include -#include "vty.h" - -#define INFINITY ((unsigned short)(~0)) - -#ifndef RTPROT_BABEL -#define RTPROT_BABEL 42 -#endif - -#define RTPROT_BABEL_LOCAL -2 - -#undef MAX -#undef MIN - -#define MAX(x,y) ((x)<=(y)?(y):(x)) -#define MIN(x,y) ((x)<=(y)?(x):(y)) - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* nothing */ -#elif defined(__GNUC__) -#define inline __inline -#if (__GNUC__ >= 3) -#define restrict __restrict -#else -#define restrict /**/ -#endif -#else -#define inline /**/ -#define restrict /**/ -#endif - -#if defined(__GNUC__) && (__GNUC__ >= 3) -#define ATTRIBUTE(x) __attribute__ (x) -#define LIKELY(_x) __builtin_expect(!!(_x), 1) -#define UNLIKELY(_x) __builtin_expect(!!(_x), 0) -#else -#define ATTRIBUTE(x) /**/ -#define LIKELY(_x) !!(_x) -#define UNLIKELY(_x) !!(_x) -#endif - -#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3) -#define COLD __attribute__ ((cold)) -#else -#define COLD /**/ -#endif - -#ifndef IF_NAMESIZE -#include -#include -#endif - -#ifdef HAVE_VALGRIND -#include -#else -#ifndef VALGRIND_MAKE_MEM_UNDEFINED -#define VALGRIND_MAKE_MEM_UNDEFINED(a, b) do {} while(0) -#endif -#ifndef VALGRIND_CHECK_MEM_IS_DEFINED -#define VALGRIND_CHECK_MEM_IS_DEFINED(a, b) do {} while(0) -#endif -#endif - - -#define BABEL_VTY_PORT 2609 -#define BABEL_DEFAULT_CONFIG "babeld.conf" -#define BABEL_VERSION "0.1 for quagga" - -/* Values in milliseconds */ -#define BABEL_DEFAULT_HELLO_INTERVAL 4000 -#define BABEL_DEFAULT_UPDATE_INTERVAL 16000 -#define BABEL_DEFAULT_RESEND_DELAY 2000 - - -/* Babel socket. */ -extern int protocol_socket; - -/* Babel structure. */ -struct babel -{ - /* Babel threads. */ - struct thread *t_read; /* on Babel protocol's socket */ - struct thread *t_update; /* timers */ -}; - - -extern void babeld_quagga_init(void); -extern int input_filter(const unsigned char *id, - const unsigned char *prefix, unsigned short plen, - const unsigned char *neigh, unsigned int ifindex); -extern int output_filter(const unsigned char *id, const unsigned char *prefix, - unsigned short plen, unsigned int ifindex); -extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, - unsigned int ifindex, int proto); -extern int resize_receive_buffer(int size); -extern void schedule_neighbours_check(int msecs, int override); - - -#endif /* BABEL_BABELD_H */ diff --git a/babeld/kernel.c b/babeld/kernel.c deleted file mode 100644 index efbb70005..000000000 --- a/babeld/kernel.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - -Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek -Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include - -#include "babeld.h" - - -#include -#include -#include -#include -#include - -#include -#include "prefix.h" -#include "zclient.h" -#include "kernel.h" -#include "privs.h" -#include "command.h" -#include "vty.h" -#include "memory.h" -#include "thread.h" - -#include "util.h" -#include "babel_interface.h" -#include "babel_zebra.h" - - -static int -kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); -static int -kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); - -int -kernel_interface_operational(struct interface *interface) -{ - return if_is_operative(interface); -} - -int -kernel_interface_mtu(struct interface *interface) -{ - return MIN(interface->mtu, interface->mtu6); -} - -int -kernel_interface_wireless(struct interface *interface) -{ - return 0; -} - -int -kernel_route(int operation, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric) -{ - int rc; - int ipv4; - - /* Check that the protocol family is consistent. */ - if(plen >= 96 && v4mapped(pref)) { - if(!v4mapped(gate)) { - errno = EINVAL; - return -1; - } - ipv4 = 1; - } else { - if(v4mapped(gate)) { - errno = EINVAL; - return -1; - } - ipv4 = 0; - } - - switch (operation) { - case ROUTE_ADD: - return ipv4 ? - kernel_route_v4(1, pref, plen, gate, ifindex, metric): - kernel_route_v6(1, pref, plen, gate, ifindex, metric); - break; - case ROUTE_FLUSH: - return ipv4 ? - kernel_route_v4(0, pref, plen, gate, ifindex, metric): - kernel_route_v6(0, pref, plen, gate, ifindex, metric); - break; - case ROUTE_MODIFY: - if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && - newifindex == ifindex) - return 0; - debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); - rc = ipv4 ? - kernel_route_v4(0, pref, plen, gate, ifindex, metric): - kernel_route_v6(0, pref, plen, gate, ifindex, metric); - - if (rc < 0) - return -1; - - rc = ipv4 ? - kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): - kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); - - return rc; - break; - default: - zlog_err("this should never appens (false value - kernel_route)"); - assert(0); - exit(1); - break; - } -} - -static int -kernel_route_v4(int add, - const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) -{ - struct zapi_ipv4 api; /* quagga's communication system */ - struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ - struct in_addr babel_prefix_addr; /* babeld's prefix addr */ - struct in_addr nexthop; /* next router to go */ - struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_inaddr(&babel_prefix_addr, pref); - uchar_to_inaddr(&nexthop, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET; - IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); - quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ - apply_mask_ipv4(&quagga_prefix); - - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - - /* Unlike the native Linux and BSD interfaces, Quagga doesn't like - there to be both and IPv4 nexthop and an ifindex. Omit the - ifindex, and assume that the connected prefixes be set up - correctly. */ - - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.ifindex_num = 0; - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_BLACKHOLE; - api.nexthop_num = 0; - } else { - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", - add ? "adding" : "removing" ); - return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD : - ZEBRA_IPV4_ROUTE_DELETE, - zclient, &quagga_prefix, &api); -} - -static int -kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) -{ - unsigned int tmp_ifindex = ifindex; /* (for typing) */ - struct zapi_ipv6 api; /* quagga's communication system */ - struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ - struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ - struct in6_addr nexthop; /* next router to go */ - struct in6_addr *nexthop_pointer = &nexthop; - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_in6addr(&babel_prefix_addr, pref); - uchar_to_in6addr(&nexthop, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET6; - IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); - quagga_prefix.prefixlen = plen; - apply_mask_ipv6(&quagga_prefix); - - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_BLACKHOLE; - api.nexthop_num = 0; - api.ifindex_num = 0; - } else { - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", - add ? "adding" : "removing" ); - return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD : - ZEBRA_IPV6_ROUTE_DELETE, - zclient, &quagga_prefix, &api); -} - -int -if_eui64(char *ifname, int ifindex, unsigned char *eui) -{ - struct interface *ifp = if_lookup_by_index(ifindex); - if (ifp == NULL) { - return -1; - } -#ifdef HAVE_STRUCT_SOCKADDR_DL - u_char len = ifp->sdl.sdl_alen; - char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen; -#else - u_char len = (u_char) ifp->hw_addr_len; - char *tmp = (void*) ifp->hw_addr; -#endif - if (len == 8) { - memcpy(eui, tmp, 8); - eui[0] ^= 2; - } else if (len == 6) { - memcpy(eui, tmp, 3); - eui[3] = 0xFF; - eui[4] = 0xFE; - memcpy(eui+5, tmp+3, 3); - } else { - return -1; - } - return 0; -} - -/* Like gettimeofday, but returns monotonic time. If POSIX clocks are not - available, falls back to gettimeofday but enforces monotonicity. */ -int -gettime(struct timeval *tv) -{ - return quagga_gettime(QUAGGA_CLK_MONOTONIC, tv); -} - -/* If /dev/urandom doesn't exist, this will fail with ENOENT, which the - caller will deal with gracefully. */ - -int -read_random_bytes(void *buf, size_t len) -{ - int fd; - int rc; - - fd = open("/dev/urandom", O_RDONLY); - if(fd < 0) { - rc = -1; - } else { - rc = read(fd, buf, len); - if(rc < 0 || (unsigned) rc < len) - rc = -1; - close(fd); - } - return rc; -} - diff --git a/babeld/kernel.h b/babeld/kernel.h deleted file mode 100644 index e8c8f9b7c..000000000 --- a/babeld/kernel.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "babel_main.h" -#include "if.h" - -#define KERNEL_INFINITY 0xFFFF - -struct kernel_route { - unsigned char prefix[16]; - int plen; - int metric; - unsigned int ifindex; - int proto; - unsigned char gw[16]; -}; - -#define ROUTE_FLUSH 0 -#define ROUTE_ADD 1 -#define ROUTE_MODIFY 2 - -extern int export_table, import_table; - -int kernel_interface_operational(struct interface *interface); -int kernel_interface_mtu(struct interface *interface); -int kernel_interface_wireless(struct interface *interface); -int kernel_route(int operation, const unsigned char *dest, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric); -int if_eui64(char *ifname, int ifindex, unsigned char *eui); -int gettime(struct timeval *tv); -int read_random_bytes(void *buf, size_t len); diff --git a/babeld/message.c b/babeld/message.c deleted file mode 100644 index 9dcfc6771..000000000 --- a/babeld/message.c +++ /dev/null @@ -1,1561 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "if.h" - -#include "babeld.h" -#include "util.h" -#include "net.h" -#include "babel_interface.h" -#include "source.h" -#include "neighbour.h" -#include "route.h" -#include "xroute.h" -#include "resend.h" -#include "message.h" -#include "kernel.h" - -unsigned char packet_header[4] = {42, 2}; - -int split_horizon = 1; - -unsigned short myseqno = 0; -struct timeval seqno_time = {0, 0}; - -#define UNICAST_BUFSIZE 1024 -int unicast_buffered = 0; -unsigned char *unicast_buffer = NULL; -struct neighbour *unicast_neighbour = NULL; -struct timeval unicast_flush_timeout = {0, 0}; - -static const unsigned char v4prefix[16] = - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; - -/* Parse a network prefix, encoded in the somewhat baroque compressed - representation used by Babel. Return the number of bytes parsed. */ -static int -network_prefix(int ae, int plen, unsigned int omitted, - const unsigned char *p, const unsigned char *dp, - unsigned int len, unsigned char *p_r) -{ - unsigned pb; - unsigned char prefix[16]; - int ret = -1; - - if(plen >= 0) - pb = (plen + 7) / 8; - else if(ae == 1) - pb = 4; - else - pb = 16; - - if(pb > 16) - return -1; - - memset(prefix, 0, 16); - - switch(ae) { - case 0: - ret = 0; - break; - case 1: - if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) - return -1; - memcpy(prefix, v4prefix, 12); - if(omitted) { - if (dp == NULL || !v4mapped(dp)) return -1; - memcpy(prefix, dp, 12 + omitted); - } - if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); - ret = pb - omitted; - break; - case 2: - if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; - if(omitted) { - if (dp == NULL || v4mapped(dp)) return -1; - memcpy(prefix, dp, omitted); - } - if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); - ret = pb - omitted; - break; - case 3: - if(pb > 8 && len < pb - 8) return -1; - prefix[0] = 0xfe; - prefix[1] = 0x80; - if(pb > 8) memcpy(prefix + 8, p, pb - 8); - ret = pb - 8; - break; - default: - return -1; - } - - mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); - return ret; -} - -static void -parse_route_attributes(const unsigned char *a, int alen, - unsigned char *channels) -{ - int type, len, i = 0; - - while(i < alen) { - type = a[i]; - if(type == 0) { - i++; - continue; - } - - if(i + 1 > alen) { - fprintf(stderr, "Received truncated attributes.\n"); - return; - } - len = a[i + 1]; - if(i + len > alen) { - fprintf(stderr, "Received truncated attributes.\n"); - return; - } - - if(type == 1) { - /* Nothing. */ - } else if(type == 2) { - if(len > DIVERSITY_HOPS) { - fprintf(stderr, - "Received overlong channel information (%d > %d).\n", - len, DIVERSITY_HOPS); - len = DIVERSITY_HOPS; - } - if(memchr(a + i + 2, 0, len) != NULL) { - /* 0 is reserved. */ - fprintf(stderr, "Channel information contains 0!"); - return; - } - memset(channels, 0, DIVERSITY_HOPS); - memcpy(channels, a + i + 2, len); - } else { - fprintf(stderr, "Received unknown route attribute %d.\n", type); - } - - i += len + 2; - } -} - -static int -network_address(int ae, const unsigned char *a, unsigned int len, - unsigned char *a_r) -{ - return network_prefix(ae, -1, 0, a, NULL, len, a_r); -} - -static int -channels_len(unsigned char *channels) -{ - unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS); - return p ? (p - channels) : DIVERSITY_HOPS; -} - -void -parse_packet(const unsigned char *from, struct interface *ifp, - const unsigned char *packet, int packetlen) -{ - int i; - const unsigned char *message; - unsigned char type, len; - int bodylen; - struct neighbour *neigh; - int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0, - have_v4_nh = 0, have_v6_nh = 0; - unsigned char router_id[8], v4_prefix[16], v6_prefix[16], - v4_nh[16], v6_nh[16]; - - if(!linklocal(from)) { - zlog_err("Received packet from non-local address %s.", - format_address(from)); - return; - } - - if(packet[0] != 42) { - zlog_err("Received malformed packet on %s from %s.", - ifp->name, format_address(from)); - return; - } - - if(packet[1] != 2) { - zlog_err("Received packet with unknown version %d on %s from %s.", - packet[1], ifp->name, format_address(from)); - return; - } - - neigh = find_neighbour(from, ifp); - if(neigh == NULL) { - zlog_err("Couldn't allocate neighbour."); - return; - } - - DO_NTOHS(bodylen, packet + 2); - - if(bodylen + 4 > packetlen) { - zlog_err("Received truncated packet (%d + 4 > %d).", - bodylen, packetlen); - bodylen = packetlen - 4; - } - - i = 0; - while(i < bodylen) { - message = packet + 4 + i; - type = message[0]; - if(type == MESSAGE_PAD1) { - debugf(BABEL_DEBUG_COMMON,"Received pad1 from %s on %s.", - format_address(from), ifp->name); - i++; - continue; - } - if(i + 1 > bodylen) { - zlog_err("Received truncated message."); - break; - } - len = message[1]; - if(i + len > bodylen) { - zlog_err("Received truncated message."); - break; - } - - if(type == MESSAGE_PADN) { - debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.", - len, format_address(from), ifp->name); - } else if(type == MESSAGE_ACK_REQ) { - unsigned short nonce, interval; - if(len < 6) goto fail; - DO_NTOHS(nonce, message + 4); - DO_NTOHS(interval, message + 6); - debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.", - nonce, interval, format_address(from), ifp->name); - send_ack(neigh, nonce, interval); - } else if(type == MESSAGE_ACK) { - debugf(BABEL_DEBUG_COMMON,"Received ack from %s on %s.", - format_address(from), ifp->name); - /* Nothing right now */ - } else if(type == MESSAGE_HELLO) { - unsigned short seqno, interval; - int changed; - if(len < 6) goto fail; - DO_NTOHS(seqno, message + 4); - DO_NTOHS(interval, message + 6); - debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", - seqno, interval, - format_address(from), ifp->name); - changed = update_neighbour(neigh, seqno, interval); - update_neighbour_metric(neigh, changed); - if(interval > 0) - schedule_neighbours_check(interval * 10, 0); - } else if(type == MESSAGE_IHU) { - unsigned short txcost, interval; - unsigned char address[16]; - int rc; - if(len < 6) goto fail; - DO_NTOHS(txcost, message + 4); - DO_NTOHS(interval, message + 6); - rc = network_address(message[2], message + 8, len - 6, address); - if(rc < 0) goto fail; - debugf(BABEL_DEBUG_COMMON,"Received ihu %d (%d) from %s on %s for %s.", - txcost, interval, - format_address(from), ifp->name, - format_address(address)); - if(message[2] == 0 || is_interface_ll_address(ifp, address)) { - int changed = txcost != neigh->txcost; - neigh->txcost = txcost; - neigh->ihu_time = babel_now; - neigh->ihu_interval = interval; - update_neighbour_metric(neigh, changed); - if(interval > 0) - schedule_neighbours_check(interval * 10 * 3, 0); - } - } else if(type == MESSAGE_ROUTER_ID) { - if(len < 10) { - have_router_id = 0; - goto fail; - } - memcpy(router_id, message + 4, 8); - have_router_id = 1; - debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.", - format_eui64(router_id), format_address(from), ifp->name); - } else if(type == MESSAGE_NH) { - unsigned char nh[16]; - int rc; - if(len < 2) { - have_v4_nh = 0; - have_v6_nh = 0; - goto fail; - } - rc = network_address(message[2], message + 4, len - 2, - nh); - if(rc < 0) { - have_v4_nh = 0; - have_v6_nh = 0; - goto fail; - } - debugf(BABEL_DEBUG_COMMON,"Received nh %s (%d) from %s on %s.", - format_address(nh), message[2], - format_address(from), ifp->name); - if(message[2] == 1) { - memcpy(v4_nh, nh, 16); - have_v4_nh = 1; - } else { - memcpy(v6_nh, nh, 16); - have_v6_nh = 1; - } - } else if(type == MESSAGE_UPDATE) { - unsigned char prefix[16], *nh; - unsigned char plen; - unsigned char channels[DIVERSITY_HOPS]; - unsigned short interval, seqno, metric; - int rc, parsed_len; - if(len < 10) { - if(len < 2 || message[3] & 0x80) - have_v4_prefix = have_v6_prefix = 0; - goto fail; - } - DO_NTOHS(interval, message + 6); - DO_NTOHS(seqno, message + 8); - DO_NTOHS(metric, message + 10); - if(message[5] == 0 || - (message[3] == 1 ? have_v4_prefix : have_v6_prefix)) - rc = network_prefix(message[2], message[4], message[5], - message + 12, - message[2] == 1 ? v4_prefix : v6_prefix, - len - 10, prefix); - else - rc = -1; - if(rc < 0) { - if(message[3] & 0x80) - have_v4_prefix = have_v6_prefix = 0; - goto fail; - } - parsed_len = 10 + rc; - - plen = message[4] + (message[2] == 1 ? 96 : 0); - - if(message[3] & 0x80) { - if(message[2] == 1) { - memcpy(v4_prefix, prefix, 16); - have_v4_prefix = 1; - } else { - memcpy(v6_prefix, prefix, 16); - have_v6_prefix = 1; - } - } - if(message[3] & 0x40) { - if(message[2] == 1) { - memset(router_id, 0, 4); - memcpy(router_id + 4, prefix + 12, 4); - } else { - memcpy(router_id, prefix + 8, 8); - } - have_router_id = 1; - } - if(!have_router_id && message[2] != 0) { - zlog_err("Received prefix with no router id."); - goto fail; - } - debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", - (message[3] & 0x80) ? "/prefix" : "", - (message[3] & 0x40) ? "/id" : "", - format_prefix(prefix, plen), - format_address(from), ifp->name); - - if(message[2] == 0) { - if(metric < 0xFFFF) { - zlog_err("Received wildcard update with finite metric."); - goto done; - } - retract_neighbour_routes(neigh); - goto done; - } else if(message[2] == 1) { - if(!have_v4_nh) - goto fail; - nh = v4_nh; - } else if(have_v6_nh) { - nh = v6_nh; - } else { - nh = neigh->address; - } - - if(message[2] == 1) { - if(!babel_get_if_nfo(ifp)->ipv4) - goto done; - } - - if((ifp->flags & BABEL_IF_FARAWAY)) { - channels[0] = 0; - } else { - /* This will be overwritten by parse_route_attributes below. */ - if(metric < 256) { - /* Assume non-interfering (wired) link. */ - channels[0] = 0; - } else { - /* Assume interfering. */ - channels[0] = BABEL_IF_CHANNEL_INTERFERING; - channels[1] = 0; - } - - if(parsed_len < len) - parse_route_attributes(message + 2 + parsed_len, - len - parsed_len, channels); - } - - update_route(router_id, prefix, plen, seqno, metric, interval, - neigh, nh, - channels, channels_len(channels)); - } else if(type == MESSAGE_REQUEST) { - unsigned char prefix[16], plen; - int rc; - if(len < 2) goto fail; - rc = network_prefix(message[2], message[3], 0, - message + 4, NULL, len - 2, prefix); - if(rc < 0) goto fail; - plen = message[3] + (message[2] == 1 ? 96 : 0); - debugf(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.", - message[2] == 0 ? "any" : format_prefix(prefix, plen), - format_address(from), ifp->name); - if(message[2] == 0) { - struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp); - /* If a neighbour is requesting a full route dump from us, - we might as well send it an IHU. */ - send_ihu(neigh, NULL); - /* Since nodes send wildcard requests on boot, booting - a large number of nodes at the same time may cause an - update storm. Ignore a wildcard request that happens - shortly after we sent a full update. */ - if(babel_ifp->last_update_time < - (time_t)(babel_now.tv_sec - - MAX(babel_ifp->hello_interval / 100, 1))) - send_update(neigh->ifp, 0, NULL, 0); - } else { - send_update(neigh->ifp, 0, prefix, plen); - } - } else if(type == MESSAGE_MH_REQUEST) { - unsigned char prefix[16], plen; - unsigned short seqno; - int rc; - if(len < 14) goto fail; - DO_NTOHS(seqno, message + 4); - rc = network_prefix(message[2], message[3], 0, - message + 16, NULL, len - 14, prefix); - if(rc < 0) goto fail; - plen = message[3] + (message[2] == 1 ? 96 : 0); - debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).", - message[6], - format_prefix(prefix, plen), - format_address(from), ifp->name, - format_eui64(message + 8), seqno); - handle_request(neigh, prefix, plen, message[6], - seqno, message + 8); - } else { - debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.", - type, format_address(from), ifp->name); - } - done: - i += len + 2; - continue; - - fail: - zlog_err("Couldn't parse packet (%d, %d) from %s on %s.", - message[0], message[1], format_address(from), ifp->name); - goto done; - } - return; -} - -/* Under normal circumstances, there are enough moderation mechanisms - elsewhere in the protocol to make sure that this last-ditch check - should never trigger. But I'm superstitious. */ - -static int -check_bucket(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->bucket <= 0) { - int seconds = babel_now.tv_sec - babel_ifp->bucket_time; - if(seconds > 0) { - babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX, - seconds * BUCKET_TOKENS_PER_SEC); - } - /* Reset bucket time unconditionally, in case clock is stepped. */ - babel_ifp->bucket_time = babel_now.tv_sec; - } - - if(babel_ifp->bucket > 0) { - babel_ifp->bucket--; - return 1; - } else { - return 0; - } -} - -void -flushbuf(struct interface *ifp) -{ - int rc; - struct sockaddr_in6 sin6; - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - - assert(babel_ifp->buffered <= babel_ifp->bufsize); - - flushupdates(ifp); - - if(babel_ifp->buffered > 0) { - debugf(BABEL_DEBUG_COMMON," (flushing %d buffered bytes on %s)", - babel_ifp->buffered, ifp->name); - if(check_bucket(ifp)) { - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - memcpy(&sin6.sin6_addr, protocol_group, 16); - sin6.sin6_port = htons(protocol_port); - sin6.sin6_scope_id = ifp->ifindex; - DO_HTONS(packet_header + 2, babel_ifp->buffered); - rc = babel_send(protocol_socket, - packet_header, sizeof(packet_header), - babel_ifp->sendbuf, babel_ifp->buffered, - (struct sockaddr*)&sin6, sizeof(sin6)); - if(rc < 0) - zlog_err("send: %s", safe_strerror(errno)); - } else { - zlog_err("Warning: bucket full, dropping packet to %s.", - ifp->name); - } - } - VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); - babel_ifp->buffered = 0; - babel_ifp->have_buffered_hello = 0; - babel_ifp->have_buffered_id = 0; - babel_ifp->have_buffered_nh = 0; - babel_ifp->have_buffered_prefix = 0; - babel_ifp->flush_timeout.tv_sec = 0; - babel_ifp->flush_timeout.tv_usec = 0; -} - -static void -schedule_flush(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - unsigned msecs = jitter(babel_ifp, 0); - if(babel_ifp->flush_timeout.tv_sec != 0 && - timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) - return; - set_timeout(&babel_ifp->flush_timeout, msecs); -} - -static void -schedule_flush_now(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - /* Almost now */ - unsigned msecs = roughly(10); - if(babel_ifp->flush_timeout.tv_sec != 0 && - timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) - return; - set_timeout(&babel_ifp->flush_timeout, msecs); -} - -static void -schedule_unicast_flush(unsigned msecs) -{ - if(!unicast_neighbour) - return; - if(unicast_flush_timeout.tv_sec != 0 && - timeval_minus_msec(&unicast_flush_timeout, &babel_now) < msecs) - return; - unicast_flush_timeout.tv_usec = (babel_now.tv_usec + msecs * 1000) %1000000; - unicast_flush_timeout.tv_sec = - babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000; -} - -static void -ensure_space(struct interface *ifp, int space) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->bufsize - babel_ifp->buffered < space) - flushbuf(ifp); -} - -static void -start_message(struct interface *ifp, int type, int len) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->bufsize - babel_ifp->buffered < len + 2) - flushbuf(ifp); - babel_ifp->sendbuf[babel_ifp->buffered++] = type; - babel_ifp->sendbuf[babel_ifp->buffered++] = len; -} - -static void -end_message(struct interface *ifp, int type, int bytes) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - assert(babel_ifp->buffered >= bytes + 2 && - babel_ifp->sendbuf[babel_ifp->buffered - bytes - 2] == type && - babel_ifp->sendbuf[babel_ifp->buffered - bytes - 1] == bytes); - schedule_flush(ifp); -} - -static void -accumulate_byte(struct interface *ifp, unsigned char value) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - babel_ifp->sendbuf[babel_ifp->buffered++] = value; -} - -static void -accumulate_short(struct interface *ifp, unsigned short value) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value); - babel_ifp->buffered += 2; -} - -static void -accumulate_bytes(struct interface *ifp, - const unsigned char *value, unsigned len) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - memcpy(babel_ifp->sendbuf + babel_ifp->buffered, value, len); - babel_ifp->buffered += len; -} - -static int -start_unicast_message(struct neighbour *neigh, int type, int len) -{ - if(unicast_neighbour) { - if(neigh != unicast_neighbour || - unicast_buffered + len + 2 >= - MIN(UNICAST_BUFSIZE, babel_get_if_nfo(neigh->ifp)->bufsize)) - flush_unicast(0); - } - if(!unicast_buffer) - unicast_buffer = malloc(UNICAST_BUFSIZE); - if(!unicast_buffer) { - zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno)); - return -1; - } - - unicast_neighbour = neigh; - - unicast_buffer[unicast_buffered++] = type; - unicast_buffer[unicast_buffered++] = len; - return 1; -} - -static void -end_unicast_message(struct neighbour *neigh, int type, int bytes) -{ - assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 && - unicast_buffer[unicast_buffered - bytes - 2] == type && - unicast_buffer[unicast_buffered - bytes - 1] == bytes); - schedule_unicast_flush(jitter(babel_get_if_nfo(neigh->ifp), 0)); -} - -static void -accumulate_unicast_byte(struct neighbour *neigh, unsigned char value) -{ - unicast_buffer[unicast_buffered++] = value; -} - -static void -accumulate_unicast_short(struct neighbour *neigh, unsigned short value) -{ - DO_HTONS(unicast_buffer + unicast_buffered, value); - unicast_buffered += 2; -} - -static void -accumulate_unicast_bytes(struct neighbour *neigh, - const unsigned char *value, unsigned len) -{ - memcpy(unicast_buffer + unicast_buffered, value, len); - unicast_buffered += len; -} - -void -send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) -{ - int rc; - debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.", - nonce, format_address(neigh->address), neigh->ifp->name); - rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; - accumulate_unicast_short(neigh, nonce); - end_unicast_message(neigh, MESSAGE_ACK, 2); - /* Roughly yields a value no larger than 3/2, so this meets the deadline */ - schedule_unicast_flush(roughly(interval * 6)); -} - -void -send_hello_noupdate(struct interface *ifp, unsigned interval) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - /* This avoids sending multiple hellos in a single packet, which breaks - link quality estimation. */ - if(babel_ifp->have_buffered_hello) - flushbuf(ifp); - - babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1); - set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); - - if(!if_up(ifp)) - return; - - debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.", - babel_ifp->hello_seqno, interval, ifp->name); - - start_message(ifp, MESSAGE_HELLO, 6); - accumulate_short(ifp, 0); - accumulate_short(ifp, babel_ifp->hello_seqno); - accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); - end_message(ifp, MESSAGE_HELLO, 6); - babel_ifp->have_buffered_hello = 1; -} - -void -send_hello(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); - /* Send full IHU every 3 hellos, and marginal IHU each time */ - if(babel_ifp->hello_seqno % 3 == 0) - send_ihu(NULL, ifp); - else - send_marginal_ihu(ifp); -} - -void -flush_unicast(int dofree) -{ - struct sockaddr_in6 sin6; - int rc; - - if(unicast_buffered == 0) - goto done; - - if(!if_up(unicast_neighbour->ifp)) - goto done; - - /* Preserve ordering of messages */ - flushbuf(unicast_neighbour->ifp); - - if(check_bucket(unicast_neighbour->ifp)) { - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - memcpy(&sin6.sin6_addr, unicast_neighbour->address, 16); - sin6.sin6_port = htons(protocol_port); - sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex; - DO_HTONS(packet_header + 2, unicast_buffered); - rc = babel_send(protocol_socket, - packet_header, sizeof(packet_header), - unicast_buffer, unicast_buffered, - (struct sockaddr*)&sin6, sizeof(sin6)); - if(rc < 0) - zlog_err("send(unicast): %s", safe_strerror(errno)); - } else { - zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.", - format_address(unicast_neighbour->address), - unicast_neighbour->ifp->name); - } - - done: - VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE); - unicast_buffered = 0; - if(dofree && unicast_buffer) { - free(unicast_buffer); - unicast_buffer = NULL; - } - unicast_neighbour = NULL; - unicast_flush_timeout.tv_sec = 0; - unicast_flush_timeout.tv_usec = 0; -} - -static void -really_send_update(struct interface *ifp, - const unsigned char *id, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned short metric, - unsigned char *channels, int channels_len) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - int add_metric, v4, real_plen, omit = 0; - const unsigned char *real_prefix; - unsigned short flags = 0; - int channels_size; - - if(diversity_kind != DIVERSITY_CHANNEL) - channels_len = -1; - - channels_size = channels_len >= 0 ? channels_len + 2 : 0; - - if(!if_up(ifp)) - return; - - add_metric = output_filter(id, prefix, plen, ifp->ifindex); - if(add_metric >= INFINITY) - return; - - metric = MIN(metric + add_metric, INFINITY); - /* Worst case */ - ensure_space(ifp, 20 + 12 + 28); - - v4 = plen >= 96 && v4mapped(prefix); - - if(v4) { - if(!babel_ifp->ipv4) - return; - if(!babel_ifp->have_buffered_nh || - memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) { - start_message(ifp, MESSAGE_NH, 6); - accumulate_byte(ifp, 1); - accumulate_byte(ifp, 0); - accumulate_bytes(ifp, babel_ifp->ipv4, 4); - end_message(ifp, MESSAGE_NH, 6); - memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4); - babel_ifp->have_buffered_nh = 1; - } - - real_prefix = prefix + 12; - real_plen = plen - 96; - } else { - if(babel_ifp->have_buffered_prefix) { - while(omit < plen / 8 && - babel_ifp->buffered_prefix[omit] == prefix[omit]) - omit++; - } - if(!babel_ifp->have_buffered_prefix || plen >= 48) - flags |= 0x80; - real_prefix = prefix; - real_plen = plen; - } - - if(!babel_ifp->have_buffered_id - || memcmp(id, babel_ifp->buffered_id, 8) != 0) { - if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) { - flags |= 0x40; - } else { - start_message(ifp, MESSAGE_ROUTER_ID, 10); - accumulate_short(ifp, 0); - accumulate_bytes(ifp, id, 8); - end_message(ifp, MESSAGE_ROUTER_ID, 10); - } - memcpy(babel_ifp->buffered_id, id, 16); - babel_ifp->have_buffered_id = 1; - } - - start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + - channels_size); - accumulate_byte(ifp, v4 ? 1 : 2); - accumulate_byte(ifp, flags); - accumulate_byte(ifp, real_plen); - accumulate_byte(ifp, omit); - accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10); - accumulate_short(ifp, seqno); - accumulate_short(ifp, metric); - accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); - /* Note that an empty channels TLV is different from no such TLV. */ - if(channels_len >= 0) { - accumulate_byte(ifp, 2); - accumulate_byte(ifp, channels_len); - accumulate_bytes(ifp, channels, channels_len); - } - end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + - channels_size); - - if(flags & 0x80) { - memcpy(babel_ifp->buffered_prefix, prefix, 16); - babel_ifp->have_buffered_prefix = 1; - } -} - -static int -compare_buffered_updates(const void *av, const void *bv) -{ - const struct buffered_update *a = av, *b = bv; - int rc, v4a, v4b, ma, mb; - - rc = memcmp(a->id, b->id, 8); - if(rc != 0) - return rc; - - v4a = (a->plen >= 96 && v4mapped(a->prefix)); - v4b = (b->plen >= 96 && v4mapped(b->prefix)); - - if(v4a > v4b) - return 1; - else if(v4a < v4b) - return -1; - - ma = (!v4a && a->plen == 128 && memcmp(a->prefix + 8, a->id, 8) == 0); - mb = (!v4b && b->plen == 128 && memcmp(b->prefix + 8, b->id, 8) == 0); - - if(ma > mb) - return -1; - else if(mb > ma) - return 1; - - if(a->plen < b->plen) - return 1; - else if(a->plen > b->plen) - return -1; - - return memcmp(a->prefix, b->prefix, 16); -} - -void -flushupdates(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = NULL; - struct xroute *xroute; - struct babel_route *route; - const unsigned char *last_prefix = NULL; - unsigned char last_plen = 0xFF; - int i; - - if(ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) - flushupdates(ifp_aux); - return; - } - - babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->num_buffered_updates > 0) { - struct buffered_update *b = babel_ifp->buffered_updates; - int n = babel_ifp->num_buffered_updates; - - babel_ifp->buffered_updates = NULL; - babel_ifp->update_bufsize = 0; - babel_ifp->num_buffered_updates = 0; - - if(!if_up(ifp)) - goto done; - - debugf(BABEL_DEBUG_COMMON," (flushing %d buffered updates on %s (%d))", - n, ifp->name, ifp->ifindex); - - /* In order to send fewer update messages, we want to send updates - with the same router-id together, with IPv6 going out before IPv4. */ - - for(i = 0; i < n; i++) { - route = find_installed_route(b[i].prefix, b[i].plen); - if(route) - memcpy(b[i].id, route->src->id, 8); - else - memcpy(b[i].id, myid, 8); - } - - qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); - - for(i = 0; i < n; i++) { - /* The same update may be scheduled multiple times before it is - sent out. Since our buffer is now sorted, it is enough to - compare with the previous update. */ - - if(last_prefix) { - if(b[i].plen == last_plen && - memcmp(b[i].prefix, last_prefix, 16) == 0) - continue; - } - - xroute = find_xroute(b[i].prefix, b[i].plen); - route = find_installed_route(b[i].prefix, b[i].plen); - - if(xroute && (!route || xroute->metric <= kernel_metric)) { - really_send_update(ifp, myid, - xroute->prefix, xroute->plen, - myseqno, xroute->metric, - NULL, 0); - last_prefix = xroute->prefix; - last_plen = xroute->plen; - } else if(route) { - unsigned char channels[DIVERSITY_HOPS]; - int chlen; - struct interface *route_ifp = route->neigh->ifp; - struct babel_interface *babel_route_ifp = NULL; - unsigned short metric; - unsigned short seqno; - - seqno = route->seqno; - metric = - route_interferes(route, ifp) ? - route_metric(route) : - route_metric_noninterfering(route); - - if(metric < INFINITY) - satisfy_request(route->src->prefix, route->src->plen, - seqno, route->src->id, ifp); - if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && - route->neigh->ifp == ifp) - continue; - - babel_route_ifp = babel_get_if_nfo(route_ifp); - if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) { - memcpy(channels, route->channels, DIVERSITY_HOPS); - } else { - if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN) - channels[0] = BABEL_IF_CHANNEL_INTERFERING; - else { - assert(babel_route_ifp->channel > 0 && - babel_route_ifp->channel <= 255); - channels[0] = babel_route_ifp->channel; - } - memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1); - } - - chlen = channels_len(channels); - really_send_update(ifp, route->src->id, - route->src->prefix, - route->src->plen, - seqno, metric, - channels, chlen); - update_source(route->src, seqno, metric); - last_prefix = route->src->prefix; - last_plen = route->src->plen; - } else { - /* There's no route for this prefix. This can happen shortly - after an xroute has been retracted, so send a retraction. */ - really_send_update(ifp, myid, b[i].prefix, b[i].plen, - myseqno, INFINITY, NULL, -1); - } - } - schedule_flush_now(ifp); - done: - free(b); - } - babel_ifp->update_flush_timeout.tv_sec = 0; - babel_ifp->update_flush_timeout.tv_usec = 0; -} - -static void -schedule_update_flush(struct interface *ifp, int urgent) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - unsigned msecs; - msecs = update_jitter(babel_ifp, urgent); - if(babel_ifp->update_flush_timeout.tv_sec != 0 && - timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs) - return; - set_timeout(&babel_ifp->update_flush_timeout, msecs); -} - -static void -buffer_update(struct interface *ifp, - const unsigned char *prefix, unsigned char plen) -{ - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->num_buffered_updates > 0 && - babel_ifp->num_buffered_updates >= babel_ifp->update_bufsize) - flushupdates(ifp); - - if(babel_ifp->update_bufsize == 0) { - int n; - assert(babel_ifp->buffered_updates == NULL); - /* Allocate enough space to hold a full update. Since the - number of installed routes will grow over time, make sure we - have enough space to send a full-ish frame. */ - n = installed_routes_estimate() + xroutes_estimate() + 4; - n = MAX(n, babel_ifp->bufsize / 16); - again: - babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); - if(babel_ifp->buffered_updates == NULL) { - zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); - if(n > 4) { - /* Try again with a tiny buffer. */ - n = 4; - goto again; - } - return; - } - babel_ifp->update_bufsize = n; - babel_ifp->num_buffered_updates = 0; - } - - memcpy(babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].prefix, - prefix, 16); - babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].plen = plen; - babel_ifp->num_buffered_updates++; -} - -static void -buffer_update_callback(struct babel_route *route, void *closure) -{ - buffer_update((struct interface*)closure, - route->src->prefix, route->src->plen); -} - -void -send_update(struct interface *ifp, int urgent, - const unsigned char *prefix, unsigned char plen) -{ - babel_interface_nfo *babel_ifp = NULL; - - if(ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - struct babel_route *route; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) - send_update(ifp_aux, urgent, prefix, plen); - if(prefix) { - /* Since flushupdates only deals with non-wildcard interfaces, we - need to do this now. */ - route = find_installed_route(prefix, plen); - if(route && route_metric(route) < INFINITY) - satisfy_request(prefix, plen, route->src->seqno, route->src->id, - NULL); - } - return; - } - - if(!if_up(ifp)) - return; - - babel_ifp = babel_get_if_nfo(ifp); - if(prefix) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", - ifp->name, format_prefix(prefix, plen)); - buffer_update(ifp, prefix, plen); - } else { - send_self_update(ifp); - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); - for_all_installed_routes(buffer_update_callback, ifp); - set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); - babel_ifp->last_update_time = babel_now.tv_sec; - } - schedule_update_flush(ifp, urgent); -} - -void -send_update_resend(struct interface *ifp, - const unsigned char *prefix, unsigned char plen) -{ - assert(prefix != NULL); - - send_update(ifp, 1, prefix, plen); - record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, resend_delay); -} - -void -send_wildcard_retraction(struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = NULL; - if(ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) - send_wildcard_retraction(ifp_aux); - return; - } - - if(!if_up(ifp)) - return; - - babel_ifp = babel_get_if_nfo(ifp); - start_message(ifp, MESSAGE_UPDATE, 10); - accumulate_byte(ifp, 0); - accumulate_byte(ifp, 0x40); - accumulate_byte(ifp, 0); - accumulate_byte(ifp, 0); - accumulate_short(ifp, 0xFFFF); - accumulate_short(ifp, myseqno); - accumulate_short(ifp, 0xFFFF); - end_message(ifp, MESSAGE_UPDATE, 10); - - babel_ifp->have_buffered_id = 0; -} - -void -update_myseqno() -{ - myseqno = seqno_plus(myseqno, 1); - seqno_time = babel_now; -} - -static void -send_xroute_update_callback(struct xroute *xroute, void *closure) -{ - struct interface *ifp = (struct interface*)closure; - send_update(ifp, 0, xroute->prefix, xroute->plen); -} - -void -send_self_update(struct interface *ifp) -{ - if(ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) { - if(!if_up(ifp_aux)) - continue; - send_self_update(ifp_aux); - } - return; - } - - debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); - for_all_xroutes(send_xroute_update_callback, ifp); -} - -void -send_ihu(struct neighbour *neigh, struct interface *ifp) -{ - babel_interface_nfo *babel_ifp = NULL; - int rxcost, interval; - int ll; - - if(neigh == NULL && ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) { - if(if_up(ifp_aux)) - continue; - send_ihu(NULL, ifp_aux); - } - return; - } - - if(neigh == NULL) { - struct neighbour *ngh; - FOR_ALL_NEIGHBOURS(ngh) { - if(ngh->ifp == ifp) - send_ihu(ngh, ifp); - } - return; - } - - - if(ifp && neigh->ifp != ifp) - return; - - ifp = neigh->ifp; - babel_ifp = babel_get_if_nfo(ifp); - if(!if_up(ifp)) - return; - - rxcost = neighbour_rxcost(neigh); - interval = (babel_ifp->hello_interval * 3 + 9) / 10; - - /* Conceptually, an IHU is a unicast message. We usually send them as - multicast, since this allows aggregation into a single packet and - avoids an ARP exchange. If we already have a unicast message queued - for this neighbour, however, we might as well piggyback the IHU. */ - debugf(BABEL_DEBUG_COMMON,"Sending %sihu %d on %s to %s.", - unicast_neighbour == neigh ? "unicast " : "", - rxcost, - neigh->ifp->name, - format_address(neigh->address)); - - ll = linklocal(neigh->address); - - if(unicast_neighbour != neigh) { - start_message(ifp, MESSAGE_IHU, ll ? 14 : 22); - accumulate_byte(ifp, ll ? 3 : 2); - accumulate_byte(ifp, 0); - accumulate_short(ifp, rxcost); - accumulate_short(ifp, interval); - if(ll) - accumulate_bytes(ifp, neigh->address + 8, 8); - else - accumulate_bytes(ifp, neigh->address, 16); - end_message(ifp, MESSAGE_IHU, ll ? 14 : 22); - } else { - int rc; - rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); - if(rc < 0) return; - accumulate_unicast_byte(neigh, ll ? 3 : 2); - accumulate_unicast_byte(neigh, 0); - accumulate_unicast_short(neigh, rxcost); - accumulate_unicast_short(neigh, interval); - if(ll) - accumulate_unicast_bytes(neigh, neigh->address + 8, 8); - else - accumulate_unicast_bytes(neigh, neigh->address, 16); - end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); - } -} - -/* Send IHUs to all marginal neighbours */ -void -send_marginal_ihu(struct interface *ifp) -{ - struct neighbour *neigh; - FOR_ALL_NEIGHBOURS(neigh) { - if(ifp && neigh->ifp != ifp) - continue; - if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) - send_ihu(neigh, ifp); - } -} - -void -send_request(struct interface *ifp, - const unsigned char *prefix, unsigned char plen) -{ - int v4, len; - - if(ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) { - if(if_up(ifp_aux)) - continue; - send_request(ifp_aux, prefix, plen); - } - return; - } - - /* make sure any buffered updates go out before this request. */ - flushupdates(ifp); - - if(!if_up(ifp)) - return; - - debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", - ifp->name, prefix ? format_prefix(prefix, plen) : "any"); - v4 = plen >= 96 && v4mapped(prefix); - len = !prefix ? 2 : v4 ? 6 : 18; - - start_message(ifp, MESSAGE_REQUEST, len); - accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2); - accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen); - if(prefix) { - if(v4) - accumulate_bytes(ifp, prefix + 12, 4); - else - accumulate_bytes(ifp, prefix, 16); - } - end_message(ifp, MESSAGE_REQUEST, len); -} - -void -send_unicast_request(struct neighbour *neigh, - const unsigned char *prefix, unsigned char plen) -{ - int rc, v4, len; - - /* make sure any buffered updates go out before this request. */ - flushupdates(neigh->ifp); - - debugf(BABEL_DEBUG_COMMON,"sending unicast request to %s for %s.", - format_address(neigh->address), - prefix ? format_prefix(prefix, plen) : "any"); - v4 = plen >= 96 && v4mapped(prefix); - len = !prefix ? 2 : v4 ? 6 : 18; - - rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); - if(rc < 0) return; - accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? 1 : 2); - accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen); - if(prefix) { - if(v4) - accumulate_unicast_bytes(neigh, prefix + 12, 4); - else - accumulate_unicast_bytes(neigh, prefix, 16); - } - end_unicast_message(neigh, MESSAGE_REQUEST, len); -} - -void -send_multihop_request(struct interface *ifp, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - unsigned short hop_count) -{ - int v4, pb, len; - - /* Make sure any buffered updates go out before this request. */ - flushupdates(ifp); - - if(ifp == NULL) { - struct interface *ifp_aux; - struct listnode *linklist_node = NULL; - FOR_ALL_INTERFACES(ifp_aux, linklist_node) { - if(!if_up(ifp_aux)) - continue; - send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count); - } - return; - } - - if(!if_up(ifp)) - return; - - debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", - hop_count, ifp->name, format_prefix(prefix, plen)); - v4 = plen >= 96 && v4mapped(prefix); - pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; - len = 6 + 8 + pb; - - start_message(ifp, MESSAGE_MH_REQUEST, len); - accumulate_byte(ifp, v4 ? 1 : 2); - accumulate_byte(ifp, v4 ? plen - 96 : plen); - accumulate_short(ifp, seqno); - accumulate_byte(ifp, hop_count); - accumulate_byte(ifp, 0); - accumulate_bytes(ifp, id, 8); - if(prefix) { - if(v4) - accumulate_bytes(ifp, prefix + 12, pb); - else - accumulate_bytes(ifp, prefix, pb); - } - end_message(ifp, MESSAGE_MH_REQUEST, len); -} - -void -send_unicast_multihop_request(struct neighbour *neigh, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - unsigned short hop_count) -{ - int rc, v4, pb, len; - - /* Make sure any buffered updates go out before this request. */ - flushupdates(neigh->ifp); - - debugf(BABEL_DEBUG_COMMON,"Sending multi-hop request to %s for %s (%d hops).", - format_address(neigh->address), - format_prefix(prefix, plen), hop_count); - v4 = plen >= 96 && v4mapped(prefix); - pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; - len = 6 + 8 + pb; - - rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len); - if(rc < 0) return; - accumulate_unicast_byte(neigh, v4 ? 1 : 2); - accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen); - accumulate_unicast_short(neigh, seqno); - accumulate_unicast_byte(neigh, hop_count); - accumulate_unicast_byte(neigh, 0); - accumulate_unicast_bytes(neigh, id, 8); - if(prefix) { - if(v4) - accumulate_unicast_bytes(neigh, prefix + 12, pb); - else - accumulate_unicast_bytes(neigh, prefix, pb); - } - end_unicast_message(neigh, MESSAGE_MH_REQUEST, len); -} - -void -send_request_resend(struct neighbour *neigh, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned char *id) -{ - if(neigh) - send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); - else - send_multihop_request(NULL, prefix, plen, seqno, id, 127); - - record_resend(RESEND_REQUEST, prefix, plen, seqno, id, - neigh ? neigh->ifp : NULL, resend_delay); -} - -void -handle_request(struct neighbour *neigh, const unsigned char *prefix, - unsigned char plen, unsigned char hop_count, - unsigned short seqno, const unsigned char *id) -{ - struct xroute *xroute; - struct babel_route *route; - struct neighbour *successor = NULL; - - xroute = find_xroute(prefix, plen); - route = find_installed_route(prefix, plen); - - if(xroute && (!route || xroute->metric <= kernel_metric)) { - if(hop_count > 0 && memcmp(id, myid, 8) == 0) { - if(seqno_compare(seqno, myseqno) > 0) { - if(seqno_minus(seqno, myseqno) > 100) { - /* Hopelessly out-of-date request */ - return; - } - update_myseqno(); - } - } - send_update(neigh->ifp, 1, prefix, plen); - return; - } - - if(route && - (memcmp(id, route->src->id, 8) != 0 || - seqno_compare(seqno, route->seqno) <= 0)) { - send_update(neigh->ifp, 1, prefix, plen); - return; - } - - if(hop_count <= 1) - return; - - if(route && memcmp(id, route->src->id, 8) == 0 && - seqno_minus(seqno, route->seqno) > 100) { - /* Hopelessly out-of-date */ - return; - } - - if(request_redundant(neigh->ifp, prefix, plen, seqno, id)) - return; - - /* Let's try to forward this request. */ - if(route && route_metric(route) < INFINITY) - successor = route->neigh; - - if(!successor || successor == neigh) { - /* We were about to forward a request to its requestor. Try to - find a different neighbour to forward the request to. */ - struct babel_route *other_route; - - other_route = find_best_route(prefix, plen, 0, neigh); - if(other_route && route_metric(other_route) < INFINITY) - successor = other_route->neigh; - } - - if(!successor || successor == neigh) - /* Give up */ - return; - - send_unicast_multihop_request(successor, prefix, plen, seqno, id, - hop_count - 1); - record_resend(RESEND_REQUEST, prefix, plen, seqno, id, - neigh->ifp, 0); -} diff --git a/babeld/message.h b/babeld/message.h deleted file mode 100644 index 6a9aa1046..000000000 --- a/babeld/message.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABEL_MESSAGE_H -#define BABEL_MESSAGE_H - -#include "babel_interface.h" - -#define MAX_BUFFERED_UPDATES 200 - -#define BUCKET_TOKENS_MAX 200 -#define BUCKET_TOKENS_PER_SEC 40 - -#define MESSAGE_PAD1 0 -#define MESSAGE_PADN 1 -#define MESSAGE_ACK_REQ 2 -#define MESSAGE_ACK 3 -#define MESSAGE_HELLO 4 -#define MESSAGE_IHU 5 -#define MESSAGE_ROUTER_ID 6 -#define MESSAGE_NH 7 -#define MESSAGE_UPDATE 8 -#define MESSAGE_REQUEST 9 -#define MESSAGE_MH_REQUEST 10 - - -extern unsigned short myseqno; -extern struct timeval seqno_time; - -extern int broadcast_ihu; -extern int split_horizon; - -extern unsigned char packet_header[4]; - -extern struct neighbour *unicast_neighbour; -extern struct timeval unicast_flush_timeout; - -void parse_packet(const unsigned char *from, struct interface *ifp, - const unsigned char *packet, int packetlen); -void flushbuf(struct interface *ifp); -void flushupdates(struct interface *ifp); -void send_ack(struct neighbour *neigh, unsigned short nonce, - unsigned short interval); -void send_hello_noupdate(struct interface *ifp, unsigned interval); -void send_hello(struct interface *ifp); -void flush_unicast(int dofree); -void send_update(struct interface *ifp, int urgent, - const unsigned char *prefix, unsigned char plen); -void send_update_resend(struct interface *ifp, - const unsigned char *prefix, unsigned char plen); -void send_wildcard_retraction(struct interface *ifp); -void update_myseqno(void); -void send_self_update(struct interface *ifp); -void send_ihu(struct neighbour *neigh, struct interface *ifp); -void send_marginal_ihu(struct interface *ifp); -void send_request(struct interface *ifp, - const unsigned char *prefix, unsigned char plen); -void send_unicast_request(struct neighbour *neigh, - const unsigned char *prefix, unsigned char plen); -void send_multihop_request(struct interface *ifp, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - unsigned short hop_count); -void -send_unicast_multihop_request(struct neighbour *neigh, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - unsigned short hop_count); -void send_request_resend(struct neighbour *neigh, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned char *id); -void handle_request(struct neighbour *neigh, const unsigned char *prefix, - unsigned char plen, unsigned char hop_count, - unsigned short seqno, const unsigned char *id); - -#endif diff --git a/babeld/neighbour.c b/babeld/neighbour.c deleted file mode 100644 index 5a327dfe9..000000000 --- a/babeld/neighbour.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include - -#include -#include "if.h" - -#include "babel_main.h" -#include "babeld.h" -#include "util.h" -#include "babel_interface.h" -#include "neighbour.h" -#include "source.h" -#include "route.h" -#include "message.h" -#include "resend.h" - -struct neighbour *neighs = NULL; - -static struct neighbour * -find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) -{ - struct neighbour *neigh; - FOR_ALL_NEIGHBOURS(neigh) { - if(memcmp(address, neigh->address, 16) == 0 && - neigh->ifp == ifp) - return neigh; - } - return NULL; -} - -void -flush_neighbour(struct neighbour *neigh) -{ - flush_neighbour_routes(neigh); - if(unicast_neighbour == neigh) - flush_unicast(1); - flush_resends(neigh); - - if(neighs == neigh) { - neighs = neigh->next; - } else { - struct neighbour *previous = neighs; - while(previous->next != neigh) - previous = previous->next; - previous->next = neigh->next; - } - free(neigh); -} - -struct neighbour * -find_neighbour(const unsigned char *address, struct interface *ifp) -{ - struct neighbour *neigh; - const struct timeval zero = {0, 0}; - - neigh = find_neighbour_nocreate(address, ifp); - if(neigh) - return neigh; - - debugf(BABEL_DEBUG_COMMON,"Creating neighbour %s on %s.", - format_address(address), ifp->name); - - neigh = malloc(sizeof(struct neighbour)); - if(neigh == NULL) { - zlog_err("malloc(neighbour): %s", safe_strerror(errno)); - return NULL; - } - - neigh->hello_seqno = -1; - memcpy(neigh->address, address, 16); - neigh->reach = 0; - neigh->txcost = INFINITY; - neigh->ihu_time = babel_now; - neigh->hello_time = zero; - neigh->hello_interval = 0; - neigh->ihu_interval = 0; - neigh->ifp = ifp; - neigh->next = neighs; - neighs = neigh; - send_hello(ifp); - return neigh; -} - -/* Recompute a neighbour's rxcost. Return true if anything changed. - This does not call local_notify_neighbour, see update_neighbour_metric. */ -int -update_neighbour(struct neighbour *neigh, int hello, int hello_interval) -{ - int missed_hellos; - int rc = 0; - - if(hello < 0) { - if(neigh->hello_interval <= 0) - return rc; - missed_hellos = - ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) - - neigh->hello_interval * 7) / - (neigh->hello_interval * 10); - if(missed_hellos <= 0) - return rc; - timeval_add_msec(&neigh->hello_time, &neigh->hello_time, - missed_hellos * neigh->hello_interval * 10); - } else { - if(neigh->hello_seqno >= 0 && neigh->reach > 0) { - missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1; - if(missed_hellos < -8) { - /* Probably a neighbour that rebooted and lost its seqno. - Reboot the universe. */ - neigh->reach = 0; - missed_hellos = 0; - rc = 1; - } else if(missed_hellos < 0) { - if(hello_interval > neigh->hello_interval) { - /* This neighbour has increased its hello interval, - and we didn't notice. */ - neigh->reach <<= -missed_hellos; - missed_hellos = 0; - } else { - /* Late hello. Probably due to the link layer buffering - packets during a link outage. Ignore it, but reset - the expected seqno. */ - neigh->hello_seqno = hello; - hello = -1; - missed_hellos = 0; - } - rc = 1; - } - } else { - missed_hellos = 0; - } - neigh->hello_time = babel_now; - neigh->hello_interval = hello_interval; - } - - if(missed_hellos > 0) { - neigh->reach >>= missed_hellos; - neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos); - missed_hellos = 0; - rc = 1; - } - - if(hello >= 0) { - neigh->hello_seqno = hello; - neigh->reach >>= 1; - neigh->reach |= 0x8000; - if((neigh->reach & 0xFC00) != 0xFC00) - rc = 1; - } - - /* Make sure to give neighbours some feedback early after association */ - if((neigh->reach & 0xBF00) == 0x8000) { - /* A new neighbour */ - send_hello(neigh->ifp); - } else { - /* Don't send hellos, in order to avoid a positive feedback loop. */ - int a = (neigh->reach & 0xC000); - int b = (neigh->reach & 0x3000); - if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { - /* Reachability is either 1100 or 0011 */ - send_self_update(neigh->ifp); - } - } - - if((neigh->reach & 0xFC00) == 0xC000) { - /* This is a newish neighbour, let's request a full route dump. - We ought to avoid this when the network is dense */ - send_unicast_request(neigh, NULL, 0); - send_ihu(neigh, NULL); - } - return rc; -} - -static int -reset_txcost(struct neighbour *neigh) -{ - unsigned delay; - - delay = timeval_minus_msec(&babel_now, &neigh->ihu_time); - - if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10U * 3U) - return 0; - - /* If we're losing a lot of packets, we probably lost an IHU too */ - if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || - (neigh->ihu_interval > 0 && - delay >= neigh->ihu_interval * 10U * 10U)) { - neigh->txcost = INFINITY; - neigh->ihu_time = babel_now; - return 1; - } - - return 0; -} - -unsigned -neighbour_txcost(struct neighbour *neigh) -{ - return neigh->txcost; -} - -unsigned -check_neighbours() -{ - struct neighbour *neigh; - int changed, rc; - unsigned msecs = 50000; - - debugf(BABEL_DEBUG_COMMON,"Checking neighbours."); - - neigh = neighs; - while(neigh) { - changed = update_neighbour(neigh, -1, 0); - - if(neigh->reach == 0 || - neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */ - timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) { - struct neighbour *old = neigh; - neigh = neigh->next; - flush_neighbour(old); - continue; - } - - rc = reset_txcost(neigh); - changed = changed || rc; - - update_neighbour_metric(neigh, changed); - - if(neigh->hello_interval > 0) - msecs = MIN(msecs, neigh->hello_interval * 10U); - if(neigh->ihu_interval > 0) - msecs = MIN(msecs, neigh->ihu_interval * 10U); - neigh = neigh->next; - } - - return msecs; -} - -unsigned -neighbour_rxcost(struct neighbour *neigh) -{ - unsigned delay; - unsigned short reach = neigh->reach; - - delay = timeval_minus_msec(&babel_now, &neigh->hello_time); - - if((reach & 0xFFF0) == 0 || delay >= 180000) { - return INFINITY; - } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { - int sreach = - ((reach & 0x8000) >> 2) + - ((reach & 0x4000) >> 1) + - (reach & 0x3FFF); - /* 0 <= sreach <= 0x7FFF */ - int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); - /* cost >= interface->cost */ - if(delay >= 40000) - cost = (cost * (delay - 20000) + 10000) / 20000; - return MIN(cost, INFINITY); - } else { - /* To lose one hello is a misfortune, to lose two is carelessness. */ - if((reach & 0xC000) == 0xC000) - return babel_get_if_nfo(neigh->ifp)->cost; - else if((reach & 0xC000) == 0) - return INFINITY; - else if((reach & 0x2000)) - return babel_get_if_nfo(neigh->ifp)->cost; - else - return INFINITY; - } -} - -unsigned -neighbour_cost(struct neighbour *neigh) -{ - unsigned a, b; - - if(!if_up(neigh->ifp)) - return INFINITY; - - a = neighbour_txcost(neigh); - - if(a >= INFINITY) - return INFINITY; - - b = neighbour_rxcost(neigh); - if(b >= INFINITY) - return INFINITY; - - if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) - || (a < 256 && b < 256)) { - return a; - } else { - /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected - probabilities of a packet getting through in the direct and reverse - directions. */ - a = MAX(a, 256); - b = MAX(b, 256); - /* 1/(alpha * beta), which is just plain ETX. */ - /* Since a and b are capped to 16 bits, overflow is impossible. */ - return (a * b + 128) >> 8; - } -} diff --git a/babeld/neighbour.h b/babeld/neighbour.h deleted file mode 100644 index cf8c0f0b2..000000000 --- a/babeld/neighbour.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -struct neighbour { - struct neighbour *next; - /* This is -1 when unknown, so don't make it unsigned */ - int hello_seqno; - unsigned char address[16]; - unsigned short reach; - unsigned short txcost; - struct timeval hello_time; - struct timeval ihu_time; - unsigned short hello_interval; /* in centiseconds */ - unsigned short ihu_interval; /* in centiseconds */ - struct interface *ifp; -}; - -extern struct neighbour *neighs; - -#define FOR_ALL_NEIGHBOURS(_neigh) \ - for(_neigh = neighs; _neigh; _neigh = _neigh->next) - -int neighbour_valid(struct neighbour *neigh); -void flush_neighbour(struct neighbour *neigh); -struct neighbour *find_neighbour(const unsigned char *address, - struct interface *ifp); -int update_neighbour(struct neighbour *neigh, int hello, int hello_interval); -unsigned check_neighbours(void); -unsigned neighbour_txcost(struct neighbour *neigh); -unsigned neighbour_rxcost(struct neighbour *neigh); -unsigned neighbour_cost(struct neighbour *neigh); diff --git a/babeld/net.c b/babeld/net.c deleted file mode 100644 index 5e0200b0a..000000000 --- a/babeld/net.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "babeld.h" -#include "util.h" -#include "net.h" - -int -babel_socket(int port) -{ - struct sockaddr_in6 sin6; - int s, rc; - int saved_errno; - int one = 1, zero = 0; - const int ds = 0xc0; /* CS6 - Network Control */ - - s = socket(PF_INET6, SOCK_DGRAM, 0); - if(s < 0) - return -1; - - rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); - if(rc < 0) - goto fail; - - rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - if(rc < 0) - goto fail; - - rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &zero, sizeof(zero)); - if(rc < 0) - goto fail; - - rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, - &one, sizeof(one)); - if(rc < 0) - goto fail; - - rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &one, sizeof(one)); - if(rc < 0) - goto fail; - -#ifdef IPV6_TCLASS - rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)); -#else - rc = -1; - errno = ENOSYS; -#endif - if(rc < 0) - perror("Couldn't set traffic class"); - - rc = fcntl(s, F_GETFL, 0); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_GETFD, 0); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); - if(rc < 0) - goto fail; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(port); - rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); - if(rc < 0) - goto fail; - - return s; - - fail: - saved_errno = errno; - close(s); - errno = saved_errno; - return -1; -} - -int -babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen) -{ - struct iovec iovec; - struct msghdr msg; - int rc; - - memset(&msg, 0, sizeof(msg)); - iovec.iov_base = buf; - iovec.iov_len = buflen; - msg.msg_name = sin; - msg.msg_namelen = slen; - msg.msg_iov = &iovec; - msg.msg_iovlen = 1; - - rc = recvmsg(s, &msg, 0); - return rc; -} - -int -babel_send(int s, - void *buf1, int buflen1, void *buf2, int buflen2, - struct sockaddr *sin, int slen) -{ - struct iovec iovec[2]; - struct msghdr msg; - int rc; - - iovec[0].iov_base = buf1; - iovec[0].iov_len = buflen1; - iovec[1].iov_base = buf2; - iovec[1].iov_len = buflen2; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = (struct sockaddr*)sin; - msg.msg_namelen = slen; - msg.msg_iov = iovec; - msg.msg_iovlen = 2; - - again: - rc = sendmsg(s, &msg, 0); - if(rc < 0) { - if(errno == EINTR) - goto again; - else if(errno == EAGAIN) { - int rc2; - rc2 = wait_for_fd(1, s, 5); - if(rc2 > 0) - goto again; - errno = EAGAIN; - } - } - return rc; -} - -int -tcp_server_socket(int port, int local) -{ - struct sockaddr_in6 sin6; - int s, rc, saved_errno; - int one = 1; - - s = socket(PF_INET6, SOCK_STREAM, 0); - if(s < 0) - return -1; - - rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_GETFL, 0); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_GETFD, 0); - if(rc < 0) - goto fail; - - rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); - if(rc < 0) - goto fail; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(port); - if(local) { - rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr); - if(rc < 0) - goto fail; - } - rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); - if(rc < 0) - goto fail; - - rc = listen(s, 2); - if(rc < 0) - goto fail; - - return s; - - fail: - saved_errno = errno; - close(s); - errno = saved_errno; - return -1; -} diff --git a/babeld/net.h b/babeld/net.h deleted file mode 100644 index 4bd0f04f9..000000000 --- a/babeld/net.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -int babel_socket(int port); -int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen); -int babel_send(int s, - void *buf1, int buflen1, void *buf2, int buflen2, - struct sockaddr *sin, int slen); -int tcp_server_socket(int port, int local); diff --git a/babeld/resend.c b/babeld/resend.c deleted file mode 100644 index 1cc6290e7..000000000 --- a/babeld/resend.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include - -#include -#include "if.h" - -#include "babel_main.h" -#include "babeld.h" -#include "util.h" -#include "neighbour.h" -#include "resend.h" -#include "message.h" -#include "babel_interface.h" - -struct timeval resend_time = {0, 0}; -struct resend *to_resend = NULL; - -static int -resend_match(struct resend *resend, - int kind, const unsigned char *prefix, unsigned char plen) -{ - return (resend->kind == kind && - resend->plen == plen && memcmp(resend->prefix, prefix, 16) == 0); -} - -/* This is called by neigh.c when a neighbour is flushed */ - -void -flush_resends(struct neighbour *neigh) -{ - /* Nothing for now */ -} - -static struct resend * -find_resend(int kind, const unsigned char *prefix, unsigned char plen, - struct resend **previous_return) -{ - struct resend *current, *previous; - - previous = NULL; - current = to_resend; - while(current) { - if(resend_match(current, kind, prefix, plen)) { - if(previous_return) - *previous_return = previous; - return current; - } - previous = current; - current = current->next; - } - - return NULL; -} - -struct resend * -find_request(const unsigned char *prefix, unsigned char plen, - struct resend **previous_return) -{ - return find_resend(RESEND_REQUEST, prefix, plen, previous_return); -} - -int -record_resend(int kind, const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - struct interface *ifp, int delay) -{ - struct resend *resend; - unsigned int ifindex = ifp ? ifp->ifindex : 0; - - if((kind == RESEND_REQUEST && - input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) || - (kind == RESEND_UPDATE && - output_filter(NULL, prefix, plen, ifindex) >= INFINITY)) - return 0; - - if(delay >= 0xFFFF) - delay = 0xFFFF; - - resend = find_resend(kind, prefix, plen, NULL); - if(resend) { - if(resend->delay && delay) - resend->delay = MIN(resend->delay, delay); - else if(delay) - resend->delay = delay; - resend->time = babel_now; - resend->max = RESEND_MAX; - if(id && memcmp(resend->id, id, 8) == 0 && - seqno_compare(resend->seqno, seqno) > 0) { - return 0; - } - if(id) - memcpy(resend->id, id, 8); - else - memset(resend->id, 0, 8); - resend->seqno = seqno; - if(resend->ifp != ifp) - resend->ifp = NULL; - } else { - resend = malloc(sizeof(struct resend)); - if(resend == NULL) - return -1; - resend->kind = kind; - resend->max = RESEND_MAX; - resend->delay = delay; - memcpy(resend->prefix, prefix, 16); - resend->plen = plen; - resend->seqno = seqno; - if(id) - memcpy(resend->id, id, 8); - else - memset(resend->id, 0, 8); - resend->ifp = ifp; - resend->time = babel_now; - resend->next = to_resend; - to_resend = resend; - } - - if(resend->delay) { - struct timeval timeout; - timeval_add_msec(&timeout, &resend->time, resend->delay); - timeval_min(&resend_time, &timeout); - } - return 1; -} - -static int -resend_expired(struct resend *resend) -{ - switch(resend->kind) { - case RESEND_REQUEST: - return timeval_minus_msec(&babel_now, &resend->time) >= REQUEST_TIMEOUT; - default: - return resend->max <= 0; - } -} - -int -unsatisfied_request(const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id) -{ - struct resend *request; - - request = find_request(prefix, plen, NULL); - if(request == NULL || resend_expired(request)) - return 0; - - if(memcmp(request->id, id, 8) != 0 || - seqno_compare(request->seqno, seqno) <= 0) - return 1; - - return 0; -} - -/* Determine whether a given request should be forwarded. */ -int -request_redundant(struct interface *ifp, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id) -{ - struct resend *request; - - request = find_request(prefix, plen, NULL); - if(request == NULL || resend_expired(request)) - return 0; - - if(memcmp(request->id, id, 8) == 0 && - seqno_compare(request->seqno, seqno) > 0) - return 0; - - if(request->ifp != NULL && request->ifp != ifp) - return 0; - - if(request->max > 0) - /* Will be resent. */ - return 1; - - if(timeval_minus_msec(&babel_now, &request->time) < - (ifp ? MIN(babel_get_if_nfo(ifp)->hello_interval, 1000) : 1000)) - /* Fairly recent. */ - return 1; - - return 0; -} - -int -satisfy_request(const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - struct interface *ifp) -{ - struct resend *request, *previous; - - request = find_request(prefix, plen, &previous); - if(request == NULL) - return 0; - - if(ifp != NULL && request->ifp != ifp) - return 0; - - if(memcmp(request->id, id, 8) != 0 || - seqno_compare(request->seqno, seqno) <= 0) { - /* We cannot remove the request, as we may be walking the list right - now. Mark it as expired, so that expire_resend will remove it. */ - request->max = 0; - request->time.tv_sec = 0; - recompute_resend_time(); - return 1; - } - - return 0; -} - -void -expire_resend() -{ - struct resend *current, *previous; - int recompute = 0; - - previous = NULL; - current = to_resend; - while(current) { - if(resend_expired(current)) { - if(previous == NULL) { - to_resend = current->next; - free(current); - current = to_resend; - } else { - previous->next = current->next; - free(current); - current = previous->next; - } - recompute = 1; - } else { - previous = current; - current = current->next; - } - } - if(recompute) - recompute_resend_time(); -} - -void -recompute_resend_time() -{ - struct resend *request; - struct timeval resend = {0, 0}; - - request = to_resend; - while(request) { - if(!resend_expired(request) && request->delay > 0 && request->max > 0) { - struct timeval timeout; - timeval_add_msec(&timeout, &request->time, request->delay); - timeval_min(&resend, &timeout); - } - request = request->next; - } - - resend_time = resend; -} - -void -do_resend() -{ - struct resend *resend; - - resend = to_resend; - while(resend) { - if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) { - struct timeval timeout; - timeval_add_msec(&timeout, &resend->time, resend->delay); - if(timeval_compare(&babel_now, &timeout) >= 0) { - switch(resend->kind) { - case RESEND_REQUEST: - send_multihop_request(resend->ifp, - resend->prefix, resend->plen, - resend->seqno, resend->id, 127); - break; - case RESEND_UPDATE: - send_update(resend->ifp, 1, - resend->prefix, resend->plen); - break; - default: abort(); - } - resend->delay = MIN(0xFFFF, resend->delay * 2); - resend->max--; - } - } - resend = resend->next; - } - recompute_resend_time(); -} diff --git a/babeld/resend.h b/babeld/resend.h deleted file mode 100644 index a6755c0eb..000000000 --- a/babeld/resend.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#define REQUEST_TIMEOUT 65000 -#define RESEND_MAX 3 - -#define RESEND_REQUEST 1 -#define RESEND_UPDATE 2 - -struct resend { - unsigned char kind; - unsigned char max; - unsigned short delay; - struct timeval time; - unsigned char prefix[16]; - unsigned char plen; - unsigned short seqno; - unsigned char id[8]; - struct interface *ifp; - struct resend *next; -}; - -extern struct timeval resend_time; - -struct resend *find_request(const unsigned char *prefix, unsigned char plen, - struct resend **previous_return); -void flush_resends(struct neighbour *neigh); -int record_resend(int kind, const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - struct interface *ifp, int delay); -int unsatisfied_request(const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id); -int request_redundant(struct interface *ifp, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id); -int satisfy_request(const unsigned char *prefix, unsigned char plen, - unsigned short seqno, const unsigned char *id, - struct interface *ifp); - -void expire_resend(void); -void recompute_resend_time(void); -void do_resend(void); diff --git a/babeld/route.c b/babeld/route.c deleted file mode 100644 index fe2b9cebb..000000000 --- a/babeld/route.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "if.h" - -#include "babeld.h" -#include "util.h" -#include "kernel.h" -#include "babel_interface.h" -#include "source.h" -#include "neighbour.h" -#include "route.h" -#include "xroute.h" -#include "message.h" -#include "resend.h" - -static void consider_route(struct babel_route *route); - -struct babel_route **routes = NULL; -static int route_slots = 0, max_route_slots = 0; -int kernel_metric = 0; -int allow_duplicates = -1; -int diversity_kind = DIVERSITY_NONE; -int diversity_factor = 256; /* in units of 1/256 */ -int keep_unfeasible = 0; - -/* We maintain a list of "slots", ordered by prefix. Every slot - contains a linked list of the routes to this prefix, with the - installed route, if any, at the head of the list. */ - -static int -route_compare(const unsigned char *prefix, unsigned char plen, - struct babel_route *route) -{ - int i = memcmp(prefix, route->src->prefix, 16); - if(i != 0) - return i; - - if(plen < route->src->plen) - return -1; - else if(plen > route->src->plen) - return 1; - else - return 0; -} - -/* Performs binary search, returns -1 in case of failure. In the latter - case, new_return is the place where to insert the new element. */ - -static int -find_route_slot(const unsigned char *prefix, unsigned char plen, - int *new_return) -{ - int p, m, g, c; - - if(route_slots < 1) { - if(new_return) - *new_return = 0; - return -1; - } - - p = 0; g = route_slots - 1; - - do { - m = (p + g) / 2; - c = route_compare(prefix, plen, routes[m]); - if(c == 0) - return m; - else if(c < 0) - g = m - 1; - else - p = m + 1; - } while(p <= g); - - if(new_return) - *new_return = p; - - return -1; -} - -struct babel_route * -find_route(const unsigned char *prefix, unsigned char plen, - struct neighbour *neigh, const unsigned char *nexthop) -{ - struct babel_route *route; - int i = find_route_slot(prefix, plen, NULL); - - if(i < 0) - return NULL; - - route = routes[i]; - - while(route) { - if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0) - return route; - route = route->next; - } - - return NULL; -} - -struct babel_route * -find_installed_route(const unsigned char *prefix, unsigned char plen) -{ - int i = find_route_slot(prefix, plen, NULL); - - if(i >= 0 && routes[i]->installed) - return routes[i]; - - return NULL; -} - -/* Returns an overestimate of the number of installed routes. */ -int -installed_routes_estimate(void) -{ - return route_slots; -} - -static int -resize_route_table(int new_slots) -{ - struct babel_route **new_routes; - assert(new_slots >= route_slots); - - if(new_slots == 0) { - new_routes = NULL; - free(routes); - } else { - new_routes = realloc(routes, new_slots * sizeof(struct babel_route*)); - if(new_routes == NULL) - return -1; - } - - max_route_slots = new_slots; - routes = new_routes; - return 1; -} - -/* Insert a route into the table. If successful, retains the route. - On failure, caller must free the route. */ -static struct babel_route * -insert_route(struct babel_route *route) -{ - int i, n; - - assert(!route->installed); - - i = find_route_slot(route->src->prefix, route->src->plen, &n); - - if(i < 0) { - if(route_slots >= max_route_slots) - resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots); - if(route_slots >= max_route_slots) - return NULL; - route->next = NULL; - if(n < route_slots) - memmove(routes + n + 1, routes + n, - (route_slots - n) * sizeof(struct babel_route*)); - route_slots++; - routes[n] = route; - } else { - struct babel_route *r; - r = routes[i]; - while(r->next) - r = r->next; - r->next = route; - route->next = NULL; - } - - return route; -} - -void -flush_route(struct babel_route *route) -{ - int i; - struct source *src; - unsigned oldmetric; - int lost = 0; - - oldmetric = route_metric(route); - src = route->src; - - if(route->installed) { - uninstall_route(route); - lost = 1; - } - - i = find_route_slot(route->src->prefix, route->src->plen, NULL); - assert(i >= 0 && i < route_slots); - - if(route == routes[i]) { - routes[i] = route->next; - route->next = NULL; - free(route); - - if(routes[i] == NULL) { - if(i < route_slots - 1) - memmove(routes + i, routes + i + 1, - (route_slots - i - 1) * sizeof(struct babel_route*)); - routes[route_slots - 1] = NULL; - route_slots--; - } - - if(route_slots == 0) - resize_route_table(0); - else if(max_route_slots > 8 && route_slots < max_route_slots / 4) - resize_route_table(max_route_slots / 2); - } else { - struct babel_route *r = routes[i]; - while(r->next != route) - r = r->next; - r->next = route->next; - route->next = NULL; - free(route); - } - - if(lost) - route_lost(src, oldmetric); - - release_source(src); -} - -void -flush_all_routes() -{ - int i; - - /* Start from the end, to avoid shifting the table. */ - i = route_slots - 1; - while(i >= 0) { - while(i < route_slots) { - /* Uninstall first, to avoid calling route_lost. */ - if(routes[i]->installed) - uninstall_route(routes[0]); - flush_route(routes[i]); - } - i--; - } - - check_sources_released(); -} - -void -flush_neighbour_routes(struct neighbour *neigh) -{ - int i; - - i = 0; - while(i < route_slots) { - struct babel_route *r; - r = routes[i]; - while(r) { - if(r->neigh == neigh) { - flush_route(r); - goto again; - } - r = r->next; - } - i++; - again: - ; - } -} - -void -flush_interface_routes(struct interface *ifp, int v4only) -{ - int i; - - i = 0; - while(i < route_slots) { - struct babel_route *r; - r = routes[i]; - while(r) { - if(r->neigh->ifp == ifp && - (!v4only || v4mapped(r->nexthop))) { - flush_route(r); - goto again; - } - r = r->next; - } - i++; - again: - ; - } -} - -/* Iterate a function over all routes. */ -void -for_all_routes(void (*f)(struct babel_route*, void*), void *closure) -{ - int i; - - for(i = 0; i < route_slots; i++) { - struct babel_route *r = routes[i]; - while(r) { - (*f)(r, closure); - r = r->next; - } - } -} - -void -for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure) -{ - int i; - - for(i = 0; i < route_slots; i++) { - if(routes[i]->installed) - (*f)(routes[i], closure); - } -} - -static int -metric_to_kernel(int metric) -{ - return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; -} - -/* This is used to maintain the invariant that the installed route is at - the head of the list. */ -static void -move_installed_route(struct babel_route *route, int i) -{ - assert(i >= 0 && i < route_slots); - assert(route->installed); - - if(route != routes[i]) { - struct babel_route *r = routes[i]; - while(r->next != route) - r = r->next; - r->next = route->next; - route->next = routes[i]; - routes[i] = route; - } -} - -void -install_route(struct babel_route *route) -{ - int i, rc; - - if(route->installed) - return; - - if(!route_feasible(route)) - zlog_err("WARNING: installing unfeasible route " - "(this shouldn't happen)."); - - i = find_route_slot(route->src->prefix, route->src->plen, NULL); - assert(i >= 0 && i < route_slots); - - if(routes[i] != route && routes[i]->installed) { - fprintf(stderr, "WARNING: attempting to install duplicate route " - "(this shouldn't happen)."); - return; - } - - rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, - route->nexthop, - route->neigh->ifp->ifindex, - metric_to_kernel(route_metric(route)), NULL, 0, 0); - if(rc < 0) { - int save = errno; - zlog_err("kernel_route(ADD): %s", safe_strerror(errno)); - if(save != EEXIST) - return; - } - route->installed = 1; - move_installed_route(route, i); - -} - -void -uninstall_route(struct babel_route *route) -{ - int rc; - - if(!route->installed) - return; - - rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, - route->nexthop, - route->neigh->ifp->ifindex, - metric_to_kernel(route_metric(route)), NULL, 0, 0); - if(rc < 0) - zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno)); - - route->installed = 0; -} - -/* This is equivalent to uninstall_route followed with install_route, - but without the race condition. The destination of both routes - must be the same. */ - -static void -switch_routes(struct babel_route *old, struct babel_route *new) -{ - int rc; - - if(!old) { - install_route(new); - return; - } - - if(!old->installed) - return; - - if(!route_feasible(new)) - zlog_err("WARNING: switching to unfeasible route " - "(this shouldn't happen)."); - - rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, - old->nexthop, old->neigh->ifp->ifindex, - metric_to_kernel(route_metric(old)), - new->nexthop, new->neigh->ifp->ifindex, - metric_to_kernel(route_metric(new))); - if(rc < 0) { - zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno)); - return; - } - - old->installed = 0; - new->installed = 1; - move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen, - NULL)); -} - -static void -change_route_metric(struct babel_route *route, - unsigned refmetric, unsigned cost, unsigned add) -{ - int old, new; - int newmetric = MIN(refmetric + cost + add, INFINITY); - - old = metric_to_kernel(route_metric(route)); - new = metric_to_kernel(newmetric); - - if(route->installed && old != new) { - int rc; - rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, - route->nexthop, route->neigh->ifp->ifindex, - old, - route->nexthop, route->neigh->ifp->ifindex, - new); - if(rc < 0) { - zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno)); - return; - } - } - - route->refmetric = refmetric; - route->cost = cost; - route->add_metric = add; -} - -static void -retract_route(struct babel_route *route) -{ - change_route_metric(route, INFINITY, INFINITY, 0); -} - -int -route_feasible(struct babel_route *route) -{ - return update_feasible(route->src, route->seqno, route->refmetric); -} - -int -route_old(struct babel_route *route) -{ - return route->time < babel_now.tv_sec - route->hold_time * 7 / 8; -} - -int -route_expired(struct babel_route *route) -{ - return route->time < babel_now.tv_sec - route->hold_time; -} - -static int -channels_interfere(int ch1, int ch2) -{ - if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING - || ch2 == BABEL_IF_CHANNEL_NONINTERFERING) - return 0; - if(ch1 == BABEL_IF_CHANNEL_INTERFERING - || ch2 == BABEL_IF_CHANNEL_INTERFERING) - return 1; - return ch1 == ch2; -} - -int -route_interferes(struct babel_route *route, struct interface *ifp) -{ - struct babel_interface *babel_ifp = NULL; - switch(diversity_kind) { - case DIVERSITY_NONE: - return 1; - case DIVERSITY_INTERFACE_1: - return route->neigh->ifp == ifp; - case DIVERSITY_CHANNEL_1: - case DIVERSITY_CHANNEL: - if(route->neigh->ifp == ifp) - return 1; - babel_ifp = babel_get_if_nfo(ifp); - if(channels_interfere(babel_ifp->channel, - babel_get_if_nfo(route->neigh->ifp)->channel)) - return 1; - if(diversity_kind == DIVERSITY_CHANNEL) { - int i; - for(i = 0; i < DIVERSITY_HOPS; i++) { - if(route->channels[i] == 0) - break; - if(channels_interfere(babel_ifp->channel, route->channels[i])) - return 1; - } - } - return 0; - default: - fprintf(stderr, "Unknown kind of diversity.\n"); - return 1; - } -} - -int -update_feasible(struct source *src, - unsigned short seqno, unsigned short refmetric) -{ - if(src == NULL) - return 1; - - if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) - /* Never mind what is probably stale data */ - return 1; - - if(refmetric >= INFINITY) - /* Retractions are always feasible */ - return 1; - - return (seqno_compare(seqno, src->seqno) > 0 || - (src->seqno == seqno && refmetric < src->metric)); -} - -/* This returns the feasible route with the smallest metric. */ -struct babel_route * -find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, - struct neighbour *exclude) -{ - struct babel_route *route = NULL, *r = NULL; - int i = find_route_slot(prefix, plen, NULL); - - if(i < 0) - return NULL; - - route = routes[i]; - - r = route->next; - while(r) { - if(!route_expired(r) && - (!feasible || route_feasible(r)) && - (!exclude || r->neigh != exclude) && - (route_metric(r) < route_metric(route))) - route = r; - r = r->next; - } - return route; -} - -void -update_route_metric(struct babel_route *route) -{ - int oldmetric = route_metric(route); - - if(route_expired(route)) { - if(route->refmetric < INFINITY) { - route->seqno = seqno_plus(route->src->seqno, 1); - retract_route(route); - if(oldmetric < INFINITY) - route_changed(route, route->src, oldmetric); - } - } else { - struct neighbour *neigh = route->neigh; - int add_metric = input_filter(route->src->id, - route->src->prefix, route->src->plen, - neigh->address, - neigh->ifp->ifindex); - change_route_metric(route, route->refmetric, - neighbour_cost(route->neigh), add_metric); - if(route_metric(route) != oldmetric) - route_changed(route, route->src, oldmetric); - } -} - -/* Called whenever a neighbour's cost changes, to update the metric of - all routes through that neighbour. Calls local_notify_neighbour. */ -void -update_neighbour_metric(struct neighbour *neigh, int changed) -{ - - if(changed) { - int i; - - for(i = 0; i < route_slots; i++) { - struct babel_route *r = routes[i]; - while(r) { - if(r->neigh == neigh) - update_route_metric(r); - r = r->next; - } - } - } -} - -void -update_interface_metric(struct interface *ifp) -{ - int i; - - for(i = 0; i < route_slots; i++) { - struct babel_route *r = routes[i]; - while(r) { - if(r->neigh->ifp == ifp) - update_route_metric(r); - r = r->next; - } - } -} - -/* This is called whenever we receive an update. */ -struct babel_route * -update_route(const unsigned char *router_id, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned short refmetric, - unsigned short interval, - struct neighbour *neigh, const unsigned char *nexthop, - const unsigned char *channels, int channels_len) -{ - struct babel_route *route; - struct source *src; - int metric, feasible; - int add_metric; - int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); - - if(memcmp(router_id, myid, 8) == 0) - return NULL; - - if(martian_prefix(prefix, plen)) { - zlog_err("Rejecting martian route to %s through %s.", - format_prefix(prefix, plen), format_address(router_id)); - return NULL; - } - - add_metric = input_filter(router_id, prefix, plen, - neigh->address, neigh->ifp->ifindex); - if(add_metric >= INFINITY) - return NULL; - - route = find_route(prefix, plen, neigh, nexthop); - - if(route && memcmp(route->src->id, router_id, 8) == 0) - /* Avoid scanning the source table. */ - src = route->src; - else - src = find_source(router_id, prefix, plen, 1, seqno); - - if(src == NULL) - return NULL; - - feasible = update_feasible(src, seqno, refmetric); - metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); - - if(route) { - struct source *oldsrc; - unsigned short oldmetric; - int lost = 0; - - oldsrc = route->src; - oldmetric = route_metric(route); - - /* If a successor switches sources, we must accept his update even - if it makes a route unfeasible in order to break any routing loops - in a timely manner. If the source remains the same, we ignore - the update. */ - if(!feasible && route->installed) { - debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s " - "(%s %d %d -> %s %d %d).", - format_prefix(src->prefix, src->plen), - format_address(route->src->id), - route->seqno, route->refmetric, - format_address(src->id), seqno, refmetric); - if(src != route->src) { - uninstall_route(route); - lost = 1; - } - } - - route->src = retain_source(src); - if((feasible || keep_unfeasible) && refmetric < INFINITY) - route->time = babel_now.tv_sec; - route->seqno = seqno; - change_route_metric(route, - refmetric, neighbour_cost(neigh), add_metric); - route->hold_time = hold_time; - - route_changed(route, oldsrc, oldmetric); - if(lost) - route_lost(oldsrc, oldmetric); - - if(!feasible) - send_unfeasible_request(neigh, route->installed && route_old(route), - seqno, metric, src); - release_source(oldsrc); - } else { - struct babel_route *new_route; - - if(refmetric >= INFINITY) - /* Somebody's retracting a route we never saw. */ - return NULL; - if(!feasible) { - send_unfeasible_request(neigh, 0, seqno, metric, src); - if(!keep_unfeasible) - return NULL; - } - - route = malloc(sizeof(struct babel_route)); - if(route == NULL) { - perror("malloc(route)"); - return NULL; - } - - route->src = retain_source(src); - route->refmetric = refmetric; - route->cost = neighbour_cost(neigh); - route->add_metric = add_metric; - route->seqno = seqno; - route->neigh = neigh; - memcpy(route->nexthop, nexthop, 16); - route->time = babel_now.tv_sec; - route->hold_time = hold_time; - route->installed = 0; - memset(&route->channels, 0, sizeof(route->channels)); - if(channels_len > 0) - memcpy(&route->channels, channels, - MIN(channels_len, DIVERSITY_HOPS)); - route->next = NULL; - new_route = insert_route(route); - if(new_route == NULL) { - fprintf(stderr, "Couldn't insert route.\n"); - free(route); - return NULL; - } - consider_route(route); - } - return route; -} - -/* We just received an unfeasible update. If it's any good, send - a request for a new seqno. */ -void -send_unfeasible_request(struct neighbour *neigh, int force, - unsigned short seqno, unsigned short metric, - struct source *src) -{ - struct babel_route *route = find_installed_route(src->prefix, src->plen); - - if(seqno_minus(src->seqno, seqno) > 100) { - /* Probably a source that lost its seqno. Let it time-out. */ - return; - } - - if(force || !route || route_metric(route) >= metric + 512) { - send_unicast_multihop_request(neigh, src->prefix, src->plen, - src->metric >= INFINITY ? - src->seqno : - seqno_plus(src->seqno, 1), - src->id, 127); - } -} - -/* This takes a feasible route and decides whether to install it. */ -static void -consider_route(struct babel_route *route) -{ - struct babel_route *installed; - struct xroute *xroute; - - if(route->installed) - return; - - if(!route_feasible(route)) - return; - - xroute = find_xroute(route->src->prefix, route->src->plen); - if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates)) - return; - - installed = find_installed_route(route->src->prefix, route->src->plen); - - if(installed == NULL) - goto install; - - if(route_metric(route) >= INFINITY) - return; - - if(route_metric(installed) >= INFINITY) - goto install; - - if(route_metric(installed) >= route_metric(route) + 64) - goto install; - - return; - - install: - switch_routes(installed, route); - if(installed && route->installed) - send_triggered_update(route, installed->src, route_metric(installed)); - else - send_update(NULL, 1, route->src->prefix, route->src->plen); - return; -} - -void -retract_neighbour_routes(struct neighbour *neigh) -{ - int i; - - for(i = 0; i < route_slots; i++) { - struct babel_route *r = routes[i]; - while(r) { - if(r->neigh == neigh) { - if(r->refmetric != INFINITY) { - unsigned short oldmetric = route_metric(r); - retract_route(r); - if(oldmetric != INFINITY) - route_changed(r, r->src, oldmetric); - } - } - r = r->next; - } - i++; - } -} - -void -send_triggered_update(struct babel_route *route, struct source *oldsrc, - unsigned oldmetric) -{ - unsigned newmetric, diff; - /* 1 means send speedily, 2 means resend */ - int urgent; - - if(!route->installed) - return; - - newmetric = route_metric(route); - diff = - newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric; - - if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY)) - /* Switching sources can cause transient routing loops. - Retractions can cause blackholes. */ - urgent = 2; - else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512) - /* Route getting significantly worse */ - urgent = 1; - else if(unsatisfied_request(route->src->prefix, route->src->plen, - route->seqno, route->src->id)) - /* Make sure that requests are satisfied speedily */ - urgent = 1; - else if(oldmetric >= INFINITY && newmetric < INFINITY) - /* New route */ - urgent = 0; - else if(newmetric < oldmetric && diff < 1024) - /* Route getting better. This may be a transient fluctuation, so - don't advertise it to avoid making routes unfeasible later on. */ - return; - else if(diff < 384) - /* Don't fret about trivialities */ - return; - else - urgent = 0; - - if(urgent >= 2) - send_update_resend(NULL, route->src->prefix, route->src->plen); - else - send_update(NULL, urgent, route->src->prefix, route->src->plen); - - if(oldmetric < INFINITY) { - if(newmetric >= oldmetric + 512) { - send_request_resend(NULL, route->src->prefix, route->src->plen, - route->src->metric >= INFINITY ? - route->src->seqno : - seqno_plus(route->src->seqno, 1), - route->src->id); - } else if(newmetric >= oldmetric + 288) { - send_request(NULL, route->src->prefix, route->src->plen); - } - } -} - -/* A route has just changed. Decide whether to switch to a different route or - send an update. */ -void -route_changed(struct babel_route *route, - struct source *oldsrc, unsigned short oldmetric) -{ - if(route->installed) { - if(route_metric(route) > oldmetric) { - struct babel_route *better_route; - better_route = - find_best_route(route->src->prefix, route->src->plen, 1, NULL); - if(better_route && - route_metric(better_route) <= route_metric(route) - 96) - consider_route(better_route); - } - - if(route->installed) - /* We didn't change routes after all. */ - send_triggered_update(route, oldsrc, oldmetric); - } else { - /* Reconsider routes even when their metric didn't decrease, - they may not have been feasible before. */ - consider_route(route); - } -} - -/* We just lost the installed route to a given destination. */ -void -route_lost(struct source *src, unsigned oldmetric) -{ - struct babel_route *new_route; - new_route = find_best_route(src->prefix, src->plen, 1, NULL); - if(new_route) { - consider_route(new_route); - } else if(oldmetric < INFINITY) { - /* Complain loudly. */ - send_update_resend(NULL, src->prefix, src->plen); - send_request_resend(NULL, src->prefix, src->plen, - src->metric >= INFINITY ? - src->seqno : seqno_plus(src->seqno, 1), - src->id); - } -} - -/* This is called periodically to flush old routes. It will also send - requests for routes that are about to expire. */ -void -expire_routes(void) -{ - struct babel_route *r; - int i; - - debugf(BABEL_DEBUG_COMMON,"Expiring old routes."); - - i = 0; - while(i < route_slots) { - r = routes[i]; - while(r) { - /* Protect against clock being stepped. */ - if(r->time > babel_now.tv_sec || route_old(r)) { - flush_route(r); - goto again; - } - - update_route_metric(r); - - if(r->installed && r->refmetric < INFINITY) { - if(route_old(r)) - /* Route about to expire, send a request. */ - send_unicast_request(r->neigh, - r->src->prefix, r->src->plen); - } - r = r->next; - } - i++; - again: - ; - } -} diff --git a/babeld/route.h b/babeld/route.h deleted file mode 100644 index b6d2d2946..000000000 --- a/babeld/route.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABEL_ROUTE_H -#define BABEL_ROUTE_H - -#include "babel_interface.h" -#include "source.h" - -#define DIVERSITY_NONE 0 -#define DIVERSITY_INTERFACE_1 1 -#define DIVERSITY_CHANNEL_1 2 -#define DIVERSITY_CHANNEL 3 - -#define DIVERSITY_HOPS 8 - -struct babel_route { - struct source *src; - unsigned short refmetric; - unsigned short cost; - unsigned short add_metric; - unsigned short seqno; - struct neighbour *neigh; - unsigned char nexthop[16]; - time_t time; - unsigned short hold_time; /* in seconds */ - short installed; - unsigned char channels[DIVERSITY_HOPS]; - struct babel_route *next; -}; - -extern struct babel_route **routes; -extern int kernel_metric, allow_duplicates; -extern int diversity_kind, diversity_factor; -extern int keep_unfeasible; - -static inline int -route_metric(const struct babel_route *route) -{ - int m = (int)route->refmetric + route->cost + route->add_metric; - return MIN(m, INFINITY); -} - -static inline int -route_metric_noninterfering(const struct babel_route *route) -{ - int m = - (int)route->refmetric + - (diversity_factor * route->cost + 128) / 256 + - route->add_metric; - m = MAX(m, route->refmetric + 1); - return MIN(m, INFINITY); -} - -struct babel_route *find_route(const unsigned char *prefix, unsigned char plen, - struct neighbour *neigh, const unsigned char *nexthop); -struct babel_route *find_installed_route(const unsigned char *prefix, - unsigned char plen); -int installed_routes_estimate(void); -void flush_route(struct babel_route *route); -void flush_all_routes(void); -void flush_neighbour_routes(struct neighbour *neigh); -void flush_interface_routes(struct interface *ifp, int v4only); -void for_all_routes(void (*f)(struct babel_route*, void*), void *closure); -void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure); -void install_route(struct babel_route *route); -void uninstall_route(struct babel_route *route); -void switch_route(struct babel_route *old, struct babel_route *new); -int route_feasible(struct babel_route *route); -int route_old(struct babel_route *route); -int route_expired(struct babel_route *route); -int route_interferes(struct babel_route *route, struct interface *ifp); -int update_feasible(struct source *src, - unsigned short seqno, unsigned short refmetric); -struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen, - int feasible, struct neighbour *exclude); -struct babel_route *install_best_route(const unsigned char prefix[16], - unsigned char plen); -void update_neighbour_metric(struct neighbour *neigh, int change); -void update_interface_metric(struct interface *ifp); -void update_route_metric(struct babel_route *route); -struct babel_route *update_route(const unsigned char *id, - const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned short refmetric, - unsigned short interval, struct neighbour *neigh, - const unsigned char *nexthop, - const unsigned char *channels, int channels_len); -void retract_neighbour_routes(struct neighbour *neigh); -void send_unfeasible_request(struct neighbour *neigh, int force, - unsigned short seqno, unsigned short metric, - struct source *src); -void send_triggered_update(struct babel_route *route, - struct source *oldsrc, unsigned oldmetric); -void route_changed(struct babel_route *route, - struct source *oldsrc, unsigned short oldmetric); -void route_lost(struct source *src, unsigned oldmetric); -void expire_routes(void); - -#endif diff --git a/babeld/source.c b/babeld/source.c deleted file mode 100644 index 772112d4d..000000000 --- a/babeld/source.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include - -#include "babel_main.h" -#include "babeld.h" -#include "util.h" -#include "source.h" -#include "babel_interface.h" -#include "route.h" - -struct source *srcs = NULL; - -struct source* -find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, - int create, unsigned short seqno) -{ - struct source *src; - - for(src = srcs; src; src = src->next) { - /* This should really be a hash table. For now, check the - last byte first. */ - if(src->id[7] != id[7]) - continue; - if(memcmp(src->id, id, 8) != 0) - continue; - if(src->plen != plen) - continue; - if(memcmp(src->prefix, p, 16) == 0) - return src; - } - - if(!create) - return NULL; - - src = malloc(sizeof(struct source)); - if(src == NULL) { - zlog_err("malloc(source): %s", safe_strerror(errno)); - return NULL; - } - - memcpy(src->id, id, 8); - memcpy(src->prefix, p, 16); - src->plen = plen; - src->seqno = seqno; - src->metric = INFINITY; - src->time = babel_now.tv_sec; - src->route_count = 0; - src->next = srcs; - srcs = src; - return src; -} - -struct source * -retain_source(struct source *src) -{ - assert(src->route_count < 0xffff); - src->route_count++; - return src; -} - -void -release_source(struct source *src) -{ - assert(src->route_count > 0); - src->route_count--; -} - -int -flush_source(struct source *src) -{ - if(src->route_count > 0) - /* The source is in use by a route. */ - return 0; - - if(srcs == src) { - srcs = src->next; - } else { - struct source *previous = srcs; - while(previous->next != src) - previous = previous->next; - previous->next = src->next; - } - - free(src); - return 1; -} - -void -update_source(struct source *src, - unsigned short seqno, unsigned short metric) -{ - if(metric >= INFINITY) - return; - - /* If a source is expired, pretend that it doesn't exist and update - it unconditionally. This makes ensures that old data will - eventually be overridden, and prevents us from getting stuck if - a router loses its sequence number. */ - if(src->time < babel_now.tv_sec - SOURCE_GC_TIME || - seqno_compare(src->seqno, seqno) < 0 || - (src->seqno == seqno && src->metric > metric)) { - src->seqno = seqno; - src->metric = metric; - } - src->time = babel_now.tv_sec; -} - -void -expire_sources() -{ - struct source *src; - - src = srcs; - while(src) { - if(src->time > babel_now.tv_sec) - /* clock stepped */ - src->time = babel_now.tv_sec; - if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) { - struct source *old = src; - src = src->next; - flush_source(old); - continue; - } - src = src->next; - } -} - -void -check_sources_released(void) -{ - struct source *src; - - for(src = srcs; src; src = src->next) { - if(src->route_count != 0) - fprintf(stderr, "Warning: source %s %s has refcount %d.\n", - format_eui64(src->id), - format_prefix(src->prefix, src->plen), - (int)src->route_count); - } -} diff --git a/babeld/source.h b/babeld/source.h deleted file mode 100644 index 62a7e1eea..000000000 --- a/babeld/source.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef BABEL_SOURCE_H -#define BABEL_SOURCE_H - -#define SOURCE_GC_TIME 200 - -struct source { - struct source *next; - unsigned char id[8]; - unsigned char prefix[16]; - unsigned char plen; - unsigned short seqno; - unsigned short metric; - unsigned short route_count; - time_t time; -}; - -struct source *find_source(const unsigned char *id, - const unsigned char *p, - unsigned char plen, - int create, unsigned short seqno); -struct source *retain_source(struct source *src); -void release_source(struct source *src); -int flush_source(struct source *src); -void update_source(struct source *src, - unsigned short seqno, unsigned short metric); -void expire_sources(void); -void check_sources_released(void); - -#endif diff --git a/babeld/util.c b/babeld/util.c deleted file mode 100644 index 011f3824e..000000000 --- a/babeld/util.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "babel_main.h" -#include "babeld.h" -#include "util.h" - -unsigned -roughly(unsigned value) -{ - return value * 3 / 4 + random() % (value / 2); -} - -/* d = s1 - s2 */ -void -timeval_minus(struct timeval *d, - const struct timeval *s1, const struct timeval *s2) -{ - if(s1->tv_usec >= s2->tv_usec) { - d->tv_usec = s1->tv_usec - s2->tv_usec; - d->tv_sec = s1->tv_sec - s2->tv_sec; - } else { - d->tv_usec = s1->tv_usec + 1000000 - s2->tv_usec; - d->tv_sec = s1->tv_sec - s2->tv_sec - 1; - } -} - -unsigned -timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) -{ - if(s1->tv_sec < s2->tv_sec) - return 0; - - /* Avoid overflow. */ - if(s1->tv_sec - s2->tv_sec > 2000000) - return 2000000000; - - if(s1->tv_sec > s2->tv_sec) - return - (unsigned)((unsigned)(s1->tv_sec - s2->tv_sec) * 1000 + - ((int)s1->tv_usec - s2->tv_usec) / 1000); - - if(s1->tv_usec <= s2->tv_usec) - return 0; - - return (unsigned)(s1->tv_usec - s2->tv_usec) / 1000u; -} - -/* d = s + msecs */ -void -timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs) -{ - int usecs; - d->tv_sec = s->tv_sec + msecs / 1000; - usecs = s->tv_usec + (msecs % 1000) * 1000; - if(usecs < 1000000) { - d->tv_usec = usecs; - } else { - d->tv_usec = usecs - 1000000; - d->tv_sec++; - } -} - -void -set_timeout(struct timeval *timeout, int msecs) -{ - timeval_add_msec(timeout, &babel_now, roughly(msecs)); -} - -/* returns <0 if "s1" < "s2", etc. */ -int -timeval_compare(const struct timeval *s1, const struct timeval *s2) -{ - if(s1->tv_sec < s2->tv_sec) - return -1; - else if(s1->tv_sec > s2->tv_sec) - return 1; - else if(s1->tv_usec < s2->tv_usec) - return -1; - else if(s1->tv_usec > s2->tv_usec) - return 1; - else - return 0; -} - -/* set d at min(d, s) */ -/* {0, 0} represents infinity */ -void -timeval_min(struct timeval *d, const struct timeval *s) -{ - if(s->tv_sec == 0) - return; - - if(d->tv_sec == 0 || timeval_compare(d, s) > 0) { - *d = *s; - } -} - -/* set d to min(d, x) with x in [secs, secs+1] */ -void -timeval_min_sec(struct timeval *d, time_t secs) -{ - if(d->tv_sec == 0 || d->tv_sec > secs) { - d->tv_sec = secs; - d->tv_usec = random() % 1000000; - } -} - -/* parse a float value in second and return the corresponding mili-seconds. - For example: - parse_msec("12.342345") returns 12342 */ -int -parse_msec(const char *string) -{ - unsigned int in, fl; - int i, j; - - in = fl = 0; - i = 0; - while(string[i] == ' ' || string[i] == '\t') - i++; - while(string[i] >= '0' && string[i] <= '9') { - in = in * 10 + string[i] - '0'; - i++; - } - if(string[i] == '.') { - i++; - j = 0; - while(string[i] >= '0' && string[i] <= '9') { - fl = fl * 10 + string[i] - '0'; - i++; - j++; - } - - while(j > 3) { - fl /= 10; - j--; - } - while(j < 3) { - fl *= 10; - j++; - } - } - - while(string[i] == ' ' || string[i] == '\t') - i++; - - if(string[i] == '\0') - return in * 1000 + fl; - - return -1; -} - -int -in_prefix(const unsigned char *restrict address, - const unsigned char *restrict prefix, unsigned char plen) -{ - unsigned char m; - - if(plen > 128) - plen = 128; - - if(memcmp(address, prefix, plen / 8) != 0) - return 0; - - if(plen % 8 == 0) - return 1; - - m = 0xFF << (8 - (plen % 8)); - - return ((address[plen / 8] & m) == (prefix[plen / 8] & m)); -} - -unsigned char * -mask_prefix(unsigned char *restrict ret, - const unsigned char *restrict prefix, unsigned char plen) -{ - if(plen >= 128) { - memcpy(ret, prefix, 16); - return ret; - } - - memset(ret, 0, 16); - memcpy(ret, prefix, plen / 8); - if(plen % 8 != 0) - ret[plen / 8] = - (prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF)); - return ret; -} - -static const unsigned char v4prefix[16] = - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; - -static const unsigned char llprefix[16] = - {0xFE, 0x80}; - -const char * -format_address(const unsigned char *address) -{ - static char buf[4][INET6_ADDRSTRLEN]; - static int i = 0; - i = (i + 1) % 4; - if(v4mapped(address)) - inet_ntop(AF_INET, address + 12, buf[i], INET6_ADDRSTRLEN); - else - inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN); - return buf[i]; -} - -const char * -format_prefix(const unsigned char *prefix, unsigned char plen) -{ - static char buf[4][INET6_ADDRSTRLEN + 4]; - static int i = 0; - int n; - i = (i + 1) % 4; - if(plen >= 96 && v4mapped(prefix)) { - inet_ntop(AF_INET, prefix + 12, buf[i], INET6_ADDRSTRLEN); - n = strlen(buf[i]); - snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen - 96); - } else { - inet_ntop(AF_INET6, prefix, buf[i], INET6_ADDRSTRLEN); - n = strlen(buf[i]); - snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen); - } - return buf[i]; -} - -const char * -format_eui64(const unsigned char *eui) -{ - static char buf[4][28]; - static int i = 0; - i = (i + 1) % 4; - snprintf(buf[i], 28, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - eui[0], eui[1], eui[2], eui[3], - eui[4], eui[5], eui[6], eui[7]); - return buf[i]; -} - -const char *format_bool(const int b) { - return b ? "true" : "false"; -} - -int -parse_address(const char *address, unsigned char *addr_r, int *af_r) -{ - struct in_addr ina; - struct in6_addr ina6; - int rc; - - rc = inet_pton(AF_INET, address, &ina); - if(rc > 0) { - memcpy(addr_r, v4prefix, 12); - memcpy(addr_r + 12, &ina, 4); - if(af_r) *af_r = AF_INET; - return 0; - } - - rc = inet_pton(AF_INET6, address, &ina6); - if(rc > 0) { - memcpy(addr_r, &ina6, 16); - if(af_r) *af_r = AF_INET6; - return 0; - } - - return -1; -} - -int -parse_eui64(const char *eui, unsigned char *eui_r) -{ - int n; - n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], - &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); - if(n == 8) - return 0; - - n = sscanf(eui, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx", - &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], - &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); - if(n == 8) - return 0; - - n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &eui_r[0], &eui_r[1], &eui_r[2], - &eui_r[5], &eui_r[6], &eui_r[7]); - if(n == 6) { - eui_r[3] = 0xFF; - eui_r[4] = 0xFE; - return 0; - } - return -1; -} - -int -wait_for_fd(int direction, int fd, int msecs) -{ - fd_set fds; - int rc; - struct timeval tv; - - tv.tv_sec = msecs / 1000; - tv.tv_usec = (msecs % 1000) * 1000; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - if(direction) - rc = select(fd + 1, NULL, &fds, NULL, &tv); - else - rc = select(fd + 1, &fds, NULL, NULL, &tv); - - return rc; -} - -int -martian_prefix(const unsigned char *prefix, int plen) -{ - return - (plen >= 8 && prefix[0] == 0xFF) || - (plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) || - (plen >= 128 && memcmp(prefix, zeroes, 15) == 0 && - (prefix[15] == 0 || prefix[15] == 1)) || - (plen >= 96 && v4mapped(prefix) && - ((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) || - (plen >= 100 && (prefix[12] & 0xE0) == 0xE0))); -} - -int -linklocal(const unsigned char *address) -{ - return memcmp(address, llprefix, 8) == 0; -} - -int -v4mapped(const unsigned char *address) -{ - return memcmp(address, v4prefix, 12) == 0; -} - -void -v4tov6(unsigned char *dst, const unsigned char *src) -{ - memcpy(dst, v4prefix, 12); - memcpy(dst + 12, src, 4); -} - -void -inaddr_to_uchar(unsigned char *dest, const struct in_addr *src) -{ - memcpy(dest, v4prefix, 12); - memcpy(dest + 12, src, 4); - assert(v4mapped(dest)); -} - -void -uchar_to_inaddr(struct in_addr *dest, const unsigned char *src) -{ - assert(v4mapped(src)); - memcpy(dest, src + 12, 4); -} - -void -in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src) -{ - memcpy(dest, src, 16); -} - -void -uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src) -{ - memcpy(dest, src, 16); -} - -int -daemonise() -{ - int rc; - - fflush(stdout); - fflush(stderr); - - rc = fork(); - if(rc < 0) - return -1; - - if(rc > 0) - exit(0); - - rc = setsid(); - if(rc < 0) - return -1; - - return 1; -} diff --git a/babeld/util.h b/babeld/util.h deleted file mode 100644 index 5d9d2f5da..000000000 --- a/babeld/util.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "babeld.h" -#include "babel_main.h" -#include "log.h" - -#if defined(i386) || defined(__mc68020__) || defined(__x86_64__) -#define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0) -#define DO_NTOHL(_d, _s) do{ _d = ntohl(*(const unsigned*)(_s)); } while(0) -#define DO_HTONS(_d, _s) do{ *(unsigned short*)(_d) = htons(_s); } while(0) -#define DO_HTONL(_d, _s) do{ *(unsigned*)(_d) = htonl(_s); } while(0) -/* Some versions of gcc seem to be buggy, and ignore the packed attribute. - Disable this code until the issue is clarified. */ -/* #elif defined __GNUC__*/ -#elif 0 -struct __us { unsigned short x __attribute__((packed)); }; -#define DO_NTOHS(_d, _s) \ - do { _d = ntohs(((const struct __us*)(_s))->x); } while(0) -#define DO_HTONS(_d, _s) \ - do { ((struct __us*)(_d))->x = htons(_s); } while(0) -#else -#define DO_NTOHS(_d, _s) \ - do { short _dd; \ - memcpy(&(_dd), (_s), 2); \ - _d = ntohs(_dd); } while(0) -#define DO_HTONS(_d, _s) \ - do { unsigned short _dd; \ - _dd = htons(_s); \ - memcpy((_d), &(_dd), 2); } while(0) -#endif - -static inline int -seqno_compare(unsigned short s1, unsigned short s2) -{ - if(s1 == s2) - return 0; - else - return ((s2 - s1) & 0x8000) ? 1 : -1; -} - -static inline short -seqno_minus(unsigned short s1, unsigned short s2) -{ - return (short)((s1 - s2) & 0xFFFF); -} - -static inline unsigned short -seqno_plus(unsigned short s, int plus) -{ - return ((s + plus) & 0xFFFF); -} - -unsigned roughly(unsigned value); -void timeval_minus(struct timeval *d, - const struct timeval *s1, const struct timeval *s2); -unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) - ATTRIBUTE ((pure)); -void timeval_add_msec(struct timeval *d, - const struct timeval *s, const int msecs); -void set_timeout (struct timeval *timeout, int msecs); -int timeval_compare(const struct timeval *s1, const struct timeval *s2) - ATTRIBUTE ((pure)); -void timeval_min(struct timeval *d, const struct timeval *s); -void timeval_min_sec(struct timeval *d, time_t secs); -int parse_msec(const char *string) ATTRIBUTE ((pure)); -int in_prefix(const unsigned char *restrict address, - const unsigned char *restrict prefix, unsigned char plen) - ATTRIBUTE ((pure)); -unsigned char *mask_prefix(unsigned char *restrict ret, - const unsigned char *restrict prefix, - unsigned char plen); -const char *format_address(const unsigned char *address); -const char *format_prefix(const unsigned char *address, unsigned char prefix); -const char *format_eui64(const unsigned char *eui); -const char *format_bool(const int b); -int parse_address(const char *address, unsigned char *addr_r, int *af_r); -int parse_eui64(const char *eui, unsigned char *eui_r); -int wait_for_fd(int direction, int fd, int msecs); -int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure)); -int linklocal(const unsigned char *address) ATTRIBUTE ((pure)); -int v4mapped(const unsigned char *address) ATTRIBUTE ((pure)); -void v4tov6(unsigned char *dst, const unsigned char *src); -void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src); -void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src); -void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src); -void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src); -int daemonise(void); - -/* If debugging is disabled, we want to avoid calling format_address - for every omitted debugging message. So debug is a macro. But - vararg macros are not portable. */ -#if defined NO_DEBUG - -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L -#define debugf(...) do {} while(0) -#elif defined __GNUC__ -#define debugf(_args...) do {} while(0) -#else -static inline void debugf(int level, const char *format, ...) { return; } -#endif - -#else /* NO_DEBUG */ - -/* some levels */ -#define BABEL_DEBUG_COMMON (1 << 0) -#define BABEL_DEBUG_KERNEL (1 << 1) -#define BABEL_DEBUG_FILTER (1 << 2) -#define BABEL_DEBUG_TIMEOUT (1 << 3) -#define BABEL_DEBUG_IF (1 << 4) -#define BABEL_DEBUG_ROUTE (1 << 5) -#define BABEL_DEBUG_ALL (0xFFFF) - -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L -#define debugf(level, ...) \ -do { \ -if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \ -} while(0) -#elif defined __GNUC__ -#define debugf(level, _args...) \ -do { \ -if(UNLIKELY(debug & level)) zlog_debug(_args); \ -} while(0) -#else -static inline void debugf(int level, const char *format, ...) { return; } -#endif - -#endif /* NO_DEBUG */ - diff --git a/babeld/xroute.c b/babeld/xroute.c deleted file mode 100644 index 806516718..000000000 --- a/babeld/xroute.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include "if.h" -#include "log.h" - -#include "babeld.h" -#include "kernel.h" -#include "neighbour.h" -#include "message.h" -#include "route.h" -#include "xroute.h" -#include "util.h" -#include "babel_interface.h" - -static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, - unsigned short metric, unsigned int ifindex, - int proto, int send_updates); - -static struct xroute *xroutes; -static int numxroutes = 0, maxxroutes = 0; - -/* Add redistributed route to Babel table. */ -int -babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex, struct in_addr *nexthop) -{ - unsigned char uchar_prefix[16]; - - inaddr_to_uchar(uchar_prefix, &prefix->prefix); - debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra."); - xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96, - api->metric, ifindex, 0, 1); - return 0; -} - -/* Remove redistributed route from Babel table. */ -int -babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex) -{ - unsigned char uchar_prefix[16]; - struct xroute *xroute = NULL; - - inaddr_to_uchar(uchar_prefix, &prefix->prefix); - xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96); - if (xroute != NULL) { - debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); - flush_xroute(xroute); - } - return 0; -} - -/* Add redistributed route to Babel table. */ -int -babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex, struct in6_addr *nexthop) -{ - unsigned char uchar_prefix[16]; - - in6addr_to_uchar(uchar_prefix, &prefix->prefix); - debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra."); - xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, - 0, 1); - return 0; -} - -/* Remove redistributed route from Babel table. */ -int -babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex) -{ - unsigned char uchar_prefix[16]; - struct xroute *xroute = NULL; - - in6addr_to_uchar(uchar_prefix, &prefix->prefix); - xroute = find_xroute(uchar_prefix, prefix->prefixlen); - if (xroute != NULL) { - debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra)."); - flush_xroute(xroute); - } - return 0; -} - -struct xroute * -find_xroute(const unsigned char *prefix, unsigned char plen) -{ - int i; - for(i = 0; i < numxroutes; i++) { - if(xroutes[i].plen == plen && - memcmp(xroutes[i].prefix, prefix, 16) == 0) - return &xroutes[i]; - } - return NULL; -} - -void -flush_xroute(struct xroute *xroute) -{ - int i; - - i = xroute - xroutes; - assert(i >= 0 && i < numxroutes); - - if(i != numxroutes - 1) - memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute)); - numxroutes--; - VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute)); - - if(numxroutes == 0) { - free(xroutes); - xroutes = NULL; - maxxroutes = 0; - } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) { - struct xroute *new_xroutes; - int n = maxxroutes / 2; - new_xroutes = realloc(xroutes, n * sizeof(struct xroute)); - if(new_xroutes == NULL) - return; - xroutes = new_xroutes; - maxxroutes = n; - } -} - -static int -add_xroute(unsigned char prefix[16], unsigned char plen, - unsigned short metric, unsigned int ifindex, int proto) -{ - struct xroute *xroute = find_xroute(prefix, plen); - if(xroute) { - if(xroute->metric <= metric) - return 0; - xroute->metric = metric; - return 1; - } - - if(numxroutes >= maxxroutes) { - struct xroute *new_xroutes; - int n = maxxroutes < 1 ? 8 : 2 * maxxroutes; - new_xroutes = xroutes == NULL ? - malloc(n * sizeof(struct xroute)) : - realloc(xroutes, n * sizeof(struct xroute)); - if(new_xroutes == NULL) - return -1; - maxxroutes = n; - xroutes = new_xroutes; - } - - memcpy(xroutes[numxroutes].prefix, prefix, 16); - xroutes[numxroutes].plen = plen; - xroutes[numxroutes].metric = metric; - xroutes[numxroutes].ifindex = ifindex; - xroutes[numxroutes].proto = proto; - numxroutes++; - return 1; -} - -/* Returns an overestimate of the number of xroutes. */ -int -xroutes_estimate() -{ - return numxroutes; -} - -void -for_all_xroutes(void (*f)(struct xroute*, void*), void *closure) -{ - int i; - - for(i = 0; i < numxroutes; i++) - (*f)(&xroutes[i], closure); -} - -/* add an xroute, verifying some conditions; return 0 if there is no changes */ -static int -xroute_add_new_route(unsigned char prefix[16], unsigned char plen, - unsigned short metric, unsigned int ifindex, - int proto, int send_updates) -{ - int rc; - if(martian_prefix(prefix, plen)) - return 0; - metric = redistribute_filter(prefix, plen, ifindex, proto); - if(metric < INFINITY) { - rc = add_xroute(prefix, plen, metric, ifindex, proto); - if(rc > 0) { - struct babel_route *route; - route = find_installed_route(prefix, plen); - if(route) { - if(allow_duplicates < 0 || - metric < allow_duplicates) - uninstall_route(route); - } - if(send_updates) - send_update(NULL, 0, prefix, plen); - return 1; - } - } - return 0; -} diff --git a/babeld/xroute.h b/babeld/xroute.h deleted file mode 100644 index 4d4ab99d0..000000000 --- a/babeld/xroute.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is free software: you may copy, redistribute and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -struct xroute { - unsigned char prefix[16]; - unsigned char plen; - unsigned short metric; - unsigned int ifindex; - int proto; -}; - -struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); -void flush_xroute(struct xroute *xroute); -int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex, struct in_addr *nexthop); -int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex); -int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex, struct in6_addr *nexthop); -int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex); -int xroutes_estimate(void); -void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure); diff --git a/configure.ac b/configure.ac index a82470cd0..f68d86fc4 100755 --- a/configure.ac +++ b/configure.ac @@ -239,8 +239,6 @@ AC_ARG_ENABLE(ospfd, AS_HELP_STRING([--disable-ospfd], [do not build ospfd])) AC_ARG_ENABLE(ospf6d, AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) -AC_ARG_ENABLE(babeld, - AS_HELP_STRING([--disable-babeld], [do not build babeld])) AC_ARG_ENABLE(watchquagga, AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) AC_ARG_ENABLE(isisd, @@ -1134,13 +1132,6 @@ else fi AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") -if test "${enable_babeld}" = "no";then - BABELD="" -else - BABELD="babeld" -fi -AM_CONDITIONAL(BABELD, test "x$BABELD" = "xbabeld") - if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else @@ -1199,7 +1190,6 @@ AC_SUBST(RIPD) AC_SUBST(RIPNGD) AC_SUBST(OSPFD) AC_SUBST(OSPF6D) -AC_SUBST(BABELD) AC_SUBST(WATCHQUAGGA) AC_SUBST(ISISD) AC_SUBST(PIMD) @@ -1533,7 +1523,6 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID) AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID) AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID) AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID) -AC_DEFINE_UNQUOTED(PATH_BABELD_PID, "$quagga_statedir/babeld.pid",babeld PID) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID) AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID) AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID) @@ -1544,7 +1533,6 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket) AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket) AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket) -AC_DEFINE_UNQUOTED(BABEL_VTYSH_PATH, "$quagga_statedir/babeld.vty",babeld vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket) AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket) AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory) @@ -1570,7 +1558,7 @@ AC_MSG_RESULT($ac_cv_htonl_works) AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile - ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile + ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile pimd/Makefile tests/bgpd.tests/Makefile diff --git a/doc/Makefile.am b/doc/Makefile.am index 11eca73ff..3ff317014 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -46,7 +46,7 @@ info_TEXINFOS = quagga.texi quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) $(TEXI2PDF) -o "$@" $< || true -quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ +quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ diff --git a/doc/babeld.texi b/doc/babeld.texi deleted file mode 100644 index 1f24edd06..000000000 --- a/doc/babeld.texi +++ /dev/null @@ -1,118 +0,0 @@ -@c -*-texinfo-*- -@c This is part of the Quagga Manual. -@c @value{COPYRIGHT_STR} -@c See file quagga.texi for copying conditions. -@node Babel -@chapter Babel - -Babel is an interior gateway protocol that is suitable both for wired -networks and for wireless mesh networks. Babel has been described as -``RIP on speed'' --- it is based on the same principles as RIP, but -includes a number of refinements that make it react much faster to -topology changes without ever counting to infinity, and allow it to -perform reliable link quality estimation on wireless links. Babel is -a double-stack routing protocol, meaning that a single Babel instance -is able to perform routing for both IPv4 and IPv6. - -Quagga implements Babel as described in RFC6126. - -@menu -* Configuring babeld:: -* Babel configuration:: -* Babel redistribution:: -* Show Babel information:: -* Babel debugging commands:: -@end menu - -@node Configuring babeld, Babel configuration, Babel, Babel -@section Configuring babeld - -The @command{babeld} daemon can be invoked with any of the common -options (@pxref{Common Invocation Options}). - -The @command{zebra} daemon must be running before @command{babeld} is -invoked. Also, if @command{zebra} is restarted then @command{babeld} -must be too. - -Configuration of @command{babeld} is done in its configuration file -@file{babeld.conf}. - -@node Babel configuration, Babel redistribution, Configuring babeld, Babel -@section Babel configuration - -@deffn Command {router babel} {} -@deffnx Command {no router babel} {} -Enable or disable Babel routing. -@end deffn - -@deffn {Babel Command} {network @var{ifname}} {} -@deffnx {Babel Command} {no network @var{ifname}} {} -Enable or disable Babel on the given interface. -@end deffn - -@deffn {Interface Command} {babel wired} {} -@deffnx {Interface Command} {babel wireless} {} -Specifies whether this interface is wireless, which disables a number -of optimisations that are only correct on wired interfaces. -Specifying @code{wireless} (the default) is always correct, but may -cause slower convergence and extra routing traffic. -@end deffn - -@deffn {Interface Command} {babel split-horizon} -@deffnx {Interface Command} {no babel split-horizon} -Specifies whether to perform split-horizon on the interface. -Specifying @code{no babel split-horizon} (the default) is always -correct, while @code{babel split-horizon} is an optimisation that -should only be used on symmetric and transitive (wired) networks. -@end deffn - -@deffn {Interface Command} {babel hello-interval <20-655340>} -Specifies the time in milliseconds between two scheduled hellos. On -wired links, Babel notices a link failure within two hello intervals; -on wireless links, the link quality value is reestimated at every -hello interval. The default is 4000@dmn{ms}. -@end deffn - -@deffn {Interface Command} {babel update-interval <20-655340>} -Specifies the time in milliseconds between two scheduled updates. -Since Babel makes extensive use of triggered updates, this can be set -to fairly high values on links with little packet loss. The default -is 20000@dmn{ms}. -@end deffn - -@deffn {Babel Command} {babel resend-delay <20-655340>} -Specifies the time in milliseconds after which an ``important'' -request or update will be resent. The default is 2000@dmn{ms}. You -probably don't want to tweak this value. -@end deffn - -@node Babel redistribution, Show Babel information, Babel configuration, Babel -@section Babel redistribution - -@deffn {Babel command} {redistribute @var{kind}} -@deffnx {Babel command} {no redistribute @var{kind}} -Specify which kind of routes should be redistributed into Babel. -@end deffn - -@node Show Babel information, Babel debugging commands, Babel redistribution, Babel -@section Show Babel information - -@deffn {Command} {show babel database} {} -@deffnx {Command} {show babel interface} {} -@deffnx {Command} {show babel neighbour} {} -@deffnx {Command} {show babel parameters} {} -These commands dump various parts of @command{babeld}'s internal -state. They are mostly useful for troubleshooting. -@end deffn - -@node Babel debugging commands, , Show Babel information, Babel -@section Babel debugging commands - -@deffn {Babel Command} {debug babel @var{kind}} {} -@deffnx {Babel Command} {no debug babel @var{kind}} {} -Enable or disable debugging messages of a given kind. @var{kind} can -be one of @samp{common}, @samp{kernel}, @samp{filter}, @samp{timeout}, -@samp{interface}, @samp{route} or @samp{all}. Note that if you have -compiled with the NO_DEBUG flag, then these commands aren't available. -@end deffn - diff --git a/doc/ipv6.texi b/doc/ipv6.texi index 2482c1c0b..5be2babed 100644 --- a/doc/ipv6.texi +++ b/doc/ipv6.texi @@ -2,7 +2,7 @@ @chapter IPv6 Support Quagga fully supports IPv6 routing. As described so far, Quagga supports -RIPng, OSPFv3, Babel and BGP-4+. You can give IPv6 addresses to an interface +RIPng, OSPFv3, and BGP-4+. You can give IPv6 addresses to an interface and configure static IPv6 routing information. Quagga IPv6 also provides automatic address configuration via a feature called @code{address auto configuration}. To do it, the router must send router advertisement diff --git a/doc/quagga.texi b/doc/quagga.texi index 836507109..65089621a 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -85,7 +85,6 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of * RIPng:: * OSPFv2:: * OSPFv3:: -* Babel:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: @@ -110,7 +109,6 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of @include ripngd.texi @include ospfd.texi @include ospf6d.texi -@include babeld.texi @include bgpd.texi @include routeserver.texi @include vtysh.texi From 5460baef7f0014f2d0c3459aa9c4180da19d6850 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 19 May 2015 00:35:04 +0200 Subject: [PATCH 0700/1342] *: fix "babeld: Remove babeld from Quagga" (336724d) This removes some more bits of babeld, particularly from: - buildtest.sh - redhat/ build files - vtysh integration (which actively broke the build) The memtype and zclient/route type are kept in place since these don't break anything and -theoretically- make it possible to build babeld with some Quagga integration externally. (Keeping vtysh integration is unfortunately not as easy.) Reported-by: Donald Sharp Fixes: 336724d ("babeld: Remove babeld from Quagga") Acked-by: Donald Sharp Acked-by: Paul Jakma Signed-off-by: David Lamparter --- buildtest.sh | 2 +- pimd/quagga-configure-no-vtysh.sh | 2 +- redhat/Makefile.am | 2 +- redhat/babeld.init | 72 ------------------------------- redhat/babeld.service | 14 ------ redhat/quagga.logrotate | 8 ---- redhat/quagga.spec.in | 3 +- vtysh/Makefile.am | 1 - vtysh/extract.pl.in | 1 - vtysh/vtysh.c | 20 --------- vtysh/vtysh_config.c | 2 - 11 files changed, 4 insertions(+), 123 deletions(-) delete mode 100644 redhat/babeld.init delete mode 100644 redhat/babeld.service diff --git a/buildtest.sh b/buildtest.sh index 3dd8ed821..ca0c03628 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -4,7 +4,7 @@ # builds some git commit of Quagga in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-babeld --enable-pimd --enable-werror" +basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror" configs_base="gcc|$basecfg" diff --git a/pimd/quagga-configure-no-vtysh.sh b/pimd/quagga-configure-no-vtysh.sh index b3052dceb..672007ba7 100755 --- a/pimd/quagga-configure-no-vtysh.sh +++ b/pimd/quagga-configure-no-vtysh.sh @@ -7,4 +7,4 @@ # # $QuaggaId: $Format:%an, %ai, %h$ $ -./configure --disable-babeld --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 +./configure --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 diff --git a/redhat/Makefile.am b/redhat/Makefile.am index c83e9591f..9612e9148 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -1,5 +1,5 @@ -EXTRA_DIST = babeld.init babeld.service bgpd.init bgpd.service isisd.init \ +EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ diff --git a/redhat/babeld.init b/redhat/babeld.init deleted file mode 100644 index 76e8e5e08..000000000 --- a/redhat/babeld.init +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash -# chkconfig: - 16 84 -# config: /etc/quagga/babeld.conf - -### BEGIN INIT INFO -# Provides: babeld -# Short-Description: Babel routing engine -# Description: Babel routing engine for use with Zebra -### END INIT INFO - -# source function library -. /etc/rc.d/init.d/functions - -# Get network config -. /etc/sysconfig/network - -# quagga command line options -. /etc/sysconfig/quagga - -RETVAL=0 -PROG="babeld" -cmd=babeld -LOCK_FILE=/var/lock/subsys/babeld -CONF_FILE=/etc/quagga/babeld.conf - -case "$1" in - start) - # Check that networking is up. - [ "${NETWORKING}" = "no" ] && exit 1 - - # The process must be configured first. - [ -f $CONF_FILE ] || exit 6 - if [ `id -u` -ne 0 ]; then - echo $"Insufficient privilege" 1>&2 - exit 4 - fi - - echo -n $"Starting $PROG: " - daemon $cmd -d $BABELD_OPTS -f $CONF_FILE - RETVAL=$? - [ $RETVAL -eq 0 ] && touch $LOCK_FILE - echo - ;; - stop) - echo -n $"Shutting down $PROG: " - killproc $cmd - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE - echo - ;; - restart|reload|force-reload) - $0 stop - $0 start - RETVAL=$? - ;; - condrestart|try-restart) - if [ -f $LOCK_FILE ]; then - $0 stop - $0 start - fi - RETVAL=$? - ;; - status) - status $cmd - RETVAL=$? - ;; - *) - echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" - exit 2 -esac - -exit $RETVAL diff --git a/redhat/babeld.service b/redhat/babeld.service deleted file mode 100644 index b1ea9432e..000000000 --- a/redhat/babeld.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=Babel routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/babeld.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/babeld -d $BABELD_OPTS -f /etc/quagga/babeld.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/quagga.logrotate b/redhat/quagga.logrotate index 9756a781a..afbd40c02 100644 --- a/redhat/quagga.logrotate +++ b/redhat/quagga.logrotate @@ -6,14 +6,6 @@ endscript } -/var/log/quagga/babeld.log { - notifempty - missingok - postrotate - /bin/kill -USR1 `cat /var/run/quagga/babeld.pid 2> /dev/null` 2> /dev/null || true - endscript -} - /var/log/quagga/bgpd.log { notifempty missingok diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 75835bbe9..43feea411 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -68,7 +68,7 @@ %define daemon_list zebra ripd ospfd bgpd %if %{with_ipv6} -%define daemonv6_list ripngd babeld ospf6d +%define daemonv6_list ripngd ospf6d %else %define daemonv6_list "" %endif @@ -409,7 +409,6 @@ rm -rf $RPM_BUILD_ROOT %if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d -%{_sbindir}/babeld %endif %if %{with_isisd} %{_sbindir}/isisd diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 0cc6d5ba0..d1ff69b9c 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -24,7 +24,6 @@ EXTRA_DIST = extract.pl vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \ $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \ - $(top_srcdir)/babeld/*.c \ $(top_srcdir)/pimd/pim_cmd.c \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index d323cdb05..99d80ed4a 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -37,7 +37,6 @@ $ignore{'"router ripng"'} = "ignore"; $ignore{'"router ospf"'} = "ignore"; $ignore{'"router ospf <0-65535>"'} = "ignore"; $ignore{'"router ospf6"'} = "ignore"; -$ignore{'"router babel"'} = "ignore"; $ignore{'"router bgp " "<1-4294967295>"'} = "ignore"; $ignore{'"router bgp " "<1-4294967295>" " view WORD"'} = "ignore"; $ignore{'"router isis WORD"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index fbbc88d0f..e2d63f9f0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -58,7 +58,6 @@ struct vtysh_client { .fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .path = OSPF6_VTYSH_PATH}, { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH}, { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH}, - { .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH}, { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH}, }; @@ -799,12 +798,6 @@ static struct cmd_node ospf6_node = "%s(config-ospf6)# " }; -static struct cmd_node babel_node = -{ - BABEL_NODE, - "%s(config-babel)# " -}; - static struct cmd_node keychain_node = { KEYCHAIN_NODE, @@ -1017,17 +1010,6 @@ DEFUNSH (VTYSH_OSPF6D, return CMD_SUCCESS; } -DEFUNSH (VTYSH_BABELD, - router_babel, - router_babel_cmd, - "router babel", - ROUTER_STR - "Babel") -{ - vty->node = BABEL_NODE; - return CMD_SUCCESS; -} - DEFUNSH (VTYSH_ISISD, router_isis, router_isis_cmd, @@ -2266,7 +2248,6 @@ vtysh_init_vty (void) install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); /* #endif */ - install_node (&babel_node, NULL); install_node (&keychain_node, NULL); install_node (&keychain_key_node, NULL); install_node (&isis_node, NULL); @@ -2369,7 +2350,6 @@ vtysh_init_vty (void) #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &router_ospf6_cmd); #endif - install_element (CONFIG_NODE, &router_babel_cmd); install_element (CONFIG_NODE, &router_isis_cmd); install_element (CONFIG_NODE, &router_bgp_cmd); install_element (CONFIG_NODE, &router_bgp_view_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 1ddaac05c..94dc995cc 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -198,8 +198,6 @@ vtysh_config_parse_line (const char *line) config = config_get (OSPF_NODE, line); else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0) config = config_get (OSPF6_NODE, line); - else if (strncmp (line, "router babel", strlen ("router babel")) == 0) - config = config_get (BABEL_NODE, line); else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0) config = config_get (BGP_NODE, line); else if (strncmp (line, "router isis", strlen ("router isis")) == 0) From 38f22ab07c8e1f0f12e23c2e2d0a3e1f71bef695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:43:02 +0300 Subject: [PATCH 0701/1342] bgpd: refactor route-map objects modifying integer values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use common code to parse, validate and adjust the route-map objects that contain a simple integer value. This also allows compiling the add/sub format metric object. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- bgpd/bgp_routemap.c | 303 ++++++++++++++++---------------------------- 1 file changed, 111 insertions(+), 192 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 416a3e511..4a0dac766 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -101,6 +101,86 @@ o Local extensions */ + /* generic value manipulation to be shared in multiple rules */ + +#define RMAP_VALUE_SET 0 +#define RMAP_VALUE_ADD 1 +#define RMAP_VALUE_SUB 2 + +struct rmap_value +{ + u_int8_t action; + u_int32_t value; +}; + +static int +route_value_match (struct rmap_value *rv, u_int32_t value) +{ + if (value == rv->value) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +static u_int32_t +route_value_adjust (struct rmap_value *rv, u_int32_t current) +{ + u_int32_t value = rv->value; + + switch (rv->action) + { + case RMAP_VALUE_ADD: + if (current > UINT32_MAX-value) + return UINT32_MAX; + return current + value; + case RMAP_VALUE_SUB: + if (current <= value) + return 0; + return current - value; + default: + return value; + } +} + +static void * +route_value_compile (const char *arg) +{ + u_int8_t action = RMAP_VALUE_SET; + unsigned long larg; + char *endptr = NULL; + struct rmap_value *rv; + + if (arg[0] == '+') + { + action = RMAP_VALUE_ADD; + arg++; + } + else if (arg[0] == '-') + { + action = RMAP_VALUE_SUB; + arg++; + } + + errno = 0; + larg = strtoul (arg, &endptr, 10); + if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX) + return NULL; + + rv = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value)); + if (!rv) + return NULL; + + rv->action = action; + rv->value = larg; + return rv; +} + +static void +route_value_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + /* generic as path object to be shared in multiple rules */ static void * @@ -518,62 +598,25 @@ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *med; + struct rmap_value *rv; struct bgp_info *bgp_info; if (type == RMAP_BGP) { - med = rule; + rv = rule; bgp_info = object; - - if (bgp_info->attr->med == *med) - return RMAP_MATCH; - else - return RMAP_NOMATCH; + return route_value_match(rv, bgp_info->attr->med); } return RMAP_NOMATCH; } -/* Route map `match metric' match statement. `arg' is MED value */ -static void * -route_match_metric_compile (const char *arg) -{ - u_int32_t *med; - char *endptr = NULL; - unsigned long tmpval; - - /* Metric value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - errno = 0; - tmpval = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || tmpval > UINT32_MAX) - return NULL; - - med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - - if (!med) - return med; - - *med = tmpval; - return med; -} - -/* Free route map's compiled `match metric' value. */ -static void -route_match_metric_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_metric_cmd = { "metric", route_match_metric, - route_match_metric_compile, - route_match_metric_free + route_value_compile, + route_value_free, }; /* `match as-path ASPATH' */ @@ -992,64 +1035,34 @@ static route_map_result_t route_set_local_pref (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *local_pref; + struct rmap_value *rv; struct bgp_info *bgp_info; + u_int32_t locpref = 0; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - local_pref = rule; + rv = rule; bgp_info = object; /* Set local preference value. */ + if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + locpref = bgp_info->attr->local_pref; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); - bgp_info->attr->local_pref = *local_pref; + bgp_info->attr->local_pref = route_value_adjust(rv, locpref); } return RMAP_OKAY; } -/* set local preference compilation. */ -static void * -route_set_local_pref_compile (const char *arg) -{ - unsigned long tmp; - u_int32_t *local_pref; - char *endptr = NULL; - - /* Local preference value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - errno = 0; - tmp = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || tmp > UINT32_MAX) - return NULL; - - local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - - if (!local_pref) - return local_pref; - - *local_pref = tmp; - - return local_pref; -} - -/* Free route map's local preference value. */ -static void -route_set_local_pref_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_local_pref_cmd = { "local-preference", route_set_local_pref, - route_set_local_pref_compile, - route_set_local_pref_free, + route_value_compile, + route_value_free, }; /* `set weight WEIGHT' */ @@ -1059,18 +1072,20 @@ static route_map_result_t route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *weight; + struct rmap_value *rv; struct bgp_info *bgp_info; + u_int32_t weight; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - weight = rule; + rv = rule; bgp_info = object; /* Set weight value. */ - if (*weight) - (bgp_attr_extra_get (bgp_info->attr))->weight = *weight; + weight = route_value_adjust(rv, 0); + if (weight) + (bgp_attr_extra_get (bgp_info->attr))->weight = weight; else if (bgp_info->attr->extra) bgp_info->attr->extra->weight = 0; } @@ -1078,47 +1093,13 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, return RMAP_OKAY; } -/* set local preference compilation. */ -static void * -route_set_weight_compile (const char *arg) -{ - unsigned long tmp; - u_int32_t *weight; - char *endptr = NULL; - - /* Local preference value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - errno = 0; - tmp = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || tmp > UINT32_MAX) - return NULL; - - weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - - if (weight == NULL) - return weight; - - *weight = tmp; - - return weight; -} - -/* Free route map's local preference value. */ -static void -route_set_weight_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_weight_cmd = { "weight", route_set_weight, - route_set_weight_compile, - route_set_weight_free, + route_value_compile, + route_value_free, }; /* `set metric METRIC' */ @@ -1128,94 +1109,32 @@ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - char *metric; - u_int32_t metric_val; + struct rmap_value *rv; struct bgp_info *bgp_info; + u_int32_t med = 0; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - metric = rule; + rv = rule; bgp_info = object; - if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) - bgp_info->attr->med = 0; - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + med = bgp_info->attr->med; - if (all_digit (metric)) - { - metric_val = strtoul (metric, (char **)NULL, 10); - bgp_info->attr->med = metric_val; - } - else - { - metric_val = strtoul (metric+1, (char **)NULL, 10); - - if (strncmp (metric, "+", 1) == 0) - { - if (bgp_info->attr->med/2 + metric_val/2 > BGP_MED_MAX/2) - bgp_info->attr->med = BGP_MED_MAX - 1; - else - bgp_info->attr->med += metric_val; - } - else if (strncmp (metric, "-", 1) == 0) - { - if (bgp_info->attr->med <= metric_val) - bgp_info->attr->med = 0; - else - bgp_info->attr->med -= metric_val; - } - } + bgp_info->attr->med = route_value_adjust(rv, med); + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); } return RMAP_OKAY; } -/* set metric compilation. */ -static void * -route_set_metric_compile (const char *arg) -{ - unsigned long larg; - char *endptr = NULL; - - if (all_digit (arg)) - { - /* set metric value check*/ - errno = 0; - larg = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || larg > UINT32_MAX) - return NULL; - } - else - { - /* set metric +/-value check */ - if ((strncmp (arg, "+", 1) != 0 - && strncmp (arg, "-", 1) != 0) - || (! all_digit (arg+1))) - return NULL; - - errno = 0; - larg = strtoul (arg+1, &endptr, 10); - if (*endptr != '\0' || errno || larg > UINT32_MAX) - return NULL; - } - - return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); -} - -/* Free route map's compiled `set metric' value. */ -static void -route_set_metric_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Set metric rule structure. */ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, - route_set_metric_compile, - route_set_metric_free, + route_value_compile, + route_value_free, }; /* `set as-path prepend ASPATH' */ From 6b2672f3c9493aef3495192e113f95a7db4b65bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:43:03 +0300 Subject: [PATCH 0702/1342] sockopt: add support for querying tcp round-trip-time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/sockopt.c | 16 ++++++++++++++++ lib/sockopt.h | 1 + 2 files changed, 17 insertions(+) diff --git a/lib/sockopt.c b/lib/sockopt.c index be22827f6..257271bc0 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -518,6 +518,22 @@ sockopt_iphdrincl_swab_systoh (struct ip *iph) iph->ip_id = ntohs(iph->ip_id); } +int +sockopt_tcp_rtt (int sock) +{ +#ifdef TCP_INFO + struct tcp_info ti; + socklen_t len = sizeof(ti); + + if (getsockopt (sock, IPPROTO_TCP, TCP_INFO, &ti, &len) != 0) + return 0; + + return ti.tcpi_rtt / 1000; +#else + return 0; +#endif +} + int sockopt_tcp_signature (int sock, union sockunion *su, const char *password) { diff --git a/lib/sockopt.h b/lib/sockopt.h index aced6d489..cb14efc7b 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -100,6 +100,7 @@ extern int getsockopt_ifindex (int, struct msghdr *); extern void sockopt_iphdrincl_swab_htosys (struct ip *iph); extern void sockopt_iphdrincl_swab_systoh (struct ip *iph); +extern int sockopt_tcp_rtt (int); extern int sockopt_tcp_signature(int sock, union sockunion *su, const char *password); #endif /*_ZEBRA_SOCKOPT_H */ From ef757700d0fd51dc0b46df9d3631208919f9b779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:43:04 +0300 Subject: [PATCH 0703/1342] bgpd: allow using rtt in route-map's set metric MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful when the BGP neighbors are over tunnels that have large differences in geographic distances and RTTs. Especially useful for DMVPN setups to allow preferring closes hub. The parameter is added as new alias command as otherwise it seems the command parser is not able to match it properly (it seems merging is done for the various 'set metric' route-map objects in different routing engines). For same reason also they are listed as three separate options: optional +/- seems not possibly easily. Related research papers: http://www.pps.univ-paris-diderot.fr/~jch/research/delay-based.pdf http://arxiv.org/pdf/1309.0632.pdf Paper on similar extension to Babel: http://www.pps.univ-paris-diderot.fr/~jch/research/rapport-jonglez-2013.pdf Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- bgpd/bgp_packet.c | 2 ++ bgpd/bgp_routemap.c | 56 +++++++++++++++++++++++++++++++++++---------- bgpd/bgp_vty.c | 5 ++++ bgpd/bgpd.h | 1 + 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 18114ad5e..7d27972e2 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "memory.h" #include "sockunion.h" /* for inet_ntop () */ +#include "sockopt.h" #include "linklist.h" #include "plist.h" @@ -2592,6 +2593,7 @@ bgp_read (struct thread *thread) { case BGP_MSG_OPEN: peer->open_in++; + peer->rtt = sockopt_tcp_rtt(peer->fd); bgp_open_receive (peer, size); /* XXX return value ignored! */ break; case BGP_MSG_UPDATE: diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 4a0dac766..5467cfdc4 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -110,22 +110,33 @@ o Local extensions struct rmap_value { u_int8_t action; + u_int8_t variable; u_int32_t value; }; static int route_value_match (struct rmap_value *rv, u_int32_t value) { - if (value == rv->value) + if (rv->variable == 0 && value == rv->value) return RMAP_MATCH; return RMAP_NOMATCH; } static u_int32_t -route_value_adjust (struct rmap_value *rv, u_int32_t current) +route_value_adjust (struct rmap_value *rv, u_int32_t current, struct peer *peer) { - u_int32_t value = rv->value; + u_int32_t value; + + switch (rv->variable) + { + case 1: + value = peer->rtt; + break; + default: + value = rv->value; + break; + } switch (rv->action) { @@ -145,8 +156,8 @@ route_value_adjust (struct rmap_value *rv, u_int32_t current) static void * route_value_compile (const char *arg) { - u_int8_t action = RMAP_VALUE_SET; - unsigned long larg; + u_int8_t action = RMAP_VALUE_SET, var = 0; + unsigned long larg = 0; char *endptr = NULL; struct rmap_value *rv; @@ -161,16 +172,27 @@ route_value_compile (const char *arg) arg++; } - errno = 0; - larg = strtoul (arg, &endptr, 10); - if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX) - return NULL; + if (all_digit(arg)) + { + errno = 0; + larg = strtoul (arg, &endptr, 10); + if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX) + return NULL; + } + else + { + if (strcmp(arg, "rtt") == 0) + var = 1; + else + return NULL; + } rv = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value)); if (!rv) return NULL; rv->action = action; + rv->variable = var; rv->value = larg; return rv; } @@ -1050,7 +1072,7 @@ route_set_local_pref (void *rule, struct prefix *prefix, locpref = bgp_info->attr->local_pref; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); - bgp_info->attr->local_pref = route_value_adjust(rv, locpref); + bgp_info->attr->local_pref = route_value_adjust(rv, locpref, bgp_info->peer); } return RMAP_OKAY; @@ -1083,7 +1105,7 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, bgp_info = object; /* Set weight value. */ - weight = route_value_adjust(rv, 0); + weight = route_value_adjust(rv, 0, bgp_info->peer); if (weight) (bgp_attr_extra_get (bgp_info->attr))->weight = weight; else if (bgp_info->attr->extra) @@ -1122,7 +1144,7 @@ route_set_metric (void *rule, struct prefix *prefix, if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) med = bgp_info->attr->med; - bgp_info->attr->med = route_value_adjust(rv, med); + bgp_info->attr->med = route_value_adjust(rv, med, bgp_info->peer); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); } return RMAP_OKAY; @@ -2974,6 +2996,15 @@ ALIAS (set_metric, "Metric value for destination routing protocol\n" "Add or subtract metric\n") +ALIAS (set_metric, + set_metric_rtt_cmd, + "set metric (rtt|+rtt|-rtt)", + SET_STR + "Metric value for destination routing protocol\n" + "Assign round trip time\n" + "Add round trip time\n" + "Subtract round trip time\n") + DEFUN (no_set_metric, no_set_metric_cmd, "no set metric", @@ -3937,6 +3968,7 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_weight_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &set_metric_addsub_cmd); + install_element (RMAP_NODE, &set_metric_rtt_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_aspath_prepend_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 00d766d61..62331635a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7906,6 +7906,11 @@ bgp_show_peer (struct vty *vty, struct peer *p) #endif /* HAVE_IPV6 */ } + /* TCP metrics. */ + if (p->status == Established && p->rtt) + vty_out (vty, "Estimated round trip time: %d ms%s", + p->rtt, VTY_NEWLINE); + /* Timer information. */ if (p->t_start) vty_out (vty, "Next start timer due in %ld seconds%s", diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 40c381c24..58d1ecafb 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -331,6 +331,7 @@ struct peer /* Peer information */ int fd; /* File descriptor */ int ttl; /* TTL of TCP connection to the peer. */ + int rtt; /* Estimated round-trip-time from TCP_INFO */ int gtsm_hops; /* minimum hopcount to peer */ char *desc; /* Description of the peer. */ unsigned short port; /* Destination port for peer */ From 9196caf16e30e938f4bc3c05d96f55195af7caff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 29 Apr 2015 09:43:05 +0300 Subject: [PATCH 0704/1342] sockunion: add hash function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/sockunion.c | 16 ++++++++++++++++ lib/sockunion.h | 1 + 2 files changed, 17 insertions(+) diff --git a/lib/sockunion.c b/lib/sockunion.c index 5e6cf6860..c7315f28b 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -27,6 +27,7 @@ #include "memory.h" #include "str.h" #include "log.h" +#include "jhash.h" #ifndef HAVE_INET_ATON int @@ -573,6 +574,21 @@ sockunion_same (const union sockunion *su1, const union sockunion *su2) return 0; } +unsigned int +sockunion_hash (const union sockunion *su) +{ + switch (sockunion_family(su)) + { + case AF_INET: + return jhash_1word(su->sin.sin_addr.s_addr, 0); +#ifdef HAVE_IPV6 + case AF_INET6: + return jhash2(su->sin6.sin6_addr.s6_addr32, ZEBRA_NUM_OF(su->sin6.sin6_addr.s6_addr32), 0); +#endif /* HAVE_IPV6 */ + } + return 0; +} + /* After TCP connection is established. Get local address and port. */ union sockunion * sockunion_getsockname (int fd) diff --git a/lib/sockunion.h b/lib/sockunion.h index 2c79fb5c6..ea3b833c8 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -87,6 +87,7 @@ extern int str2sockunion (const char *, union sockunion *); extern const char *sockunion2str (const union sockunion *, char *, size_t); extern int sockunion_cmp (const union sockunion *, const union sockunion *); extern int sockunion_same (const union sockunion *, const union sockunion *); +extern unsigned int sockunion_hash (const union sockunion *); extern union sockunion *sockunion_str2su (const char *str); extern int sockunion_accept (int sock, union sockunion *); From ec38711852abdcaa0e7001e6a1e957052a0e723d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 20 May 2015 22:34:56 +0200 Subject: [PATCH 0705/1342] lib: fix "sockunion: add hash function" for BSD (9196caf) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sockunion_hash() function uses s6_addr32, which is not defined on BSD systems. (It only works on glibc because we set _GNU_SOURCE) ripngd/ripng_nexthop.h already contains a workaround for this. Bump workaround to prefix.h so it's available everywhere. Reported-by: NetDEF CI System Fixes: 9196caf ("sockunion: add hash function") Cc: Timo Teräs Signed-off-by: David Lamparter --- lib/prefix.h | 10 ++++++++++ ripngd/ripng_nexthop.h | 13 ++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/prefix.h b/lib/prefix.h index 45889e086..a1a0679c9 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -156,6 +156,16 @@ union prefix46constptr /* Prefix's family member. */ #define PREFIX_FAMILY(p) ((p)->family) +/* glibc defines s6_addr32 to __in6_u.__u6_addr32 if __USE_{MISC || GNU} */ +#ifndef s6_addr32 +#if defined(SUNOS_5) +/* Some SunOS define s6_addr32 only to kernel */ +#define s6_addr32 _S6_un._S6_u32 +#else +#define s6_addr32 __u6_addr.__u6_addr32 +#endif /* SUNOS_5 */ +#endif /*s6_addr32*/ + /* Prototypes. */ extern int afi2family (afi_t); extern afi_t family2afi (int); diff --git a/ripngd/ripng_nexthop.h b/ripngd/ripng_nexthop.h index 7c0410592..19bd32b50 100644 --- a/ripngd/ripng_nexthop.h +++ b/ripngd/ripng_nexthop.h @@ -41,17 +41,8 @@ extern void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, * -1 if A < B **/ static inline int -addr6_cmp(struct in6_addr *A, struct in6_addr *B) { - -#ifndef s6_addr32 -#if defined(SUNOS_5) -/* Some SunOS define s6_addr32 only to kernel */ -#define s6_addr32 _S6_un._S6_u32 -#else -#define s6_addr32 __u6_addr.__u6_addr32 -#endif /* SUNOS_5 */ -#endif /*s6_addr32*/ - +addr6_cmp(struct in6_addr *A, struct in6_addr *B) +{ #define a(i) A->s6_addr32[i] #define b(i) B->s6_addr32[i] From ee53c8b9f7979c79beada960746ca35046016a45 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 23 May 2015 05:45:59 +0200 Subject: [PATCH 0706/1342] vtysh: fix the fix for babeld removal... (5460bae) Commit 5460bae ("*: fix 'babeld: Remove babeld from Quagga' (336724d)") unfortunately removed the BABEL_NODE from vtysh, which now no longer starts. Fix by restoring the node (even though it won't be accessible). Reported-by: Nicolas Dichtel Fixes: 5460bae ("*: fix 'babeld: Remove babeld from Quagga' (336724d)") Signed-off-by: David Lamparter --- vtysh/vtysh.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index e2d63f9f0..b33ac90bd 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -798,6 +798,12 @@ static struct cmd_node ospf6_node = "%s(config-ospf6)# " }; +static struct cmd_node babel_node = +{ + BABEL_NODE, + "%s(config-babel)# " +}; + static struct cmd_node keychain_node = { KEYCHAIN_NODE, @@ -2248,6 +2254,7 @@ vtysh_init_vty (void) install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); /* #endif */ + install_node (&babel_node, NULL); install_node (&keychain_node, NULL); install_node (&keychain_key_node, NULL); install_node (&isis_node, NULL); From 4715a53b4d390e72a06c864a6a505971841e3dc9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 30 May 2013 16:31:49 +0200 Subject: [PATCH 0707/1342] lib/vty: add separate output fd support to VTYs to be used with stdin/stdout terminals, this adds support for writing to a different FD than we're reading from. Also fixes error messages from config load being written to stdin. [v2: fixed config write] Signed-off-by: David Lamparter --- lib/command.c | 2 +- lib/vty.c | 27 +++++++++++++++------------ lib/vty.h | 3 +++ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/command.c b/lib/command.c index 8ae27de92..3a59f2449 100644 --- a/lib/command.c +++ b/lib/command.c @@ -3065,7 +3065,7 @@ DEFUN (config_write_file, /* Make vty for configuration file. */ file_vty = vty_new (); - file_vty->fd = fd; + file_vty->wfd = fd; file_vty->type = VTY_FILE; /* Config file header print. */ diff --git a/lib/vty.c b/lib/vty.c index d623b8533..4b4458923 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -184,7 +184,7 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str, buf[len++] = '\r'; buf[len++] = '\n'; - if (write(vty->fd, buf, len) < 0) + if (write(vty->wfd, buf, len) < 0) { if (ERRNO_IO_RETRY(errno)) /* Kernel buffer is full, probably too much debugging output, so just @@ -1542,7 +1542,7 @@ vty_read (struct thread *thread) vty_close (vty); else { - vty_event (VTY_WRITE, vty_sock, vty); + vty_event (VTY_WRITE, vty->wfd, vty); vty_event (VTY_READ, vty_sock, vty); } return 0; @@ -1571,12 +1571,12 @@ vty_flush (struct thread *thread) /* N.B. if width is 0, that means we don't know the window size. */ if ((vty->lines == 0) || (vty->width == 0)) - flushrc = buffer_flush_available(vty->obuf, vty->fd); + flushrc = buffer_flush_available(vty->obuf, vty_sock); else if (vty->status == VTY_MORELINE) - flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width, + flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, 1, erase, 0); else - flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width, + flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, vty->lines >= 0 ? vty->lines : vty->height, erase, 0); @@ -1622,6 +1622,7 @@ vty_create (int vty_sock, union sockunion *su) /* Allocate new vty structure and set up default values. */ vty = vty_new (); vty->fd = vty_sock; + vty->wfd = vty_sock; vty->type = VTY_TERM; strcpy (vty->address, buf); if (no_password_check) @@ -2022,6 +2023,7 @@ vtysh_accept (struct thread *thread) vty = vty_new (); vty->fd = sock; + vty->wfd = sock; vty->type = VTY_SHELL_SERV; vty->node = VIEW_NODE; @@ -2033,10 +2035,10 @@ vtysh_accept (struct thread *thread) static int vtysh_flush(struct vty *vty) { - switch (buffer_flush_available(vty->obuf, vty->fd)) + switch (buffer_flush_available(vty->obuf, vty->wfd)) { case BUFFER_PENDING: - vty_event(VTYSH_WRITE, vty->fd, vty); + vty_event(VTYSH_WRITE, vty->wfd, vty); break; case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ @@ -2172,7 +2174,7 @@ vty_close (struct vty *vty) thread_cancel (vty->t_timeout); /* Flush buffer. */ - buffer_flush_all (vty->obuf, vty->fd); + buffer_flush_all (vty->obuf, vty->wfd); /* Free input buffer. */ buffer_free (vty->obuf); @@ -2229,12 +2231,13 @@ vty_read_file (FILE *confp) unsigned int line_num = 0; vty = vty_new (); - vty->fd = dup(STDERR_FILENO); /* vty_close() will close this */ - if (vty->fd < 0) + vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */ + if (vty->wfd < 0) { /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */ - vty->fd = STDOUT_FILENO; + vty->wfd = STDOUT_FILENO; } + vty->fd = STDIN_FILENO; vty->type = VTY_FILE; vty->node = CONFIG_NODE; @@ -2475,7 +2478,7 @@ vty_log_fixed (char *buf, size_t len) if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor) /* N.B. We don't care about the return code, since process is most likely just about to die anyway. */ - writev(vty->fd, iov, 2); + writev(vty->wfd, iov, 2); } } diff --git a/lib/vty.h b/lib/vty.h index f31f4b5d6..b758df3e1 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -34,6 +34,9 @@ struct vty /* File descripter of this vty. */ int fd; + /* output FD, to support stdin/stdout combination */ + int wfd; + /* Is this vty connect to file or not */ enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type; From ba5dc5ebb4dba56cb3a64acc21e71aa34df375d9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 30 May 2013 16:33:45 +0200 Subject: [PATCH 0708/1342] lib/vty: add vty_stdio() this introduces a new public/API function to the vty code for opening a VTY on stdin/stdout. Intended for unrestricted use by the individual daemons, i.e. "offical API". Signed-off-by: David Lamparter --- lib/vty.c | 77 ++++++++++++++++++++++++++++++++++++++++--------------- lib/vty.h | 1 + 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 4b4458923..24df32c42 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1610,6 +1610,34 @@ vty_flush (struct thread *thread) return 0; } +/* allocate and initialise vty */ +static struct vty * +vty_new_init (int vty_sock) +{ + struct vty *vty; + + vty = vty_new (); + vty->fd = vty_sock; + vty->wfd = vty_sock; + vty->type = VTY_TERM; + vty->node = AUTH_NODE; + vty->fail = 0; + vty->cp = 0; + vty_clear_buf (vty); + vty->length = 0; + memset (vty->hist, 0, sizeof (vty->hist)); + vty->hp = 0; + vty->hindex = 0; + vector_set_index (vtyvec, vty_sock, vty); + vty->status = VTY_NORMAL; + vty->lines = -1; + vty->iac = 0; + vty->iac_sb_in_progress = 0; + vty->sb_len = 0; + + return vty; +} + /* Create new vty structure. */ static struct vty * vty_create (int vty_sock, union sockunion *su) @@ -1620,10 +1648,10 @@ vty_create (int vty_sock, union sockunion *su) sockunion2str(su, buf, SU_ADDRSTRLEN); /* Allocate new vty structure and set up default values. */ - vty = vty_new (); - vty->fd = vty_sock; - vty->wfd = vty_sock; - vty->type = VTY_TERM; + vty = vty_new_init (vty_sock); + + /* configurable parameters not part of basic init */ + vty->v_timeout = vty_timeout_val; strcpy (vty->address, buf); if (no_password_check) { @@ -1634,25 +1662,8 @@ vty_create (int vty_sock, union sockunion *su) else vty->node = VIEW_NODE; } - else - vty->node = AUTH_NODE; - vty->fail = 0; - vty->cp = 0; - vty_clear_buf (vty); - vty->length = 0; - memset (vty->hist, 0, sizeof (vty->hist)); - vty->hp = 0; - vty->hindex = 0; - vector_set_index (vtyvec, vty_sock, vty); - vty->status = VTY_NORMAL; - vty->v_timeout = vty_timeout_val; if (host.lines >= 0) vty->lines = host.lines; - else - vty->lines = -1; - vty->iac = 0; - vty->iac_sb_in_progress = 0; - vty->sb_len = 0; if (! no_password_check) { @@ -1688,6 +1699,30 @@ vty_create (int vty_sock, union sockunion *su) return vty; } +/* create vty for stdio */ +struct vty * +vty_stdio (void) +{ + struct vty *vty; + + vty = vty_new_init (0); + vty->wfd = 1; + + /* always have stdio vty in a known _unchangeable_ state, don't want config + * to have any effect here to make sure scripting this works as intended */ + vty->node = ENABLE_NODE; + vty->v_timeout = 0; + strcpy (vty->address, "console"); + + vty_prompt (vty); + + /* Add read/write thread. */ + vty_event (VTY_WRITE, 1, vty); + vty_event (VTY_READ, 0, vty); + + return vty; +} + /* Accept connection from the network. */ static int vty_accept (struct thread *thread) diff --git a/lib/vty.h b/lib/vty.h index b758df3e1..abac3ddf1 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -237,6 +237,7 @@ extern void vty_init_vtysh (void); extern void vty_terminate (void); extern void vty_reset (void); extern struct vty *vty_new (void); +extern struct vty *vty_stdio (void); extern int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_read_config (char *, char *); extern void vty_time_print (struct vty *, int); From ba53a8fdecef07577dcc4109e5c82bb124d49c58 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 5 May 2015 11:04:46 +0200 Subject: [PATCH 0709/1342] lib/vty: put stdin in raw mode for vty The interactive CLI actually works just fine, if we just put the terminal in raw mode to get keystrokes as they come. Signed-off-by: David Lamparter --- lib/vty.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/vty.c b/lib/vty.c index 24df32c42..a3f1a3c4c 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -38,6 +38,7 @@ #include "network.h" #include +#include /* Vty events */ enum event @@ -1700,12 +1701,30 @@ vty_create (int vty_sock, union sockunion *su) } /* create vty for stdio */ +static struct termios stdio_orig_termios; +static struct vty *stdio_vty = NULL; + +static void +vty_stdio_reset (void) +{ + if (stdio_vty) + { + tcsetattr (0, TCSANOW, &stdio_orig_termios); + stdio_vty = NULL; + } +} + struct vty * vty_stdio (void) { struct vty *vty; + struct termios termios; - vty = vty_new_init (0); + /* refuse creating two vtys on stdio */ + if (stdio_vty) + return NULL; + + vty = stdio_vty = vty_new_init (0); vty->wfd = 1; /* always have stdio vty in a known _unchangeable_ state, don't want config @@ -1714,6 +1733,18 @@ vty_stdio (void) vty->v_timeout = 0; strcpy (vty->address, "console"); + if (!tcgetattr (0, &stdio_orig_termios)) + { + termios = stdio_orig_termios; + termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + termios.c_oflag &= ~OPOST; + termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CS8; + tcsetattr (0, TCSANOW, &termios); + } + vty_prompt (vty); /* Add read/write thread. */ @@ -2225,6 +2256,8 @@ vty_close (struct vty *vty) /* Close socket. */ if (vty->fd > 0) close (vty->fd); + else + vty_stdio_reset (); if (vty->buf) XFREE (MTYPE_VTY, vty->buf); @@ -3004,6 +3037,8 @@ vty_init (struct thread_master *master_thread) master = master_thread; + atexit (vty_stdio_reset); + /* Initilize server thread vector. */ Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); From 464ccf36b4aa1b942cad413ea30267b4bf9e6315 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 12 May 2015 21:56:18 +0200 Subject: [PATCH 0710/1342] lib/vty: add vty_stdio at-close hook This is intended to be used for either "exit on close", "fork on close" or "reopen vty on close" functionality for the stdio vty. Which of these options to take depends on the context, the use case right now is test programs exiting on EOF. Signed-off-by: David Lamparter --- lib/vty.c | 8 +++++++- lib/vty.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index a3f1a3c4c..3477f638c 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1703,6 +1703,7 @@ vty_create (int vty_sock, union sockunion *su) /* create vty for stdio */ static struct termios stdio_orig_termios; static struct vty *stdio_vty = NULL; +static void (*stdio_vty_atclose)(void); static void vty_stdio_reset (void) @@ -1711,11 +1712,15 @@ vty_stdio_reset (void) { tcsetattr (0, TCSANOW, &stdio_orig_termios); stdio_vty = NULL; + + if (stdio_vty_atclose) + stdio_vty_atclose (); + stdio_vty_atclose = NULL; } } struct vty * -vty_stdio (void) +vty_stdio (void (*atclose)()) { struct vty *vty; struct termios termios; @@ -1725,6 +1730,7 @@ vty_stdio (void) return NULL; vty = stdio_vty = vty_new_init (0); + stdio_vty_atclose = atclose; vty->wfd = 1; /* always have stdio vty in a known _unchangeable_ state, don't want config diff --git a/lib/vty.h b/lib/vty.h index abac3ddf1..806f2c603 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -237,7 +237,7 @@ extern void vty_init_vtysh (void); extern void vty_terminate (void); extern void vty_reset (void); extern struct vty *vty_new (void); -extern struct vty *vty_stdio (void); +extern struct vty *vty_stdio (void (*atclose)(void)); extern int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_read_config (char *, char *); extern void vty_time_print (struct vty *, int); From 90d313578f035110422799ca2e188d745ceb3733 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 14 May 2015 14:24:06 +0200 Subject: [PATCH 0711/1342] lib/vty: don't clear output buffer on input EOF A VTY's input can be closed without the output becoming unavailable. This happens both on stdio when stdin ends, as well as over TCP when an unidirectional input shutdown() happens. In such a case, resetting the output buffer is not appropriate since there might still be data to be successfully written. Signed-off-by: David Lamparter --- lib/vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vty.c b/lib/vty.c index 3477f638c..d0028580f 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1364,8 +1364,8 @@ vty_read (struct thread *thread) vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ zlog_warn("%s: read error on vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); + buffer_reset(vty->obuf); } - buffer_reset(vty->obuf); vty->status = VTY_CLOSE; } From 19ed526eab33728723e25f2727f60f41d3533503 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 20 May 2015 19:06:12 +0200 Subject: [PATCH 0712/1342] isisd: always print adj->sysid (clang 3.6 warning) As any new compiler version, clang 3.6 has new warnings, one of these being that it now warns for testing whether the address of an array will be true. Of course there is no point in this check for the sysid, so let's always just print the sysid. Signed-off-by: David Lamparter --- isisd/isis_adjacency.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index a3524362e..a485575be 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -377,14 +377,8 @@ isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail) dyn = dynhn_find_by_id (adj->sysid); if (dyn) vty_out (vty, " %-20s", dyn->name.name); - else if (adj->sysid) - { - vty_out (vty, " %-20s", sysid_print (adj->sysid)); - } else - { - vty_out (vty, " unknown "); - } + vty_out (vty, " %-20s", sysid_print (adj->sysid)); if (detail == ISIS_UI_LEVEL_BRIEF) { From 3065777ece6d14c6acd04f8b2b693a15c9f2f37c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 13 May 2015 13:59:17 +0200 Subject: [PATCH 0713/1342] lib/privs: display more info if cap_set_proc fails. Signed-off-by: David Lamparter --- lib/privs.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/privs.c b/lib/privs.c index f7269f4ac..3355f24a7 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -299,7 +299,21 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) */ if ( cap_set_proc (zprivs_state.caps) ) { - fprintf (stderr, "privs_init: initial cap_set_proc failed\n"); + cap_t current_caps; + char *current_caps_text = NULL; + char *wanted_caps_text = NULL; + + fprintf(stderr, "privs_init: initial cap_set_proc failed: %s\n", + safe_strerror(errno)); + + current_caps = cap_get_proc(); + if (current_caps) + current_caps_text = cap_to_text(current_caps, NULL); + + wanted_caps_text = cap_to_text(zprivs_state.caps, NULL); + fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???"); + fprintf(stderr, "Have caps: %s\n", current_caps_text ? current_caps_text : "???"); + exit (1); } From a5d589dfbf2c563868d944376155cd4a5998722f Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 13 May 2015 13:59:18 +0200 Subject: [PATCH 0714/1342] lib/privs: Don't use CAP_NET_BROADCAST From what I can tell, CAP_NET_BROADCAST has never been required for any functionality in the Linux kernel, so we do not really need it. However, it causes breakage in contexts where Quagga is started with a limited set of capabilities, e.g. in Docker, because these may not include CAP_NET_BROADCAST and in the case of Docker do not even support adding CAP_NET_BROADCAST. Signed-off-by: David Lamparter --- lib/privs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/privs.c b/lib/privs.c index 3355f24a7..8cfd8dfd5 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -102,8 +102,7 @@ static struct #ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */ [ZCAP_SETID] = { 2, (pvalue_t []) { CAP_SETGID, CAP_SETUID }, }, - [ZCAP_BIND] = { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE, - CAP_NET_BROADCAST }, }, + [ZCAP_BIND] = { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE }, }, [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { CAP_NET_ADMIN }, }, [ZCAP_NET_RAW] = { 1, (pvalue_t []) { CAP_NET_RAW }, }, [ZCAP_CHROOT] = { 1, (pvalue_t []) { CAP_SYS_CHROOT, }, }, From 54b88cac24f335414caa875b390d2d78ff4bf9e0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 13 May 2015 20:34:46 -0400 Subject: [PATCH 0715/1342] lib: wrong #define used for IPV6_MINHOPCOUNT The #define IPV6_MINHOPCNT define is never defined on any unix platform. >From what I can tell the original implementation on the linux platform was IPV6_MINHOPCNT, when it got accepted into the mainstream kernel it was transformed into IPV6_MINHOPCOUNT. Since we test for the define before attempting to use the code it was silently doing nothing for a long time. Signed-off-by: David Lamparter --- configure.ac | 5 ++++- lib/sockunion.c | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index f68d86fc4..27014c3c8 100755 --- a/configure.ac +++ b/configure.ac @@ -1072,7 +1072,7 @@ dnl ------------------ dnl IPv6 header checks dnl ------------------ AC_CHECK_HEADERS([netinet6/in6.h netinet/in6_var.h netinet/icmp6.h \ - netinet6/in6_var.h netinet6/nd6.h], [], [], + netinet6/in6_var.h netinet6/nd6.h linux/in6.h], [], [], QUAGGA_INCLUDES) m4_define([QUAGGA_INCLUDES],dnl @@ -1092,6 +1092,9 @@ QUAGGA_INCLUDES #if HAVE_NETINET6_ND6_H # include #endif +#if HAVE_LINUX_IN6_H +# include +#endif ])dnl dnl disable doc check diff --git a/lib/sockunion.c b/lib/sockunion.c index c7315f28b..8f3540d3f 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -29,6 +29,10 @@ #include "log.h" #include "jhash.h" +#if defined(HAVE_LINUX_IN6_H) +#include +#endif + #ifndef HAVE_INET_ATON int inet_aton (const char *cp, struct in_addr *inaddr) @@ -506,13 +510,13 @@ sockopt_minttl (int family, int sock, int minttl) return ret; } #endif /* IP_MINTTL */ -#ifdef IPV6_MINHOPCNT +#ifdef IPV6_MINHOPCOUNT if (family == AF_INET6) { - int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl)); + int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &minttl, sizeof(minttl)); if (ret < 0) zlog (NULL, LOG_WARNING, - "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s", + "can't set sockopt IPV6_MINHOPCOUNT to %d on socket %d: %s", minttl, sock, safe_strerror (errno)); return ret; } From e97c31aafc013b8b9a0e61cb79ee97a5f1e419bf Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:53 +0200 Subject: [PATCH 0716/1342] ripngd: add ECMP support * Each node in the routing table is changed into a list, holding the multiple equal-cost paths. * If one of the multiple entries gets less-preferred (greater metric or greater distance), it will be directly deleted instead of starting a garbage-collection timer for it. The garbage-collection timer is started only when the last entry in the list gets INFINITY. * Some new functions are used to maintain the ECMP list. And hence ripng_route_process(), ripng_redistribute_add() and ripng_timeout() are significantly simplified. * ripng_zebra_ipv6_add() and ripng_zebra_ipv6_delete() now can share the common code. The common part is moved to ripng_zebra_ipv6_send(). Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent Jardin Signed-off-by: David Lamparter --- ripngd/ripng_interface.c | 37 +-- ripngd/ripng_route.c | 45 ++- ripngd/ripng_route.h | 3 + ripngd/ripng_zebra.c | 89 ++++-- ripngd/ripngd.c | 622 ++++++++++++++++++++++----------------- ripngd/ripngd.h | 12 +- 6 files changed, 459 insertions(+), 349 deletions(-) diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 8717bfb0e..358846346 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -163,38 +163,15 @@ ripng_if_down (struct interface *ifp) struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; + struct list *list = NULL; + struct listnode *listnode = NULL, *nextnode = NULL; if (ripng) - { - for (rp = route_top (ripng->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) - { - /* Routes got through this interface. */ - if (rinfo->ifindex == ifp->ifindex - && rinfo->type == ZEBRA_ROUTE_RIPNG - && rinfo->sub_type == RIPNG_ROUTE_RTE) - { - ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, - &rinfo->nexthop, - rinfo->ifindex); - - ripng_redistribute_delete (rinfo->type, rinfo->sub_type, - (struct prefix_ipv6 *)&rp->p, - rinfo->ifindex); - } - else - { - /* All redistributed routes got through this interface, - * but the static and system ones are kept. */ - if ((rinfo->ifindex == ifp->ifindex) && - (rinfo->type != ZEBRA_ROUTE_STATIC) && - (rinfo->type != ZEBRA_ROUTE_SYSTEM)) - ripng_redistribute_delete (rinfo->type, rinfo->sub_type, - (struct prefix_ipv6 *) &rp->p, - rinfo->ifindex); - } - } - } + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo)) + if (rinfo->ifindex == ifp->ifindex) + ripng_ecmp_delete (rinfo); ri = ifp->info; diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c index d4bf0262b..f26302e88 100644 --- a/ripngd/ripng_route.c +++ b/ripngd/ripng_route.c @@ -40,7 +40,7 @@ ripng_aggregate_new () return new; } -static void +void ripng_aggregate_free (struct ripng_aggregate *aggregate) { XFREE (MTYPE_RIPNG_AGGREGATE, aggregate); @@ -76,6 +76,23 @@ ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo) } } +/* Aggregate count decrement check for a list. */ +void +ripng_aggregate_decrement_list (struct route_node *child, struct list *list) +{ + struct route_node *np; + struct ripng_aggregate *aggregate; + struct ripng_info *rinfo = NULL; + struct listnode *node = NULL; + + for (np = child; np; np = np->parent) + if ((aggregate = np->aggregate) != NULL) + aggregate->count -= listcount (list); + + for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) + rinfo->suppress--; +} + /* RIPng routes treatment. */ int ripng_aggregate_add (struct prefix *p) @@ -85,6 +102,8 @@ ripng_aggregate_add (struct prefix *p) struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct ripng_aggregate *sub; + struct list *list = NULL; + struct listnode *node = NULL; /* Get top node for aggregation. */ top = route_node_get (ripng->table, p); @@ -99,11 +118,12 @@ ripng_aggregate_add (struct prefix *p) for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) { /* Suppress normal route. */ - if ((rinfo = rp->info) != NULL) - { - aggregate->count++; - rinfo->suppress++; - } + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) + { + aggregate->count++; + rinfo->suppress++; + } /* Suppress aggregate route. This may not need. */ if (rp != top && (sub = rp->aggregate) != NULL) { @@ -124,6 +144,8 @@ ripng_aggregate_delete (struct prefix *p) struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct ripng_aggregate *sub; + struct list *list = NULL; + struct listnode *node = NULL; /* Get top node for aggregation. */ top = route_node_get (ripng->table, p); @@ -135,11 +157,12 @@ ripng_aggregate_delete (struct prefix *p) for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) { /* Suppress normal route. */ - if ((rinfo = rp->info) != NULL) - { - aggregate->count--; - rinfo->suppress--; - } + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) + { + aggregate->count--; + rinfo->suppress--; + } if (rp != top && (sub = rp->aggregate) != NULL) { diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h index 2f5b75754..fe65c8836 100644 --- a/ripngd/ripng_route.h +++ b/ripngd/ripng_route.h @@ -48,7 +48,10 @@ extern void ripng_aggregate_increment (struct route_node *rp, struct ripng_info *rinfo); extern void ripng_aggregate_decrement (struct route_node *rp, struct ripng_info *rinfo); +extern void ripng_aggregate_decrement_list (struct route_node *rp, + struct list *list); extern int ripng_aggregate_add (struct prefix *p); extern int ripng_aggregate_delete (struct prefix *p); +extern void ripng_aggregate_free (struct ripng_aggregate *aggregate); #endif /* _ZEBRA_RIPNG_ROUTE_H */ diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 68f37be32..b5cf445dd 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -24,12 +24,15 @@ #include "command.h" #include "prefix.h" +#include "table.h" #include "stream.h" +#include "memory.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "ripngd/ripngd.h" +#include "ripngd/ripng_debug.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -42,11 +45,19 @@ int ripng_interface_delete (int, struct zclient *, zebra_size_t); int ripng_interface_address_add (int, struct zclient *, zebra_size_t); int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); -void -ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, - unsigned int ifindex, u_char metric) +/* Send ECMP routes to zebra. */ +static void +ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) { + static struct in6_addr **nexthops = NULL; + static unsigned int *ifindexes = NULL; + static unsigned int nexthops_len = 0; + + struct list *list = (struct list *)rp->info; struct zapi_ipv6 api; + struct listnode *listnode = NULL; + struct ripng_info *rinfo = NULL; + int count = 0; if (zclient->redist[ZEBRA_ROUTE_RIPNG]) { @@ -54,40 +65,62 @@ ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; + + if (nexthops_len < listcount (list)) + { + nexthops_len = listcount (list); + nexthops = XREALLOC (MTYPE_TMP, nexthops, + nexthops_len * sizeof (struct in6_addr *)); + ifindexes = XREALLOC (MTYPE_TMP, ifindexes, + nexthops_len * sizeof (unsigned int)); + } + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &ifindex; + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + nexthops[count] = &rinfo->nexthop; + ifindexes[count] = rinfo->ifindex; + count++; + if (cmd == ZEBRA_IPV6_ROUTE_ADD) + SET_FLAG (rinfo->flags, RIPNG_RTF_FIB); + else + UNSET_FLAG (rinfo->flags, RIPNG_RTF_FIB); + } + + api.nexthop = nexthops; + api.nexthop_num = count; + api.ifindex = ifindexes; + api.ifindex_num = count; + + rinfo = listgetdata (listhead (list)); + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - - zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, p, &api); + api.metric = rinfo->metric; + + zapi_ipv6_route (cmd, zclient, + (struct prefix_ipv6 *)&rp->p, &api); + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_debug ("%s: %s/%d nexthops %d", + (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count); } } +/* Add/update ECMP routes to zebra. */ void -ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, - unsigned int ifindex) +ripng_zebra_ipv6_add (struct route_node *rp) { - struct zapi_ipv6 api; - - if (zclient->redist[ZEBRA_ROUTE_RIPNG]) - { - api.type = ZEBRA_ROUTE_RIPNG; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; - SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &ifindex; + ripng_zebra_ipv6_send (rp, ZEBRA_IPV6_ROUTE_ADD); +} - zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, p, &api); - } +/* Delete ECMP routes from zebra. */ +void +ripng_zebra_ipv6_delete (struct route_node *rp) +{ + ripng_zebra_ipv6_send (rp, ZEBRA_IPV6_ROUTE_DELETE); } /* Zebra route add and delete treatment. */ diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 4c0b67dfc..21e45b6ea 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -421,8 +421,13 @@ ripng_garbage_collect (struct thread *t) rp = rinfo->rp; /* Unlock route_node. */ - rp->info = NULL; - route_unlock_node (rp); + listnode_delete (rp->info, rinfo); + if (list_isempty ((struct list *)rp->info)) + { + list_free (rp->info); + rp->info = NULL; + route_unlock_node (rp); + } /* Free RIPng routing information. */ ripng_info_free (rinfo); @@ -430,41 +435,159 @@ ripng_garbage_collect (struct thread *t) return 0; } -/* Timeout RIPng routes. */ -static int -ripng_timeout (struct thread *t) +static void ripng_timeout_update (struct ripng_info *rinfo); + +/* Add new route to the ECMP list. + * RETURN: the new entry added in the list + */ +struct ripng_info * +ripng_ecmp_add (struct ripng_info *rinfo_new) { - struct ripng_info *rinfo; - struct route_node *rp; + struct route_node *rp = rinfo_new->rp; + struct ripng_info *rinfo = NULL; + struct list *list = NULL; - rinfo = THREAD_ARG (t); - rinfo->t_timeout = NULL; + if (rp->info == NULL) + rp->info = list_new (); + list = (struct list *)rp->info; - /* Get route_node pointer. */ - rp = rinfo->rp; + rinfo = ripng_info_new (); + memcpy (rinfo, rinfo_new, sizeof (struct ripng_info)); + listnode_add (list, rinfo); + + if (ripng_route_rte (rinfo)) + { + ripng_timeout_update (rinfo); + ripng_zebra_ipv6_add (rp); + } + + ripng_aggregate_increment (rp, rinfo); + + /* Set the route change flag on the first entry. */ + rinfo = listgetdata (listhead (list)); + SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + + return rinfo; +} + +/* Replace the ECMP list with the new route. + * RETURN: the new entry added in the list + */ +struct ripng_info * +ripng_ecmp_replace (struct ripng_info *rinfo_new) +{ + struct route_node *rp = rinfo_new->rp; + struct list *list = (struct list *)rp->info; + struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL; + struct listnode *node = NULL, *nextnode = NULL; + + if (list == NULL || listcount (list) == 0) + return ripng_ecmp_add (rinfo_new); + + /* Get the first entry */ + rinfo = listgetdata (listhead (list)); + + /* Learnt route replaced by a local one. Delete it from zebra. */ + if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new)) + if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) + ripng_zebra_ipv6_delete (rp); + + if (rinfo->metric != RIPNG_METRIC_INFINITY) + ripng_aggregate_decrement_list (rp, list); + + /* Re-use the first entry, and delete the others. */ + for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) + if (tmp_rinfo != rinfo) + { + RIPNG_TIMER_OFF (tmp_rinfo->t_timeout); + RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect); + list_delete_node (list, node); + ripng_info_free (tmp_rinfo); + } + + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + memcpy (rinfo, rinfo_new, sizeof (struct ripng_info)); + + if (ripng_route_rte (rinfo)) + { + ripng_timeout_update (rinfo); + /* The ADD message implies an update. */ + ripng_zebra_ipv6_add (rp); + } + + ripng_aggregate_increment (rp, rinfo); + + /* Set the route change flag. */ + SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + + return rinfo; +} + +/* Delete one route from the ECMP list. + * RETURN: + * null - the entry is freed, and other entries exist in the list + * the entry - the entry is the last one in the list; its metric is set + * to INFINITY, and the garbage collector is started for it + */ +struct ripng_info * +ripng_ecmp_delete (struct ripng_info *rinfo) +{ + struct route_node *rp = rinfo->rp; + struct list *list = (struct list *)rp->info; + + RIPNG_TIMER_OFF (rinfo->t_timeout); + + if (rinfo->metric != RIPNG_METRIC_INFINITY) + ripng_aggregate_decrement (rp, rinfo); + + if (listcount (list) > 1) + { + /* Some other ECMP entries still exist. Just delete this entry. */ + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + listnode_delete (list, rinfo); + if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) + /* The ADD message implies the update. */ + ripng_zebra_ipv6_add (rp); + ripng_info_free (rinfo); + rinfo = NULL; + } + else + { + assert (rinfo == listgetdata (listhead (list))); - /* - The garbage-collection timer is set for 120 seconds. */ - RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, - ripng->garbage_time); + /* This is the only entry left in the list. We must keep it in + * the list for garbage collection time, with INFINITY metric. */ - /* Delete this route from the kernel. */ - ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, - rinfo->ifindex); - /* - The metric for the route is set to 16 (infinity). This causes - the route to be removed from service. */ - rinfo->metric = RIPNG_METRIC_INFINITY; - rinfo->flags &= ~RIPNG_RTF_FIB; + rinfo->metric = RIPNG_METRIC_INFINITY; + RIPNG_TIMER_ON (rinfo->t_garbage_collect, + ripng_garbage_collect, ripng->garbage_time); - /* Aggregate count decrement. */ - ripng_aggregate_decrement (rp, rinfo); + if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) + ripng_zebra_ipv6_delete (rp); + } - /* - The route change flag is to indicate that this entry has been - changed. */ - rinfo->flags |= RIPNG_RTF_CHANGED; + /* Set the route change flag on the first entry. */ + rinfo = listgetdata (listhead (list)); + SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); - /* - The output process is signalled to trigger a response. */ + /* Signal the output process to trigger an update. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + return rinfo; +} + +/* Timeout RIPng routes. */ +static int +ripng_timeout (struct thread *t) +{ + ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t)); return 0; } @@ -628,11 +751,12 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, int ret; struct prefix_ipv6 p; struct route_node *rp; - struct ripng_info *rinfo; + struct ripng_info *rinfo = NULL, newinfo; struct ripng_interface *ri; struct in6_addr *nexthop; - u_char oldmetric; int same = 0; + struct list *list = NULL; + struct listnode *node = NULL; /* Make prefix structure. */ memset (&p, 0, sizeof (struct prefix_ipv6)); @@ -653,24 +777,23 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, if (ret < 0) return; + memset (&newinfo, 0, sizeof (newinfo)); + newinfo.type = ZEBRA_ROUTE_RIPNG; + newinfo.sub_type = RIPNG_ROUTE_RTE; + if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) + newinfo.nexthop = ripng_nexthop->address; + else + newinfo.nexthop = from->sin6_addr; + newinfo.from = from->sin6_addr; + newinfo.ifindex = ifp->ifindex; + newinfo.metric = rte->metric; + newinfo.metric_out = rte->metric; /* XXX */ + newinfo.tag = ntohs (rte->tag); /* XXX */ + /* Modify entry. */ if (ri->routemap[RIPNG_FILTER_IN]) { int ret; - struct ripng_info newinfo; - - memset (&newinfo, 0, sizeof (struct ripng_info)); - newinfo.type = ZEBRA_ROUTE_RIPNG; - newinfo.sub_type = RIPNG_ROUTE_RTE; - if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) - newinfo.nexthop = ripng_nexthop->address; - else - newinfo.nexthop = from->sin6_addr; - newinfo.from = from->sin6_addr; - newinfo.ifindex = ifp->ifindex; - newinfo.metric = rte->metric; - newinfo.metric_out = rte->metric; /* XXX */ - newinfo.tag = ntohs(rte->tag); /* XXX */ ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN], (struct prefix *)&p, RMAP_RIPNG, &newinfo); @@ -731,24 +854,66 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, /* Lookup RIPng routing table. */ rp = route_node_get (ripng->table, (struct prefix *) &p); - /* Sanity check */ - rinfo = rp->info; + newinfo.rp = rp; + newinfo.nexthop = *nexthop; + newinfo.metric = rte->metric; + newinfo.tag = ntohs (rte->tag); + + /* Check to see whether there is already RIPng route on the table. */ + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) + { + /* Need to compare with redistributed entry or local entry */ + if (!ripng_route_rte (rinfo)) + break; + + if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) && + IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) + break; + + if (!listnextnode (node)) + { + /* Not found in the list */ + + if (rte->metric > rinfo->metric) + { + /* New route has a greater metric. Discard it. */ + route_unlock_node (rp); + return; + } + + if (rte->metric < rinfo->metric) + /* New route has a smaller metric. Replace the ECMP list + * with the new one in below. */ + break; + + /* Metrics are same. Keep "rinfo" null and the new route + * is added in the ECMP list in below. */ + } + } + if (rinfo) { /* Redistributed route check. */ if (rinfo->type != ZEBRA_ROUTE_RIPNG && rinfo->metric != RIPNG_METRIC_INFINITY) - return; + { + route_unlock_node (rp); + return; + } /* Local static route. */ if (rinfo->type == ZEBRA_ROUTE_RIPNG && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) && rinfo->metric != RIPNG_METRIC_INFINITY) - return; + { + route_unlock_node (rp); + return; + } } - if (rp->info == NULL) + if (!rinfo) { /* Now, check to see whether there is already an explicit route for the destination prefix. If there is no such route, add @@ -756,53 +921,10 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIPNG_METRIC_INFINITY) - { - rinfo = ripng_info_new (); - - /* - Setting the destination prefix and length to those in - the RTE. */ - rp->info = rinfo; - rinfo->rp = rp; - - /* - Setting the metric to the newly calculated metric (as - described above). */ - rinfo->metric = rte->metric; - rinfo->tag = ntohs (rte->tag); - - /* - Set the next hop address to be the address of the router - from which the datagram came or the next hop address - specified by a next hop RTE. */ - IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); - IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); - rinfo->ifindex = ifp->ifindex; - - /* - Initialize the timeout for the route. If the - garbage-collection timer is running for this route, stop it. */ - ripng_timeout_update (rinfo); - - /* - Set the route change flag. */ - rinfo->flags |= RIPNG_RTF_CHANGED; - - /* - Signal the output process to trigger an update (see section - 2.5). */ - ripng_event (RIPNG_TRIGGERED_UPDATE, 0); - - /* Finally, route goes into the kernel. */ - rinfo->type = ZEBRA_ROUTE_RIPNG; - rinfo->sub_type = RIPNG_ROUTE_RTE; - - ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex, - rinfo->metric); - rinfo->flags |= RIPNG_RTF_FIB; - - /* Aggregate check. */ - ripng_aggregate_increment (rp, rinfo); - } + ripng_ecmp_add (&newinfo); } else { - rinfo = rp->info; - /* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. If this datagram is from the same router as the existing @@ -810,9 +932,6 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) && (rinfo->ifindex == ifp->ifindex)); - if (same) - ripng_timeout_update (rinfo); - /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old @@ -820,96 +939,24 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, if ((same && rinfo->metric != rte->metric) || rte->metric < rinfo->metric) { - /* - Adopt the route from the datagram. That is, put the - new metric in, and adjust the next hop address (if - necessary). */ - oldmetric = rinfo->metric; - rinfo->metric = rte->metric; - rinfo->tag = ntohs (rte->tag); - IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); - rinfo->ifindex = ifp->ifindex; - - /* Should a new route to this network be established - while the garbage-collection timer is running, the - new route will replace the one that is about to be - deleted. In this case the garbage-collection timer - must be cleared. */ - - if (oldmetric == RIPNG_METRIC_INFINITY && - rinfo->metric < RIPNG_METRIC_INFINITY) - { - rinfo->type = ZEBRA_ROUTE_RIPNG; - rinfo->sub_type = RIPNG_ROUTE_RTE; - - RIPNG_TIMER_OFF (rinfo->t_garbage_collect); - - if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) - IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); - - ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric); - rinfo->flags |= RIPNG_RTF_FIB; - - /* The aggregation counter needs to be updated because - the prefixes, which are into the gc, have been - removed from the aggregator (see ripng_timout). */ - ripng_aggregate_increment (rp, rinfo); - } - - /* Update nexthop and/or metric value. */ - if (oldmetric != RIPNG_METRIC_INFINITY) - { - ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); - ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric); - rinfo->flags |= RIPNG_RTF_FIB; - - if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) - IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); - } - - /* - Set the route change flag and signal the output process - to trigger an update. */ - rinfo->flags |= RIPNG_RTF_CHANGED; - ripng_event (RIPNG_TRIGGERED_UPDATE, 0); - - /* - If the new metric is infinity, start the deletion - process (described above); */ - if (rinfo->metric == RIPNG_METRIC_INFINITY) - { - /* If the new metric is infinity, the deletion process - begins for the route, which is no longer used for - routing packets. Note that the deletion process is - started only when the metric is first set to - infinity. If the metric was already infinity, then a - new deletion process is not started. */ - if (oldmetric != RIPNG_METRIC_INFINITY) - { - /* - The garbage-collection timer is set for 120 seconds. */ - RIPNG_TIMER_ON (rinfo->t_garbage_collect, - ripng_garbage_collect, ripng->garbage_time); - RIPNG_TIMER_OFF (rinfo->t_timeout); - - /* - The metric for the route is set to 16 - (infinity). This causes the route to be removed - from service.*/ - ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); - rinfo->flags &= ~RIPNG_RTF_FIB; - - /* Aggregate count decrement. */ - ripng_aggregate_decrement (rp, rinfo); - - /* - The route change flag is to indicate that this - entry has been changed. */ - /* - The output process is signalled to trigger a - response. */ - ; /* Above processes are already done previously. */ - } - } - else - { - /* otherwise, re-initialize the timeout. */ - ripng_timeout_update (rinfo); - } + if (listcount (list) == 1) + { + if (newinfo.metric != RIPNG_METRIC_INFINITY) + ripng_ecmp_replace (&newinfo); + else + ripng_ecmp_delete (rinfo); + } + else + { + if (newinfo.metric < rinfo->metric) + ripng_ecmp_replace (&newinfo); + else /* newinfo.metric > rinfo->metric */ + ripng_ecmp_delete (rinfo); + } } + else /* same & no change */ + ripng_timeout_update (rinfo); + /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } @@ -921,7 +968,8 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, unsigned int ifindex, struct in6_addr *nexthop) { struct route_node *rp; - struct ripng_info *rinfo; + struct ripng_info *rinfo = NULL, newinfo; + struct list *list = NULL; /* Redistribute route */ if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) @@ -930,10 +978,20 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, return; rp = route_node_get (ripng->table, (struct prefix *) p); - rinfo = rp->info; - if (rinfo) + memset (&newinfo, 0, sizeof (struct ripng_info)); + newinfo.type = type; + newinfo.sub_type = sub_type; + newinfo.ifindex = ifindex; + newinfo.metric = 1; + newinfo.rp = rp; + if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop)) + newinfo.nexthop = *nexthop; + + if ((list = rp->info) != NULL && listcount (list) != 0) { + rinfo = listgetdata (listhead (list)); + if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIPNG_ROUTE_INTERFACE && rinfo->metric != RIPNG_METRIC_INFINITY) { @@ -953,42 +1011,12 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, return; } } - - RIPNG_TIMER_OFF (rinfo->t_timeout); - RIPNG_TIMER_OFF (rinfo->t_garbage_collect); - - /* Tells the other daemons about the deletion of - * this RIPng route - **/ - if (ripng_route_rte (rinfo)) - ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, - rinfo->metric); - - rp->info = NULL; - ripng_info_free (rinfo); + rinfo = ripng_ecmp_replace (&newinfo); route_unlock_node (rp); - } - - rinfo = ripng_info_new (); - - rinfo->type = type; - rinfo->sub_type = sub_type; - rinfo->ifindex = ifindex; - rinfo->metric = 1; - rinfo->rp = rp; - - if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop)) - rinfo->nexthop = *nexthop; - - rinfo->flags |= RIPNG_RTF_FIB; - rp->info = rinfo; - - /* Aggregate check. */ - ripng_aggregate_increment (rp, rinfo); - - rinfo->flags |= RIPNG_RTF_CHANGED; + else + rinfo = ripng_ecmp_add (&newinfo); if (IS_RIPNG_DEBUG_EVENT) { if (!nexthop) @@ -1021,31 +1049,37 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, if (rp) { - rinfo = rp->info; - - if (rinfo != NULL - && rinfo->type == type - && rinfo->sub_type == sub_type - && rinfo->ifindex == ifindex) - { - /* Perform poisoned reverse. */ - rinfo->metric = RIPNG_METRIC_INFINITY; - RIPNG_TIMER_ON (rinfo->t_garbage_collect, - ripng_garbage_collect, ripng->garbage_time); - RIPNG_TIMER_OFF (rinfo->t_timeout); - - /* Aggregate count decrement. */ - ripng_aggregate_decrement (rp, rinfo); - - rinfo->flags |= RIPNG_RTF_CHANGED; - - if (IS_RIPNG_DEBUG_EVENT) - zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]", - inet6_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(ifindex)); - - ripng_event (RIPNG_TRIGGERED_UPDATE, 0); - } + struct list *list = rp->info; + + if (list != NULL && listcount (list) != 0) + { + rinfo = listgetdata (listhead (list)); + if (rinfo != NULL + && rinfo->type == type + && rinfo->sub_type == sub_type + && rinfo->ifindex == ifindex) + { + /* Perform poisoned reverse. */ + rinfo->metric = RIPNG_METRIC_INFINITY; + RIPNG_TIMER_ON (rinfo->t_garbage_collect, + ripng_garbage_collect, ripng->garbage_time); + RIPNG_TIMER_OFF (rinfo->t_timeout); + + /* Aggregate count decrement. */ + ripng_aggregate_decrement (rp, rinfo); + + rinfo->flags |= RIPNG_RTF_CHANGED; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug ("Poisone %s/%d on the interface %s with an " + "infinity metric [delete]", + inet6_ntoa (p->prefix), p->prefixlen, + ifindex2ifname (ifindex)); + + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + } + } + route_unlock_node (rp); } } @@ -1054,14 +1088,16 @@ void ripng_redistribute_withdraw (int type) { struct route_node *rp; - struct ripng_info *rinfo; + struct ripng_info *rinfo = NULL; + struct list *list = NULL; if (!ripng) return; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) + if ((list = rp->info) != NULL) { + rinfo = listgetdata (listhead (list)); if ((rinfo->type == type) && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) { @@ -1296,7 +1332,7 @@ ripng_request_process (struct ripng_packet *packet,int size, if (rp) { - rinfo = rp->info; + rinfo = listgetdata (listhead ((struct list *)rp->info)); rte->metric = rinfo->metric; route_unlock_node (rp); } @@ -1404,12 +1440,18 @@ static void ripng_clear_changed_flag (void) { struct route_node *rp; - struct ripng_info *rinfo; + struct ripng_info *rinfo = NULL; + struct list *list = NULL; + struct listnode *listnode = NULL; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) - if ((rinfo = rp->info) != NULL) - if (rinfo->flags & RIPNG_RTF_CHANGED) - rinfo->flags &= ~RIPNG_RTF_CHANGED; + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); + /* This flag can be set only on the first entry. */ + break; + } } /* Regular update of RIPng route. Send all routing formation to RIPng @@ -1587,6 +1629,8 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; struct list * ripng_rte_list; + struct list *list = NULL; + struct listnode *listnode = NULL; if (IS_RIPNG_DEBUG_EVENT) { if (to) @@ -1603,7 +1647,9 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { - if ((rinfo = rp->info) != NULL && rinfo->suppress == 0) + if ((list = rp->info) != NULL && + (rinfo = listgetdata (listhead (list))) != NULL && + rinfo->suppress == 0) { /* If no route-map are applied, the RTE will be these following * informations. @@ -1635,8 +1681,17 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, if (ri->split_horizon == RIPNG_SPLIT_HORIZON) { /* We perform split horizon for RIPng routes. */ - if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && - rinfo->ifindex == ifp->ifindex) + int suppress = 0; + struct ripng_info *tmp_rinfo = NULL; + + for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG && + tmp_rinfo->ifindex == ifp->ifindex) + { + suppress = 1; + break; + } + if (suppress) continue; } @@ -1715,9 +1770,12 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, * for RIPng routes. **/ if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) { - if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && - rinfo->ifindex == ifp->ifindex) - rinfo->metric_out = RIPNG_METRIC_INFINITY; + struct ripng_info *tmp_rinfo = NULL; + + for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) + if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) && + tmp_rinfo->ifindex == ifp->ifindex) + rinfo->metric_out = RIPNG_METRIC_INFINITY; } /* Add RTE to the list */ @@ -1983,6 +2041,8 @@ DEFUN (show_ipv6_ripng, struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; + struct list *list = NULL; + struct listnode *listnode = NULL; int len; if (! ripng) @@ -2020,7 +2080,8 @@ DEFUN (show_ipv6_ripng, VTY_NEWLINE); } - if ((rinfo = rp->info) != NULL) + if ((list = rp->info) != NULL) + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { p = (struct prefix_ipv6 *) &rp->p; @@ -2757,24 +2818,37 @@ ripng_clean() int i; struct route_node *rp; struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct list *list = NULL; + struct listnode *listnode = NULL; if (ripng) { /* Clear RIPng routes */ - for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { - if ((rinfo = rp->info) != NULL) { - if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && - (rinfo->sub_type == RIPNG_ROUTE_RTE)) - ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, - &rinfo->nexthop, rinfo->metric); - - RIPNG_TIMER_OFF (rinfo->t_timeout); - RIPNG_TIMER_OFF (rinfo->t_garbage_collect); - - rp->info = NULL; - route_unlock_node (rp); - - ripng_info_free(rinfo); - } + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + { + if ((list = rp->info) != NULL) + { + rinfo = listgetdata (listhead (list)); + if (ripng_route_rte (rinfo)) + ripng_zebra_ipv6_delete (rp); + + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + ripng_info_free (rinfo); + } + list_delete (list); + rp->info = NULL; + route_unlock_node (rp); + } + + if ((aggregate = rp->aggregate) != NULL) + { + ripng_aggregate_free (aggregate); + rp->aggregate = NULL; + route_unlock_node (rp); + } } /* Cancel the RIPng timers */ diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index ab06d81bf..75c5dfa0e 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -389,12 +389,8 @@ extern void ripng_redistribute_withdraw (int type); extern void ripng_distribute_update_interface (struct interface *); extern void ripng_if_rmap_update_interface (struct interface *); -extern void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, - struct in6_addr *nexthop, - unsigned int ifindex, u_char metric); -extern void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, - struct in6_addr *nexthop, - unsigned int ifindex); +extern void ripng_zebra_ipv6_add (struct route_node *); +extern void ripng_zebra_ipv6_delete (struct route_node *); extern void ripng_redistribute_clean (void); extern int ripng_redistribute_check (int); @@ -418,4 +414,8 @@ extern int ripng_interface_address_delete (int command, struct zclient *, zebra_ extern int ripng_network_write (struct vty *, int); +extern struct ripng_info *ripng_ecmp_add (struct ripng_info *); +extern struct ripng_info *ripng_ecmp_replace (struct ripng_info *); +extern struct ripng_info *ripng_ecmp_delete (struct ripng_info *); + #endif /* _ZEBRA_RIPNG_RIPNGD_H */ From 72855b16b72e9ad2c7eb0c0bfd8f5985f779608f Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:54 +0200 Subject: [PATCH 0717/1342] ripngd: allow to enable/disable the ECMP feature Introduce a new command "[no] allow-ecmp" to enable/disable the ECMP feature in RIPng. By default, ECMP is not allowed. Once ECMP is disabled, only one route entry can exist in the list. * ripng_zebra.c: adjust a debugging information, which shows the number of nexthops according to whether ECMP is enabled. * ripngd.c: ripng_ecmp_add() will reject the new route if ECMP is not allowed and some entry already exists. A new configurable command "allow-ecmp" is added to control whether ECMP is allowed. When ECMP is disabled, ripng_ecmp_disable() is called to remove the multiple nexthops. * ripngd.h: Add a new member "ecmp" to "struct ripng", indicating whether ECMP is allowed or not. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent Jardin Signed-off-by: David Lamparter --- ripngd/ripng_zebra.c | 16 ++++++-- ripngd/ripngd.c | 89 +++++++++++++++++++++++++++++++++++++++++++- ripngd/ripngd.h | 3 ++ 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index b5cf445dd..5d383fa2a 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -102,10 +102,18 @@ ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) (struct prefix_ipv6 *)&rp->p, &api); if (IS_RIPNG_DEBUG_ZEBRA) - zlog_debug ("%s: %s/%d nexthops %d", - (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ - "Install into zebra" : "Delete from zebra", - inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count); + { + if (ripng->ecmp) + zlog_debug ("%s: %s/%d nexthops %d", + (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count); + else + zlog_debug ("%s: %s/%d", + (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ + "Install into zebra" : "Delete from zebra", + inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen); + } } } diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 21e45b6ea..4a7f52fbf 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -438,7 +438,8 @@ ripng_garbage_collect (struct thread *t) static void ripng_timeout_update (struct ripng_info *rinfo); /* Add new route to the ECMP list. - * RETURN: the new entry added in the list + * RETURN: the new entry added in the list, or NULL if it is not the first + * entry and ECMP is not allowed. */ struct ripng_info * ripng_ecmp_add (struct ripng_info *rinfo_new) @@ -451,6 +452,11 @@ ripng_ecmp_add (struct ripng_info *rinfo_new) rp->info = list_new (); list = (struct list *)rp->info; + /* If ECMP is not allowed and some entry already exists in the list, + * do nothing. */ + if (listcount (list) && !ripng->ecmp) + return NULL; + rinfo = ripng_info_new (); memcpy (rinfo, rinfo_new, sizeof (struct ripng_info)); listnode_add (list, rinfo); @@ -2636,6 +2642,80 @@ DEFUN (no_ripng_default_information_originate, return CMD_SUCCESS; } +/* Update ECMP routes to zebra when ECMP is disabled. */ +static void +ripng_ecmp_disable (void) +{ + struct route_node *rp; + struct ripng_info *rinfo, *tmp_rinfo; + struct list *list; + struct listnode *node, *nextnode; + + if (!ripng) + return; + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((list = rp->info) != NULL && listcount (list) > 1) + { + rinfo = listgetdata (listhead (list)); + if (!ripng_route_rte (rinfo)) + continue; + + /* Drop all other entries, except the first one. */ + for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) + if (tmp_rinfo != rinfo) + { + RIPNG_TIMER_OFF (tmp_rinfo->t_timeout); + RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect); + list_delete_node (list, node); + ripng_info_free (tmp_rinfo); + } + + /* Update zebra. */ + ripng_zebra_ipv6_add (rp); + + /* Set the route change flag. */ + SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + } +} + +DEFUN (ripng_allow_ecmp, + ripng_allow_ecmp_cmd, + "allow-ecmp", + "Allow Equal Cost MultiPath\n") +{ + if (ripng->ecmp) + { + vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ripng->ecmp = 1; + zlog_info ("ECMP is enabled."); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_allow_ecmp, + no_ripng_allow_ecmp_cmd, + "no allow-ecmp", + NO_STR + "Allow Equal Cost MultiPath\n") +{ + if (!ripng->ecmp) + { + vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ripng->ecmp = 0; + zlog_info ("ECMP is disabled."); + ripng_ecmp_disable (); + return CMD_SUCCESS; +} + /* RIPng configuration write function. */ static int ripng_config_write (struct vty *vty) @@ -2675,6 +2755,10 @@ ripng_config_write (struct vty *vty) VTY_NEWLINE); + /* ECMP configuration. */ + if (ripng->ecmp) + vty_out (vty, " allow-ecmp%s", VTY_NEWLINE); + /* RIPng static routes. */ for (rp = route_top (ripng->route); rp; rp = route_next (rp)) if (rp->info != NULL) @@ -3040,6 +3124,9 @@ ripng_init () install_element (RIPNG_NODE, &ripng_default_information_originate_cmd); install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd); + install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd); + install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd); + ripng_if_init (); ripng_debug_init (); diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 75c5dfa0e..706ff542d 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -129,6 +129,9 @@ struct ripng struct thread *t_triggered_update; struct thread *t_triggered_interval; + /* RIPng ECMP flag */ + unsigned int ecmp; + /* For redistribute route map. */ struct { From 05a69d2f3833c285b399558ba7ab4a57f194a88d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 27 May 2015 22:15:37 +0200 Subject: [PATCH 0718/1342] Revert "lib: wrong #define used for IPV6_MINHOPCOUNT" This reverts commit 54b88cac24f335414caa875b390d2d78ff4bf9e0. Unfortunately, this breaks the build on systems where linux/in6.h and netinet/in.h can't both be included, such as Ubuntu 14.04 and Debian Jessie. Signed-off-by: David Lamparter --- configure.ac | 5 +---- lib/sockunion.c | 10 +++------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 27014c3c8..f68d86fc4 100755 --- a/configure.ac +++ b/configure.ac @@ -1072,7 +1072,7 @@ dnl ------------------ dnl IPv6 header checks dnl ------------------ AC_CHECK_HEADERS([netinet6/in6.h netinet/in6_var.h netinet/icmp6.h \ - netinet6/in6_var.h netinet6/nd6.h linux/in6.h], [], [], + netinet6/in6_var.h netinet6/nd6.h], [], [], QUAGGA_INCLUDES) m4_define([QUAGGA_INCLUDES],dnl @@ -1092,9 +1092,6 @@ QUAGGA_INCLUDES #if HAVE_NETINET6_ND6_H # include #endif -#if HAVE_LINUX_IN6_H -# include -#endif ])dnl dnl disable doc check diff --git a/lib/sockunion.c b/lib/sockunion.c index 8f3540d3f..c7315f28b 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -29,10 +29,6 @@ #include "log.h" #include "jhash.h" -#if defined(HAVE_LINUX_IN6_H) -#include -#endif - #ifndef HAVE_INET_ATON int inet_aton (const char *cp, struct in_addr *inaddr) @@ -510,13 +506,13 @@ sockopt_minttl (int family, int sock, int minttl) return ret; } #endif /* IP_MINTTL */ -#ifdef IPV6_MINHOPCOUNT +#ifdef IPV6_MINHOPCNT if (family == AF_INET6) { - int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &minttl, sizeof(minttl)); + int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl)); if (ret < 0) zlog (NULL, LOG_WARNING, - "can't set sockopt IPV6_MINHOPCOUNT to %d on socket %d: %s", + "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s", minttl, sock, safe_strerror (errno)); return ret; } From db93eec18d8f1e840b32ba2cdf8baf2510f6e1a5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 5 May 2015 11:04:59 +0200 Subject: [PATCH 0719/1342] tests: add CLI dummy command-exec tool This adds some common CLI testtool code as well as a tool that has a bunch of commands to be poked for their correct processing. The tool doesn't work correctly from a script at stdin at this point because the vty code will throw away all buffered when it sees EOF, so the tail end of the input file is lost. Signed-off-by: David Lamparter --- tests/.gitignore | 1 + tests/Makefile.am | 5 ++- tests/common-cli.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ tests/common-cli.h | 49 +++++++++++++++++++++++++ tests/test-cli.c | 56 +++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 tests/common-cli.c create mode 100644 tests/common-cli.h create mode 100644 tests/test-cli.c diff --git a/tests/.gitignore b/tests/.gitignore index 1cb28c9fd..3002b2714 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -29,6 +29,7 @@ testbgpmpath testbgpmpattr testbuffer testchecksum +testcli testmemory testprivs testsegv diff --git a/tests/Makefile.am b/tests/Makefile.am index b5420710a..cdd5d0265 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -29,6 +29,7 @@ endif check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ testcommands test-timer-correctness test-timer-performance \ + testcli \ $(TESTS_BGPD) ../vtysh/vtysh_cmd.c: @@ -43,8 +44,9 @@ test-commands-defun.c: ../vtysh/vtysh_cmd.c > test-commands-defun.c BUILT_SOURCES = test-commands-defun.c -noinst_HEADERS = prng.h tests.h +noinst_HEADERS = prng.h tests.h common-cli.h +testcli_SOURCES = test-cli.c common-cli.c testsig_SOURCES = test-sig.c testsegv_SOURCES = test-segv.c testbuffer_SOURCES = test-buffer.c @@ -66,6 +68,7 @@ testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c test_timer_correctness_SOURCES = test-timer-correctness.c prng.c test_timer_performance_SOURCES = test-timer-performance.c prng.c +testcli_LDADD = ../lib/libzebra.la @LIBCAP@ testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/tests/common-cli.c b/tests/common-cli.c new file mode 100644 index 000000000..7135856e9 --- /dev/null +++ b/tests/common-cli.c @@ -0,0 +1,90 @@ +/* + * generic CLI test helper functions + * + * Copyright (C) 2015 by David Lamparter, + * for Open Source Routing / NetDEF, Inc. + * + * 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 + +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "memory.h" +#include "log.h" + +#include "common-cli.h" + +struct thread_master *master; + +int dump_args(struct vty *vty, const char *descr, + int argc, const char **argv) +{ + int i; + vty_out (vty, "%s with %d args.%s", descr, argc, VTY_NEWLINE); + for (i = 0; i < argc; i++) + { + vty_out (vty, "[%02d]: %s%s", i, argv[i], VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +static void vty_do_exit(void) +{ + printf ("\nend.\n"); + exit (0); +} + +/* main routine. */ +int +main (int argc, char **argv) +{ + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* master init. */ + master = thread_master_create (); + + zlog_default = openzlog ("common-cli", ZLOG_NONE, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); + zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); + zlog_set_level (NULL, ZLOG_DEST_MONITOR, LOG_DEBUG); + + /* Library inits. */ + cmd_init (1); + host.name = strdup ("test"); + + vty_init (master); + memory_init (); + + test_init (); + + vty_stdio (vty_do_exit); + + /* Fetch next active thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} + diff --git a/tests/common-cli.h b/tests/common-cli.h new file mode 100644 index 000000000..8f6751512 --- /dev/null +++ b/tests/common-cli.h @@ -0,0 +1,49 @@ +/* + * generic CLI test helper functions + * + * Copyright (C) 2015 by David Lamparter, + * for Open Source Routing / NetDEF, Inc. + * + * 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 _COMMON_CLI_H +#define _COMMON_CLI_H + +#include "zebra.h" +#include "vty.h" +#include "command.h" + +/* function to be implemented by test */ +extern void test_init (void); + +/* functions provided by common cli + * (includes main()) + */ +extern struct thread_master *master; + +extern int dump_args(struct vty *vty, const char *descr, + int argc, const char **argv); + +#define DUMMY_HELPSTR \ + "00\n01\n02\n03\n04\n05\n06\n07\n08\n09\n" \ + "10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n" \ + "20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n" +#define DUMMY_DEFUN(name, cmdstr) \ + DEFUN (name, name ## _cmd, cmdstr, DUMMY_HELPSTR) \ + { return dump_args(vty, #name, argc, argv); } + +#endif /* _COMMON_CLI_H */ diff --git a/tests/test-cli.c b/tests/test-cli.c new file mode 100644 index 000000000..3db44eec8 --- /dev/null +++ b/tests/test-cli.c @@ -0,0 +1,56 @@ +/* + * CLI/command dummy handling tester + * + * Copyright (C) 2015 by David Lamparter, + * for Open Source Routing / NetDEF, Inc. + * + * 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 "common-cli.h" + +DUMMY_DEFUN(cmd0, "arg ipv4 A.B.C.D"); +DUMMY_DEFUN(cmd1, "arg ipv4m A.B.C.D/M"); +DUMMY_DEFUN(cmd2, "arg ipv6 X:X::X:X"); +DUMMY_DEFUN(cmd3, "arg ipv6m X:X::X:X/M"); +DUMMY_DEFUN(cmd4, "arg range <5-15>"); +DUMMY_DEFUN(cmd5, "pat a ( a|b)"); +DUMMY_DEFUN(cmd6, "pat b (a|)"); +DUMMY_DEFUN(cmd7, "pat c (a | b|c) A.B.C.D"); +DUMMY_DEFUN(cmd8, "pat d { foo A.B.C.D|bar X:X::X:X| baz }"); +DUMMY_DEFUN(cmd9, "pat e [ WORD ]"); +DUMMY_DEFUN(cmd10, "pat f [key]"); +DUMMY_DEFUN(cmd11, "alt a WORD"); +DUMMY_DEFUN(cmd12, "alt a A.B.C.D"); +DUMMY_DEFUN(cmd13, "alt a X:X::X:X"); + +void test_init(void) +{ + install_element (ENABLE_NODE, &cmd0_cmd); + install_element (ENABLE_NODE, &cmd1_cmd); + install_element (ENABLE_NODE, &cmd2_cmd); + install_element (ENABLE_NODE, &cmd3_cmd); + install_element (ENABLE_NODE, &cmd4_cmd); + install_element (ENABLE_NODE, &cmd5_cmd); + install_element (ENABLE_NODE, &cmd6_cmd); + install_element (ENABLE_NODE, &cmd7_cmd); + install_element (ENABLE_NODE, &cmd8_cmd); + install_element (ENABLE_NODE, &cmd9_cmd); + install_element (ENABLE_NODE, &cmd10_cmd); + install_element (ENABLE_NODE, &cmd11_cmd); + install_element (ENABLE_NODE, &cmd12_cmd); + install_element (ENABLE_NODE, &cmd13_cmd); +} From d79668fb440ae2689b54f52c076dbd79a8689135 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 14 May 2015 14:47:05 +0200 Subject: [PATCH 0720/1342] tests: add testcli reference in/out & do DejaGNU This adds reference in & output for the previously added testcli tool, to check basic CLI parsing/help functions. Unlike "testcommands", this one doesn't depend on compile-time system details. Signed-off-by: David Lamparter --- tests/Makefile.am | 4 +- tests/libzebra.tests/Makefile.am | 1 + tests/libzebra.tests/testcli.exp | 23 +++ tests/testcli.in | 93 ++++++++++ tests/testcli.refout | 290 +++++++++++++++++++++++++++++++ 5 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 tests/libzebra.tests/testcli.exp create mode 100644 tests/testcli.in create mode 100644 tests/testcli.refout diff --git a/tests/Makefile.am b/tests/Makefile.am index cdd5d0265..6dfab5371 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,7 +11,9 @@ EXTRA_DIST = \ lib/libzebra.exp \ global-conf.exp \ testcommands.in \ - testcommands.refout + testcommands.refout \ + testcli.in \ + testcli.refout AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" diff --git a/tests/libzebra.tests/Makefile.am b/tests/libzebra.tests/Makefile.am index 819cce2fe..4b74e2d3f 100644 --- a/tests/libzebra.tests/Makefile.am +++ b/tests/libzebra.tests/Makefile.am @@ -2,4 +2,5 @@ EXTRA_DIST = \ tabletest.exp \ test-timer-correctness.exp \ testcommands.exp \ + testcli.exp \ testnexthopiter.exp diff --git a/tests/libzebra.tests/testcli.exp b/tests/libzebra.tests/testcli.exp new file mode 100644 index 000000000..778bd0caa --- /dev/null +++ b/tests/libzebra.tests/testcli.exp @@ -0,0 +1,23 @@ +set timeout 30 +set test_name "testcli" + +spawn sh -c "./testcli < $env(srcdir)/testcli.in | diff -au $env(srcdir)/testcli.refout -" + +expect { + eof { + } + timeout { + exp_close + fail "$test_name: timeout" + } +} + +catch wait result +set os_error [lindex $result 2] +set exit_status [lindex $result 3] + +if { $os_error == 0 && $exit_status == 0 } { + pass "$test_name" +} else { + fail "$test_name" +} diff --git a/tests/testcli.in b/tests/testcli.in new file mode 100644 index 000000000..f4212b975 --- /dev/null +++ b/tests/testcli.in @@ -0,0 +1,93 @@ +echo this is a test message +echo foo bla ? baz +echo + +arg ipv4 1.2.3.4 +arg ipv4 1.2.?3.4 +arg ipv4 1.2.3 +arg ipv4 1.2.3.4.5 +arg ipv4 1.a.3.4 +arg ipv4 blah + +arg ipv4m 1.2.3.0/24 +arg ipv4m 1.2.?3.0/24 +arg ipv4m 1.2.3/9 +arg ipv4m 1.2.3.4.5/6 +arg ipv4m 1.a.3.4 +arg ipv4m blah +arg ipv4m 1.2.3.0/999 +arg ipv4m 1.2.3.0/a9 +arg ipv4m 1.2.3.0/9a + +arg ipv6 de4d:b33f::cafe +arg ipv6 de4d:b3?3f::caf?e +arg ipv6 de4d:b3 3f::caf?e +arg ipv6 de4d:b33f:z::cafe +arg ipv6 de4d:b33f:cafe: +arg ipv6 :: +arg ipv6 ::/ +arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0 +arg ipv6 12::34::56 +arg ipv6m dead:beef:cafe::/64 +arg ipv6m dead:be?ef:cafe:?:/64 + +arg range 4 +arg range 5 +arg range 9? +arg range 15 +arg range 16 +arg range -1 +arg range 99999999999999999999999999999999999999999 + +arg ? + +pa +pat + +pat a +pat a a +pat a ?b +pat a c? +pat a a x + +pat b +pat b ?a +pat b x +pat b x y + +pat c a +pat c a 1.2.3.4 +pat c b 2.3.4 +pat c c ?x + +pat d +pat d +pat d foo 1.2.3.4 +pat d foo +pat d noooo +pat d bar 1::2 +pat d bar 1::2 foo 3.4.5.6 +pat d ba?z +pat d foo 3.4.5.6 baz + +pat e +pat e f +pat e f g +pat e 1.2.3.4 + +pat f +pat f foo +pat f key + +alt a a?b +alt a 1 .2?.3.4 +alt a 1 :2? ::?3 + +conf t +do pat d baz +exit + +show run +conf t +hostname foohost +do show run diff --git a/tests/testcli.refout b/tests/testcli.refout new file mode 100644 index 000000000..1515ea2c6 --- /dev/null +++ b/tests/testcli.refout @@ -0,0 +1,290 @@ +test# echo this is a test message +this is a test message +test# echo foo bla + MESSAGE The message to echo + +test# echo foo bla baz +foo bla baz +test# echo +% Command incomplete. +test# +test# arg ipv4 1.2.3.4 +cmd0 with 1 args. +[00]: 1.2.3.4 +test# arg ipv4 1.2. + A.B.C.D 02 +test# arg ipv4 1.2.3.4 +cmd0 with 1 args. +[00]: 1.2.3.4 +test# arg ipv4 1.2.3 +cmd0 with 1 args. +[00]: 1.2.3 +test# arg ipv4 1.2.3.4.5 +% [NONE] Unknown command: arg ipv4 1.2.3.4.5 +test# arg ipv4 1.a.3.4 +% [NONE] Unknown command: arg ipv4 1.a.3.4 +test# arg ipv4 blah +% [NONE] Unknown command: arg ipv4 blah +test# +test# arg ipv4m 1.2.3.0/24 +cmd1 with 1 args. +[00]: 1.2.3.0/24 +test# arg ipv4m 1.2. + A.B.C.D/M 02 +test# arg ipv4m 1.2.3.0/24 +cmd1 with 1 args. +[00]: 1.2.3.0/24 +test# arg ipv4m 1.2.3/9 +% [NONE] Unknown command: arg ipv4m 1.2.3/9 +test# arg ipv4m 1.2.3.4.5/6 +% [NONE] Unknown command: arg ipv4m 1.2.3.4.5/6 +test# arg ipv4m 1.a.3.4 +% [NONE] Unknown command: arg ipv4m 1.a.3.4 +test# arg ipv4m blah +% [NONE] Unknown command: arg ipv4m blah +test# arg ipv4m 1.2.3.0/999 +% [NONE] Unknown command: arg ipv4m 1.2.3.0/999 +test# arg ipv4m 1.2.3.0/a9 +% [NONE] Unknown command: arg ipv4m 1.2.3.0/a9 +test# arg ipv4m 1.2.3.0/9a +% [NONE] Unknown command: arg ipv4m 1.2.3.0/9a +test# +test# arg ipv6 de4d:b33f::cafe +cmd2 with 1 args. +[00]: de4d:b33f::cafe +test# arg ipv6 de4d:b3 +% There is no matched command. +test# arg ipv6 de4d:b33f::caf + X:X::X:X 02 +test# arg ipv6 de4d:b33f::cafe +cmd2 with 1 args. +[00]: de4d:b33f::cafe +test# arg ipv6 de4d:b3 +test# arg ipv6 de4d:b33f::caf + X:X::X:X 02 +test# arg ipv6 de4d:b33f::cafe +cmd2 with 1 args. +[00]: de4d:b33f::cafe +test# arg ipv6 de4d:b33f:z::cafe +% [NONE] Unknown command: arg ipv6 de4d:b33f:z::cafe +test# arg ipv6 de4d:b33f:cafe: +% [NONE] Unknown command: arg ipv6 de4d:b33f:cafe: +test# arg ipv6 :: +cmd2 with 1 args. +[00]: :: +test# arg ipv6 ::/ +% [NONE] Unknown command: arg ipv6 ::/ +test# arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0 +% [NONE] Unknown command: arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0 +test# arg ipv6 12::34::56 +% [NONE] Unknown command: arg ipv6 12::34::56 +test# arg ipv6m dead:beef:cafe::/64 +cmd3 with 1 args. +[00]: dead:beef:cafe::/64 +test# arg ipv6m dead:be + X:X::X:X/M 02 +test# arg ipv6m dead:beef:cafe: + X:X::X:X/M 02 +test# arg ipv6m dead:beef:cafe::/64 +cmd3 with 1 args. +[00]: dead:beef:cafe::/64 +test# +test# arg range 4 +% [NONE] Unknown command: arg range 4 +test# arg range 5 +cmd4 with 1 args. +[00]: 5 +test# arg range 9 + <5-15> 02 +test# arg range 9 +cmd4 with 1 args. +[00]: 9 +test# arg range 15 +cmd4 with 1 args. +[00]: 15 +test# arg range 16 +% [NONE] Unknown command: arg range 16 +test# arg range -1 +% [NONE] Unknown command: arg range -1 +test# arg range 99999999999999999999999999999999999999999 +% [NONE] Unknown command: arg range 99999999999999999999999999999999999999999 +test# +test# arg + ipv4 01 + ipv4m 01 + ipv6 01 + ipv6m 01 + range 01 +test# arg +% Command incomplete. +test# +test# pa +test# papat +% Command incomplete. +test# pat +a b c d e f +test# pat +% Command incomplete. +test# +test# pat a +% Command incomplete. +test# pat a a +cmd5 with 1 args. +[00]: a +test# pat a + a 02 + b 03 +test# pat a b +cmd5 with 1 args. +[00]: b +test# pat a c +% There is no matched command. +test# pat a c +% [NONE] Unknown command: pat a c +test# pat a a x +% [NONE] Unknown command: pat a a x +test# +test# pat b +% Command incomplete. +test# pat b + a 02 +test# pat b a +cmd6 with 1 args. +[00]: a +test# pat b x +% [NONE] Unknown command: pat b x +test# pat b x y +% [NONE] Unknown command: pat b x y +test# +test# pat c a +% Command incomplete. +test# pat c a 1.2.3.4 +cmd7 with 2 args. +[00]: a +[01]: 1.2.3.4 +test# pat c b 2.3.4 +cmd7 with 2 args. +[00]: b +[01]: 2.3.4 +test# pat c c + A.B.C.D 05 +test# pat c c x +% [NONE] Unknown command: pat c c x +test# +test# pat d +cmd8 with 3 args. +[00]: (null) +[01]: (null) +[02]: (null) +test# pat d +bar baz foo +test# pat d +cmd8 with 3 args. +[00]: (null) +[01]: (null) +[02]: (null) +test# pat d foo 1.2.3.4 +cmd8 with 3 args. +[00]: 1.2.3.4 +[01]: (null) +[02]: (null) +test# pat d foo +% Command incomplete. +test# pat d noooo +% [NONE] Unknown command: pat d noooo +test# pat d bar 1::2 +cmd8 with 3 args. +[00]: (null) +[01]: 1::2 +[02]: (null) +test# pat d bar 1::2 foo 3.4.5.6 +cmd8 with 3 args. +[00]: 3.4.5.6 +[01]: 1::2 +[02]: (null) +test# pat d ba + bar 04 + baz 06 +test# pat d baz +cmd8 with 3 args. +[00]: (null) +[01]: (null) +[02]: baz +test# pat d foo 3.4.5.6 baz +cmd8 with 3 args. +[00]: 3.4.5.6 +[01]: (null) +[02]: baz +test# +test# pat e +% Command incomplete. +test# pat e f +% Command incomplete. +test# pat e f g +% Command incomplete. +test# pat e 1.2.3.4 +% Command incomplete. +test# +test# pat f +cmd10 with 0 args. +test# pat f foo +cmd10 with 1 args. +[00]: foo +test# pat f key +cmd10 with 1 args. +[00]: key +test# +test# alt a +test# alt a a + WORD 02 +test# alt a ab +cmd11 with 1 args. +[00]: ab +test# alt a 1 +test# alt a 1.2 + A.B.C.D 02 + WORD 02 +test# alt a 1.2.3.4 +cmd12 with 1 args. +[00]: 1.2.3.4 +test# alt a 1 +test# alt a 1:2 + WORD 02 +test# alt a 1:2 +test# alt a 1:2:: + WORD 02 + X:X::X:X 02 +test# alt a 1:2::3 +cmd13 with 1 args. +[00]: 1:2::3 +test# +test# conf t +test(config)# do pat d baz +cmd8 with 3 args. +[00]: (null) +[01]: (null) +[02]: baz +test(config)# exit +test# +test# show run + +Current configuration: +! +hostname test +! +line vty +! +end +test# conf t +test(config)# hostname foohost +foohost(config)# do show run + +Current configuration: +! +hostname foohost +! +line vty +! +end +foohost(config)# +end. From 80c9354835bb924983d12b0efad957e78f219287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 22 May 2015 13:40:56 +0300 Subject: [PATCH 0721/1342] privs: fix privilege dropping to use system defined groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It may be requred for quagga process to belong to additional groups. E.g. nhrp module will need to talk to strongSwan using vici and may require additional permissions. Initialize groups from the system group database. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/privs.c | 66 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/privs.c b/lib/privs.c index 8cfd8dfd5..ff0be2fe1 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -627,6 +627,8 @@ zprivs_init(struct zebra_privs_t *zprivs) { struct passwd *pwentry = NULL; struct group *grentry = NULL; + gid_t groups[NGROUPS_MAX]; + int i, ngroups = 0; if (!zprivs) { @@ -645,33 +647,59 @@ zprivs_init(struct zebra_privs_t *zprivs) if (zprivs->user) { - if ( (pwentry = getpwnam (zprivs->user)) ) - { - zprivs_state.zuid = pwentry->pw_uid; - } - else + if ( (pwentry = getpwnam (zprivs->user)) == NULL ) { /* cant use log.h here as it depends on vty */ fprintf (stderr, "privs_init: could not lookup user %s\n", zprivs->user); exit (1); } + + zprivs_state.zuid = pwentry->pw_uid; + zprivs_state.zgid = pwentry->pw_gid; } grentry = NULL; + if (zprivs->group) + { + if ( (grentry = getgrnam (zprivs->group)) == NULL ) + { + fprintf (stderr, "privs_init: could not lookup group %s\n", + zprivs->group); + exit (1); + } + + zprivs_state.zgid = grentry->gr_gid; + } + + if (zprivs->user) + { + ngroups = sizeof(groups); + if ( (ngroups = getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups )) < 0 ) + { + /* cant use log.h here as it depends on vty */ + fprintf (stderr, "privs_init: could not getgrouplist for user %s\n", + zprivs->user); + exit (1); + } + } + if (zprivs->vty_group) /* Add the vty_group to the supplementary groups so it can be chowned to */ { if ( (grentry = getgrnam (zprivs->vty_group)) ) { zprivs_state.vtygrp = grentry->gr_gid; - if ( setgroups (1, &zprivs_state.vtygrp) ) + + for ( i = 0; i < ngroups; i++ ) + if ( groups[i] == zprivs_state.vtygrp ) + break; + + if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) ) { - fprintf (stderr, "privs_init: could not setgroups, %s\n", - safe_strerror (errno) ); - exit (1); - } + groups[i] = zprivs_state.vtygrp; + } } else { @@ -680,19 +708,19 @@ zprivs_init(struct zebra_privs_t *zprivs) exit (1); } } - - if (zprivs->group) + + if (ngroups) { - if ( (grentry = getgrnam (zprivs->group)) ) + if ( setgroups (ngroups, groups) ) { - zprivs_state.zgid = grentry->gr_gid; - } - else - { - fprintf (stderr, "privs_init: could not lookup group %s\n", - zprivs->group); + fprintf (stderr, "privs_init: could not setgroups, %s\n", + safe_strerror (errno) ); exit (1); } + } + + if (zprivs_state.zgid) + { /* change group now, forever. uid we do later */ if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) { From c1c69e43cda64122b599746df4d1c6c5d8b52e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 22 May 2015 13:40:57 +0300 Subject: [PATCH 0722/1342] lib: allow caller to provide prefix storage in sockunion2hostprefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids a dynamic allocation which is usually freed immediate afterwards. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 11 +++++------ lib/prefix.c | 6 +++--- lib/prefix.h | 2 +- lib/vty.c | 18 ++++++------------ 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index cea430cce..976509642 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -304,28 +304,27 @@ static int bgp_update_address (struct interface *ifp, const union sockunion *dst, union sockunion *addr) { - struct prefix *p, *sel, *d; + struct prefix *p, *sel, d; struct connected *connected; struct listnode *node; int common; - d = sockunion2hostprefix (dst); + sockunion2hostprefix (dst, &d); sel = NULL; common = -1; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { p = connected->address; - if (p->family != d->family) + if (p->family != d.family) continue; - if (prefix_common_bits (p, d) > common) + if (prefix_common_bits (p, &d) > common) { sel = p; - common = prefix_common_bits (sel, d); + common = prefix_common_bits (sel, &d); } } - prefix_free (d); if (!sel) return 1; diff --git a/lib/prefix.c b/lib/prefix.c index dbfdc8301..57cf12afa 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -681,13 +681,13 @@ sockunion2prefix (const union sockunion *dest, /* Utility function of convert between struct prefix <=> union sockunion. */ struct prefix * -sockunion2hostprefix (const union sockunion *su) +sockunion2hostprefix (const union sockunion *su, struct prefix *prefix) { if (su->sa.sa_family == AF_INET) { struct prefix_ipv4 *p; - p = prefix_ipv4_new (); + p = prefix ? (struct prefix_ipv4 *) prefix : prefix_ipv4_new (); p->family = AF_INET; p->prefix = su->sin.sin_addr; p->prefixlen = IPV4_MAX_BITLEN; @@ -698,7 +698,7 @@ sockunion2hostprefix (const union sockunion *su) { struct prefix_ipv6 *p; - p = prefix_ipv6_new (); + p = prefix ? (struct prefix_ipv6 *) prefix : prefix_ipv6_new (); p->family = AF_INET6; p->prefixlen = IPV6_MAX_BITLEN; memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr)); diff --git a/lib/prefix.h b/lib/prefix.h index a1a0679c9..404a63ac0 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -189,7 +189,7 @@ extern void apply_mask (struct prefix *); extern struct prefix *sockunion2prefix (const union sockunion *dest, const union sockunion *mask); -extern struct prefix *sockunion2hostprefix (const union sockunion *); +extern struct prefix *sockunion2hostprefix (const union sockunion *, struct prefix *p); extern void prefix2sockunion (const struct prefix *, union sockunion *); extern struct prefix_ipv4 *prefix_ipv4_new (void); diff --git a/lib/vty.c b/lib/vty.c index d0028580f..5c4a23bd4 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1769,7 +1769,7 @@ vty_accept (struct thread *thread) int ret; unsigned int on; int accept_sock; - struct prefix *p = NULL; + struct prefix p; struct access_list *acl = NULL; char buf[SU_ADDRSTRLEN]; @@ -1789,13 +1789,13 @@ vty_accept (struct thread *thread) } set_nonblocking(vty_sock); - p = sockunion2hostprefix (&su); + sockunion2hostprefix (&su, &p); /* VTY's accesslist apply. */ - if (p->family == AF_INET && vty_accesslist_name) + if (p.family == AF_INET && vty_accesslist_name) { if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && - (access_list_apply (acl, p) == FILTER_DENY)) + (access_list_apply (acl, &p) == FILTER_DENY)) { zlog (NULL, LOG_INFO, "Vty connection refused from %s", sockunion2str (&su, buf, SU_ADDRSTRLEN)); @@ -1804,18 +1804,16 @@ vty_accept (struct thread *thread) /* continue accepting connections */ vty_event (VTY_SERV, accept_sock, NULL); - prefix_free (p); - return 0; } } #ifdef HAVE_IPV6 /* VTY's ipv6 accesslist apply. */ - if (p->family == AF_INET6 && vty_ipv6_accesslist_name) + if (p.family == AF_INET6 && vty_ipv6_accesslist_name) { if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && - (access_list_apply (acl, p) == FILTER_DENY)) + (access_list_apply (acl, &p) == FILTER_DENY)) { zlog (NULL, LOG_INFO, "Vty connection refused from %s", sockunion2str (&su, buf, SU_ADDRSTRLEN)); @@ -1824,15 +1822,11 @@ vty_accept (struct thread *thread) /* continue accepting connections */ vty_event (VTY_SERV, accept_sock, NULL); - prefix_free (p); - return 0; } } #endif /* HAVE_IPV6 */ - prefix_free (p); - on = 1; ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof (on)); From 483abc037b0ac4b3ed168c4810bb14ea338fa80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 22 May 2015 13:40:59 +0300 Subject: [PATCH 0723/1342] sockunion: add accessors for sockunion address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upcoming nhrp code will use this, and it can be used to remove the sockunion2ip(X) macro. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/sockunion.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/sockunion.h | 5 +++++ 2 files changed, 61 insertions(+) diff --git a/lib/sockunion.c b/lib/sockunion.c index c7315f28b..727730af8 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -589,6 +589,62 @@ sockunion_hash (const union sockunion *su) return 0; } +size_t +family2addrsize(int family) +{ + switch (family) + { + case AF_INET: + return sizeof(struct in_addr); +#ifdef HAVE_IPV6 + case AF_INET6: + return sizeof(struct in6_addr); +#endif /* HAVE_IPV6 */ + } + return 0; +} + +size_t +sockunion_get_addrlen(const union sockunion *su) +{ + return family2addrsize(sockunion_family(su)); +} + +const u_char * +sockunion_get_addr(const union sockunion *su) +{ + switch (sockunion_family(su)) + { + case AF_INET: + return (const u_char *) &su->sin.sin_addr.s_addr; +#ifdef HAVE_IPV6 + case AF_INET6: + return (const u_char *) &su->sin6.sin6_addr; +#endif /* HAVE_IPV6 */ + } + return NULL; +} + +void +sockunion_set(union sockunion *su, int family, const u_char *addr, size_t bytes) +{ + if (family2addrsize(family) != bytes) + return; + + sockunion_family(su) = family; + switch (family) + { + case AF_INET: + memcpy(&su->sin.sin_addr.s_addr, addr, bytes); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + memcpy(&su->sin6.sin6_addr, addr, bytes); + break; +#endif /* HAVE_IPV6 */ + } +} + /* After TCP connection is established. Get local address and port. */ union sockunion * sockunion_getsockname (int fd) diff --git a/lib/sockunion.h b/lib/sockunion.h index ea3b833c8..a6f964fec 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -89,6 +89,11 @@ extern int sockunion_cmp (const union sockunion *, const union sockunion *); extern int sockunion_same (const union sockunion *, const union sockunion *); extern unsigned int sockunion_hash (const union sockunion *); +extern size_t family2addrsize(int family); +extern size_t sockunion_get_addrlen(const union sockunion *); +extern const u_char *sockunion_get_addr(const union sockunion *); +extern void sockunion_set(union sockunion *, int family, const u_char *addr, size_t bytes); + extern union sockunion *sockunion_str2su (const char *str); extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); From f85592e05ae6463727433893e61afd1081fcf7e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 22 May 2015 13:41:00 +0300 Subject: [PATCH 0724/1342] zebra: simplify redistribution code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge the conditionals as one to avoid code duplication. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- zebra/redistribute.c | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 078c2ad0b..8d5b4cae4 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -176,19 +176,8 @@ redistribute_add (struct prefix *p, struct rib *rib) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { - if (is_default (p)) - { - if (client->redist_default || client->redist[rib->type]) - { - if (p->family == AF_INET) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); -#ifdef HAVE_IPV6 - if (p->family == AF_INET6) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); -#endif /* HAVE_IPV6 */ - } - } - else if (client->redist[rib->type]) + if ((is_default (p) && client->redist_default) + || client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); @@ -212,21 +201,8 @@ redistribute_delete (struct prefix *p, struct rib *rib) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { - if (is_default (p)) - { - if (client->redist_default || client->redist[rib->type]) - { - if (p->family == AF_INET) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, - rib); -#ifdef HAVE_IPV6 - if (p->family == AF_INET6) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, - rib); -#endif /* HAVE_IPV6 */ - } - } - else if (client->redist[rib->type]) + if ((is_default (p) && client->redist_default) + || client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib); From 3293bc280f15d8e3c04e0bf9b0a8d54d342a87a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 22 May 2015 13:41:01 +0300 Subject: [PATCH 0725/1342] route table: constify some APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/table.c | 12 ++++++------ lib/table.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/table.c b/lib/table.c index bd7023c12..da2136168 100644 --- a/lib/table.c +++ b/lib/table.c @@ -59,7 +59,7 @@ route_node_new (struct route_table *table) /* Allocate new route node with prefix set. */ static struct route_node * -route_node_set (struct route_table *table, struct prefix *prefix) +route_node_set (struct route_table *table, const struct prefix *prefix) { struct route_node *node; @@ -141,14 +141,14 @@ static const u_char maskbit[] = /* Common prefix route genaration. */ static void -route_common (struct prefix *n, struct prefix *p, struct prefix *new) +route_common (const struct prefix *n, const struct prefix *p, struct prefix *new) { int i; u_char diff; u_char mask; - u_char *np = (u_char *)&n->u.prefix; - u_char *pp = (u_char *)&p->u.prefix; + const u_char *np = (const u_char *)&n->u.prefix; + const u_char *pp = (const u_char *)&p->u.prefix; u_char *newp = (u_char *)&new->u.prefix; for (i = 0; i < p->prefixlen / 8; i++) @@ -265,7 +265,7 @@ route_node_match_ipv6 (const struct route_table *table, /* Lookup same prefix node. Return NULL when we can't find route. */ struct route_node * -route_node_lookup (const struct route_table *table, struct prefix *p) +route_node_lookup (const struct route_table *table, const struct prefix *p) { struct route_node *node; u_char prefixlen = p->prefixlen; @@ -287,7 +287,7 @@ route_node_lookup (const struct route_table *table, struct prefix *p) /* Add node to routing table. */ struct route_node * -route_node_get (struct route_table *const table, struct prefix *p) +route_node_get (struct route_table *const table, const struct prefix *p) { struct route_node *new; struct route_node *node; diff --git a/lib/table.h b/lib/table.h index ab7eb68ce..2ffd79b53 100644 --- a/lib/table.h +++ b/lib/table.h @@ -148,9 +148,9 @@ extern struct route_node *route_next (struct route_node *); extern struct route_node *route_next_until (struct route_node *, struct route_node *); extern struct route_node *route_node_get (struct route_table *const, - struct prefix *); + const struct prefix *); extern struct route_node *route_node_lookup (const struct route_table *, - struct prefix *); + const struct prefix *); extern struct route_node *route_lock_node (struct route_node *node); extern struct route_node *route_node_match (const struct route_table *, const struct prefix *); From 53009d387a633997b16d32224b50451b5c81b61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 23 May 2015 11:08:38 +0300 Subject: [PATCH 0726/1342] lib: make sockunion2str safer to use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's mostly used for logging, and the return value is never checked, so try to make it valid. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/sockunion.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/sockunion.c b/lib/sockunion.c index 727730af8..492c36ec5 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -166,13 +166,20 @@ str2sockunion (const char *str, union sockunion *su) const char * sockunion2str (const union sockunion *su, char *buf, size_t len) { - if (su->sa.sa_family == AF_INET) - return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); + switch (sockunion_family(su)) + { + case AF_UNSPEC: + snprintf (buf, len, "(unspec)"); + return buf; + case AF_INET: + return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); #ifdef HAVE_IPV6 - else if (su->sa.sa_family == AF_INET6) - return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); + case AF_INET6: + return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); #endif /* HAVE_IPV6 */ - return NULL; + } + snprintf (buf, len, "(af %d)", sockunion_family(su)); + return buf; } union sockunion * From 41eb9a4305fbcb206c900a18af7df7115d857d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 23 May 2015 11:08:39 +0300 Subject: [PATCH 0727/1342] lib: make prefix2str simpler to use, and use it in zclient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning the buffer allows using it in the logging functions in easier way. This also makes the API consistent with sockunion. Add also PREFIX_STRLEN to be the generic buffer length required for any prefix string representation. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- lib/prefix.c | 7 ++++--- lib/prefix.h | 5 ++++- lib/zclient.c | 6 +++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 57cf12afa..63742f393 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -760,14 +760,15 @@ str2prefix (const char *str, struct prefix *p) return 0; } -int -prefix2str (const struct prefix *p, char *str, int size) +const char * +prefix2str (union prefix46constptr pu, char *str, int size) { + const struct prefix *p = pu.p; char buf[BUFSIZ]; inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ); snprintf (str, size, "%s/%d", buf, p->prefixlen); - return 0; + return str; } struct prefix * diff --git a/lib/prefix.h b/lib/prefix.h index 404a63ac0..bc8aebc55 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -129,6 +129,9 @@ union prefix46constptr #define INET6_BUFSIZ 51 #endif /* INET6_BUFSIZ */ +/* Maximum prefix string length (IPv6) */ +#define PREFIX_STRLEN 51 + /* Max bit/byte length of IPv4 address. */ #define IPV4_MAX_BYTELEN 4 #define IPV4_MAX_BITLEN 32 @@ -179,7 +182,7 @@ extern void prefix_free (struct prefix *); extern const char *prefix_family_str (const struct prefix *); extern int prefix_blen (const struct prefix *); extern int str2prefix (const char *, struct prefix *); -extern int prefix2str (const struct prefix *, char *, int); +extern const char *prefix2str (union prefix46constptr, char *, int); extern int prefix_match (const struct prefix *, const struct prefix *); extern int prefix_same (const struct prefix *, const struct prefix *); extern int prefix_cmp (const struct prefix *, const struct prefix *); diff --git a/lib/zclient.c b/lib/zclient.c index 1e05d6dde..71da87c6f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -808,11 +808,11 @@ zebra_interface_address_read (int type, struct stream *s) else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { /* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */ - char buf[BUFSIZ]; - prefix2str (ifc->address, buf, sizeof(buf)); + char buf[PREFIX_STRLEN]; zlog_warn("warning: interface %s address %s " "with peer flag set, but no peer address!", - ifp->name, buf); + ifp->name, + prefix2str (ifc->address, buf, sizeof buf)); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } } From 53a5c39c705f917567d5b1764f1fe12ad5c5e577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 23 May 2015 11:08:40 +0300 Subject: [PATCH 0728/1342] zebra/vty: use prefix2str and unify show ip/ipv6 route code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use prefix2str where possible. As now ip/ipv6 are practically identical, they are merged removing unneeded code duplication. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 412 +++++++++++++--------------------------------- 1 file changed, 114 insertions(+), 298 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 1e39ebdd0..bc453de96 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -699,6 +699,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) struct rib *rib; struct nexthop *nexthop, *tnexthop; int recursing; + char buf[PREFIX_STRLEN]; RNODE_FOREACH_RIB (rn, rib) { @@ -710,15 +711,15 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) ? " using Multicast RIB" : " using Unicast RIB"; } - vty_out (vty, "Routing entry for %s/%d%s%s", - inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, mcast_info, - VTY_NEWLINE); + vty_out (vty, "Routing entry for %s%s%s", + prefix2str (&rn->p, buf, sizeof(buf)), mcast_info, + VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - vty_out (vty, ", best"); + vty_out (vty, ", best"); if (rib->refcnt) - vty_out (vty, ", refcnt %ld", rib->refcnt); + vty_out (vty, ", refcnt %ld", rib->refcnt); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, ", blackhole"); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) @@ -728,10 +729,12 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (rib->type == ZEBRA_ROUTE_RIP - || rib->type == ZEBRA_ROUTE_OSPF - || rib->type == ZEBRA_ROUTE_BABEL - || rib->type == ZEBRA_ROUTE_ISIS - || rib->type == ZEBRA_ROUTE_BGP) + || rib->type == ZEBRA_ROUTE_RIPNG + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_OSPF6 + || rib->type == ZEBRA_ROUTE_BABEL + || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; struct tm *tm; @@ -756,53 +759,60 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) } for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - char addrstr[32]; - - vty_out (vty, " %c%s", - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', - recursing ? " " : ""); + { + vty_out (vty, " %c%s", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', + recursing ? " " : ""); - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4)); - if (nexthop->ifindex) - vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " directly connected, %s", - ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFNAME: - vty_out (vty, " directly connected, %s", nexthop->ifname); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out (vty, " directly connected, Null0"); - break; - default: - break; - } - if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out (vty, " inactive"); + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " %s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, sizeof(buf))); + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + vty_out (vty, ", %s", nexthop->ifname); + else if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " directly connected, Null0"); + break; + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out (vty, " onlink"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out (vty, " onlink"); - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out (vty, " (recursive)"); + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out (vty, " (recursive)"); - switch (nexthop->type) + switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: if (nexthop->src.ipv4.s_addr) { - if (inet_ntop(AF_INET, &nexthop->src.ipv4, addrstr, - sizeof addrstr)) - vty_out (vty, ", src %s", addrstr); + if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) + vty_out (vty, ", src %s", buf); } break; #ifdef HAVE_IPV6 @@ -811,17 +821,16 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) case NEXTHOP_TYPE_IPV6_IFNAME: if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { - if (inet_ntop(AF_INET6, &nexthop->src.ipv6, addrstr, - sizeof addrstr)) - vty_out (vty, ", src %s", addrstr); + if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) + vty_out (vty, ", src %s", buf); } break; #endif /* HAVE_IPV6 */ default: - break; + break; } - vty_out (vty, "%s", VTY_NEWLINE); - } + vty_out (vty, "%s", VTY_NEWLINE); + } vty_out (vty, "%s", VTY_NEWLINE); } } @@ -840,14 +849,13 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) if (nexthop == rib->nexthop) { /* Prefix information. */ - len = vty_out (vty, "%c%c%c %s/%d", + len = vty_out (vty, "%c%c%c %s", zebra_route_char (rib->type), CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', - inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ), - rn->p.prefixlen); + prefix2str (&rn->p, buf, sizeof buf)); /* Distance and metric display. */ if (rib->type != ZEBRA_ROUTE_CONNECT @@ -862,34 +870,44 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) len - 3 + (2 * recursing), ' '); switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); - if (nexthop->ifindex) - vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " is directly connected, %s", - ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFNAME: - vty_out (vty, " is directly connected, %s", nexthop->ifname); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out (vty, " is directly connected, Null0"); - break; - default: - break; - } + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " via %s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + vty_out (vty, ", %s", nexthop->ifname); + else if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " is directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " is directly connected, Null0"); + break; + default: + break; + } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out (vty, " inactive"); + vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out (vty, " onlink"); + vty_out (vty, " onlink"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out (vty, " (recursive)"); + vty_out (vty, " (recursive)"); switch (nexthop->type) { @@ -898,7 +916,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) case NEXTHOP_TYPE_IPV4_IFNAME: if (nexthop->src.ipv4.s_addr) { - if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) + if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) vty_out (vty, ", src %s", buf); } break; @@ -908,13 +926,13 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) case NEXTHOP_TYPE_IPV6_IFNAME: if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { - if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) + if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) vty_out (vty, ", src %s", buf); } break; #endif /* HAVE_IPV6 */ default: - break; + break; } if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) @@ -923,10 +941,12 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) vty_out (vty, ", rej"); if (rib->type == ZEBRA_ROUTE_RIP - || rib->type == ZEBRA_ROUTE_OSPF - || rib->type == ZEBRA_ROUTE_BABEL - || rib->type == ZEBRA_ROUTE_ISIS - || rib->type == ZEBRA_ROUTE_BGP) + || rib->type == ZEBRA_ROUTE_RIPNG + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_OSPF6 + || rib->type == ZEBRA_ROUTE_BABEL + || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; struct tm *tm; @@ -1376,6 +1396,7 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) struct route_node *rn; struct static_ipv4 *si; struct route_table *stable; + char buf[PREFIX_STRLEN]; int write; write = 0; @@ -1388,8 +1409,7 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { - vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), - rn->p.prefixlen); + vty_out (vty, "%s %s", cmd, prefix2str (&rn->p, buf, sizeof buf)); switch (si->type) { @@ -1794,208 +1814,6 @@ DEFUN (no_ipv6_route_ifname_flags_pref, return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]); } -/* New RIB. Detailed information for IPv6 route. */ -static void -vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) -{ - struct rib *rib; - struct nexthop *nexthop, *tnexthop; - int recursing; - char buf[BUFSIZ]; - - RNODE_FOREACH_RIB (rn, rib) - { - vty_out (vty, "Routing entry for %s/%d%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), - rn->p.prefixlen, - VTY_NEWLINE); - vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); - vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - vty_out (vty, ", best"); - if (rib->refcnt) - vty_out (vty, ", refcnt %ld", rib->refcnt); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, ", blackhole"); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, ", reject"); - vty_out (vty, "%s", VTY_NEWLINE); - -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (rib->type == ZEBRA_ROUTE_RIPNG - || rib->type == ZEBRA_ROUTE_OSPF6 - || rib->type == ZEBRA_ROUTE_BABEL - || rib->type == ZEBRA_ROUTE_ISIS - || rib->type == ZEBRA_ROUTE_BGP) - { - time_t uptime; - struct tm *tm; - - uptime = time (NULL); - uptime -= rib->uptime; - tm = gmtime (&uptime); - - vty_out (vty, " Last update "); - - if (uptime < ONE_DAY_SECOND) - vty_out (vty, "%02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - else if (uptime < ONE_WEEK_SECOND) - vty_out (vty, "%dd%02dh%02dm", - tm->tm_yday, tm->tm_hour, tm->tm_min); - else - vty_out (vty, "%02dw%dd%02dh", - tm->tm_yday/7, - tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); - vty_out (vty, " ago%s", VTY_NEWLINE); - } - - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - vty_out (vty, " %c%s", - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', - recursing ? " " : ""); - - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - case NEXTHOP_TYPE_IPV6_IFNAME: - vty_out (vty, " %s", - inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) - vty_out (vty, ", %s", nexthop->ifname); - else if (nexthop->ifindex) - vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " directly connected, %s", - ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFNAME: - vty_out (vty, " directly connected, %s", - nexthop->ifname); - break; - default: - break; - } - if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out (vty, " inactive"); - - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out (vty, " onlink"); - - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out (vty, " (recursive)"); - - vty_out (vty, "%s", VTY_NEWLINE); - } - vty_out (vty, "%s", VTY_NEWLINE); - } -} - -static void -vty_show_ipv6_route (struct vty *vty, struct route_node *rn, - struct rib *rib) -{ - struct nexthop *nexthop, *tnexthop; - int recursing; - int len = 0; - char buf[BUFSIZ]; - - /* Nexthop information. */ - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - if (nexthop == rib->nexthop) - { - /* Prefix information. */ - len = vty_out (vty, "%c%c%c %s/%d", - zebra_route_char (rib->type), - CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) - ? '>' : ' ', - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) - ? '*' : ' ', - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), - rn->p.prefixlen); - - /* Distance and metric display. */ - if (rib->type != ZEBRA_ROUTE_CONNECT - && rib->type != ZEBRA_ROUTE_KERNEL) - len += vty_out (vty, " [%d/%d]", rib->distance, - rib->metric); - } - else - vty_out (vty, " %c%*c", - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) - ? '*' : ' ', - len - 3 + (2 * recursing), ' '); - - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - case NEXTHOP_TYPE_IPV6_IFNAME: - vty_out (vty, " via %s", - inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) - vty_out (vty, ", %s", nexthop->ifname); - else if (nexthop->ifindex) - vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " is directly connected, %s", - ifindex2ifname (nexthop->ifindex)); - break; - case NEXTHOP_TYPE_IFNAME: - vty_out (vty, " is directly connected, %s", - nexthop->ifname); - break; - default: - break; - } - if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out (vty, " inactive"); - - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out (vty, " (recursive)"); - - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, ", bh"); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, ", rej"); - - if (rib->type == ZEBRA_ROUTE_RIPNG - || rib->type == ZEBRA_ROUTE_OSPF6 - || rib->type == ZEBRA_ROUTE_BABEL - || rib->type == ZEBRA_ROUTE_ISIS - || rib->type == ZEBRA_ROUTE_BGP) - { - time_t uptime; - struct tm *tm; - - uptime = time (NULL); - uptime -= rib->uptime; - tm = gmtime (&uptime); - -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - - if (uptime < ONE_DAY_SECOND) - vty_out (vty, ", %02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - else if (uptime < ONE_WEEK_SECOND) - vty_out (vty, ", %dd%02dh%02dm", - tm->tm_yday, tm->tm_hour, tm->tm_min); - else - vty_out (vty, ", %02dw%dd%02dh", - tm->tm_yday/7, - tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); - } - vty_out (vty, "%s", VTY_NEWLINE); - } -} - DEFUN (show_ipv6_route, show_ipv6_route_cmd, "show ipv6 route", @@ -2021,7 +1839,7 @@ DEFUN (show_ipv6_route, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ipv6_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } @@ -2063,7 +1881,7 @@ DEFUN (show_ipv6_route_prefix_longer, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ipv6_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } @@ -2103,7 +1921,7 @@ DEFUN (show_ipv6_route_protocol, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ipv6_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } @@ -2139,7 +1957,7 @@ DEFUN (show_ipv6_route_addr, return CMD_WARNING; } - vty_show_ipv6_route_detail (vty, rn); + vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); @@ -2179,7 +1997,7 @@ DEFUN (show_ipv6_route_prefix, return CMD_WARNING; } - vty_show_ipv6_route_detail (vty, rn); + vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); @@ -2257,7 +2075,7 @@ DEFUN (show_ipv6_mroute, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ipv6_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } @@ -2282,9 +2100,7 @@ static_config_ipv6 (struct vty *vty) for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { - vty_out (vty, "ipv6 route %s/%d", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), - rn->p.prefixlen); + vty_out (vty, "ipv6 route %s", prefix2str (&rn->p, buf, sizeof buf)); switch (si->type) { From be6335d682c5ee1b6930345193eda875705fbab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 23 May 2015 11:08:41 +0300 Subject: [PATCH 0729/1342] zebra: use prefix2str for logging where possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes code more robust, consice and readable. Signed-off-by: Timo Teräs Signed-off-by: David Lamparter --- zebra/interface.c | 5 ++- zebra/ioctl_solaris.c | 16 ++++----- zebra/irdp_main.c | 6 ++-- zebra/kernel_socket.c | 68 ++++++++++++++---------------------- zebra/redistribute.c | 16 ++++----- zebra/rt_netlink.c | 35 +++++++------------ zebra/rt_socket.c | 20 +++++------ zebra/rtadv.c | 8 ++--- zebra/zebra_fpm.c | 7 ++-- zebra/zebra_rib.c | 80 ++++++++++++++++++------------------------- 10 files changed, 107 insertions(+), 154 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 54d8b1038..80eb6aa91 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1593,10 +1593,9 @@ if_config_write (struct vty *vty) { char buf[INET6_ADDRSTRLEN]; p = ifc->address; - vty_out (vty, " ip%s address %s/%d", + vty_out (vty, " ip%s address %s", p->family == AF_INET ? "" : "v6", - inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf)), - p->prefixlen); + prefix2str (p, buf, sizeof(buf))); if (ifc->label) vty_out (vty, " label %s", ifc->label); diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index 6c1c254a7..16934f063 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -407,11 +407,11 @@ if_unset_flags (struct interface *ifp, uint64_t flags) int if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) { - char addrbuf[INET_ADDRSTRLEN]; + char addrbuf[PREFIX_STRLEN]; - inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix), - addrbuf, sizeof (addrbuf)); - zlog_warn ("Can't set %s on interface %s", addrbuf, ifp->name); + zlog_warn ("Can't set %s on interface %s", + prefix2str(ifc->address->prefix, addrbuf, sizeof(addrbuf)), + ifp->name); return 0; @@ -420,11 +420,11 @@ if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { - char addrbuf[INET_ADDRSTRLEN]; + char addrbuf[PREFIX_STRLEN]; - inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix), - addrbuf, sizeof (addrbuf)); - zlog_warn ("Can't delete %s on interface %s", addrbuf, ifp->name); + zlog_warn ("Can't delete %s on interface %s", + prefix2str(ifc->address->prefix, addrbuf, sizeof(addrbuf)), + ifp->name); return 0; diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index c297979cf..cf78a54e7 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -180,6 +180,7 @@ irdp_send(struct interface *ifp, struct prefix *p, struct stream *s) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; + char buf[PREFIX_STRLEN]; u_int32_t dst; u_int32_t ttl=1; @@ -191,10 +192,9 @@ irdp_send(struct interface *ifp, struct prefix *p, struct stream *s) dst = htonl(INADDR_ALLHOSTS_GROUP); if(irdp->flags & IF_DEBUG_MESSAGES) - zlog_debug("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", + zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d", ifp->name, - inet_ntoa(p->u.prefix4), - p->prefixlen, + prefix2str(p, buf, sizeof buf), irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime, get_pref(irdp, p)); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 916dad97f..fefccdceb 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -631,50 +631,32 @@ ifam_read_mesg (struct ifa_msghdr *ifm, if (IS_ZEBRA_DEBUG_KERNEL) { - switch (sockunion_family(addr)) + int family = sockunion_family(addr); + switch (family) { case AF_INET: - { - char buf[4][INET_ADDRSTRLEN]; - zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " - "ifam_flags 0x%x, addr %s/%d broad %s dst %s " - "gateway %s", - __func__, ifm->ifam_index, - (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, - ifm->ifam_flags, - inet_ntop(AF_INET,&addr->sin.sin_addr, - buf[0],sizeof(buf[0])), - ip_masklen(mask->sin.sin_addr), - inet_ntop(AF_INET,&brd->sin.sin_addr, - buf[1],sizeof(buf[1])), - inet_ntop(AF_INET,&dst.sin.sin_addr, - buf[2],sizeof(buf[2])), - inet_ntop(AF_INET,&gateway.sin.sin_addr, - buf[3],sizeof(buf[3]))); - } - break; #ifdef HAVE_IPV6 case AF_INET6: +#endif { char buf[4][INET6_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", - __func__, ifm->ifam_index, + __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, - inet_ntop(AF_INET6,&addr->sin6.sin6_addr, + inet_ntop(family,&addr->sin.sin_addr, buf[0],sizeof(buf[0])), - ip6_masklen(mask->sin6.sin6_addr), - inet_ntop(AF_INET6,&brd->sin6.sin6_addr, + ip_masklen(mask->sin.sin_addr), + inet_ntop(family,&brd->sin.sin_addr, buf[1],sizeof(buf[1])), - inet_ntop(AF_INET6,&dst.sin6.sin6_addr, + inet_ntop(family,&dst.sin.sin_addr, buf[2],sizeof(buf[2])), - inet_ntop(AF_INET6,&gateway.sin6.sin6_addr, + inet_ntop(family,&gateway.sin.sin_addr, buf[3],sizeof(buf[3]))); } break; -#endif /* HAVE_IPV6 */ default: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", __func__, ifm->ifam_index, @@ -904,12 +886,12 @@ rtm_read (struct rt_msghdr *rtm) */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) { - char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN]; + char buf[PREFIX_STRLEN], gate_buf[INET_ADDRSTRLEN]; int ret; if (! IS_ZEBRA_DEBUG_RIB) return; ret = rib_lookup_ipv4_route (&p, &gate); - inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN); + prefix2str (&p, buf, sizeof(buf)); switch (rtm->rtm_type) { case RTM_ADD: @@ -920,18 +902,18 @@ rtm_read (struct rt_msghdr *rtm) switch (ret) { case ZEBRA_RIB_NOTFOUND: - zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB", - __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); + zlog_debug ("%s: %s %s: desync: RR isn't yet in RIB, while already in FIB", + __func__, lookup (rtm_type_str, rtm->rtm_type), buf); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN); - zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)", - __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf); + zlog_debug ("%s: %s %s: desync: RR is in RIB, but gate differs (ours is %s)", + __func__, lookup (rtm_type_str, rtm->rtm_type), buf, gate_buf); break; case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */ - zlog_debug ("%s: %s %s/%d: done Ok", - __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); + zlog_debug ("%s: %s %s: done Ok", + __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); return; break; @@ -943,27 +925,27 @@ rtm_read (struct rt_msghdr *rtm) switch (ret) { case ZEBRA_RIB_FOUND_EXACT: - zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB", - __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); + zlog_debug ("%s: %s %s: desync: RR is still in RIB, while already not in FIB", + __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: - zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs", - __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); + zlog_debug ("%s: %s %s: desync: RR is still in RIB, plus gate differs", + __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ - zlog_debug ("%s: %s %s/%d: done Ok", - __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); + zlog_debug ("%s: %s %s: done Ok", + __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); return; break; } break; default: - zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received", - __func__, buf, p.prefixlen, lookup (rtm_type_str, rtm->rtm_type)); + zlog_debug ("%s: %s: warning: loopback RTM of type %s received", + __func__, buf, lookup (rtm_type_str, rtm->rtm_type)); } return; } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 8d5b4cae4..94330aed2 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -326,12 +326,12 @@ zebra_interface_address_add_update (struct interface *ifp, if (IS_ZEBRA_DEBUG_EVENT) { - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX_STRLEN]; p = ifc->address; - zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s", - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), - p->prefixlen, ifc->ifp->name); + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s on %s", + prefix2str (p, buf, sizeof(buf)), + ifc->ifp->name); } if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) @@ -355,12 +355,12 @@ zebra_interface_address_delete_update (struct interface *ifp, if (IS_ZEBRA_DEBUG_EVENT) { - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX_STRLEN]; p = ifc->address; - zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s", - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), - p->prefixlen, ifc->ifp->name); + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s on %s", + prefix2str (p, buf, sizeof(buf)), + ifc->ifp->name); } router_id_del_address(ifc); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7e4107297..45ebf20ec 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -933,12 +933,10 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (IS_ZEBRA_DEBUG_KERNEL) { - if (h->nlmsg_type == RTM_NEWROUTE) - zlog_debug ("RTM_NEWROUTE %s/%d", - inet_ntoa (p.prefix), p.prefixlen); - else - zlog_debug ("RTM_DELROUTE %s/%d", - inet_ntoa (p.prefix), p.prefixlen); + char buf[PREFIX_STRLEN]; + zlog_debug ("%s %s", + h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", + prefix2str (&p, buf, sizeof(buf))); } if (h->nlmsg_type == RTM_NEWROUTE) @@ -1010,7 +1008,6 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; - char buf[BUFSIZ]; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); @@ -1018,14 +1015,10 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (IS_ZEBRA_DEBUG_KERNEL) { - if (h->nlmsg_type == RTM_NEWROUTE) - zlog_debug ("RTM_NEWROUTE %s/%d", - inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), - p.prefixlen); - else - zlog_debug ("RTM_DELROUTE %s/%d", - inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), - p.prefixlen); + char buf[PREFIX_STRLEN]; + zlog_debug ("%s %s", + h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", + prefix2str (&p, buf, sizeof(buf))); } if (h->nlmsg_type == RTM_NEWROUTE) @@ -1563,16 +1556,12 @@ _netlink_route_debug( { if (IS_ZEBRA_DEBUG_KERNEL) { - zlog_debug ("netlink_route_multipath() (%s): %s %s/%d type %s", + char buf[PREFIX_STRLEN]; + zlog_debug ("netlink_route_multipath() (%s): %s %s 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)); + prefix2str (p, buf, sizeof(buf)), + nexthop_type_to_str (nexthop->type)); } } diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index d8c947c67..bf21ca955 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -77,10 +77,10 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) unsigned int ifindex = 0; int gate = 0; int error; - char prefix_buf[INET_ADDRSTRLEN]; + char prefix_buf[PREFIX_STRLEN]; if (IS_ZEBRA_DEBUG_RIB) - inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); + prefix2str (p, prefix_buf, sizeof(prefix_buf)); memset (&sin_dest, 0, sizeof (struct sockaddr_in)); sin_dest.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN @@ -158,8 +158,8 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) { if (!gate) { - zlog_debug ("%s: %s/%d: attention! gate not found for rib %p", - __func__, prefix_buf, p->prefixlen, rib); + zlog_debug ("%s: %s: attention! gate not found for rib %p", + __func__, prefix_buf, rib); rib_dump (p, rib); } else @@ -172,8 +172,8 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) case ZEBRA_ERR_NOERROR: nexthop_num++; if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: successfully did NH %s", - __func__, prefix_buf, p->prefixlen, gate_buf); + zlog_debug ("%s: %s: successfully did NH %s", + __func__, prefix_buf, gate_buf); if (cmd == RTM_ADD) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); break; @@ -195,11 +195,9 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) case ZEBRA_ERR_RTNOEXIST: case ZEBRA_ERR_RTUNREACH: default: - /* This point is reachable regardless of debugging mode. */ - if (!IS_ZEBRA_DEBUG_RIB) - inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); - zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s", - __func__, prefix_buf, p->prefixlen, error, lookup (rtm_type_str, cmd)); + zlog_err ("%s: %s: rtm_write() unexpectedly returned %d for command %s", + __func__, prefix2str(p, prefix_buf, sizeof(prefix_buf)), + error, lookup (rtm_type_str, cmd)); break; } } /* if (cmd and flags make sense) */ diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9a3fd265d..b3959823f 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -1537,7 +1537,7 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) struct zebra_if *zif; struct listnode *node; struct rtadv_prefix *rprefix; - u_char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX_STRLEN]; int interval; if (! rtadv) @@ -1601,10 +1601,8 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { - vty_out (vty, " ipv6 nd prefix %s/%d", - inet_ntop (AF_INET6, &rprefix->prefix.prefix, - (char *) buf, INET6_ADDRSTRLEN), - rprefix->prefix.prefixlen); + vty_out (vty, " ipv6 nd prefix %s", + prefix2str (&rprefix->prefix, buf, sizeof(buf))); if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) || (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME)) { diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index e02d17455..896915c21 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -1301,7 +1301,7 @@ void zfpm_trigger_update (struct route_node *rn, const char *reason) { rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX_STRLEN]; /* * Ignore if the connection is down. We will update the FPM about @@ -1329,9 +1329,8 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) if (reason) { - zfpm_debug ("%s/%d triggering update to FPM - Reason: %s", - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)), - rn->p.prefixlen, reason); + zfpm_debug ("%s triggering update to FPM - Reason: %s", + prefix2str (&rn->p, buf, sizeof(buf)), reason); } SET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index cc7f48fa5..f247f1d29 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -82,7 +82,7 @@ static void __attribute__((format (printf, 4, 5))) _rnode_zlog(const char *_func, struct route_node *rn, int priority, const char *msgfmt, ...) { - char buf[INET6_ADDRSTRLEN + 4], *bptr; + char buf[PREFIX_STRLEN + 8]; char msgbuf[512]; va_list ap; @@ -94,10 +94,9 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, { rib_table_info_t *info = rn->table->info; - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - bptr = buf + strlen(buf); - snprintf(bptr, buf + sizeof(buf) - bptr, "/%d%s", rn->p.prefixlen, - info->safi == SAFI_MULTICAST ? " (MRIB)" : ""); + prefix2str(&rn->p, buf, sizeof(buf)); + if (info->safi == SAFI_MULTICAST) + strcat(buf, " (MRIB)"); } else { @@ -2010,13 +2009,12 @@ void _rib_dump (const char * func, union prefix46constptr pp, const struct rib * rib) { const struct prefix *p = pp.p; - char straddr[INET6_ADDRSTRLEN]; + char straddr[PREFIX_STRLEN]; struct nexthop *nexthop, *tnexthop; int recursing; - inet_ntop (p->family, &p->u.prefix, straddr, INET6_ADDRSTRLEN); - zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, (void *)rib, - straddr, p->prefixlen); + zlog_debug ("%s: dumping RIB entry %p for %s", func, (void *)rib, + prefix2str(p, straddr, sizeof(straddr))); zlog_debug ( "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", @@ -2080,14 +2078,14 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) return; } - inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN); /* Scan the RIB table for exactly matching RIB entry. */ rn = route_node_lookup (table, (struct prefix *) p); /* No route for this prefix. */ if (! rn) { - zlog_debug ("%s: lookup failed for %s/%d", __func__, prefix_buf, p->prefixlen); + zlog_debug ("%s: lookup failed for %s", __func__, + prefix2str((struct prefix*) p, prefix_buf, sizeof(prefix_buf))); return; } @@ -2150,9 +2148,9 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) changed = 1; if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET_ADDRSTRLEN]; - inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); - zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); + char buf[PREFIX_STRLEN]; + zlog_debug ("%s: freeing way for connected prefix %s", __func__, + prefix2str(&rn->p, buf, sizeof(buf))); rib_dump (&rn->p, rib); } rib_uninstall (rn, rib); @@ -2246,7 +2244,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct rib *same = NULL; struct nexthop *nexthop, *tnexthop; int recursing; - char buf1[INET_ADDRSTRLEN]; + char buf1[PREFIX_STRLEN]; char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ @@ -2260,15 +2258,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("rib_delete_ipv4(): route delete %s via %s ifindex %d", + prefix2str (p, buf1, sizeof(buf1)), inet_ntoa (*gate), ifindex); else - zlog_debug ("rib_delete_ipv4(): route delete %s/%d ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("rib_delete_ipv4(): route delete %s ifindex %d", + prefix2str (p, buf1, sizeof(buf1)), ifindex); } @@ -2279,15 +2275,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s via %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex); else - zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), ifindex); } return ZEBRA_ERR_RTNOEXIST; @@ -2354,16 +2348,14 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s via %s ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex, type); else - zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), ifindex, type); } @@ -2807,7 +2799,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct rib *same = NULL; struct nexthop *nexthop, *tnexthop; int recursing; - char buf1[INET6_ADDRSTRLEN]; + char buf1[PREFIX_STRLEN]; char buf2[INET6_ADDRSTRLEN]; /* Apply mask. */ @@ -2825,15 +2817,13 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s via %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex); else - zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), ifindex); } return ZEBRA_ERR_RTNOEXIST; @@ -2901,16 +2891,14 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s via %s ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex, type); else - zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), ifindex, type); } From 395828eea809e8b2b8c5824d3639cefedd7aa9f0 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:55 +0200 Subject: [PATCH 0730/1342] ospf6d, bgpd: avoid calling if_nametoindex As the comments in if.h, it is better to call ifname2ifindex() instead of if_nametoindex(). And ifname2ifindex() can work for VRF by appending a parameter while if_nametoindex() can not. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 2 +- bgpd/bgp_zebra.c | 6 +++--- ospf6d/ospf6_route.c | 15 +++++++-------- ospf6d/ospf6_zebra.c | 5 ++--- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 976509642..7059e8ae1 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -402,7 +402,7 @@ bgp_connect (struct peer *peer) #ifdef HAVE_IPV6 if (peer->ifname) - ifindex = if_nametoindex (peer->ifname); + ifindex = ifname2ifindex (peer->ifname); #endif /* HAVE_IPV6 */ if (BGP_DEBUG (events, EVENTS)) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index f18d916f1..8ae7f465b 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -572,7 +572,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) { if (peer->ifname) - ifp = if_lookup_by_index (if_nametoindex (peer->ifname)); + ifp = if_lookup_by_name (peer->ifname); } else ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); @@ -792,7 +792,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) { if (info->peer->ifname) - ifindex = if_nametoindex (info->peer->ifname); + ifindex = ifname2ifindex (info->peer->ifname); else if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } @@ -913,7 +913,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) if (info->peer->ifname) - ifindex = if_nametoindex (info->peer->ifname); + ifindex = ifname2ifindex (info->peer->ifname); api.flags = flags; api.type = ZEBRA_ROUTE_BGP; diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 30927737a..50575564b 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -792,7 +792,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) { int i; char destination[64], nexthop[64]; - char duration[16], ifname[IFNAMSIZ]; + char duration[16]; + const char *ifname; struct timeval now, res; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); @@ -812,8 +813,7 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop, sizeof (nexthop)); - if (! if_indextoname (route->nexthop[0].ifindex, ifname)) - snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex); + ifname = ifindex2ifname (route->nexthop[0].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", (ospf6_route_is_best (route) ? '*' : ' '), @@ -827,8 +827,7 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); - if (! if_indextoname (route->nexthop[i].ifindex, ifname)) - snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); + ifname = ifindex2ifname (route->nexthop[i].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); @@ -838,7 +837,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) { - char destination[64], nexthop[64], ifname[IFNAMSIZ]; + const char *ifname; + char destination[64], nexthop[64]; char area_id[16], id[16], adv_router[16], capa[16], options[16]; struct timeval now, res; char duration[16]; @@ -924,8 +924,7 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); - if (! if_indextoname (route->nexthop[i].ifindex, ifname)) - snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); + ifname = ifindex2ifname (route->nexthop[i].ifindex); vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL); } vty_out (vty, "%s", VNL); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 85f70647f..ac3235c41 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -443,11 +443,10 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) { - char ifname[IFNAMSIZ]; + const char *ifname; inet_ntop (AF_INET6, &request->nexthop[i].address, buf, sizeof (buf)); - if (!if_indextoname(request->nexthop[i].ifindex, ifname)) - strlcpy(ifname, "unknown", sizeof(ifname)); + ifname = ifindex2ifname (request->nexthop[i].ifindex); zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname, request->nexthop[i].ifindex); } From 41f44a23e86a65a5cad7e5e8cafd7e935f153232 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:56 +0200 Subject: [PATCH 0731/1342] lib, zebra: move "struct vrf" to be a lib module Previously "struct vrf" is defined locally in zebra. Now it is moved to be a lib module. This is the first step to support multi-VRF in quagga. The implementation is splitted into small patches for the purpose of easy review. * lib: "struct vrf" with basic members is defined in vrf.c. The member "void *info" is for user data. Some basic functions are defined in vrf.c for adding/deleting/ looking up a VRF, scanning the VRF table and initializing the VRF module. The type "vrf_id_t" is defined specificly for VRF ID. * zebra: The previous "struct vrf" is re-defined as "struct zebra_vrf"; and previous "vrf" variables are renamed to "zvrf". The previous "struct vrf" related functions are removed from zbera_rib.c. New functions are defined to maintain the new "struct zebra_vrf". The names vrf_xxx are reserved for the functions in VRF module. So: - the previous vrf_table() are renamed to zebra_vrf_table(); - the previous vrf_static_table() are renamed to zebra_vrf_static_table(). The main logic is not changed. BTW: Add a statement to zebra_snmp.c telling that the SNMP is running only for the MIBs in the default VRF. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- lib/Makefile.am | 4 +- lib/memtypes.c | 5 +- lib/vrf.c | 268 +++++++++++++++++++++++++++++++++++++ lib/vrf.h | 96 ++++++++++++++ lib/zebra.h | 3 + zebra/main.c | 27 +++- zebra/redistribute.c | 9 +- zebra/rib.h | 22 ++-- zebra/test_main.c | 25 ++++ zebra/zebra_fpm.c | 2 +- zebra/zebra_fpm_netlink.c | 2 +- zebra/zebra_rib.c | 270 +++++++++++++++++--------------------- zebra/zebra_snmp.c | 11 +- zebra/zebra_vty.c | 39 +++--- 14 files changed, 591 insertions(+), 192 deletions(-) create mode 100644 lib/vrf.c create mode 100644 lib/vrf.h diff --git a/lib/Makefile.am b/lib/Makefile.am index fc0231230..ac51fc625 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -13,7 +13,7 @@ libzebra_la_SOURCES = \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c memtypes.c workqueue.c + sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c BUILT_SOURCES = memtypes.h route_types.h gitversion.h @@ -28,7 +28,7 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h libospf.h + workqueue.h route_types.h libospf.h vrf.h noinst_HEADERS = \ plist_int.h diff --git a/lib/memtypes.c b/lib/memtypes.c index 1a0c11fee..3e599f673 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -69,14 +69,15 @@ struct memory_list memory_list_lib[] = { MTYPE_PQUEUE, "Priority queue" }, { MTYPE_PQUEUE_DATA, "Priority queue data" }, { MTYPE_HOST, "Host config" }, + { MTYPE_VRF, "VRF" }, + { MTYPE_VRF_NAME, "VRF name" }, { -1, NULL }, }; struct memory_list memory_list_zebra[] = { { MTYPE_RTADV_PREFIX, "Router Advertisement Prefix" }, - { MTYPE_VRF, "VRF" }, - { MTYPE_VRF_NAME, "VRF name" }, + { MTYPE_ZEBRA_VRF, "ZEBRA VRF" }, { MTYPE_NEXTHOP, "Nexthop" }, { MTYPE_RIB, "RIB" }, { MTYPE_RIB_QUEUE, "RIB process work queue" }, diff --git a/lib/vrf.c b/lib/vrf.c new file mode 100644 index 000000000..3ccbb9961 --- /dev/null +++ b/lib/vrf.c @@ -0,0 +1,268 @@ +/* + * VRF functions. + * Copyright (C) 2014 6WIND S.A. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "vrf.h" +#include "prefix.h" +#include "table.h" +#include "log.h" +#include "memory.h" + +struct vrf +{ + /* Identifier, same as the vector index */ + vrf_id_t vrf_id; + /* Name */ + char *name; + + /* User data */ + void *info; +}; + +/* Holding VRF hooks */ +struct vrf_master +{ + int (*vrf_new_hook) (vrf_id_t, void **); + int (*vrf_delete_hook) (vrf_id_t, void **); +} vrf_master = {0,}; + +/* VRF table */ +struct route_table *vrf_table = NULL; + +/* Build the table key */ +static void +vrf_build_key (vrf_id_t vrf_id, struct prefix *p) +{ + p->family = AF_INET; + p->prefixlen = IPV4_MAX_BITLEN; + p->u.prefix4.s_addr = vrf_id; +} + +/* Get a VRF. If not found, create one. */ +static struct vrf * +vrf_get (vrf_id_t vrf_id) +{ + struct prefix p; + struct route_node *rn; + struct vrf *vrf; + + vrf_build_key (vrf_id, &p); + rn = route_node_get (vrf_table, &p); + if (rn->info) + { + vrf = (struct vrf *)rn->info; + route_unlock_node (rn); /* get */ + return vrf; + } + + vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); + vrf->vrf_id = vrf_id; + rn->info = vrf; + + zlog_info ("VRF %u is created.", vrf_id); + + if (vrf_master.vrf_new_hook) + (*vrf_master.vrf_new_hook) (vrf_id, &vrf->info); + + return vrf; +} + +/* Delete a VRF. This is called in vrf_terminate(). */ +static void +vrf_delete (struct vrf *vrf) +{ + zlog_info ("VRF %u is to be deleted.", vrf->vrf_id); + + if (vrf_master.vrf_delete_hook) + (*vrf_master.vrf_delete_hook) (vrf->vrf_id, &vrf->info); + + if (vrf->name) + XFREE (MTYPE_VRF_NAME, vrf->name); + + XFREE (MTYPE_VRF, vrf); +} + +/* Look up a VRF by identifier. */ +static struct vrf * +vrf_lookup (vrf_id_t vrf_id) +{ + struct prefix p; + struct route_node *rn; + struct vrf *vrf = NULL; + + vrf_build_key (vrf_id, &p); + rn = route_node_lookup (vrf_table, &p); + if (rn) + { + vrf = (struct vrf *)rn->info; + route_unlock_node (rn); /* lookup */ + } + return vrf; +} + +/* Add a VRF hook. Please add hooks before calling vrf_init(). */ +void +vrf_add_hook (int type, int (*func)(vrf_id_t, void **)) +{ + switch (type) { + case VRF_NEW_HOOK: + vrf_master.vrf_new_hook = func; + break; + case VRF_DELETE_HOOK: + vrf_master.vrf_delete_hook = func; + break; + default: + break; + } +} + +/* Return the iterator of the first VRF. */ +vrf_iter_t +vrf_first (void) +{ + struct route_node *rn; + + for (rn = route_top (vrf_table); rn; rn = route_next (rn)) + if (rn->info) + { + route_unlock_node (rn); /* top/next */ + return (vrf_iter_t)rn; + } + return VRF_ITER_INVALID; +} + +/* Return the next VRF iterator to the given iterator. */ +vrf_iter_t +vrf_next (vrf_iter_t iter) +{ + struct route_node *rn = NULL; + + /* Lock it first because route_next() will unlock it. */ + if (iter != VRF_ITER_INVALID) + rn = route_next (route_lock_node ((struct route_node *)iter)); + + for (; rn; rn = route_next (rn)) + if (rn->info) + { + route_unlock_node (rn); /* next */ + return (vrf_iter_t)rn; + } + return VRF_ITER_INVALID; +} + +/* Return the VRF iterator of the given VRF ID. If it does not exist, + * the iterator of the next existing VRF is returned. */ +vrf_iter_t +vrf_iterator (vrf_id_t vrf_id) +{ + struct prefix p; + struct route_node *rn; + + vrf_build_key (vrf_id, &p); + rn = route_node_get (vrf_table, &p); + if (rn->info) + { + /* OK, the VRF exists. */ + route_unlock_node (rn); /* get */ + return (vrf_iter_t)rn; + } + + /* Find the next VRF. */ + for (rn = route_next (rn); rn; rn = route_next (rn)) + if (rn->info) + { + route_unlock_node (rn); /* next */ + return (vrf_iter_t)rn; + } + + return VRF_ITER_INVALID; +} + +/* Obtain the VRF ID from the given VRF iterator. */ +vrf_id_t +vrf_iter2id (vrf_iter_t iter) +{ + struct route_node *rn = (struct route_node *) iter; + return (rn && rn->info) ? ((struct vrf *)rn->info)->vrf_id : VRF_DEFAULT; +} + +/* Obtain the data pointer from the given VRF iterator. */ +void * +vrf_iter2info (vrf_iter_t iter) +{ + struct route_node *rn = (struct route_node *) iter; + return (rn && rn->info) ? ((struct vrf *)rn->info)->info : NULL; +} + +/* Get the data pointer of the specified VRF. If not found, create one. */ +void * +vrf_info_get (vrf_id_t vrf_id) +{ + struct vrf *vrf = vrf_get (vrf_id); + return vrf->info; +} + +/* Look up the data pointer of the specified VRF. */ +void * +vrf_info_lookup (vrf_id_t vrf_id) +{ + struct vrf *vrf = vrf_lookup (vrf_id); + return vrf ? vrf->info : NULL; +} + +/* Initialize VRF module. */ +void +vrf_init (void) +{ + struct vrf *default_vrf; + + /* Allocate VRF table. */ + vrf_table = route_table_init (); + + /* The default VRF always exists. */ + default_vrf = vrf_get (VRF_DEFAULT); + if (!default_vrf) + { + zlog_err ("vrf_init: failed to create the default VRF!"); + exit (1); + } + + /* Set the default VRF name. */ + default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, "Default-IP-Routing-Table"); +} + +/* Terminate VRF module. */ +void +vrf_terminate (void) +{ + struct route_node *rn; + struct vrf *vrf; + + for (rn = route_top (vrf_table); rn; rn = route_next (rn)) + if ((vrf = rn->info) != NULL) + vrf_delete (vrf); + + route_table_finish (vrf_table); + vrf_table = NULL; +} + diff --git a/lib/vrf.h b/lib/vrf.h new file mode 100644 index 000000000..7e0509943 --- /dev/null +++ b/lib/vrf.h @@ -0,0 +1,96 @@ +/* + * VRF related header. + * Copyright (C) 2014 6WIND S.A. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_VRF_H +#define _ZEBRA_VRF_H + +/* The default VRF ID */ +#define VRF_DEFAULT 0 + +/* + * VRF hooks + */ + +#define VRF_NEW_HOOK 0 /* a new VRF is just created */ +#define VRF_DELETE_HOOK 1 /* a VRF is to be deleted */ + +/* + * Add a specific hook to VRF module. + * @param1: hook type + * @param2: the callback function + * - param 1: the VRF ID + * - param 2: the address of the user data pointer (the user data + * can be stored in or freed from there) + */ +extern void vrf_add_hook (int, int (*)(vrf_id_t, void **)); + +/* + * VRF iteration + */ + +typedef void * vrf_iter_t; +#define VRF_ITER_INVALID NULL /* invalid value of the iterator */ + +/* + * VRF iteration utilities. Example for the usage: + * + * vrf_iter_t iter = vrf_first(); + * for (; iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + * + * or + * + * vrf_iter_t iter = vrf_iterator (); + * for (; iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + */ + +/* Return the iterator of the first VRF. */ +extern vrf_iter_t vrf_first (void); +/* Return the next VRF iterator to the given iterator. */ +extern vrf_iter_t vrf_next (vrf_iter_t); +/* Return the VRF iterator of the given VRF ID. If it does not exist, + * the iterator of the next existing VRF is returned. */ +extern vrf_iter_t vrf_iterator (vrf_id_t); + +/* + * VRF iterator to properties + */ +extern vrf_id_t vrf_iter2id (vrf_iter_t); +extern void *vrf_iter2info (vrf_iter_t); + +/* + * Utilities to obtain the user data + */ + +/* Get the data pointer of the specified VRF. If not found, create one. */ +extern void *vrf_info_get (vrf_id_t); +/* Look up the data pointer of the specified VRF. */ +extern void *vrf_info_lookup (vrf_id_t); + +/* + * VRF initializer/destructor + */ +/* Please add hooks before calling vrf_init(). */ +extern void vrf_init (void); +extern void vrf_terminate (void); + +#endif /*_ZEBRA_VRF_H*/ + diff --git a/lib/zebra.h b/lib/zebra.h index a5ed20e40..e88a6293d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -522,6 +522,9 @@ typedef u_int8_t safi_t; typedef u_int16_t zebra_size_t; typedef u_int16_t zebra_command_t; +/* VRF ID type. */ +typedef u_int16_t vrf_id_t; + /* FIFO -- first in first out structure and macros. */ struct fifo { diff --git a/zebra/main.c b/zebra/main.c index d7f2a108b..a690c9a19 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -32,6 +32,7 @@ #include "plist.h" #include "privs.h" #include "sigevent.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -204,6 +205,29 @@ struct quagga_signal_t zebra_signals[] = }, }; +/* Callback upon creating a new VRF. */ +static int +zebra_vrf_new (vrf_id_t vrf_id, void **info) +{ + struct zebra_vrf *zvrf = *info; + + if (! zvrf) + { + zvrf = zebra_vrf_alloc (vrf_id); + *info = (void *)zvrf; + } + + return 0; +} + +/* Zebra VRF initialization. */ +static void +zebra_vrf_init (void) +{ + vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new); + vrf_init (); +} + /* Main startup routine. */ int main (int argc, char **argv) @@ -338,7 +362,8 @@ main (int argc, char **argv) /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ - /* Make kernel routing socket. */ + /* Initialize VRF module, and make kernel routing socket. */ + zebra_vrf_init (); kernel_init (); interface_list (); route_read (); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 94330aed2..8bf8ea8c0 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -30,6 +30,7 @@ #include "zclient.h" #include "linklist.h" #include "log.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -101,7 +102,7 @@ zebra_redistribute_default (struct zserv *client) p.family = AF_INET; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (table) { rn = route_node_lookup (table, (struct prefix *)&p); @@ -121,7 +122,7 @@ zebra_redistribute_default (struct zserv *client) p6.family = AF_INET6; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (table) { rn = route_node_lookup (table, (struct prefix *)&p6); @@ -145,7 +146,7 @@ zebra_redistribute (struct zserv *client, int type) struct route_table *table; struct route_node *rn; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) @@ -156,7 +157,7 @@ zebra_redistribute (struct zserv *client, int type) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); #ifdef HAVE_IPV6 - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) diff --git a/zebra/rib.h b/zebra/rib.h index 94a74194f..802d875f8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -315,10 +315,10 @@ struct nexthop : (((recursing) = 0),((tnexthop) = (tnexthop)->next))) /* Routing table instance. */ -struct vrf +struct zebra_vrf { - /* Identifier. This is same as routing table vector index. */ - u_int32_t id; + /* Identifier. */ + vrf_id_t vrf_id; /* Routing table name. */ char *name; @@ -346,9 +346,9 @@ typedef struct rib_table_info_t_ { /* - * Back pointer to vrf. + * Back pointer to zebra_vrf. */ - struct vrf *vrf; + struct zebra_vrf *zvrf; afi_t afi; safi_t safi; @@ -367,7 +367,7 @@ typedef enum */ typedef struct rib_tables_iter_t_ { - uint32_t vrf_id; + vrf_id_t vrf_id; int afi_safi_ix; rib_tables_iter_state_t state; @@ -415,9 +415,9 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *); extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); #endif /* HAVE_IPV6 */ -extern struct vrf *vrf_lookup (u_int32_t); -extern struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id); -extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id); +extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t); +extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t); +extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); /* NOTE: * All rib_add_ipv[46]* functions will not just add prefix into RIB, but @@ -557,10 +557,10 @@ rib_dest_table (rib_dest_t *dest) /* * rib_dest_vrf */ -static inline struct vrf * +static inline struct zebra_vrf * rib_dest_vrf (rib_dest_t *dest) { - return rib_table_info (rib_dest_table (dest))->vrf; + return rib_table_info (rib_dest_table (dest))->zvrf; } /* diff --git a/zebra/test_main.c b/zebra/test_main.c index f98bb4199..a92cd6189 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -29,6 +29,7 @@ #include "log.h" #include "privs.h" #include "sigevent.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -196,6 +197,29 @@ struct quagga_signal_t zebra_signals[] = }, }; +/* Callback upon creating a new VRF. */ +static int +zebra_vrf_new (vrf_id_t vrf_id, void **info) +{ + struct zebra_vrf *zvrf = *info; + + if (! zvrf) + { + zvrf = zebra_vrf_alloc (vrf_id); + *info = (void *)zvrf; + } + + return 0; +} + +/* Zebra VRF initialization. */ +static void +zebra_vrf_init (void) +{ + vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new); + vrf_init (); +} + /* Main startup routine. */ int main (int argc, char **argv) @@ -294,6 +318,7 @@ main (int argc, char **argv) access_list_init (); /* Make kernel routing socket. */ + zebra_vrf_init (); kernel_init (); route_read (); zebra_vty_init(); diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 896915c21..292dbb638 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -330,7 +330,7 @@ zfpm_is_table_for_fpm (struct route_table *table) * We only send the unicast tables in the main instance to the FPM * at this point. */ - if (info->vrf->id != 0) + if (info->zvrf->vrf_id != 0) return 0; if (info->safi != SAFI_UNICAST) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index b5f2b7607..c4a650d6e 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -245,7 +245,7 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd, ri->af = rib_dest_af (dest); ri->nlmsg_type = cmd; - ri->rtm_table = rib_dest_vrf (dest)->id; + ri->rtm_table = rib_dest_vrf (dest)->vrf_id; ri->rtm_protocol = RTPROT_UNSPEC; /* diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f247f1d29..f206205b0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -34,6 +34,7 @@ #include "workqueue.h" #include "prefix.h" #include "routemap.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/rt.h" @@ -72,9 +73,6 @@ static const struct /* no entry/default: 150 */ }; -/* Vector for routing table. */ -static vector vrf_vector; - /* RPF lookup behaviour */ static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; @@ -111,108 +109,6 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, #define rnode_info(node, ...) \ _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) -/* - * vrf_table_create - */ -static void -vrf_table_create (struct vrf *vrf, afi_t afi, safi_t safi) -{ - rib_table_info_t *info; - struct route_table *table; - - assert (!vrf->table[afi][safi]); - - table = route_table_init (); - vrf->table[afi][safi] = table; - - info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); - info->vrf = vrf; - info->afi = afi; - info->safi = safi; - table->info = info; -} - -/* Allocate new VRF. */ -static struct vrf * -vrf_alloc (const char *name) -{ - struct vrf *vrf; - - vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); - - /* Put name. */ - if (name) - vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); - - /* Allocate routing table and static table. */ - vrf_table_create (vrf, AFI_IP, SAFI_UNICAST); - vrf_table_create (vrf, AFI_IP6, SAFI_UNICAST); - vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); - vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); - vrf_table_create (vrf, AFI_IP, SAFI_MULTICAST); - vrf_table_create (vrf, AFI_IP6, SAFI_MULTICAST); - vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); - vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); - - - return vrf; -} - -/* Lookup VRF by identifier. */ -struct vrf * -vrf_lookup (u_int32_t id) -{ - return vector_lookup (vrf_vector, id); -} - -/* Initialize VRF. */ -static void -vrf_init (void) -{ - struct vrf *default_table; - - /* Allocate VRF vector. */ - vrf_vector = vector_init (1); - - /* Allocate default main table. */ - default_table = vrf_alloc ("Default-IP-Routing-Table"); - - /* Default table index must be 0. */ - vector_set_index (vrf_vector, 0, default_table); -} - -/* Lookup route table. */ -struct route_table * -vrf_table (afi_t afi, safi_t safi, u_int32_t id) -{ - struct vrf *vrf; - - vrf = vrf_lookup (id); - if (! vrf) - return NULL; - - if( afi >= AFI_MAX || safi >= SAFI_MAX ) - return NULL; - - return vrf->table[afi][safi]; -} - -/* Lookup static route table. */ -struct route_table * -vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) -{ - struct vrf *vrf; - - vrf = vrf_lookup (id); - if (! vrf) - return NULL; - - if( afi >= AFI_MAX || safi >= SAFI_MAX ) - return NULL; - - return vrf->stable[afi][safi]; -} - /* * nexthop_type_to_str */ @@ -473,7 +369,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, p.prefix = nexthop->gate.ipv4; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return 0; @@ -615,7 +511,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, p.prefix = nexthop->gate.ipv6; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return 0; @@ -731,7 +627,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, int recursing; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return 0; @@ -865,7 +761,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) int recursing; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return 0; @@ -922,7 +818,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) int nexthops_active; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return ZEBRA_RIB_LOOKUP_ERROR; @@ -988,7 +884,7 @@ rib_match_ipv6 (struct in6_addr *addr) int recursing; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return 0; @@ -1907,7 +1803,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return 0; @@ -2071,10 +1967,10 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) char prefix_buf[INET_ADDRSTRLEN]; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) { - zlog_err ("%s: vrf_table() returned NULL", __func__); + zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); return; } @@ -2120,9 +2016,9 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) struct rib *rib; unsigned changed = 0; - if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0))) + if (NULL == (table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT))) { - zlog_err ("%s: vrf_table() returned NULL", __func__); + zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); return; } @@ -2169,7 +2065,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return 0; @@ -2248,7 +2144,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return 0; @@ -2380,7 +2276,7 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return; @@ -2473,7 +2369,7 @@ static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return; @@ -2538,7 +2434,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, safi, vrf_id); + stable = zebra_vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2629,7 +2525,7 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, safi, vrf_id); + stable = zebra_vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2695,7 +2591,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + table = zebra_vrf_table (AFI_IP6, safi, VRF_DEFAULT); if (! table) return 0; @@ -2806,7 +2702,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, apply_mask_ipv6 (p); /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + table = zebra_vrf_table (AFI_IP6, safi, VRF_DEFAULT); if (! table) return 0; @@ -2923,7 +2819,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) struct route_node *rn; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return; @@ -3018,7 +2914,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return; @@ -3084,7 +2980,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); + stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! stable) return -1; @@ -3169,7 +3065,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); + stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! stable) return -1; @@ -3220,13 +3116,13 @@ rib_update (void) struct route_node *rn; struct route_table *table; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) @@ -3259,8 +3155,8 @@ rib_weed_table (struct route_table *table) void rib_weed_tables (void) { - rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); - rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + rib_weed_table (zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)); + rib_weed_table (zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); } /* Delete self installed routes after zebra is relaunched. */ @@ -3293,8 +3189,8 @@ rib_sweep_table (struct route_table *table) void rib_sweep_route (void) { - rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); - rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + rib_sweep_table (zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)); + rib_sweep_table (zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); } /* Remove specific by protocol routes from 'table'. */ @@ -3326,8 +3222,8 @@ rib_score_proto_table (u_char proto, struct route_table *table) unsigned long rib_score_proto (u_char proto) { - return rib_score_proto_table (proto, vrf_table (AFI_IP, SAFI_UNICAST, 0)) - +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + return rib_score_proto_table (proto, zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)) + +rib_score_proto_table (proto, zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); } /* Close RIB and clean up kernel routes. */ @@ -3357,8 +3253,8 @@ rib_close_table (struct route_table *table) void rib_close (void) { - rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); - rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + rib_close_table (zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)); + rib_close_table (zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); } /* Routing information base initialize. */ @@ -3366,8 +3262,6 @@ void rib_init (void) { rib_queue_init (&zebrad); - /* VRF initialization. */ - vrf_init (); } /* @@ -3378,15 +3272,19 @@ rib_init (void) * Returns TRUE if a vrf id was found, FALSE otherwise. */ static inline int -vrf_id_get_next (uint32_t id, uint32_t *next_id_p) +vrf_id_get_next (vrf_id_t vrf_id, vrf_id_t *next_id_p) { - while (++id < vector_active (vrf_vector)) + vrf_iter_t iter = vrf_iterator (vrf_id); + struct zebra_vrf *zvrf = vrf_iter2info (iter); + + /* The same one ? Then find out the next. */ + if (zvrf && (zvrf->vrf_id == vrf_id)) + zvrf = vrf_iter2info (vrf_next (iter)); + + if (zvrf) { - if (vrf_lookup (id)) - { - *next_id_p = id; - return 1; - } + *next_id_p = zvrf->vrf_id; + return 1; } return 0; @@ -3434,7 +3332,7 @@ rib_tables_iter_next (rib_tables_iter_t *iter) while (iter->afi_safi_ix < (int) ZEBRA_NUM_OF (afi_safis)) { - table = vrf_table (afi_safis[iter->afi_safi_ix].afi, + table = zebra_vrf_table (afi_safis[iter->afi_safi_ix].afi, afi_safis[iter->afi_safi_ix].safi, iter->vrf_id); if (table) @@ -3472,3 +3370,79 @@ rib_tables_iter_next (rib_tables_iter_t *iter) return table; } + +/* + * Create a routing table for the specific AFI/SAFI in the given VRF. + */ +static void +zebra_vrf_table_create (struct zebra_vrf *zvrf, afi_t afi, safi_t safi) +{ + rib_table_info_t *info; + struct route_table *table; + + assert (!zvrf->table[afi][safi]); + + table = route_table_init (); + zvrf->table[afi][safi] = table; + + info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); + info->zvrf = zvrf; + info->afi = afi; + info->safi = safi; + table->info = info; +} + +/* Allocate new zebra VRF. */ +struct zebra_vrf * +zebra_vrf_alloc (vrf_id_t vrf_id) +{ + struct zebra_vrf *zvrf; + + zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf)); + + /* Allocate routing table and static table. */ + zebra_vrf_table_create (zvrf, AFI_IP, SAFI_UNICAST); + zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_UNICAST); + zvrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); + zvrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); + zebra_vrf_table_create (zvrf, AFI_IP, SAFI_MULTICAST); + zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_MULTICAST); + zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); + zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + + /* Set VRF ID */ + zvrf->vrf_id = vrf_id; + + return zvrf; +} + +/* Lookup the routing table in an enabled VRF. */ +struct route_table * +zebra_vrf_table (afi_t afi, safi_t safi, vrf_id_t vrf_id) +{ + struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id); + + if (!zvrf) + return NULL; + + if (afi >= AFI_MAX || safi >= SAFI_MAX) + return NULL; + + return zvrf->table[afi][safi]; +} + +/* Lookup the static routing table in a VRF. */ +struct route_table * +zebra_vrf_static_table (afi_t afi, safi_t safi, vrf_id_t vrf_id) +{ + struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id); + + if (!zvrf) + return NULL; + + if (afi >= AFI_MAX || safi >= SAFI_MAX) + return NULL; + + return zvrf->stable[afi][safi]; +} + diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index f0d3e7e58..3d005aa55 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -19,6 +19,10 @@ * 02111-1307, USA. */ +/* + * Currently SNMP is only running properly for MIBs in the default VRF. + */ + #include #ifdef HAVE_SNMP @@ -31,6 +35,7 @@ #include "command.h" #include "smux.h" #include "table.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -143,7 +148,7 @@ ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return NULL; @@ -168,7 +173,7 @@ ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len, if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return 0; @@ -330,7 +335,7 @@ get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, if (exact && (*objid_len != (unsigned) v->namelen + 10)) return; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index bc453de96..a4e6af78c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -27,6 +27,7 @@ #include "command.h" #include "table.h" #include "rib.h" +#include "vrf.h" #include "zebra/zserv.h" @@ -989,7 +990,7 @@ static int do_show_ip_route(struct vty *vty, safi_t safi) { struct rib *rib; int first = 1; - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1030,7 +1031,7 @@ DEFUN (show_ip_route_prefix_longer, return CMD_WARNING; } - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1063,7 +1064,7 @@ DEFUN (show_ip_route_supernets, u_int32_t addr; int first = 1; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1109,7 +1110,7 @@ DEFUN (show_ip_route_protocol, return CMD_WARNING; } - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1148,7 +1149,7 @@ DEFUN (show_ip_route_addr, return CMD_WARNING; } - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1186,7 +1187,7 @@ DEFUN (show_ip_route_prefix, return CMD_WARNING; } - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1359,7 +1360,7 @@ DEFUN (show_ip_route_summary, { struct route_table *table; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1380,7 +1381,7 @@ DEFUN (show_ip_route_summary_prefix, { struct route_table *table; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1402,7 +1403,7 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) write = 0; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, safi, 0); + stable = zebra_vrf_static_table (AFI_IP, safi, VRF_DEFAULT); if (! stable) return -1; @@ -1489,7 +1490,7 @@ DEFUN (show_ip_mroute, struct rib *rib; int first = 1; - table = vrf_table (AFI_IP, SAFI_MULTICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_MULTICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1826,7 +1827,7 @@ DEFUN (show_ipv6_route, struct rib *rib; int first = 1; - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1860,7 +1861,7 @@ DEFUN (show_ipv6_route_prefix_longer, int ret; int first = 1; - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1907,7 +1908,7 @@ DEFUN (show_ipv6_route_protocol, return CMD_WARNING; } - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1946,7 +1947,7 @@ DEFUN (show_ipv6_route_addr, return CMD_WARNING; } - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -1984,7 +1985,7 @@ DEFUN (show_ipv6_route_prefix, return CMD_WARNING; } - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -2015,7 +2016,7 @@ DEFUN (show_ipv6_route_summary, { struct route_table *table; - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -2036,7 +2037,7 @@ DEFUN (show_ipv6_route_summary_prefix, { struct route_table *table; - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -2062,7 +2063,7 @@ DEFUN (show_ipv6_mroute, struct rib *rib; int first = 1; - table = vrf_table (AFI_IP6, SAFI_MULTICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_MULTICAST, VRF_DEFAULT); if (! table) return CMD_SUCCESS; @@ -2093,7 +2094,7 @@ static_config_ipv6 (struct vty *vty) write = 0; /* Lookup table. */ - stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, 0); + stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); if (! stable) return -1; From 2fc97f6335dd5d7df2c285b363c6ef56bb98dcf8 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:57 +0200 Subject: [PATCH 0732/1342] lib, zebra: add "vrf_id" into the "struct interface" Later, an interface will belong to a specific VRF. Now we add a property "vrf_id" to the "struct interface", and keep it as the default value 0. This property is shown when displaying interfaces information. It is also added in some logs. This is just the preparation to move the interace list into the "struct vrf". The main logic is not changed. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- lib/if.c | 8 ++++---- lib/if.h | 2 ++ zebra/interface.c | 22 +++++++++++++--------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/if.c b/lib/if.c index 3a1f9b415..f17e50863 100644 --- a/lib/if.c +++ b/lib/if.c @@ -454,12 +454,12 @@ if_dump (const struct interface *ifp) struct connected *c __attribute__((unused)); for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) - zlog_info ("Interface %s index %d metric %d mtu %d " + zlog_info ("Interface %s vrf %u index %d metric %d mtu %d " #ifdef HAVE_IPV6 "mtu6 %d " #endif /* HAVE_IPV6 */ "%s", - ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, + ifp->name, ifp->vrf_id, ifp->ifindex, ifp->metric, ifp->mtu, #ifdef HAVE_IPV6 ifp->mtu6, #endif /* HAVE_IPV6 */ @@ -675,8 +675,8 @@ connected_log (struct connected *connected, char *str) ifp = connected->ifp; p = connected->address; - snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", - str, ifp->name, prefix_family_str (p), + snprintf (logbuf, BUFSIZ, "%s interface %s vrf %u %s %s/%d ", + str, ifp->name, ifp->vrf_id, prefix_family_str (p), inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); diff --git a/lib/if.h b/lib/if.h index 8081be87d..029f57fd7 100644 --- a/lib/if.h +++ b/lib/if.h @@ -139,6 +139,8 @@ struct interface #ifdef HAVE_NET_RT_IFLIST struct if_data stats; #endif /* HAVE_NET_RT_IFLIST */ + + vrf_id_t vrf_id; }; /* Connected address structure. */ diff --git a/zebra/interface.c b/zebra/interface.c index 80eb6aa91..49d40ba37 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -381,21 +381,23 @@ if_add_update (struct interface *ifp) if (if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("interface %s index %d is shutdown. Won't wake it up.", - ifp->name, ifp->ifindex); + zlog_debug ("interface %s vrf %u index %d is shutdown. " + "Won't wake it up.", + ifp->name, ifp->vrf_id, ifp->ifindex); return; } if_addr_wakeup (ifp); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("interface %s index %d becomes active.", - ifp->name, ifp->ifindex); + zlog_debug ("interface %s vrf %u index %d becomes active.", + ifp->name, ifp->vrf_id, ifp->ifindex); } else { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("interface %s index %d is added.", ifp->name, ifp->ifindex); + zlog_debug ("interface %s vrf %u index %d is added.", + ifp->name, ifp->vrf_id, ifp->ifindex); } } @@ -412,8 +414,8 @@ if_delete_update (struct interface *ifp) if (if_is_up(ifp)) { - zlog_err ("interface %s index %d is still up while being deleted.", - ifp->name, ifp->ifindex); + zlog_err ("interface %s vrf %u index %d is still up while being deleted.", + ifp->name, ifp->vrf_id, ifp->ifindex); return; } @@ -421,8 +423,8 @@ if_delete_update (struct interface *ifp) UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("interface %s index %d is now inactive.", - ifp->name, ifp->ifindex); + zlog_debug ("interface %s vrf %u index %d is now inactive.", + ifp->name, ifp->vrf_id, ifp->ifindex); /* Delete connected routes from the kernel. */ if (ifp->connected) @@ -726,6 +728,8 @@ if_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, "down%s", VTY_NEWLINE); } + vty_out (vty, " vrf: %u%s", ifp->vrf_id, VTY_NEWLINE); + if (ifp->desc) vty_out (vty, " Description: %s%s", ifp->desc, VTY_NEWLINE); From 126215c1238eb42cc92d23aefbe1fac3b204438f Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:58 +0200 Subject: [PATCH 0733/1342] *: call if_init()/if_terminate() from vrf_init()/vrf_terminate() Later, an interface will belong to a specific VRF, and the interface initialization will be a part of the VRF initialization. So now call if_init() from vrf_init(), and if_terminate() from vrf_terminate(). Daemons have the according changes: - if if_init() was called or "iflist" was initialized, now call vrf_init() instead; - if if_terminate() was called or "iflist" was destroyed, now call vrf_terminate() instead. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- bgpd/bgp_main.c | 8 ++++---- bgpd/bgp_zebra.c | 3 --- isisd/isis_circuit.c | 1 - isisd/isis_main.c | 2 ++ lib/vrf.c | 5 +++++ ospf6d/ospf6_main.c | 5 +++-- ospfd/ospf_interface.c | 1 - ospfd/ospf_main.c | 2 ++ pimd/pim_iface.c | 5 ----- pimd/pim_iface.h | 2 -- pimd/pim_main.c | 2 ++ pimd/pimd.c | 3 ++- ripd/rip_interface.c | 1 - ripd/rip_main.c | 2 ++ ripngd/ripng_interface.c | 2 +- ripngd/ripng_main.c | 2 ++ zebra/interface.c | 1 - zebra/test_main.c | 1 - 18 files changed, 25 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 5026b5eaa..ad4de7989 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "filter.h" #include "plist.h" #include "stream.h" +#include "vrf.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -248,17 +249,14 @@ bgp_exit (int status) /* reverse bgp_zebra_init/if_init */ if (retain_mode) if_add_hook (IF_DELETE_HOOK, NULL); - for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct listnode *c_node, *c_nnode; struct connected *c; for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) bgp_connected_delete (c); - - if_delete (ifp); } - list_free (iflist); /* reverse bgp_attr_init */ bgp_attr_finish (); @@ -293,6 +291,7 @@ bgp_exit (int status) /* reverse community_list_init */ community_list_terminate (bgp_clist); + vrf_terminate (); cmd_terminate (); vty_terminate (); if (zclient) @@ -427,6 +426,7 @@ main (int argc, char **argv) cmd_init (1); vty_init (master); memory_init (); + vrf_init (); /* BGP related initialization. */ bgp_init (); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8ae7f465b..13f71de94 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1096,8 +1096,5 @@ bgp_zebra_init (void) zclient->ipv6_route_delete = zebra_read_ipv6; #endif /* HAVE_IPV6 */ - /* Interface related init. */ - if_init (); - bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index fdff819ca..2ef43ccfd 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -2739,7 +2739,6 @@ void isis_circuit_init () { /* Initialize Zebra interface data structure */ - if_init (); if_add_hook (IF_NEW_HOOK, isis_if_new_hook); if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 283b7eaae..60ecb754a 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -35,6 +35,7 @@ #include "sigevent.h" #include "filter.h" #include "zclient.h" +#include "vrf.h" #include "isisd/dict.h" #include "include-netbsd/iso.h" @@ -330,6 +331,7 @@ main (int argc, char **argv, char **envp) vty_init (master); memory_init (); access_list_init(); + vrf_init (); isis_init (); isis_circuit_init (); isis_spf_cmds_init (); diff --git a/lib/vrf.c b/lib/vrf.c index 3ccbb9961..51f9e3795 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -22,6 +22,7 @@ #include +#include "if.h" #include "vrf.h" #include "prefix.h" #include "table.h" @@ -249,6 +250,8 @@ vrf_init (void) /* Set the default VRF name. */ default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, "Default-IP-Routing-Table"); + + if_init (); } /* Terminate VRF module. */ @@ -264,5 +267,7 @@ vrf_terminate (void) route_table_finish (vrf_table); vrf_table = NULL; + + if_terminate (); } diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 4f6d9e514..1afe84a73 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -35,6 +35,7 @@ #include "privs.h" #include "sigevent.h" #include "zclient.h" +#include "vrf.h" #include "ospf6d.h" #include "ospf6_top.h" @@ -150,7 +151,7 @@ ospf6_exit (int status) ospf6_asbr_terminate (); ospf6_lsa_terminate (); - if_terminate (); + vrf_terminate (); vty_terminate (); cmd_terminate (); @@ -318,7 +319,7 @@ main (int argc, char *argv[], char *envp[]) cmd_init (1); vty_init (master); memory_init (); - if_init (); + vrf_init (); access_list_init (); prefix_list_init (); diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 0f02cc821..07c3fe35e 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -1254,7 +1254,6 @@ void ospf_if_init () { /* Initialize Zebra interface data structure. */ - if_init (); om->iflist = iflist; if_add_hook (IF_NEW_HOOK, ospf_if_new_hook); if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 96dfd5799..826fc9833 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -39,6 +39,7 @@ #include "privs.h" #include "sigevent.h" #include "zclient.h" +#include "vrf.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -290,6 +291,7 @@ main (int argc, char **argv) debug_init (); vty_init (master); memory_init (); + vrf_init (); access_list_init (); prefix_list_init (); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index ecf9ef6bc..dc3e9a2bb 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -43,11 +43,6 @@ static void pim_if_igmp_join_del_all(struct interface *ifp); -void pim_if_init() -{ - if_init(); -} - static void *if_list_clean(struct pim_interface *pim_ifp) { if (pim_ifp->igmp_join_list) { diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 4b06b9ff2..8806fdd93 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -108,8 +108,6 @@ struct pim_interface { ((pim_ifp)->pim_hello_period * 7 / 2) : \ ((pim_ifp)->pim_default_holdtime)) -void pim_if_init(void); - struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); void pim_if_delete(struct interface *ifp); void pim_if_addr_add(struct connected *ifc); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index b57f88113..63dd63648 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -31,6 +31,7 @@ #include #include "memory.h" +#include "vrf.h" #include "filter.h" #include "vty.h" #include "sigevent.h" @@ -203,6 +204,7 @@ int main(int argc, char** argv, char** envp) { cmd_init(1); vty_init(master); memory_init(); + vrf_init(); access_list_init(); pim_init(); diff --git a/pimd/pimd.c b/pimd/pimd.c index 855defcc7..78c3ff5d0 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -24,6 +24,7 @@ #include "log.h" #include "memory.h" +#include "vrf.h" #include "pimd.h" #include "pim_cmd.h" @@ -130,12 +131,12 @@ void pim_init() qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; qpim_infinite_assert_metric.ip_address = qpim_inaddr_any; - pim_if_init(); pim_cmd_init(); pim_ssmpingd_init(); } void pim_terminate() { + vrf_terminate(); pim_free(); } diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 35685a75b..f26ef48a2 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -2055,7 +2055,6 @@ void rip_if_init (void) { /* Default initial size of interface vector. */ - if_init(); if_add_hook (IF_NEW_HOOK, rip_interface_new_hook); if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index e81e61b80..95b1f6d4a 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -33,6 +33,7 @@ #include "privs.h" #include "sigevent.h" #include "zclient.h" +#include "vrf.h" #include "ripd/ripd.h" @@ -280,6 +281,7 @@ main (int argc, char **argv) vty_init (master); memory_init (); keychain_init (); + vrf_init (); /* RIP related initialization. */ rip_init (); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 358846346..c7865d1e9 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -35,6 +35,7 @@ #include "table.h" #include "thread.h" #include "privs.h" +#include "vrf.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" @@ -1177,7 +1178,6 @@ void ripng_if_init () { /* Interface initialize. */ - iflist = list_new (); if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index acc980ded..d8f224112 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -34,6 +34,7 @@ #include "if.h" #include "privs.h" #include "sigevent.h" +#include "vrf.h" #include "ripngd/ripngd.h" @@ -276,6 +277,7 @@ main (int argc, char **argv) cmd_init (1); vty_init (master); memory_init (); + vrf_init (); /* RIPngd inits. */ ripng_init (); diff --git a/zebra/interface.c b/zebra/interface.c index 49d40ba37..3063dad81 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1634,7 +1634,6 @@ void zebra_if_init (void) { /* Initialize interface and new hook. */ - if_init (); if_add_hook (IF_NEW_HOOK, if_zebra_new_hook); if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook); diff --git a/zebra/test_main.c b/zebra/test_main.c index a92cd6189..aad616f7f 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -308,7 +308,6 @@ main (int argc, char **argv) cmd_init (1); vty_init (zebrad.master); memory_init (); - if_init(); zebra_debug_init (); zebra_if_init (); test_cmd_init (); From 5a5702fac5458d63d7a099c4db7ac387afefd2de Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:39:59 +0200 Subject: [PATCH 0734/1342] lib: move the interface list into "struct vrf" An interface belongs to a specific VRF. So move the interface list into the "struct vrf". * vrf.c/vrf.h: - add a new member "struct list *iflist" to the the "struct vrf"; - call if_init() in vrf_new(); - call if_terminate() in vrf_delete(); - add utilities to access the interface list and VRF ID in the specified VRF. * if.c/if.h: - the global "iflist" now only exists for the default VRF; - the global "if_master" is initialized on the definition; - in if_create(), the interface is added into the list in the specified VRF; if the VRF does not exist, create one; - add parameters to if_init()/if_terminate() so that the interface list in the VRF can be initialized/destroyed; - in if_dump_all() scan the interfaces in all the VRFs; - add a command "show address vrf N" to show addresses in a specified VRF; - add a command "show address vrf all" to show addresses in all VRFs; - new APIs ifxxx_vrf() are added to access an interface in a specified VRF. The old interface APIs (the global variable "iflist" and the API functions) are not changed to keep the backward compatibility. The new APIs are used in the daemons which support multiple VRFs (till now only zebra). Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- lib/if.c | 226 ++++++++++++++++++++++++++++++++++++++++++------------ lib/if.h | 33 +++++++- lib/vrf.c | 36 ++++++++- lib/vrf.h | 22 ++++++ 4 files changed, 259 insertions(+), 58 deletions(-) diff --git a/lib/if.c b/lib/if.c index f17e50863..30da8a9b1 100644 --- a/lib/if.c +++ b/lib/if.c @@ -27,6 +27,7 @@ #include "vector.h" #include "vty.h" #include "command.h" +#include "vrf.h" #include "if.h" #include "sockunion.h" #include "prefix.h" @@ -36,7 +37,7 @@ #include "str.h" #include "log.h" -/* Master list of interfaces. */ +/* List of interfaces in only the default VRF */ struct list *iflist; /* One for each program. This structure is needed to store hooks. */ @@ -44,7 +45,7 @@ struct if_master { int (*if_new_hook) (struct interface *); int (*if_delete_hook) (struct interface *); -} if_master; +} if_master = {0,}; /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the @@ -113,9 +114,10 @@ if_cmp_func (struct interface *ifp1, struct interface *ifp2) /* Create new interface structure. */ struct interface * -if_create (const char *name, int namelen) +if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id) { struct interface *ifp; + struct list *intf_list = vrf_iflist_get (vrf_id); ifp = XCALLOC (MTYPE_IF, sizeof (struct interface)); ifp->ifindex = IFINDEX_INTERNAL; @@ -124,11 +126,12 @@ if_create (const char *name, int namelen) assert (namelen <= INTERFACE_NAMSIZ); /* Need space for '\0' at end. */ strncpy (ifp->name, name, namelen); ifp->name[namelen] = '\0'; - if (if_lookup_by_name(ifp->name) == NULL) - listnode_add_sort (iflist, ifp); + ifp->vrf_id = vrf_id; + if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL) + listnode_add_sort (intf_list, ifp); else zlog_err("if_create(%s): corruption detected -- interface with this " - "name exists already!", ifp->name); + "name exists already in VRF %u!", ifp->name, vrf_id); ifp->connected = list_new (); ifp->connected->del = (void (*) (void *)) connected_free; @@ -138,6 +141,12 @@ if_create (const char *name, int namelen) return ifp; } +struct interface * +if_create (const char *name, int namelen) +{ + return if_create_vrf (name, namelen, VRF_DEFAULT); +} + /* Delete interface structure. */ void if_delete_retain (struct interface *ifp) @@ -153,7 +162,7 @@ if_delete_retain (struct interface *ifp) void if_delete (struct interface *ifp) { - listnode_delete (iflist, ifp); + listnode_delete (vrf_iflist (ifp->vrf_id), ifp); if_delete_retain(ifp); @@ -180,12 +189,12 @@ if_add_hook (int type, int (*func)(struct interface *ifp)) /* Interface existance check by index. */ struct interface * -if_lookup_by_index (unsigned int index) +if_lookup_by_index_vrf (unsigned int index, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; - for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { if (ifp->ifindex == index) return ifp; @@ -193,33 +202,51 @@ if_lookup_by_index (unsigned int index) return NULL; } +struct interface * +if_lookup_by_index (unsigned int index) +{ + return if_lookup_by_index_vrf (index, VRF_DEFAULT); +} + const char * -ifindex2ifname (unsigned int index) +ifindex2ifname_vrf (unsigned int index, vrf_id_t vrf_id) { struct interface *ifp; - return ((ifp = if_lookup_by_index(index)) != NULL) ? + return ((ifp = if_lookup_by_index_vrf (index, vrf_id)) != NULL) ? ifp->name : "unknown"; } +const char * +ifindex2ifname (unsigned int index) +{ + return ifindex2ifname_vrf (index, VRF_DEFAULT); +} + unsigned int -ifname2ifindex (const char *name) +ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id) { struct interface *ifp; - return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp->ifindex + return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp->ifindex : IFINDEX_INTERNAL; } +unsigned int +ifname2ifindex (const char *name) +{ + return ifname2ifindex_vrf (name, VRF_DEFAULT); +} + /* Interface existance check by interface name. */ struct interface * -if_lookup_by_name (const char *name) +if_lookup_by_name_vrf (const char *name, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; if (name) - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { if (strcmp(name, ifp->name) == 0) return ifp; @@ -228,7 +255,13 @@ if_lookup_by_name (const char *name) } struct interface * -if_lookup_by_name_len(const char *name, size_t namelen) +if_lookup_by_name (const char *name) +{ + return if_lookup_by_name_vrf (name, VRF_DEFAULT); +} + +struct interface * +if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; @@ -236,7 +269,7 @@ if_lookup_by_name_len(const char *name, size_t namelen) if (namelen > INTERFACE_NAMSIZ) return NULL; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0')) return ifp; @@ -244,9 +277,15 @@ if_lookup_by_name_len(const char *name, size_t namelen) return NULL; } +struct interface * +if_lookup_by_name_len(const char *name, size_t namelen) +{ + return if_lookup_by_name_len_vrf (name, namelen, VRF_DEFAULT); +} + /* Lookup interface by IPv4 address. */ struct interface * -if_lookup_exact_address (struct in_addr src) +if_lookup_exact_address_vrf (struct in_addr src, vrf_id_t vrf_id) { struct listnode *node; struct listnode *cnode; @@ -254,7 +293,7 @@ if_lookup_exact_address (struct in_addr src) struct prefix *p; struct connected *c; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { @@ -270,9 +309,15 @@ if_lookup_exact_address (struct in_addr src) return NULL; } +struct interface * +if_lookup_exact_address (struct in_addr src) +{ + return if_lookup_exact_address_vrf (src, VRF_DEFAULT); +} + /* Lookup interface by IPv4 address. */ struct interface * -if_lookup_address (struct in_addr src) +if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id) { struct listnode *node; struct prefix addr; @@ -288,7 +333,7 @@ if_lookup_address (struct in_addr src) match = NULL; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { @@ -304,16 +349,22 @@ if_lookup_address (struct in_addr src) return match; } +struct interface * +if_lookup_address (struct in_addr src) +{ + return if_lookup_address_vrf (src, VRF_DEFAULT); +} + /* Lookup interface by prefix */ struct interface * -if_lookup_prefix (struct prefix *prefix) +if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id) { struct listnode *node; struct listnode *cnode; struct interface *ifp; struct connected *c; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { @@ -326,24 +377,42 @@ if_lookup_prefix (struct prefix *prefix) return NULL; } +struct interface * +if_lookup_prefix (struct prefix *prefix) +{ + return if_lookup_prefix_vrf (prefix, VRF_DEFAULT); +} + /* Get interface by name if given name interface doesn't exist create one. */ struct interface * -if_get_by_name (const char *name) +if_get_by_name_vrf (const char *name, vrf_id_t vrf_id) { struct interface *ifp; - return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp : - if_create(name, strlen(name)); + return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp : + if_create_vrf (name, strlen(name), vrf_id); +} + +struct interface * +if_get_by_name (const char *name) +{ + return if_get_by_name_vrf (name, VRF_DEFAULT); } struct interface * -if_get_by_name_len(const char *name, size_t namelen) +if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id) { struct interface *ifp; - return ((ifp = if_lookup_by_name_len(name, namelen)) != NULL) ? ifp : - if_create(name, namelen); + return ((ifp = if_lookup_by_name_len_vrf (name, namelen, vrf_id)) != NULL) ? \ + ifp : if_create_vrf (name, namelen, vrf_id); +} + +struct interface * +if_get_by_name_len (const char *name, size_t namelen) +{ + return if_get_by_name_len_vrf (name, namelen, VRF_DEFAULT); } /* Does interface up ? */ @@ -470,11 +539,15 @@ if_dump (const struct interface *ifp) void if_dump_all (void) { + struct list *intf_list; struct listnode *node; void *p; + vrf_iter_t iter; - for (ALL_LIST_ELEMENTS_RO (iflist, node, p)) - if_dump (p); + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((intf_list = vrf_iter2iflist (iter)) != NULL) + for (ALL_LIST_ELEMENTS_RO (intf_list, node, p)) + if_dump (p); } DEFUN (interface_desc, @@ -534,12 +607,12 @@ DEFUN (no_interface_desc, * - no idea, just get the name in its entirety. */ static struct interface * -if_sunwzebra_get (const char *name, size_t nlen) +if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id) { struct interface *ifp; size_t seppos = 0; - if ( (ifp = if_lookup_by_name_len(name, nlen)) != NULL) + if ( (ifp = if_lookup_by_name_len_vrf (name, nlen, vrf_id)) != NULL) return ifp; /* hunt the primary interface name... */ @@ -548,9 +621,9 @@ if_sunwzebra_get (const char *name, size_t nlen) /* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */ if (seppos < nlen) - return if_get_by_name_len (name, seppos); + return if_get_by_name_len_vrf (name, seppos, vrf_id); else - return if_get_by_name_len (name, nlen); + return if_get_by_name_len_vrf (name, nlen, vrf_id); } #endif /* SUNOS_5 */ @@ -562,6 +635,7 @@ DEFUN (interface, { struct interface *ifp; size_t sl; + vrf_id_t vrf_id = VRF_DEFAULT; if ((sl = strlen(argv[0])) > INTERFACE_NAMSIZ) { @@ -572,9 +646,9 @@ DEFUN (interface, } #ifdef SUNOS_5 - ifp = if_sunwzebra_get (argv[0], sl); + ifp = if_sunwzebra_get (argv[0], sl, vrf_id); #else - ifp = if_get_by_name_len(argv[0], sl); + ifp = if_get_by_name_len_vrf (argv[0], sl, vrf_id); #endif /* SUNOS_5 */ vty->index = ifp; @@ -592,8 +666,9 @@ DEFUN_NOSH (no_interface, { // deleting interface struct interface *ifp; + vrf_id_t vrf_id = VRF_DEFAULT; - ifp = if_lookup_by_name (argv[0]); + ifp = if_lookup_by_name_vrf (argv[0], vrf_id); if (ifp == NULL) { @@ -625,8 +700,12 @@ DEFUN (show_address, struct interface *ifp; struct connected *ifc; struct prefix *p; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) { @@ -640,6 +719,52 @@ DEFUN (show_address, return CMD_SUCCESS; } +ALIAS (show_address, + show_address_vrf_cmd, + "show address " VRF_CMD_STR, + SHOW_STR + "address\n" + VRF_CMD_HELP_STR) + +DEFUN (show_address_vrf_all, + show_address_vrf_all_cmd, + "show address " VRF_ALL_CMD_STR, + SHOW_STR + "address\n" + VRF_ALL_CMD_HELP_STR) +{ + struct list *intf_list; + struct listnode *node; + struct listnode *node2; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + intf_list = vrf_iter2iflist (iter); + if (!intf_list || !listcount (intf_list)) + continue; + + vty_out (vty, "%sVRF %u%s%s", VTY_NEWLINE, vrf_iter2id (iter), + VTY_NEWLINE, VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (intf_list, node, ifp)) + { + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) + { + p = ifc->address; + + if (p->family == AF_INET) + vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen, + VTY_NEWLINE); + } + } + } + return CMD_SUCCESS; +} + /* Allocate connected structure. */ struct connected * connected_new (void) @@ -886,35 +1011,36 @@ ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) /* Initialize interface list. */ void -if_init (void) +if_init (vrf_id_t vrf_id, struct list **intf_list) { - iflist = list_new (); + *intf_list = list_new (); #if 0 ifaddr_ipv4_table = route_table_init (); #endif /* ifaddr_ipv4_table */ - if (iflist) { - iflist->cmp = (int (*)(void *, void *))if_cmp_func; - return; - } + (*intf_list)->cmp = (int (*)(void *, void *))if_cmp_func; - memset (&if_master, 0, sizeof if_master); + if (vrf_id == VRF_DEFAULT) + iflist = *intf_list; } void -if_terminate (void) +if_terminate (vrf_id_t vrf_id, struct list **intf_list) { for (;;) { struct interface *ifp; - ifp = listnode_head (iflist); + ifp = listnode_head (*intf_list); if (ifp == NULL) break; if_delete (ifp); } - list_delete (iflist); - iflist = NULL; + list_delete (*intf_list); + *intf_list = NULL; + + if (vrf_id == VRF_DEFAULT) + iflist = NULL; } diff --git a/lib/if.h b/lib/if.h index 029f57fd7..03bd52171 100644 --- a/lib/if.h +++ b/lib/if.h @@ -249,17 +249,38 @@ extern struct interface *if_lookup_exact_address (struct in_addr); extern struct interface *if_lookup_address (struct in_addr); extern struct interface *if_lookup_prefix (struct prefix *prefix); +extern struct interface *if_create_vrf (const char *name, int namelen, + vrf_id_t vrf_id); +extern struct interface *if_lookup_by_index_vrf (unsigned int, + vrf_id_t vrf_id); +extern struct interface *if_lookup_exact_address_vrf (struct in_addr, + vrf_id_t vrf_id); +extern struct interface *if_lookup_address_vrf (struct in_addr, + vrf_id_t vrf_id); +extern struct interface *if_lookup_prefix_vrf (struct prefix *prefix, + vrf_id_t vrf_id); + /* These 2 functions are to be used when the ifname argument is terminated by a '\0' character: */ extern struct interface *if_lookup_by_name (const char *ifname); extern struct interface *if_get_by_name (const char *ifname); +extern struct interface *if_lookup_by_name_vrf (const char *ifname, + vrf_id_t vrf_id); +extern struct interface *if_get_by_name_vrf (const char *ifname, + vrf_id_t vrf_id); + /* For these 2 functions, the namelen argument should be the precise length of the ifname string (not counting any optional trailing '\0' character). In most cases, strnlen should be used to calculate the namelen value. */ extern struct interface *if_lookup_by_name_len(const char *ifname, - size_t namelen); -extern struct interface *if_get_by_name_len(const char *ifname, size_t namelen); + size_t namelen); +extern struct interface *if_get_by_name_len(const char *ifname,size_t namelen); + +extern struct interface *if_lookup_by_name_len_vrf(const char *ifname, + size_t namelen, vrf_id_t vrf_id); +extern struct interface *if_get_by_name_len_vrf(const char *ifname, + size_t namelen, vrf_id_t vrf_id); /* Delete the interface, but do not free the structure, and leave it in the @@ -279,8 +300,8 @@ extern int if_is_broadcast (struct interface *); extern int if_is_pointopoint (struct interface *); extern int if_is_multicast (struct interface *); extern void if_add_hook (int, int (*)(struct interface *)); -extern void if_init (void); -extern void if_terminate (void); +extern void if_init (vrf_id_t, struct list **); +extern void if_terminate (vrf_id_t, struct list **); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); @@ -288,11 +309,13 @@ extern const char *if_flag_dump(unsigned long); ifindex2ifname uses internal interface info, whereas if_indextoname must make a system call. */ extern const char *ifindex2ifname (unsigned int); +extern const char *ifindex2ifname_vrf (unsigned int, vrf_id_t vrf_id); /* Please use ifname2ifindex instead of if_nametoindex where possible; ifname2ifindex uses internal interface info, whereas if_nametoindex must make a system call. */ extern unsigned int ifname2ifindex(const char *ifname); +extern unsigned int ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id); /* Connected address functions. */ extern struct connected *connected_new (void); @@ -322,5 +345,7 @@ extern struct cmd_element no_interface_cmd; extern struct cmd_element interface_pseudo_cmd; extern struct cmd_element no_interface_pseudo_cmd; extern struct cmd_element show_address_cmd; +extern struct cmd_element show_address_vrf_cmd; +extern struct cmd_element show_address_vrf_all_cmd; #endif /* _ZEBRA_IF_H */ diff --git a/lib/vrf.c b/lib/vrf.c index 51f9e3795..ea14fd3c6 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -36,6 +36,9 @@ struct vrf /* Name */ char *name; + /* Master list of interfaces belonging to this VRF */ + struct list *iflist; + /* User data */ void *info; }; @@ -80,6 +83,9 @@ vrf_get (vrf_id_t vrf_id) vrf->vrf_id = vrf_id; rn->info = vrf; + /* Initialize interfaces. */ + if_init (vrf_id, &vrf->iflist); + zlog_info ("VRF %u is created.", vrf_id); if (vrf_master.vrf_new_hook) @@ -97,6 +103,8 @@ vrf_delete (struct vrf *vrf) if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook) (vrf->vrf_id, &vrf->info); + if_terminate (vrf->vrf_id, &vrf->iflist); + if (vrf->name) XFREE (MTYPE_VRF_NAME, vrf->name); @@ -215,6 +223,14 @@ vrf_iter2info (vrf_iter_t iter) return (rn && rn->info) ? ((struct vrf *)rn->info)->info : NULL; } +/* Obtain the interface list from the given VRF iterator. */ +struct list * +vrf_iter2iflist (vrf_iter_t iter) +{ + struct route_node *rn = (struct route_node *) iter; + return (rn && rn->info) ? ((struct vrf *)rn->info)->iflist : NULL; +} + /* Get the data pointer of the specified VRF. If not found, create one. */ void * vrf_info_get (vrf_id_t vrf_id) @@ -231,6 +247,22 @@ vrf_info_lookup (vrf_id_t vrf_id) return vrf ? vrf->info : NULL; } +/* Look up the interface list in a VRF. */ +struct list * +vrf_iflist (vrf_id_t vrf_id) +{ + struct vrf * vrf = vrf_lookup (vrf_id); + return vrf ? vrf->iflist : NULL; +} + +/* Get the interface list of the specified VRF. Create one if not find. */ +struct list * +vrf_iflist_get (vrf_id_t vrf_id) +{ + struct vrf * vrf = vrf_get (vrf_id); + return vrf->iflist; +} + /* Initialize VRF module. */ void vrf_init (void) @@ -250,8 +282,6 @@ vrf_init (void) /* Set the default VRF name. */ default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, "Default-IP-Routing-Table"); - - if_init (); } /* Terminate VRF module. */ @@ -267,7 +297,5 @@ vrf_terminate (void) route_table_finish (vrf_table); vrf_table = NULL; - - if_terminate (); } diff --git a/lib/vrf.h b/lib/vrf.h index 7e0509943..d7b799875 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -23,9 +23,21 @@ #ifndef _ZEBRA_VRF_H #define _ZEBRA_VRF_H +#include "linklist.h" + /* The default VRF ID */ #define VRF_DEFAULT 0 +/* + * The command strings + */ + +#define VRF_CMD_STR "vrf <0-65535>" +#define VRF_CMD_HELP_STR "Specify the VRF\nThe VRF ID\n" + +#define VRF_ALL_CMD_STR "vrf all" +#define VRF_ALL_CMD_HELP_STR "Specify the VRF\nAll VRFs\n" + /* * VRF hooks */ @@ -75,6 +87,7 @@ extern vrf_iter_t vrf_iterator (vrf_id_t); */ extern vrf_id_t vrf_iter2id (vrf_iter_t); extern void *vrf_iter2info (vrf_iter_t); +extern struct list *vrf_iter2iflist (vrf_iter_t); /* * Utilities to obtain the user data @@ -85,6 +98,15 @@ extern void *vrf_info_get (vrf_id_t); /* Look up the data pointer of the specified VRF. */ extern void *vrf_info_lookup (vrf_id_t); +/* + * Utilities to obtain the interface list + */ + +/* Look up the interface list of the specified VRF. */ +extern struct list *vrf_iflist (vrf_id_t); +/* Get the interface list of the specified VRF. Create one if not find. */ +extern struct list *vrf_iflist_get (vrf_id_t); + /* * VRF initializer/destructor */ From 471ea39ce54537194ff2f22420589ddec5ef5ada Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:00 +0200 Subject: [PATCH 0735/1342] lib, zebra, vtysh: configure an interface in non-default VRF Introduce a new command "interface IFNAME vrf N" to configure an interface in the non-default VRF. Till now, only zebra uses this command. Other daemons will install the command when they support multiple VRFs. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- lib/if.c | 21 +++++++++++++++++++++ lib/if.h | 2 ++ vtysh/extract.pl.in | 1 + vtysh/vtysh.c | 19 +++++++++++++++++++ zebra/interface.c | 23 +++++++++++++++++++---- 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/lib/if.c b/lib/if.c index 30da8a9b1..4d4b6564b 100644 --- a/lib/if.c +++ b/lib/if.c @@ -645,6 +645,9 @@ DEFUN (interface, return CMD_WARNING; } + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + #ifdef SUNOS_5 ifp = if_sunwzebra_get (argv[0], sl, vrf_id); #else @@ -657,6 +660,13 @@ DEFUN (interface, return CMD_SUCCESS; } +ALIAS (interface, + interface_vrf_cmd, + "interface IFNAME " VRF_CMD_STR, + "Select an interface to configure\n" + "Interface's name\n" + VRF_CMD_HELP_STR) + DEFUN_NOSH (no_interface, no_interface_cmd, "no interface IFNAME", @@ -668,6 +678,9 @@ DEFUN_NOSH (no_interface, struct interface *ifp; vrf_id_t vrf_id = VRF_DEFAULT; + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + ifp = if_lookup_by_name_vrf (argv[0], vrf_id); if (ifp == NULL) @@ -688,6 +701,14 @@ DEFUN_NOSH (no_interface, return CMD_SUCCESS; } +ALIAS (no_interface, + no_interface_vrf_cmd, + "no interface IFNAME " VRF_CMD_STR, + NO_STR + "Delete a pseudo interface's configuration\n" + "Interface's name\n" + VRF_CMD_HELP_STR) + /* For debug purpose. */ DEFUN (show_address, show_address_cmd, diff --git a/lib/if.h b/lib/if.h index 03bd52171..ad85dcad7 100644 --- a/lib/if.h +++ b/lib/if.h @@ -342,6 +342,8 @@ extern struct cmd_element interface_desc_cmd; extern struct cmd_element no_interface_desc_cmd; extern struct cmd_element interface_cmd; extern struct cmd_element no_interface_cmd; +extern struct cmd_element interface_vrf_cmd; +extern struct cmd_element no_interface_vrf_cmd; extern struct cmd_element interface_pseudo_cmd; extern struct cmd_element no_interface_pseudo_cmd; extern struct cmd_element show_address_cmd; diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 99d80ed4a..f057e2492 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -31,6 +31,7 @@ print <"'} = "ignore"; $ignore{'"ip vrf NAME"'} = "ignore"; $ignore{'"router rip"'} = "ignore"; $ignore{'"router ripng"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b33ac90bd..04ac55094 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -35,6 +35,7 @@ #include "vtysh/vtysh.h" #include "log.h" #include "bgpd/bgp_vty.h" +#include "vrf.h" /* Struct VTY. */ struct vty *vty; @@ -1296,6 +1297,14 @@ DEFUNSH (VTYSH_INTERFACE, return CMD_SUCCESS; } +ALIAS_SH (VTYSH_ZEBRA, + vtysh_interface, + vtysh_interface_vrf_cmd, + "interface IFNAME " VRF_CMD_STR, + "Select an interface to configure\n" + "Interface's name\n" + VRF_CMD_HELP_STR) + /* TODO Implement "no interface command in isisd. */ DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D, vtysh_no_interface_cmd, @@ -1304,6 +1313,14 @@ DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D, "Delete a pseudo interface's configuration\n" "Interface's name\n") +DEFSH (VTYSH_ZEBRA, + vtysh_no_interface_vrf_cmd, + "no interface IFNAME " VRF_CMD_STR, + NO_STR + "Delete a pseudo interface's configuration\n" + "Interface's name\n" + VRF_CMD_HELP_STR) + /* TODO Implement interface description commands in ripngd, ospf6d * and isisd. */ DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD, @@ -2381,6 +2398,8 @@ vtysh_init_vty (void) install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd); install_element (CONFIG_NODE, &vtysh_interface_cmd); install_element (CONFIG_NODE, &vtysh_no_interface_cmd); + install_element (CONFIG_NODE, &vtysh_interface_vrf_cmd); + install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_cmd); install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); install_element (ENABLE_NODE, &vtysh_write_file_cmd); diff --git a/zebra/interface.c b/zebra/interface.c index 3063dad81..527893be1 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -32,6 +32,7 @@ #include "connected.h" #include "log.h" #include "zclient.h" +#include "vrf.h" #include "zebra/interface.h" #include "zebra/rtadv.h" @@ -914,6 +915,13 @@ DEFUN_NOSH (zebra_interface, return ret; } +ALIAS (zebra_interface, + zebra_interface_vrf_cmd, + "interface IFNAME " VRF_CMD_STR, + "Select an interface to configure\n" + "Interface's name\n" + VRF_CMD_HELP_STR) + struct cmd_node interface_node = { INTERFACE_NODE, @@ -1558,8 +1566,10 @@ if_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; + vrf_iter_t iter; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp)) { struct zebra_if *if_data; struct listnode *addrnode; @@ -1567,9 +1577,12 @@ if_config_write (struct vty *vty) struct prefix *p; if_data = ifp->info; - - vty_out (vty, "interface %s%s", ifp->name, - VTY_NEWLINE); + + if (ifp->vrf_id == VRF_DEFAULT) + vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); + else + vty_out (vty, "interface %s vrf %u%s", ifp->name, ifp->vrf_id, + VTY_NEWLINE); if (if_data) { @@ -1644,7 +1657,9 @@ zebra_if_init (void) install_element (ENABLE_NODE, &show_interface_cmd); install_element (ENABLE_NODE, &show_interface_desc_cmd); install_element (CONFIG_NODE, &zebra_interface_cmd); + install_element (CONFIG_NODE, &zebra_interface_vrf_cmd); install_element (CONFIG_NODE, &no_interface_cmd); + install_element (CONFIG_NODE, &no_interface_vrf_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); From a2854770ff839553c9444193e84a1593645fa848 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:01 +0200 Subject: [PATCH 0736/1342] zebra: show interfaces in a specified VRF or all VRFs The following commands only show interfaces in the default VRF: show interface show interface IFNAME show interface description New options are introduced to show interfaces in a specified VRF: show interface vrf N show interface IFNAME vrf N show interface description vrf N or all VRFs: show interface vrf all show interface IFNAME vrf all show interface description vrf all Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/interface.c | 209 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 186 insertions(+), 23 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 527893be1..25657e831 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -929,16 +929,53 @@ struct cmd_node interface_node = 1 }; -/* Show all or specified interface to vty. */ +/* Show all interfaces to vty. */ DEFUN (show_interface, show_interface_cmd, - "show interface [IFNAME]", + "show interface", + SHOW_STR + "Interface status and configuration\n") +{ + struct listnode *node; + struct interface *ifp; + vrf_id_t vrf_id = VRF_DEFAULT; + +#ifdef HAVE_PROC_NET_DEV + /* If system has interface statistics via proc file system, update + statistics. */ + ifstat_update_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST + ifstat_update_sysctl (); +#endif /* HAVE_NET_RT_IFLIST */ + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + /* All interface print. */ + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) + if_dump_vty (vty, ifp); + + return CMD_SUCCESS; +} + +ALIAS (show_interface, + show_interface_vrf_cmd, + "show interface " VRF_CMD_STR, SHOW_STR "Interface status and configuration\n" - "Inteface name\n") + VRF_CMD_HELP_STR) + +/* Show all interfaces to vty. */ +DEFUN (show_interface_vrf_all, show_interface_vrf_all_cmd, + "show interface " VRF_ALL_CMD_STR, + SHOW_STR + "Interface status and configuration\n" + VRF_ALL_CMD_HELP_STR) { struct listnode *node; struct interface *ifp; - + vrf_iter_t iter; + #ifdef HAVE_PROC_NET_DEV /* If system has interface statistics via proc file system, update statistics. */ @@ -948,39 +985,107 @@ DEFUN (show_interface, show_interface_cmd, ifstat_update_sysctl (); #endif /* HAVE_NET_RT_IFLIST */ + /* All interface print. */ + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp)) + if_dump_vty (vty, ifp); + + return CMD_SUCCESS; +} + +/* Show specified interface to vty. */ +DEFUN (show_interface_name, show_interface_name_cmd, + "show interface IFNAME", + SHOW_STR + "Interface status and configuration\n" + "Inteface name\n") +{ + struct interface *ifp; + vrf_id_t vrf_id = VRF_DEFAULT; + +#ifdef HAVE_PROC_NET_DEV + /* If system has interface statistics via proc file system, update + statistics. */ + ifstat_update_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST + ifstat_update_sysctl (); +#endif /* HAVE_NET_RT_IFLIST */ + + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + /* Specified interface print. */ - if (argc != 0) + ifp = if_lookup_by_name_vrf (argv[0], vrf_id); + if (ifp == NULL) { - ifp = if_lookup_by_name (argv[0]); - if (ifp == NULL) - { - vty_out (vty, "%% Can't find interface %s%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - if_dump_vty (vty, ifp); - return CMD_SUCCESS; + vty_out (vty, "%% Can't find interface %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; } - - /* All interface print. */ - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) - if_dump_vty (vty, ifp); + if_dump_vty (vty, ifp); return CMD_SUCCESS; } -DEFUN (show_interface_desc, - show_interface_desc_cmd, - "show interface description", +ALIAS (show_interface_name, + show_interface_name_vrf_cmd, + "show interface IFNAME " VRF_CMD_STR, SHOW_STR "Interface status and configuration\n" - "Interface description\n") + "Inteface name\n" + VRF_CMD_HELP_STR) + +/* Show specified interface to vty. */ +DEFUN (show_interface_name_vrf_all, show_interface_name_vrf_all_cmd, + "show interface IFNAME " VRF_ALL_CMD_STR, + SHOW_STR + "Interface status and configuration\n" + "Inteface name\n" + VRF_ALL_CMD_HELP_STR) +{ + struct interface *ifp; + vrf_iter_t iter; + int found = 0; + +#ifdef HAVE_PROC_NET_DEV + /* If system has interface statistics via proc file system, update + statistics. */ + ifstat_update_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST + ifstat_update_sysctl (); +#endif /* HAVE_NET_RT_IFLIST */ + + /* All interface print. */ + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + /* Specified interface print. */ + ifp = if_lookup_by_name_vrf (argv[0], vrf_iter2id (iter)); + if (ifp) + { + if_dump_vty (vty, ifp); + found++; + } + } + + if (!found) + { + vty_out (vty, "%% Can't find interface %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +static void +if_show_description (struct vty *vty, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; vty_out (vty, "Interface Status Protocol Description%s", VTY_NEWLINE); - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { int len; @@ -1011,6 +1116,52 @@ DEFUN (show_interface_desc, vty_out (vty, "%s", ifp->desc); vty_out (vty, "%s", VTY_NEWLINE); } +} + +DEFUN (show_interface_desc, + show_interface_desc_cmd, + "show interface description", + SHOW_STR + "Interface status and configuration\n" + "Interface description\n") +{ + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + if_show_description (vty, vrf_id); + + return CMD_SUCCESS; +} + +ALIAS (show_interface_desc, + show_interface_desc_vrf_cmd, + "show interface description " VRF_CMD_STR, + SHOW_STR + "Interface status and configuration\n" + "Interface description\n" + VRF_CMD_HELP_STR) + +DEFUN (show_interface_desc_vrf_all, + show_interface_desc_vrf_all_cmd, + "show interface description " VRF_ALL_CMD_STR, + SHOW_STR + "Interface status and configuration\n" + "Interface description\n" + VRF_ALL_CMD_HELP_STR) +{ + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if (!list_isempty (vrf_iter2iflist (iter))) + { + vty_out (vty, "%s\tVRF %u%s%s", VTY_NEWLINE, + vrf_iter2id (iter), + VTY_NEWLINE, VTY_NEWLINE); + if_show_description (vty, vrf_iter2id (iter)); + } + return CMD_SUCCESS; } @@ -1654,8 +1805,20 @@ zebra_if_init (void) install_node (&interface_node, if_config_write); install_element (VIEW_NODE, &show_interface_cmd); + install_element (VIEW_NODE, &show_interface_vrf_cmd); + install_element (VIEW_NODE, &show_interface_vrf_all_cmd); + install_element (VIEW_NODE, &show_interface_name_cmd); + install_element (VIEW_NODE, &show_interface_name_vrf_cmd); + install_element (VIEW_NODE, &show_interface_name_vrf_all_cmd); install_element (ENABLE_NODE, &show_interface_cmd); + install_element (ENABLE_NODE, &show_interface_vrf_cmd); + install_element (ENABLE_NODE, &show_interface_vrf_all_cmd); + install_element (ENABLE_NODE, &show_interface_name_cmd); + install_element (ENABLE_NODE, &show_interface_name_vrf_cmd); + install_element (ENABLE_NODE, &show_interface_name_vrf_all_cmd); install_element (ENABLE_NODE, &show_interface_desc_cmd); + install_element (ENABLE_NODE, &show_interface_desc_vrf_cmd); + install_element (ENABLE_NODE, &show_interface_desc_vrf_all_cmd); install_element (CONFIG_NODE, &zebra_interface_cmd); install_element (CONFIG_NODE, &zebra_interface_vrf_cmd); install_element (CONFIG_NODE, &no_interface_cmd); From 0d0686f98e64017415071e590bde262f0ab5a4c9 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:02 +0200 Subject: [PATCH 0737/1342] zebra: let FIB stand for its respective VRF A new member "vrf_id" is added to "struct rib", reflecting the VRF which it belongs to. A new parameter "vrf_id" is added to the relative functions where need, except those: - which already have the parameter "vrf_id"; or - which have a parameter in type of "struct rib"; or - which have a parameter in type of "struct interface". All incoming routes are set to default VRF. In fact, all routes in FIB are kept in default VRF. And the logic is not changed. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN [DL: conflicts fixed + compile warning fix] Signed-off-by: David Lamparter --- zebra/connected.c | 29 +++--- zebra/interface.c | 4 +- zebra/kernel_socket.c | 24 ++--- zebra/rib.h | 38 ++++---- zebra/rt_netlink.c | 22 +++-- zebra/rtread_getmsg.c | 4 +- zebra/zebra_rib.c | 211 ++++++++++++++++++++++++++---------------- zebra/zebra_vty.c | 18 ++-- zebra/zserv.c | 30 +++--- 9 files changed, 229 insertions(+), 151 deletions(-) diff --git a/zebra/connected.c b/zebra/connected.c index 2db981b38..244f29115 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -192,12 +192,12 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) return; rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); + ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); + ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); - rib_update (); + rib_update (ifp->vrf_id); } /* Add connected IPv4 route to the interface. */ @@ -304,11 +304,13 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) return; /* Same logic as for connected_up_ipv4(): push the changes into the head. */ - rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, + SAFI_UNICAST); - rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_MULTICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, + SAFI_MULTICAST); - rib_update (); + rib_update (ifp->vrf_id); } /* Delete connected IPv4 route to the interface. */ @@ -330,7 +332,7 @@ connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, connected_withdraw (ifc); - rib_update(); + rib_update (ifp->vrf_id); } #ifdef HAVE_IPV6 @@ -353,10 +355,10 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) return; #endif - rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN, - ifp->metric, 0, SAFI_UNICAST); + rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, + RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); - rib_update (); + rib_update (ifp->vrf_id); } /* Add connected IPv6 route to the interface. */ @@ -436,9 +438,10 @@ connected_down_ipv6 (struct interface *ifp, struct connected *ifc) if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; - rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST); + rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, + SAFI_UNICAST); - rib_update (); + rib_update (ifp->vrf_id); } void @@ -459,6 +462,6 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, connected_withdraw (ifc); - rib_update(); + rib_update (ifp->vrf_id); } #endif /* HAVE_IPV6 */ diff --git a/zebra/interface.c b/zebra/interface.c index 25657e831..14c3e78ae 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -555,7 +555,7 @@ if_up (struct interface *ifp) } /* Examine all static routes. */ - rib_update (); + rib_update (ifp->vrf_id); } /* Interface goes down. We have to manage different behavior of based @@ -588,7 +588,7 @@ if_down (struct interface *ifp) } /* Examine all static routes which direct to the interface. */ - rib_update (); + rib_update (ifp->vrf_id); } void diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index fefccdceb..bdfb148db 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -32,6 +32,7 @@ #include "table.h" #include "rib.h" #include "privs.h" +#include "vrf.h" #include "zebra/interface.h" #include "zebra/zserv.h" @@ -890,7 +891,7 @@ rtm_read (struct rt_msghdr *rtm) int ret; if (! IS_ZEBRA_DEBUG_RIB) return; - ret = rib_lookup_ipv4_route (&p, &gate); + ret = rib_lookup_ipv4_route (&p, &gate, VRF_DEFAULT); prefix2str (&p, buf, sizeof(buf)); switch (rtm->rtm_type) { @@ -955,16 +956,16 @@ rtm_read (struct rt_msghdr *rtm) */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, - NULL, 0, 0, SAFI_UNICAST); + NULL, 0, VRF_DEFAULT, SAFI_UNICAST); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, SAFI_UNICAST); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, + NULL, 0, VRF_DEFAULT, rtm->rtm_table, 0, 0, SAFI_UNICAST); else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin.sin_addr, 0, 0, SAFI_UNICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, + &gate.sin.sin_addr, 0, VRF_DEFAULT, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) @@ -997,16 +998,17 @@ rtm_read (struct rt_msghdr *rtm) */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, - NULL, 0, 0, SAFI_UNICAST); + NULL, 0, VRF_DEFAULT, SAFI_UNICAST); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0, SAFI_UNICAST); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, + ifindex, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, SAFI_UNICAST); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin6.sin6_addr, ifindex, 0, SAFI_UNICAST); + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, + &gate.sin6.sin6_addr, ifindex, + VRF_DEFAULT, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ } diff --git a/zebra/rib.h b/zebra/rib.h index 802d875f8..2d8805a88 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -56,6 +56,9 @@ struct rib /* Type fo this route. */ int type; + /* VRF identifier. */ + vrf_id_t vrf_id; + /* Which routing table */ int table; @@ -404,7 +407,8 @@ extern void rib_lookup_and_pushup (struct prefix_ipv4 *); #define rib_dump(prefix ,rib) _rib_dump(__func__, prefix, rib) extern void _rib_dump (const char *, union prefix46constptr, const struct rib *); -extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *); +extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, + vrf_id_t); #define ZEBRA_RIB_LOOKUP_ERROR -1 #define ZEBRA_RIB_FOUND_EXACT 0 #define ZEBRA_RIB_FOUND_NOGATE 1 @@ -424,23 +428,25 @@ extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); * also implicitly withdraw equal prefix of same type. */ extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, u_int32_t vrf_id, + unsigned int ifindex, vrf_id_t vrf_id, int table_id, u_int32_t, u_char, safi_t); extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t); extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, - u_int32_t, safi_t safi); + vrf_id_t, safi_t safi); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, - int skip_bgp, struct route_node **rn_out); + int skip_bgp, struct route_node **rn_out, + vrf_id_t); extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, - struct route_node **rn_out); + struct route_node **rn_out, + vrf_id_t); -extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); +extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *, vrf_id_t); -extern void rib_update (void); +extern void rib_update (vrf_id_t); extern void rib_weed_tables (void); extern void rib_sweep_route (void); extern void rib_close (void); @@ -450,35 +456,35 @@ extern unsigned long rib_score_proto (u_char proto); extern int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, u_char flags, u_char distance, - u_int32_t vrf_id); + vrf_id_t vrf_id); extern int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char distance, u_int32_t vrf_id); + const char *ifname, u_char distance, vrf_id_t vrf_id); #ifdef HAVE_IPV6 extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, - u_int32_t metric, u_char distance, safi_t safi); + struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, + int table_id, u_int32_t metric, u_char distance, safi_t safi); extern int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi); + struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, safi_t safi); -extern struct rib *rib_lookup_ipv6 (struct in6_addr *); +extern struct rib *rib_lookup_ipv6 (struct in6_addr *, vrf_id_t); -extern struct rib *rib_match_ipv6 (struct in6_addr *); +extern struct rib *rib_match_ipv6 (struct in6_addr *, vrf_id_t); extern struct route_table *rib_table_ipv6; extern int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, u_char distance, - u_int32_t vrf_id); + vrf_id_t vrf_id); extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, u_int32_t vrf_id); + const char *ifname, u_char distance, vrf_id_t vrf_id); #endif /* HAVE_IPV6 */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 45ebf20ec..cf6ce0cde 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -36,6 +36,7 @@ #include "rib.h" #include "thread.h" #include "privs.h" +#include "vrf.h" #include "zebra/zserv.h" #include "zebra/rt.h" @@ -743,7 +744,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, - table, metric, 0, SAFI_UNICAST); + VRF_DEFAULT, table, metric, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -759,6 +760,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) rib->distance = 0; rib->flags = flags; rib->metric = metric; + rib->vrf_id = VRF_DEFAULT; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -808,8 +810,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, - metric, 0, SAFI_UNICAST); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, VRF_DEFAULT, + table, metric, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -942,8 +944,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (h->nlmsg_type == RTM_NEWROUTE) { if (!tb[RTA_MULTIPATH]) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, - metric, 0, SAFI_UNICAST); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, VRF_DEFAULT, + table, metric, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -959,6 +961,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) rib->distance = 0; rib->flags = 0; rib->metric = metric; + rib->vrf_id = VRF_DEFAULT; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -1001,7 +1004,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } } else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, + SAFI_UNICAST); } #ifdef HAVE_IPV6 @@ -1022,9 +1026,11 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, table, + metric, 0, SAFI_UNICAST); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, + SAFI_UNICAST); } #endif /* HAVE_IPV6 */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 81bf0de64..83ef64832 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -25,6 +25,7 @@ #include "prefix.h" #include "log.h" #include "if.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -90,7 +91,8 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry) gateway.s_addr = routeEntry->ipRouteNextHop; rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, - &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST); + &gateway, NULL, 0, VRF_DEFAULT, RT_TABLE_MAIN, + 0, 0, SAFI_UNICAST); } void diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f206205b0..336b56627 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -80,7 +80,7 @@ static void __attribute__((format (printf, 4, 5))) _rnode_zlog(const char *_func, struct route_node *rn, int priority, const char *msgfmt, ...) { - char buf[PREFIX_STRLEN + 8]; + char prefix[PREFIX_STRLEN], buf[256]; char msgbuf[512]; va_list ap; @@ -92,9 +92,10 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, { rib_table_info_t *info = rn->table->info; - prefix2str(&rn->p, buf, sizeof(buf)); - if (info->safi == SAFI_MULTICAST) - strcat(buf, " (MRIB)"); + snprintf(buf, sizeof(buf), "%s%s vrf %u", + prefix2str(&rn->p, prefix, sizeof(prefix)), + info->safi == SAFI_MULTICAST ? " (MRIB)" : "", + info->zvrf->vrf_id); } else { @@ -369,7 +370,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, p.prefix = nexthop->gate.ipv4; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, rib->vrf_id); if (! table) return 0; @@ -511,7 +512,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, p.prefix = nexthop->gate.ipv6; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, rib->vrf_id); if (! table) return 0; @@ -618,7 +619,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct rib * rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, - struct route_node **rn_out) + struct route_node **rn_out, vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; @@ -627,7 +628,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, int recursing; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; @@ -680,7 +681,8 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, } struct rib * -rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) +rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, + vrf_id_t vrf_id) { struct rib *rib = NULL, *mrib = NULL, *urib = NULL; struct route_node *m_rn = NULL, *u_rn = NULL; @@ -689,18 +691,24 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) switch (ipv4_multicast_mode) { case MCAST_MRIB_ONLY: - return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out); + return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out, + vrf_id); case MCAST_URIB_ONLY: - return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out); + return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out, + vrf_id); case MCAST_NO_CONFIG: case MCAST_MIX_MRIB_FIRST: - rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, + vrf_id); if (!mrib) - rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, + vrf_id); break; case MCAST_MIX_DISTANCE: - mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); - urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, + vrf_id); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, + vrf_id); if (mrib && urib) rib = urib->distance < mrib->distance ? urib : mrib; else if (mrib) @@ -709,8 +717,10 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) rib = urib; break; case MCAST_MIX_PFXLEN: - mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn); - urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn); + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, + vrf_id); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, + vrf_id); if (mrib && urib) rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; else if (mrib) @@ -728,8 +738,8 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) char buf[BUFSIZ]; inet_ntop (AF_INET, &addr, buf, BUFSIZ); - zlog_debug("%s: %s: found %s, using %s", - __func__, buf, + zlog_debug("%s: %s vrf %u: found %s, using %s", + __func__, buf, vrf_id, mrib ? (urib ? "MRIB+URIB" : "MRIB") : urib ? "URIB" : "nothing", rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none"); @@ -752,7 +762,7 @@ multicast_mode_ipv4_get (void) } struct rib * -rib_lookup_ipv4 (struct prefix_ipv4 *p) +rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; @@ -761,7 +771,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) int recursing; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return 0; @@ -808,7 +818,8 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) * 3: no matches found */ int -rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) +rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, + vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; @@ -818,7 +829,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) int nexthops_active; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return ZEBRA_RIB_LOOKUP_ERROR; @@ -874,7 +885,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) #ifdef HAVE_IPV6 struct rib * -rib_match_ipv6 (struct in6_addr *addr) +rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) { struct prefix_ipv6 p; struct route_table *table; @@ -884,7 +895,7 @@ rib_match_ipv6 (struct in6_addr *addr) int recursing; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return 0; @@ -965,7 +976,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - ifp = if_lookup_by_index (nexthop->ifindex); + ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -974,7 +985,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, case NEXTHOP_TYPE_IPV6_IFNAME: family = AFI_IP6; case NEXTHOP_TYPE_IFNAME: - ifp = if_lookup_by_name (nexthop->ifname); + ifp = if_lookup_by_name_vrf (nexthop->ifname, rib->vrf_id); if (ifp && if_is_operative(ifp)) { if (set) @@ -1008,7 +1019,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, family = AFI_IP6; if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) { - ifp = if_lookup_by_index (nexthop->ifindex); + ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -1793,7 +1804,7 @@ rib_delnode (struct route_node *rn, struct rib *rib) int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, u_int32_t vrf_id, + unsigned int ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_char distance, safi_t safi) { struct rib *rib; @@ -1803,7 +1814,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct nexthop *nexthop; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; @@ -1857,7 +1868,8 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; - rib->table = vrf_id; + rib->vrf_id = vrf_id; + rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -1909,8 +1921,8 @@ void _rib_dump (const char * func, struct nexthop *nexthop, *tnexthop; int recursing; - zlog_debug ("%s: dumping RIB entry %p for %s", func, (void *)rib, - prefix2str(p, straddr, sizeof(straddr))); + zlog_debug ("%s: dumping RIB entry %p for %s vrf %u", func, (void *)rib, + prefix2str(p, straddr, sizeof(straddr)), rib->vrf_id); zlog_debug ( "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", @@ -2065,7 +2077,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) struct nexthop *nexthop; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id); if (! table) return 0; @@ -2131,7 +2143,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) + struct in_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -2144,7 +2156,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; @@ -2154,13 +2166,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("rib_delete_ipv4(): route delete %s via %s ifindex %d", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u via %s ifindex %d", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntoa (*gate), ifindex); else - zlog_debug ("rib_delete_ipv4(): route delete %s ifindex %d", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u ifindex %d", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } @@ -2171,13 +2183,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s via %s ifindex %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex); else - zlog_debug ("route %s ifindex %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } return ZEBRA_ERR_RTNOEXIST; @@ -2244,14 +2256,15 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s via %s ifindex %d type %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u via %s ifindex %d type %d " + "doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex, type); else - zlog_debug ("route %s ifindex %d type %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex, type); } @@ -2318,6 +2331,7 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; + rib->vrf_id = VRF_DEFAULT; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; @@ -2423,7 +2437,7 @@ static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, u_char flags, u_char distance, - u_int32_t vrf_id) + vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2431,10 +2445,9 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, struct static_ipv4 *pp; struct static_ipv4 *cp; struct static_ipv4 *update = NULL; - struct route_table *stable; + struct zebra_vrf *zvrf = vrf_info_get (vrf_id); + struct route_table *stable = zvrf->stable[AFI_IP][safi]; - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2517,7 +2530,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char distance, u_int32_t vrf_id) + const char *ifname, u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2581,7 +2594,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, #ifdef HAVE_IPV6 int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, + struct in6_addr *gate, unsigned int ifindex, + vrf_id_t vrf_id, int table_id, u_int32_t metric, u_char distance, safi_t safi) { struct rib *rib; @@ -2591,7 +2605,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, safi, vrf_id); if (! table) return 0; @@ -2638,7 +2652,8 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; - rib->table = vrf_id; + rib->vrf_id = vrf_id; + rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -2686,7 +2701,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) + struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -2702,7 +2717,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, apply_mask_ipv6 (p); /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, safi, vrf_id); if (! table) return 0; @@ -2713,13 +2728,13 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s via %s ifindex %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex); else - zlog_debug ("route %s ifindex %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } return ZEBRA_ERR_RTNOEXIST; @@ -2787,14 +2802,15 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s via %s ifindex %d type %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u via %s ifindex %d type %d " + "doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex, type); else - zlog_debug ("route %s ifindex %d type %d doesn't exist in rib", - prefix2str (p, buf1, sizeof(buf1)), + zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex, type); } @@ -2862,6 +2878,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; + rib->vrf_id = VRF_DEFAULT; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; @@ -2971,16 +2988,15 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, u_char distance, - u_int32_t vrf_id) + vrf_id_t vrf_id) { struct route_node *rn; struct static_ipv6 *si; struct static_ipv6 *pp; struct static_ipv6 *cp; - struct route_table *stable; + struct zebra_vrf *zvrf = vrf_info_get (vrf_id); + struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]; - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! stable) return -1; @@ -3058,7 +3074,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Delete static route from static route configuration. */ int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, u_int32_t vrf_id) + const char *ifname, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_ipv6 *si; @@ -3111,18 +3127,18 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* RIB update function. */ void -rib_update (void) +rib_update (vrf_id_t vrf_id) { struct route_node *rn; struct route_table *table; - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) @@ -3155,10 +3171,18 @@ rib_weed_table (struct route_table *table) void rib_weed_tables (void) { - rib_weed_table (zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)); - rib_weed_table (zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); + vrf_iter_t iter; + struct zebra_vrf *zvrf; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + { + rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]); + rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); + } } +#if 0 /* Delete self installed routes after zebra is relaunched. */ static void rib_sweep_table (struct route_table *table) @@ -3184,13 +3208,21 @@ rib_sweep_table (struct route_table *table) } } } +#endif /* Sweep all RIB tables. */ void rib_sweep_route (void) { - rib_sweep_table (zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)); - rib_sweep_table (zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); + vrf_iter_t iter; + struct zebra_vrf *zvrf; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + { + rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]); + rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); + } } /* Remove specific by protocol routes from 'table'. */ @@ -3222,8 +3254,16 @@ rib_score_proto_table (u_char proto, struct route_table *table) unsigned long rib_score_proto (u_char proto) { - return rib_score_proto_table (proto, zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)) - +rib_score_proto_table (proto, zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); + vrf_iter_t iter; + struct zebra_vrf *zvrf; + unsigned long cnt = 0; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + cnt += rib_score_proto_table (proto, zvrf->table[AFI_IP][SAFI_UNICAST]) + +rib_score_proto_table (proto, zvrf->table[AFI_IP6][SAFI_UNICAST]); + + return cnt; } /* Close RIB and clean up kernel routes. */ @@ -3253,8 +3293,15 @@ rib_close_table (struct route_table *table) void rib_close (void) { - rib_close_table (zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)); - rib_close_table (zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT)); + vrf_iter_t iter; + struct zebra_vrf *zvrf; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + { + rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); + rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); + } } /* Routing information base initialize. */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a4e6af78c..78e73669b 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -285,7 +285,7 @@ DEFUN (show_ip_rpf_addr, return CMD_WARNING; } - rib = rib_match_ipv4_multicast (addr, &rn); + rib = rib_match_ipv4_multicast (addr, &rn, VRF_DEFAULT); if (rib) vty_show_ip_route_detail (vty, rn, 1); @@ -771,7 +771,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4)); if (nexthop->ifindex) - vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + vty_out (vty, ", via %s", + ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -781,11 +782,12 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) vty_out (vty, ", %s", nexthop->ifname); else if (nexthop->ifindex) - vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + vty_out (vty, ", via %s", + ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " directly connected, %s", - ifindex2ifname (nexthop->ifindex)); + ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " directly connected, %s", nexthop->ifname); @@ -876,7 +878,8 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); if (nexthop->ifindex) - vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + vty_out (vty, ", %s", + ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -886,11 +889,12 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) vty_out (vty, ", %s", nexthop->ifname); else if (nexthop->ifindex) - vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + vty_out (vty, ", %s", + ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " is directly connected, %s", - ifindex2ifname (nexthop->ifindex)); + ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s", nexthop->ifname); diff --git a/zebra/zserv.c b/zebra/zserv.c index 432c31824..85f448c42 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -36,6 +36,7 @@ #include "privs.h" #include "network.h" #include "buffer.h" +#include "vrf.h" #include "zebra/zserv.h" #include "zebra/router-id.h" @@ -473,7 +474,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) struct nexthop *nexthop; /* Lookup nexthop. */ - rib = rib_match_ipv6 (addr); + rib = rib_match_ipv6 (addr, VRF_DEFAULT); /* Get output stream. */ s = client->obuf; @@ -540,7 +541,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, VRF_DEFAULT); /* Get output stream. */ s = client->obuf; @@ -679,7 +680,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) struct nexthop *nexthop; /* Lookup nexthop. */ - rib = rib_lookup_ipv4 (p); + rib = rib_lookup_ipv4 (p, VRF_DEFAULT); /* Get output stream. */ s = client->obuf; @@ -842,6 +843,9 @@ zread_ipv4_add (struct zserv *client, u_short length) p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + /* VRF ID */ + rib->vrf_id = VRF_DEFAULT; + /* Nexthop parse. */ if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) { @@ -972,7 +976,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) api.metric = 0; rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, - client->rtm_table, api.safi); + VRF_DEFAULT, api.safi); return 0; } @@ -998,7 +1002,7 @@ zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length) struct rib *rib; addr.s_addr = stream_get_ipv4 (client->ibuf); - rib = rib_match_ipv4_multicast (addr, NULL); + rib = rib_match_ipv4_multicast (addr, NULL, VRF_DEFAULT); return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib); } @@ -1076,11 +1080,13 @@ zread_ipv6_add (struct zserv *client, u_short length) api.metric = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, zebrad.rtm_table_default, api.metric, - api.distance, api.safi); + rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, + VRF_DEFAULT, zebrad.rtm_table_default, api.metric, + api.distance, api.safi); else - rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric, - api.distance, api.safi); + rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, + VRF_DEFAULT, zebrad.rtm_table_default, api.metric, + api.distance, api.safi); return 0; } @@ -1143,9 +1149,11 @@ zread_ipv6_delete (struct zserv *client, u_short length) api.metric = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi); + rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, VRF_DEFAULT, + api.safi); else - rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.safi); + rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, VRF_DEFAULT, + api.safi); return 0; } From 4364ee5b6f65008fe19225f05e489ad8257a7df8 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:03 +0200 Subject: [PATCH 0738/1342] zebra: show routes in a specified VRF or all VRFs The present "show ip[v6] [m]route [xxx]" and "show ip rpf [xxx]" commands now show routes only in the default VRF. A new option is introduced to show routes in a specified VRF: show ip[v6] [m]route [xxx] vrf N show ip rpf [xxx] vrf N and a new option is used to show routes through all VRFs: show ip[v6] [m]route [xxx] vrf all show ip rpf [xxx] vrf all Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN [DL: conflicts resolved] Signed-off-by: David Lamparter --- zebra/zebra_vty.c | 1336 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 1197 insertions(+), 139 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 78e73669b..33368b612 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -31,9 +31,11 @@ #include "zebra/zserv.h" -static int do_show_ip_route(struct vty *vty, safi_t safi); +static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id); static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast); +static void vty_show_ip_route (struct vty *vty, struct route_node *rn, + struct rib *rib); /* General function for static route. */ static int @@ -259,10 +261,23 @@ DEFUN (show_ip_rpf, IP_STR "Display RPF information for multicast source\n") { + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + VTY_WARN_EXPERIMENTAL(); - return do_show_ip_route(vty, SAFI_MULTICAST); + return do_show_ip_route(vty, SAFI_MULTICAST, vrf_id); } +ALIAS (show_ip_rpf, + show_ip_rpf_vrf_cmd, + "show ip rpf " VRF_CMD_STR, + SHOW_STR + IP_STR + "Display RPF information for multicast source\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_rpf_addr, show_ip_rpf_addr_cmd, "show ip rpf A.B.C.D", @@ -274,8 +289,12 @@ DEFUN (show_ip_rpf_addr, struct in_addr addr; struct route_node *rn; struct rib *rib; + vrf_id_t vrf_id = VRF_DEFAULT; int ret; + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + VTY_WARN_EXPERIMENTAL(); ret = inet_aton (argv[0], &addr); @@ -285,7 +304,7 @@ DEFUN (show_ip_rpf_addr, return CMD_WARNING; } - rib = rib_match_ipv4_multicast (addr, &rn, VRF_DEFAULT); + rib = rib_match_ipv4_multicast (addr, &rn, vrf_id); if (rib) vty_show_ip_route_detail (vty, rn, 1); @@ -295,6 +314,86 @@ DEFUN (show_ip_rpf_addr, return CMD_SUCCESS; } +ALIAS (show_ip_rpf_addr, + show_ip_rpf_addr_vrf_cmd, + "show ip rpf A.B.C.D " VRF_CMD_STR, + SHOW_STR + IP_STR + "Display RPF information for multicast source\n" + "IP multicast source address (e.g. 10.0.0.0)\n" + VRF_CMD_HELP_STR) + +DEFUN (show_ip_rpf_vrf_all, + show_ip_rpf_vrf_all_cmd, + "show ip rpf " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "Display RPF information for multicast source\n" + VRF_ALL_CMD_HELP_STR) +{ + struct zebra_vrf *zvrf; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + vrf_iter_t iter; + int first = 1; + + VTY_WARN_EXPERIMENTAL(); + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_MULTICAST]) == NULL) + continue; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_rpf_addr_vrf_all, + show_ip_rpf_addr_vrf_all_cmd, + "show ip rpf A.B.C.D " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "Display RPF information for multicast source\n" + "IP multicast source address (e.g. 10.0.0.0)\n" + VRF_ALL_CMD_HELP_STR) +{ + struct in_addr addr; + struct route_node *rn; + vrf_iter_t iter; + int ret; + + VTY_WARN_EXPERIMENTAL(); + + ret = inet_aton (argv[0], &addr); + if (ret == 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if (rib_match_ipv4_multicast (addr, &rn, vrf_iter2id (iter))) + vty_show_ip_route_detail (vty, rn, 1); + } + + return CMD_SUCCESS; +} + /* Static route configuration. */ DEFUN (ip_route, ip_route_cmd, @@ -717,6 +816,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); + vty_out (vty, ", vrf %u", rib->vrf_id); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); if (rib->refcnt) @@ -865,6 +965,9 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) && rib->type != ZEBRA_ROUTE_KERNEL) len += vty_out (vty, " [%d/%d]", rib->distance, rib->metric); + + if (rib->vrf_id != VRF_DEFAULT) + len += vty_out (vty, " [vrf %u]", rib->vrf_id); } else vty_out (vty, " %c%*c", @@ -985,16 +1088,22 @@ DEFUN (show_ip_route, IP_STR "IP routing table\n") { - return do_show_ip_route(vty, SAFI_UNICAST); + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + return do_show_ip_route(vty, SAFI_UNICAST, vrf_id); } -static int do_show_ip_route(struct vty *vty, safi_t safi) { +static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id) +{ struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return CMD_SUCCESS; @@ -1012,6 +1121,14 @@ static int do_show_ip_route(struct vty *vty, safi_t safi) { return CMD_SUCCESS; } +ALIAS (show_ip_route, + show_ip_route_vrf_cmd, + "show ip route " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_prefix_longer, show_ip_route_prefix_longer_cmd, "show ip route A.B.C.D/M longer-prefixes", @@ -1027,6 +1144,7 @@ DEFUN (show_ip_route_prefix_longer, struct prefix p; int ret; int first = 1; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (argv[0], &p); if (! ret) @@ -1034,8 +1152,11 @@ DEFUN (show_ip_route_prefix_longer, vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } - - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1054,6 +1175,16 @@ DEFUN (show_ip_route_prefix_longer, return CMD_SUCCESS; } +ALIAS (show_ip_route_prefix_longer, + show_ip_route_prefix_longer_vrf_cmd, + "show ip route A.B.C.D/M longer-prefixes " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Show route matching the specified Network/Mask pair only\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_supernets, show_ip_route_supernets_cmd, "show ip route supernets-only", @@ -1065,10 +1196,14 @@ DEFUN (show_ip_route_supernets, struct route_table *table; struct route_node *rn; struct rib *rib; - u_int32_t addr; + u_int32_t addr; int first = 1; + vrf_id_t vrf_id = VRF_DEFAULT; - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1080,7 +1215,7 @@ DEFUN (show_ip_route_supernets, if ((IN_CLASSC (addr) && rn->p.prefixlen < 24) || (IN_CLASSB (addr) && rn->p.prefixlen < 16) - || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) + || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) { if (first) { @@ -1093,6 +1228,15 @@ DEFUN (show_ip_route_supernets, return CMD_SUCCESS; } +ALIAS (show_ip_route_supernets, + show_ip_route_supernets_vrf_cmd, + "show ip route supernets-only " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Show supernet entries only\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_protocol, show_ip_route_protocol_cmd, "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA, @@ -1106,6 +1250,7 @@ DEFUN (show_ip_route_protocol, struct route_node *rn; struct rib *rib; int first = 1; + vrf_id_t vrf_id = VRF_DEFAULT; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0) @@ -1113,8 +1258,11 @@ DEFUN (show_ip_route_protocol, vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } - - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1133,6 +1281,15 @@ DEFUN (show_ip_route_protocol, return CMD_SUCCESS; } +ALIAS (show_ip_route_protocol, + show_ip_route_protocol_vrf_cmd, + "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA " " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + QUAGGA_IP_REDIST_HELP_STR_ZEBRA + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_addr, show_ip_route_addr_cmd, "show ip route A.B.C.D", @@ -1145,6 +1302,7 @@ DEFUN (show_ip_route_addr, struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) @@ -1153,7 +1311,10 @@ DEFUN (show_ip_route_addr, return CMD_WARNING; } - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1171,6 +1332,15 @@ DEFUN (show_ip_route_addr, return CMD_SUCCESS; } +ALIAS (show_ip_route_addr, + show_ip_route_addr_vrf_cmd, + "show ip route A.B.C.D " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Network in the IP routing table to display\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_prefix, show_ip_route_prefix_cmd, "show ip route A.B.C.D/M", @@ -1183,6 +1353,7 @@ DEFUN (show_ip_route_prefix, struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) @@ -1191,7 +1362,10 @@ DEFUN (show_ip_route_prefix, return CMD_WARNING; } - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1211,6 +1385,15 @@ DEFUN (show_ip_route_prefix, return CMD_SUCCESS; } +ALIAS (show_ip_route_prefix, + show_ip_route_prefix_vrf_cmd, + "show ip route A.B.C.D/M " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + VRF_CMD_HELP_STR) + static void vty_show_ip_route_summary (struct vty *vty, struct route_table *table) { @@ -1247,8 +1430,10 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table) } } - vty_out (vty, "%-20s %-20s %-20s %s", - "Route Source", "Routes", "FIB", VTY_NEWLINE); + vty_out (vty, "%-20s %-20s %s (vrf %u)%s", + "Route Source", "Routes", "FIB", + ((rib_table_info_t *)table->info)->zvrf->vrf_id, + VTY_NEWLINE); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { @@ -1273,6 +1458,7 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table) vty_out (vty, "------%s", VTY_NEWLINE); vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); } /* @@ -1325,8 +1511,10 @@ vty_show_ip_route_summary_prefix (struct vty *vty, struct route_table *table) } } - vty_out (vty, "%-20s %-20s %-20s %s", - "Route Source", "Prefix Routes", "FIB", VTY_NEWLINE); + vty_out (vty, "%-20s %-20s %s (vrf %u)%s", + "Route Source", "Prefix Routes", "FIB", + ((rib_table_info_t *)table->info)->zvrf->vrf_id, + VTY_NEWLINE); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { @@ -1351,6 +1539,7 @@ vty_show_ip_route_summary_prefix (struct vty *vty, struct route_table *table) vty_out (vty, "------%s", VTY_NEWLINE); vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); } /* Show route summary. */ @@ -1363,8 +1552,12 @@ DEFUN (show_ip_route_summary, "Summary of all routes\n") { struct route_table *table; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1373,6 +1566,15 @@ DEFUN (show_ip_route_summary, return CMD_SUCCESS; } +ALIAS (show_ip_route_summary, + show_ip_route_summary_vrf_cmd, + "show ip route summary " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n" + VRF_CMD_HELP_STR) + /* Show route summary prefix. */ DEFUN (show_ip_route_summary_prefix, show_ip_route_summary_prefix_cmd, @@ -1384,8 +1586,12 @@ DEFUN (show_ip_route_summary_prefix, "Prefix routes\n") { struct route_table *table; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1394,141 +1600,504 @@ DEFUN (show_ip_route_summary_prefix, return CMD_SUCCESS; } -/* Write IPv4 static route configuration. */ -static int -static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) +ALIAS (show_ip_route_summary_prefix, + show_ip_route_summary_prefix_vrf_cmd, + "show ip route summary prefix " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n" + "Prefix routes\n" + VRF_CMD_HELP_STR) + +DEFUN (show_ip_route_vrf_all, + show_ip_route_vrf_all_cmd, + "show ip route " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + VRF_ALL_CMD_HELP_STR) { + struct route_table *table; struct route_node *rn; - struct static_ipv4 *si; - struct route_table *stable; - char buf[PREFIX_STRLEN]; - int write; - - write = 0; - - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP, safi, VRF_DEFAULT); - if (! stable) - return -1; + struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int first = 1; - for (rn = route_top (stable); rn; rn = route_next (rn)) - for (si = rn->info; si; si = si->next) - { - vty_out (vty, "%s %s", cmd, prefix2str (&rn->p, buf, sizeof buf)); + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) + continue; - switch (si->type) - { - case STATIC_IPV4_GATEWAY: - vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); - break; - case STATIC_IPV4_IFNAME: - vty_out (vty, " %s", si->gate.ifname); - break; - case STATIC_IPV4_BLACKHOLE: - vty_out (vty, " Null0"); - break; - } - - /* flags are incompatible with STATIC_IPV4_BLACKHOLE */ - if (si->type != STATIC_IPV4_BLACKHOLE) + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) { - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, " %s", "reject"); - - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, " %s", "blackhole"); + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); } + } - if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) - vty_out (vty, " %d", si->distance); - - vty_out (vty, "%s", VTY_NEWLINE); - - write = 1; - } - return write; + return CMD_SUCCESS; } -DEFUN (show_ip_protocol, - show_ip_protocol_cmd, - "show ip protocol", - SHOW_STR - IP_STR - "IP protocol filtering status\n") +DEFUN (show_ip_route_prefix_longer_vrf_all, + show_ip_route_prefix_longer_vrf_all_cmd, + "show ip route A.B.C.D/M longer-prefixes " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Show route matching the specified Network/Mask pair only\n" + VRF_ALL_CMD_HELP_STR) { - int i; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct prefix p; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int ret; + int first = 1; - vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); - vty_out(vty, "------------------------%s", VTY_NEWLINE); - for (i=0;itable[AFI_IP][SAFI_UNICAST]) == NULL) + continue; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; } -/* - * Show IP mroute command to dump the BGP Multicast - * routing table - */ -DEFUN (show_ip_mroute, - show_ip_mroute_cmd, - "show ip mroute", +DEFUN (show_ip_route_supernets_vrf_all, + show_ip_route_supernets_vrf_all_cmd, + "show ip route supernets-only " VRF_ALL_CMD_STR, SHOW_STR IP_STR - "IP Multicast routing table\n") + "IP routing table\n" + "Show supernet entries only\n" + VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + u_int32_t addr; int first = 1; - table = zebra_vrf_table (AFI_IP, SAFI_MULTICAST, VRF_DEFAULT); - if (! table) - return CMD_SUCCESS; + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) + continue; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + addr = ntohl (rn->p.u.prefix4.s_addr); + + if ((IN_CLASSC (addr) && rn->p.prefixlen < 24) + || (IN_CLASSB (addr) && rn->p.prefixlen < 16) + || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + } - /* Show all IPv4 routes. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V4_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } return CMD_SUCCESS; } - -#ifdef HAVE_IPV6 -/* General fucntion for IPv6 static route. */ -static int -static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, - const char *gate_str, const char *ifname, - const char *flag_str, const char *distance_str) +DEFUN (show_ip_route_protocol_vrf_all, + show_ip_route_protocol_vrf_all_cmd, + "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA " " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + QUAGGA_IP_REDIST_HELP_STR_ZEBRA + VRF_ALL_CMD_HELP_STR) { - int ret; - u_char distance; - struct prefix p; - struct in6_addr *gate = NULL; - struct in6_addr gate_addr; - u_char type = 0; - int table = 0; - u_char flag = 0; - + int type; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int first = 1; + + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0) + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) + continue; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_addr_vrf_all, + show_ip_route_addr_vrf_all_cmd, + "show ip route A.B.C.D " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Network in the IP routing table to display\n" + VRF_ALL_CMD_HELP_STR) +{ + int ret; + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) + continue; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + continue; + + vty_show_ip_route_detail (vty, rn, 0); + + route_unlock_node (rn); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_prefix_vrf_all, + show_ip_route_prefix_vrf_all_cmd, + "show ip route A.B.C.D/M " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + VRF_ALL_CMD_HELP_STR) +{ + int ret; + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) + continue; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + continue; + if (rn->p.prefixlen != p.prefixlen) + { + route_unlock_node (rn); + continue; + } + + vty_show_ip_route_detail (vty, rn, 0); + + route_unlock_node (rn); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_summary_vrf_all, + show_ip_route_summary_vrf_all_cmd, + "show ip route summary " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n" + VRF_ALL_CMD_HELP_STR) +{ + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + vty_show_ip_route_summary (vty, zvrf->table[AFI_IP][SAFI_UNICAST]); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_summary_prefix_vrf_all, + show_ip_route_summary_prefix_vrf_all_cmd, + "show ip route summary prefix " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n" + "Prefix routes\n" + VRF_ALL_CMD_HELP_STR) +{ + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + vty_show_ip_route_summary_prefix (vty, zvrf->table[AFI_IP][SAFI_UNICAST]); + + return CMD_SUCCESS; +} + +/* Write IPv4 static route configuration. */ +static int +static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) +{ + struct route_node *rn; + struct static_ipv4 *si; + struct route_table *stable; + int write; + + write = 0; + + /* Lookup table. */ + stable = zebra_vrf_static_table (AFI_IP, safi, VRF_DEFAULT); + if (! stable) + return -1; + + for (rn = route_top (stable); rn; rn = route_next (rn)) + for (si = rn->info; si; si = si->next) + { + vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen); + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); + break; + case STATIC_IPV4_IFNAME: + vty_out (vty, " %s", si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + vty_out (vty, " Null0"); + break; + } + + /* flags are incompatible with STATIC_IPV4_BLACKHOLE */ + if (si->type != STATIC_IPV4_BLACKHOLE) + { + if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) + vty_out (vty, " %s", "reject"); + + if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) + vty_out (vty, " %s", "blackhole"); + } + + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); + + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + return write; +} + +DEFUN (show_ip_protocol, + show_ip_protocol_cmd, + "show ip protocol", + SHOW_STR + IP_STR + "IP protocol filtering status\n") +{ + int i; + + vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); + vty_out(vty, "------------------------%s", VTY_NEWLINE); + for (i=0;i 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + table = zebra_vrf_table (AFI_IP, SAFI_MULTICAST, vrf_id); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +ALIAS (show_ip_mroute, + show_ip_mroute_vrf_cmd, + "show ip mroute " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP Multicast routing table\n" + VRF_CMD_HELP_STR) + +DEFUN (show_ip_mroute_vrf_all, + show_ip_mroute_vrf_all_cmd, + "show ip mroute " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP Multicast routing table\n" + VRF_ALL_CMD_HELP_STR) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int first = 1; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) + continue; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* General fucntion for IPv6 static route. */ +static int +static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *distance_str) +{ + int ret; + u_char distance; + struct prefix p; + struct in6_addr *gate = NULL; + struct in6_addr gate_addr; + u_char type = 0; + int table = 0; + u_char flag = 0; + ret = str2prefix (dest_str, &p); if (ret <= 0) { @@ -1830,8 +2399,12 @@ DEFUN (show_ipv6_route, struct route_node *rn; struct rib *rib; int first = 1; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1849,6 +2422,14 @@ DEFUN (show_ipv6_route, return CMD_SUCCESS; } +ALIAS (show_ipv6_route, + show_ipv6_route_vrf_cmd, + "show ipv6 route " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + VRF_CMD_HELP_STR) + DEFUN (show_ipv6_route_prefix_longer, show_ipv6_route_prefix_longer_cmd, "show ipv6 route X:X::X:X/M longer-prefixes", @@ -1864,10 +2445,7 @@ DEFUN (show_ipv6_route_prefix_longer, struct prefix p; int ret; int first = 1; - - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); - if (! table) - return CMD_SUCCESS; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (argv[0], &p); if (! ret) @@ -1876,6 +2454,13 @@ DEFUN (show_ipv6_route_prefix_longer, return CMD_WARNING; } + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); + if (! table) + return CMD_SUCCESS; + /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) @@ -1891,6 +2476,16 @@ DEFUN (show_ipv6_route_prefix_longer, return CMD_SUCCESS; } +ALIAS (show_ipv6_route_prefix_longer, + show_ipv6_route_prefix_longer_vrf_cmd, + "show ipv6 route X:X::X:X/M longer-prefixes " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n" + "Show route matching the specified Network/Mask pair only\n" + VRF_CMD_HELP_STR) + DEFUN (show_ipv6_route_protocol, show_ipv6_route_protocol_cmd, "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA, @@ -1904,6 +2499,7 @@ DEFUN (show_ipv6_route_protocol, struct route_node *rn; struct rib *rib; int first = 1; + vrf_id_t vrf_id = VRF_DEFAULT; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0) @@ -1911,8 +2507,11 @@ DEFUN (show_ipv6_route_protocol, vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } - - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1931,6 +2530,15 @@ DEFUN (show_ipv6_route_protocol, return CMD_SUCCESS; } +ALIAS (show_ipv6_route_protocol, + show_ipv6_route_protocol_vrf_cmd, + "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA " " VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + QUAGGA_IP6_REDIST_HELP_STR_ZEBRA + VRF_CMD_HELP_STR) + DEFUN (show_ipv6_route_addr, show_ipv6_route_addr_cmd, "show ipv6 route X:X::X:X", @@ -1943,6 +2551,7 @@ DEFUN (show_ipv6_route_addr, struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) @@ -1951,7 +2560,10 @@ DEFUN (show_ipv6_route_addr, return CMD_WARNING; } - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -1969,6 +2581,15 @@ DEFUN (show_ipv6_route_addr, return CMD_SUCCESS; } +ALIAS (show_ipv6_route_addr, + show_ipv6_route_addr_vrf_cmd, + "show ipv6 route X:X::X:X " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 Address\n" + VRF_CMD_HELP_STR) + DEFUN (show_ipv6_route_prefix, show_ipv6_route_prefix_cmd, "show ipv6 route X:X::X:X/M", @@ -1981,6 +2602,7 @@ DEFUN (show_ipv6_route_prefix, struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) @@ -1989,7 +2611,10 @@ DEFUN (show_ipv6_route_prefix, return CMD_WARNING; } - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -2009,6 +2634,15 @@ DEFUN (show_ipv6_route_prefix, return CMD_SUCCESS; } +ALIAS (show_ipv6_route_prefix, + show_ipv6_route_prefix_vrf_cmd, + "show ipv6 route X:X::X:X/M " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n" + VRF_CMD_HELP_STR) + /* Show route summary. */ DEFUN (show_ipv6_route_summary, show_ipv6_route_summary_cmd, @@ -2019,8 +2653,12 @@ DEFUN (show_ipv6_route_summary, "Summary of all IPv6 routes\n") { struct route_table *table; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -2029,6 +2667,15 @@ DEFUN (show_ipv6_route_summary, return CMD_SUCCESS; } +ALIAS (show_ipv6_route_summary, + show_ipv6_route_summary_vrf_cmd, + "show ipv6 route summary " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Summary of all IPv6 routes\n" + VRF_CMD_HELP_STR) + /* Show ipv6 route summary prefix. */ DEFUN (show_ipv6_route_summary_prefix, show_ipv6_route_summary_prefix_cmd, @@ -2040,8 +2687,12 @@ DEFUN (show_ipv6_route_summary_prefix, "Prefix routes\n") { struct route_table *table; + vrf_id_t vrf_id = VRF_DEFAULT; - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -2050,6 +2701,16 @@ DEFUN (show_ipv6_route_summary_prefix, return CMD_SUCCESS; } +ALIAS (show_ipv6_route_summary_prefix, + show_ipv6_route_summary_prefix_vrf_cmd, + "show ipv6 route summary prefix " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Summary of all IPv6 routes\n" + "Prefix routes\n" + VRF_CMD_HELP_STR) + /* * Show IPv6 mroute command.Used to dump * the Multicast routing table. @@ -2066,8 +2727,12 @@ DEFUN (show_ipv6_mroute, struct route_node *rn; struct rib *rib; int first = 1; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - table = zebra_vrf_table (AFI_IP6, SAFI_MULTICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_MULTICAST, vrf_id); if (! table) return CMD_SUCCESS; @@ -2085,6 +2750,310 @@ DEFUN (show_ipv6_mroute, return CMD_SUCCESS; } +ALIAS (show_ipv6_mroute, + show_ipv6_mroute_vrf_cmd, + "show ipv6 mroute " VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 Multicast routing table\n" + VRF_CMD_HELP_STR) + +DEFUN (show_ipv6_route_vrf_all, + show_ipv6_route_vrf_all_cmd, + "show ipv6 route " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + VRF_ALL_CMD_HELP_STR) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int first = 1; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; + + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_prefix_longer_vrf_all, + show_ipv6_route_prefix_longer_vrf_all_cmd, + "show ipv6 route X:X::X:X/M longer-prefixes " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n" + "Show route matching the specified Network/Mask pair only\n" + VRF_ALL_CMD_HELP_STR) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct prefix p; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int ret; + int first = 1; + + ret = str2prefix (argv[0], &p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; + + /* Show matched type IPv6 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_protocol_vrf_all, + show_ipv6_route_protocol_vrf_all_cmd, + "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA " " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + QUAGGA_IP6_REDIST_HELP_STR_ZEBRA + VRF_ALL_CMD_HELP_STR) +{ + int type; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int first = 1; + + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0) + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; + + /* Show matched type IPv6 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_addr_vrf_all, + show_ipv6_route_addr_vrf_all_cmd, + "show ipv6 route X:X::X:X " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 Address\n" + VRF_ALL_CMD_HELP_STR) +{ + int ret; + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + ret = str2prefix_ipv6 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + continue; + + vty_show_ip_route_detail (vty, rn, 0); + + route_unlock_node (rn); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_prefix_vrf_all, + show_ipv6_route_prefix_vrf_all_cmd, + "show ipv6 route X:X::X:X/M " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n" + VRF_ALL_CMD_HELP_STR) +{ + int ret; + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + ret = str2prefix_ipv6 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + continue; + if (rn->p.prefixlen != p.prefixlen) + { + route_unlock_node (rn); + continue; + } + + vty_show_ip_route_detail (vty, rn, 0); + + route_unlock_node (rn); + } + + return CMD_SUCCESS; +} + +/* Show route summary. */ +DEFUN (show_ipv6_route_summary_vrf_all, + show_ipv6_route_summary_vrf_all_cmd, + "show ipv6 route summary " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Summary of all IPv6 routes\n" + VRF_ALL_CMD_HELP_STR) +{ + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + vty_show_ip_route_summary (vty, zvrf->table[AFI_IP6][SAFI_UNICAST]); + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_mroute_vrf_all, + show_ipv6_mroute_vrf_all_cmd, + "show ipv6 mroute " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 Multicast routing table\n" + VRF_ALL_CMD_HELP_STR) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct zebra_vrf *zvrf; + vrf_iter_t iter; + int first = 1; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; + + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_summary_prefix_vrf_all, + show_ipv6_route_summary_prefix_vrf_all_cmd, + "show ipv6 route summary prefix " VRF_ALL_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Summary of all IPv6 routes\n" + "Prefix routes\n" + VRF_ALL_CMD_HELP_STR) +{ + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + vty_show_ip_route_summary_prefix (vty, zvrf->table[AFI_IP6][SAFI_UNICAST]); + + return CMD_SUCCESS; +} + /* Write IPv6 static route configuration. */ static int static_config_ipv6 (struct vty *vty) @@ -2252,6 +3221,57 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_rpf_addr_cmd); install_element (ENABLE_NODE, &show_ip_rpf_addr_cmd); + /* Commands for VRF */ + + install_element (VIEW_NODE, &show_ip_route_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_addr_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_longer_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_protocol_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_supernets_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_summary_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_summary_prefix_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_addr_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_longer_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_protocol_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_supernets_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_summary_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_route_summary_prefix_vrf_cmd); + + install_element (VIEW_NODE, &show_ip_route_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_addr_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_longer_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_protocol_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_supernets_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_summary_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_route_summary_prefix_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_addr_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_longer_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_protocol_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_supernets_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_summary_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_route_summary_prefix_vrf_all_cmd); + + install_element (VIEW_NODE, &show_ip_mroute_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_mroute_vrf_cmd); + + install_element (VIEW_NODE, &show_ip_mroute_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_mroute_vrf_all_cmd); + + install_element (VIEW_NODE, &show_ip_rpf_vrf_cmd); + install_element (VIEW_NODE, &show_ip_rpf_vrf_all_cmd); + install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_cmd); + install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_addr_vrf_cmd); + install_element (ENABLE_NODE, &show_ip_rpf_addr_vrf_all_cmd); + #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); install_element (CONFIG_NODE, &ipv6_route_flags_cmd); @@ -2286,5 +3306,43 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_mroute_cmd); install_element (ENABLE_NODE, &show_ipv6_mroute_cmd); + + /* Commands for VRF */ + + install_element (VIEW_NODE, &show_ipv6_route_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_summary_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_protocol_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_addr_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_protocol_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_addr_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_summary_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_vrf_cmd); + + install_element (VIEW_NODE, &show_ipv6_route_vrf_all_cmd); + install_element (VIEW_NODE, &show_ipv6_route_summary_vrf_all_cmd); + install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_vrf_all_cmd); + install_element (VIEW_NODE, &show_ipv6_route_protocol_vrf_all_cmd); + install_element (VIEW_NODE, &show_ipv6_route_addr_vrf_all_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_vrf_all_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_protocol_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_addr_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_summary_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_vrf_all_cmd); + + install_element (VIEW_NODE, &show_ipv6_mroute_vrf_cmd); + install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_cmd); + + install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_all_cmd); #endif /* HAVE_IPV6 */ } From 1885d0a5274cd78e46ad6c22171a5240a2f27f64 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:04 +0200 Subject: [PATCH 0739/1342] zebra: let the route-map rule "match interface" work for VRFs Introduce a new "struct nexthop_vrfid" to specify a nexthop together with the VRF ID it belongs to. Thus in route_match_interface(), we can lookup the interface from the correct VRF. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/rib.h | 8 ++++++++ zebra/zebra_rib.c | 3 ++- zebra/zebra_routemap.c | 8 ++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 2d8805a88..84cd3da6c 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -317,6 +317,14 @@ struct nexthop : ((tnexthop) = (nexthop)->next)) \ : (((recursing) = 0),((tnexthop) = (tnexthop)->next))) +/* Structure holding nexthop & VRF identifier, + * used for applying the route-map. */ +struct nexthop_vrfid +{ + struct nexthop *nexthop; + vrf_id_t vrf_id; +}; + /* Routing table instance. */ struct zebra_vrf { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 336b56627..8bd4ecc88 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1066,7 +1066,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); if (rmap) { - ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop); + struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id}; + ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf); } if (ret == RMAP_DENYMATCH) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index b0dca088b..f3737757d 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -130,6 +130,7 @@ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { + struct nexthop_vrfid *nh_vrf; struct nexthop *nexthop; char *ifname = rule; unsigned int ifindex; @@ -138,10 +139,13 @@ route_match_interface (void *rule, struct prefix *prefix, { if (strcasecmp(ifname, "any") == 0) return RMAP_MATCH; - ifindex = ifname2ifindex(ifname); + nh_vrf = object; + if (!nh_vrf) + return RMAP_NOMATCH; + ifindex = ifname2ifindex_vrf (ifname, nh_vrf->vrf_id); if (ifindex == 0) return RMAP_NOMATCH; - nexthop = object; + nexthop = nh_vrf->nexthop; if (!nexthop) return RMAP_NOMATCH; if (nexthop->ifindex == ifindex) From 8970f74ec77f93eb862ab8803d9d7c76c7128940 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:05 +0200 Subject: [PATCH 0740/1342] zebra: lookup the address in all VRFs when set the route-map rule "set src" When configuring the route-map rule "set src A.B.C.D", it checked whether the source address exists on some interface. Now it checks the source address throughout all VRFs. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/zebra_routemap.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index f3737757d..bd9be5323 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -28,6 +28,7 @@ #include "command.h" #include "filter.h" #include "plist.h" +#include "vrf.h" #include "zebra/zserv.h" @@ -369,7 +370,8 @@ DEFUN (set_src, "src address\n") { struct in_addr src; - struct interface *pif; + struct interface *pif = NULL; + vrf_iter_t iter; if (inet_pton(AF_INET, argv[0], &src) <= 0) { @@ -377,12 +379,16 @@ DEFUN (set_src, return CMD_WARNING; } - pif = if_lookup_exact_address (src); - if (!pif) - { - vty_out (vty, "%% not a local address%s", VTY_NEWLINE); - return CMD_WARNING; - } + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((pif = if_lookup_exact_address_vrf (src, vrf_iter2id (iter))) != NULL) + break; + + if (!pif) + { + vty_out (vty, "%% not a local address%s", VTY_NEWLINE); + return CMD_WARNING; + } + return zebra_route_set_add (vty, vty->index, "src", argv[0]); } From 7aaf4ea990398335bd40b56cc9586ab6a7178a4f Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:06 +0200 Subject: [PATCH 0741/1342] zebra: configure static routes in any VRF Introduce new commands to configure static routes in any VRF, by appending the old static route commands with a new parameter "vrf N". A new parameter "const char *vrf_id_str" is added to the functions zebra_static_ipv4() and static_ipv6_func() to get the configured VRF ID. A new member "vrf_id" is added to the "struct static_ipv4" and "struct static_ipv6", indicating which VRF this static route is configured in. But till now, no interface can exist in any non-default VRF. So these static routes in non-default VRFs are kept inactive. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/rib.h | 6 + zebra/zebra_rib.c | 14 +- zebra/zebra_vty.c | 1093 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 963 insertions(+), 150 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 84cd3da6c..dcb307efc 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -173,6 +173,9 @@ struct static_ipv4 struct static_ipv4 *prev; struct static_ipv4 *next; + /* VRF identifier. */ + vrf_id_t vrf_id; + /* Administrative distance. */ u_char distance; @@ -205,6 +208,9 @@ struct static_ipv6 struct static_ipv6 *prev; struct static_ipv6 *next; + /* VRF identifier. */ + vrf_id_t vrf_id; + /* Administrative distance. */ u_char distance; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8bd4ecc88..68ae397bf 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2290,7 +2290,7 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) struct route_table *table; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, si->vrf_id); if (! table) return; @@ -2332,7 +2332,7 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; - rib->vrf_id = VRF_DEFAULT; + rib->vrf_id = si->vrf_id; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; @@ -2384,7 +2384,7 @@ static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) struct route_table *table; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, safi, si->vrf_id); if (! table) return; @@ -2490,6 +2490,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, si->type = type; si->distance = distance; si->flags = flags; + si->vrf_id = vrf_id; if (gate) si->gate.ipv4 = *gate; @@ -2836,7 +2837,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) struct route_node *rn; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, si->vrf_id); if (! table) return; @@ -2879,7 +2880,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; - rib->vrf_id = VRF_DEFAULT; + rib->vrf_id = si->vrf_id; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; @@ -2932,7 +2933,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) struct nexthop *nexthop; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, si->vrf_id); if (! table) return; @@ -3031,6 +3032,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->type = type; si->distance = distance; si->flags = flags; + si->vrf_id = vrf_id; switch (type) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 33368b612..dd7df5c96 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -42,7 +42,7 @@ static int zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, const char *dest_str, const char *mask_str, const char *gate_str, const char *flag_str, - const char *distance_str) + const char *distance_str, const char *vrf_id_str) { int ret; u_char distance; @@ -51,6 +51,7 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, struct in_addr mask; const char *ifname; u_char flag = 0; + vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -80,6 +81,10 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + /* VRF id */ + if (vrf_id_str) + VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); + /* Null0 static route. */ if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)) { @@ -89,9 +94,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, return CMD_WARNING; } if (add_cmd) - static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); + static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, 0); + static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id); return CMD_SUCCESS; } @@ -115,9 +120,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, if (gate_str == NULL) { if (add_cmd) - static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, 0); + static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, 0); + static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id); return CMD_SUCCESS; } @@ -131,9 +136,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, ifname = gate_str; if (add_cmd) - static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, 0); + static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, 0); + static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, vrf_id); return CMD_SUCCESS; } @@ -141,9 +146,11 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, static int zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, const char *mask_str, const char *gate_str, - const char *flag_str, const char *distance_str) + const char *flag_str, const char *distance_str, + const char *vrf_id_str) { - return zebra_static_ipv4_safi(vty, SAFI_UNICAST, add_cmd, dest_str, mask_str, gate_str, flag_str, distance_str); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, add_cmd, dest_str, mask_str, + gate_str, flag_str, distance_str, vrf_id_str); } /* Static unicast routes for multicast RPF lookup. */ @@ -159,7 +166,7 @@ DEFUN (ip_mroute_dist, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], - NULL, argc > 2 ? argv[2] : NULL); + NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (ip_mroute_dist, @@ -171,6 +178,33 @@ ALIAS (ip_mroute_dist, "Nexthop address\n" "Nexthop interface name\n") +DEFUN (ip_mroute_dist_vrf, + ip_mroute_dist_vrf_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255> " VRF_CMD_STR, + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n" + VRF_CMD_HELP_STR) +{ + VTY_WARN_EXPERIMENTAL(); + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], + NULL, argc > 3 ? argv[2] : NULL, + argc > 3 ? argv[3] : argv[2]); +} + +ALIAS (ip_mroute_dist_vrf, + ip_mroute_vrf_cmd, + "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) "VRF_CMD_STR, + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + VRF_CMD_HELP_STR) + DEFUN (no_ip_mroute_dist, no_ip_mroute_dist_cmd, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", @@ -183,7 +217,7 @@ DEFUN (no_ip_mroute_dist, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], - NULL, argc > 2 ? argv[2] : NULL); + NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (no_ip_mroute_dist, @@ -196,6 +230,34 @@ ALIAS (no_ip_mroute_dist, "Nexthop address\n" "Nexthop interface name\n") +DEFUN (no_ip_mroute_dist_vrf, + no_ip_mroute_dist_vrf_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255> " VRF_CMD_STR, + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n" + VRF_CMD_HELP_STR) +{ + VTY_WARN_EXPERIMENTAL(); + return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], + NULL, argc > 3 ? argv[2] : NULL, + argc > 3 ? argv[3] : argv[2]); +} + +ALIAS (no_ip_mroute_dist_vrf, + no_ip_mroute_vrf_cmd, + "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) " VRF_CMD_STR, + NO_STR + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + VRF_CMD_HELP_STR) + DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", @@ -405,7 +467,8 @@ DEFUN (ip_route, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL); + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, + NULL); } DEFUN (ip_route_flags, @@ -419,7 +482,8 @@ DEFUN (ip_route_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL); + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, + NULL); } DEFUN (ip_route_flags2, @@ -431,7 +495,8 @@ DEFUN (ip_route_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL); + return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, + NULL); } /* Mask as A.B.C.D format. */ @@ -446,7 +511,8 @@ DEFUN (ip_route_mask, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL); + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, + NULL); } DEFUN (ip_route_mask_flags, @@ -461,7 +527,8 @@ DEFUN (ip_route_mask_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL); + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, + NULL); } DEFUN (ip_route_mask_flags2, @@ -474,7 +541,8 @@ DEFUN (ip_route_mask_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL); + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, + NULL); } /* Distance option value. */ @@ -489,7 +557,8 @@ DEFUN (ip_route_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2]); + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], + NULL); } DEFUN (ip_route_flags_distance, @@ -504,7 +573,8 @@ DEFUN (ip_route_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3]); + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], + NULL); } DEFUN (ip_route_flags_distance2, @@ -517,7 +587,8 @@ DEFUN (ip_route_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2]); + return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], + NULL); } DEFUN (ip_route_mask_distance, @@ -532,7 +603,8 @@ DEFUN (ip_route_mask_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3]); + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + NULL); } DEFUN (ip_route_mask_flags_distance, @@ -548,7 +620,8 @@ DEFUN (ip_route_mask_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]); + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + NULL); } DEFUN (ip_route_mask_flags_distance2, @@ -562,7 +635,8 @@ DEFUN (ip_route_mask_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + NULL); } DEFUN (no_ip_route, @@ -576,7 +650,8 @@ DEFUN (no_ip_route, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL); + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, + NULL); } ALIAS (no_ip_route, @@ -601,7 +676,8 @@ DEFUN (no_ip_route_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL); + return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, + NULL); } DEFUN (no_ip_route_mask, @@ -616,7 +692,8 @@ DEFUN (no_ip_route_mask, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL); + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + NULL); } ALIAS (no_ip_route_mask, @@ -632,23 +709,408 @@ ALIAS (no_ip_route_mask, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") -DEFUN (no_ip_route_mask_flags2, - no_ip_route_mask_flags2_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole)", +DEFUN (no_ip_route_mask_flags2, + no_ip_route_mask_flags2_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole)", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + NULL); +} + +DEFUN (no_ip_route_distance, + no_ip_route_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], + NULL); +} + +DEFUN (no_ip_route_flags_distance, + no_ip_route_flags_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], + NULL); +} + +DEFUN (no_ip_route_flags_distance2, + no_ip_route_flags_distance2_cmd, + "no ip route A.B.C.D/M (reject|blackhole) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2], + NULL); +} + +DEFUN (no_ip_route_mask_distance, + no_ip_route_mask_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + NULL); +} + +DEFUN (no_ip_route_mask_flags_distance, + no_ip_route_mask_flags_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + NULL); +} + +DEFUN (no_ip_route_mask_flags_distance2, + no_ip_route_mask_flags_distance2_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + NULL); +} + +DEFUN (ip_route_vrf, + ip_route_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, + argv[2]); +} + +DEFUN (ip_route_flags_vrf, + ip_route_flags_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, + argv[3]); +} + +DEFUN (ip_route_flags2_vrf, + ip_route_flags2_vrf_cmd, + "ip route A.B.C.D/M (reject|blackhole) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, + argv[2]); +} + +/* Mask as A.B.C.D format. */ +DEFUN (ip_route_mask_vrf, + ip_route_mask_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, + argv[3]); +} + +DEFUN (ip_route_mask_flags_vrf, + ip_route_mask_flags_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, + argv[4]); +} + +DEFUN (ip_route_mask_flags2_vrf, + ip_route_mask_flags2_vrf_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, + argv[3]); +} + +/* Distance option value. */ +DEFUN (ip_route_distance_vrf, + ip_route_distance_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], + argv[3]); +} + +DEFUN (ip_route_flags_distance_vrf, + ip_route_flags_distance_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], + argv[4]); +} + +DEFUN (ip_route_flags_distance2_vrf, + ip_route_flags_distance2_vrf_cmd, + "ip route A.B.C.D/M (reject|blackhole) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], + argv[3]); +} + +DEFUN (ip_route_mask_distance_vrf, + ip_route_mask_distance_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + argv[4]); +} + +DEFUN (ip_route_mask_flags_distance_vrf, + ip_route_mask_flags_distance_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); +} + +DEFUN (ip_route_mask_flags_distance2_vrf, + ip_route_mask_flags_distance2_vrf_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + argv[4]); +} + +DEFUN (no_ip_route_vrf, + no_ip_route_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, + (argc > 3) ? argv[3] : argv[2]); +} + +ALIAS (no_ip_route_vrf, + no_ip_route_flags_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) + +DEFUN (no_ip_route_flags2_vrf, + no_ip_route_flags2_vrf_cmd, + "no ip route A.B.C.D/M (reject|blackhole) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, + argv[2]); +} + +DEFUN (no_ip_route_mask_vrf, + no_ip_route_mask_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + (argc > 4) ? argv[4] : argv[3]); +} + +ALIAS (no_ip_route_mask_vrf, + no_ip_route_mask_flags_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) + +DEFUN (no_ip_route_mask_flags2_vrf, + no_ip_route_mask_flags2_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n") + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL); + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + argv[2]); } -DEFUN (no_ip_route_distance, - no_ip_route_distance_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", +DEFUN (no_ip_route_distance_vrf, + no_ip_route_distance_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -656,14 +1118,16 @@ DEFUN (no_ip_route_distance, "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" - "Distance value for this route\n") + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2]); + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], + argv[3]); } -DEFUN (no_ip_route_flags_distance, - no_ip_route_flags_distance_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", +DEFUN (no_ip_route_flags_distance_vrf, + no_ip_route_flags_distance_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -672,28 +1136,32 @@ DEFUN (no_ip_route_flags_distance, "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" - "Distance value for this route\n") + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3]); + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], + argv[4]); } -DEFUN (no_ip_route_flags_distance2, - no_ip_route_flags_distance2_cmd, - "no ip route A.B.C.D/M (reject|blackhole) <1-255>", +DEFUN (no_ip_route_flags_distance2_vrf, + no_ip_route_flags_distance2_vrf_cmd, + "no ip route A.B.C.D/M (reject|blackhole) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" - "Distance value for this route\n") + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2]); + return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2], + argv[3]); } -DEFUN (no_ip_route_mask_distance, - no_ip_route_mask_distance_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", +DEFUN (no_ip_route_mask_distance_vrf, + no_ip_route_mask_distance_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -702,14 +1170,16 @@ DEFUN (no_ip_route_mask_distance, "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" - "Distance value for this route\n") + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]); + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + argv[4]); } -DEFUN (no_ip_route_mask_flags_distance, - no_ip_route_mask_flags_distance_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", +DEFUN (no_ip_route_mask_flags_distance_vrf, + no_ip_route_mask_flags_distance_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -719,14 +1189,16 @@ DEFUN (no_ip_route_mask_flags_distance, "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" - "Distance value for this route\n") + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]); + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); } -DEFUN (no_ip_route_mask_flags_distance2, - no_ip_route_mask_flags_distance2_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", +DEFUN (no_ip_route_mask_flags_distance2_vrf, + no_ip_route_mask_flags_distance2_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -734,9 +1206,11 @@ DEFUN (no_ip_route_mask_flags_distance2, "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" - "Distance value for this route\n") + "Distance value for this route\n" + VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]); + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + argv[4]); } char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ @@ -1922,51 +2396,58 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) struct route_node *rn; struct static_ipv4 *si; struct route_table *stable; + struct zebra_vrf *zvrf; + vrf_iter_t iter; int write; write = 0; - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP, safi, VRF_DEFAULT); - if (! stable) - return -1; - - for (rn = route_top (stable); rn; rn = route_next (rn)) - for (si = rn->info; si; si = si->next) - { - vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), - rn->p.prefixlen); + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (stable = zvrf->stable[AFI_IP][safi]) == NULL) + continue; - switch (si->type) - { - case STATIC_IPV4_GATEWAY: - vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); - break; - case STATIC_IPV4_IFNAME: - vty_out (vty, " %s", si->gate.ifname); - break; - case STATIC_IPV4_BLACKHOLE: - vty_out (vty, " Null0"); - break; - } - - /* flags are incompatible with STATIC_IPV4_BLACKHOLE */ - if (si->type != STATIC_IPV4_BLACKHOLE) + for (rn = route_top (stable); rn; rn = route_next (rn)) + for (si = rn->info; si; si = si->next) { - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, " %s", "reject"); + vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen); - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, " %s", "blackhole"); - } + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); + break; + case STATIC_IPV4_IFNAME: + vty_out (vty, " %s", si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + vty_out (vty, " Null0"); + break; + } + + /* flags are incompatible with STATIC_IPV4_BLACKHOLE */ + if (si->type != STATIC_IPV4_BLACKHOLE) + { + if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) + vty_out (vty, " %s", "reject"); - if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) - vty_out (vty, " %d", si->distance); + if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) + vty_out (vty, " %s", "blackhole"); + } - vty_out (vty, "%s", VTY_NEWLINE); + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); - write = 1; - } + if (si->vrf_id != VRF_DEFAULT) + vty_out (vty, " vrf %u", si->vrf_id); + + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + } return write; } @@ -2087,7 +2568,8 @@ DEFUN (show_ip_mroute_vrf_all, static int static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, const char *gate_str, const char *ifname, - const char *flag_str, const char *distance_str) + const char *flag_str, const char *distance_str, + const char *vrf_id_str) { int ret; u_char distance; @@ -2095,7 +2577,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, struct in6_addr *gate = NULL; struct in6_addr gate_addr; u_char type = 0; - int table = 0; + vrf_id_t vrf_id = VRF_DEFAULT; u_char flag = 0; ret = str2prefix (dest_str, &p); @@ -2161,10 +2643,14 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, } } + /* VRF id */ + if (vrf_id_str) + VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); + if (add_cmd) - static_add_ipv6 (&p, type, gate, ifname, flag, distance, table); + static_add_ipv6 (&p, type, gate, ifname, flag, distance, vrf_id); else - static_delete_ipv6 (&p, type, gate, ifname, distance, table); + static_delete_ipv6 (&p, type, gate, ifname, distance, vrf_id); return CMD_SUCCESS; } @@ -2178,7 +2664,8 @@ DEFUN (ipv6_route, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL); + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, + NULL); } DEFUN (ipv6_route_flags, @@ -2192,7 +2679,8 @@ DEFUN (ipv6_route_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL); + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, + NULL); } DEFUN (ipv6_route_ifname, @@ -2204,7 +2692,8 @@ DEFUN (ipv6_route_ifname, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL); + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, + NULL); } DEFUN (ipv6_route_ifname_flags, @@ -2218,7 +2707,8 @@ DEFUN (ipv6_route_ifname_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL); + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, + NULL); } DEFUN (ipv6_route_pref, @@ -2231,7 +2721,8 @@ DEFUN (ipv6_route_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2]); + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], + NULL); } DEFUN (ipv6_route_flags_pref, @@ -2246,7 +2737,8 @@ DEFUN (ipv6_route_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + NULL); } DEFUN (ipv6_route_ifname_pref, @@ -2259,7 +2751,8 @@ DEFUN (ipv6_route_ifname_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3]); + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + NULL); } DEFUN (ipv6_route_ifname_flags_pref, @@ -2274,7 +2767,8 @@ DEFUN (ipv6_route_ifname_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]); + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + NULL); } DEFUN (no_ipv6_route, @@ -2287,7 +2781,8 @@ DEFUN (no_ipv6_route, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL); + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + NULL); } ALIAS (no_ipv6_route, @@ -2312,7 +2807,8 @@ DEFUN (no_ipv6_route_ifname, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL); + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + NULL); } ALIAS (no_ipv6_route_ifname, @@ -2338,7 +2834,8 @@ DEFUN (no_ipv6_route_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2]); + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], + NULL); } DEFUN (no_ipv6_route_flags_pref, @@ -2355,7 +2852,8 @@ DEFUN (no_ipv6_route_flags_pref, "Distance value for this prefix\n") { /* We do not care about argv[2] */ - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]); + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + NULL); } DEFUN (no_ipv6_route_ifname_pref, @@ -2369,7 +2867,8 @@ DEFUN (no_ipv6_route_ifname_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]); + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + NULL); } DEFUN (no_ipv6_route_ifname_flags_pref, @@ -2385,7 +2884,257 @@ DEFUN (no_ipv6_route_ifname_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]); + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + NULL); +} + +DEFUN (ipv6_route_vrf, + ipv6_route_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, + argv[2]); +} + +DEFUN (ipv6_route_flags_vrf, + ipv6_route_flags_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, + argv[3]); +} + +DEFUN (ipv6_route_ifname_vrf, + ipv6_route_ifname_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, + argv[3]); +} + +DEFUN (ipv6_route_ifname_flags_vrf, + ipv6_route_ifname_flags_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, + argv[4]); +} + +DEFUN (ipv6_route_pref_vrf, + ipv6_route_pref_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], + argv[3]); +} + +DEFUN (ipv6_route_flags_pref_vrf, + ipv6_route_flags_pref_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + argv[4]); +} + +DEFUN (ipv6_route_ifname_pref_vrf, + ipv6_route_ifname_pref_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + argv[4]); +} + +DEFUN (ipv6_route_ifname_flags_pref_vrf, + ipv6_route_ifname_flags_pref_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255> " VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); +} + +DEFUN (no_ipv6_route_vrf, + no_ipv6_route_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + (argc > 3) ? argv[3] : argv[2]); +} + +ALIAS (no_ipv6_route_vrf, + no_ipv6_route_flags_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) + +DEFUN (no_ipv6_route_ifname_vrf, + no_ipv6_route_ifname_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + (argc > 4) ? argv[4] : argv[3]); +} + +ALIAS (no_ipv6_route_ifname_vrf, + no_ipv6_route_ifname_flags_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) + +DEFUN (no_ipv6_route_pref_vrf, + no_ipv6_route_pref_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255> " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], + argv[3]); +} + +DEFUN (no_ipv6_route_flags_pref_vrf, + no_ipv6_route_flags_pref_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + /* We do not care about argv[2] */ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + argv[4]); +} + +DEFUN (no_ipv6_route_ifname_pref_vrf, + no_ipv6_route_ifname_pref_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255> " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + argv[4]); +} + +DEFUN (no_ipv6_route_ifname_flags_pref_vrf, + no_ipv6_route_ifname_flags_pref_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255> " VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); } DEFUN (show_ipv6_route, @@ -3063,45 +3812,55 @@ static_config_ipv6 (struct vty *vty) int write; char buf[BUFSIZ]; struct route_table *stable; + struct zebra_vrf *zvrf; + vrf_iter_t iter; write = 0; - /* Lookup table. */ - stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); - if (! stable) - return -1; + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + { + if ((zvrf = vrf_iter2info (iter)) == NULL || + (stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]) == NULL) + continue; - for (rn = route_top (stable); rn; rn = route_next (rn)) - for (si = rn->info; si; si = si->next) - { - vty_out (vty, "ipv6 route %s", prefix2str (&rn->p, buf, sizeof buf)); + for (rn = route_top (stable); rn; rn = route_next (rn)) + for (si = rn->info; si; si = si->next) + { + vty_out (vty, "ipv6 route %s", prefix2str (&rn->p, buf, sizeof buf)); - switch (si->type) - { - case STATIC_IPV6_GATEWAY: - vty_out (vty, " %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ)); - break; - case STATIC_IPV6_IFNAME: - vty_out (vty, " %s", si->ifname); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - vty_out (vty, " %s %s", - inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname); - break; - } + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + vty_out (vty, " %s", + inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ)); + break; + case STATIC_IPV6_IFNAME: + vty_out (vty, " %s", si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + vty_out (vty, " %s %s", + inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), + si->ifname); + break; + } + + if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) + vty_out (vty, " %s", "reject"); - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, " %s", "reject"); + if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) + vty_out (vty, " %s", "blackhole"); - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, " %s", "blackhole"); + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); - if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) - vty_out (vty, " %d", si->distance); - vty_out (vty, "%s", VTY_NEWLINE); + if (si->vrf_id != VRF_DEFAULT) + vty_out (vty, " vrf %u", si->vrf_id); - write = 1; - } + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + } return write; } #endif /* HAVE_IPV6 */ @@ -3223,6 +3982,35 @@ zebra_vty_init (void) /* Commands for VRF */ + install_element (CONFIG_NODE, &ip_mroute_vrf_cmd); + install_element (CONFIG_NODE, &ip_mroute_dist_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_mroute_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_mroute_dist_vrf_cmd); + + install_element (CONFIG_NODE, &ip_route_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_flags_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_flags2_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_mask_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags2_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags2_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags2_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_distance_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_flags_distance_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_flags_distance2_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_mask_distance_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_distance_vrf_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_distance_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_distance_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_distance2_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_vrf_cmd); + install_element (VIEW_NODE, &show_ip_route_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_addr_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_prefix_vrf_cmd); @@ -3309,6 +4097,23 @@ zebra_vty_init (void) /* Commands for VRF */ + install_element (CONFIG_NODE, &ipv6_route_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_pref_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_route_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_vrf_cmd); From ac19a449261bf69e83827f4bb0c6e5526277b41b Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:07 +0200 Subject: [PATCH 0742/1342] zebra: maintain the router-id per VRF A router may need different identifier among the VRFs. So move the maintenance of router-id per VRF. * rib.h: Move the previous global variables in router-id.c into the "struct zebra_vrf": - struct list _rid_all_sorted_list/*rid_all_sorted_list - struct list _rid_lo_sorted_list/*rid_lo_sorted_list - struct prefix rid_user_assigned * router-id.c/router-id.h: A new parameter "vrf_id" is added to all the router-id APIs. Their operations are done only within the specified VRF. A new command "router-id A.B.C.D vrf N" is added to allow manual router-id for any VRF. The old router_id_init() function is splitted into two: - router_id_cmd_init(): it only installs the commands - router_id_init(): this new one initializes the variables for a specified VRF * zebra_rib.c: Add new functions zebra_vrf_get/lookup() called from router-id.c. * main.c: Replace router_id_init() with router_id_cmd_init() and call the new router_id_init() in zebra_vrf_new(). Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/main.c | 3 +- zebra/rib.h | 10 ++++ zebra/router-id.c | 136 +++++++++++++++++++++++++++++++--------------- zebra/router-id.h | 5 +- zebra/zserv.c | 7 ++- zebra/zserv.h | 3 +- 6 files changed, 114 insertions(+), 50 deletions(-) diff --git a/zebra/main.c b/zebra/main.c index a690c9a19..c7e3b68c3 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -215,6 +215,7 @@ zebra_vrf_new (vrf_id_t vrf_id, void **info) { zvrf = zebra_vrf_alloc (vrf_id); *info = (void *)zvrf; + router_id_init (zvrf); } return 0; @@ -348,7 +349,7 @@ main (int argc, char **argv) rib_init (); zebra_if_init (); zebra_debug_init (); - router_id_init(); + router_id_cmd_init (); zebra_vty_init (); access_list_init (); prefix_list_init (); diff --git a/zebra/rib.h b/zebra/rib.h index dcb307efc..06aa3535d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -23,6 +23,7 @@ #ifndef _ZEBRA_RIB_H #define _ZEBRA_RIB_H +#include "linklist.h" #include "prefix.h" #include "table.h" #include "queue.h" @@ -351,6 +352,15 @@ struct zebra_vrf /* Static route configuration. */ struct route_table *stable[AFI_MAX][SAFI_MAX]; + + /* 2nd pointer type used primarily to quell a warning on + * ALL_LIST_ELEMENTS_RO + */ + struct list _rid_all_sorted_list; + struct list _rid_lo_sorted_list; + struct list *rid_all_sorted_list; + struct list *rid_lo_sorted_list; + struct prefix rid_user_assigned; }; /* diff --git a/zebra/router-id.c b/zebra/router-id.c index bfafc2727..a4eb73ae5 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -36,20 +36,12 @@ #include "log.h" #include "table.h" #include "rib.h" +#include "vrf.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" -/* 2nd pointer type used primarily to quell a warning on - * ALL_LIST_ELEMENTS_RO - */ -static struct list _rid_all_sorted_list; -static struct list _rid_lo_sorted_list; -static struct list *rid_all_sorted_list = &_rid_all_sorted_list; -static struct list *rid_lo_sorted_list = &_rid_lo_sorted_list; -static struct prefix rid_user_assigned; - /* master zebra server structure */ extern struct zebra_t zebrad; @@ -80,44 +72,55 @@ router_id_bad_address (struct connected *ifc) } void -router_id_get (struct prefix *p) +router_id_get (struct prefix *p, vrf_id_t vrf_id) { struct listnode *node; struct connected *c; + struct zebra_vrf *zvrf = vrf_info_get (vrf_id); p->u.prefix4.s_addr = 0; p->family = AF_INET; p->prefixlen = 32; - if (rid_user_assigned.u.prefix4.s_addr) - p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr; - else if (!list_isempty (rid_lo_sorted_list)) + if (zvrf->rid_user_assigned.u.prefix4.s_addr) + p->u.prefix4.s_addr = zvrf->rid_user_assigned.u.prefix4.s_addr; + else if (!list_isempty (zvrf->rid_lo_sorted_list)) { - node = listtail (rid_lo_sorted_list); + node = listtail (zvrf->rid_lo_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } - else if (!list_isempty (rid_all_sorted_list)) + else if (!list_isempty (zvrf->rid_all_sorted_list)) { - node = listtail (rid_all_sorted_list); + node = listtail (zvrf->rid_all_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } } static void -router_id_set (struct prefix *p) +router_id_set (struct prefix *p, vrf_id_t vrf_id) { struct prefix p2; struct listnode *node; struct zserv *client; + struct zebra_vrf *zvrf; + + if (p->u.prefix4.s_addr == 0) /* unset */ + { + zvrf = vrf_info_lookup (vrf_id); + if (! zvrf) + return; + } + else /* set */ + zvrf = vrf_info_get (vrf_id); - rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr; + zvrf->rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr; - router_id_get (&p2); + router_id_get (&p2, vrf_id); for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - zsend_router_id_update (client, &p2); + zsend_router_id_update (client, &p2, vrf_id); } void @@ -128,28 +131,29 @@ router_id_add_address (struct connected *ifc) struct prefix before; struct prefix after; struct zserv *client; + struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id); if (router_id_bad_address (ifc)) return; - router_id_get (&before); + router_id_get (&before, zvrf->vrf_id); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) - l = rid_lo_sorted_list; + l = zvrf->rid_lo_sorted_list; else - l = rid_all_sorted_list; + l = zvrf->rid_all_sorted_list; if (!router_id_find_node (l, ifc)) listnode_add_sort (l, ifc); - router_id_get (&after); + router_id_get (&after, zvrf->vrf_id); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - zsend_router_id_update (client, &after); + zsend_router_id_update (client, &after, zvrf->vrf_id); } void @@ -161,36 +165,51 @@ router_id_del_address (struct connected *ifc) struct prefix before; struct listnode *node; struct zserv *client; + struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id); if (router_id_bad_address (ifc)) return; - router_id_get (&before); + router_id_get (&before, zvrf->vrf_id); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) - l = rid_lo_sorted_list; + l = zvrf->rid_lo_sorted_list; else - l = rid_all_sorted_list; + l = zvrf->rid_all_sorted_list; if ((c = router_id_find_node (l, ifc))) listnode_delete (l, c); - router_id_get (&after); + router_id_get (&after, zvrf->vrf_id); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - zsend_router_id_update (client, &after); + zsend_router_id_update (client, &after, zvrf->vrf_id); } void router_id_write (struct vty *vty) { - if (rid_user_assigned.u.prefix4.s_addr) - vty_out (vty, "router-id %s%s", inet_ntoa (rid_user_assigned.u.prefix4), - VTY_NEWLINE); + struct zebra_vrf *zvrf; + vrf_iter_t iter; + + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + if ((zvrf = vrf_iter2info (iter)) != NULL) + if (zvrf->rid_user_assigned.u.prefix4.s_addr) + { + if (zvrf->vrf_id == VRF_DEFAULT) + vty_out (vty, "router-id %s%s", + inet_ntoa (zvrf->rid_user_assigned.u.prefix4), + VTY_NEWLINE); + else + vty_out (vty, "router-id %s vrf %u%s", + inet_ntoa (zvrf->rid_user_assigned.u.prefix4), + zvrf->vrf_id, + VTY_NEWLINE); + } } DEFUN (router_id, @@ -200,6 +219,7 @@ DEFUN (router_id, "IP address to use for router-id\n") { struct prefix rid; + vrf_id_t vrf_id = VRF_DEFAULT; rid.u.prefix4.s_addr = inet_addr (argv[0]); if (!rid.u.prefix4.s_addr) @@ -208,11 +228,21 @@ DEFUN (router_id, rid.prefixlen = 32; rid.family = AF_INET; - router_id_set (&rid); + if (argc > 1) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + router_id_set (&rid, vrf_id); return CMD_SUCCESS; } +ALIAS (router_id, + router_id_vrf_cmd, + "router-id A.B.C.D " VRF_CMD_STR, + "Manually set the router-id\n" + "IP address to use for router-id\n" + VRF_CMD_HELP_STR) + DEFUN (no_router_id, no_router_id_cmd, "no router-id", @@ -220,16 +250,27 @@ DEFUN (no_router_id, "Remove the manually configured router-id\n") { struct prefix rid; + vrf_id_t vrf_id = VRF_DEFAULT; rid.u.prefix4.s_addr = 0; rid.prefixlen = 0; rid.family = AF_INET; - router_id_set (&rid); + if (argc > 0) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + + router_id_set (&rid, vrf_id); return CMD_SUCCESS; } +ALIAS (no_router_id, + no_router_id_vrf_cmd, + "no router-id " VRF_CMD_STR, + NO_STR + "Remove the manually configured router-id\n" + VRF_CMD_HELP_STR) + static int router_id_cmp (void *a, void *b) { @@ -240,18 +281,27 @@ router_id_cmp (void *a, void *b) } void -router_id_init (void) +router_id_cmd_init (void) { install_element (CONFIG_NODE, &router_id_cmd); install_element (CONFIG_NODE, &no_router_id_cmd); + install_element (CONFIG_NODE, &router_id_vrf_cmd); + install_element (CONFIG_NODE, &no_router_id_vrf_cmd); +} + +void +router_id_init (struct zebra_vrf *zvrf) +{ + zvrf->rid_all_sorted_list = &zvrf->_rid_all_sorted_list; + zvrf->rid_lo_sorted_list = &zvrf->_rid_lo_sorted_list; - memset (rid_all_sorted_list, 0, sizeof (*rid_all_sorted_list)); - memset (rid_lo_sorted_list, 0, sizeof (*rid_lo_sorted_list)); - memset (&rid_user_assigned, 0, sizeof (rid_user_assigned)); + memset (zvrf->rid_all_sorted_list, 0, sizeof (zvrf->_rid_all_sorted_list)); + memset (zvrf->rid_lo_sorted_list, 0, sizeof (zvrf->_rid_lo_sorted_list)); + memset (&zvrf->rid_user_assigned, 0, sizeof (zvrf->rid_user_assigned)); - rid_all_sorted_list->cmp = router_id_cmp; - rid_lo_sorted_list->cmp = router_id_cmp; + zvrf->rid_all_sorted_list->cmp = router_id_cmp; + zvrf->rid_lo_sorted_list->cmp = router_id_cmp; - rid_user_assigned.family = AF_INET; - rid_user_assigned.prefixlen = 32; + zvrf->rid_user_assigned.family = AF_INET; + zvrf->rid_user_assigned.prefixlen = 32; } diff --git a/zebra/router-id.h b/zebra/router-id.h index be12bf502..46d300eea 100644 --- a/zebra/router-id.h +++ b/zebra/router-id.h @@ -33,8 +33,9 @@ extern void router_id_add_address(struct connected *); extern void router_id_del_address(struct connected *); -extern void router_id_init(void); +extern void router_id_init(struct zebra_vrf *); +extern void router_id_cmd_init(void); extern void router_id_write(struct vty *); -extern void router_id_get(struct prefix *); +extern void router_id_get(struct prefix *, vrf_id_t); #endif diff --git a/zebra/zserv.c b/zebra/zserv.c index 85f448c42..e17bb7207 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -735,7 +735,8 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ int -zsend_router_id_update (struct zserv *client, struct prefix *p) +zsend_router_id_update (struct zserv *client, struct prefix *p, + vrf_id_t vrf_id) { struct stream *s; int blen; @@ -1181,9 +1182,9 @@ zread_router_id_add (struct zserv *client, u_short length) /* Router-id information is needed. */ client->ridinfo = 1; - router_id_get (&p); + router_id_get (&p, VRF_DEFAULT); - return zsend_router_id_update (client,&p); + return zsend_router_id_update (client, &p, VRF_DEFAULT); } /* Unregister zebra server router-id information. */ diff --git a/zebra/zserv.h b/zebra/zserv.h index 5e8bccac3..eaa164b95 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -106,7 +106,8 @@ extern int zsend_interface_address (int, struct zserv *, struct interface *, extern int zsend_interface_update (int, struct zserv *, struct interface *); extern int zsend_route_multipath (int, struct zserv *, struct prefix *, struct rib *); -extern int zsend_router_id_update(struct zserv *, struct prefix *); +extern int zsend_router_id_update (struct zserv *, struct prefix *, + vrf_id_t); extern pid_t pid; From fb2bfc1ba2416c1561bc9bfb30dfb5adf3e65616 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:08 +0200 Subject: [PATCH 0743/1342] lib/vrf: enable / disable a VRF A new API vrf_is_enabled() is defined to check whether a VRF is ready to use, that is, to allocate resources in that VRF. Currently there's only one type of resource: socket. Two new hooks VRF_ENABLE_HOOK/VRF_DISABLE_HOOK are introduced to tell the user when a VRF gets ready or to be unavailable. The VRF_ENABLE_HOOK callback is called in the new function vrf_enable(), which is used to let the VRF be ready to use. Till now, only the default VRF can be enabled, and we need do nothing to enable the default, except calling the hook. The VRF_DISABLE_HOOK callback is called in the new function vrf_disable(), which is used to let the VRF be unusable. Till now, it is called only when the VRF is to be deleted. A new utility vrf_socket() is defined to provide a socket in a given VRF to the user. Till now before introducing a way of VRF realization, only the default VRF is enabled since its birth, and vrf_socket() creates socket for only the default VRF. This patch defines the framework of the VRF APIs. The way they serve the users is: - vrf_is_enabled() is used to tell the user whether a VRF is usable; - users are informed by the VRF_ENABLE_HOOK that a VRF gets usable; they can allocate resources after that; - users are informed by the VRF_DISABLE_HOOK that a VRF is to be unavailable, and they must release the resources instantly; - vrf_socket() is used to provide a socket in a given VRF. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- lib/vrf.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/vrf.h | 9 +++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/lib/vrf.c b/lib/vrf.c index ea14fd3c6..d11a98264 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -29,6 +29,8 @@ #include "log.h" #include "memory.h" +#define VRF_DEFAULT_NAME "Default-IP-Routing-Table" + struct vrf { /* Identifier, same as the vector index */ @@ -48,11 +50,18 @@ struct vrf_master { int (*vrf_new_hook) (vrf_id_t, void **); int (*vrf_delete_hook) (vrf_id_t, void **); + int (*vrf_enable_hook) (vrf_id_t, void **); + int (*vrf_disable_hook) (vrf_id_t, void **); } vrf_master = {0,}; /* VRF table */ struct route_table *vrf_table = NULL; +static int vrf_is_enabled (struct vrf *vrf); +static int vrf_enable (struct vrf *vrf); +static void vrf_disable (struct vrf *vrf); + + /* Build the table key */ static void vrf_build_key (vrf_id_t vrf_id, struct prefix *p) @@ -100,6 +109,9 @@ vrf_delete (struct vrf *vrf) { zlog_info ("VRF %u is to be deleted.", vrf->vrf_id); + if (vrf_is_enabled (vrf)) + vrf_disable (vrf); + if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook) (vrf->vrf_id, &vrf->info); @@ -129,6 +141,61 @@ vrf_lookup (vrf_id_t vrf_id) return vrf; } +/* + * Check whether the VRF is enabled - that is, whether the VRF + * is ready to allocate resources. Currently there's only one + * type of resource: socket. + */ +static int +vrf_is_enabled (struct vrf *vrf) +{ + return vrf && vrf->vrf_id == VRF_DEFAULT; +} + +/* + * Enable a VRF - that is, let the VRF be ready to use. + * The VRF_ENABLE_HOOK callback will be called to inform + * that they can allocate resources in this VRF. + * + * RETURN: 1 - enabled successfully; otherwise, 0. + */ +static int +vrf_enable (struct vrf *vrf) +{ + /* Till now, only the default VRF can be enabled. */ + if (vrf->vrf_id == VRF_DEFAULT) + { + zlog_info ("VRF %u is enabled.", vrf->vrf_id); + + if (vrf_master.vrf_enable_hook) + (*vrf_master.vrf_enable_hook) (vrf->vrf_id, &vrf->info); + + return 1; + } + + return 0; +} + +/* + * Disable a VRF - that is, let the VRF be unusable. + * The VRF_DELETE_HOOK callback will be called to inform + * that they must release the resources in the VRF. + */ +static void +vrf_disable (struct vrf *vrf) +{ + if (vrf_is_enabled (vrf)) + { + zlog_info ("VRF %u is to be disabled.", vrf->vrf_id); + + /* Till now, nothing to be done for the default VRF. */ + + if (vrf_master.vrf_disable_hook) + (*vrf_master.vrf_disable_hook) (vrf->vrf_id, &vrf->info); + } +} + + /* Add a VRF hook. Please add hooks before calling vrf_init(). */ void vrf_add_hook (int type, int (*func)(vrf_id_t, void **)) @@ -140,6 +207,12 @@ vrf_add_hook (int type, int (*func)(vrf_id_t, void **)) case VRF_DELETE_HOOK: vrf_master.vrf_delete_hook = func; break; + case VRF_ENABLE_HOOK: + vrf_master.vrf_enable_hook = func; + break; + case VRF_DISABLE_HOOK: + vrf_master.vrf_disable_hook = func; + break; default: break; } @@ -281,7 +354,14 @@ vrf_init (void) } /* Set the default VRF name. */ - default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, "Default-IP-Routing-Table"); + default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, VRF_DEFAULT_NAME); + + /* Enable the default VRF. */ + if (!vrf_enable (default_vrf)) + { + zlog_err ("vrf_init: failed to enable the default VRF!"); + exit (1); + } } /* Terminate VRF module. */ @@ -299,3 +379,23 @@ vrf_terminate (void) vrf_table = NULL; } +/* Create a socket for the VRF. */ +int +vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id) +{ + int ret = -1; + + if (!vrf_is_enabled (vrf_lookup (vrf_id))) + { + errno = ENOSYS; + return -1; + } + + if (vrf_id == VRF_DEFAULT) + ret = socket (domain, type, protocol); + else + errno = ENOSYS; + + return ret; +} + diff --git a/lib/vrf.h b/lib/vrf.h index d7b799875..653fabf90 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -44,6 +44,8 @@ #define VRF_NEW_HOOK 0 /* a new VRF is just created */ #define VRF_DELETE_HOOK 1 /* a VRF is to be deleted */ +#define VRF_ENABLE_HOOK 2 /* a VRF is ready to use */ +#define VRF_DISABLE_HOOK 3 /* a VRF is to be unusable */ /* * Add a specific hook to VRF module. @@ -114,5 +116,12 @@ extern struct list *vrf_iflist_get (vrf_id_t); extern void vrf_init (void); extern void vrf_terminate (void); +/* + * VRF utilities + */ + +/* Create a socket serving for the given VRF */ +extern int vrf_socket (int, int, int, vrf_id_t); + #endif /*_ZEBRA_VRF_H*/ From 267ceb2ce3adf4ce1357deb7ce48f151d6c58b92 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:09 +0200 Subject: [PATCH 0744/1342] zebra: add hooks upon enabling / disabling a VRF zebra_vrf_enable() is the callback for VRF_ENABLE_HOOK. It presently needs do nothing. zebra_vrf_disable() is the callback for VRF_DISABLE_HOOK. It presently withdraws routes, shuts down interfaces, and clears the router-id candidates in that VRF. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/main.c | 40 ++++++++++++++++++++++++++++++++++++++++ zebra/rib.h | 1 + zebra/test_main.c | 37 +++++++++++++++++++++++++++++++++++++ zebra/zebra_rib.c | 2 +- 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/zebra/main.c b/zebra/main.c index c7e3b68c3..1e9757b61 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -221,11 +221,51 @@ zebra_vrf_new (vrf_id_t vrf_id, void **info) return 0; } +/* Callback upon enabling a VRF. */ +static int +zebra_vrf_enable (vrf_id_t vrf_id, void **info) +{ + struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); + + assert (zvrf); + + return 0; +} + +/* Callback upon disabling a VRF. */ +static int +zebra_vrf_disable (vrf_id_t vrf_id, void **info) +{ + struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); + struct listnode *list_node; + struct interface *ifp; + + assert (zvrf); + + rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); + rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); + + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), list_node, ifp)) + { + int operative = if_is_operative (ifp); + UNSET_FLAG (ifp->flags, IFF_UP); + if (operative) + if_down (ifp); + } + + list_delete_all_node (zvrf->rid_all_sorted_list); + list_delete_all_node (zvrf->rid_lo_sorted_list); + + return 0; +} + /* Zebra VRF initialization. */ static void zebra_vrf_init (void) { vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new); + vrf_add_hook (VRF_ENABLE_HOOK, zebra_vrf_enable); + vrf_add_hook (VRF_DISABLE_HOOK, zebra_vrf_disable); vrf_init (); } diff --git a/zebra/rib.h b/zebra/rib.h index 06aa3535d..5663f3033 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -473,6 +473,7 @@ extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *, vrf_id_t); extern void rib_update (vrf_id_t); extern void rib_weed_tables (void); extern void rib_sweep_route (void); +extern void rib_close_table (struct route_table *); extern void rib_close (void); extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); diff --git a/zebra/test_main.c b/zebra/test_main.c index aad616f7f..17014ea73 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -212,11 +212,48 @@ zebra_vrf_new (vrf_id_t vrf_id, void **info) return 0; } +/* Callback upon enabling a VRF. */ +static int +zebra_vrf_enable (vrf_id_t vrf_id, void **info) +{ + struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); + + assert (zvrf); + + return 0; +} + +/* Callback upon disabling a VRF. */ +static int +zebra_vrf_disable (vrf_id_t vrf_id, void **info) +{ + struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); + struct listnode *list_node; + struct interface *ifp; + + assert (zvrf); + + rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); + rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); + + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), list_node, ifp)) + { + int operative = if_is_operative (ifp); + UNSET_FLAG (ifp->flags, IFF_UP); + if (operative) + if_down (ifp); + } + + return 0; +} + /* Zebra VRF initialization. */ static void zebra_vrf_init (void) { vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new); + vrf_add_hook (VRF_ENABLE_HOOK, zebra_vrf_enable); + vrf_add_hook (VRF_DISABLE_HOOK, zebra_vrf_disable); vrf_init (); } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 68ae397bf..9d966a0f2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3270,7 +3270,7 @@ rib_score_proto (u_char proto) } /* Close RIB and clean up kernel routes. */ -static void +void rib_close_table (struct route_table *table) { struct route_node *rn; From 49f76097fc191761db8482aa3bf6e6322c52c647 Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Fri, 22 May 2015 11:40:10 +0200 Subject: [PATCH 0745/1342] zebra: maintain RTADV per VRF This moves the global variable "rtadv" into the "struct zebra_vrf", so that RTADV feature can work per VRF. * rtadv.c/rtadv.h: Add a proper parameter to the functions so that the entity of the "struct zebra_vrf" and interfaces can be obtained from the specified VRF. The old rtadv_init() is splitted into: - rtadv_cmd_init(): it installs the RTADV commands; is called from main(); - new rtadv_init(): it creates the socket; is called from zebra_vrf_enable(). rtadv_terminate() is added to stop the threads, close the socket and clear the counters. It is called from zebra_vrf_disable(). rtadv_make_socket() now calls vrf_socket() to create a socket in the VRF. * interface.h and rib.h: define the macro RTADV. * main.c: according changes, refer to rtadv.c. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Vincent JARDIN Signed-off-by: David Lamparter --- zebra/interface.h | 2 + zebra/main.c | 9 ++- zebra/rib.h | 27 +++++++++ zebra/rtadv.c | 147 +++++++++++++++++++++++++--------------------- zebra/rtadv.h | 4 +- 5 files changed, 121 insertions(+), 68 deletions(-) diff --git a/zebra/interface.h b/zebra/interface.h index 0f081f6b3..fe2460435 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -38,11 +38,13 @@ #define IF_ZEBRA_SHUTDOWN_ON 1 /* Router advertisement feature. */ +#ifndef RTADV #if (defined(LINUX_IPV6) && (!defined(__GLIBC__) || defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) #ifdef HAVE_RTADV #define RTADV #endif #endif +#endif #ifdef RTADV /* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */ diff --git a/zebra/main.c b/zebra/main.c index 1e9757b61..08cc247d8 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -229,6 +229,9 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info) assert (zvrf); +#ifdef RTADV + rtadv_init (zvrf); +#endif return 0; } @@ -253,6 +256,10 @@ zebra_vrf_disable (vrf_id_t vrf_id, void **info) if_down (ifp); } +#ifdef RTADV + rtadv_terminate (zvrf); +#endif + list_delete_all_node (zvrf->rid_all_sorted_list); list_delete_all_node (zvrf->rid_lo_sorted_list); @@ -394,7 +401,7 @@ main (int argc, char **argv) access_list_init (); prefix_list_init (); #ifdef RTADV - rtadv_init (); + rtadv_cmd_init (); #endif #ifdef HAVE_IRDP irdp_init(); diff --git a/zebra/rib.h b/zebra/rib.h index 5663f3033..99729411f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -332,6 +332,29 @@ struct nexthop_vrfid vrf_id_t vrf_id; }; +/* Router advertisement feature. */ +#ifndef RTADV +#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) + #ifdef HAVE_RTADV + #define RTADV + #endif +#endif +#endif + +#if defined (HAVE_IPV6) && defined (RTADV) +/* Structure which hold status of router advertisement. */ +struct rtadv +{ + int sock; + + int adv_if_count; + int adv_msec_if_count; + + struct thread *ra_read; + struct thread *ra_timer; +}; +#endif /* RTADV && HAVE_IPV6 */ + /* Routing table instance. */ struct zebra_vrf { @@ -361,6 +384,10 @@ struct zebra_vrf struct list *rid_all_sorted_list; struct list *rid_lo_sorted_list; struct prefix rid_user_assigned; + +#if defined (HAVE_IPV6) && defined (RTADV) + struct rtadv rtadv; +#endif /* RTADV && HAVE_IPV6 */ }; /* diff --git a/zebra/rtadv.c b/zebra/rtadv.c index b3959823f..be4aeb1b1 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -31,6 +31,7 @@ #include "linklist.h" #include "command.h" #include "privs.h" +#include "vrf.h" #include "zebra/interface.h" #include "zebra/rtadv.h" @@ -62,31 +63,11 @@ extern struct zebra_t zebrad; enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_TIMER_MSEC, RTADV_READ}; -static void rtadv_event (enum rtadv_event, int); +static void rtadv_event (struct zebra_vrf *, enum rtadv_event, int); static int if_join_all_router (int, struct interface *); static int if_leave_all_router (int, struct interface *); -/* Structure which hold status of router advertisement. */ -struct rtadv -{ - int sock; - - int adv_if_count; - int adv_msec_if_count; - - struct thread *ra_read; - struct thread *ra_timer; -}; - -struct rtadv *rtadv = NULL; - -static struct rtadv * -rtadv_new (void) -{ - return XCALLOC (MTYPE_TMP, sizeof (struct rtadv)); -} - static int rtadv_recv_packet (int sock, u_char *buf, int buflen, struct sockaddr_in6 *from, unsigned int *ifindex, @@ -389,24 +370,25 @@ rtadv_send_packet (int sock, struct interface *ifp) static int rtadv_timer (struct thread *thread) { + struct zebra_vrf *zvrf = THREAD_ARG (thread); struct listnode *node, *nnode; struct interface *ifp; struct zebra_if *zif; int period; - rtadv->ra_timer = NULL; - if (rtadv->adv_msec_if_count == 0) + zvrf->rtadv.ra_timer = NULL; + if (zvrf->rtadv.adv_msec_if_count == 0) { period = 1000; /* 1 s */ - rtadv_event (RTADV_TIMER, 1 /* 1 s */); + rtadv_event (zvrf, RTADV_TIMER, 1 /* 1 s */); } else { period = 10; /* 10 ms */ - rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */); + rtadv_event (zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */); } - for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) + for (ALL_LIST_ELEMENTS (vrf_iflist (zvrf->vrf_id), node, nnode, ifp)) { if (if_is_loopback (ifp) || ! if_is_operative (ifp)) continue; @@ -421,7 +403,7 @@ rtadv_timer (struct thread *thread) /* FIXME: using MaxRtrAdvInterval each time isn't what section 6.2.4 of RFC4861 tells to do. */ zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; - rtadv_send_packet (rtadv->sock, ifp); + rtadv_send_packet (zvrf->rtadv.sock, ifp); } } } @@ -431,9 +413,11 @@ rtadv_timer (struct thread *thread) static void rtadv_process_solicit (struct interface *ifp) { - zlog_info ("Router solicitation received on %s", ifp->name); + struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); - rtadv_send_packet (rtadv->sock, ifp); + zlog_info ("Router solicitation received on %s vrf %u", ifp->name, zvrf->vrf_id); + + rtadv_send_packet (zvrf->rtadv.sock, ifp); } static void @@ -443,17 +427,18 @@ rtadv_process_advert (void) } static void -rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit) +rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, + int hoplimit, vrf_id_t vrf_id) { struct icmp6_hdr *icmph; struct interface *ifp; struct zebra_if *zif; /* Interface search. */ - ifp = if_lookup_by_index (ifindex); + ifp = if_lookup_by_index_vrf (ifindex, vrf_id); if (ifp == NULL) { - zlog_warn ("Unknown interface index: %d", ifindex); + zlog_warn ("Unknown interface index: %d, vrf %u", ifindex, vrf_id); return; } @@ -508,12 +493,13 @@ rtadv_read (struct thread *thread) struct sockaddr_in6 from; unsigned int ifindex = 0; int hoplimit = -1; + struct zebra_vrf *zvrf = THREAD_ARG (thread); sock = THREAD_FD (thread); - rtadv->ra_read = NULL; + zvrf->rtadv.ra_read = NULL; /* Register myself. */ - rtadv_event (RTADV_READ, sock); + rtadv_event (zvrf, RTADV_READ, sock); len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); @@ -523,13 +509,13 @@ rtadv_read (struct thread *thread) return len; } - rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit); + rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id); return 0; } static int -rtadv_make_socket (void) +rtadv_make_socket (vrf_id_t vrf_id) { int sock; int ret; @@ -539,7 +525,7 @@ rtadv_make_socket (void) zlog_err ("rtadv_make_socket: could not raise privs, %s", safe_strerror (errno) ); - sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + sock = vrf_socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, vrf_id); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("rtadv_make_socket: could not lower privs, %s", @@ -661,9 +647,11 @@ DEFUN (ipv6_nd_suppress_ra, { struct interface *ifp; struct zebra_if *zif; + struct zebra_vrf *zvrf; ifp = vty->index; zif = ifp->info; + zvrf = vrf_info_lookup (ifp->vrf_id); if (if_is_loopback (ifp)) { @@ -675,12 +663,12 @@ DEFUN (ipv6_nd_suppress_ra, { zif->rtadv.AdvSendAdvertisements = 0; zif->rtadv.AdvIntervalTimer = 0; - rtadv->adv_if_count--; + zvrf->rtadv.adv_if_count--; - if_leave_all_router (rtadv->sock, ifp); + if_leave_all_router (zvrf->rtadv.sock, ifp); - if (rtadv->adv_if_count == 0) - rtadv_event (RTADV_STOP, 0); + if (zvrf->rtadv.adv_if_count == 0) + rtadv_event (zvrf, RTADV_STOP, 0); } return CMD_SUCCESS; @@ -696,9 +684,11 @@ DEFUN (no_ipv6_nd_suppress_ra, { struct interface *ifp; struct zebra_if *zif; + struct zebra_vrf *zvrf; ifp = vty->index; zif = ifp->info; + zvrf = vrf_info_lookup (ifp->vrf_id); if (if_is_loopback (ifp)) { @@ -710,12 +700,12 @@ DEFUN (no_ipv6_nd_suppress_ra, { zif->rtadv.AdvSendAdvertisements = 1; zif->rtadv.AdvIntervalTimer = 0; - rtadv->adv_if_count++; + zvrf->rtadv.adv_if_count++; - if_join_all_router (rtadv->sock, ifp); + if_join_all_router (zvrf->rtadv.sock, ifp); - if (rtadv->adv_if_count == 1) - rtadv_event (RTADV_START, rtadv->sock); + if (zvrf->rtadv.adv_if_count == 1) + rtadv_event (zvrf, RTADV_START, zvrf->rtadv.sock); } return CMD_SUCCESS; @@ -732,6 +722,7 @@ DEFUN (ipv6_nd_ra_interval_msec, unsigned interval; struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000); if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) @@ -741,10 +732,10 @@ DEFUN (ipv6_nd_ra_interval_msec, } if (zif->rtadv.MaxRtrAdvInterval % 1000) - rtadv->adv_msec_if_count--; + zvrf->rtadv.adv_msec_if_count--; if (interval % 1000) - rtadv->adv_msec_if_count++; + zvrf->rtadv.adv_msec_if_count++; zif->rtadv.MaxRtrAdvInterval = interval; zif->rtadv.MinRtrAdvInterval = 0.33 * interval; @@ -764,6 +755,7 @@ DEFUN (ipv6_nd_ra_interval, unsigned interval; struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800); if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) @@ -773,7 +765,7 @@ DEFUN (ipv6_nd_ra_interval, } if (zif->rtadv.MaxRtrAdvInterval % 1000) - rtadv->adv_msec_if_count--; + zvrf->rtadv.adv_msec_if_count--; /* convert to milliseconds */ interval = interval * 1000; @@ -795,12 +787,14 @@ DEFUN (no_ipv6_nd_ra_interval, { struct interface *ifp; struct zebra_if *zif; + struct zebra_vrf *zvrf; ifp = (struct interface *) vty->index; zif = ifp->info; + zvrf = vrf_info_lookup (ifp->vrf_id); if (zif->rtadv.MaxRtrAdvInterval % 1000) - rtadv->adv_msec_if_count--; + zvrf->rtadv.adv_msec_if_count--; zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; @@ -1540,9 +1534,6 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) char buf[PREFIX_STRLEN]; int interval; - if (! rtadv) - return; - zif = ifp->info; if (! if_is_loopback (ifp)) @@ -1627,16 +1618,18 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) static void -rtadv_event (enum rtadv_event event, int val) +rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val) { + struct rtadv *rtadv = &zvrf->rtadv; + switch (event) { case RTADV_START: if (! rtadv->ra_read) - rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); + rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val); if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer, - NULL, 0); + zvrf, 0); break; case RTADV_STOP: if (rtadv->ra_timer) @@ -1652,17 +1645,17 @@ rtadv_event (enum rtadv_event event, int val) break; case RTADV_TIMER: if (! rtadv->ra_timer) - rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL, + rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, zvrf, val); break; case RTADV_TIMER_MSEC: if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer, - NULL, val); + zvrf, val); break; case RTADV_READ: if (! rtadv->ra_read) - rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); + rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val); break; default: break; @@ -1671,17 +1664,29 @@ rtadv_event (enum rtadv_event event, int val) } void -rtadv_init (void) +rtadv_init (struct zebra_vrf *zvrf) { - int sock; + zvrf->rtadv.sock = rtadv_make_socket (zvrf->vrf_id); +} - sock = rtadv_make_socket (); - if (sock < 0) - return; +void +rtadv_terminate (struct zebra_vrf *zvrf) +{ + rtadv_event (zvrf, RTADV_STOP, 0); + + if (zvrf->rtadv.sock >= 0) + { + close (zvrf->rtadv.sock); + zvrf->rtadv.sock = -1; + } - rtadv = rtadv_new (); - rtadv->sock = sock; + zvrf->rtadv.adv_if_count = 0; + zvrf->rtadv.adv_msec_if_count = 0; +} +void +rtadv_cmd_init (void) +{ install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); @@ -1776,7 +1781,17 @@ if_leave_all_router (int sock, struct interface *ifp) #else void -rtadv_init (void) +rtadv_init (struct zebra_vrf *zvrf) +{ + /* Empty.*/; +} +void +rtadv_terminate (struct zebra_vrf *zvrf) +{ + /* Empty.*/; +} +void +rtadv_cmd_init (void) { /* Empty.*/; } diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 1e1aec9ac..76f98cf2c 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -100,6 +100,8 @@ extern const char *rtadv_pref_strs[]; #endif /* RTADV */ -extern void rtadv_init (void); +extern void rtadv_init (struct zebra_vrf *); +extern void rtadv_terminate (struct zebra_vrf *); +extern void rtadv_cmd_init (void); #endif /* _ZEBRA_RTADV_H */ From d6cf5134c05a7890738411852d9357ee5bb322f3 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 2 Jun 2015 08:31:38 +0200 Subject: [PATCH 0746/1342] zebra: fix VRF code for *BSD There seems to be no rtm_table in struct rt_msghdr, at least on the systems I have access to... Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index bdfb148db..374ca412a 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -962,7 +962,7 @@ rtm_read (struct rt_msghdr *rtm) || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, - NULL, 0, VRF_DEFAULT, rtm->rtm_table, 0, 0, SAFI_UNICAST); + NULL, 0, VRF_DEFAULT, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, VRF_DEFAULT, SAFI_UNICAST); From 758fb8f99a7bfac3d31c419fd1a5694fc5f33f6a Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Thu, 3 Jul 2014 18:23:09 +0800 Subject: [PATCH 0747/1342] zebra, lib/memtypes.c: the netlink sockets work per VRF This patch lets the netlink sockets work per VRF. * The definition of "struct nlsock" is moved into zebra/rib.h. * The previous global variables "netlink" and "netlink_cmd" now become the members of "struct zebra_vrf", and are initialized in zebra_vrf_alloc(). * All relative functions now work for a specific VRF, by adding a new parameter which specifies the working VRF, except those functions in which the VRF ID can be obtained from the interface. * kernel_init(), interface_list() and route_read() are now also working per VRF, and moved from main() to zebra_vrf_enable(). * A new function kernel_terminate() is added to release the netlink sockets. It is called from zebra_vrf_disable(). * Correct VRF ID, instead of the previous VRF_DEFAULT, are now passed to the functions of processing interfaces or route entries. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Donald Sharp --- lib/memtypes.c | 1 + zebra/if_ioctl.c | 9 +- zebra/if_ioctl_solaris.c | 9 +- zebra/if_netlink.c | 4 +- zebra/if_sysctl.c | 10 +- zebra/kernel_null.c | 6 +- zebra/kernel_socket.c | 16 ++- zebra/main.c | 8 +- zebra/rib.h | 17 +++ zebra/rt_netlink.c | 219 ++++++++++++++++++++++----------------- zebra/rt_netlink.h | 4 +- zebra/rtread_getmsg.c | 6 +- zebra/rtread_netlink.c | 4 +- zebra/rtread_sysctl.c | 8 +- zebra/test_main.c | 7 +- zebra/zebra_rib.c | 14 +++ zebra/zserv.h | 7 +- 17 files changed, 229 insertions(+), 120 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index 3e599f673..60f24e6a7 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -85,6 +85,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_STATIC_IPV6, "Static IPv6 route" }, { MTYPE_RIB_DEST, "RIB destination" }, { MTYPE_RIB_TABLE_INFO, "RIB table info" }, + { MTYPE_NETLINK_NAME, "Netlink name" }, { -1, NULL }, }; diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index f357e1544..8df877dba 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -29,8 +29,10 @@ #include "connected.h" #include "memory.h" #include "log.h" +#include "vrf.h" #include "zebra/interface.h" +#include "zebra/rib.h" /* Interface looking up using infamous SIOCGIFCONF. */ static int @@ -442,8 +444,13 @@ interface_info_ioctl () /* Lookup all interface information. */ void -interface_list () +interface_list (struct zebra_vrf *zvrf) { + if (zvrf->vrf_id != VRF_DEFAULT) + { + zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id); + return; + } /* Linux can do both proc & ioctl, ioctl is the only way to get interface aliases in 2.2 series kernels. */ #ifdef HAVE_PROC_NET_DEV diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index fc384ea29..3f33f749a 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -30,8 +30,10 @@ #include "memory.h" #include "log.h" #include "privs.h" +#include "vrf.h" #include "zebra/interface.h" +#include "zebra/rib.h" void lifreq_set_name (struct lifreq *, const char *); int if_get_flags_direct (const char *, uint64_t *, unsigned int af); @@ -349,8 +351,13 @@ interface_info_ioctl (struct interface *ifp) /* Lookup all interface information. */ void -interface_list () +interface_list (struct zebra_vrf *zvrf) { + if (zvrf->vrf_id != VRF_DEFAULT) + { + zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id); + return; + } interface_list_ioctl (AF_INET); interface_list_ioctl (AF_INET6); interface_list_ioctl (AF_UNSPEC); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 87014160c..245b7b250 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -27,7 +27,7 @@ /* Interface information read by netlink. */ void -interface_list (void) +interface_list (struct zebra_vrf *zvrf) { - interface_lookup_netlink (); + interface_lookup_netlink (zvrf); } diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index ffa6927d6..bb48f6182 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -30,9 +30,11 @@ #include "ioctl.h" #include "log.h" #include "interface.h" +#include "vrf.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" +#include "zebra/rib.h" void ifstat_update_sysctl (void) @@ -90,7 +92,7 @@ ifstat_update_sysctl (void) /* Interface listing up function using sysctl(). */ void -interface_list () +interface_list (struct zebra_vrf *zvrf) { caddr_t ref, buf, end; size_t bufsiz; @@ -107,6 +109,12 @@ interface_list () 0 }; + if (zvrf->vrf_id != VRF_DEFAULT) + { + zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id); + return; + } + /* Query buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 4cd43db48..58d2c3ae7 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -28,6 +28,7 @@ #include "zebra/rt.h" #include "zebra/redistribute.h" #include "zebra/connected.h" +#include "zebra/rib.h" int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA @@ -64,9 +65,10 @@ int kernel_address_delete_ipv4 (struct interface *a, struct connected *b) return 0; } -void kernel_init (void) { return; } +void kernel_init (struct zebra_vrf *zvrf) { return; } +void kernel_terminate (struct zebra_vrf *zvrf) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak route_read = kernel_init #else -void route_read (void) { return; } +void route_read (struct zebra_vrf *zvrf) { return; } #endif diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 374ca412a..fd0d8fd1b 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -38,6 +38,7 @@ #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/kernel_socket.h" +#include "zebra/rib.h" extern struct zebra_privs_t zserv_privs; extern struct zebra_t zebrad; @@ -1273,8 +1274,11 @@ kernel_read (struct thread *thread) /* Make routing socket. */ static void -routing_socket (void) +routing_socket (struct zebra_vrf *zvrf) { + if (zvrf->vrf_id != VRF_DEFAULT) + return; + if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("routing_socket: Can't raise privileges"); @@ -1305,7 +1309,13 @@ routing_socket (void) /* Exported interface function. This function simply calls routing_socket (). */ void -kernel_init (void) +kernel_init (struct zebra_vrf *zvrf) +{ + routing_socket (zvrf); +} + +void +kernel_terminate (struct zebra_vrf *zvrf) { - routing_socket (); + return; } diff --git a/zebra/main.c b/zebra/main.c index 08cc247d8..c5d1d76c5 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -232,6 +232,10 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info) #ifdef RTADV rtadv_init (zvrf); #endif + kernel_init (zvrf); + interface_list (zvrf); + route_read (zvrf); + return 0; } @@ -259,6 +263,7 @@ zebra_vrf_disable (vrf_id_t vrf_id, void **info) #ifdef RTADV rtadv_terminate (zvrf); #endif + kernel_terminate (zvrf); list_delete_all_node (zvrf->rid_all_sorted_list); list_delete_all_node (zvrf->rid_lo_sorted_list); @@ -412,9 +417,6 @@ main (int argc, char **argv) /* Initialize VRF module, and make kernel routing socket. */ zebra_vrf_init (); - kernel_init (); - interface_list (); - route_read (); #ifdef HAVE_SNMP zebra_snmp_init (); diff --git a/zebra/rib.h b/zebra/rib.h index 99729411f..8328f23bb 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -355,6 +355,17 @@ struct rtadv }; #endif /* RTADV && HAVE_IPV6 */ +#ifdef HAVE_NETLINK +/* Socket interface to kernel */ +struct nlsock +{ + int sock; + int seq; + struct sockaddr_nl snl; + const char *name; +}; +#endif + /* Routing table instance. */ struct zebra_vrf { @@ -376,6 +387,12 @@ struct zebra_vrf /* Static route configuration. */ struct route_table *stable[AFI_MAX][SAFI_MAX]; +#ifdef HAVE_NETLINK + struct nlsock netlink; /* kernel messages */ + struct nlsock netlink_cmd; /* command channel */ + struct thread *t_netlink; +#endif + /* 2nd pointer type used primarily to quell a warning on * ALL_LIST_ELEMENTS_RO */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cf6ce0cde..0f0f3fed3 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -46,16 +46,6 @@ #include "rt_netlink.h" -/* Socket interface to kernel */ -struct nlsock -{ - int sock; - int seq; - struct sockaddr_nl snl; - const char *name; -} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */ - netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */ - static const struct message nlmsg_str[] = { {RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_DELROUTE, "RTM_DELROUTE"}, @@ -155,7 +145,7 @@ netlink_recvbuf (struct nlsock *nl, uint32_t newsize) /* Make socket for Linux netlink interface. */ static int -netlink_socket (struct nlsock *nl, unsigned long groups) +netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id) { int ret; struct sockaddr_nl snl; @@ -169,7 +159,7 @@ netlink_socket (struct nlsock *nl, unsigned long groups) return -1; } - sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id); if (sock < 0) { zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name, @@ -273,8 +263,9 @@ netlink_request (int family, int type, struct nlsock *nl) /* Receive message from netlink interface and pass those information to the given function. */ static int -netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), - struct nlsock *nl) +netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, + vrf_id_t), + struct nlsock *nl, struct zebra_vrf *zvrf) { int status; int ret = 0; @@ -363,7 +354,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), } /* Deal with errors that occur because of races in link handling */ - if (nl == &netlink_cmd + if (nl == &zvrf->netlink_cmd && ((msg_type == RTM_DELROUTE && (-errnum == ENODEV || -errnum == ESRCH)) || (msg_type == RTM_NEWROUTE && -errnum == EEXIST))) @@ -393,16 +384,17 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), /* skip unsolicited messages originating from command socket * linux sets the originators port-id for {NEW|DEL}ADDR messages, * so this has to be checked here. */ - if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid + if (nl != &zvrf->netlink_cmd + && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s packet comes from %s", - netlink_cmd.name, nl->name); + zvrf->netlink_cmd.name, nl->name); continue; } - error = (*filter) (&snl, h); + error = (*filter) (&snl, h, zvrf->vrf_id); if (error < 0) { zlog (NULL, LOG_ERR, "%s filter function error", nl->name); @@ -473,7 +465,8 @@ netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int -netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { int len; struct ifinfomsg *ifi; @@ -509,7 +502,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) name = (char *) RTA_DATA (tb[IFLA_IFNAME]); /* Add interface. */ - ifp = if_get_by_name (name); + ifp = if_get_by_name_vrf (name, vrf_id); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); @@ -526,7 +519,8 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Lookup interface IPv4/IPv6 address. */ static int -netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { int len; struct ifaddrmsg *ifa; @@ -556,19 +550,19 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); - ifp = if_lookup_by_index (ifa->ifa_index); + ifp = if_lookup_by_index_vrf (ifa->ifa_index, vrf_id); if (ifp == NULL) { - zlog_err ("netlink_interface_addr can't find interface by index %d", - ifa->ifa_index); + zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u", + ifa->ifa_index, vrf_id); return -1; } if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; - zlog_debug ("netlink_interface_addr %s %s:", - lookup (nlmsg_str, h->nlmsg_type), ifp->name); + zlog_debug ("netlink_interface_addr %s %s vrf %u:", + lookup (nlmsg_str, h->nlmsg_type), ifp->name, vrf_id); if (tb[IFA_LOCAL]) zlog_debug (" IFA_LOCAL %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), @@ -661,7 +655,8 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Looking up routing table by netlink interface. */ static int -netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { int len; struct rtmsg *rtm; @@ -744,7 +739,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, - VRF_DEFAULT, table, metric, 0, SAFI_UNICAST); + vrf_id, table, metric, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -760,7 +755,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) rib->distance = 0; rib->flags = flags; rib->metric = metric; - rib->vrf_id = VRF_DEFAULT; + rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -810,7 +805,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, VRF_DEFAULT, + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id, table, metric, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -835,7 +830,8 @@ static const struct message rtproto_str[] = { /* Routing information change from the kernel. */ static int -netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { int len; struct rtmsg *rtm; @@ -856,18 +852,19 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { /* If this is not route add/delete message print warning. */ - zlog_warn ("Kernel message: %d\n", h->nlmsg_type); + zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id); return 0; } /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s %s %s proto %s", + zlog_debug ("%s %s %s proto %s vrf %u", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", - lookup (rtproto_str, rtm->rtm_protocol)); + lookup (rtproto_str, rtm->rtm_protocol), + vrf_id); if (rtm->rtm_type != RTN_UNICAST) { @@ -899,7 +896,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (rtm->rtm_src_len != 0) { - zlog_warn ("netlink_route_change(): no src len"); + zlog_warn ("netlink_route_change(): no src len, vrf %u", vrf_id); return 0; } @@ -936,15 +933,15 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (IS_ZEBRA_DEBUG_KERNEL) { char buf[PREFIX_STRLEN]; - zlog_debug ("%s %s", + zlog_debug ("%s %s vrf %u", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", - prefix2str (&p, buf, sizeof(buf))); + prefix2str (&p, buf, sizeof(buf)), vrf_id); } if (h->nlmsg_type == RTM_NEWROUTE) { if (!tb[RTA_MULTIPATH]) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, VRF_DEFAULT, + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id, table, metric, 0, SAFI_UNICAST); else { @@ -961,7 +958,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) rib->distance = 0; rib->flags = 0; rib->metric = metric; - rib->vrf_id = VRF_DEFAULT; + rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -1004,7 +1001,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } } else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, SAFI_UNICAST); } @@ -1020,16 +1017,16 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (IS_ZEBRA_DEBUG_KERNEL) { char buf[PREFIX_STRLEN]; - zlog_debug ("%s %s", + zlog_debug ("%s %s vrf %u", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", - prefix2str (&p, buf, sizeof(buf))); + prefix2str (&p, buf, sizeof(buf)), vrf_id); } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, table, + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, metric, 0, SAFI_UNICAST); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -1038,7 +1035,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } static int -netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { int len; struct ifinfomsg *ifi; @@ -1051,8 +1049,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ - zlog_warn ("netlink_link_change: wrong kernel message %d\n", - h->nlmsg_type); + zlog_warn ("netlink_link_change: wrong kernel message %d vrf %u\n", + h->nlmsg_type, vrf_id); return 0; } @@ -1069,7 +1067,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); + zlog_debug ("%s: ignoring IFLA_WIRELESS message, vrf %u", __func__, + vrf_id); return 0; } #endif /* IFLA_WIRELESS */ @@ -1081,12 +1080,12 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { - ifp = if_lookup_by_name (name); + ifp = if_lookup_by_name_vrf (name, vrf_id); if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) - ifp = if_get_by_name (name); + ifp = if_get_by_name_vrf (name, vrf_id); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; @@ -1127,12 +1126,12 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) else { /* RTM_DELLINK. */ - ifp = if_lookup_by_name (name); + ifp = if_lookup_by_name_vrf (name, vrf_id); if (ifp == NULL) { - zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", - name); + zlog_warn ("interface %s vrf %u is deleted but can't find", + name, vrf_id); return 0; } @@ -1143,7 +1142,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } static int -netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { /* JF: Ignore messages that aren't from the kernel */ if ( snl->nl_pid != 0 ) @@ -1155,25 +1155,26 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) switch (h->nlmsg_type) { case RTM_NEWROUTE: - return netlink_route_change (snl, h); + return netlink_route_change (snl, h, vrf_id); break; case RTM_DELROUTE: - return netlink_route_change (snl, h); + return netlink_route_change (snl, h, vrf_id); break; case RTM_NEWLINK: - return netlink_link_change (snl, h); + return netlink_link_change (snl, h, vrf_id); break; case RTM_DELLINK: - return netlink_link_change (snl, h); + return netlink_link_change (snl, h, vrf_id); break; case RTM_NEWADDR: - return netlink_interface_addr (snl, h); + return netlink_interface_addr (snl, h, vrf_id); break; case RTM_DELADDR: - return netlink_interface_addr (snl, h); + return netlink_interface_addr (snl, h, vrf_id); break; default: - zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type); + zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type, + vrf_id); break; } return 0; @@ -1181,32 +1182,32 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Interface lookup by netlink socket. */ int -interface_lookup_netlink (void) +interface_lookup_netlink (struct zebra_vrf *zvrf) { int ret; /* Get interface information. */ - ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); + ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd); if (ret < 0) return ret; - ret = netlink_parse_info (netlink_interface, &netlink_cmd); + ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; /* Get IPv4 address of the interfaces. */ - ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd); + ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd); if (ret < 0) return ret; - ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); + ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 address of the interfaces. */ - ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd); + ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd); if (ret < 0) return ret; - ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); + ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ @@ -1217,24 +1218,24 @@ interface_lookup_netlink (void) /* Routing table read function using netlink interface. Only called bootstrap time. */ int -netlink_route_read (void) +netlink_route_read (struct zebra_vrf *zvrf) { int ret; /* Get IPv4 routing table. */ - ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); + ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd); if (ret < 0) return ret; - ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); + ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 routing table. */ - ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd); + ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd); if (ret < 0) return ret; - ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); + ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ @@ -1307,15 +1308,17 @@ addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data) } static int -netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) +netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h, + vrf_id_t vrf_id) { - zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); + zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type, + vrf_id); return 0; } /* sendmsg() to netlink socket then recvmsg(). */ static int -netlink_talk (struct nlmsghdr *n, struct nlsock *nl) +netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf) { int status; struct sockaddr_nl snl; @@ -1364,7 +1367,7 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) * Get reply from netlink socket. * The reply should either be an acknowlegement or an error. */ - return netlink_parse_info (netlink_talk_filter, nl); + return netlink_parse_info (netlink_talk_filter, nl, zvrf); } /* This function takes a nexthop as argument and adds @@ -1558,12 +1561,13 @@ _netlink_route_debug( struct prefix *p, struct nexthop *nexthop, const char *routedesc, - int family) + int family, + struct zebra_vrf *zvrf) { if (IS_ZEBRA_DEBUG_KERNEL) { char buf[PREFIX_STRLEN]; - zlog_debug ("netlink_route_multipath() (%s): %s %s type %s", + zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s", routedesc, lookup (nlmsg_str, cmd), prefix2str (p, buf, sizeof(buf)), @@ -1591,6 +1595,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, char buf[NL_PKT_BUF_SIZE]; } req; + struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id); + memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); @@ -1675,7 +1681,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, { routedesc = recursing ? "recursive, 1 hop" : "single hop"; - _netlink_route_debug(cmd, p, nexthop, routedesc, family); + _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); _netlink_route_build_singlepath(routedesc, bytelen, nexthop, &req.n, &req.r, sizeof req); @@ -1717,7 +1723,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, nexthop_num++; _netlink_route_debug(cmd, p, nexthop, - routedesc, family); + routedesc, family, zvrf); _netlink_route_build_multipath(routedesc, bytelen, nexthop, rta, rtnh, &src); rtnh = RTNH_NEXT (rtnh); @@ -1749,7 +1755,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, snl.nl_family = AF_NETLINK; /* Talk to netlink socket. */ - return netlink_talk (&req.n, &netlink_cmd); + return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf); } int @@ -1793,6 +1799,8 @@ netlink_address (int cmd, int family, struct interface *ifp, char buf[NL_PKT_BUF_SIZE]; } req; + struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); + p = ifc->address; memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); @@ -1825,7 +1833,7 @@ netlink_address (int cmd, int family, struct interface *ifp, addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, strlen (ifc->label) + 1); - return netlink_talk (&req.n, &netlink_cmd); + return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf); } int @@ -1847,8 +1855,10 @@ extern struct thread_master *master; static int kernel_read (struct thread *thread) { - netlink_parse_info (netlink_information_fetch, &netlink); - thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); + struct zebra_vrf *zvrf = (struct zebra_vrf *)THREAD_ARG (thread); + netlink_parse_info (netlink_information_fetch, &zvrf->netlink, zvrf); + zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, + zvrf->netlink.sock); return 0; } @@ -1887,7 +1897,7 @@ static void netlink_install_filter (int sock, __u32 pid) /* Exported interface function. This function simply calls netlink_socket (). */ void -kernel_init (void) +kernel_init (struct zebra_vrf *zvrf) { unsigned long groups; @@ -1895,23 +1905,42 @@ kernel_init (void) #ifdef HAVE_IPV6 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR; #endif /* HAVE_IPV6 */ - netlink_socket (&netlink, groups); - netlink_socket (&netlink_cmd, 0); + netlink_socket (&zvrf->netlink, groups, zvrf->vrf_id); + netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id); /* Register kernel socket. */ - if (netlink.sock > 0) + if (zvrf->netlink.sock > 0) { /* Only want non-blocking on the netlink event socket */ - if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0) - zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name, - safe_strerror (errno)); + if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0) + zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name, + safe_strerror (errno)); /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) - netlink_recvbuf (&netlink, nl_rcvbufsize); + netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize); - netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid); - thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); + netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid); + zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, + zvrf->netlink.sock); + } +} + +void +kernel_terminate (struct zebra_vrf *zvrf) +{ + THREAD_READ_OFF (zvrf->t_netlink); + + if (zvrf->netlink.sock >= 0) + { + close (zvrf->netlink.sock); + zvrf->netlink.sock = -1; + } + + if (zvrf->netlink_cmd.sock >= 0) + { + close (zvrf->netlink_cmd.sock); + zvrf->netlink_cmd.sock = -1; } } diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index d8f9db856..40fa8eb4b 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -41,8 +41,8 @@ extern const char * nl_rtproto_to_str (u_char rtproto); -extern int interface_lookup_netlink (void); -extern int netlink_route_read (void); +extern int interface_lookup_netlink (struct zebra_vrf *zvrf); +extern int netlink_route_read (struct zebra_vrf *zvrf); #endif /* HAVE_NETLINK */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 83ef64832..7fb916ffa 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -96,7 +96,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry) } void -route_read (void) +route_read (struct zebra_vrf *zvrf) { char storage[RT_BUFSIZ]; @@ -111,6 +111,10 @@ route_read (void) struct strbuf msgdata; int flags, dev, retval, process; + if (zvrf->vrf_id != VRF_DEFAULT) { + return; + } + if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, safe_strerror (errno)); diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 7abbc590a..1f658646e 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -25,7 +25,7 @@ #include "zebra/zserv.h" #include "rt_netlink.h" -void route_read (void) +void route_read (struct zebra_vrf *zvrf) { - netlink_route_read (); + netlink_route_read (zvrf); } diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index b8f5bde70..385e15069 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -24,6 +24,7 @@ #include "memory.h" #include "log.h" +#include "vrf.h" #include "zebra/zserv.h" #include "zebra/rt.h" @@ -31,7 +32,7 @@ /* Kernel routing table read up by sysctl function. */ void -route_read (void) +route_read (struct zebra_vrf *zvrf) { caddr_t buf, end, ref; size_t bufsiz; @@ -47,7 +48,10 @@ route_read (void) NET_RT_DUMP, 0 }; - + + if (zvrf->vrf_id != VRF_DEFAULT) + return; + /* Get buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { diff --git a/zebra/test_main.c b/zebra/test_main.c index 17014ea73..448d1ef9f 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -220,6 +220,9 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info) assert (zvrf); + kernel_init (zvrf); + route_read (zvrf); + return 0; } @@ -244,6 +247,8 @@ zebra_vrf_disable (vrf_id_t vrf_id, void **info) if_down (ifp); } + kernel_terminate (zvrf); + return 0; } @@ -355,8 +360,6 @@ main (int argc, char **argv) /* Make kernel routing socket. */ zebra_vrf_init (); - kernel_init (); - route_read (); zebra_vty_init(); /* Configuration file read*/ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 9d966a0f2..084af3802 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3447,6 +3447,9 @@ struct zebra_vrf * zebra_vrf_alloc (vrf_id_t vrf_id) { struct zebra_vrf *zvrf; +#ifdef HAVE_NETLINK + char nl_name[64]; +#endif zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf)); @@ -3463,6 +3466,17 @@ zebra_vrf_alloc (vrf_id_t vrf_id) /* Set VRF ID */ zvrf->vrf_id = vrf_id; +#ifdef HAVE_NETLINK + /* Initialize netlink sockets */ + snprintf (nl_name, 64, "netlink-listen (vrf %u)", vrf_id); + zvrf->netlink.sock = -1; + zvrf->netlink.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name); + + snprintf (nl_name, 64, "netlink-cmd (vrf %u)", vrf_id); + zvrf->netlink_cmd.sock = -1; + zvrf->netlink_cmd.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name); +#endif + return zvrf; } diff --git a/zebra/zserv.h b/zebra/zserv.h index eaa164b95..af005f851 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -92,9 +92,10 @@ extern void zebra_if_init (void); extern void zebra_zserv_socket_init (char *path); extern void hostinfo_get (void); extern void rib_init (void); -extern void interface_list (void); -extern void kernel_init (void); -extern void route_read (void); +extern void interface_list (struct zebra_vrf *); +extern void route_read (struct zebra_vrf *); +extern void kernel_init (struct zebra_vrf *); +extern void kernel_terminate (struct zebra_vrf *); extern void zebra_route_map_init (void); extern void zebra_snmp_init (void); extern void zebra_vty_init (void); From c99f3481a598e9cadd1de96714f6b5df9ad85c4a Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Thu, 16 Oct 2014 09:52:36 +0800 Subject: [PATCH 0748/1342] *: add VRF ID in the API message header The API messages are used by zebra to exchange the interfaces, addresses, routes and router-id information with its clients. To distinguish which VRF the information belongs to, a new field "VRF ID" is added in the message header. And hence the message version is increased to 3. * The new field "VRF ID" in the message header: Length (2 bytes) Marker (1 byte) Version (1 byte) VRF ID (2 bytes, newly added) Command (2 bytes) - Client side: - zclient_create_header() adds the VRF ID in the message header. - zclient_read() extracts and validates the VRF ID from the header, and passes the VRF ID to the callback functions registered to the API messages. - All relative functions are appended with a new parameter "vrf_id", including all the callback functions. - "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6". Clients need to correctly set the VRF ID when using the API functions zapi_ipv4_route() and zapi_ipv6_route(). - Till now all messages sent from a client have the default VRF ID "0" in the header. - The HELLO message is special, which is used as the heart-beat of a client, and has no relation with VRF. The VRF ID in the HELLO message header will always be 0 and ignored by zebra. - Zebra side: - zserv_create_header() adds the VRF ID in the message header. - zebra_client_read() extracts and validates the VRF ID from the header, and passes the VRF ID to the functions which process the received messages. - All relative functions are appended with a new parameter "vrf_id". * Suppress the messages in a VRF which a client does not care: Some clients may not care about the information in the VRF X, and zebra should not send the messages in the VRF X to those clients. Extra flags are used to indicate which VRF is registered by a client, and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client can unregister a VRF when it does not need any information in that VRF. A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF will automatically register to that VRF. - lib/vrf: A new utility "VRF bit-map" is provided to manage the flags for VRFs, one bit per VRF ID. - Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a bit-map; - Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag in the given bit-map, corresponding to the given VRF ID; - Use vrf_bitmap_check() to test whether the flag, in the given bit-map and for the given VRF ID, is set. - Client side: - In "struct zclient", the following flags are changed from "u_char" to "vrf_bitmap_t": redist[ZEBRA_ROUTE_MAX] default_information These flags are extended for each VRF, and controlled by the clients themselves (or with the help of zclient_redistribute() and zclient_redistribute_default()). - Zebra side: - In "struct zserv", the following flags are changed from "u_char" to "vrf_bitmap_t": redist[ZEBRA_ROUTE_MAX] redist_default ifinfo ridinfo These flags are extended for each VRF, as the VRF registration flags. They are maintained on receiving a ZEBRA_XXX_ADD or ZEBRA_XXX_DELETE message. When sending an interface/address/route/router-id message in a VRF to a client, if the corresponding VRF registration flag is not set, this message will not be dropped by zebra. - A new function zread_vrf_unregister() is introduced to process the new command ZEBRA_VRF_UNREGISTER. All the VRF registration flags are cleared for the requested VRF. Those clients, who support only the default VRF, will never receive a message in a non-default VRF, thanks to the filter in zebra. * New callback for the event of successful connection to zebra: - zclient_start() is splitted, keeping only the code of connecting to zebra. - Now zclient_init()=>zclient_connect()=>zclient_start() operations are purely dealing with the connection to zbera. - Once zebra is successfully connected, at the end of zclient_start(), a new callback is used to inform the client about connection. - Till now, in the callback of connect-to-zebra event, all clients send messages to zebra to request the router-id/interface/routes information in the default VRF. Of corse in future the client can do anything it wants in this callback. For example, it may send requests for both default VRF and some non-default VRFs. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel Acked-by: Donald Sharp --- bgpd/bgp_nexthop.c | 6 +- bgpd/bgp_zebra.c | 64 +++++++++----- isisd/isis_zebra.c | 55 +++++++----- lib/memtypes.c | 1 + lib/vrf.c | 93 +++++++++++++++++++ lib/vrf.h | 13 +++ lib/zclient.c | 151 +++++++++++++++++++------------ lib/zclient.h | 63 ++++++++----- lib/zebra.h | 3 +- ospf6d/ospf6_zebra.c | 69 +++++++++------ ospf6d/ospf6_zebra.h | 3 +- ospfd/ospf_vty.c | 3 +- ospfd/ospf_zebra.c | 65 ++++++++------ pimd/pim_zebra.c | 38 ++++---- pimd/pim_zlookup.c | 2 +- ripd/rip_interface.c | 27 +++--- ripd/rip_interface.h | 18 ++-- ripd/rip_zebra.c | 54 +++++++---- ripngd/ripng_interface.c | 26 +++--- ripngd/ripng_zebra.c | 53 +++++------ ripngd/ripngd.h | 18 ++-- zebra/client_main.c | 1 + zebra/redistribute.c | 49 +++++----- zebra/redistribute.h | 12 ++- zebra/redistribute_null.c | 12 ++- zebra/zserv.c | 182 +++++++++++++++++++++++--------------- zebra/zserv.h | 9 +- 27 files changed, 705 insertions(+), 385 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 6218e6704..7336793e0 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -873,7 +873,7 @@ zlookup_query (struct in_addr addr) s = zlookup->obuf; stream_reset (s); - zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); + zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, VRF_DEFAULT); stream_put_in_addr (s, &addr); stream_putw_at (s, 0, stream_get_endp (s)); @@ -988,7 +988,7 @@ zlookup_query_ipv6 (struct in6_addr *addr) s = zlookup->obuf; stream_reset (s); - zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); + zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, VRF_DEFAULT); stream_put (s, addr, 16); stream_putw_at (s, 0, stream_get_endp (s)); @@ -1038,7 +1038,7 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, /* Send query to the lookup connection */ s = zlookup->obuf; stream_reset (s); - zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP); + zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP, VRF_DEFAULT); stream_putc (s, p->prefixlen); stream_put_in_addr (s, &p->u.prefix4); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 13f71de94..261635162 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -48,7 +48,8 @@ struct stream *bgp_nexthop_buf = NULL; /* Router-id update message from zebra. */ static int -bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length) +bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct prefix router_id; struct listnode *node, *nnode; @@ -76,11 +77,12 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length) /* Inteface addition message from zebra. */ static int -bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) +bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_add_read (zclient->ibuf); + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (BGP_DEBUG(zebra, ZEBRA) && ifp) zlog_debug("Zebra rcvd: interface add %s", ifp->name); @@ -90,13 +92,13 @@ bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) static int bgp_interface_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; s = zclient->ibuf; - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); ifp->ifindex = IFINDEX_INTERNAL; if (BGP_DEBUG(zebra, ZEBRA)) @@ -106,7 +108,8 @@ bgp_interface_delete (int command, struct zclient *zclient, } static int -bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) +bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; @@ -114,7 +117,7 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) struct listnode *node, *nnode; s = zclient->ibuf; - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); if (! ifp) return 0; @@ -129,7 +132,8 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) } static int -bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) +bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; @@ -137,7 +141,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) struct listnode *node, *nnode; s = zclient->ibuf; - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); if (! ifp) return 0; @@ -174,11 +178,11 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) static int bgp_interface_address_add (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; - ifc = zebra_interface_address_read (command, zclient->ibuf); + ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (ifc == NULL) return 0; @@ -199,11 +203,11 @@ bgp_interface_address_add (int command, struct zclient *zclient, static int bgp_interface_address_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; - ifc = zebra_interface_address_read (command, zclient->ibuf); + ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (ifc == NULL) return 0; @@ -226,7 +230,8 @@ bgp_interface_address_delete (int command, struct zclient *zclient, /* Zebra route add and delete treatment. */ static int -zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; @@ -302,7 +307,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) #ifdef HAVE_IPV6 /* Zebra route add and delete treatment. */ static int -zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) +zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv6 api; @@ -672,7 +678,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa if (zclient->sock < 0) return; - if (! zclient->redist[ZEBRA_ROUTE_BGP]) + if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT)) return; flags = 0; @@ -708,6 +714,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa struct zapi_ipv4 api; struct in_addr *nexthop; + api.vrf_id = VRF_DEFAULT; api.flags = flags; nexthop = &info->attr->nexthop; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); @@ -798,6 +805,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa } /* Make Zebra API structure. */ + api.vrf_id = VRF_DEFAULT; api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; @@ -836,7 +844,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (zclient->sock < 0) return; - if (! zclient->redist[ZEBRA_ROUTE_BGP]) + if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT)) return; peer = info->peer; @@ -857,6 +865,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) struct zapi_ipv4 api; struct in_addr *nexthop; + api.vrf_id = VRF_DEFAULT; api.flags = flags; nexthop = &info->attr->nexthop; @@ -915,6 +924,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (info->peer->ifname) ifindex = ifname2ifindex (info->peer->ifname); + api.vrf_id = VRF_DEFAULT; api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; @@ -952,10 +962,10 @@ bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) bgp->redist[afi][type] = 1; /* Return if already redistribute flag is set. */ - if (zclient->redist[type]) + if (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_WARNING; - zclient->redist[type] = 1; + vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); /* Return if zebra connection is not established. */ if (zclient->sock < 0) @@ -965,7 +975,7 @@ bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type)); /* Send distribute add message to zebra. */ - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } @@ -1020,9 +1030,9 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) bgp->redist_metric[afi][type] = 0; /* Return if zebra connection is disabled. */ - if (! zclient->redist[type]) + if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_WARNING; - zclient->redist[type] = 0; + vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT); if (bgp->redist[AFI_IP][type] == 0 && bgp->redist[AFI_IP6][type] == 0 @@ -1032,7 +1042,8 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra send: redistribute delete %s", zebra_route_string(type)); - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, + VRF_DEFAULT); } /* Withdraw redistributed routes from current BGP's routing table. */ @@ -1076,12 +1087,19 @@ bgp_zclient_reset (void) zclient_reset (zclient); } +static void +bgp_zebra_connected (struct zclient *zclient) +{ + zclient_send_requests (zclient, VRF_DEFAULT); +} + void bgp_zebra_init (void) { /* Set default values. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_BGP); + zclient->zebra_connected = bgp_zebra_connected; zclient->router_id_update = bgp_router_id_update; zclient->interface_add = bgp_interface_add; zclient->interface_delete = bgp_interface_delete; diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 1ba0100d4..6d0c15711 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -32,6 +32,7 @@ #include "zclient.h" #include "stream.h" #include "linklist.h" +#include "vrf.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -52,7 +53,7 @@ struct zclient *zclient = NULL; /* Router-id update message from zebra. */ static int isis_router_id_update_zebra (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct isis_area *area; struct listnode *node; @@ -71,11 +72,12 @@ isis_router_id_update_zebra (int command, struct zclient *zclient, } static int -isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) +isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_add_read (zclient->ibuf); + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("Zebra I/F add: %s index %d flags %ld metric %d mtu %d", @@ -88,13 +90,14 @@ isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) } static int -isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) +isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); if (!ifp) return 0; @@ -120,11 +123,11 @@ isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) static int isis_zebra_if_state_up (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_state_read (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -136,12 +139,12 @@ isis_zebra_if_state_up (int command, struct zclient *zclient, static int isis_zebra_if_state_down (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct isis_circuit *circuit; - ifp = zebra_interface_state_read (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -156,14 +159,14 @@ isis_zebra_if_state_down (int command, struct zclient *zclient, static int isis_zebra_if_address_add (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; char buf[BUFSIZ]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, - zclient->ibuf); + zclient->ibuf, vrf_id); if (c == NULL) return 0; @@ -187,7 +190,7 @@ isis_zebra_if_address_add (int command, struct zclient *zclient, static int isis_zebra_if_address_del (int command, struct zclient *client, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct interface *ifp; @@ -197,7 +200,7 @@ isis_zebra_if_address_del (int command, struct zclient *client, #endif /* EXTREME_DEBUG */ c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, - zclient->ibuf); + zclient->ibuf, vrf_id); if (c == NULL) return 0; @@ -236,7 +239,7 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; - if (zclient->redist[ZEBRA_ROUTE_ISIS]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) { message = 0; flags = 0; @@ -249,7 +252,7 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, stream = zclient->obuf; stream_reset (stream); - zclient_create_header (stream, ZEBRA_IPV4_ROUTE_ADD); + zclient_create_header (stream, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); /* type */ stream_putc (stream, ZEBRA_ROUTE_ISIS); /* flags */ @@ -301,8 +304,9 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix, struct zapi_ipv4 api; struct prefix_ipv4 prefix4; - if (zclient->redist[ZEBRA_ROUTE_ISIS]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) { + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; @@ -333,6 +337,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; @@ -418,6 +423,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; @@ -488,7 +494,7 @@ isis_zebra_route_update (struct prefix *prefix, if (zclient->sock < 0) return; - if (!zclient->redist[ZEBRA_ROUTE_ISIS]) + if (!vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) return; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) @@ -514,7 +520,7 @@ isis_zebra_route_update (struct prefix *prefix, static int isis_zebra_read_ipv4 (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *stream; struct zapi_ipv4 api; @@ -563,14 +569,16 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, #ifdef HAVE_IPV6 static int isis_zebra_read_ipv6 (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { return 0; } #endif #define ISIS_TYPE_IS_REDISTRIBUTED(T) \ -T == ZEBRA_ROUTE_MAX ? zclient->default_information : zclient->redist[type] +T == ZEBRA_ROUTE_MAX ? \ + vrf_bitmap_check (zclient->default_information, VRF_DEFAULT) : \ + vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) int isis_distribute_list_update (int routetype) @@ -587,11 +595,18 @@ isis_redistribute_default_set (int routetype, int metric_type, } #endif /* 0 */ +static void +isis_zebra_connected (struct zclient *zclient) +{ + zclient_send_requests (zclient, VRF_DEFAULT); +} + void isis_zebra_init () { zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_ISIS); + zclient->zebra_connected = isis_zebra_connected; zclient->router_id_update = isis_router_id_update_zebra; zclient->interface_add = isis_zebra_if_add; zclient->interface_delete = isis_zebra_if_del; diff --git a/lib/memtypes.c b/lib/memtypes.c index 60f24e6a7..ab3c1f8ee 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -71,6 +71,7 @@ struct memory_list memory_list_lib[] = { MTYPE_HOST, "Host config" }, { MTYPE_VRF, "VRF" }, { MTYPE_VRF_NAME, "VRF name" }, + { MTYPE_VRF_BITMAP, "VRF bit-map" }, { -1, NULL }, }; diff --git a/lib/vrf.c b/lib/vrf.c index d11a98264..683026e5c 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -336,6 +336,99 @@ vrf_iflist_get (vrf_id_t vrf_id) return vrf->iflist; } +/* + * VRF bit-map + */ + +#define VRF_BITMAP_NUM_OF_GROUPS 8 +#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP \ + (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS) +#define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \ + (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */ + +#define VRF_BITMAP_GROUP(_id) \ + ((_id) / VRF_BITMAP_NUM_OF_BITS_IN_GROUP) +#define VRF_BITMAP_BIT_OFFSET(_id) \ + ((_id) % VRF_BITMAP_NUM_OF_BITS_IN_GROUP) + +#define VRF_BITMAP_INDEX_IN_GROUP(_bit_offset) \ + ((_bit_offset) / CHAR_BIT) +#define VRF_BITMAP_FLAG(_bit_offset) \ + (((u_char)1) << ((_bit_offset) % CHAR_BIT)) + +struct vrf_bitmap +{ + u_char *groups[VRF_BITMAP_NUM_OF_GROUPS]; +}; + +vrf_bitmap_t +vrf_bitmap_init (void) +{ + return (vrf_bitmap_t) XCALLOC (MTYPE_VRF_BITMAP, sizeof (struct vrf_bitmap)); +} + +void +vrf_bitmap_free (vrf_bitmap_t bmap) +{ + struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; + int i; + + if (bmap == VRF_BITMAP_NULL) + return; + + for (i = 0; i < VRF_BITMAP_NUM_OF_GROUPS; i++) + if (bm->groups[i]) + XFREE (MTYPE_VRF_BITMAP, bm->groups[i]); + + XFREE (MTYPE_VRF_BITMAP, bm); +} + +void +vrf_bitmap_set (vrf_bitmap_t bmap, vrf_id_t vrf_id) +{ + struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; + u_char group = VRF_BITMAP_GROUP (vrf_id); + u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); + + if (bmap == VRF_BITMAP_NULL) + return; + + if (bm->groups[group] == NULL) + bm->groups[group] = XCALLOC (MTYPE_VRF_BITMAP, + VRF_BITMAP_NUM_OF_BYTES_IN_GROUP); + + SET_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)], + VRF_BITMAP_FLAG (offset)); +} + +void +vrf_bitmap_unset (vrf_bitmap_t bmap, vrf_id_t vrf_id) +{ + struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; + u_char group = VRF_BITMAP_GROUP (vrf_id); + u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); + + if (bmap == VRF_BITMAP_NULL || bm->groups[group] == NULL) + return; + + UNSET_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)], + VRF_BITMAP_FLAG (offset)); +} + +int +vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id) +{ + struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; + u_char group = VRF_BITMAP_GROUP (vrf_id); + u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); + + if (bmap == VRF_BITMAP_NULL || bm->groups[group] == NULL) + return 0; + + return CHECK_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)], + VRF_BITMAP_FLAG (offset)) ? 1 : 0; +} + /* Initialize VRF module. */ void vrf_init (void) diff --git a/lib/vrf.h b/lib/vrf.h index 653fabf90..8b29b8093 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -109,6 +109,19 @@ extern struct list *vrf_iflist (vrf_id_t); /* Get the interface list of the specified VRF. Create one if not find. */ extern struct list *vrf_iflist_get (vrf_id_t); +/* + * VRF bit-map: maintaining flags, one bit per VRF ID + */ + +typedef void * vrf_bitmap_t; +#define VRF_BITMAP_NULL NULL + +extern vrf_bitmap_t vrf_bitmap_init (void); +extern void vrf_bitmap_free (vrf_bitmap_t); +extern void vrf_bitmap_set (vrf_bitmap_t, vrf_id_t); +extern void vrf_bitmap_unset (vrf_bitmap_t, vrf_id_t); +extern int vrf_bitmap_check (vrf_bitmap_t, vrf_id_t); + /* * VRF initializer/destructor */ diff --git a/lib/zclient.c b/lib/zclient.c index 71da87c6f..8e443e28d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -93,15 +93,14 @@ zclient_init (struct zclient *zclient, int redist_default) /* Clear redistribution flags. */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - zclient->redist[i] = 0; + zclient->redist[i] = vrf_bitmap_init (); /* Set unwanted redistribute route. bgpd does not need BGP route redistribution. */ zclient->redist_default = redist_default; - zclient->redist[redist_default] = 1; /* Set default-information redistribute to zero. */ - zclient->default_information = 0; + zclient->default_information = vrf_bitmap_init (); /* Schedule first zclient connection. */ if (zclient_debug) @@ -293,18 +292,19 @@ zclient_send_message(struct zclient *zclient) } void -zclient_create_header (struct stream *s, uint16_t command) +zclient_create_header (struct stream *s, uint16_t command, vrf_id_t vrf_id) { /* length placeholder, caller can update */ stream_putw (s, ZEBRA_HEADER_SIZE); stream_putc (s, ZEBRA_HEADER_MARKER); stream_putc (s, ZSERV_VERSION); + stream_putw (s, vrf_id); stream_putw (s, command); } /* Send simple Zebra message. */ static int -zebra_message_send (struct zclient *zclient, int command) +zebra_message_send (struct zclient *zclient, int command, vrf_id_t vrf_id) { struct stream *s; @@ -313,7 +313,7 @@ zebra_message_send (struct zclient *zclient, int command) stream_reset (s); /* Send very simple command only Zebra message. */ - zclient_create_header (s, command); + zclient_create_header (s, command, vrf_id); return zclient_send_message(zclient); } @@ -328,7 +328,8 @@ zebra_hello_send (struct zclient *zclient) s = zclient->obuf; stream_reset (s); - zclient_create_header (s, ZEBRA_HELLO); + /* The VRF ID in the HELLO message is always 0. */ + zclient_create_header (s, ZEBRA_HELLO, VRF_DEFAULT); stream_putc (s, zclient->redist_default); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); @@ -337,12 +338,47 @@ zebra_hello_send (struct zclient *zclient) return 0; } +/* Send requests to zebra daemon for the information in a VRF. */ +void +zclient_send_requests (struct zclient *zclient, vrf_id_t vrf_id) +{ + int i; + + /* zclient is disabled. */ + if (! zclient->enable) + return; + + /* If not connected to the zebra yet. */ + if (zclient->sock < 0) + return; + + if (zclient_debug) + zlog_debug ("%s: send messages for VRF %u", __func__, vrf_id); + + /* We need router-id information. */ + zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD, vrf_id); + + /* We need interface information. */ + zebra_message_send (zclient, ZEBRA_INTERFACE_ADD, vrf_id); + + /* Set unwanted redistribute route. */ + vrf_bitmap_set (zclient->redist[zclient->redist_default], vrf_id); + + /* Flush all redistribute request. */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && + vrf_bitmap_check (zclient->redist[i], vrf_id)) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, i, vrf_id); + + /* If default information is needed. */ + if (vrf_bitmap_check (zclient->default_information, VRF_DEFAULT)) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD, vrf_id); +} + /* Make connection to zebra daemon. */ int zclient_start (struct zclient *zclient) { - int i; - if (zclient_debug) zlog_debug ("zclient_start is called"); @@ -380,20 +416,9 @@ zclient_start (struct zclient *zclient) zebra_hello_send (zclient); - /* We need router-id information. */ - zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD); - - /* We need interface information. */ - zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); - - /* Flush all redistribute request. */ - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default && zclient->redist[i]) - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, i); - - /* If default information is needed. */ - if (zclient->default_information) - zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD); + /* Inform the successful connection. */ + if (zclient->zebra_connected) + (*zclient->zebra_connected) (zclient); return 0; } @@ -469,8 +494,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, /* Reset stream. */ s = zclient->obuf; stream_reset (s); - - zclient_create_header (s, cmd); + + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ stream_putc (s, api->type); @@ -532,7 +557,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, s = zclient->obuf; stream_reset (s); - zclient_create_header (s, cmd); + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ stream_putc (s, api->type); @@ -581,14 +606,15 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, * sending client */ int -zebra_redistribute_send (int command, struct zclient *zclient, int type) +zebra_redistribute_send (int command, struct zclient *zclient, int type, + vrf_id_t vrf_id) { struct stream *s; s = zclient->obuf; stream_reset(s); - zclient_create_header (s, command); + zclient_create_header (s, command, vrf_id); stream_putc (s, type); stream_putw_at (s, 0, stream_get_endp (s)); @@ -643,7 +669,7 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid) */ struct interface * -zebra_interface_add_read (struct stream *s) +zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id) { struct interface *ifp; char ifname_tmp[INTERFACE_NAMSIZ]; @@ -652,7 +678,9 @@ zebra_interface_add_read (struct stream *s) stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* Lookup/create interface by name. */ - ifp = if_get_by_name_len (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); + ifp = if_get_by_name_len_vrf (ifname_tmp, + strnlen (ifname_tmp, INTERFACE_NAMSIZ), + vrf_id); zebra_interface_if_set_value (s, ifp); @@ -667,7 +695,7 @@ zebra_interface_add_read (struct stream *s) * is sent at the tail of the message. */ struct interface * -zebra_interface_state_read (struct stream *s) +zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) { struct interface *ifp; char ifname_tmp[INTERFACE_NAMSIZ]; @@ -676,8 +704,9 @@ zebra_interface_state_read (struct stream *s) stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* Lookup this by interface index. */ - ifp = if_lookup_by_name_len (ifname_tmp, - strnlen(ifname_tmp, INTERFACE_NAMSIZ)); + ifp = if_lookup_by_name_len_vrf (ifname_tmp, + strnlen (ifname_tmp, INTERFACE_NAMSIZ), + vrf_id); /* If such interface does not exist, indicate an error */ if (! ifp) @@ -754,7 +783,7 @@ memconstant(const void *s, int c, size_t n) } struct connected * -zebra_interface_address_read (int type, struct stream *s) +zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) { unsigned int ifindex; struct interface *ifp; @@ -771,7 +800,7 @@ zebra_interface_address_read (int type, struct stream *s) ifindex = stream_getl (s); /* Lookup index. */ - ifp = if_lookup_by_index (ifindex); + ifp = if_lookup_by_index_vrf (ifindex, vrf_id); if (ifp == NULL) { zlog_warn ("zebra_interface_address_read(%s): " @@ -834,6 +863,7 @@ zclient_read (struct thread *thread) size_t already; uint16_t length, command; uint8_t marker, version; + vrf_id_t vrf_id; struct zclient *zclient; /* Get socket to zebra. */ @@ -868,6 +898,7 @@ zclient_read (struct thread *thread) length = stream_getw (zclient->ibuf); marker = stream_getc (zclient->ibuf); version = stream_getc (zclient->ibuf); + vrf_id = stream_getw (zclient->ibuf); command = stream_getw (zclient->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) @@ -919,53 +950,53 @@ zclient_read (struct thread *thread) length -= ZEBRA_HEADER_SIZE; if (zclient_debug) - zlog_debug("zclient 0x%p command 0x%x \n", (void *)zclient, command); + zlog_debug("zclient 0x%p command 0x%x VRF %u\n", (void *)zclient, command, vrf_id); switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) - (*zclient->router_id_update) (command, zclient, length); + (*zclient->router_id_update) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) - (*zclient->interface_add) (command, zclient, length); + (*zclient->interface_add) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) - (*zclient->interface_delete) (command, zclient, length); + (*zclient->interface_delete) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) - (*zclient->interface_address_add) (command, zclient, length); + (*zclient->interface_address_add) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) - (*zclient->interface_address_delete) (command, zclient, length); + (*zclient->interface_address_delete) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) - (*zclient->interface_up) (command, zclient, length); + (*zclient->interface_up) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) - (*zclient->interface_down) (command, zclient, length); + (*zclient->interface_down) (command, zclient, length, vrf_id); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) - (*zclient->ipv4_route_add) (command, zclient, length); + (*zclient->ipv4_route_add) (command, zclient, length, vrf_id); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) - (*zclient->ipv4_route_delete) (command, zclient, length); + (*zclient->ipv4_route_delete) (command, zclient, length, vrf_id); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) - (*zclient->ipv6_route_add) (command, zclient, length); + (*zclient->ipv6_route_add) (command, zclient, length, vrf_id); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) - (*zclient->ipv6_route_delete) (command, zclient, length); + (*zclient->ipv6_route_delete) (command, zclient, length, vrf_id); break; default: break; @@ -983,46 +1014,48 @@ zclient_read (struct thread *thread) } void -zclient_redistribute (int command, struct zclient *zclient, int type) +zclient_redistribute (int command, struct zclient *zclient, int type, + vrf_id_t vrf_id) { if (command == ZEBRA_REDISTRIBUTE_ADD) { - if (zclient->redist[type]) + if (vrf_bitmap_check (zclient->redist[type], vrf_id)) return; - zclient->redist[type] = 1; + vrf_bitmap_set (zclient->redist[type], vrf_id); } else { - if (!zclient->redist[type]) + if (!vrf_bitmap_check (zclient->redist[type], vrf_id)) return; - zclient->redist[type] = 0; + vrf_bitmap_unset (zclient->redist[type], vrf_id); } if (zclient->sock > 0) - zebra_redistribute_send (command, zclient, type); + zebra_redistribute_send (command, zclient, type, vrf_id); } void -zclient_redistribute_default (int command, struct zclient *zclient) +zclient_redistribute_default (int command, struct zclient *zclient, + vrf_id_t vrf_id) { if (command == ZEBRA_REDISTRIBUTE_DEFAULT_ADD) { - if (zclient->default_information) + if (vrf_bitmap_check (zclient->default_information, vrf_id)) return; - zclient->default_information = 1; + vrf_bitmap_set (zclient->default_information, vrf_id); } else { - if (!zclient->default_information) + if (!vrf_bitmap_check (zclient->default_information, vrf_id)) return; - zclient->default_information = 0; + vrf_bitmap_unset (zclient->default_information, vrf_id); } if (zclient->sock > 0) - zebra_message_send (zclient, command); + zebra_message_send (zclient, command, vrf_id); } static void diff --git a/lib/zclient.h b/lib/zclient.h index a51b3defd..19b4f0ead 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -28,11 +28,14 @@ /* For struct interface and struct connected. */ #include "if.h" +/* For vrf_bitmap_t. */ +#include "vrf.h" + /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 /* Zebra header size. */ -#define ZEBRA_HEADER_SIZE 6 +#define ZEBRA_HEADER_SIZE 8 /* Structure for the zebra client. */ struct zclient @@ -65,23 +68,24 @@ struct zclient /* Redistribute information. */ u_char redist_default; - u_char redist[ZEBRA_ROUTE_MAX]; + vrf_bitmap_t redist[ZEBRA_ROUTE_MAX]; /* Redistribute defauilt. */ - u_char default_information; + vrf_bitmap_t default_information; /* Pointer to the callback functions. */ - int (*router_id_update) (int, struct zclient *, uint16_t); - int (*interface_add) (int, struct zclient *, uint16_t); - int (*interface_delete) (int, struct zclient *, uint16_t); - int (*interface_up) (int, struct zclient *, uint16_t); - int (*interface_down) (int, struct zclient *, uint16_t); - int (*interface_address_add) (int, struct zclient *, uint16_t); - int (*interface_address_delete) (int, struct zclient *, uint16_t); - int (*ipv4_route_add) (int, struct zclient *, uint16_t); - int (*ipv4_route_delete) (int, struct zclient *, uint16_t); - int (*ipv6_route_add) (int, struct zclient *, uint16_t); - int (*ipv6_route_delete) (int, struct zclient *, uint16_t); + void (*zebra_connected) (struct zclient *); + int (*router_id_update) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_add) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_delete) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_up) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t); + int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t); + int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); + int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t); + int (*ipv6_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); }; /* Zebra API message flag. */ @@ -98,7 +102,8 @@ struct zserv_header * always set to 255 in new zserv. */ uint8_t version; -#define ZSERV_VERSION 2 +#define ZSERV_VERSION 3 + vrf_id_t vrf_id; uint16_t command; }; @@ -122,6 +127,8 @@ struct zapi_ipv4 u_char distance; u_int32_t metric; + + vrf_id_t vrf_id; }; /* Prototypes of zebra client service functions. */ @@ -136,25 +143,33 @@ extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); extern const char *zclient_serv_path_get (void); +extern void zclient_send_requests (struct zclient *, vrf_id_t); + /* Send redistribute command to zebra daemon. Do not update zclient state. */ -extern int zebra_redistribute_send (int command, struct zclient *, int type); +extern int zebra_redistribute_send (int command, struct zclient *, int type, + vrf_id_t vrf_id); /* If state has changed, update state and call zebra_redistribute_send. */ -extern void zclient_redistribute (int command, struct zclient *, int type); +extern void zclient_redistribute (int command, struct zclient *, int type, + vrf_id_t vrf_id); /* If state has changed, update state and send the command to zebra. */ -extern void zclient_redistribute_default (int command, struct zclient *); +extern void zclient_redistribute_default (int command, struct zclient *, + vrf_id_t vrf_id); /* Send the message in zclient->obuf to the zebra daemon (or enqueue it). Returns 0 for success or -1 on an I/O error. */ extern int zclient_send_message(struct zclient *); /* create header for command, length to be filled in by user later */ -extern void zclient_create_header (struct stream *, uint16_t); - -extern struct interface *zebra_interface_add_read (struct stream *); -extern struct interface *zebra_interface_state_read (struct stream *s); -extern struct connected *zebra_interface_address_read (int, struct stream *); +extern void zclient_create_header (struct stream *, uint16_t, vrf_id_t); + +extern struct interface *zebra_interface_add_read (struct stream *, + vrf_id_t); +extern struct interface *zebra_interface_state_read (struct stream *, + vrf_id_t); +extern struct connected *zebra_interface_address_read (int, struct stream *, + vrf_id_t); extern void zebra_interface_if_set_value (struct stream *, struct interface *); extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid); extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *, @@ -182,6 +197,8 @@ struct zapi_ipv6 u_char distance; u_int32_t metric; + + vrf_id_t vrf_id; }; extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient, diff --git a/lib/zebra.h b/lib/zebra.h index e88a6293d..858643778 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -412,7 +412,8 @@ struct in_pktinfo #define ZEBRA_ROUTER_ID_UPDATE 22 #define ZEBRA_HELLO 23 #define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24 -#define ZEBRA_MESSAGE_MAX 25 +#define ZEBRA_VRF_UNREGISTER 25 +#define ZEBRA_MESSAGE_MAX 26 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index ac3235c41..951e11d24 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -49,7 +49,7 @@ struct in_addr router_id_zebra; /* Router-id update message from zebra. */ static int ospf6_router_id_update_zebra (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; struct ospf6 *o = ospf6; @@ -70,30 +70,33 @@ ospf6_router_id_update_zebra (int command, struct zclient *zclient, void ospf6_zebra_redistribute (int type) { - if (zclient->redist[type]) + if (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return; - zclient->redist[type] = 1; + vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, + VRF_DEFAULT); } void ospf6_zebra_no_redistribute (int type) { - if (! zclient->redist[type]) + if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return; - zclient->redist[type] = 0; + vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, + VRF_DEFAULT); } /* Inteface addition message from zebra. */ static int -ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) +ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_add_read (zclient->ibuf); + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface add: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); @@ -102,11 +105,12 @@ ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) } static int -ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) +ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - if (!(ifp = zebra_interface_state_read(zclient->ibuf))) + if (!(ifp = zebra_interface_state_read (zclient->ibuf, vrf_id))) return 0; if (if_is_up (ifp)) @@ -129,11 +133,11 @@ ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) static int ospf6_zebra_if_state_update (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_state_read (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -149,12 +153,13 @@ ospf6_zebra_if_state_update (int command, struct zclient *zclient, static int ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; char buf[128]; - c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); + c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, + vrf_id); if (c == NULL) return 0; @@ -174,12 +179,13 @@ ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, static int ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; char buf[128]; - c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); + c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf, + vrf_id); if (c == NULL) return 0; @@ -200,7 +206,7 @@ ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, static int ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv6 api; @@ -291,12 +297,13 @@ DEFUN (show_zebra, vty_out (vty, "Zebra Infomation%s", VNL); vty_out (vty, " enable: %d fail: %d%s", zclient->enable, zclient->fail, VNL); - vty_out (vty, " redistribute default: %d%s", zclient->redist_default, + vty_out (vty, " redistribute default: %d%s", + vrf_bitmap_check (zclient->default_information, VRF_DEFAULT), VNL); vty_out (vty, " redistribute:"); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (zclient->redist[i]) + if (vrf_bitmap_check (zclient->redist[i], VRF_DEFAULT)) vty_out (vty, " %s", zebra_route_string(i)); } vty_out (vty, "%s", VNL); @@ -336,7 +343,7 @@ config_write_ospf6_zebra (struct vty *vty) vty_out (vty, "no router zebra%s", VNL); vty_out (vty, "!%s", VNL); } - else if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + else if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) { vty_out (vty, "router zebra%s", VNL); vty_out (vty, " no redistribute ospf6%s", VNL); @@ -454,6 +461,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) ifindexes[i] = request->nexthop[i].ifindex; } + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.flags = 0; api.message = 0; @@ -487,7 +495,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) void ospf6_zebra_route_update_add (struct ospf6_route *request) { - if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) { ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; @@ -499,7 +507,7 @@ ospf6_zebra_route_update_add (struct ospf6_route *request) void ospf6_zebra_route_update_remove (struct ospf6_route *request) { - if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) { ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; @@ -516,10 +524,10 @@ DEFUN (redistribute_ospf6, { struct ospf6_route *route; - if (zclient->redist[ZEBRA_ROUTE_OSPF6]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) return CMD_SUCCESS; - zclient->redist[ZEBRA_ROUTE_OSPF6] = 1; + vrf_bitmap_set (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT); if (ospf6 == NULL) return CMD_SUCCESS; @@ -544,10 +552,10 @@ DEFUN (no_redistribute_ospf6, { struct ospf6_route *route; - if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) return CMD_SUCCESS; - zclient->redist[ZEBRA_ROUTE_OSPF6] = 0; + vrf_bitmap_unset (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT); if (ospf6 == NULL) return CMD_SUCCESS; @@ -563,12 +571,19 @@ DEFUN (no_redistribute_ospf6, return CMD_SUCCESS; } +static void +ospf6_zebra_connected (struct zclient *zclient) +{ + zclient_send_requests (zclient, VRF_DEFAULT); +} + void ospf6_zebra_init (void) { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_OSPF6); + zclient->zebra_connected = ospf6_zebra_connected; zclient->router_id_update = ospf6_router_id_update_zebra; zclient->interface_add = ospf6_zebra_if_add; zclient->interface_delete = ospf6_zebra_if_del; diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index 24a4ae639..a219450e5 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -42,7 +42,8 @@ extern void ospf6_zebra_route_update_remove (struct ospf6_route *request); extern void ospf6_zebra_redistribute (int); extern void ospf6_zebra_no_redistribute (int); -#define ospf6_zebra_is_redistribute(type) (zclient->redist[type]) +#define ospf6_zebra_is_redistribute(type) \ + vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) extern void ospf6_zebra_init (void); extern int config_write_ospf6_debug_zebra (struct vty *vty); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index d57eb41d0..9d04892c7 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -7133,7 +7133,8 @@ config_write_ospf_redistribute (struct vty *vty, struct ospf *ospf) /* redistribute print. */ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - if (type != zclient->redist_default && zclient->redist[type]) + if (type != zclient->redist_default && + vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) { vty_out (vty, " redistribute %s", zebra_route_string(type)); if (ospf->dmetric[type].value >= 0) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index bdb5193ab..fe1f45db5 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -59,7 +59,7 @@ struct in_addr router_id_zebra; /* Router-id update message from zebra. */ static int ospf_router_id_update_zebra (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct ospf *ospf; struct prefix router_id; @@ -84,11 +84,12 @@ ospf_router_id_update_zebra (int command, struct zclient *zclient, /* Inteface addition message from zebra. */ static int -ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length) +ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_add_read (zclient->ibuf); + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: interface add %s index %d flags %llx metric %d mtu %d", @@ -114,7 +115,7 @@ ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length) static int ospf_interface_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; @@ -122,7 +123,7 @@ ospf_interface_delete (int command, struct zclient *zclient, s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; @@ -149,7 +150,7 @@ ospf_interface_delete (int command, struct zclient *zclient, } static struct interface * -zebra_interface_if_lookup (struct stream *s) +zebra_interface_if_lookup (struct stream *s, vrf_id_t vrf_id) { char ifname_tmp[INTERFACE_NAMSIZ]; @@ -163,13 +164,13 @@ zebra_interface_if_lookup (struct stream *s) static int ospf_interface_state_up (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct ospf_interface *oi; struct route_node *rn; - ifp = zebra_interface_if_lookup (zclient->ibuf); + ifp = zebra_interface_if_lookup (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -225,13 +226,13 @@ ospf_interface_state_up (int command, struct zclient *zclient, static int ospf_interface_state_down (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct ospf_interface *oi; struct route_node *node; - ifp = zebra_interface_state_read (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -251,11 +252,11 @@ ospf_interface_state_down (int command, struct zclient *zclient, static int ospf_interface_address_add (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; - c = zebra_interface_address_read (command, zclient->ibuf); + c = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (c == NULL) return 0; @@ -278,7 +279,7 @@ ospf_interface_address_add (int command, struct zclient *zclient, static int ospf_interface_address_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct interface *ifp; @@ -286,7 +287,7 @@ ospf_interface_address_delete (int command, struct zclient *zclient, struct route_node *rn; struct prefix p; - c = zebra_interface_address_read (command, zclient->ibuf); + c = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (c == NULL) return 0; @@ -335,7 +336,7 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) struct ospf_path *path; struct listnode *node; - if (zclient->redist[ZEBRA_ROUTE_OSPF]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { message = 0; flags = 0; @@ -354,7 +355,7 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) stream_reset (s); /* Put command, type, flags, message. */ - zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD); + zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); @@ -433,7 +434,7 @@ ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) struct ospf_path *path; struct listnode *node; - if (zclient->redist[ZEBRA_ROUTE_OSPF]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { message = 0; flags = 0; @@ -444,7 +445,7 @@ ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) stream_reset (s); /* Put command, type, flags, message. */ - zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE); + zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); @@ -514,8 +515,9 @@ ospf_zebra_add_discard (struct prefix_ipv4 *p) { struct zapi_ipv4 api; - if (zclient->redist[ZEBRA_ROUTE_OSPF]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; @@ -537,8 +539,9 @@ ospf_zebra_delete_discard (struct prefix_ipv4 *p) { struct zapi_ipv4 api; - if (zclient->redist[ZEBRA_ROUTE_OSPF]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; @@ -560,7 +563,8 @@ int ospf_is_type_redistributed (int type) { return (DEFAULT_ROUTE_TYPE (type)) ? - zclient->default_information : zclient->redist[type]; + vrf_bitmap_check (zclient->default_information, VRF_DEFAULT) : \ + vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT); } int @@ -594,7 +598,7 @@ ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue) ospf->dmetric[type].type = mtype; ospf->dmetric[type].value = mvalue; - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]", @@ -615,7 +619,7 @@ ospf_redistribute_unset (struct ospf *ospf, int type) if (!ospf_is_type_redistributed (type)) return CMD_SUCCESS; - zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Stop", @@ -655,7 +659,8 @@ ospf_redistribute_default_set (struct ospf *ospf, int originate, return CMD_SUCCESS; } - zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient); + zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, + VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", @@ -682,7 +687,8 @@ ospf_redistribute_default_unset (struct ospf *ospf) ospf->dmetric[DEFAULT_ROUTE].type = -1; ospf->dmetric[DEFAULT_ROUTE].value = -1; - zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient); + zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, + VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[DEFAULT]: Stop"); @@ -816,7 +822,7 @@ ospf_routemap_unset (struct ospf *ospf, int type) /* Zebra route add and delete treatment. */ static int ospf_zebra_read_ipv4 (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; @@ -1292,12 +1298,19 @@ ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or) return 0; } +static void +ospf_zebra_connected (struct zclient *zclient) +{ + zclient_send_requests (zclient, VRF_DEFAULT); +} + void ospf_zebra_init () { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_OSPF); + zclient->zebra_connected = ospf_zebra_connected; zclient->router_id_update = ospf_router_id_update_zebra; zclient->interface_add = ospf_interface_add; zclient->interface_delete = ospf_interface_delete; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 129cbe4fb..dfc871b3b 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -70,7 +70,7 @@ static void zclient_broken(struct zclient *zclient) /* Router-id update message from zebra. */ static int pim_router_id_update_zebra(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; @@ -80,7 +80,7 @@ static int pim_router_id_update_zebra(int command, struct zclient *zclient, } static int pim_zebra_if_add(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; @@ -88,7 +88,7 @@ static int pim_zebra_if_add(int command, struct zclient *zclient, zebra api adds/dels interfaces using the same call interface_add_read below, see comments in lib/zclient.c */ - ifp = zebra_interface_add_read(zclient->ibuf); + ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); if (!ifp) return 0; @@ -106,7 +106,7 @@ static int pim_zebra_if_add(int command, struct zclient *zclient, } static int pim_zebra_if_del(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; @@ -120,7 +120,7 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, pimd to assert. Other clients use zebra_interface_state_read and it appears to work just fine. */ - ifp = zebra_interface_state_read(zclient->ibuf); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (!ifp) return 0; @@ -138,7 +138,7 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, } static int pim_zebra_if_state_up(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; @@ -146,7 +146,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, zebra api notifies interface up/down events by using the same call zebra_interface_state_read below, see comments in lib/zclient.c */ - ifp = zebra_interface_state_read(zclient->ibuf); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (!ifp) return 0; @@ -170,7 +170,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, } static int pim_zebra_if_state_down(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; @@ -178,7 +178,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, zebra api notifies interface up/down events by using the same call zebra_interface_state_read below, see comments in lib/zclient.c */ - ifp = zebra_interface_state_read(zclient->ibuf); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (!ifp) return 0; @@ -237,7 +237,7 @@ static void dump_if_address(struct interface *ifp) #endif static int pim_zebra_if_address_add(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; @@ -252,7 +252,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, will add address to interface list by calling connected_add_by_prefix() */ - c = zebra_interface_address_read(command, zclient->ibuf); + c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (!c) return 0; @@ -299,7 +299,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, } static int pim_zebra_if_address_del(int command, struct zclient *client, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; @@ -314,7 +314,7 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, will remove address from interface list by calling connected_delete_by_prefix() */ - c = zebra_interface_address_read(command, client->ibuf); + c = zebra_interface_address_read(command, client->ibuf, vrf_id); if (!c) return 0; @@ -526,7 +526,7 @@ static void sched_rpf_cache_refresh() } static int redist_read_ipv4_route(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; @@ -650,6 +650,11 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, return 0; } +static void pim_zebra_connected(struct zclient *zclient) +{ + zclient_send_requests(zclient, VRF_DEFAULT); +} + void pim_zebra_init(char *zebra_sock_path) { int i; @@ -666,6 +671,7 @@ void pim_zebra_init(char *zebra_sock_path) /* Socket for receiving updates from Zebra daemon */ qpim_zclient_update = zclient_new(); + qpim_zclient_update->zebra_connected = pim_zebra_connected; qpim_zclient_update->router_id_update = pim_router_id_update_zebra; qpim_zclient_update->interface_add = pim_zebra_if_add; qpim_zclient_update->interface_delete = pim_zebra_if_del; @@ -687,7 +693,7 @@ void pim_zebra_init(char *zebra_sock_path) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i == qpim_zclient_update->redist_default) continue; - qpim_zclient_update->redist[i] = 1; + vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT); if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: requesting redistribution for %s (%i)", __PRETTY_FUNCTION__, zebra_route_string(i), i); @@ -695,7 +701,7 @@ void pim_zebra_init(char *zebra_sock_path) } /* Request default information */ - qpim_zclient_update->default_information = 1; + vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT); if (PIM_DEBUG_PIM_TRACE) { zlog_info("%s: requesting default information redistribution", __PRETTY_FUNCTION__); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 2e71dc4ef..60003670c 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -346,7 +346,7 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup, s = zlookup->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); + zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, VRF_DEFAULT); stream_put_in_addr(s, &addr); stream_putw_at(s, 0, stream_get_endp(s)); diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index f26ef48a2..00612df43 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -380,7 +380,8 @@ if_check_address (struct in_addr addr) /* Inteface link down message processing. */ int -rip_interface_down (int command, struct zclient *zclient, zebra_size_t length) +rip_interface_down (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; @@ -389,7 +390,7 @@ rip_interface_down (int command, struct zclient *zclient, zebra_size_t length) /* zebra_interface_state_read() updates interface structure in iflist. */ - ifp = zebra_interface_state_read(s); + ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; @@ -406,13 +407,14 @@ rip_interface_down (int command, struct zclient *zclient, zebra_size_t length) /* Inteface link up message processing */ int -rip_interface_up (int command, struct zclient *zclient, zebra_size_t length) +rip_interface_up (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; /* zebra_interface_state_read () updates interface structure in iflist. */ - ifp = zebra_interface_state_read (zclient->ibuf); + ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -436,11 +438,12 @@ rip_interface_up (int command, struct zclient *zclient, zebra_size_t length) /* Inteface addition message from zebra. */ int -rip_interface_add (int command, struct zclient *zclient, zebra_size_t length) +rip_interface_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_add_read (zclient->ibuf); + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface add %s index %d flags %#llx metric %d mtu %d", @@ -466,7 +469,7 @@ rip_interface_add (int command, struct zclient *zclient, zebra_size_t length) int rip_interface_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; @@ -474,7 +477,7 @@ rip_interface_delete (int command, struct zclient *zclient, s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ - ifp = zebra_interface_state_read(s); + ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; @@ -644,13 +647,13 @@ rip_apply_address_add (struct connected *ifc) int rip_interface_address_add (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, - zclient->ibuf); + zclient->ibuf, vrf_id); if (ifc == NULL) return 0; @@ -700,13 +703,13 @@ rip_apply_address_del (struct connected *ifc) { int rip_interface_address_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, - zclient->ibuf); + zclient->ibuf, vrf_id); if (ifc) { diff --git a/ripd/rip_interface.h b/ripd/rip_interface.h index 8926cce7b..d9dfbb7cc 100644 --- a/ripd/rip_interface.h +++ b/ripd/rip_interface.h @@ -21,11 +21,17 @@ #ifndef _QUAGGA_RIP_INTERFACE_H #define _QUAGGA_RIP_INTERFACE_H -extern int rip_interface_down (int , struct zclient *, zebra_size_t); -extern int rip_interface_up (int , struct zclient *, zebra_size_t); -extern int rip_interface_add (int , struct zclient *, zebra_size_t); -extern int rip_interface_delete (int , struct zclient *, zebra_size_t); -extern int rip_interface_address_add (int , struct zclient *, zebra_size_t); -extern int rip_interface_address_delete (int , struct zclient *, zebra_size_t); +extern int rip_interface_down (int , struct zclient *, zebra_size_t, + vrf_id_t); +extern int rip_interface_up (int , struct zclient *, zebra_size_t, + vrf_id_t); +extern int rip_interface_add (int , struct zclient *, zebra_size_t, + vrf_id_t); +extern int rip_interface_delete (int , struct zclient *, zebra_size_t, + vrf_id_t); +extern int rip_interface_address_add (int , struct zclient *, zebra_size_t, + vrf_id_t); +extern int rip_interface_address_delete (int , struct zclient *, zebra_size_t, + vrf_id_t); #endif /* _QUAGGA_RIP_INTERFACE_H */ diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index b005ece96..de981623a 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -29,6 +29,7 @@ #include "routemap.h" #include "zclient.h" #include "log.h" +#include "vrf.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" @@ -49,8 +50,9 @@ rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) struct rip_info *rinfo = NULL; int count = 0; - if (zclient->redist[ZEBRA_ROUTE_RIP]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT)) { + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; @@ -125,7 +127,8 @@ rip_zebra_ipv4_delete (struct route_node *rp) /* Zebra route add and delete treatment. */ static int -rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; @@ -272,10 +275,10 @@ DEFUN (no_router_zebra, static int rip_redistribute_set (int type) { - if (zclient->redist[type]) + if (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_SUCCESS; - zclient->redist[type] = 1; + vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); @@ -287,13 +290,14 @@ rip_redistribute_set (int type) static int rip_redistribute_unset (int type) { - if (! zclient->redist[type]) + if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_SUCCESS; - zclient->redist[type] = 0; + vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, + VRF_DEFAULT); /* Remove the routes from RIP table. */ rip_redistribute_withdraw (type); @@ -304,7 +308,7 @@ rip_redistribute_unset (int type) int rip_redistribute_check (int type) { - return (zclient->redist[type]); + return vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT); } void @@ -314,13 +318,14 @@ rip_redistribute_clean (void) for (i = 0; redist_type[i].str; i++) { - if (zclient->redist[redist_type[i].type]) + if (vrf_bitmap_check (zclient->redist[redist_type[i].type], VRF_DEFAULT)) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, - zclient, redist_type[i].type); + zclient, redist_type[i].type, + VRF_DEFAULT); - zclient->redist[redist_type[i].type] = 0; + vrf_bitmap_unset (zclient->redist[redist_type[i].type], VRF_DEFAULT); /* Remove the routes from RIP table. */ rip_redistribute_withdraw (redist_type[i].type); @@ -334,7 +339,7 @@ DEFUN (rip_redistribute_rip, "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") { - zclient->redist[ZEBRA_ROUTE_RIP] = 1; + vrf_bitmap_set (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT); return CMD_SUCCESS; } @@ -345,7 +350,7 @@ DEFUN (no_rip_redistribute_rip, "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") { - zclient->redist[ZEBRA_ROUTE_RIP] = 0; + vrf_bitmap_unset (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT); return CMD_SUCCESS; } @@ -363,7 +368,7 @@ DEFUN (rip_redistribute_type, redist_type[i].str_min_len) == 0) { zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, - redist_type[i].type); + redist_type[i].type, VRF_DEFAULT); return CMD_SUCCESS; } } @@ -416,7 +421,8 @@ DEFUN (rip_redistribute_type_routemap, redist_type[i].str_min_len) == 0) { rip_routemap_set (redist_type[i].type, argv[1]); - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, + VRF_DEFAULT); return CMD_SUCCESS; } } @@ -474,7 +480,8 @@ DEFUN (rip_redistribute_type_metric, redist_type[i].str_min_len) == 0) { rip_redistribute_metric_set (redist_type[i].type, metric); - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, + VRF_DEFAULT); return CMD_SUCCESS; } } @@ -535,7 +542,8 @@ DEFUN (rip_redistribute_type_metric_routemap, { rip_redistribute_metric_set (redist_type[i].type, metric); rip_routemap_set (redist_type[i].type, argv[2]); - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, + VRF_DEFAULT); return CMD_SUCCESS; } } @@ -639,7 +647,7 @@ config_write_zebra (struct vty *vty) vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } - else if (! zclient->redist[ZEBRA_ROUTE_RIP]) + else if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT)) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute rip%s", VTY_NEWLINE); @@ -654,7 +662,8 @@ config_write_rip_redistribute (struct vty *vty, int config_mode) int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default && zclient->redist[i]) + if (i != zclient->redist_default && + vrf_bitmap_check (zclient->redist[i], VRF_DEFAULT)) { if (config_mode) { @@ -694,12 +703,19 @@ static struct cmd_node zebra_node = "%s(config-router)# ", }; +static void +rip_zebra_connected (struct zclient *zclient) +{ + zclient_send_requests (zclient, VRF_DEFAULT); +} + void rip_zclient_init () { /* Set default value to the zebra client structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_RIP); + zclient->zebra_connected = rip_zebra_connected; zclient->interface_add = rip_interface_add; zclient->interface_delete = rip_interface_delete; zclient->interface_address_add = rip_interface_address_add; diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index c7865d1e9..e1f436ebf 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -192,14 +192,15 @@ ripng_if_down (struct interface *ifp) /* Inteface link up message processing. */ int -ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) +ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; @@ -224,14 +225,14 @@ ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) /* Inteface link down message processing. */ int ripng_interface_down (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; - ifp = zebra_interface_state_read (s); + ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; @@ -248,11 +249,12 @@ ripng_interface_down (int command, struct zclient *zclient, /* Inteface addition message from zebra. */ int -ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) +ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_add_read (zclient->ibuf); + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d", @@ -273,14 +275,14 @@ ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) int ripng_interface_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ - ifp = zebra_interface_state_read(s); + ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; @@ -387,13 +389,13 @@ ripng_apply_address_add (struct connected *ifc) { int ripng_interface_address_add (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, - zclient->ibuf); + zclient->ibuf, vrf_id); if (c == NULL) return 0; @@ -454,14 +456,14 @@ ripng_apply_address_del (struct connected *ifc) { int ripng_interface_address_delete (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; char buf[INET6_ADDRSTRLEN]; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, - zclient->ibuf); + zclient->ibuf, vrf_id); if (ifc) { diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 5d383fa2a..58f88606c 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -37,14 +37,6 @@ /* All information about zebra. */ struct zclient *zclient = NULL; -/* Callback prototypes for zebra client service. */ -int ripng_interface_up (int, struct zclient *, zebra_size_t); -int ripng_interface_down (int, struct zclient *, zebra_size_t); -int ripng_interface_add (int, struct zclient *, zebra_size_t); -int ripng_interface_delete (int, struct zclient *, zebra_size_t); -int ripng_interface_address_add (int, struct zclient *, zebra_size_t); -int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); - /* Send ECMP routes to zebra. */ static void ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) @@ -59,8 +51,9 @@ ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) struct ripng_info *rinfo = NULL; int count = 0; - if (zclient->redist[ZEBRA_ROUTE_RIPNG]) + if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT)) { + api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; @@ -134,7 +127,7 @@ ripng_zebra_ipv6_delete (struct route_node *rp) /* Zebra route add and delete treatment. */ static int ripng_zebra_read_ipv6 (int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv6 api; @@ -194,13 +187,14 @@ ripng_zclient_reset (void) static int ripng_redistribute_unset (int type) { - if (! zclient->redist[type]) + if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_SUCCESS; - zclient->redist[type] = 0; + vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, + VRF_DEFAULT); ripng_redistribute_withdraw (type); @@ -210,7 +204,7 @@ ripng_redistribute_unset (int type) int ripng_redistribute_check (int type) { - return (zclient->redist[type]); + return vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT); } static void @@ -270,13 +264,14 @@ ripng_redistribute_clean () for (i = 0; redist_type[i].str; i++) { - if (zclient->redist[redist_type[i].type]) + if (vrf_bitmap_check (zclient->redist[redist_type[i].type], VRF_DEFAULT)) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, - zclient, redist_type[i].type); + zclient, redist_type[i].type, + VRF_DEFAULT); - zclient->redist[redist_type[i].type] = 0; + vrf_bitmap_unset (zclient->redist[redist_type[i].type], VRF_DEFAULT); /* Remove the routes from RIPng table. */ ripng_redistribute_withdraw (redist_type[i].type); @@ -314,7 +309,7 @@ DEFUN (ripng_redistribute_ripng, "Redistribute information from another routing protocol\n" "RIPng route\n") { - zclient->redist[ZEBRA_ROUTE_RIPNG] = 1; + vrf_bitmap_set (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT); return CMD_SUCCESS; } @@ -325,7 +320,7 @@ DEFUN (no_ripng_redistribute_ripng, "Redistribute information from another routing protocol\n" "RIPng route\n") { - zclient->redist[ZEBRA_ROUTE_RIPNG] = 0; + vrf_bitmap_unset (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT); return CMD_SUCCESS; } @@ -345,7 +340,7 @@ DEFUN (ripng_redistribute_type, return CMD_WARNING; } - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } @@ -393,7 +388,7 @@ DEFUN (ripng_redistribute_type_metric, } ripng_redistribute_metric_set (type, metric); - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } @@ -425,7 +420,7 @@ DEFUN (ripng_redistribute_type_routemap, } ripng_redistribute_routemap_set (type, argv[1]); - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } @@ -462,7 +457,7 @@ DEFUN (ripng_redistribute_type_metric_routemap, ripng_redistribute_metric_set (type, metric); ripng_redistribute_routemap_set (type, argv[2]); - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } @@ -481,7 +476,8 @@ ripng_redistribute_write (struct vty *vty, int config_mode) int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default && zclient->redist[i]) + if (i != zclient->redist_default && + vrf_bitmap_check (zclient->redist[i], VRF_DEFAULT)) { if (config_mode) { @@ -521,7 +517,7 @@ zebra_config_write (struct vty *vty) vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } - else if (! zclient->redist[ZEBRA_ROUTE_RIPNG]) + else if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT)) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE); @@ -537,6 +533,12 @@ static struct cmd_node zebra_node = "%s(config-router)# ", }; +static void +ripng_zebra_connected (struct zclient *zclient) +{ + zclient_send_requests (zclient, VRF_DEFAULT); +} + /* Initialize zebra structure and it's commands. */ void zebra_init () @@ -545,6 +547,7 @@ zebra_init () zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_RIPNG); + zclient->zebra_connected = ripng_zebra_connected; zclient->interface_up = ripng_interface_up; zclient->interface_down = ripng_interface_down; zclient->interface_add = ripng_interface_add; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 706ff542d..28ca41bc9 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -408,12 +408,18 @@ extern int ripng_send_packet (caddr_t buf, int bufsize, extern void ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv); -extern int ripng_interface_up (int command, struct zclient *, zebra_size_t); -extern int ripng_interface_down (int command, struct zclient *, zebra_size_t); -extern int ripng_interface_add (int command, struct zclient *, zebra_size_t); -extern int ripng_interface_delete (int command, struct zclient *, zebra_size_t); -extern int ripng_interface_address_add (int command, struct zclient *, zebra_size_t); -extern int ripng_interface_address_delete (int command, struct zclient *, zebra_size_t); +extern int ripng_interface_up (int command, struct zclient *, zebra_size_t, + vrf_id_t); +extern int ripng_interface_down (int command, struct zclient *, zebra_size_t, + vrf_id_t); +extern int ripng_interface_add (int command, struct zclient *, zebra_size_t, + vrf_id_t); +extern int ripng_interface_delete (int command, struct zclient *, zebra_size_t, + vrf_id_t); +extern int ripng_interface_address_add (int command, struct zclient *, zebra_size_t, + vrf_id_t); +extern int ripng_interface_address_delete (int command, struct zclient *, zebra_size_t, + vrf_id_t); extern int ripng_network_write (struct vty *, int); diff --git a/zebra/client_main.c b/zebra/client_main.c index 8b95907bc..06afc56d4 100644 --- a/zebra/client_main.c +++ b/zebra/client_main.c @@ -54,6 +54,7 @@ zebra_test_ipv4 (int command, int type, char *prefix, char *gateway, inet_aton (gateway, &gate); gpnt = &gate; + api.vrf_id = VRF_DEFAULT; api.type = type; api.flags = 0; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 8bf8ea8c0..5ec821988 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -68,7 +68,7 @@ zebra_check_addr (struct prefix *p) return 1; } -static int +int is_default (struct prefix *p) { if (p->family == AF_INET) @@ -86,7 +86,7 @@ is_default (struct prefix *p) } static void -zebra_redistribute_default (struct zserv *client) +zebra_redistribute_default (struct zserv *client, vrf_id_t vrf_id) { struct prefix_ipv4 p; struct route_table *table; @@ -102,7 +102,7 @@ zebra_redistribute_default (struct zserv *client) p.family = AF_INET; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) { rn = route_node_lookup (table, (struct prefix *)&p); @@ -122,7 +122,7 @@ zebra_redistribute_default (struct zserv *client) p6.family = AF_INET6; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) { rn = route_node_lookup (table, (struct prefix *)&p6); @@ -140,13 +140,13 @@ zebra_redistribute_default (struct zserv *client) /* Redistribute routes. */ static void -zebra_redistribute (struct zserv *client, int type) +zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) { struct rib *newrib; struct route_table *table; struct route_node *rn; - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) @@ -157,7 +157,7 @@ zebra_redistribute (struct zserv *client, int type) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); #ifdef HAVE_IPV6 - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) @@ -177,8 +177,9 @@ redistribute_add (struct prefix *p, struct rib *rib) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { - if ((is_default (p) && client->redist_default) - || client->redist[rib->type]) + if ((is_default (p) && + vrf_bitmap_check (client->redist_default, rib->vrf_id)) + || vrf_bitmap_check (client->redist[rib->type], rib->vrf_id)) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); @@ -202,8 +203,9 @@ redistribute_delete (struct prefix *p, struct rib *rib) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { - if ((is_default (p) && client->redist_default) - || client->redist[rib->type]) + if ((is_default (p) && + vrf_bitmap_check (client->redist_default, rib->vrf_id)) + || vrf_bitmap_check (client->redist[rib->type], rib->vrf_id)) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib); @@ -216,7 +218,8 @@ redistribute_delete (struct prefix *p, struct rib *rib) } void -zebra_redistribute_add (int command, struct zserv *client, int length) +zebra_redistribute_add (int command, struct zserv *client, int length, + vrf_id_t vrf_id) { int type; @@ -225,15 +228,16 @@ zebra_redistribute_add (int command, struct zserv *client, int length) if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; - if (! client->redist[type]) + if (! vrf_bitmap_check (client->redist[type], vrf_id)) { - client->redist[type] = 1; - zebra_redistribute (client, type); + vrf_bitmap_set (client->redist[type], vrf_id); + zebra_redistribute (client, type, vrf_id); } } void -zebra_redistribute_delete (int command, struct zserv *client, int length) +zebra_redistribute_delete (int command, struct zserv *client, int length, + vrf_id_t vrf_id) { int type; @@ -242,21 +246,22 @@ zebra_redistribute_delete (int command, struct zserv *client, int length) if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; - client->redist[type] = 0; + vrf_bitmap_unset (client->redist[type], vrf_id); } void -zebra_redistribute_default_add (int command, struct zserv *client, int length) +zebra_redistribute_default_add (int command, struct zserv *client, int length, + vrf_id_t vrf_id) { - client->redist_default = 1; - zebra_redistribute_default (client); + vrf_bitmap_set (client->redist_default, vrf_id); + zebra_redistribute_default (client, vrf_id); } void zebra_redistribute_default_delete (int command, struct zserv *client, - int length) + int length, vrf_id_t vrf_id) { - client->redist_default = 0;; + vrf_bitmap_unset (client->redist_default, vrf_id); } /* Interface up information. */ diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 9ed99bc59..6a36f4d86 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -26,11 +26,13 @@ #include "table.h" #include "zserv.h" -extern void zebra_redistribute_add (int, struct zserv *, int); -extern void zebra_redistribute_delete (int, struct zserv *, int); +extern void zebra_redistribute_add (int, struct zserv *, int, vrf_id_t); +extern void zebra_redistribute_delete (int, struct zserv *, int, vrf_id_t); -extern void zebra_redistribute_default_add (int, struct zserv *, int); -extern void zebra_redistribute_default_delete (int, struct zserv *, int); +extern void zebra_redistribute_default_add (int, struct zserv *, int, + vrf_id_t); +extern void zebra_redistribute_default_delete (int, struct zserv *, int, + vrf_id_t); extern void redistribute_add (struct prefix *, struct rib *); extern void redistribute_delete (struct prefix *, struct rib *); @@ -48,5 +50,7 @@ extern void zebra_interface_address_delete_update (struct interface *, extern int zebra_check_addr (struct prefix *); +extern int is_default (struct prefix *); + #endif /* _ZEBRA_REDISTRIBUTE_H */ diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index c45ebe1db..c68cec6ae 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -25,18 +25,22 @@ #include "zebra/redistribute.h" -void zebra_redistribute_add (int a, struct zserv *b, int c) +void zebra_redistribute_add (int a, struct zserv *b, int c, + vrf_id_t vrf_id) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_redistribute_delete = zebra_redistribute_add #pragma weak zebra_redistribute_default_add = zebra_redistribute_add #pragma weak zebra_redistribute_default_delete = zebra_redistribute_add #else -void zebra_redistribute_delete (int a, struct zserv *b, int c) +void zebra_redistribute_delete (int a, struct zserv *b, int c, + vrf_id_t vrf_id) { return; } -void zebra_redistribute_default_add (int a, struct zserv *b, int c) +void zebra_redistribute_default_add (int a, struct zserv *b, int c, + vrf_id_t vrf_id) { return; } -void zebra_redistribute_default_delete (int a, struct zserv *b, int c) +void zebra_redistribute_default_delete (int a, struct zserv *b, int c, + vrf_id_t vrf_id) { return; } #endif diff --git a/zebra/zserv.c b/zebra/zserv.c index e17bb7207..8ca561565 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -132,12 +132,13 @@ zebra_server_send_message(struct zserv *client) } static void -zserv_create_header (struct stream *s, uint16_t cmd) +zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id) { /* length placeholder, caller can update */ stream_putw (s, ZEBRA_HEADER_SIZE); stream_putc (s, ZEBRA_HEADER_MARKER); stream_putc (s, ZSERV_VERSION); + stream_putw (s, vrf_id); stream_putw (s, cmd); } @@ -182,13 +183,13 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) struct stream *s; /* Check this client need interface information. */ - if (! client->ifinfo) + if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id)) return 0; s = client->obuf; stream_reset (s); - zserv_create_header (s, ZEBRA_INTERFACE_ADD); + zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface (s, ifp); return zebra_server_send_message(client); @@ -201,13 +202,13 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) struct stream *s; /* Check this client need interface information. */ - if (! client->ifinfo) + if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id)) return 0; s = client->obuf; stream_reset (s); - zserv_create_header (s, ZEBRA_INTERFACE_DELETE); + zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface (s, ifp); return zebra_server_send_message (client); @@ -260,13 +261,13 @@ zsend_interface_address (int cmd, struct zserv *client, struct prefix *p; /* Check this client need interface information. */ - if (! client->ifinfo) + if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id)) return 0; s = client->obuf; stream_reset (s); - zserv_create_header (s, cmd); + zserv_create_header (s, cmd, ifp->vrf_id); stream_putl (s, ifp->ifindex); /* Interface address flag. */ @@ -314,13 +315,13 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) struct stream *s; /* Check this client need interface information. */ - if (! client->ifinfo) + if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id)) return 0; s = client->obuf; stream_reset (s); - zserv_create_header (s, cmd); + zserv_create_header (s, cmd, ifp->vrf_id); zserv_encode_interface (s, ifp); return zebra_server_send_message(client); @@ -359,11 +360,17 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, unsigned long nhnummark = 0, messmark = 0; int nhnum = 0; u_char zapi_flags = 0; - + + /* Check this client need this route. */ + if (!vrf_bitmap_check (client->redist[rib->type], rib->vrf_id) && + !(is_default (p) && + vrf_bitmap_check (client->redist_default, rib->vrf_id))) + return 0; + s = client->obuf; stream_reset (s); - zserv_create_header (s, cmd); + zserv_create_header (s, cmd, rib->vrf_id); /* Put type and nexthop. */ stream_putc (s, rib->type); @@ -465,7 +472,8 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, #ifdef HAVE_IPV6 static int -zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) +zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, + vrf_id_t vrf_id) { struct stream *s; struct rib *rib; @@ -474,14 +482,14 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) struct nexthop *nexthop; /* Lookup nexthop. */ - rib = rib_match_ipv6 (addr, VRF_DEFAULT); + rib = rib_match_ipv6 (addr, vrf_id); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); + zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, vrf_id); stream_put (s, &addr, 16); if (rib) @@ -532,7 +540,8 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) #endif /* HAVE_IPV6 */ static int -zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) +zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, + vrf_id_t vrf_id) { struct stream *s; struct rib *rib; @@ -541,14 +550,14 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, VRF_DEFAULT); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, vrf_id); stream_put_in_addr (s, &addr); if (rib) @@ -619,7 +628,7 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, rib->vrf_id); stream_put_in_addr (s, &addr); if (rib) @@ -671,7 +680,8 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, } static int -zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) +zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, + vrf_id_t vrf_id) { struct stream *s; struct rib *rib; @@ -680,14 +690,14 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) struct nexthop *nexthop; /* Lookup nexthop. */ - rib = rib_lookup_ipv4 (p, VRF_DEFAULT); + rib = rib_lookup_ipv4 (p, vrf_id); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP); + zserv_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP, vrf_id); stream_put_in_addr (s, &p->prefix); if (rib) @@ -742,14 +752,14 @@ zsend_router_id_update (struct zserv *client, struct prefix *p, int blen; /* Check this client need interface information. */ - if (!client->ridinfo) + if (! vrf_bitmap_check (client->ridinfo, vrf_id)) return 0; s = client->obuf; stream_reset (s); /* Message type. */ - zserv_create_header (s, ZEBRA_ROUTER_ID_UPDATE); + zserv_create_header (s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); /* Prefix information. */ stream_putc (s, p->family); @@ -766,7 +776,7 @@ zsend_router_id_update (struct zserv *client, struct prefix *p, /* Register zebra server interface information. Send current all interface and address information. */ static int -zread_interface_add (struct zserv *client, u_short length) +zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { struct listnode *ifnode, *ifnnode; struct listnode *cnode, *cnnode; @@ -774,9 +784,9 @@ zread_interface_add (struct zserv *client, u_short length) struct connected *c; /* Interface information is needed. */ - client->ifinfo = 1; + vrf_bitmap_set (client->ifinfo, vrf_id); - for (ALL_LIST_ELEMENTS (iflist, ifnode, ifnnode, ifp)) + for (ALL_LIST_ELEMENTS (vrf_iflist (vrf_id), ifnode, ifnnode, ifp)) { /* Skip pseudo interface. */ if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) @@ -798,9 +808,9 @@ zread_interface_add (struct zserv *client, u_short length) /* Unregister zebra server interface information. */ static int -zread_interface_delete (struct zserv *client, u_short length) +zread_interface_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) { - client->ifinfo = 0; + vrf_bitmap_unset (client->ifinfo, vrf_id); return 0; } @@ -810,7 +820,7 @@ zread_interface_delete (struct zserv *client, u_short length) * add kernel route. */ static int -zread_ipv4_add (struct zserv *client, u_short length) +zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct rib *rib; @@ -845,7 +855,7 @@ zread_ipv4_add (struct zserv *client, u_short length) stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* VRF ID */ - rib->vrf_id = VRF_DEFAULT; + rib->vrf_id = vrf_id; /* Nexthop parse. */ if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) @@ -901,7 +911,7 @@ zread_ipv4_add (struct zserv *client, u_short length) /* Zebra server IPv4 prefix delete function. */ static int -zread_ipv4_delete (struct zserv *client, u_short length) +zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct stream *s; @@ -977,13 +987,14 @@ zread_ipv4_delete (struct zserv *client, u_short length) api.metric = 0; rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, - VRF_DEFAULT, api.safi); + vrf_id, api.safi); return 0; } /* Nexthop lookup for IPv4. */ static int -zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) +zread_ipv4_nexthop_lookup (struct zserv *client, u_short length, + vrf_id_t vrf_id) { struct in_addr addr; char buf[BUFSIZ]; @@ -992,24 +1003,26 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: looking up %s", __func__, inet_ntop (AF_INET, &addr, buf, BUFSIZ)); - return zsend_ipv4_nexthop_lookup (client, addr); + return zsend_ipv4_nexthop_lookup (client, addr, vrf_id); } /* MRIB Nexthop lookup for IPv4. */ static int -zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length) +zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length, + vrf_id_t vrf_id) { struct in_addr addr; struct rib *rib; addr.s_addr = stream_get_ipv4 (client->ibuf); - rib = rib_match_ipv4_multicast (addr, NULL, VRF_DEFAULT); + rib = rib_match_ipv4_multicast (addr, NULL, vrf_id); return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib); } /* Nexthop lookup for IPv4. */ static int -zread_ipv4_import_lookup (struct zserv *client, u_short length) +zread_ipv4_import_lookup (struct zserv *client, u_short length, + vrf_id_t vrf_id) { struct prefix_ipv4 p; @@ -1017,13 +1030,13 @@ zread_ipv4_import_lookup (struct zserv *client, u_short length) p.prefixlen = stream_getc (client->ibuf); p.prefix.s_addr = stream_get_ipv4 (client->ibuf); - return zsend_ipv4_import_lookup (client, &p); + return zsend_ipv4_import_lookup (client, &p, vrf_id); } #ifdef HAVE_IPV6 /* Zebra server IPv6 prefix add function. */ static int -zread_ipv6_add (struct zserv *client, u_short length) +zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct stream *s; @@ -1082,18 +1095,18 @@ zread_ipv6_add (struct zserv *client, u_short length) if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, - VRF_DEFAULT, zebrad.rtm_table_default, api.metric, + vrf_id, zebrad.rtm_table_default, api.metric, api.distance, api.safi); else rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, - VRF_DEFAULT, zebrad.rtm_table_default, api.metric, + vrf_id, zebrad.rtm_table_default, api.metric, api.distance, api.safi); return 0; } /* Zebra server IPv6 prefix delete function. */ static int -zread_ipv6_delete (struct zserv *client, u_short length) +zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct stream *s; @@ -1150,16 +1163,17 @@ zread_ipv6_delete (struct zserv *client, u_short length) api.metric = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, VRF_DEFAULT, + rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id, api.safi); else - rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, VRF_DEFAULT, + rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id, api.safi); return 0; } static int -zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) +zread_ipv6_nexthop_lookup (struct zserv *client, u_short length, + vrf_id_t vrf_id) { struct in6_addr addr; char buf[BUFSIZ]; @@ -1169,29 +1183,29 @@ zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) zlog_debug("%s: looking up %s", __func__, inet_ntop (AF_INET6, &addr, buf, BUFSIZ)); - return zsend_ipv6_nexthop_lookup (client, &addr); + return zsend_ipv6_nexthop_lookup (client, &addr, vrf_id); } #endif /* HAVE_IPV6 */ /* Register zebra server router-id information. Send current router-id */ static int -zread_router_id_add (struct zserv *client, u_short length) +zread_router_id_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { struct prefix p; /* Router-id information is needed. */ - client->ridinfo = 1; + vrf_bitmap_set (client->ridinfo, vrf_id); - router_id_get (&p, VRF_DEFAULT); + router_id_get (&p, vrf_id); - return zsend_router_id_update (client, &p, VRF_DEFAULT); + return zsend_router_id_update (client, &p, vrf_id); } /* Unregister zebra server router-id information. */ static int -zread_router_id_delete (struct zserv *client, u_short length) +zread_router_id_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) { - client->ridinfo = 0; + vrf_bitmap_unset (client->ridinfo, vrf_id); return 0; } @@ -1220,6 +1234,21 @@ zread_hello (struct zserv *client) } } +/* Unregister all information in a VRF. */ +static int +zread_vrf_unregister (struct zserv *client, u_short length, vrf_id_t vrf_id) +{ + int i; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + vrf_bitmap_unset (client->redist[i], vrf_id); + vrf_bitmap_unset (client->redist_default, vrf_id); + vrf_bitmap_unset (client->ifinfo, vrf_id); + vrf_bitmap_unset (client->ridinfo, vrf_id); + + return 0; +} + /* If client sent routes of specific type, zebra removes it * and returns number of deleted routes. */ @@ -1276,6 +1305,7 @@ static void zebra_client_create (int sock) { struct zserv *client; + int i; client = XCALLOC (0, sizeof (struct zserv)); @@ -1288,6 +1318,13 @@ zebra_client_create (int sock) /* Set table number. */ client->rtm_table = zebrad.rtm_table_default; + /* Initialize flags */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + client->redist[i] = vrf_bitmap_init (); + client->redist_default = vrf_bitmap_init (); + client->ifinfo = vrf_bitmap_init (); + client->ridinfo = vrf_bitmap_init (); + /* Add this client to linked list. */ listnode_add (zebrad.client_list, client); @@ -1304,6 +1341,7 @@ zebra_client_read (struct thread *thread) size_t already; uint16_t length, command; uint8_t marker, version; + vrf_id_t vrf_id; /* Get thread data. Reset reading thread because I'm running. */ sock = THREAD_FD (thread); @@ -1345,6 +1383,7 @@ zebra_client_read (struct thread *thread) length = stream_getw (client->ibuf); marker = stream_getc (client->ibuf); version = stream_getc (client->ibuf); + vrf_id = stream_getw (client->ibuf); command = stream_getw (client->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) @@ -1397,66 +1436,69 @@ zebra_client_read (struct thread *thread) zlog_debug ("zebra message comes from socket [%d]", sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug ("zebra message received [%s] %d", - zserv_command_string (command), length); + zlog_debug ("zebra message received [%s] %d in VRF %u", + zserv_command_string (command), length, vrf_id); switch (command) { case ZEBRA_ROUTER_ID_ADD: - zread_router_id_add (client, length); + zread_router_id_add (client, length, vrf_id); break; case ZEBRA_ROUTER_ID_DELETE: - zread_router_id_delete (client, length); + zread_router_id_delete (client, length, vrf_id); break; case ZEBRA_INTERFACE_ADD: - zread_interface_add (client, length); + zread_interface_add (client, length, vrf_id); break; case ZEBRA_INTERFACE_DELETE: - zread_interface_delete (client, length); + zread_interface_delete (client, length, vrf_id); break; case ZEBRA_IPV4_ROUTE_ADD: - zread_ipv4_add (client, length); + zread_ipv4_add (client, length, vrf_id); break; case ZEBRA_IPV4_ROUTE_DELETE: - zread_ipv4_delete (client, length); + zread_ipv4_delete (client, length, vrf_id); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_ROUTE_ADD: - zread_ipv6_add (client, length); + zread_ipv6_add (client, length, vrf_id); break; case ZEBRA_IPV6_ROUTE_DELETE: - zread_ipv6_delete (client, length); + zread_ipv6_delete (client, length, vrf_id); break; #endif /* HAVE_IPV6 */ case ZEBRA_REDISTRIBUTE_ADD: - zebra_redistribute_add (command, client, length); + zebra_redistribute_add (command, client, length, vrf_id); break; case ZEBRA_REDISTRIBUTE_DELETE: - zebra_redistribute_delete (command, client, length); + zebra_redistribute_delete (command, client, length, vrf_id); break; case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: - zebra_redistribute_default_add (command, client, length); + zebra_redistribute_default_add (command, client, length, vrf_id); break; case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: - zebra_redistribute_default_delete (command, client, length); + zebra_redistribute_default_delete (command, client, length, vrf_id); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP: - zread_ipv4_nexthop_lookup (client, length); + zread_ipv4_nexthop_lookup (client, length, vrf_id); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB: - zread_ipv4_nexthop_lookup_mrib (client, length); + zread_ipv4_nexthop_lookup_mrib (client, length, vrf_id); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: - zread_ipv6_nexthop_lookup (client, length); + zread_ipv6_nexthop_lookup (client, length, vrf_id); break; #endif /* HAVE_IPV6 */ case ZEBRA_IPV4_IMPORT_LOOKUP: - zread_ipv4_import_lookup (client, length); + zread_ipv4_import_lookup (client, length, vrf_id); break; case ZEBRA_HELLO: zread_hello (client); break; + case ZEBRA_VRF_UNREGISTER: + zread_vrf_unregister (client, length, vrf_id); + break; default: zlog_info ("Zebra received unknown command %d", command); break; diff --git a/zebra/zserv.h b/zebra/zserv.h index af005f851..fc01f961a 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -25,6 +25,7 @@ #include "rib.h" #include "if.h" #include "workqueue.h" +#include "vrf.h" /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -56,16 +57,16 @@ struct zserv int rtm_table; /* This client's redistribute flag. */ - u_char redist[ZEBRA_ROUTE_MAX]; + vrf_bitmap_t redist[ZEBRA_ROUTE_MAX]; /* Redistribute default route flag. */ - u_char redist_default; + vrf_bitmap_t redist_default; /* Interface information. */ - u_char ifinfo; + vrf_bitmap_t ifinfo; /* Router-id information. */ - u_char ridinfo; + vrf_bitmap_t ridinfo; }; /* Zebra instance */ From 55cfa2f190620f7c711944637659bc208970324d Mon Sep 17 00:00:00 2001 From: Feng Lu Date: Thu, 3 Jul 2014 18:24:34 +0800 Subject: [PATCH 0749/1342] lib, vtysh: support multiple VRFs by using linux netns We realize VRFs with linux netns by default. The main job is to associate a VRF with a netns. Currently this is done by the configuration: [no] vrf N netns This command is also available in vtysh and goes to only zebra, because presently only zebra supports multiple VRF. A file descriptor is added to "struct vrf". This is for the associated netns file. Once the command "vrf N netns NAME" is executed, the specified file is opened and the file descriptor is stored in the VRF N. In this way the association is formed. In vrf_socket(), we first switch to the specified VRF by using the stored file descriptor, and then can allocate a socket which is working in the associated netns. Signed-off-by: Feng Lu Reviewed-by: Alain Ritoux Signed-off-by: Nicolas Dichtel --- configure.ac | 8 ++ lib/command.h | 1 + lib/vrf.c | 245 +++++++++++++++++++++++++++++++++++++++++--- vtysh/Makefile.am | 1 + vtysh/extract.pl.in | 3 + 5 files changed, 241 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index f68d86fc4..6da65f34d 100755 --- a/configure.ac +++ b/configure.ac @@ -801,6 +801,14 @@ AC_CHECK_FUNCS(setproctitle, , ] ) +AC_CHECK_HEADER([asm-generic/unistd.h], + [AC_CHECK_DECL(__NR_setns, + AC_DEFINE(HAVE_NETNS,, Have netns),, + QUAGGA_INCLUDES [#include + ]) + AC_CHECK_FUNCS(setns, AC_DEFINE(HAVE_SETNS,, Have setns))] + ) + dnl ------------------------------------ dnl Determine routing get and set method dnl ------------------------------------ diff --git a/lib/command.h b/lib/command.h index a36a524a0..bb0122fa4 100644 --- a/lib/command.h +++ b/lib/command.h @@ -68,6 +68,7 @@ enum node_type AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ ENABLE_NODE, /* Enable node. */ CONFIG_NODE, /* Config node. Default mode of config file. */ + VRF_NODE, /* VRF node. */ SERVICE_NODE, /* Service node. */ DEBUG_NODE, /* Debug node. */ AAA_NODE, /* AAA node. */ diff --git a/lib/vrf.c b/lib/vrf.c index 683026e5c..89653a8bb 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -22,21 +22,57 @@ #include +#ifdef HAVE_NETNS +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#endif + #include "if.h" #include "vrf.h" #include "prefix.h" #include "table.h" #include "log.h" #include "memory.h" +#include "command.h" +#include "vty.h" + +#ifdef HAVE_NETNS + +#ifndef CLONE_NEWNET +#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ +#endif + +#ifndef HAVE_SETNS +static inline int setns(int fd, int nstype) +{ +#ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif /* HAVE_SETNS */ + +#define VRF_RUN_DIR "/var/run/netns" +#define VRF_DEFAULT_NAME "/proc/self/ns/net" + +#else /* !HAVE_NETNS */ #define VRF_DEFAULT_NAME "Default-IP-Routing-Table" +#endif /* HAVE_NETNS */ + struct vrf { /* Identifier, same as the vector index */ vrf_id_t vrf_id; /* Name */ char *name; + /* File descriptor */ + int fd; /* Master list of interfaces belonging to this VRF */ struct list *iflist; @@ -90,6 +126,7 @@ vrf_get (vrf_id_t vrf_id) vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); vrf->vrf_id = vrf_id; + vrf->fd = -1; rn->info = vrf; /* Initialize interfaces. */ @@ -109,8 +146,7 @@ vrf_delete (struct vrf *vrf) { zlog_info ("VRF %u is to be deleted.", vrf->vrf_id); - if (vrf_is_enabled (vrf)) - vrf_disable (vrf); + vrf_disable (vrf); if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook) (vrf->vrf_id, &vrf->info); @@ -149,7 +185,11 @@ vrf_lookup (vrf_id_t vrf_id) static int vrf_is_enabled (struct vrf *vrf) { - return vrf && vrf->vrf_id == VRF_DEFAULT; +#ifdef HAVE_NETNS + return vrf && vrf->fd >= 0; +#else + return vrf && vrf->fd == -2 && vrf->vrf_id == VRF_DEFAULT; +#endif } /* @@ -162,18 +202,34 @@ vrf_is_enabled (struct vrf *vrf) static int vrf_enable (struct vrf *vrf) { - /* Till now, only the default VRF can be enabled. */ - if (vrf->vrf_id == VRF_DEFAULT) + + if (!vrf_is_enabled (vrf)) { - zlog_info ("VRF %u is enabled.", vrf->vrf_id); +#ifdef HAVE_NETNS + vrf->fd = open (vrf->name, O_RDONLY); +#else + vrf->fd = -2; /* Remember that vrf_enable_hook has been called */ + errno = -ENOTSUP; +#endif + + if (!vrf_is_enabled (vrf)) + { + zlog_err ("Can not enable VRF %u: %s!", + vrf->vrf_id, safe_strerror (errno)); + return 0; + } + +#ifdef HAVE_NETNS + zlog_info ("VRF %u is associated with NETNS %s.", + vrf->vrf_id, vrf->name); +#endif + zlog_info ("VRF %u is enabled.", vrf->vrf_id); if (vrf_master.vrf_enable_hook) (*vrf_master.vrf_enable_hook) (vrf->vrf_id, &vrf->info); - - return 1; } - return 0; + return 1; } /* @@ -188,10 +244,13 @@ vrf_disable (struct vrf *vrf) { zlog_info ("VRF %u is to be disabled.", vrf->vrf_id); - /* Till now, nothing to be done for the default VRF. */ - if (vrf_master.vrf_disable_hook) (*vrf_master.vrf_disable_hook) (vrf->vrf_id, &vrf->info); + +#ifdef HAVE_NETNS + close (vrf->fd); +#endif + vrf->fd = -1; } } @@ -429,6 +488,144 @@ vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id) VRF_BITMAP_FLAG (offset)) ? 1 : 0; } +#ifdef HAVE_NETNS +/* + * VRF realization with NETNS + */ + +static char * +vrf_netns_pathname (struct vty *vty, const char *name) +{ + static char pathname[PATH_MAX]; + char *result; + + if (name[0] == '/') /* absolute pathname */ + result = realpath (name, pathname); + else /* relevant pathname */ + { + char tmp_name[PATH_MAX]; + snprintf (tmp_name, PATH_MAX, "%s/%s", VRF_RUN_DIR, name); + result = realpath (tmp_name, pathname); + } + + if (! result) + { + vty_out (vty, "Invalid pathname: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return NULL; + } + return pathname; +} + +DEFUN (vrf_netns, + vrf_netns_cmd, + "vrf <1-65535> netns NAME", + "Enable a VRF\n" + "Specify the VRF identifier\n" + "Associate with a NETNS\n" + "The file name in " VRF_RUN_DIR ", or a full pathname\n") +{ + vrf_id_t vrf_id = VRF_DEFAULT; + struct vrf *vrf = NULL; + char *pathname = vrf_netns_pathname (vty, argv[1]); + + if (!pathname) + return CMD_WARNING; + + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + vrf = vrf_get (vrf_id); + + if (vrf->name && strcmp (vrf->name, pathname) != 0) + { + vty_out (vty, "VRF %u is already configured with NETNS %s%s", + vrf->vrf_id, vrf->name, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!vrf->name) + vrf->name = XSTRDUP (MTYPE_VRF_NAME, pathname); + + if (!vrf_enable (vrf)) + { + vty_out (vty, "Can not associate VRF %u with NETNS %s%s", + vrf->vrf_id, vrf->name, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_vrf_netns, + no_vrf_netns_cmd, + "no vrf <1-65535> netns NAME", + NO_STR + "Enable a VRF\n" + "Specify the VRF identifier\n" + "Associate with a NETNS\n" + "The file name in " VRF_RUN_DIR ", or a full pathname\n") +{ + vrf_id_t vrf_id = VRF_DEFAULT; + struct vrf *vrf = NULL; + char *pathname = vrf_netns_pathname (vty, argv[1]); + + if (!pathname) + return CMD_WARNING; + + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); + vrf = vrf_lookup (vrf_id); + + if (!vrf) + { + vty_out (vty, "VRF %u is not found%s", vrf_id, VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (vrf->name && strcmp (vrf->name, pathname) != 0) + { + vty_out (vty, "Incorrect NETNS file name%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vrf_disable (vrf); + + if (vrf->name) + { + XFREE (MTYPE_VRF_NAME, vrf->name); + vrf->name = NULL; + } + + return CMD_SUCCESS; +} + +/* VRF node. */ +static struct cmd_node vrf_node = +{ + VRF_NODE, + "", /* VRF node has no interface. */ + 1 +}; + +/* VRF configuration write function. */ +static int +vrf_config_write (struct vty *vty) +{ + struct route_node *rn; + struct vrf *vrf; + int write = 0; + + for (rn = route_top (vrf_table); rn; rn = route_next (rn)) + if ((vrf = rn->info) != NULL && + vrf->vrf_id != VRF_DEFAULT && vrf->name) + { + vty_out (vty, "vrf %u netns %s%s", vrf->vrf_id, vrf->name, VTY_NEWLINE); + write++; + } + + return write; +} + +#endif /* HAVE_NETNS */ + /* Initialize VRF module. */ void vrf_init (void) @@ -455,6 +652,13 @@ vrf_init (void) zlog_err ("vrf_init: failed to enable the default VRF!"); exit (1); } + +#ifdef HAVE_NETNS + /* Install VRF commands. */ + install_node (&vrf_node, vrf_config_write); + install_element (CONFIG_NODE, &vrf_netns_cmd); + install_element (CONFIG_NODE, &no_vrf_netns_cmd); +#endif } /* Terminate VRF module. */ @@ -476,19 +680,26 @@ vrf_terminate (void) int vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id) { + struct vrf *vrf = vrf_lookup (vrf_id); int ret = -1; - if (!vrf_is_enabled (vrf_lookup (vrf_id))) + if (!vrf_is_enabled (vrf)) { errno = ENOSYS; return -1; } - if (vrf_id == VRF_DEFAULT) - ret = socket (domain, type, protocol); - else - errno = ENOSYS; +#ifdef HAVE_NETNS + ret = (vrf_id != VRF_DEFAULT) ? setns (vrf->fd, CLONE_NEWNET) : 0; + if (ret >= 0) + { + ret = socket (domain, type, protocol); + if (vrf_id != VRF_DEFAULT) + setns (vrf_lookup (VRF_DEFAULT)->fd, CLONE_NEWNET); + } +#else + ret = socket (domain, type, protocol); +#endif return ret; } - diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index d1ff69b9c..850b505e5 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -28,6 +28,7 @@ vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \ + $(top_srcdir)/lib/vrf.c \ $(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \ $(top_srcdir)/zebra/interface.c \ $(top_srcdir)/zebra/irdp_interface.c \ diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index f057e2492..aa90be4a1 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -99,6 +99,9 @@ foreach (@ARGV) { elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; } + elsif ($file =~ /lib\/vrf\.c$/) { + $protocol = "VTYSH_ZEBRA"; + } elsif ($file =~ /lib\/plist\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; From 84c3840c7157438b5cb2e324d184ca08ac07fb41 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 26 May 2015 15:19:38 +0100 Subject: [PATCH 0750/1342] bgpd: peer_uptime overflows after 1 year MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bgpd.c: (peer_uptime) Wraps after 1 year, and doesn't indicate years. Fix. Assume a year is 365 days, for an easy life. Fixes: Bug #836 Reported-by: Rolf Hanßen Acked-by: Donald Sharp --- bgpd/bgpd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4de854e4e..7a0274c0a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4699,10 +4699,11 @@ peer_uptime (time_t uptime2, char *buf, size_t len) uptime1 = bgp_clock (); uptime1 -= uptime2; tm = gmtime (&uptime1); - + /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 +#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 +#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 if (uptime1 < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", @@ -4710,9 +4711,13 @@ peer_uptime (time_t uptime2, char *buf, size_t len) else if (uptime1 < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); - else + else if (uptime1 < ONE_YEAR_SECOND) snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + else + snprintf (buf, len, "%02dy%02dw%dd", + tm->tm_year - 70, tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7)); return buf; } From 1ed8ce47b922b71f3b3cdd661e647bbe7ed2eca7 Mon Sep 17 00:00:00 2001 From: Wenjian Ma Date: Fri, 19 Jun 2015 10:53:26 +0800 Subject: [PATCH 0751/1342] lib, stream: fix stream sanity checks Because operator "!" has higher priority than "&&", So we put the "&&" expression in "()" to check both getp and endp. Acked-by: Donald Sharp --- lib/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stream.c b/lib/stream.c index e13da08bc..9c26fea88 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -60,7 +60,7 @@ #define STREAM_VERIFY_SANE(S) \ do { \ - if ( !(GETP_VALID(S, (S)->getp)) && ENDP_VALID(S, (S)->endp) ) \ + if ( !(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp)) ) \ STREAM_WARN_OFFSETS(S); \ assert ( GETP_VALID(S, (S)->getp) ); \ assert ( ENDP_VALID(S, (S)->endp) ); \ From 771626860adfc30c00f70d993ccb8f4d7c0c0c63 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 19 Jun 2015 19:26:18 -0400 Subject: [PATCH 0752/1342] PIMD: Fix code to use srandom/random pimd rolled it's own solution to random #'s, that was not terribly random. Rely on the underlying system to generate random #'s for us Signed-off-by: Donald Sharp --- pimd/Makefile.am | 4 ++-- pimd/pim_iface.c | 8 +++---- pimd/pim_pim.c | 5 ++-- pimd/pim_rand.c | 60 ------------------------------------------------ pimd/pim_rand.h | 30 ------------------------ pimd/pimd.c | 3 +-- 6 files changed, 9 insertions(+), 101 deletions(-) delete mode 100644 pimd/pim_rand.c delete mode 100644 pimd/pim_rand.h diff --git a/pimd/Makefile.am b/pimd/Makefile.am index b82613a80..cb525f7be 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -52,7 +52,7 @@ libpim_a_SOURCES = \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ - pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c \ + pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ pim_igmp_join.c pim_ssmpingd.c pim_int.c noinst_HEADERS = \ @@ -61,7 +61,7 @@ noinst_HEADERS = \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ - pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h \ + pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pimd_SOURCES = \ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index dc3e9a2bb..6f806a1b2 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -36,7 +36,6 @@ #include "pim_pim.h" #include "pim_neighbor.h" #include "pim_ifchannel.h" -#include "pim_rand.h" #include "pim_sock.h" #include "pim_time.h" #include "pim_ssmpingd.h" @@ -839,7 +838,7 @@ int pim_if_t_override_msec(struct interface *ifp) effective_override_interval_msec = pim_if_effective_override_interval_msec(ifp); - t_override_msec = pim_rand_next(0, effective_override_interval_msec); + t_override_msec = random() % (effective_override_interval_msec + 1); return t_override_msec; } @@ -902,6 +901,7 @@ long pim_if_t_suppressed_msec(struct interface *ifp) { struct pim_interface *pim_ifp; long t_suppressed_msec; + uint32_t ramount = 0; pim_ifp = ifp->info; zassert(pim_ifp); @@ -911,8 +911,8 @@ long pim_if_t_suppressed_msec(struct interface *ifp) return 0; /* t_suppressed = t_periodic * rand(1.1, 1.4) */ - - t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400); + ramount = 1100 + (random() % (1400 - 1100 + 1)); + t_suppressed_msec = qpim_t_periodic * ramount; return t_suppressed_msec; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index f8ac650d2..409972d4b 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -39,7 +39,6 @@ #include "pim_join.h" #include "pim_assert.h" #include "pim_msg.h" -#include "pim_rand.h" static int on_pim_hello_send(struct thread *t); static int pim_hello_send(struct interface *ifp, @@ -686,7 +685,7 @@ void pim_hello_restart_triggered(struct interface *ifp) } zassert(!pim_ifp->t_pim_hello_timer); - random_msec = pim_rand_next(0, triggered_hello_delay_msec); + random_msec = random() % (triggered_hello_delay_msec + 1); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("Scheduling %d msec triggered hello on interface %s", @@ -724,7 +723,7 @@ int pim_sock_add(struct interface *ifp) pim_ifp->t_pim_sock_read = 0; pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); - pim_ifp->pim_generation_id = pim_rand() & (int64_t) 0xFFFFFFFF; + pim_ifp->pim_generation_id = random(); zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name, ifp->ifindex); diff --git a/pimd/pim_rand.c b/pimd/pim_rand.c deleted file mode 100644 index df2a1111e..000000000 --- a/pimd/pim_rand.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - PIM for Quagga - Copyright (C) 2008 Everton da Silva Marques - - This program 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 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING; if not, write to the - Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - MA 02110-1301 USA - - $QuaggaId: $Format:%an, %ai, %h$ $ -*/ - -#include "pim_rand.h" -#include "pim_time.h" - -/* Quick and dirty random number generator from NUMERICAL RECIPES IN C: - THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5). */ -/* BEWARE: '_qseed_' is assigned! */ -#define QRANDOM(_qseed_) ((_qseed_) = (((_qseed_) * 1664525L) + 1013904223L)) - -static long qpim_rand_seed; - -void pim_rand_init() -{ - qpim_rand_seed = pim_time_monotonic_sec() ^ getpid(); -} - -long pim_rand() -{ - return QRANDOM(qpim_rand_seed); -} - -int pim_rand_next(int min, int max) -{ - long rand; - - assert(min <= max); - - /* FIXME better random generator ? */ - - rand = QRANDOM(qpim_rand_seed); - if (rand < 0) - rand = -rand; - rand = rand % (1 + max - min) + min; - - assert(rand >= min); - assert(rand <= max); - - return rand; -} diff --git a/pimd/pim_rand.h b/pimd/pim_rand.h deleted file mode 100644 index a1df5054e..000000000 --- a/pimd/pim_rand.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - PIM for Quagga - Copyright (C) 2008 Everton da Silva Marques - - This program 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 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING; if not, write to the - Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - MA 02110-1301 USA - - $QuaggaId: $Format:%an, %ai, %h$ $ -*/ - -#ifndef PIM_RAND_H -#define PIM_RAND_H - -void pim_rand_init(void); -long pim_rand(void); -int pim_rand_next(int min, int max); - -#endif /* PIM_RAND_H */ diff --git a/pimd/pimd.c b/pimd/pimd.c index 78c3ff5d0..3797d4fc4 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -34,7 +34,6 @@ #include "pim_oil.h" #include "pim_pim.h" #include "pim_upstream.h" -#include "pim_rand.h" #include "pim_rpf.h" #include "pim_ssmpingd.h" @@ -83,7 +82,7 @@ static void pim_free() void pim_init() { - pim_rand_init(); + srandom(time(NULL)); if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", From f31bab4fbf367a4417784ba9873e524d42242036 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 19 Jun 2015 19:26:19 -0400 Subject: [PATCH 0753/1342] Quagga: Fix code to use srandom/random Quagga was using a mix of srand/rand and srandom/random. Consolidate to use srandom/random which are the POSIX versions of random number generators Signed-off-by: Donald Sharp --- bgpd/bgp_fsm.c | 2 +- bgpd/bgp_main.c | 2 +- bgpd/bgp_routemap.c | 13 +------------ isisd/isis_main.c | 2 +- isisd/isis_misc.c | 2 +- lib/command.c | 2 +- ripd/ripd.c | 4 ++-- ripngd/ripngd.c | 4 ++-- 8 files changed, 10 insertions(+), 21 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index d261bb598..6a2e41e89 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -65,7 +65,7 @@ static int bgp_start (struct peer *); static int bgp_start_jitter (int time) { - return ((rand () % (time + 1)) - (time / 2)); + return ((random () % (time + 1)) - (time / 2)); } /* Check if suppress start/restart of sessions to peer. */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index ad4de7989..7c2988cd1 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -420,7 +420,7 @@ main (int argc, char **argv) master = bm->master; /* Initializations. */ - srand (time (NULL)); + srandom (time (NULL)); signal_init (master, array_size(bgp_signals), bgp_signals); zprivs_init (&bgpd_privs); cmd_init (1); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 5467cfdc4..20bf2ebaa 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -884,12 +884,7 @@ static route_map_result_t route_match_probability (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - long r; -#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 - r = random(); -#else - r = (long) rand(); -#endif + long r = random(); switch (*(long *) rule) { @@ -911,12 +906,6 @@ route_match_probability_compile (const char *arg) long *lobule; unsigned perc; -#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 - srandom (time (NULL)); -#else - srand (time (NULL)); -#endif - perc = atoi (arg); lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (long)); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 60ecb754a..e1af71f7e 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -320,7 +320,7 @@ main (int argc, char **argv, char **envp) master = thread_master_create (); /* random seed from time */ - srand (time (NULL)); + srandom (time (NULL)); /* * initializations diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 968fa05fe..2dfd7cca3 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -510,7 +510,7 @@ isis_jitter (unsigned long timer, unsigned long jitter) * most IS-IS timers are no longer than 16 bit */ - j = 1 + (int) ((RANDOM_SPREAD * rand ()) / (RAND_MAX + 1.0)); + j = 1 + (int) ((RANDOM_SPREAD * random ()) / (RAND_MAX + 1.0)); k = timer - (timer * (100 - jitter)) / 100; diff --git a/lib/command.c b/lib/command.c index 3a59f2449..641cf2078 100644 --- a/lib/command.c +++ b/lib/command.c @@ -4144,7 +4144,7 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_work_queues_cmd); install_element (ENABLE_NODE, &show_work_queues_cmd); } - srand(time(NULL)); + srandom(time(NULL)); } static void diff --git a/ripd/ripd.c b/ripd/ripd.c index 9d355ecb9..b42ca7264 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2859,7 +2859,7 @@ rip_update_jitter (unsigned long time) if (jitter_input < JITTER_BOUND) jitter_input = JITTER_BOUND; - jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input)); + jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input)); return jitter/JITTER_BOUND; } @@ -4132,7 +4132,7 @@ void rip_init (void) { /* Randomize for triggered update random(). */ - srand (time (NULL)); + srandom (time (NULL)); /* Install top nodes. */ install_node (&rip_node, config_write_rip); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 4a7f52fbf..97a139281 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -1936,7 +1936,7 @@ ripng_request (struct interface *ifp) static int ripng_update_jitter (int time) { - return ((rand () % (time + 1)) - (time / 2)); + return ((random () % (time + 1)) - (time / 2)); } void @@ -3084,7 +3084,7 @@ void ripng_init () { /* Randomize. */ - srand (time (NULL)); + srandom (time (NULL)); /* Install RIPNG_NODE. */ install_node (&cmd_ripng_node, ripng_config_write); From 1934e7895ded8d9d7a76ab3f482c381bf5f6725c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 5 Jun 2015 12:15:44 -0700 Subject: [PATCH 0754/1342] pim_mroute.h has a different version of code than linux/mroute.h provides linux/mroutes.h and pim_mroute.h both have copies of the same structures. This is causing failures in setsockopt(..., MRT_ADD_MFC,...) because of data structure incompatibilities between the kernel and what pim_mroute.h was providing. Modify the code to check for mroute.h and include it if necessary. I did not modify the non linux/mroute.h path because I do not have other systems to test on easily. Signed-off-by: Donald Sharp --- configure.ac | 5 +++++ pimd/pim_mroute.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 6da65f34d..6e92bd150 100755 --- a/configure.ac +++ b/configure.ac @@ -950,6 +950,11 @@ dnl figure out how to specify an interface in multicast sockets API dnl --------------------------------------------------------------- AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES) +AC_CHECK_HEADERS([linux/mroute.h], [], [], +[ +#if HAVE_NETINET_IN_H +#include +#endif]) AC_MSG_CHECKING([for BSD struct ip_mreq hack]) AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H #include diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index 350b1e373..125d1901b 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -40,6 +40,9 @@ #define PIM_MROUTE_MIN_TTL (1) +#if defined(HAVE_LINUX_MROUTE_H) +#include +#else /* Below: from */ @@ -154,6 +157,7 @@ struct igmpmsg struct in_addr im_src,im_dst; }; #endif +#endif /* Above: from From b1891fb9705b6085f81269dec0795f2065442047 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 9 Jun 2015 20:22:42 -0400 Subject: [PATCH 0755/1342] Add code to extract.pl.in to prevent further cli function overwrites Currently extract.pl.in is used to build the vtysh cli. When two different cli's collide with the same command name, the original cli is never called, because it is dropped. This code notes the silent drop and tracks the number of drops. If they change then the code will fail the build. The current number of drops was figured out by running extract.pl and counting up the drops then adding code to compare the numbers returned. If you have added to the problem, the solution is to fix your cli command to not stomp on someone else's command. If you have removed a stomp, safely modify extract.pl.in as part of your commit. Signed-off-by: Donald Sharp Acked-by: Vincent Jardin --- vtysh/extract.pl.in | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index aa90be4a1..738600705 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -60,6 +60,8 @@ $ignore{'"terminal monitor"'} = "ignore"; $ignore{'"terminal no monitor"'} = "ignore"; $ignore{'"show history"'} = "ignore"; +my $cli_stomp = 0; + foreach (@ARGV) { $file = $_; @@ -136,6 +138,12 @@ foreach (@ARGV) { $defun_body = join (", ", @defun_array); # $cmd -> $str hash for lookup + if (exists($cmd2str{$cmd})) { + warn "Duplicate CLI Function: $cmd\n"; + warn "\tFrom cli: $cmd2str{$cmd} to New cli: $str\n"; + warn "\tOriginal Protocol: $cmd2proto{$cmd} to New Protocol: $protocol\n"; + $cli_stomp++; + } $cmd2str{$cmd} = $str; $cmd2defun{$cmd} = $defun_body; $cmd2proto{$cmd} = $protocol; @@ -169,6 +177,27 @@ foreach (@ARGV) { } } +my $bad_cli_stomps = 78; +# Currently we have $bad_cli_stomps. This was determined by +# running this script and counting up the collisions from what +# was returned. +# +# When we have cli commands that map to the same function name, we +# can introduce subtle bugs due to code not being called when +# we think it is. +# +# If extract.pl fails with a error message and you've been +# modifying the cli, then go back and fix your code to +# not have cli command function collisions. +# +# If you've removed a cli overwrite, you can safely subtract +# one from $bad_cli_stomps. If you've added to the problem +# please fix your code before submittal +if ($cli_stomp != $bad_cli_stomps) { + warn "Expected $bad_cli_stomps command line stomps, but got $cli_stomp instead\n"; + exit $cli_stomp; +} + # Check finaly alive $cmd; foreach (keys %odefun) { my ($node, $str) = (split (/,/)); From 7f56743f7d4b3dcdae329de2de2aba820368c3d9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 12 Jun 2015 17:47:26 -0700 Subject: [PATCH 0756/1342] pimd assert when no route to source from a new igmp join When pim_upstream_new is called the code looks up the nexthop. If there is no route to the source, the code silently ignored the error returned. When the nexthop lookup fails don't create the 'struct pim_stream *' to return. Signed-off-by: Donald Sharp --- pimd/pim_upstream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index d02f91548..a4d274ab5 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -349,6 +349,7 @@ static struct pim_upstream *pim_upstream_new(struct in_addr source_addr, struct in_addr group_addr) { struct pim_upstream *up; + enum pim_rpf_result rpf_result; up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); if (!up) { @@ -372,7 +373,11 @@ static struct pim_upstream *pim_upstream_new(struct in_addr source_addr, up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric; up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY; - pim_rpf_update(up, 0); + rpf_result = pim_rpf_update(up, 0); + if (rpf_result == PIM_RPF_FAILURE) { + XFREE(MTYPE_PIM_UPSTREAM, up); + return NULL; + } listnode_add(qpim_upstream_list, up); From 94266fa822baf9b9c9e10ac03ccec8ccf3ce0c98 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 19 Nov 2009 15:27:30 +0100 Subject: [PATCH 0757/1342] ospfd: Self nbrs needs to be rebuilt when router ID changes. Some self nbrs are identified by router_id, these needs to be rebuilt instead of just resetting router ID. Possibly one could optimize for !(virtual | ptop) links by doing oi->nbr_self->router_id = router_id instead. Router ID will change once after startup config has been read and zebra reports router ID, unless router ID has been configured in ospf. --- ospfd/ospfd.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index c55bdaebf..4062d6450 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -112,8 +112,15 @@ ospf_router_id_update (struct ospf *ospf) if (!IPV4_ADDR_SAME (&router_id_old, &router_id)) { for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) - /* Update self-neighbor's router_id. */ - oi->nbr_self->router_id = router_id; + { + /* Some nbrs are identified by router_id, these needs + * to be rebuilt. Possible optimization would be to do + * oi->nbr_self->router_id = router_id for + * !(virtual | ptop) links + */ + ospf_nbr_delete(oi->nbr_self); + ospf_nbr_add_self(oi); + } /* If AS-external-LSA is queued, then flush those LSAs. */ if (router_id_old.s_addr == 0 && ospf->external_origin) From fbb6c8650344fe72d39f538c681659e8b76a39d0 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Mon, 8 Mar 2010 13:58:09 +0100 Subject: [PATCH 0758/1342] ospfd: add missing unlock for ospf_interface_address_delete() Signed-off-by: Joakim Tjernlund Acked-by: Feng Lu --- ospfd/ospf_zebra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index fe1f45db5..27041003f 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -312,6 +312,7 @@ ospf_interface_address_delete (int command, struct zclient *zclient, assert (rn->info); oi = rn->info; + route_unlock_node (rn); /* Call interface hook functions to clean up */ ospf_if_free (oi); From d5643f5a477e099a3dcae4a707ccb5ca66bfee66 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Mon, 8 Mar 2010 13:58:10 +0100 Subject: [PATCH 0759/1342] ospfd: Move route_unlock_node() in ospf_ase_incremental_update() Signed-off-by: Joakim Tjernlund Acked-by: Feng Lu --- ospfd/ospf_ase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 04240c15a..027e49ff7 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -821,6 +821,7 @@ ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa) { rn2 = route_node_get (tmp_old, (struct prefix *) &p); rn2->info = rn->info; + route_unlock_node (rn); } /* install changes to zebra */ @@ -845,7 +846,6 @@ ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa) { rn->info = NULL; route_unlock_node (rn); - route_unlock_node (rn); } } From fc363cd8a02ad1ac8a6ca57013fd8c531d45926a Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Mon, 8 Mar 2010 13:58:12 +0100 Subject: [PATCH 0760/1342] ospfd: ospf_ase.c, external_lsa locking fixes. Signed-off-by: Joakim Tjernlund Acked-by: Feng Lu --- ospfd/ospf_ase.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 027e49ff7..74c1711ef 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -723,6 +723,8 @@ ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top) rn = route_node_get (top->external_lsas, (struct prefix *) &p); if ((lst = rn->info) == NULL) rn->info = lst = list_new(); + else + route_unlock_node (rn); /* We assume that if LSA is deleted from DB is is also deleted from this RT */ @@ -743,13 +745,13 @@ ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top) p.prefixlen = ip_masklen (al->mask); apply_mask_ipv4 (&p); - rn = route_node_get (top->external_lsas, (struct prefix *) &p); - lst = rn->info; + rn = route_node_lookup (top->external_lsas, (struct prefix *) &p); - /* XXX lst can be NULL */ - if (lst) { + if (rn) { + lst = rn->info; listnode_delete (lst, lsa); ospf_lsa_unlock (&lsa); /* external_lsas list */ + route_unlock_node (rn); } } From 4eaecdc403461fe59026e1ce3a217526d75eca25 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Mon, 8 Mar 2010 13:58:13 +0100 Subject: [PATCH 0761/1342] ospfd: ospf_ls_upd_send() add missing unlock. Signed-off-by: Joakim Tjernlund Acked-by: Feng Lu --- ospfd/ospf_packet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 587484f2a..c6cd01844 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3822,6 +3822,8 @@ ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag) if (rn->info == NULL) rn->info = list_new (); + else + route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO (update, node, lsa)) listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */ From 4de398e3b676bcf041984e285dba12f229215419 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Mon, 8 Mar 2010 13:58:14 +0100 Subject: [PATCH 0762/1342] ospfd: ospf_nbr_nbma_set()/ospf_snmp_vl_add() add unlock Signed-off-by: Joakim Tjernlund Acked-by: Feng Lu --- ospfd/ospf_snmp.c | 3 +++ ospfd/ospfd.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 9f9177694..604766d82 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1927,6 +1927,9 @@ ospf_snmp_vl_add (struct ospf_vl_data *vl_data) lp.adv_router = vl_data->vl_peer; rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + if (rn->info) + route_unlock_node (rn); + rn->info = vl_data; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 4062d6450..019a22b70 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -1557,6 +1557,8 @@ ospf_nbr_nbma_set (struct ospf *ospf, struct in_addr nbr_addr) p.prefixlen = IPV4_MAX_BITLEN; rn = route_node_get (ospf->nbr_nbma, (struct prefix *)&p); + if (rn->info) + route_unlock_node (rn); rn->info = nbr_nbma; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) From 08d95905acd0cbb810831429b638ac2d1604ca37 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 27 May 2015 17:57:31 -0700 Subject: [PATCH 0763/1342] Fixup of redhat control files to properly start pimd --- redhat/quagga.sysconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/redhat/quagga.sysconfig b/redhat/quagga.sysconfig index 4d6ec5ad1..caa0fffe2 100644 --- a/redhat/quagga.sysconfig +++ b/redhat/quagga.sysconfig @@ -9,6 +9,7 @@ OSPFD_OPTS="-A 127.0.0.1" RIPD_OPTS="-A 127.0.0.1" RIPNGD_OPTS="-A ::1" ZEBRA_OPTS="-A 127.0.0.1" +PIMD_OPTS="-A 127.0.0.1" # Watchquagga configuration for LSB initscripts # From cd557c3d766a7233490b8cf7325219ffa1398ef2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 27 May 2015 17:40:46 -0700 Subject: [PATCH 0764/1342] pim: 'show debugging' collision The 'show debugging' cli as setup by pim collided with 'show debugging isis'. Fix that and clean up cli help commands to actually display correctly. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 13812cd85..a5d11b9f7 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3519,11 +3519,12 @@ ALIAS (no_debug_pim_zebra, DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) -DEFUN (show_debugging, - show_debugging_cmd, - "show debugging", +DEFUN (show_debugging_pim, + show_debugging_pim_cmd, + "show debugging pim", SHOW_STR - "State of each debugging option\n") + DEBUG_STR + PIM_STR) { pim_debug_config_write(vty); return CMD_SUCCESS; @@ -4373,7 +4374,7 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_mroute_count_cmd); install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); - install_element (VIEW_NODE, &show_debugging_cmd); + install_element (VIEW_NODE, &show_debugging_pim_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); @@ -4412,7 +4413,7 @@ void pim_cmd_init() install_element (ENABLE_NODE, &show_ip_mroute_count_cmd); install_element (ENABLE_NODE, &show_ip_rib_cmd); install_element (ENABLE_NODE, &show_ip_ssmpingd_cmd); - install_element (ENABLE_NODE, &show_debugging_cmd); + install_element (ENABLE_NODE, &show_debugging_pim_cmd); install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd); From 9487b4fcfc0754109e49240214e283fd58756843 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 23 May 2015 18:16:50 -0700 Subject: [PATCH 0765/1342] watchquagga.c does not compile without warnings Signed-off-by: Donald Sharp --- watchquagga/watchquagga.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index d92803d7e..9bd7a5f25 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -334,7 +334,7 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", } static pid_t -run_background(const char *shell_cmd) +run_background(char *shell_cmd) { pid_t child; @@ -350,8 +350,10 @@ run_background(const char *shell_cmd) if (setpgid(0,0) < 0) zlog_warn("warning: setpgid(0,0) failed: %s",safe_strerror(errno)); { - const char *argv[4] = { "sh", "-c", shell_cmd, NULL}; - execv("/bin/sh",(char *const *)argv); + char shell[] = "sh"; + char dashc[] = "-c"; + char *const argv[4] = { shell, dashc, shell_cmd, NULL}; + execv("/bin/sh", argv); zlog_err("execv(/bin/sh -c '%s') failed: %s", shell_cmd,safe_strerror(errno)); _exit(127); From 8c56b44de0fa8100b6f0b367dbc604d41b94025f Mon Sep 17 00:00:00 2001 From: Kaloyan Kovachev Date: Mon, 15 Jun 2015 17:08:48 +0300 Subject: [PATCH 0766/1342] Fix _netlink_route_debug message --- zebra/rt_netlink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 0f0f3fed3..33fbc0805 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1571,6 +1571,7 @@ _netlink_route_debug( routedesc, lookup (nlmsg_str, cmd), prefix2str (p, buf, sizeof(buf)), + zvrf->vrf_id, nexthop_type_to_str (nexthop->type)); } } From 8b84c2762ccd2d47a115824ee083d33e697a7741 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 30 May 2015 18:57:54 -0400 Subject: [PATCH 0767/1342] Removal of 'show ip mroute' The 'show ip mroute' in zebra_vty.c collided with the 'show ip mroute' command in pim_cmd.c. The 'show ip rpf' command is functionally equivalent to the zebra_vty.c 'show ip mroute'. Therefore remove the 'show ip mroute' command in zebra_vty.c. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 92 ----------------------------------------------- 1 file changed, 92 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index dd7df5c96..6ad286ff0 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2480,89 +2480,6 @@ DEFUN (show_ip_protocol, return CMD_SUCCESS; } -/* - * Show IP mroute command to dump the BGP Multicast - * routing table - */ -DEFUN (show_ip_mroute, - show_ip_mroute_cmd, - "show ip mroute", - SHOW_STR - IP_STR - "IP Multicast routing table\n") -{ - struct route_table *table; - struct route_node *rn; - struct rib *rib; - int first = 1; - vrf_id_t vrf_id = VRF_DEFAULT; - - if (argc > 0) - VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); - - table = zebra_vrf_table (AFI_IP, SAFI_MULTICAST, vrf_id); - if (! table) - return CMD_SUCCESS; - - /* Show all IPv4 routes. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V4_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } - return CMD_SUCCESS; -} - -ALIAS (show_ip_mroute, - show_ip_mroute_vrf_cmd, - "show ip mroute " VRF_CMD_STR, - SHOW_STR - IP_STR - "IP Multicast routing table\n" - VRF_CMD_HELP_STR) - -DEFUN (show_ip_mroute_vrf_all, - show_ip_mroute_vrf_all_cmd, - "show ip mroute " VRF_ALL_CMD_STR, - SHOW_STR - IP_STR - "IP Multicast routing table\n" - VRF_ALL_CMD_HELP_STR) -{ - struct route_table *table; - struct route_node *rn; - struct rib *rib; - struct zebra_vrf *zvrf; - vrf_iter_t iter; - int first = 1; - - for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) - { - if ((zvrf = vrf_iter2info (iter)) == NULL || - (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) - continue; - - /* Show all IPv4 routes. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V4_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } - } - - return CMD_SUCCESS; -} - #ifdef HAVE_IPV6 /* General fucntion for IPv6 static route. */ static int @@ -3972,9 +3889,6 @@ zebra_vty_init (void) install_element (ENABLE_NODE, &show_ip_route_summary_cmd); install_element (ENABLE_NODE, &show_ip_route_summary_prefix_cmd); - install_element (VIEW_NODE, &show_ip_mroute_cmd); - install_element (ENABLE_NODE, &show_ip_mroute_cmd); - install_element (VIEW_NODE, &show_ip_rpf_cmd); install_element (ENABLE_NODE, &show_ip_rpf_cmd); install_element (VIEW_NODE, &show_ip_rpf_addr_cmd); @@ -4045,12 +3959,6 @@ zebra_vty_init (void) install_element (ENABLE_NODE, &show_ip_route_summary_vrf_all_cmd); install_element (ENABLE_NODE, &show_ip_route_summary_prefix_vrf_all_cmd); - install_element (VIEW_NODE, &show_ip_mroute_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_mroute_vrf_cmd); - - install_element (VIEW_NODE, &show_ip_mroute_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_mroute_vrf_all_cmd); - install_element (VIEW_NODE, &show_ip_rpf_vrf_cmd); install_element (VIEW_NODE, &show_ip_rpf_vrf_all_cmd); install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_cmd); From c9b07581e0df8867499e97e08b382b6d3cc9c4c4 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Mon, 8 Mar 2010 13:58:11 +0100 Subject: [PATCH 0768/1342] ospfd: Use route_node_lookup() instaed of route_node_get() Signed-off-by: Joakim Tjernlund --- ospfd/ospf_abr.c | 4 +++- ospfd/ospf_snmp.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index e172e53cd..5c308092d 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -133,7 +133,9 @@ ospf_area_range_lookup_next (struct ospf_area *area, rn = route_top (area->ranges); else { - rn = route_node_get (area->ranges, (struct prefix *) &p); + rn = route_node_lookup (area->ranges, (struct prefix *) &p); + if (!rn) + return NULL; rn = route_next (rn); } diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 604766d82..78435de56 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1994,7 +1994,9 @@ ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor, rn = route_top (ospf_snmp_vl_table); else { - rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (!rn) + return NULL; rn = route_next (rn); } From 6064613154b6302606547735f0c466910a6443ea Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 4 Aug 2015 17:37:16 +0100 Subject: [PATCH 0769/1342] vtysh: adjust bad_cli_stomps in extract.pl.in to reflect fixes & fix build --- vtysh/extract.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 738600705..63186d738 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -177,7 +177,7 @@ foreach (@ARGV) { } } -my $bad_cli_stomps = 78; +my $bad_cli_stomps = 76; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. From 030674d7f9b2a25d4d337459ef32287de8f9879d Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Thu, 11 Jun 2015 18:29:02 -0500 Subject: [PATCH 0770/1342] pimd: add support for configuring multicast static routes Hi, This patch adds the ability to configure multicast static routes directly into pimd. Two source files are introduced to implement the new feature in addition to changes to existing files. Here is how it can be used the CLI: interface ip mroute # for asm or ip mroute # for ssm Please let me know if you have any questions or concerns, Regards, Jafar Acked-by: Donald Sharp --- lib/memtypes.c | 1 + pimd/Makefile.am | 4 +- pimd/pim_cmd.c | 354 +++++++++++++++++++++++++++++++++++++++++++++- pimd/pim_cmd.h | 1 + pimd/pim_static.c | 305 +++++++++++++++++++++++++++++++++++++++ pimd/pim_static.h | 47 ++++++ pimd/pimd.c | 13 ++ pimd/pimd.h | 13 +- 8 files changed, 731 insertions(+), 7 deletions(-) create mode 100644 pimd/pim_static.c create mode 100644 pimd/pim_static.h diff --git a/lib/memtypes.c b/lib/memtypes.c index ab3c1f8ee..57de5c4fd 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -270,6 +270,7 @@ struct memory_list memory_list_pim[] = { MTYPE_PIM_IFCHANNEL, "PIM interface (S,G) state" }, { MTYPE_PIM_UPSTREAM, "PIM upstream (S,G) state" }, { MTYPE_PIM_SSMPINGD, "PIM sspimgd socket" }, + { MTYPE_PIM_STATIC_ROUTE, "PIM Static Route" }, { -1, NULL }, }; diff --git a/pimd/Makefile.am b/pimd/Makefile.am index cb525f7be..bf8a158f3 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -53,7 +53,7 @@ libpim_a_SOURCES = \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ - pim_igmp_join.c pim_ssmpingd.c pim_int.c + pim_igmp_join.c pim_ssmpingd.c pim_int.c pim_static.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ @@ -62,7 +62,7 @@ noinst_HEADERS = \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \ - pim_igmp_join.h pim_ssmpingd.h pim_int.h + pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_static.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a5d11b9f7..10d0c86a0 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -51,6 +51,7 @@ #include "pim_macro.h" #include "pim_ssmpingd.h" #include "pim_zebra.h" +#include "pim_static.h" static struct cmd_node pim_global_node = { PIM_NODE, @@ -1626,6 +1627,44 @@ static void mroute_del_all() } } +static void static_mroute_add_all() +{ + struct listnode *node; + struct static_route *s_route; + + for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + if (pim_mroute_add(&s_route->mc)) { + /* just log warning */ + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } +} + +static void static_mroute_del_all() +{ + struct listnode *node; + struct static_route *s_route; + + for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + if (pim_mroute_del(&s_route->mc)) { + /* just log warning */ + char source_str[100]; + char group_str[100]; + pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); + pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); + zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", + __FILE__, __PRETTY_FUNCTION__, + source_str, group_str); + } + } +} + DEFUN (clear_ip_mroute, clear_ip_mroute_cmd, "clear ip mroute", @@ -2133,15 +2172,17 @@ static void show_mroute(struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; + struct static_route *s_route; time_t now; - vty_out(vty, "Proto: I=IGMP P=PIM%s%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "Proto: I=IGMP P=PIM S=STATIC%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Source Group Proto Input iVifI Output oVifI TTL Uptime %s", VTY_NEWLINE); now = pim_time_monotonic_sec(); + /* print list of PIM and IGMP routes */ for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; @@ -2187,6 +2228,48 @@ static void show_mroute(struct vty *vty) VTY_NEWLINE); } } + + /* Print list of static routes */ + for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + char group_str[100]; + char source_str[100]; + int oif_vif_index; + + pim_inet4_dump("", s_route->group, group_str, sizeof(group_str)); + pim_inet4_dump("", s_route->source, source_str, sizeof(source_str)); + + for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) { + struct interface *ifp_in; + struct interface *ifp_out; + char oif_uptime[10]; + int ttl; + char proto[5]; + + ttl = s_route->oif_ttls[oif_vif_index]; + if (ttl < 1) + continue; + + ifp_in = pim_if_find_by_vif_index(s_route->iif); + ifp_out = pim_if_find_by_vif_index(oif_vif_index); + + pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - s_route->creation[oif_vif_index]); + + proto[0] = '\0'; + strcat(proto, "S"); + + vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s", + source_str, + group_str, + proto, + ifp_in ? ifp_in->name : "", + s_route->iif, + ifp_out ? ifp_out->name : "", + oif_vif_index, + ttl, + oif_uptime, + VTY_NEWLINE); + } + } } DEFUN (show_ip_mroute, @@ -2204,12 +2287,14 @@ static void show_mroute_count(struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; + struct static_route *s_route; vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Source Group Packets Bytes WrongIf %s", VTY_NEWLINE); + /* Print PIM and IGMP route counts */ for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; @@ -2242,7 +2327,41 @@ static void show_mroute_count(struct vty *vty) sgreq.bytecnt, sgreq.wrong_if, VTY_NEWLINE); + } + + /* Print static route counts */ + for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + char group_str[100]; + char source_str[100]; + struct sioc_sg_req sgreq; + + memset(&sgreq, 0, sizeof(sgreq)); + sgreq.src = s_route->mc.mfcc_origin; + sgreq.grp = s_route->mc.mfcc_mcastgrp; + + pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); + pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); + + if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { + int e = errno; + vty_out(vty, + "ioctl(SIOCGETSGCNT=%d) failure for (S,G)=(%s,%s): errno=%d: %s%s", + SIOCGETSGCNT, + source_str, + group_str, + e, + safe_strerror(e), + VTY_NEWLINE); + continue; + } + vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", + source_str, + group_str, + sgreq.pktcnt, + sgreq.bytecnt, + sgreq.wrong_if, + VTY_NEWLINE); } } @@ -2365,6 +2484,7 @@ DEFUN (ip_multicast_routing, pim_mroute_socket_enable(); pim_if_add_vif_all(); mroute_add_all(); + static_mroute_add_all(); return CMD_SUCCESS; } @@ -2377,6 +2497,7 @@ DEFUN (no_ip_multicast_routing, "Enable IP multicast forwarding\n") { mroute_del_all(); + static_mroute_del_all(); pim_if_del_vif_all(); pim_mroute_socket_disable(); return CMD_SUCCESS; @@ -3071,6 +3192,200 @@ DEFUN (interface_no_ip_pim_ssm, return CMD_SUCCESS; } +DEFUN (interface_ip_mroute, + interface_ip_mroute_cmd, + "ip mroute INTERFACE A.B.C.D", + IP_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group address\n") +{ + struct interface *iif; + struct interface *oif; + const char *oifname; + const char *grp_str; + struct in_addr grp_addr; + struct in_addr src_addr; + int result; + + iif = vty->index; + + oifname = argv[0]; + oif = if_lookup_by_name(oifname); + if (!oif) { + vty_out(vty, "No such interface name %s%s", + oifname, VTY_NEWLINE); + return CMD_WARNING; + } + + grp_str = argv[1]; + result = inet_pton(AF_INET, grp_str, &grp_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + grp_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + src_addr.s_addr = INADDR_ANY; + + if (pim_static_add(iif, oif, grp_addr, src_addr)) { + vty_out(vty, "Failed to add route%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (interface_ip_mroute_source, + interface_ip_mroute_source_cmd, + "ip mroute INTERFACE A.B.C.D A.B.C.D", + IP_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group address\n" + "Source address\n") +{ + struct interface *iif; + struct interface *oif; + const char *oifname; + const char *grp_str; + struct in_addr grp_addr; + const char *src_str; + struct in_addr src_addr; + int result; + + iif = vty->index; + + oifname = argv[0]; + oif = if_lookup_by_name(oifname); + if (!oif) { + vty_out(vty, "No such interface name %s%s", + oifname, VTY_NEWLINE); + return CMD_WARNING; + } + + grp_str = argv[1]; + result = inet_pton(AF_INET, grp_str, &grp_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + grp_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + src_str = argv[2]; + result = inet_pton(AF_INET, src_str, &src_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + src_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (pim_static_add(iif, oif, grp_addr, src_addr)) { + vty_out(vty, "Failed to add route%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_mroute, + interface_no_ip_mroute_cmd, + "no ip mroute INTERFACE A.B.C.D", + NO_STR + IP_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group Address\n") +{ + struct interface *iif; + struct interface *oif; + const char *oifname; + const char *grp_str; + struct in_addr grp_addr; + struct in_addr src_addr; + int result; + + iif = vty->index; + + oifname = argv[0]; + oif = if_lookup_by_name(oifname); + if (!oif) { + vty_out(vty, "No such interface name %s%s", + oifname, VTY_NEWLINE); + return CMD_WARNING; + } + + grp_str = argv[1]; + result = inet_pton(AF_INET, grp_str, &grp_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + grp_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + src_addr.s_addr = INADDR_ANY; + + if (pim_static_del(iif, oif, grp_addr, src_addr)) { + vty_out(vty, "Failed to remove route%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_mroute_source, + interface_no_ip_mroute_source_cmd, + "no ip mroute INTERFACE A.B.C.D A.B.C.D", + NO_STR + IP_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group Address\n" + "Source Address\n") +{ + struct interface *iif; + struct interface *oif; + const char *oifname; + const char *grp_str; + struct in_addr grp_addr; + const char *src_str; + struct in_addr src_addr; + int result; + + iif = vty->index; + + oifname = argv[0]; + oif = if_lookup_by_name(oifname); + if (!oif) { + vty_out(vty, "No such interface name %s%s", + oifname, VTY_NEWLINE); + return CMD_WARNING; + } + + grp_str = argv[1]; + result = inet_pton(AF_INET, grp_str, &grp_addr); + if (result <= 0) { + vty_out(vty, "Bad group address %s: errno=%d: %s%s", + grp_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + src_str = argv[2]; + result = inet_pton(AF_INET, src_str, &src_addr); + if (result <= 0) { + vty_out(vty, "Bad source address %s: errno=%d: %s%s", + src_str, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (pim_static_del(iif, oif, grp_addr, src_addr)) { + vty_out(vty, "Failed to remove route%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + DEFUN (debug_igmp, debug_igmp_cmd, "debug igmp", @@ -3219,6 +3534,33 @@ ALIAS (no_debug_mroute, UNDEBUG_STR DEBUG_MROUTE_STR) +DEFUN (debug_static, + debug_static_cmd, + "debug static", + DEBUG_STR + DEBUG_STATIC_STR) +{ + PIM_DO_DEBUG_STATIC; + return CMD_SUCCESS; +} + +DEFUN (no_debug_static, + no_debug_static_cmd, + "no debug static", + NO_STR + DEBUG_STR + DEBUG_STATIC_STR) +{ + PIM_DONT_DEBUG_STATIC; + return CMD_SUCCESS; +} + +ALIAS (no_debug_static, + undebug_static_cmd, + "undebug static", + UNDEBUG_STR + DEBUG_STATIC_STR) + DEFUN (debug_pim, debug_pim_cmd, "debug pim", @@ -4344,6 +4686,12 @@ void pim_cmd_init() install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd); install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); + // Static mroutes NEB + install_element (INTERFACE_NODE, &interface_ip_mroute_cmd); + install_element (INTERFACE_NODE, &interface_ip_mroute_source_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_mroute_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_mroute_source_cmd); + install_element (VIEW_NODE, &show_ip_igmp_interface_cmd); install_element (VIEW_NODE, &show_ip_igmp_join_cmd); install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd); @@ -4437,6 +4785,8 @@ void pim_cmd_init() install_element (ENABLE_NODE, &undebug_igmp_trace_cmd); install_element (ENABLE_NODE, &debug_mroute_cmd); install_element (ENABLE_NODE, &no_debug_mroute_cmd); + install_element (ENABLE_NODE, &debug_static_cmd); + install_element (ENABLE_NODE, &no_debug_static_cmd); install_element (ENABLE_NODE, &debug_pim_cmd); install_element (ENABLE_NODE, &no_debug_pim_cmd); install_element (ENABLE_NODE, &undebug_pim_cmd); @@ -4478,6 +4828,8 @@ void pim_cmd_init() install_element (CONFIG_NODE, &undebug_igmp_trace_cmd); install_element (CONFIG_NODE, &debug_mroute_cmd); install_element (CONFIG_NODE, &no_debug_mroute_cmd); + install_element (CONFIG_NODE, &debug_static_cmd); + install_element (CONFIG_NODE, &no_debug_static_cmd); install_element (CONFIG_NODE, &debug_pim_cmd); install_element (CONFIG_NODE, &no_debug_pim_cmd); install_element (CONFIG_NODE, &undebug_pim_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index c50374009..25e244462 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -39,6 +39,7 @@ #define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n" #define DEBUG_IGMP_TRACE_STR "IGMP internal daemon activity\n" #define DEBUG_MROUTE_STR "PIM interaction with kernel MFC cache\n" +#define DEBUG_STATIC_STR "PIM Static Multicast Route activity\n" #define DEBUG_PIM_STR "PIM protocol activity\n" #define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" diff --git a/pimd/pim_static.c b/pimd/pim_static.c new file mode 100644 index 000000000..f2b8e856b --- /dev/null +++ b/pimd/pim_static.c @@ -0,0 +1,305 @@ +/* + PIM for Quagga: add the ability to configure multicast static routes + Copyright (C) 2014 Nathan Bahr, ATCorp + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include "pim_static.h" +#include "pim_time.h" +#include "pim_str.h" +#include "pimd.h" +#include "pim_iface.h" +#include "log.h" +#include "memory.h" +#include "linklist.h" + +void pim_static_route_free(struct static_route *s_route) +{ + XFREE(MTYPE_PIM_STATIC_ROUTE, s_route); +} + +static struct static_route * static_route_alloc() +{ + struct static_route *s_route; + + s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route)); + if (!s_route) { + zlog_err("PIM XCALLOC(%lu) failure", sizeof(*s_route)); + return 0; + } + return s_route; +} + +static struct static_route *static_route_new(unsigned int iif, + unsigned int oif, + struct in_addr group, + struct in_addr source) +{ + struct static_route * s_route; + s_route = static_route_alloc(); + if (!s_route) { + return 0; + } + + s_route->group = group; + s_route->source = source; + s_route->iif = iif; + s_route->oif_ttls[oif] = 1; + s_route->oif_count = 1; + s_route->mc.mfcc_origin = source; + s_route->mc.mfcc_mcastgrp = group; + s_route->mc.mfcc_parent = iif; + s_route->mc.mfcc_ttls[oif] = 1; + s_route->creation[oif] = pim_time_monotonic_sec(); + + return s_route; +} + + +int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source) +{ + struct listnode *node = 0; + struct static_route *s_route = 0; + struct static_route *original_s_route = 0; + struct pim_interface *pim_iif = iif ? iif->info : 0; + struct pim_interface *pim_oif = oif ? oif->info : 0; + unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; + unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; + + if (!iif_index || !oif_index) { + zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index); + return -2; + } + +#ifdef PIM_ENFORCE_LOOPFREE_MFC + if (iif_index == oif_index) { + /* looped MFC entry */ + zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index); + return -4; + } +#endif + + for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + if (s_route->group.s_addr == group.s_addr && + s_route->source.s_addr == source.s_addr) { + if (s_route->iif == iif_index && + s_route->oif_ttls[oif_index]) { + char gifaddr_str[100]; + char sifaddr_str[100]; + pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); + pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); + zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index, + gifaddr_str, + sifaddr_str); + return -3; + } + + /* Ok, from here on out we will be making changes to the s_route structure, but if + * for some reason we fail to commit these changes to the kernel, we want to be able + * restore the state of the list. So copy the node data and if need be, we can copy + * back if it fails. + */ + original_s_route = static_route_alloc(); + if (!original_s_route) { + return -5; + } + memcpy(original_s_route, s_route, sizeof(struct static_route)); + + /* Route exists and has the same input interface, but adding a new output interface */ + if (s_route->iif == iif_index) { + s_route->oif_ttls[oif_index] = 1; + s_route->mc.mfcc_ttls[oif_index] = 1; + s_route->creation[oif_index] = pim_time_monotonic_sec(); + ++s_route->oif_count; + } else { + /* input interface changed */ + s_route->iif = iif_index; + s_route->mc.mfcc_parent = iif_index; + +#ifdef PIM_ENFORCE_LOOPFREE_MFC + /* check to make sure the new input was not an old output */ + if (s_route->oif_ttls[iif_index]) { + s_route->oif_ttls[iif_index] = 0; + s_route->creation[iif_index] = 0; + s_route->mc.mfcc_ttls[iif_index] = 0; + --s_route->oif_count; + } +#endif + + /* now add the new output, if it is new */ + if (!s_route->oif_ttls[oif_index]) { + s_route->oif_ttls[oif_index] = 1; + s_route->creation[oif_index] = pim_time_monotonic_sec(); + s_route->mc.mfcc_ttls[oif_index] = 1; + ++s_route->oif_count; + } + } + + break; + } + } + + /* If node is null then we reached the end of the list without finding a match */ + if (!node) { + s_route = static_route_new(iif_index, oif_index, group, source); + listnode_add(qpim_static_route_list, s_route); + } + + if (pim_mroute_add(&(s_route->mc))) + { + char gifaddr_str[100]; + char sifaddr_str[100]; + pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); + pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); + zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index, + gifaddr_str, + sifaddr_str); + + /* Need to put s_route back to the way it was */ + if (original_s_route) { + memcpy(s_route, original_s_route, sizeof(struct static_route)); + } else { + /* we never stored off a copy, so it must have been a fresh new route */ + listnode_delete(qpim_static_route_list, s_route); + pim_static_route_free(s_route); + } + + return -1; + } + + /* Make sure we free the memory for the route copy if used */ + if (original_s_route) { + pim_static_route_free(original_s_route); + } + + if (PIM_DEBUG_STATIC) { + char gifaddr_str[100]; + char sifaddr_str[100]; + pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); + pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); + zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)", + __PRETTY_FUNCTION__, + iif_index, + oif_index, + gifaddr_str, + sifaddr_str); + } + + return 0; +} + +int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source) +{ + struct listnode *node = 0; + struct listnode *nextnode = 0; + struct static_route *s_route = 0; + struct pim_interface *pim_iif = iif ? iif->info : 0; + struct pim_interface *pim_oif = oif ? oif->info : 0; + unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; + unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; + + if (!iif_index || !oif_index) { + zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index); + return -2; + } + + for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, s_route)) { + if (s_route->iif == iif_index && + s_route->group.s_addr == group.s_addr && + s_route->source.s_addr == source.s_addr && + s_route->oif_ttls[oif_index]) { + s_route->oif_ttls[oif_index] = 0; + s_route->mc.mfcc_ttls[oif_index] = 0; + --s_route->oif_count; + + /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */ + if (s_route->oif_count <= 0 ? pim_mroute_del(&s_route->mc) : pim_mroute_add(&s_route->mc)) { + char gifaddr_str[100]; + char sifaddr_str[100]; + pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); + pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); + zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index, + gifaddr_str, + sifaddr_str); + + s_route->oif_ttls[oif_index] = 1; + s_route->mc.mfcc_ttls[oif_index] = 1; + ++s_route->oif_count; + + return -1; + } + + s_route->creation[oif_index] = 0; + + if (s_route->oif_count <= 0) { + listnode_delete(qpim_static_route_list, s_route); + pim_static_route_free(s_route); + } + + if (PIM_DEBUG_STATIC) { + char gifaddr_str[100]; + char sifaddr_str[100]; + pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); + pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); + zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)", + __PRETTY_FUNCTION__, + iif_index, + oif_index, + gifaddr_str, + sifaddr_str); + } + + break; + } + } + + if (!node) { + char gifaddr_str[100]; + char sifaddr_str[100]; + pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); + pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); + zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)", + __FILE__, __PRETTY_FUNCTION__, + iif_index, + oif_index, + gifaddr_str, + sifaddr_str); + return -3; + } + + return 0; +} diff --git a/pimd/pim_static.h b/pimd/pim_static.h new file mode 100644 index 000000000..3a096932d --- /dev/null +++ b/pimd/pim_static.h @@ -0,0 +1,47 @@ +/* + PIM for Quagga: add the ability to configure multicast static routes + Copyright (C) 2014 Nathan Bahr, ATCorp + + This program 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#ifndef PIM_STATIC_H_ +#define PIM_STATIC_H_ + +#include +#include "pim_mroute.h" +#include "if.h" + +struct static_route { + /* Each static route is unique by these pair of addresses */ + struct in_addr group; + struct in_addr source; + + unsigned int iif; + unsigned char oif_ttls[MAXVIFS]; + int oif_count; + struct mfcctl mc; + time_t creation[MAXVIFS]; +}; + +void pim_static_route_free(struct static_route *s_route); + +int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source); +int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source); + +#endif /* PIM_STATIC_H_ */ diff --git a/pimd/pimd.c b/pimd/pimd.c index 3797d4fc4..97fb22331 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -36,6 +36,7 @@ #include "pim_upstream.h" #include "pim_rpf.h" #include "pim_ssmpingd.h" +#include "pim_static.h" const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; @@ -68,6 +69,7 @@ int64_t qpim_mroute_add_events = 0; int64_t qpim_mroute_add_last = 0; int64_t qpim_mroute_del_events = 0; int64_t qpim_mroute_del_last = 0; +struct list *qpim_static_route_list = 0; static void pim_free() { @@ -78,6 +80,9 @@ static void pim_free() if (qpim_upstream_list) list_free(qpim_upstream_list); + + if (qpim_static_route_list) + list_free(qpim_static_route_list); } void pim_init() @@ -109,6 +114,14 @@ void pim_init() } qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free; + qpim_static_route_list = list_new(); + if (!qpim_static_route_list) { + zlog_err("%s %s: failure: static_route_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return; + } + qpim_static_route_list->del = (void (*)(void *)) pim_static_route_free; + qpim_mroute_socket_fd = -1; /* mark mroute as disabled */ qpim_mroute_oif_highest_vif_index = -1; diff --git a/pimd/pimd.h b/pimd/pimd.h index 22a29220d..aed26bea2 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -64,8 +64,9 @@ #define PIM_MASK_ZEBRA (1 << 8) #define PIM_MASK_SSMPINGD (1 << 9) #define PIM_MASK_MROUTE (1 << 10) -#define PIM_MASK_PIM_HELLO (1 << 11) -#define PIM_MASK_PIM_J_P (1 << 12) +#define PIM_MASK_PIM_HELLO (1 << 11) +#define PIM_MASK_PIM_J_P (1 << 12) +#define PIM_MASK_STATIC (1 << 13) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; @@ -99,6 +100,7 @@ int64_t qpim_mroute_add_events; int64_t qpim_mroute_add_last; int64_t qpim_mroute_del_events; int64_t qpim_mroute_del_last; +struct list *qpim_static_route_list; /* list of routes added statically */ #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) @@ -116,8 +118,9 @@ int64_t qpim_mroute_del_last; #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) #define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE) -#define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO) -#define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P) +#define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO) +#define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P) +#define PIM_DEBUG_STATIC (qpim_debugs & PIM_MASK_STATIC) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) @@ -136,6 +139,7 @@ int64_t qpim_mroute_del_last; #define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE) #define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO) #define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P) +#define PIM_DO_DEBUG_STATIC (qpim_debugs |= PIM_MASK_STATIC) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) @@ -150,6 +154,7 @@ int64_t qpim_mroute_del_last; #define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO) #define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P) +#define PIM_DONT_DEBUG_STATIC (qpim_debugs &= ~PIM_MASK_STATIC) void pim_init(void); void pim_terminate(void); From 6ae80e0d80531f602c3cb0e535c4e12bd2181b40 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 18 Jun 2015 18:14:20 -0700 Subject: [PATCH 0771/1342] pimd: Add ability to set DR Priority for an interface From RFC 4601, Section 4.3.1: The DR_Priority Option allows a network administrator to give preference to a particular router in the DR election process by giving it a numerically larger DR Priority. The DR_Priority Option SHOULD be included in every Hello message, even if no DR Priority is explicitly configured on that interface. This is necessary because priority-based DR election is only enabled when all neighbors on an interface advertise that they are capable of using the DR_Priority Option. The default priority is 1. This modification allows the setting of the DR Priority on a per interface basis. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 74 ++++++++++++++++++++++++++++++++++++++++++--- pimd/pim_neighbor.c | 5 ++- pimd/pim_neighbor.h | 2 +- pimd/pim_vty.c | 8 +++++ 4 files changed, 82 insertions(+), 7 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 10d0c86a0..9833411da 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -563,10 +563,11 @@ static void pim_show_dr(struct vty *vty) now = pim_time_monotonic_sec(); vty_out(vty, - "NonPri: Number of neighbors missing DR Priority hello option%s%s", - VTY_NEWLINE, VTY_NEWLINE); + "NonPri: Number of neighbors missing DR Priority hello option%s" + "DrPri: Designated Router Priority sent%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - vty_out(vty, "Interface Address DR Uptime Elections Changes NonPri%s", VTY_NEWLINE); + vty_out(vty, "Interface Address DR Uptime Elections Changes NonPri DrPri%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; @@ -590,7 +591,7 @@ static void pim_show_dr(struct vty *vty) pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_str, sizeof(dr_str)); - vty_out(vty, "%-9s %-15s %-15s %8s %9d %7d %6d%s", + vty_out(vty, "%-9s %-15s %-15s %8s %9d %7d %6d %10d%s", ifp->name, inet_ntoa(ifaddr), dr_str, @@ -598,6 +599,7 @@ static void pim_show_dr(struct vty *vty) pim_ifp->pim_dr_election_count, pim_ifp->pim_dr_election_changes, pim_ifp->pim_dr_num_nondrpri_neighbors, + pim_ifp->pim_dr_priority, VTY_NEWLINE); } } @@ -3123,6 +3125,66 @@ DEFUN (interface_no_ip_igmp_query_max_response_time_dsec, return CMD_SUCCESS; } +DEFUN (interface_ip_pim_drprio, + interface_ip_pim_drprio_cmd, + "ip pim drpriority <1-4294967295>", + IP_STR + PIM_STR + "Set the Designated Router Election Priority\n" + "Value of the new DR Priority\n") +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + uint32_t old_dr_prio; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, "Please enable PIM on interface, first%s", VTY_NEWLINE); + return CMD_WARNING; + } + + old_dr_prio = pim_ifp->pim_dr_priority; + + pim_ifp->pim_dr_priority = strtol(argv[0], NULL, 10); + + if (old_dr_prio != pim_ifp->pim_dr_priority) { + if (pim_if_dr_election(ifp)) + pim_hello_restart_now(ifp); + } + + return CMD_SUCCESS; +} + +DEFUN (interface_no_ip_pim_drprio, + interface_no_ip_pim_drprio_cmd, + "no ip pim drpriority {<1-4294967295>}", + IP_STR + PIM_STR + "Revert the Designated Router Priority to default\n" + "Old Value of the Priority\n") +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, "Pim no enabled on this interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { + pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; + if (pim_if_dr_election(ifp)) + pim_hello_restart_now(ifp); + } + + return CMD_SUCCESS; +} + DEFUN (interface_ip_pim_ssm, interface_ip_pim_ssm_cmd, "ip pim ssm", @@ -4684,7 +4746,9 @@ void pim_cmd_init() install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd); - install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); + install_element (INTERFACE_NODE, &interface_ip_pim_drprio_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd); // Static mroutes NEB install_element (INTERFACE_NODE, &interface_ip_mroute_cmd); diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 9404cec13..eaf36df35 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -106,7 +106,7 @@ static void dr_election_by_pri(struct interface *ifp) PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ -void pim_if_dr_election(struct interface *ifp) +int pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr old_dr_addr; @@ -140,7 +140,10 @@ void pim_if_dr_election(struct interface *ifp) pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); + return 1; } + + return 0; } static void update_dr_priority(struct pim_neighbor *neigh, diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index 8f19c7505..5b2172dfc 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -69,6 +69,6 @@ void pim_neighbor_update(struct pim_neighbor *neigh, struct list *addr_list); struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, struct in_addr addr); -void pim_if_dr_election(struct interface *ifp); +int pim_if_dr_election(struct interface *ifp); #endif /* PIM_NEIGHBOR_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index bcace95c9..e31e2d6e6 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -31,6 +31,7 @@ #include "pim_cmd.h" #include "pim_str.h" #include "pim_ssmpingd.h" +#include "pim_pim.h" int pim_debug_config_write(struct vty *vty) { @@ -134,6 +135,13 @@ int pim_interface_config_write(struct vty *vty) ++writes; } + /* IF ip pim drpriority */ + if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { + vty_out(vty, " ip pim drpriority %d%s", pim_ifp->pim_dr_priority, + VTY_NEWLINE); + ++writes; + } + /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); From 76240f11e640824438605012a8e44c968bc9e5b0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 18 Jun 2015 17:01:34 -0700 Subject: [PATCH 0772/1342] pimd: Fix first DR Election The function pim_neighbor_new caused the dr election before the addition of the neighbor to the pim_ifp->pim_neighbor_list, in pim_neighbor_add, which is needed to properly elect the correct DR. Move the dr_election and hello trigger till after the addition to the list. Signed-off-by: Donald Sharp --- pimd/pim_neighbor.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index eaf36df35..72a35382f 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -347,26 +347,6 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, ++pim_ifp->pim_dr_num_nondrpri_neighbors; } - /* - RFC 4601: 4.3.2. DR Election - - A router's idea of the current DR on an interface can change when a - PIM Hello message is received, when a neighbor times out, or when a - router's own DR Priority changes. - */ - pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election... - - /* - RFC 4601: 4.3.1. Sending Hello Messages - - To allow new or rebooting routers to learn of PIM neighbors quickly, - when a Hello message is received from a new neighbor, or a Hello - message with a new GenID is received from an existing neighbor, a - new Hello message should be sent on this interface after a - randomized delay between 0 and Triggered_Hello_Delay. - */ - pim_hello_restart_triggered(neigh->interface); - return neigh; } @@ -453,6 +433,26 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp, listnode_add(pim_ifp->pim_neighbor_list, neigh); + /* + RFC 4601: 4.3.2. DR Election + + A router's idea of the current DR on an interface can change when a + PIM Hello message is received, when a neighbor times out, or when a + router's own DR Priority changes. + */ + pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election... + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + To allow new or rebooting routers to learn of PIM neighbors quickly, + when a Hello message is received from a new neighbor, or a Hello + message with a new GenID is received from an existing neighbor, a + new Hello message should be sent on this interface after a + randomized delay between 0 and Triggered_Hello_Delay. + */ + pim_hello_restart_triggered(neigh->interface); + return neigh; } From 73de55a53c78d572f63d45115681567a4c0cef65 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 16 Jun 2015 13:19:56 -0700 Subject: [PATCH 0773/1342] pimd: Stop DR election on every hello The DR election is occurring on every hello received. This is because the hello receive packet returns a 0 for any successfully received packet. PIMD then looked at the 0 returned and did a DR election. Code was inspected for the cases where DR should happen: (A) Interface ip address change (B) DR priority in hello packet changes (C) Received a new neighbor on an interface (D) Neighbor timer pops. Each of these initiate a DR election in the code currently. Testing was initiated on a pim network: tor-11# show ip pim designated-router NonPri: Number of neighbors missing DR Priority hello option Interface Address DR Uptime Elections Changes NonPri br1 20.0.15.1 20.0.15.1 00:08:16 1 1 0 swp1 169.254.0.10 169.254.0.10 00:08:16 2 1 0 swp2 169.254.0.26 169.254.0.26 00:08:16 2 1 0 tor-11# As you can see Elections == 2. This is because pimd performs an election on (A) and (C) above. I see no need to modify (A) to check if we have any knowledge of the interface before this call. Signed-off-by: Donald Sharp --- pimd/pim_pim.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 409972d4b..7dcb50199 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -211,9 +211,6 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); - if (!result) { - pim_if_dr_election(ifp); /* PIM Hello message is received */ - } return result; } From a031c4dd72514232296e9a570c3d701f5f33ad63 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jul 2015 13:22:49 -0400 Subject: [PATCH 0774/1342] pimd: Ensure new generation_id is different from previous The RFC states that an interfaces generation_id must be changed if it experiences an if down. From 4.3.1: The GenID option contains a randomly generated 32-bit value that is regenerated each time PIM forwarding is started or restarted on the interface, including when the router itself restarts. Since we are only grabbing a new generation_id without comparing it to the previous generation_id, it is possible that random can generate the exact same number. Signed-off-by: Donald Sharp --- pimd/pim_pim.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 7dcb50199..41c26a888 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -698,6 +698,7 @@ int pim_sock_add(struct interface *ifp) { struct pim_interface *pim_ifp; struct in_addr ifaddr; + uint32_t old_genid; pim_ifp = ifp->info; zassert(pim_ifp); @@ -720,7 +721,18 @@ int pim_sock_add(struct interface *ifp) pim_ifp->t_pim_sock_read = 0; pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); - pim_ifp->pim_generation_id = random(); + /* + * Just ensure that the new generation id + * actually chooses something different. + * Actually ran across a case where this + * happened, pre-switch to random(). + * While this is unlikely to happen now + * let's make sure it doesn't. + */ + old_genid = pim_ifp->pim_generation_id; + + while (old_genid == pim_ifp->pim_generation_id) + pim_ifp->pim_generation_id = random(); zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name, ifp->ifindex); From d2c6da209cec42c05941eff52d88f0ed7eabad48 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jul 2015 09:53:59 -0400 Subject: [PATCH 0775/1342] pimd: Change ioctl call failure from vty_out to zlog_warn The command 'show ip multicast' when run, iterates over all interfaces on the router, if you do not have pim configured on that interface it would generate an error message: Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut br1 20.0.15.1 7 7 0 0 0 0 swp1 169.254.0.10 3 3 0 0 0 0 swp2 169.254.0.26 4 4 0 0 0 0 ioctl(SIOCGETVIFCNT=35296) failure for interface swp3 vif_index=-1: errno=22: Invalid argument ioctl(SIOCGETVIFCNT=35296) failure for interface swp4 vif_index=-1: errno=22: Invalid argument This fixes the issue to display this instead: Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut br1 20.0.15.1 7 7 0 0 0 0 swp1 169.254.0.10 3 3 0 0 0 0 swp2 169.254.0.26 4 4 0 0 0 0 swp3 0.0.0.0 5 -1 0 0 0 0 swp4 0.0.0.0 6 -1 0 0 0 0 Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 9833411da..336445403 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2070,16 +2070,13 @@ static void show_multicast_interfaces(struct vty *vty) vreq.vifi = pim_ifp->mroute_vif_index; if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) { - int e = errno; - vty_out(vty, - "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s%s", - (unsigned long)SIOCGETVIFCNT, - ifp->name, - pim_ifp->mroute_vif_index, - e, - safe_strerror(e), - VTY_NEWLINE); - continue; + zlog_warn("ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s%s", + (unsigned long)SIOCGETVIFCNT, + ifp->name, + pim_ifp->mroute_vif_index, + errno, + safe_strerror(errno), + VTY_NEWLINE); } ifaddr = pim_ifp->primary_address; From 22e0224d4148e0e4fd5952020fd6ae74efd1bf93 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 21 Aug 2015 19:35:27 -0400 Subject: [PATCH 0776/1342] pimd: Create ability to modify hell and hold timers per interface Create new per interface command: 'ip pim hello <1-180> {<1-180>}' The first number is the Hello Timer for this interface The second number is the Hold Timer to pass to neighbors on this interface. The second number is optional. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++- pimd/pim_cmd.h | 3 +++ pimd/pim_vty.c | 8 ++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 336445403..55545c15b 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3169,7 +3169,7 @@ DEFUN (interface_no_ip_pim_drprio, pim_ifp = ifp->info; if (!pim_ifp) { - vty_out(vty, "Pim no enabled on this interface%s", VTY_NEWLINE); + vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE); return CMD_WARNING; } @@ -3445,6 +3445,70 @@ DEFUN (interface_no_ip_mroute_source, return CMD_SUCCESS; } +DEFUN (interface_ip_pim_hello, + interface_ip_pim_hello_cmd, + "ip pim hello <1-180>", + IP_STR + PIM_STR + IFACE_PIM_HELLO_STR + IFACE_PIM_HELLO_TIME_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + pim_ifp->pim_hello_period = strtol(argv[0], NULL, 10); + + if (argc == 2) + pim_ifp->pim_default_holdtime = strtol(argv[1], NULL, 10); + + return CMD_SUCCESS; +} + +ALIAS (interface_ip_pim_hello, + interface_ip_pim_hello_hold_cmd, + "ip pim hello <1-180> <1-180>", + IP_STR + PIM_STR + IFACE_PIM_HELLO_STR + IFACE_PIM_HELLO_TIME_STR + IFACE_PIM_HELLO_HOLD_STR) + + +DEFUN (interface_no_ip_pim_hello, + interface_no_ip_pim_hello_cmd, + "no ip pim hello {<1-180> <1-180>}", + NO_STR + IP_STR + PIM_STR + IFACE_PIM_HELLO_STR + IFACE_PIM_HELLO_TIME_STR + IFACE_PIM_HELLO_HOLD_STR) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + ifp = vty->index; + pim_ifp = ifp->info; + + if (!pim_ifp) { + vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; + pim_ifp->pim_default_holdtime = -1; + + return CMD_SUCCESS; +} + DEFUN (debug_igmp, debug_igmp_cmd, "debug igmp", @@ -4746,6 +4810,9 @@ void pim_cmd_init() install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_drprio_cmd); install_element (INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd); + install_element (INTERFACE_NODE, &interface_ip_pim_hello_cmd); + install_element (INTERFACE_NODE, &interface_ip_pim_hello_hold_cmd); + install_element (INTERFACE_NODE, &interface_no_ip_pim_hello_cmd); // Static mroutes NEB install_element (INTERFACE_NODE, &interface_ip_mroute_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index 25e244462..a1cb58161 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -30,6 +30,9 @@ #define CONF_SSMPINGD_STR "Enable ssmpingd operation\n" #define SHOW_SSMPINGD_STR "ssmpingd operation\n" #define IFACE_PIM_STR "Enable PIM SSM operation\n" +#define IFACE_PIM_HELLO_STR "Hello Interval\n" +#define IFACE_PIM_HELLO_TIME_STR "Time in seconds for Hello Interval\n" +#define IFACE_PIM_HELLO_HOLD_STR "Time in seconds for Hold Interval\n" #define IFACE_IGMP_STR "Enable IGMP operation\n" #define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "IGMP max query response value (seconds)\n" diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index e31e2d6e6..512c0e672 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -142,6 +142,14 @@ int pim_interface_config_write(struct vty *vty) ++writes; } + /* IF ip pim hello */ + if (pim_ifp->pim_hello_period != PIM_DEFAULT_HELLO_PERIOD) { + vty_out(vty, " ip pim hello %d", pim_ifp->pim_hello_period); + if (pim_ifp->pim_default_holdtime != -1) + vty_out(vty, " %d", pim_ifp->pim_default_holdtime); + vty_out(vty, "%s", VTY_NEWLINE); + } + /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); From 06cc655c0345d610eb946bd41968caa03dc118ed Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Thu, 2 Jul 2015 15:42:58 -0700 Subject: [PATCH 0777/1342] isisd: Add new adjacency to LSP neighbor list isis_pdu.c : New adjacency did not always get added to LSP neighbor list. The adjacencies that were created once minimum time allowed before LSP retransmission had surpassed, instantly got their LSP regenerated, but the adjacency circuit type was not set to IIH PDU circuit type before the LSP was regenerated , hence didn't pass the check for adjacency circuit type in lsp_build(), and the adjacency was not added to neighbor list. When a new adjacency is up, to build LSP with neighbor entry corresponding to the adjacency, set adjacency circuit type to circuit type from hello PDU header before new LSP is regenerated/built. This will result in the new adjacency entry getting added to the LSP neighbor list TLV. Signed-off-by: Amritha Nambiar --- isisd/isis_pdu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 7c04f44a1..c50b53ffe 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -601,6 +601,13 @@ process_p2p_hello (struct isis_circuit *circuit) adj->level = hdr->circuit_t; } circuit->u.p2p.neighbor = adj; + /* Build lsp with the new neighbor entry when a new + * adjacency is formed. Set adjacency circuit type to + * IIH PDU header circuit type before lsp is regenerated + * when an adjacency is up. This will result in the new + * adjacency entry getting added to the lsp tlv neighbor list. + */ + adj->circuit_t = hdr->circuit_t; isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } @@ -886,7 +893,6 @@ process_p2p_hello (struct isis_circuit *circuit) break; } - adj->circuit_t = hdr->circuit_t; if (isis->debugs & DEBUG_ADJ_PACKETS) { From c8ee940cc695cbcf9c0156ee6f72730f1fff9814 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Mon, 24 Aug 2015 16:40:14 -0700 Subject: [PATCH 0778/1342] isisd: Attached-bit in LSP header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set/reset attached-bit in LSP header: This patch provides support for set/reset attached_bit in the LSP header. In IS-IS networks, routing inter-area traffic from L1 areas is accomplished by sending the traffic to the nearest L1/L2 router. A L1/L2 router identifies itself by setting an attach-bit (ATT-bit) in its (LSP). The ATT-bit in LSP can be changed using the set-attached-bit or no-set-attached-bit commands (similar to ‘set-overload-bit’ and 'no set-overload-bit’) using telnet terminal in router configuration mode. Steps: enable configure terminal router isis set-attached-bit V2: Removed looping through area list as this well set the bit for all areas in the list. This implementation now looks exactly like the current overload bit implementation. Signed-off-by: Amritha Nambiar --- isisd/isis_lsp.c | 33 ++++++++++++++++++++++----------- isisd/isisd.c | 36 ++++++++++++++++++++++++++++++++++++ isisd/isisd.h | 2 ++ 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 88593de70..0b1dac181 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -442,7 +442,7 @@ lsp_seqnum_update (struct isis_lsp *lsp0) } static u_int8_t -lsp_bits_generate (int level, int overload_bit) +lsp_bits_generate (int level, int overload_bit, int attached_bit) { u_int8_t lsp_bits = 0; if (level == IS_LEVEL_1) @@ -451,6 +451,8 @@ lsp_bits_generate (int level, int overload_bit) lsp_bits = IS_LEVEL_1_AND_2; if (overload_bit) lsp_bits |= overload_bit; + if (attached_bit) + lsp_bits |= attached_bit; return lsp_bits; } @@ -1135,7 +1137,8 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, return lsp; } lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, - lsp_bits_generate (level, area->overload_bit), 0, level); + lsp_bits_generate (level, area->overload_bit, + area->attached_bit), 0, level); lsp->area = area; lsp->own_lsp = 1; lsp_insert (lsp, area->lspdb[level - 1]); @@ -1589,7 +1592,8 @@ lsp_generate (struct isis_area *area, int level) } rem_lifetime = lsp_rem_lifetime (area, level); newlsp = lsp_new (lspid, rem_lifetime, seq_num, - area->is_type | area->overload_bit, 0, level); + area->is_type | area->overload_bit | area->attached_bit, + 0, level); newlsp->area = area; newlsp->own_lsp = 1; @@ -1656,7 +1660,8 @@ lsp_regenerate (struct isis_area *area, int level) lsp_clear_data (lsp); lsp_build (lsp, area); - lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit); + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit, + area->attached_bit); rem_lifetime = lsp_rem_lifetime (area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_seqnum_update (lsp); @@ -1666,7 +1671,8 @@ lsp_regenerate (struct isis_area *area, int level) for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag)) { frag->lsp_header->lsp_bits = lsp_bits_generate (level, - area->overload_bit); + area->overload_bit, + area->attached_bit); /* Set the lifetime values of all the fragments to the same value, * so that no fragment expires before the lsp is refreshed. */ @@ -1816,7 +1822,8 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0, + circuit->area->attached_bit); /* * add self to IS neighbours @@ -1946,7 +1953,9 @@ lsp_generate_pseudo (struct isis_circuit *circuit, int level) rem_lifetime = lsp_rem_lifetime (circuit->area, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp = lsp_new (lsp_id, rem_lifetime, 1, circuit->area->is_type, 0, level); + lsp = lsp_new (lsp_id, rem_lifetime, 1, + circuit->area->is_type | circuit->area->attached_bit, + 0, level); lsp->area = circuit->area; lsp_build_pseudo (lsp, circuit, level); @@ -2012,7 +2021,8 @@ lsp_regenerate_pseudo (struct isis_circuit *circuit, int level) lsp_build_pseudo (lsp, circuit, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0, + circuit->area->attached_bit); rem_lifetime = lsp_rem_lifetime (circuit->area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_inc_seqnum (lsp, 0); @@ -2416,7 +2426,8 @@ top_lsp_refresh (struct thread *thread) IS_LEVEL_1); lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level, - lsp->area->overload_bit); + lsp->area->overload_bit, + lsp->area->attached_bit); rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); @@ -2455,8 +2466,8 @@ generate_topology_lsps (struct isis_area *area) lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF); rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1); - lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit, - 0, 1); + lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit + | area->attached_bit, 0, 1); if (!lsp) return; lsp->area = area; diff --git a/isisd/isisd.c b/isisd/isisd.c index 898dfd23d..20b8e5012 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2170,6 +2170,39 @@ DEFUN (no_set_overload_bit, return CMD_SUCCESS; } +DEFUN (set_attached_bit, + set_attached_bit_cmd, + "set-attached-bit", + "Set attached bit to identify as L1/L2 router for inter-area traffic\n" + "Set attached bit\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->attached_bit = LSPBIT_ATT; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_set_attached_bit, + no_set_attached_bit_cmd, + "no set-attached-bit", + "Reset attached bit\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->attached_bit = 0; + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + DEFUN (dynamic_hostname, dynamic_hostname_cmd, "hostname dynamic", @@ -3245,6 +3278,9 @@ isis_init () install_element (ISIS_NODE, &set_overload_bit_cmd); install_element (ISIS_NODE, &no_set_overload_bit_cmd); + install_element (ISIS_NODE, &set_attached_bit_cmd); + install_element (ISIS_NODE, &no_set_attached_bit_cmd); + install_element (ISIS_NODE, &dynamic_hostname_cmd); install_element (ISIS_NODE, &no_dynamic_hostname_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 5db485f47..838a08bd8 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -116,6 +116,8 @@ struct isis_area char is_type; /* level-1 level-1-2 or level-2-only */ /* are we overloaded? */ char overload_bit; + /* L1/L2 router identifier for inter-area traffic */ + char attached_bit; u_int16_t lsp_refresh[ISIS_LEVELS]; /* minimum time allowed before lsp retransmission */ u_int16_t lsp_gen_interval[ISIS_LEVELS]; From 52c0bc739b1184621525e64720b944268d6b0eeb Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 20 Aug 2015 21:30:17 +0100 Subject: [PATCH 0779/1342] build: Remove the old PIC/PIE patch, let libtool sort it out * Remove the old change from '08 to add in PIE arguments at automake level. Versions of libtool since then know how to deal with -fpie and do the right thing according to whether its building shared or executable objects. So just pass '-fpie' as CFLAG and let libtool do its thing. --- bgpd/Makefile.am | 3 +-- configure.ac | 26 ++------------------------ isisd/Makefile.am | 3 +-- ospf6d/Makefile.am | 3 +-- ospfclient/Makefile.am | 5 ++--- pimd/Makefile.am | 3 +-- ripd/Makefile.am | 3 +-- ripngd/Makefile.am | 3 +-- tests/Makefile.am | 3 --- vtysh/Makefile.am | 3 +-- watchquagga/Makefile.am | 3 +-- zebra/Makefile.am | 3 +-- 12 files changed, 13 insertions(+), 48 deletions(-) diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 92fa10cd4..4659ac681 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -4,8 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libbgp.a sbin_PROGRAMS = bgpd diff --git a/configure.ac b/configure.ac index 6e92bd150..6864a29ca 100755 --- a/configure.ac +++ b/configure.ac @@ -144,6 +144,7 @@ if test "x${cflags_specified}" = "x" ; then AC_C_FLAG([-Os], [ AC_C_FLAG([-O2]) ]) + AC_C_FLAG([-fpie]) AC_C_FLAG([-fno-omit-frame-pointer]) AC_C_FLAG([-Wall]) AC_C_FLAG([-Wextra]) @@ -212,7 +213,7 @@ AC_GNU_SOURCE dnl ------- dnl libtool dnl ------- -AC_PROG_LIBTOOL +LT_INIT dnl ---------------------- dnl Packages configuration @@ -1465,29 +1466,6 @@ dnl ---------- CONFDATE=`date '+%Y%m%d'` AC_SUBST(CONFDATE) -dnl Conditionally enable PIE support for GNU toolchains. -AC_ARG_ENABLE(pie, AS_HELP_STRING([--disable-pie], [Do not build tools as a Position Independent Executables])) -if test "$enable_pie" != "no"; then - AC_CACHE_CHECK([whether $CC accepts PIE flags], [ap_cv_cc_pie], [ - save_CFLAGS=$CFLAGS - save_LDFLAGS=$LDFLAGS - CFLAGS="$CFLAGS -fPIE" - LDFLAGS="$LDFLAGS -pie" - AC_LINK_IFELSE([AC_LANG_SOURCE([[static int foo[30000]; int main () { return 0; }]])], - [ap_cv_cc_pie=yes], [ap_cv_cc_pie=no] - ) - CFLAGS=$save_CFLAGS - LDFLAGS=$save_LDFLAGS - ]) - if test "$ap_cv_cc_pie" = "yes"; then - PICFLAGS="-fPIE" - PILDFLAGS="-pie" - fi -fi - -AC_SUBST(PICFLAGS) -AC_SUBST(PILDFLAGS) - dnl ------- dnl DejaGNU dnl ------- diff --git a/isisd/Makefile.am b/isisd/Makefile.am index 4e67b228f..ff6ce3caa 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -6,8 +6,7 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libisis.a sbin_PROGRAMS = isisd diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index cbd850f33..75f225727 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -4,8 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libospf6.a sbin_PROGRAMS = ospf6d diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index c4f0da834..8a3ad2162 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -22,6 +22,5 @@ ospfclient_SOURCES = \ ospfclient_LDADD = libospfapiclient.la \ ../ospfd/libospf.la ../lib/libzebra.la @LIBCAP@ -ospfclient_CFLAGS = $(AM_CFLAGS) $(PICFLAGS) -ospfclient_LDFLAGS = $(AM_LDFLAGS) $(PILDFLAGS) - +ospfclient_CFLAGS = $(AM_CFLAGS) +ospfclient_LDFLAGS = $(AM_LDFLAGS) diff --git a/pimd/Makefile.am b/pimd/Makefile.am index bf8a158f3..f57c4c254 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -39,8 +39,7 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libpim.a sbin_PROGRAMS = pimd diff --git a/ripd/Makefile.am b/ripd/Makefile.am index 34c5f183a..571a4993d 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -4,8 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) noinst_LIBRARIES = librip.a sbin_PROGRAMS = ripd diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index 0487459bb..df0f7d377 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -4,8 +4,7 @@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libripng.a sbin_PROGRAMS = ripngd diff --git a/tests/Makefile.am b/tests/Makefile.am index 6dfab5371..16c9e4c3d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,9 +18,6 @@ EXTRA_DIST = \ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" -AM_CFLAGS = $(PICFLAGS) -AM_LDFLAGS = $(PILDFLAGS) - if BGPD TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath DEJATOOL += bgpd diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 850b505e5..d34773522 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -5,8 +5,7 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" LIBS = @LIBS@ @CURSES@ @LIBPAM@ -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) bin_PROGRAMS = vtysh diff --git a/watchquagga/Makefile.am b/watchquagga/Makefile.am index 939ecd710..1f05f26ce 100644 --- a/watchquagga/Makefile.am +++ b/watchquagga/Makefile.am @@ -3,8 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) sbin_PROGRAMS = watchquagga diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 7dcbd6607..01779c9b3 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -20,8 +20,7 @@ if HAVE_NETLINK othersrc = zebra_fpm_netlink.c endif -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) +AM_CFLAGS = $(WERROR) sbin_PROGRAMS = zebra From a29c8a23a35b3f94c6aea5b3b7578b5dbf81ad71 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 21 Sep 2015 10:26:02 +0100 Subject: [PATCH 0780/1342] Revert "ospfd: Use route_node_lookup() instaed of route_node_get()" This reverts commit c9b07581e0df8867499e97e08b382b6d3cc9c4c4. See: http://patchwork.quagga.net/patch/410/ --- ospfd/ospf_abr.c | 4 +--- ospfd/ospf_snmp.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 5c308092d..e172e53cd 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -133,9 +133,7 @@ ospf_area_range_lookup_next (struct ospf_area *area, rn = route_top (area->ranges); else { - rn = route_node_lookup (area->ranges, (struct prefix *) &p); - if (!rn) - return NULL; + rn = route_node_get (area->ranges, (struct prefix *) &p); rn = route_next (rn); } diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 78435de56..604766d82 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1994,9 +1994,7 @@ ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor, rn = route_top (ospf_snmp_vl_table); else { - rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); - if (!rn) - return NULL; + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); rn = route_next (rn); } From 794c4735f81289d9fc603b5fd5e4a5d39dbb5ca5 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 16 Sep 2015 09:42:36 +0200 Subject: [PATCH 0781/1342] bgpd/pimd: fix zAPI parsing Commit c99f3481a598 has changed the API. Now, the vrfid has been added in the header, thus we must read it before parsing the rest of the message. To ease code maintenance, let's add a new function to read a zAPI header. Fixes: c99f3481a598 ("*: add VRF ID in the API message header") Reported-by: Martin Winter Signed-off-by: Nicolas Dichtel Acked-by: Donald Sharp Tested-by: Martin Winter --- bgpd/bgp_nexthop.c | 68 ++++++++++++++++++---------------------------- lib/zclient.c | 19 +++++++++++++ lib/zclient.h | 3 ++ pimd/pim_zlookup.c | 51 ++++++++++++++++------------------ 4 files changed, 73 insertions(+), 68 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 7336793e0..c74bebad8 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -789,8 +789,9 @@ zlookup_read (void) uint16_t length; u_char marker; u_char version; - uint16_t command __attribute__((unused)); - int nbytes __attribute__((unused)); + uint16_t vrf_id; + uint16_t command; + int err; struct in_addr raddr __attribute__((unused)); uint32_t metric; int i; @@ -801,14 +802,13 @@ zlookup_read (void) s = zlookup->ibuf; stream_reset (s); - /* nbytes not being checked */ - nbytes = stream_read (s, zlookup->sock, 2); - length = stream_getw (s); - - nbytes = stream_read (s, zlookup->sock, length - 2); - marker = stream_getc (s); - version = stream_getc (s); - + err = zclient_read_header (s, zlookup->sock, &length, &marker, &version, + &vrf_id, &command); + if (err < 0) + { + zlog_err("%s: zserv_read_header() failed", __func__); + return NULL; + } if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", @@ -816,9 +816,6 @@ zlookup_read (void) return NULL; } - /* XXX: not checking command */ - command = stream_getw (s); - /* XXX: not doing anything with raddr */ raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); @@ -902,11 +899,11 @@ static struct bgp_nexthop_cache * zlookup_read_ipv6 (void) { struct stream *s; - uint16_t length; + uint16_t length, vrf_id, cmd; u_char version, marker; struct in6_addr raddr; uint32_t metric; - int i; + int i, err; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; @@ -914,14 +911,13 @@ zlookup_read_ipv6 (void) s = zlookup->ibuf; stream_reset (s); - /* XXX: ignoring nbytes, see also zread_lookup */ - stream_read (s, zlookup->sock, 2); - length = stream_getw (s); - - stream_read (s, zlookup->sock, length - 2); - marker = stream_getc (s); - version = stream_getc (s); - + err = zclient_read_header (s, zlookup->sock, &length, &marker, &version, + &vrf_id, &cmd); + if (err < 0) + { + zlog_err("%s: zserv_read_header() failed", __func__); + return NULL; + } if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", @@ -929,9 +925,6 @@ zlookup_read_ipv6 (void) return NULL; } - /* XXX: ignoring command */ - stream_getw (s); - /* XXX: not actually doing anything with raddr */ stream_get (&raddr, s, 16); @@ -1018,9 +1011,8 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, { struct stream *s; int ret; - u_int16_t length, command __attribute__((unused)); + u_int16_t length, vrf_id, command; u_char version, marker; - int nbytes __attribute__((unused)); struct in_addr addr __attribute__((unused)); struct in_addr nexthop; u_int32_t metric = 0; @@ -1066,16 +1058,13 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, /* Get result. */ stream_reset (s); - /* Fetch length. */ - /* XXX: not using nbytes */ - nbytes = stream_read (s, zlookup->sock, 2); - length = stream_getw (s); - - /* Fetch whole data. */ - nbytes = stream_read (s, zlookup->sock, length - 2); - marker = stream_getc (s); - version = stream_getc (s); - + ret = zclient_read_header (s, zlookup->sock, &length, &marker, &version, + &vrf_id, &command); + if (ret < 0) + { + zlog_err("%s: zserv_read_header() failed", __func__); + return 0; + } if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", @@ -1083,9 +1072,6 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, return 0; } - /* XXX: not using command */ - command = stream_getw (s); - /* XXX: not using addr */ addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); diff --git a/lib/zclient.c b/lib/zclient.c index 8e443e28d..a09563248 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -302,6 +302,25 @@ zclient_create_header (struct stream *s, uint16_t command, vrf_id_t vrf_id) stream_putw (s, command); } +int +zclient_read_header (struct stream *s, int sock, u_int16_t *size, u_char *marker, + u_char *version, u_int16_t *vrf_id, u_int16_t *cmd) +{ + if (stream_read (s, sock, ZEBRA_HEADER_SIZE) != ZEBRA_HEADER_SIZE) + return -1; + + *size = stream_getw (s) - ZEBRA_HEADER_SIZE; + *marker = stream_getc (s); + *version = stream_getc (s); + *vrf_id = stream_getw (s); + *cmd = stream_getw (s); + + if (*size && stream_read (s, sock, *size) != *size) + return -1; + + return 0; +} + /* Send simple Zebra message. */ static int zebra_message_send (struct zclient *zclient, int command, vrf_id_t vrf_id) diff --git a/lib/zclient.h b/lib/zclient.h index 19b4f0ead..3490b3209 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -163,6 +163,9 @@ extern int zclient_send_message(struct zclient *); /* create header for command, length to be filled in by user later */ extern void zclient_create_header (struct stream *, uint16_t, vrf_id_t); +extern int zclient_read_header (struct stream *s, int sock, u_int16_t *size, + u_char *marker, u_char *version, + u_int16_t *vrf_id, u_int16_t *cmd); extern struct interface *zebra_interface_add_read (struct stream *, vrf_id_t); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 60003670c..fae8f81ca 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -149,17 +149,18 @@ static int zclient_read_nexthop(struct zclient *zlookup, { int num_ifindex = 0; struct stream *s; - const uint16_t MIN_LEN = 14; /* getc=1 getc=1 getw=2 getipv4=4 getc=1 getl=4 getc=1 */ - uint16_t length, len; + const uint16_t MIN_LEN = 10; /* getipv4=4 getc=1 getl=4 getc=1 */ + uint16_t length; u_char marker; u_char version; + uint16_t vrf_id; uint16_t command; int nbytes; struct in_addr raddr; uint8_t distance; uint32_t metric; int nexthop_num; - int i; + int i, err; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; @@ -172,41 +173,37 @@ static int zclient_read_nexthop(struct zclient *zlookup, s = zlookup->ibuf; stream_reset(s); - nbytes = stream_read(s, zlookup->sock, 2); - if (nbytes < 2) { - zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d", - __FILE__, __PRETTY_FUNCTION__, nbytes); + err = zclient_read_header (s, zlookup->sock, &length, &marker, &version, + &vrf_id, &command); + if (err < 0) { + zlog_err("%s %s: zclient_read_header() failed", + __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } - length = stream_getw(s); - - len = length - 2; - if (len < MIN_LEN) { + if (length < MIN_LEN) { zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", - __FILE__, __PRETTY_FUNCTION__, len, MIN_LEN); + __FILE__, __PRETTY_FUNCTION__, length, MIN_LEN); zclient_lookup_failed(zlookup); return -2; } - - nbytes = stream_read(s, zlookup->sock, len); - if (nbytes < (length - 2)) { + + nbytes = stream_read(s, zlookup->sock, length); + if (nbytes < length) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d", - __FILE__, __PRETTY_FUNCTION__, nbytes, len); + __FILE__, __PRETTY_FUNCTION__, nbytes, length); zclient_lookup_failed(zlookup); return -3; } - marker = stream_getc(s); - version = stream_getc(s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); + zclient_lookup_failed(zlookup); return -4; } - command = stream_getw(s); if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); @@ -236,19 +233,19 @@ static int zclient_read_nexthop(struct zclient *zlookup, return -6; } - len -= MIN_LEN; + length -= MIN_LEN; for (i = 0; i < nexthop_num; ++i) { enum nexthop_types_t nexthop_type; - if (len < 1) { + if (length < 1) { zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d", - __func__, zlookup->sock, len); + __func__, zlookup->sock, length); return -7; } nexthop_type = stream_getc(s); - --len; + --length; switch (nexthop_type) { case ZEBRA_NEXTHOP_IFINDEX: @@ -263,13 +260,13 @@ static int zclient_read_nexthop(struct zclient *zlookup, return num_ifindex; } if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { - if (len < 4) { + if (length < 4) { zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d", - __func__, zlookup->sock, len); + __func__, zlookup->sock, length); return -8; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); - len -= 4; + length -= 4; } else { nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY; @@ -289,7 +286,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, return num_ifindex; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); - len -= 4; + length -= 4; nexthop_tab[num_ifindex].ifindex = 0; nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; From c920e510d09c6c4ab63a3da5375009442a950f82 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 8 Sep 2015 15:31:45 +0100 Subject: [PATCH 0782/1342] ospfd: Fix bug in 94266fa822ba, nbr_self rebuild didn't add valid nbr_self * 94266fa822ba "ospfd: Self nbrs needs to be rebuilt when router ID changes." deleted the nbr_self, and added it back, but ospf_nbr_add_self doesn't actually create the nbr_self - it assumes it's already there. Leading to use after free and crashes after a router-id change. * ospfd/ospf_neighbor.{c,h}: (ospf_nbr_self_reset) Little helper to reset the nbr_self correctly. * ospf_interface.c: (ospf_if_cleanup) moved code to ospf_nbr_self_reset * ospfd.c: (ospf_router_id_update) Use ospf_nbr_self_reset instead of doing the reset badly, fixing 94266fa822ba. --- ospfd/ospf_interface.c | 4 +--- ospfd/ospf_neighbor.c | 9 +++++++++ ospfd/ospf_neighbor.h | 1 + ospfd/ospfd.c | 3 +-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 07c3fe35e..af4f0a608 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -295,9 +295,7 @@ ospf_if_cleanup (struct ospf_interface *oi) ospf_ls_upd_queue_empty (oi); /* Reset pseudo neighbor. */ - ospf_nbr_delete (oi->nbr_self); - oi->nbr_self = ospf_nbr_new (oi); - ospf_nbr_add_self (oi); + ospf_nbr_self_reset (oi); } void diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 967ca15db..c3bdf9929 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -202,6 +202,15 @@ ospf_nbr_bidirectional (struct in_addr *router_id, return 0; } +/* reset nbr_self */ +void +ospf_nbr_self_reset (struct ospf_interface *oi) +{ + ospf_nbr_delete (oi->nbr_self); + oi->nbr_self = ospf_nbr_new (oi); + ospf_nbr_add_self (oi); +} + /* Add self to nbr list. */ void ospf_nbr_add_self (struct ospf_interface *oi) diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 25f135242..822c2024c 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -99,6 +99,7 @@ extern struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); extern void ospf_nbr_free (struct ospf_neighbor *); extern void ospf_nbr_delete (struct ospf_neighbor *); extern int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); +extern void ospf_nbr_self_reset (struct ospf_interface *); extern void ospf_nbr_add_self (struct ospf_interface *); extern int ospf_nbr_count (struct ospf_interface *, int); #ifdef HAVE_OPAQUE_LSA diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 019a22b70..1a549c3aa 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -118,8 +118,7 @@ ospf_router_id_update (struct ospf *ospf) * oi->nbr_self->router_id = router_id for * !(virtual | ptop) links */ - ospf_nbr_delete(oi->nbr_self); - ospf_nbr_add_self(oi); + ospf_nbr_self_reset (oi); } /* If AS-external-LSA is queued, then flush those LSAs. */ From 2ef762ed9b88e5745012c5829f8f526c95443ddf Mon Sep 17 00:00:00 2001 From: Michael Rossberg Date: Mon, 27 Jul 2015 07:56:25 +0200 Subject: [PATCH 0783/1342] ospfd: Fast OSPF convergence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When considering small networks that have extreme requirements on availability and thus convergence delay, the timers given in the OSPF RFC seem a little “conservativeâ€, i.e., the delay between accepted LSAs and the rate at which LSAs are sent. Cisco introduced two commands 'timers throttle lsa all’ and 'timers lsa arrival’, which allow operators to tune these parameters. I have been writing a patch to also support 'timers lsa arrival’ fully and ‘timers throttle lsa all’ (without the throttling part) also in quagga. --- lib/libospf.h | 4 +- ospfd/ospf_flood.c | 2 +- ospfd/ospf_lsa.c | 15 +++++++- ospfd/ospf_lsa.h | 1 + ospfd/ospf_opaque.c | 26 ++++++------- ospfd/ospf_packet.c | 6 +-- ospfd/ospf_vty.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ ospfd/ospf_zebra.c | 6 +-- ospfd/ospfd.c | 4 ++ ospfd/ospfd.h | 4 ++ 10 files changed, 134 insertions(+), 25 deletions(-) diff --git a/lib/libospf.h b/lib/libospf.h index 2796209d7..e8db5c133 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -39,8 +39,8 @@ #else #define OSPF_LS_REFRESH_TIME 1800 #endif -#define OSPF_MIN_LS_INTERVAL 5 -#define OSPF_MIN_LS_ARRIVAL 1 +#define OSPF_MIN_LS_INTERVAL 5000 /* msec */ +#define OSPF_MIN_LS_ARRIVAL 1000 /* msec */ #define OSPF_LSA_INITIAL_AGE 0 /* useful for debug */ #define OSPF_LSA_MAXAGE 3600 #define OSPF_CHECK_AGE 300 diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 0e42ff54e..df19adff4 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -266,7 +266,7 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, ; /* Accept this LSA for quick LSDB resynchronization. */ } else if (tv_cmp (tv_sub (recent_relative_time (), current->tv_recv), - int2tv (OSPF_MIN_LS_ARRIVAL)) < 0) + msec2tv (ospf->min_ls_arrival)) < 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Flooding]: LSA is received recently."); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index f032601a3..e62a4e7b9 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -107,6 +107,17 @@ int2tv (int a) return ret; } +struct timeval +msec2tv (int a) +{ + struct timeval ret; + + ret.tv_sec = 0; + ret.tv_usec = a * 1000; + + return tv_adjust (ret); +} + struct timeval tv_add (struct timeval a, struct timeval b) { @@ -145,9 +156,9 @@ ospf_lsa_refresh_delay (struct ospf_lsa *lsa) quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); delta = tv_sub (now, lsa->tv_orig); - if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) + if (tv_cmp (delta, msec2tv (OSPF_MIN_LS_INTERVAL)) < 0) { - delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta)); + delay = tv_ceil (tv_sub (msec2tv (OSPF_MIN_LS_INTERVAL), delta)); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Refresh timer delay %d seconds", diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index c71877da4..dd3b91a57 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -237,6 +237,7 @@ extern struct timeval tv_adjust (struct timeval); extern int tv_ceil (struct timeval); extern int tv_floor (struct timeval); extern struct timeval int2tv (int); +extern struct timeval msec2tv (int); extern struct timeval tv_add (struct timeval, struct timeval); extern struct timeval tv_sub (struct timeval, struct timeval); extern int tv_cmp (struct timeval, struct timeval); diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index f584fc71f..64284803d 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1331,10 +1331,10 @@ ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) && oi->t_opaque_lsa_self == NULL) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay); + zlog_debug ("Schedule Type-9 Opaque-LSA origination in %d ms later.", delay); oi->t_opaque_lsa_self = - thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay); - delay += OSPF_MIN_LS_INTERVAL; + thread_add_timer_msec (master, ospf_opaque_type9_lsa_originate, oi, delay); + delay += top->min_ls_interval; } if (! list_isempty (ospf_opaque_type10_funclist) @@ -1347,11 +1347,11 @@ ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) * again and again. */ if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay); + zlog_debug ("Schedule Type-10 Opaque-LSA origination in %d ms later.", delay); area->t_opaque_lsa_self = - thread_add_timer (master, ospf_opaque_type10_lsa_originate, + thread_add_timer_msec (master, ospf_opaque_type10_lsa_originate, area, delay); - delay += OSPF_MIN_LS_INTERVAL; + delay += top->min_ls_interval; } if (! list_isempty (ospf_opaque_type11_funclist) @@ -1364,11 +1364,11 @@ ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) * again and again. */ if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay); + zlog_debug ("Schedule Type-11 Opaque-LSA origination in %d ms later.", delay); top->t_opaque_lsa_self = - thread_add_timer (master, ospf_opaque_type11_lsa_originate, + thread_add_timer_msec (master, ospf_opaque_type11_lsa_originate, top, delay); - delay += OSPF_MIN_LS_INTERVAL; + delay += top->min_ls_interval; } /* @@ -1646,7 +1646,7 @@ ospf_opaque_lsa_refresh (struct ospf_lsa *lsa) #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \ if (!(T)) \ - (T) = thread_add_timer (master, (F), (L), (V)) + (T) = thread_add_timer_msec (master, (F), (L), (V)) static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type); static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t); @@ -1794,11 +1794,11 @@ ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, * it is highly possible that these conditions might not be satisfied * at the time of re-origination function is to be called. */ - delay = OSPF_MIN_LS_INTERVAL; /* XXX */ + delay = top->min_ls_interval; /* XXX */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d" - " sec later: [opaque-type=%u]", + " ms later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); @@ -2024,7 +2024,7 @@ ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) zlog_debug ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self, - ospf_opaque_lsa_refresh_timer, oipi, delay); + ospf_opaque_lsa_refresh_timer, oipi, delay * 1000); out: return; } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index c6cd01844..73111e87b 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1703,7 +1703,7 @@ ospf_upd_list_clean (struct list *lsas) /* OSPF Link State Update message read -- RFC2328 Section 13. */ static void -ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, +ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, struct stream *s, struct ospf_interface *oi, u_int16_t size) { struct ospf_neighbor *nbr; @@ -2046,7 +2046,7 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (tv_cmp (tv_sub (now, current->tv_orig), - int2tv (OSPF_MIN_LS_ARRIVAL)) >= 0) + msec2tv (ospf->min_ls_arrival)) >= 0) /* Trap NSSA type later.*/ ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); DISCARD_LSA (lsa, 8); @@ -2932,7 +2932,7 @@ ospf_read (struct thread *thread) ospf_ls_req (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_UPD: - ospf_ls_upd (iph, ospfh, ibuf, oi, length); + ospf_ls_upd (ospf, iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_ACK: ospf_ls_ack (iph, ospfh, ibuf, oi, length); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 9d04892c7..e5e56319a 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2233,6 +2233,83 @@ ospf_timers_spf_set (struct vty *vty, unsigned int delay, return CMD_SUCCESS; } +DEFUN (ospf_timers_min_ls_interval, + ospf_timers_min_ls_interval_cmd, + "timers throttle lsa all <0-5000>", + "Adjust routing timers\n" + "Throttling adaptive timer\n" + "LSA delay between transmissions\n" + NO_STR + "Delay (msec) between sending LSAs\n") +{ + struct ospf *ospf = vty->index; + unsigned int interval; + + if (argc != 1) + { + vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_GET_INTEGER ("LSA interval", interval, argv[0]); + + ospf->min_ls_interval = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_timers_min_ls_interval, + no_ospf_timers_min_ls_interval_cmd, + "no timers throttle lsa all", + NO_STR + "Adjust routing timers\n" + "Throttling adaptive timer\n" + "LSA delay between transmissions\n") +{ + struct ospf *ospf = vty->index; + ospf->min_ls_interval = OSPF_MIN_LS_INTERVAL; + + return CMD_SUCCESS; +} + +DEFUN (ospf_timers_min_ls_arrival, + ospf_timers_min_ls_arrival_cmd, + "timers lsa arrival <0-1000>", + "Adjust routing timers\n" + "Throttling link state advertisement delays\n" + "OSPF minimum arrival interval delay\n" + "Delay (msec) between accepted LSAs\n") +{ + struct ospf *ospf = vty->index; + unsigned int arrival; + + if (argc != 1) + { + vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_GET_INTEGER_RANGE ("minimum LSA inter-arrival time", arrival, argv[0], 0, 1000); + + ospf->min_ls_arrival = arrival; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_timers_min_ls_arrival, + no_ospf_timers_min_ls_arrival_cmd, + "no timers lsa arrival", + NO_STR + "Adjust routing timers\n" + "Throttling link state advertisement delays\n" + "OSPF minimum arrival interval delay\n") +{ + struct ospf *ospf = vty->index; + ospf->min_ls_arrival = OSPF_MIN_LS_ARRIVAL; + + return CMD_SUCCESS; +} + DEFUN (ospf_timers_throttle_spf, ospf_timers_throttle_spf_cmd, "timers throttle spf <0-600000> <0-600000> <0-600000>", @@ -7289,6 +7366,14 @@ ospf_config_write (struct vty *vty) ospf->ref_bandwidth / 1000, VTY_NEWLINE); } + /* LSA timers */ + if (ospf->min_ls_interval != OSPF_MIN_LS_INTERVAL) + vty_out (vty, " timers throttle lsa all %d%s", + ospf->min_ls_interval, VTY_NEWLINE); + if (ospf->min_ls_arrival != OSPF_MIN_LS_ARRIVAL) + vty_out (vty, " timers lsa arrival %d%s", + ospf->min_ls_arrival, VTY_NEWLINE); + /* SPF timers print. */ if (ospf->spf_delay != OSPF_SPF_DELAY_DEFAULT || ospf->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || @@ -7700,6 +7785,12 @@ ospf_vty_init (void) install_element (OSPF_NODE, &ospf_area_import_list_cmd); install_element (OSPF_NODE, &no_ospf_area_import_list_cmd); + /* LSA timer commands */ + install_element (OSPF_NODE, &ospf_timers_min_ls_interval_cmd); + install_element (OSPF_NODE, &no_ospf_timers_min_ls_interval_cmd); + install_element (OSPF_NODE, &ospf_timers_min_ls_arrival_cmd); + install_element (OSPF_NODE, &no_ospf_timers_min_ls_arrival_cmd); + /* SPF timer commands */ install_element (OSPF_NODE, &ospf_timers_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_spf_cmd); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 27041003f..588f0fb5c 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1007,8 +1007,6 @@ ospf_distribute_list_update_timer (struct thread *thread) return 0; } -#define OSPF_DISTRIBUTE_UPDATE_DELAY 5 - /* Update distribute-list and set timer to apply access-list. */ void ospf_distribute_list_update (struct ospf *ospf, uintptr_t type) @@ -1025,8 +1023,8 @@ ospf_distribute_list_update (struct ospf *ospf, uintptr_t type) /* Set timer. */ ospf->t_distribute_update = - thread_add_timer (master, ospf_distribute_list_update_timer, - (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY); + thread_add_timer_msec (master, ospf_distribute_list_update_timer, + (void *) type, ospf->min_ls_interval); } /* If access-list is updated, apply some check. */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 1a549c3aa..8c7d1c2fe 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -199,6 +199,10 @@ ospf_new (void) new->default_metric = -1; new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; + /* LSA timers */ + new->min_ls_interval = OSPF_MIN_LS_INTERVAL; + new->min_ls_arrival = OSPF_MIN_LS_ARRIVAL; + /* SPF timer value init. */ new->spf_delay = OSPF_SPF_DELAY_DEFAULT; new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 06841b83c..c50e615ff 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -147,6 +147,10 @@ struct ospf #define OSPF_STUB_MAX_METRIC_SUMMARY_COST 0x00ff0000 + /* LSA timers */ + unsigned int min_ls_interval; /* minimum delay between LSAs (in msec) */ + unsigned int min_ls_arrival; /* minimum interarrival time between LSAs (in msec) */ + /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ From b075e8728f650b0850e20fdf8dde467440a24b28 Mon Sep 17 00:00:00 2001 From: "Vystoropskyi, Sergii" Date: Sun, 16 Aug 2015 13:25:36 +0000 Subject: [PATCH 0784/1342] ospfd: Fix for 'no' + 'debug command' does not disable 'debug command' "no debug ospf packet all detail" does not cancel "debug ospf packet all detail" due to the code inconsistency in setting/unsetting debug flags. * ospf_dump.c: added missing flags. Acked-by: Donald Sharp --- ospfd/ospf_dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 2e4e69dc1..ac93f1d3e 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -902,7 +902,7 @@ DEFUN (no_debug_ospf_packet, else if (strncmp (argv[1], "r", 1) == 0) flag = OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; else if (strncmp (argv[1], "d", 1) == 0) - flag = OSPF_DEBUG_DETAIL; + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; } /* detail. */ From b6404390a713144252b62f49a328315d1952c6d8 Mon Sep 17 00:00:00 2001 From: Fernando Soto Date: Mon, 11 May 2015 20:52:00 +0000 Subject: [PATCH 0785/1342] ospfd: trap on state change seems to send incorrect value for ospfNbrState The ospfNbrState in the ospf trap sent from ospfd shows an incorrect state. For example, when the connection goes down, the ospfNbrState in the trap is sent as '8' (full). When the connection is reestablished, the state is sent as '7' (loading). The reason seems to be that the trap is sent from nsm_notice_state_change() before the state is actually updated by calling nsm_change_state(). After applying the attached patch, the traps are sent with nbrState '1' when the connection goes down and '8' when it goes back up. Bugzilla #833 https://bugzilla.quagga.net/show_bug.cgi?id=833 --- ospfd/ospf_nsm.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 0e6814e22..4fecb599b 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -621,23 +621,6 @@ nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event) nbr->last_regress_str = ospf_nsm_event_str [event]; } -#ifdef HAVE_SNMP - /* Terminal state or regression */ - if ((next_state == NSM_Full) - || (next_state == NSM_TwoWay) - || (next_state < nbr->state)) - { - /* ospfVirtNbrStateChange */ - if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) - ospfTrapVirtNbrStateChange(nbr); - /* ospfNbrStateChange trap */ - else - /* To/From FULL, only managed by DR */ - if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) - || (nbr->oi->state == ISM_DR)) - ospfTrapNbrStateChange(nbr); - } -#endif } static void @@ -830,7 +813,34 @@ ospf_nsm_event (struct thread *thread) if (next_state != nbr->state) { nsm_notice_state_change (nbr, next_state, event); +#ifdef HAVE_SNMP + int send_trap_virt = 0; + int send_trap = 0; + /* Terminal state or regression */ + if ((next_state == NSM_Full) + || (next_state == NSM_TwoWay) + || (next_state < nbr->state)) + { + /* ospfVirtNbrStateChange */ + if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) + send_trap_virt = 1; + /* ospfNbrStateChange trap */ + else + /* To/From FULL, only managed by DR */ + if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) + || (nbr->oi->state == ISM_DR)) + send_trap = 1; + } +#endif nsm_change_state (nbr, next_state); + +#ifdef HAVE_SNMP + if (send_trap_virt) { + ospfTrapVirtNbrStateChange(nbr); + } else if (send_trap) { + ospfTrapNbrStateChange(nbr); + } +#endif } /* Make sure timer is set. */ From bd4b7f1559ab5cb52bbe9dc2db9e50a032ccdbb7 Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 30 Sep 2014 15:54:45 -0700 Subject: [PATCH 0786/1342] bgpd: Ignore stale entry candidates during bestpath selection. During best path selection, if one of the candidates is a stale entry, do not perform the neighbor address comparison as that information is invalid for the stale entry. Attempting to perform the comparison results in a bgpd exception. Signed-off-by: Vivek Venkataraman Reviewed-by: Dinesh G Dutt --- bgpd/bgp_route.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 34ba1abe6..648dc9c85 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -524,7 +524,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, return 0; } - /* 11. Rourter-ID comparision. */ + /* 11. Router-ID comparision. */ + /* If one of the paths is "stale", the corresponding peer router-id will + * be 0 and would always win over the other path. If originator id is + * used for the comparision, it will decide which path is better. + */ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) new_id.s_addr = newattre->originator_id.s_addr; else @@ -553,6 +557,14 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, return 0; /* 13. Neighbor address comparision. */ + /* Do this only if neither path is "stale" as stale paths do not have + * valid peer information (as the connection may or may not be up). + */ + if (CHECK_FLAG (exist->flags, BGP_INFO_STALE)) + return 1; + if (CHECK_FLAG (new->flags, BGP_INFO_STALE)) + return 0; + ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); if (ret == 1) From 234e5c8d5a35339fb319affb952581bf5abb48a7 Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Sun, 1 Feb 2015 00:56:12 -0800 Subject: [PATCH 0787/1342] bgpd: Only use routes from Established peers for best path selection Ensure that routes from a peer are not considered for best path comparison if the peer is not in an Established state. There can be a window between a peer being deleted and the background thread that actually clears the routes (marks them as "removed") runs during which best path may run. If this path selection compared two prefixes all the way down to peer IP addresses and one of these two peers had just been deleted, that peer would not have its sockunion structures, especially su_remote, resulting in a BGPD exception. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_route.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 648dc9c85..02c926fe8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1345,6 +1345,9 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, continue; if (BGP_INFO_HOLDDOWN (ri1)) continue; + if (ri1->peer && ri1->peer != bgp->peer_self) + if (ri1->peer->status != Established) + continue; new_select = ri1; if (do_mpath) @@ -1357,6 +1360,11 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, continue; if (BGP_INFO_HOLDDOWN (ri2)) continue; + if (ri2->peer && + ri2->peer != bgp->peer_self && + !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT)) + if (ri2->peer->status != Established) + continue; if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath) || aspath_cmp_left_confed (ri1->attr->aspath, @@ -1408,6 +1416,12 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, continue; } + if (ri->peer && + ri->peer != bgp->peer_self && + !CHECK_FLAG (ri->peer->sflags, PEER_STATUS_NSF_WAIT)) + if (ri->peer->status != Established) + continue; + if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))) { From 7ef4221c3f85121edb68a6a54ebd6bb167408e47 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 30 Mar 2015 06:32:52 -0700 Subject: [PATCH 0788/1342] bgpd: Fix race in clearing completion When a peer that is Established goes down, it is moved into the Clearing state to facilitate clearing of the routes received from the peer - remove from the RIB, reselect best path, update/delete from Zebra and to other peers etc. At the end of this, a Clearing_Completed event is generated to the FSM which will allow the peer to move out of Clearing to Idle. The issue in the code is that there is a possibility of multiple Clearing Completed events being generated for a peer, one per AFI/SAFI. Upon the first such event, the peer would move to Idle. If other events happened (e.g., new connection got established) before the last Clearing_Completed event is received, bad things can happen. Fix to ensure only one Clearing_Completed event is generated. Signed-off-by: Vivek Venkataraman --- bgpd/bgp_fsm.c | 18 +++++++++++++++++- bgpd/bgp_route.c | 32 ++++++++++---------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 6a2e41e89..80ced4795 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -406,7 +406,23 @@ bgp_fsm_change_status (struct peer *peer, int status) * (and must do so before actually changing into Deleted.. */ if (status >= Clearing) - bgp_clear_route_all (peer); + { + bgp_clear_route_all (peer); + + /* If no route was queued for the clear-node processing, generate the + * completion event here. This is needed because if there are no routes + * to trigger the background clear-node thread, the event won't get + * generated and the peer would be stuck in Clearing. Note that this + * event is for the peer and helps the peer transition out of Clearing + * state; it should not be generated per (AFI,SAFI). The event is + * directly posted here without calling clear_node_complete() as we + * shouldn't do an extra unlock. This event will get processed after + * the state change that happens below, so peer will be in Clearing + * (or Deleted). + */ + if (!peer->clear_node_queue->thread) + BGP_EVENT_ADD (peer, Clearing_Completed); + } /* Preserve old status and change into new status. */ peer->ostatus = peer->status; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 02c926fe8..f40127195 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2979,8 +2979,13 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, * on the process_main queue. Fast-flapping could cause that queue * to grow and grow. */ + + /* lock peer in assumption that clear-node-queue will get nodes; if so, + * the unlock will happen upon work-queue completion; other wise, the + * unlock happens at the end of this function. + */ if (!peer->clear_node_queue->thread) - peer_lock (peer); /* bgp_clear_node_complete */ + peer_lock (peer); switch (purpose) { @@ -3007,28 +3012,11 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, assert (0); break; } - - /* If no routes were cleared, nothing was added to workqueue, the - * completion function won't be run by workqueue code - call it here. - * XXX: Actually, this assumption doesn't hold, see - * bgp_clear_route_table(), we queue all non-empty nodes. - * - * Additionally, there is a presumption in FSM that clearing is only - * really needed if peer state is Established - peers in - * pre-Established states shouldn't have any route-update state - * associated with them (in or out). - * - * We still can get here in pre-Established though, through - * peer_delete -> bgp_fsm_change_status, so this is a useful sanity - * check to ensure the assumption above holds. - * - * At some future point, this check could be move to the top of the - * function, and do a quick early-return when state is - * pre-Established, avoiding above list and table scans. Once we're - * sure it is safe.. - */ + + /* unlock if no nodes got added to the clear-node-queue. */ if (!peer->clear_node_queue->thread) - bgp_clear_node_complete (peer->clear_node_queue); + peer_unlock (peer); + } void From e8441a81f6c9f73bc8a25669003abffb40066703 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 15 Sep 2015 16:15:27 +0100 Subject: [PATCH 0789/1342] build/lib: Check for and include stdbool.h by default * stdbool.h should be widely supported by now, and the 'bool' type makes more semantic sense than an integer type for boolean values. --- configure.ac | 1 + lib/zebra.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index 6864a29ca..aa84ee518 100755 --- a/configure.ac +++ b/configure.ac @@ -436,6 +436,7 @@ AC_C_VOLATILE AC_HEADER_STDC AC_HEADER_TIME AC_HEADER_SYS_WAIT +AC_HEADER_STDBOOL dnl AC_TYPE_PID_T AC_TYPE_UID_T AC_TYPE_MODE_T diff --git a/lib/zebra.h b/lib/zebra.h index 858643778..1ee5107e0 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -92,6 +92,9 @@ typedef int socklen_t; #ifdef HAVE_INTTYPES_H #include #endif /* HAVE_INTTYPES_H */ +#ifdef HAVE_STDBOOL_H +#include +#endif /* machine dependent includes */ #ifdef SUNOS_5 From 13c2a3db503fde67f647fa58fd4e1077517ebb5c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 15 Sep 2015 16:16:42 +0100 Subject: [PATCH 0790/1342] lib/workqueue: Add trivial work_queue_is_scheduled helper --- lib/workqueue.c | 6 ++++++ lib/workqueue.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/lib/workqueue.c b/lib/workqueue.c index e09d009f1..9fc89314e 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -107,6 +107,12 @@ work_queue_free (struct work_queue *wq) return; } +bool +work_queue_is_scheduled (struct work_queue *wq) +{ + return (wq->thread != NULL); +} + static int work_queue_schedule (struct work_queue *wq, unsigned int delay) { diff --git a/lib/workqueue.h b/lib/workqueue.h index f59499a0a..5ad25893b 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -119,6 +119,8 @@ extern void work_queue_plug (struct work_queue *wq); /* unplug the queue, allow it to be drained again */ extern void work_queue_unplug (struct work_queue *wq); +bool work_queue_is_scheduled (struct work_queue *); + /* Helpers, exported for thread.c and command.c */ extern int work_queue_run (struct thread *); extern struct cmd_element show_work_queues_cmd; From 782fb0770080d0e2970fc63af8645e82543aa4d0 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 15 Sep 2015 16:17:22 +0100 Subject: [PATCH 0791/1342] bgpd: Compile fix for clearing-completion FSM fix, using workqueue helper. --- bgpd/bgp_fsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 80ced4795..9ac333526 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "stream.h" #include "memory.h" #include "plist.h" +#include "workqueue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -420,7 +421,7 @@ bgp_fsm_change_status (struct peer *peer, int status) * the state change that happens below, so peer will be in Clearing * (or Deleted). */ - if (!peer->clear_node_queue->thread) + if (!work_queue_is_scheduled (peer->clear_node_queue)) BGP_EVENT_ADD (peer, Clearing_Completed); } From 2820a01eed1c616d490ddbfd17793c19597459d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 24 Jun 2015 15:27:21 +0300 Subject: [PATCH 0792/1342] bgpd: Make bgp_info_cmp robust to paths that do not have su_remote info My original su_remote == NULL check is not correct. It seems that * bgp_route.c: (bgp_info_cmp) Some bgp_info is compared with su_remote=NULL and it's supposed to be perfectly legal. E.g. configured subnet announces ("network a.b.c.d/n"). Ensure bgp_info_cmp is robust if such a path gets as far as the neighbour address comparison step. --- bgpd/bgp_route.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f40127195..40012ac26 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -564,7 +564,12 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, return 1; if (CHECK_FLAG (new->flags, BGP_INFO_STALE)) return 0; - + /* locally configured routes to advertise do not have su_remote */ + if (new->peer->su_remote == NULL) + return 0; + if (exist->peer->su_remote == NULL) + return 1; + ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); if (ret == 1) From 3921cc54445417aa1ca22668063701a626e93098 Mon Sep 17 00:00:00 2001 From: Balaji Date: Sat, 16 May 2015 23:12:17 +0530 Subject: [PATCH 0793/1342] bgpd: Addition of "show ip bgp dampening" command tree This patch addresses David's comments and contains: 1.Addition of show ip bgp dampening command tree 2.Addition of show ip bgp dampening parameters to display BGP dampening parameters. Signed-off-by: Balaji.G --- bgpd/bgp_route.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 40012ac26..7de94615a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7200,6 +7200,17 @@ DEFUN (show_ip_bgp_flap_regexp, bgp_show_type_flap_regexp); } +ALIAS (show_ip_bgp_flap_regexp, + show_ip_bgp_damp_flap_regexp_cmd, + "show ip bgp dampening flap-statistics regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + DEFUN (show_ip_bgp_ipv4_regexp, show_ip_bgp_ipv4_regexp_cmd, "show ip bgp ipv4 (unicast|multicast) regexp .LINE", @@ -7315,6 +7326,17 @@ DEFUN (show_ip_bgp_flap_prefix_list, bgp_show_type_flap_prefix_list); } +ALIAS (show_ip_bgp_flap_prefix_list, + show_ip_bgp_damp_flap_prefix_list_cmd, + "show ip bgp dampening flap-statistics prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") + DEFUN (show_ip_bgp_ipv4_prefix_list, show_ip_bgp_ipv4_prefix_list_cmd, "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", @@ -7429,6 +7451,17 @@ DEFUN (show_ip_bgp_flap_filter_list, bgp_show_type_flap_filter_list); } +ALIAS (show_ip_bgp_flap_filter_list, + show_ip_bgp_damp_flap_filter_list_cmd, + "show ip bgp dampening flap-statistics filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + DEFUN (show_ip_bgp_ipv4_filter_list, show_ip_bgp_ipv4_filter_list_cmd, "show ip bgp ipv4 (unicast|multicast) filter-list WORD", @@ -7500,6 +7533,18 @@ DEFUN (show_ipv6_mbgp_filter_list, } #endif /* HAVE_IPV6 */ +DEFUN (show_ip_bgp_dampening_info, + show_ip_bgp_dampening_params_cmd, + "show ip bgp dampening parameters", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display detail of configured dampening parameters\n") +{ + return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); +} + static int bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -7544,6 +7589,17 @@ DEFUN (show_ip_bgp_flap_route_map, bgp_show_type_flap_route_map); } +ALIAS (show_ip_bgp_flap_route_map, + show_ip_bgp_damp_flap_route_map_cmd, + "show ip bgp dampening flap-statistics route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + DEFUN (show_ip_bgp_ipv4_route_map, show_ip_bgp_ipv4_route_map_cmd, "show ip bgp ipv4 (unicast|multicast) route-map WORD", @@ -7610,6 +7666,16 @@ DEFUN (show_ip_bgp_flap_cidr_only, bgp_show_type_flap_cidr_only, NULL); } +ALIAS (show_ip_bgp_flap_cidr_only, + show_ip_bgp_damp_flap_cidr_only_cmd, + "show ip bgp dampening flap-statistics cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display only routes with non-natural netmasks\n") + DEFUN (show_ip_bgp_ipv4_cidr_only, show_ip_bgp_ipv4_cidr_only_cmd, "show ip bgp ipv4 (unicast|multicast) cidr-only", @@ -9093,6 +9159,17 @@ DEFUN (show_ip_bgp_flap_prefix_longer, bgp_show_type_flap_prefix_longer); } +ALIAS (show_ip_bgp_flap_prefix_longer, + show_ip_bgp_damp_flap_prefix_longer_cmd, + "show ip bgp dampening flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + DEFUN (show_ip_bgp_ipv4_prefix_longer, show_ip_bgp_ipv4_prefix_longer_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", @@ -9126,6 +9203,16 @@ DEFUN (show_ip_bgp_flap_address, bgp_show_type_flap_address); } +ALIAS (show_ip_bgp_flap_address, + show_ip_bgp_damp_flap_address_cmd, + "show ip bgp dampening flap-statistics A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") + DEFUN (show_ip_bgp_flap_prefix, show_ip_bgp_flap_prefix_cmd, "show ip bgp flap-statistics A.B.C.D/M", @@ -9138,6 +9225,17 @@ DEFUN (show_ip_bgp_flap_prefix, return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_prefix); } + +ALIAS (show_ip_bgp_flap_prefix, + show_ip_bgp_damp_flap_prefix_cmd, + "show ip bgp dampening flap-statistics A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + #ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_longer, show_bgp_prefix_longer_cmd, @@ -12012,6 +12110,15 @@ DEFUN (show_ip_bgp_dampened_paths, NULL); } +ALIAS (show_ip_bgp_dampened_paths, + show_ip_bgp_damp_dampened_paths_cmd, + "show ip bgp dampening dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display paths suppressed due to dampening\n") + DEFUN (show_ip_bgp_flap_statistics, show_ip_bgp_flap_statistics_cmd, "show ip bgp flap-statistics", @@ -12024,6 +12131,15 @@ DEFUN (show_ip_bgp_flap_statistics, bgp_show_type_flap_statistics, NULL); } +ALIAS (show_ip_bgp_flap_statistics, + show_ip_bgp_damp_flap_statistics_cmd, + "show ip bgp dampening flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n") + /* Display specified route of BGP table. */ static int bgp_clear_damp_route (struct vty *vty, const char *view_name, @@ -12537,16 +12653,25 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_address_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); @@ -12670,16 +12795,27 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_address_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); From 7053d8176ce502aabe39bf167f01354654bde5df Mon Sep 17 00:00:00 2001 From: Denil Vira Date: Thu, 23 Jul 2015 06:52:18 -0700 Subject: [PATCH 0794/1342] bgpd: Fix useless call in bgpd/bgp_mplsvpn.c Coverity scan ID : 1302528. Calling "decode_label(pnt)" is only useful for its return value, which is ignored. Removed the call. Signed-off-by: Denil Vira --- bgpd/bgp_mplsvpn.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3d2dadef6..cf4ab6f24 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -116,9 +116,6 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, zlog_err ("prefix length is less than 88: %d", prefixlen); return -1; } - - /* XXX: Not doing anything with the label */ - decode_label (pnt); /* Copyr label to prefix. */ tagpnt = pnt;; From 57cd5e7a2623258e1a095d63e0faaad2cddf61e8 Mon Sep 17 00:00:00 2001 From: Denil Vira Date: Mon, 10 Aug 2015 12:46:14 -0700 Subject: [PATCH 0795/1342] bgpd: Variable reuse in bgpd/bgpd.c In bgp_delete(), variables 'node' and 'next' are overwritten in the nested for loop. Signed-off-by: Denil Vira Acked-by: Donald Sharp --- bgpd/bgpd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 7a0274c0a..4b69313ef 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2098,8 +2098,8 @@ bgp_delete (struct bgp *bgp) { struct peer *peer; struct peer_group *group; - struct listnode *node; - struct listnode *next; + struct listnode *node, *pnode; + struct listnode *next, *pnext; afi_t afi; int i; @@ -2127,7 +2127,7 @@ bgp_delete (struct bgp *bgp) for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) { - for (ALL_LIST_ELEMENTS (group->peer, node, next, peer)) + for (ALL_LIST_ELEMENTS (group->peer, pnode, pnext, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { From e2a9258c16bce1b3797efb9be354d20d68236194 Mon Sep 17 00:00:00 2001 From: Denil Vira Date: Tue, 11 Aug 2015 13:34:59 -0700 Subject: [PATCH 0796/1342] bgpd: Fix memory leak in bgpd/bgp_route.c In function bgp_aggregate_add, variables 'aspath' and 'community' are malloced but not guaranteed to be freed before the function returns. Signed-off-by: Denil Vira --- bgpd/bgp_route.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7de94615a..4db2e3ea6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4888,6 +4888,13 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, /* Process change. */ bgp_process (bgp, rn, afi, safi); } + else + { + if (aspath) + aspath_free (aspath); + if (community) + community_free (community); + } } void From a752c3be8c2436941311788f2e7b644a2af0fd65 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 18 Aug 2015 08:48:53 -0400 Subject: [PATCH 0797/1342] bgpd: Remove unnecessary stream_dup calls BGP packet handling creates a stream to handle data for an outgoing packet. In some cases the code would create a new stream, add data, then duplicate the stream and then free the original stream. This change removes the unnecessary duplication, which entails a malloc and memcpy. Signed-off-by: Donald Sharp --- bgpd/bgp_packet.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 7d27972e2..e1ae494d3 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -275,7 +275,6 @@ static struct stream * bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; - struct stream *packet; if (DISABLE_BGP_ANNOUNCE) return NULL; @@ -308,10 +307,8 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) } bgp_packet_set_size (s); - packet = stream_dup (s); - bgp_packet_add (peer, packet); - stream_free (s); - return packet; + bgp_packet_add (peer, s); + return s; } /* Make BGP withdraw packet. */ @@ -431,7 +428,6 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, afi_t afi, safi_t safi, struct peer *from) { struct stream *s; - struct stream *packet; struct prefix p; unsigned long pos; bgp_size_t total_attr_len; @@ -482,16 +478,13 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, /* Set size. */ bgp_packet_set_size (s); - packet = stream_dup (s); - stream_free (s); - /* Dump packet if debug option is set. */ #ifdef DEBUG /* bgp_packet_dump (packet); */ #endif /* DEBUG */ /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -500,7 +493,6 @@ void bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; - struct stream *packet; struct prefix p; unsigned long attrlen_pos = 0; unsigned long cp; @@ -570,11 +562,8 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) bgp_packet_set_size (s); - packet = stream_dup (s); - stream_free (s); - /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -1029,7 +1018,6 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, u_char orf_type, u_char when_to_refresh, int remove) { struct stream *s; - struct stream *packet; int length; struct bgp_filter *filter; int orf_refresh = 0; @@ -1110,12 +1098,8 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); } - /* Make real packet. */ - packet = stream_dup (s); - stream_free (s); - /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } @@ -1126,7 +1110,6 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, int capability_code, int action) { struct stream *s; - struct stream *packet; int length; /* Adjust safi code. */ @@ -1157,12 +1140,9 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, /* Set packet size. */ length = bgp_packet_set_size (s); - /* Make real packet. */ - packet = stream_dup (s); - stream_free (s); /* Add packet to the peer. */ - bgp_packet_add (peer, packet); + bgp_packet_add (peer, s); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", From 79969960aae4adbae1eac6caebc289fe09ddc1d6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 19 Aug 2015 21:27:24 -0400 Subject: [PATCH 0798/1342] bgpd: Fix small memory leak in str2prefix_rd str2prefix_rd has a memory leak. This commit fixes that issue Signed-off-by: Donald Sharp --- bgpd/bgp_mplsvpn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index cf4ab6f24..8a1ed70e2 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -220,6 +220,7 @@ str2prefix_rd (const char *str, struct prefix_rd *prd) } memcpy (prd->val, s->data, 8); + XFREE(MTYPE_TMP, half); return 1; } From 58a83f2f5dc24da3194bfa8255499029315e8649 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 11 Sep 2015 10:11:42 -0400 Subject: [PATCH 0799/1342] bgpd: Warn user that bgp is setting maximum-paths larger than MULTIPATH_NUM In cases where a distribution has compiled zebra with a MULTIPATH_NUM that is less than what the user is setting the maximum-paths in bgp, warn them that some of the nexthops will not make it into zebra and by extension the kernel for routing. The command is still accepted. dell-s6000-02(config)# router bgp 100 dell-s6000-02(config-router)# maximum-paths 3 % Warning: maximum-paths set to 3 is greater than 2 that zebra is compiled to support dell-s6000-02(config-router)# maximum-paths ibgp 44 % Warning: maximum-paths set to 44 is greater than 2 that zebra is compiled to support dell-s6000-02(config-router)# Signed-off-by: Donald Sharp --- bgpd/Makefile.am | 2 +- bgpd/bgp_vty.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 4659ac681..b2614f46f 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 62331635a..4fd255fce 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -676,6 +676,11 @@ DEFUN (bgp_maxpaths, return CMD_WARNING; } + if ((MULTIPATH_NUM != 0) && (maxpaths > MULTIPATH_NUM)) + vty_out (vty, + "%% Warning: maximum-paths set to %d is greater than %d that zebra is compiled to support%s", + maxpaths, MULTIPATH_NUM, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -704,6 +709,11 @@ DEFUN (bgp_maxpaths_ibgp, return CMD_WARNING; } + if ((MULTIPATH_NUM != 0) && (maxpaths > MULTIPATH_NUM)) + vty_out (vty, + "%% Warning: maximum-paths set to %d is greater than %d that zebra is compiled to support%s", + maxpaths, MULTIPATH_NUM, VTY_NEWLINE); + return CMD_SUCCESS; } From 104576dcafe356985326b2950bfc50962702b4fb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 16 Sep 2015 13:17:55 -0400 Subject: [PATCH 0800/1342] bgpd: Add some peer_lock/unlock debug code Finding memory leaks associated with the peer data structure is incredibly hard, add some code to allow you to find this leaked code when needed. Signed-off-by: Donald Sharp --- bgpd/bgpd.c | 28 ++++++++++++---------------- bgpd/bgpd.h | 13 +++++++++++-- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4b69313ef..f77aa7243 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -745,10 +745,14 @@ peer_free (struct peer *peer) /* increase reference count on a struct peer */ struct peer * -peer_lock (struct peer *peer) +peer_lock_with_caller (const char *name, struct peer *peer) { assert (peer && (peer->lock >= 0)); - + +#if 0 + zlog_debug("%s peer_lock %p %d", name, peer, peer->lock); +#endif + peer->lock++; return peer; @@ -758,30 +762,22 @@ peer_lock (struct peer *peer) * struct peer is freed and NULL returned if last reference */ struct peer * -peer_unlock (struct peer *peer) +peer_unlock_with_caller (const char *name, struct peer *peer) { assert (peer && (peer->lock > 0)); - + +#if 0 + zlog_debug("%s peer_unlock %p %d", name, peer, peer->lock); +#endif + peer->lock--; if (peer->lock == 0) { -#if 0 - zlog_debug ("unlocked and freeing"); - zlog_backtrace (LOG_DEBUG); -#endif peer_free (peer); return NULL; } -#if 0 - if (peer->lock == 1) - { - zlog_debug ("unlocked to 1"); - zlog_backtrace (LOG_DEBUG); - } -#endif - return peer; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 58d1ecafb..7ae0acb30 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -851,8 +851,17 @@ extern struct peer_group *peer_group_lookup (struct bgp *, const char *); extern struct peer_group *peer_group_get (struct bgp *, const char *); extern struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *, int *); -extern struct peer *peer_lock (struct peer *); -extern struct peer *peer_unlock (struct peer *); + +/* + * Peers are incredibly easy to memory leak + * due to the various ways that they are actually used + * Provide some functionality to debug locks and unlocks + */ +extern struct peer *peer_lock_with_caller(const char *, struct peer *); +extern struct peer *peer_unlock_with_caller(const char *, struct peer *); +#define peer_unlock(A) peer_unlock_with_caller(__FUNCTION__, (A)) +#define peer_lock(B) peer_lock_with_caller(__FUNCTION__, (B)) + extern bgp_peer_sort_t peer_sort (struct peer *peer); extern int peer_active (struct peer *); extern int peer_active_nego (struct peer *); From b3eeabee657df14509ce50d5f64262b672e87d62 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 16 Sep 2015 13:17:56 -0400 Subject: [PATCH 0801/1342] bgpd: Fix 'struct peer' memory leaks peer_delete has been written to handle the peer->group pointer and to remove the peer from the peer group if it exists upon deletion being called. Shutdown/deletion Code was intentionally setting the peer-group to NULL prior to calling peer_delete. This leaked the memory associated with the peer->group because of refcnt accounting. Signed-off-by: Donald Sharp --- bgpd/bgpd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f77aa7243..006803729 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1696,7 +1696,6 @@ peer_group_delete (struct peer_group *group) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - peer->group = NULL; peer_delete (peer); } list_delete (group->peer); @@ -1726,7 +1725,6 @@ peer_group_remote_as_delete (struct peer_group *group) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - peer->group = NULL; peer_delete (peer); } list_delete_all_node (group->peer); From e675678789b11d175a08a9e0be73917aa8f23a15 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 16 Jul 2015 21:18:34 -0400 Subject: [PATCH 0802/1342] build: Enable vtysh and pimd as part of default build The default build needs vtysh and pimd as a default build so that when a change is made we can catch build issues before they become a problem. Signed-off-by: Donald Sharp --- configure.ac | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index aa84ee518..747a0c610 100755 --- a/configure.ac +++ b/configure.ac @@ -225,7 +225,7 @@ AC_ARG_WITH(pkg-git-version, AS_HELP_STRING([--with-pkg-git-version], [add git information to MOTD and build version string]), [ test "x$withval" != "xno" && with_pkg_git_version="yes" ]) AC_ARG_ENABLE(vtysh, - AS_HELP_STRING([--enable-vtysh], [include integrated vty shell for Quagga])) + AS_HELP_STRING([--disable-vtysh], [do not build integrated vty shell for Quagga])) AC_ARG_ENABLE(doc, AS_HELP_STRING([--disable-doc], [do not build docs])) AC_ARG_ENABLE(zebra, @@ -245,7 +245,7 @@ AC_ARG_ENABLE(watchquagga, AC_ARG_ENABLE(isisd, AS_HELP_STRING([--disable-isisd], [do not build isisd])) AC_ARG_ENABLE(pimd, - AS_HELP_STRING([--enable-pimd], [build pimd])) + AS_HELP_STRING([--disable-pimd], [do not build pimd])) AC_ARG_ENABLE(bgp-announce, AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement])) AC_ARG_ENABLE(snmp, @@ -637,7 +637,8 @@ dnl --------------------- dnl Integrated VTY option dnl --------------------- case "${enable_vtysh}" in - "yes") VTYSH="vtysh"; + "no") VTYSH="";; + *) VTYSH="vtysh"; AC_DEFINE(VTYSH,,VTY shell) dnl Vtysh uses libreadline, which looks for termcap functions at dnl configure time. We follow readlines search order. @@ -667,7 +668,6 @@ dnl [TODO] on Linux, and in [TODO] on Solaris. fi ;; "no" ) VTYSH="";; - * ) ;; esac AC_SUBST(LIBREADLINE) AM_CONDITIONAL(VTYSH, test "x$VTYSH" = "xvtysh") @@ -1186,9 +1186,8 @@ esac AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") case "${enable_pimd}" in - "yes") PIMD="pimd";; "no" ) PIMD="";; - * ) ;; + * ) PIMD="pimd";; esac AM_CONDITIONAL(PIMD, test "x$PIMD" = "xpimd") From f733280419f18b1a0e3b06ec3681781689d57053 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 17 Jul 2015 22:36:57 -0400 Subject: [PATCH 0803/1342] lib/command: Fix optional arguments with description interactions If you have a cli like this: "neighbor WORD interface {v6only}" When in the cli you hit ? after entering v6only you get this: tor-11(config-router)# neighbor swp1 interface v6only % There is no matched command. tor-11(config-router)# neighbor swp1 interface v6only With this fix we now see: tor-22(config-router)# neighbor swp1 interface v6only tor-22(config-router)# neighbor swp1 interface v6only This behavior is now consistent with non-optional last arguments. Signed-off-by: Donald Sharp --- lib/command.c | 74 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/lib/command.c b/lib/command.c index 641cf2078..20841604c 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2119,6 +2119,8 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) char *command; vector matches = NULL; vector match_vector; + uint32_t command_found = 0; + const char *last_word; /* Set index. */ if (vector_active (vline) == 0) @@ -2205,40 +2207,54 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) /* Make description vector. */ for (i = 0; i < vector_active (matches); i++) - if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) - { - unsigned int j; - const char *last_word; - vector vline_trimmed; + { + if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) + { + unsigned int j; + vector vline_trimmed; - last_word = vector_slot(vline, vector_active(vline) - 1); - if (last_word == NULL || !strlen(last_word)) - { - vline_trimmed = vector_copy(vline); - vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1); + command_found++; + last_word = vector_slot(vline, vector_active(vline) - 1); + if (last_word == NULL || !strlen(last_word)) + { + vline_trimmed = vector_copy(vline); + vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1); - if (cmd_is_complete(cmd_element, vline_trimmed) - && desc_unique_string(matchvec, command_cr)) - { - if (match != vararg_match) - vector_set(matchvec, &token_cr); - } + if (cmd_is_complete(cmd_element, vline_trimmed) + && desc_unique_string(matchvec, command_cr)) + { + if (match != vararg_match) + vector_set(matchvec, &token_cr); + } - vector_free(vline_trimmed); - } + vector_free(vline_trimmed); + } - match_vector = vector_slot (matches, i); - if (match_vector) - for (j = 0; j < vector_active(match_vector); j++) - { - struct cmd_token *token = vector_slot(match_vector, j); - const char *string; + match_vector = vector_slot (matches, i); + if (match_vector) + { + for (j = 0; j < vector_active(match_vector); j++) + { + struct cmd_token *token = vector_slot(match_vector, j); + const char *string; + + string = cmd_entry_function_desc(command, token); + if (string && desc_unique_string(matchvec, string)) + vector_set(matchvec, token); + } + } + } + } + + /* + * We can get into this situation when the command is complete + * but the last part of the command is an optional piece of + * the cli. + */ + last_word = vector_slot(vline, vector_active(vline) - 1); + if (command_found == 0 && (last_word == NULL || !strlen(last_word))) + vector_set(matchvec, &token_cr); - string = cmd_entry_function_desc(command, token); - if (string && desc_unique_string(matchvec, string)) - vector_set(matchvec, token); - } - } vector_free (cmd_vector); cmd_matches_free(&matches); From a9d4cb33faa6af622240190a80f41c4672374925 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 17 Sep 2015 10:54:25 -0400 Subject: [PATCH 0804/1342] lib/zclient: Consolidate error reporting for zclient_read_header All functions that call zclient_read_header immediately turn around and check to ensure that the version and marker fields are correct Move this code into zclient_read_header Signed-off-by: Donald Sharp --- bgpd/bgp_nexthop.c | 24 +++--------------------- lib/zclient.c | 7 +++++++ pimd/pim_zlookup.c | 9 +-------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index c74bebad8..20302e392 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -809,13 +809,7 @@ zlookup_read (void) zlog_err("%s: zserv_read_header() failed", __func__); return NULL; } - if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) - { - zlog_err("%s: socket %d version mismatch, marker %d, version %d", - __func__, zlookup->sock, marker, version); - return NULL; - } - + /* XXX: not doing anything with raddr */ raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); @@ -918,13 +912,7 @@ zlookup_read_ipv6 (void) zlog_err("%s: zserv_read_header() failed", __func__); return NULL; } - if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) - { - zlog_err("%s: socket %d version mismatch, marker %d, version %d", - __func__, zlookup->sock, marker, version); - return NULL; - } - + /* XXX: not actually doing anything with raddr */ stream_get (&raddr, s, 16); @@ -1065,13 +1053,7 @@ bgp_import_check (struct prefix *p, u_int32_t *igpmetric, zlog_err("%s: zserv_read_header() failed", __func__); return 0; } - if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) - { - zlog_err("%s: socket %d version mismatch, marker %d, version %d", - __func__, zlookup->sock, marker, version); - return 0; - } - + /* XXX: not using addr */ addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); diff --git a/lib/zclient.c b/lib/zclient.c index a09563248..0ce46fefd 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -315,6 +315,13 @@ zclient_read_header (struct stream *s, int sock, u_int16_t *size, u_char *marker *vrf_id = stream_getw (s); *cmd = stream_getw (s); + if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) + { + zlog_err("%s: socket %d version mismatch, marker %d, version %d", + __func__, sock, *marker, *version); + return -1; + } + if (*size && stream_read (s, sock, *size) != *size) return -1; diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index fae8f81ca..67896d96b 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -196,14 +196,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, zclient_lookup_failed(zlookup); return -3; } - - if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { - zlog_err("%s: socket %d version mismatch, marker %d, version %d", - __func__, zlookup->sock, marker, version); - zclient_lookup_failed(zlookup); - return -4; - } - + if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); From 4fdb5f401eb277fa54d80e99d241bd9b03895a6a Mon Sep 17 00:00:00 2001 From: Denil Vira Date: Thu, 23 Jul 2015 06:52:16 -0700 Subject: [PATCH 0805/1342] lib: Fix Free Pointer dereference in lib/filter.c Coverity Scan ID 23056. access is accessed after free in access_list_delete Signed-off-by: Denil Vira --- lib/filter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/filter.c b/lib/filter.c index 96605c7d5..a47294140 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -493,13 +493,13 @@ access_list_filter_delete (struct access_list *access, struct filter *filter) filter_free (filter); - /* If access_list becomes empty delete it from access_master. */ - if (access_list_empty (access)) - access_list_delete (access); - /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (access); + + /* If access_list becomes empty delete it from access_master. */ + if (access_list_empty (access)) + access_list_delete (access); } /* From fbc3e97d747862fd47f711c9f15b8166bdf94b18 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 12 Aug 2015 14:32:47 -0400 Subject: [PATCH 0806/1342] lib: Remove unused 'show memory XXX' functionality The 'show memory XXXX' functionality is not used at all. This removes the unused code Signed-off-by: Donald Sharp --- lib/memory.c | 154 ++------------------------------------------------- 1 file changed, 4 insertions(+), 150 deletions(-) diff --git a/lib/memory.c b/lib/memory.c index 84daeeef9..a9149e10f 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -392,12 +392,11 @@ show_memory_mallinfo (struct vty *vty) } #endif /* HAVE_MALLINFO */ -DEFUN (show_memory_all, - show_memory_all_cmd, - "show memory all", +DEFUN (show_memory, + show_memory_cmd, + "show memory", "Show running system information\n" - "Memory statistics\n" - "All memory statistics\n") + "Memory statistics\n") { struct mlist *ml; int needsep = 0; @@ -416,160 +415,15 @@ DEFUN (show_memory_all, return CMD_SUCCESS; } -ALIAS (show_memory_all, - show_memory_cmd, - "show memory", - "Show running system information\n" - "Memory statistics\n") - -DEFUN (show_memory_lib, - show_memory_lib_cmd, - "show memory lib", - SHOW_STR - "Memory statistics\n" - "Library memory\n") -{ - show_memory_vty (vty, memory_list_lib); - return CMD_SUCCESS; -} - -DEFUN (show_memory_zebra, - show_memory_zebra_cmd, - "show memory zebra", - SHOW_STR - "Memory statistics\n" - "Zebra memory\n") -{ - show_memory_vty (vty, memory_list_zebra); - return CMD_SUCCESS; -} - -DEFUN (show_memory_rip, - show_memory_rip_cmd, - "show memory rip", - SHOW_STR - "Memory statistics\n" - "RIP memory\n") -{ - show_memory_vty (vty, memory_list_rip); - return CMD_SUCCESS; -} - -DEFUN (show_memory_ripng, - show_memory_ripng_cmd, - "show memory ripng", - SHOW_STR - "Memory statistics\n" - "RIPng memory\n") -{ - show_memory_vty (vty, memory_list_ripng); - return CMD_SUCCESS; -} - -DEFUN (show_memory_babel, - show_memory_babel_cmd, - "show memory babel", - SHOW_STR - "Memory statistics\n" - "Babel memory\n") -{ - show_memory_vty (vty, memory_list_babel); - return CMD_SUCCESS; -} - -DEFUN (show_memory_bgp, - show_memory_bgp_cmd, - "show memory bgp", - SHOW_STR - "Memory statistics\n" - "BGP memory\n") -{ - show_memory_vty (vty, memory_list_bgp); - return CMD_SUCCESS; -} - -DEFUN (show_memory_ospf, - show_memory_ospf_cmd, - "show memory ospf", - SHOW_STR - "Memory statistics\n" - "OSPF memory\n") -{ - show_memory_vty (vty, memory_list_ospf); - return CMD_SUCCESS; -} - -DEFUN (show_memory_ospf6, - show_memory_ospf6_cmd, - "show memory ospf6", - SHOW_STR - "Memory statistics\n" - "OSPF6 memory\n") -{ - show_memory_vty (vty, memory_list_ospf6); - return CMD_SUCCESS; -} - -DEFUN (show_memory_isis, - show_memory_isis_cmd, - "show memory isis", - SHOW_STR - "Memory statistics\n" - "ISIS memory\n") -{ - show_memory_vty (vty, memory_list_isis); - return CMD_SUCCESS; -} - -DEFUN (show_memory_pim, - show_memory_pim_cmd, - "show memory pim", - SHOW_STR - "Memory statistics\n" - "PIM memory\n") -{ - show_memory_vty (vty, memory_list_pim); - return CMD_SUCCESS; -} void memory_init (void) { install_element (RESTRICTED_NODE, &show_memory_cmd); - install_element (RESTRICTED_NODE, &show_memory_all_cmd); - install_element (RESTRICTED_NODE, &show_memory_lib_cmd); - install_element (RESTRICTED_NODE, &show_memory_rip_cmd); - install_element (RESTRICTED_NODE, &show_memory_ripng_cmd); - install_element (RESTRICTED_NODE, &show_memory_babel_cmd); - install_element (RESTRICTED_NODE, &show_memory_bgp_cmd); - install_element (RESTRICTED_NODE, &show_memory_ospf_cmd); - install_element (RESTRICTED_NODE, &show_memory_ospf6_cmd); - install_element (RESTRICTED_NODE, &show_memory_isis_cmd); install_element (VIEW_NODE, &show_memory_cmd); - install_element (VIEW_NODE, &show_memory_all_cmd); - install_element (VIEW_NODE, &show_memory_lib_cmd); - install_element (VIEW_NODE, &show_memory_rip_cmd); - install_element (VIEW_NODE, &show_memory_ripng_cmd); - install_element (VIEW_NODE, &show_memory_babel_cmd); - install_element (VIEW_NODE, &show_memory_bgp_cmd); - install_element (VIEW_NODE, &show_memory_ospf_cmd); - install_element (VIEW_NODE, &show_memory_ospf6_cmd); - install_element (VIEW_NODE, &show_memory_isis_cmd); - install_element (VIEW_NODE, &show_memory_pim_cmd); install_element (ENABLE_NODE, &show_memory_cmd); - install_element (ENABLE_NODE, &show_memory_all_cmd); - install_element (ENABLE_NODE, &show_memory_lib_cmd); - install_element (ENABLE_NODE, &show_memory_zebra_cmd); - install_element (ENABLE_NODE, &show_memory_rip_cmd); - install_element (ENABLE_NODE, &show_memory_ripng_cmd); - install_element (ENABLE_NODE, &show_memory_babel_cmd); - install_element (ENABLE_NODE, &show_memory_bgp_cmd); - install_element (ENABLE_NODE, &show_memory_ospf_cmd); - install_element (ENABLE_NODE, &show_memory_ospf6_cmd); - install_element (ENABLE_NODE, &show_memory_isis_cmd); - install_element (ENABLE_NODE, &show_memory_pim_cmd); } /* Stats querying from users */ From 0bc874b88cf86fca4b18f3672a441ed142fc499d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 29 Jul 2015 19:16:13 -0400 Subject: [PATCH 0807/1342] build/arm: Arm compilation warning fix The arm cross compiler is issuing warnings for signed/unsigned comparisons for ntohs. ntohs returns a unsigned int, while the counting variables are signed. Fixed to allow -Werror to work properly Signed-off-by: Donald Sharp --- ospf6d/ospf6_message.c | 2 +- ospfd/ospf_interface.c | 2 +- ospfd/ospf_vty.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index ecc96f714..e71b4101b 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1630,7 +1630,7 @@ static void ospf6_send (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { - int len; + unsigned int len; char srcname[64], dstname[64]; struct iovec iovector[2]; diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index af4f0a608..f41c4f168 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -1011,7 +1011,7 @@ ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v) struct ospf_interface *voi; struct listnode *node; struct vertex_parent *vp = NULL; - int i; + unsigned int i; struct router_lsa *rl; voi = vl_data->vl_oi; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index e5e56319a..c6f3b4049 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3694,7 +3694,8 @@ static void show_ip_ospf_database_router_links (struct vty *vty, struct router_lsa *rl) { - int len, i, type; + int len, type; + unsigned int i; len = ntohs (rl->header.length) - 4; for (i = 0; i < ntohs (rl->links) && len > 0; len -= 12, i++) From 04a3aabf58d95d01c4c8168eeff43cf9d9892eee Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 3 Sep 2015 10:47:43 +0200 Subject: [PATCH 0808/1342] vrf: add a runtime check before playing with netns This patch adds a runtime check to determine if netns are available. Some systems like OpenWRT have the system call setns() but don't have the kernel option CONFIG_NET_NS enabled. Reported-by: Christian Franke Signed-off-by: Nicolas Dichtel Tested-by: Christian Franke --- lib/vrf.c | 95 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index 89653a8bb..29be02a05 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -38,7 +38,6 @@ #include "command.h" #include "vty.h" -#ifdef HAVE_NETNS #ifndef CLONE_NEWNET #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ @@ -57,7 +56,11 @@ static inline int setns(int fd, int nstype) #endif /* HAVE_SETNS */ #define VRF_RUN_DIR "/var/run/netns" + +#ifdef HAVE_NETNS + #define VRF_DEFAULT_NAME "/proc/self/ns/net" +static int have_netns_enabled = -1; #else /* !HAVE_NETNS */ @@ -65,6 +68,27 @@ static inline int setns(int fd, int nstype) #endif /* HAVE_NETNS */ +static int have_netns(void) +{ +#ifdef HAVE_NETNS + if (have_netns_enabled < 0) + { + int fd = open (VRF_DEFAULT_NAME, O_RDONLY); + + if (fd < 0) + have_netns_enabled = 0; + else + { + have_netns_enabled = 1; + close(fd); + } + } + return have_netns_enabled; +#else + return 0; +#endif +} + struct vrf { /* Identifier, same as the vector index */ @@ -185,11 +209,10 @@ vrf_lookup (vrf_id_t vrf_id) static int vrf_is_enabled (struct vrf *vrf) { -#ifdef HAVE_NETNS - return vrf && vrf->fd >= 0; -#else - return vrf && vrf->fd == -2 && vrf->vrf_id == VRF_DEFAULT; -#endif + if (have_netns()) + return vrf && vrf->fd >= 0; + else + return vrf && vrf->fd == -2 && vrf->vrf_id == VRF_DEFAULT; } /* @@ -205,12 +228,12 @@ vrf_enable (struct vrf *vrf) if (!vrf_is_enabled (vrf)) { -#ifdef HAVE_NETNS - vrf->fd = open (vrf->name, O_RDONLY); -#else - vrf->fd = -2; /* Remember that vrf_enable_hook has been called */ - errno = -ENOTSUP; -#endif + if (have_netns()) { + vrf->fd = open (vrf->name, O_RDONLY); + } else { + vrf->fd = -2; /* Remember that vrf_enable_hook has been called */ + errno = -ENOTSUP; + } if (!vrf_is_enabled (vrf)) { @@ -219,10 +242,9 @@ vrf_enable (struct vrf *vrf) return 0; } -#ifdef HAVE_NETNS - zlog_info ("VRF %u is associated with NETNS %s.", - vrf->vrf_id, vrf->name); -#endif + if (have_netns()) + zlog_info ("VRF %u is associated with NETNS %s.", + vrf->vrf_id, vrf->name); zlog_info ("VRF %u is enabled.", vrf->vrf_id); if (vrf_master.vrf_enable_hook) @@ -247,9 +269,9 @@ vrf_disable (struct vrf *vrf) if (vrf_master.vrf_disable_hook) (*vrf_master.vrf_disable_hook) (vrf->vrf_id, &vrf->info); -#ifdef HAVE_NETNS - close (vrf->fd); -#endif + if (have_netns()) + close (vrf->fd); + vrf->fd = -1; } } @@ -488,7 +510,6 @@ vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id) VRF_BITMAP_FLAG (offset)) ? 1 : 0; } -#ifdef HAVE_NETNS /* * VRF realization with NETNS */ @@ -624,8 +645,6 @@ vrf_config_write (struct vty *vty) return write; } -#endif /* HAVE_NETNS */ - /* Initialize VRF module. */ void vrf_init (void) @@ -653,12 +672,13 @@ vrf_init (void) exit (1); } -#ifdef HAVE_NETNS - /* Install VRF commands. */ - install_node (&vrf_node, vrf_config_write); - install_element (CONFIG_NODE, &vrf_netns_cmd); - install_element (CONFIG_NODE, &no_vrf_netns_cmd); -#endif + if (have_netns()) + { + /* Install VRF commands. */ + install_node (&vrf_node, vrf_config_write); + install_element (CONFIG_NODE, &vrf_netns_cmd); + install_element (CONFIG_NODE, &no_vrf_netns_cmd); + } } /* Terminate VRF module. */ @@ -689,17 +709,18 @@ vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id) return -1; } -#ifdef HAVE_NETNS - ret = (vrf_id != VRF_DEFAULT) ? setns (vrf->fd, CLONE_NEWNET) : 0; - if (ret >= 0) + if (have_netns()) { - ret = socket (domain, type, protocol); - if (vrf_id != VRF_DEFAULT) - setns (vrf_lookup (VRF_DEFAULT)->fd, CLONE_NEWNET); + ret = (vrf_id != VRF_DEFAULT) ? setns (vrf->fd, CLONE_NEWNET) : 0; + if (ret >= 0) + { + ret = socket (domain, type, protocol); + if (vrf_id != VRF_DEFAULT) + setns (vrf_lookup (VRF_DEFAULT)->fd, CLONE_NEWNET); + } } -#else - ret = socket (domain, type, protocol); -#endif + else + ret = socket (domain, type, protocol); return ret; } From 567a638fc7aee31c9421159140b8e18b83a099b3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 19 Aug 2015 21:22:17 -0400 Subject: [PATCH 0809/1342] vtysh: Add missing show thread/work-queues commands 'show thread cpu ..' and 'show work-queues' are missing from vtysh, but are available from telnet. This commit adds these commands to the vtysh interface. Signed-off-by: Donald Sharp --- vtysh/vtysh.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 04ac55094..91791e2de 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1349,6 +1349,52 @@ ALIAS (vtysh_exit_interface, "quit", "Exit current mode and down to previous mode\n") +DEFUN (vtysh_show_thread, + vtysh_show_thread_cmd, + "show thread cpu [FILTER]", + SHOW_STR + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtexb)\n") +{ + unsigned int i; + int ret = CMD_SUCCESS; + char line[100]; + + sprintf(line, "show thread cpu %s\n", (argc == 1) ? argv[0] : ""); + for (i = 0; i < array_size(vtysh_client); i++) + if ( vtysh_client[i].fd >= 0 ) + { + fprintf (stdout, "Thread statistics for %s:\n", + vtysh_client[i].name); + ret = vtysh_client_execute (&vtysh_client[i], line, stdout); + fprintf (stdout,"\n"); + } + return ret; +} + +DEFUN (vtysh_show_work_queues, + vtysh_show_work_queues_cmd, + "show work-queues", + SHOW_STR + "Work Queue information\n") +{ + unsigned int i; + int ret = CMD_SUCCESS; + char line[] = "show work-queues\n"; + + for (i = 0; i < array_size(vtysh_client); i++) + if ( vtysh_client[i].fd >= 0 ) + { + fprintf (stdout, "Work queue statistics for %s:\n", + vtysh_client[i].name); + ret = vtysh_client_execute (&vtysh_client[i], line, stdout); + fprintf (stdout,"\n"); + } + + return ret; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2450,6 +2496,12 @@ vtysh_init_vty (void) install_element (VIEW_NODE, &vtysh_show_memory_cmd); install_element (ENABLE_NODE, &vtysh_show_memory_cmd); + install_element (VIEW_NODE, &vtysh_show_work_queues_cmd); + install_element (ENABLE_NODE, &vtysh_show_work_queues_cmd); + + install_element (VIEW_NODE, &vtysh_show_thread_cmd); + install_element (ENABLE_NODE, &vtysh_show_thread_cmd); + /* Logging */ install_element (ENABLE_NODE, &vtysh_show_logging_cmd); install_element (VIEW_NODE, &vtysh_show_logging_cmd); From 8965be4baaa1a4c619cbb4a8a10d15a72d80b60d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 4 Sep 2015 14:21:23 -0400 Subject: [PATCH 0810/1342] vtysh: allow --with-libpam to build with --enable-werror The function vtysh_pam fails the build with --enable-werror enabled because it is a static function not declared as such Signed-off-by: Donald Sharp --- vtysh/vtysh_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index e1c611cee..7e10d68ed 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -46,7 +46,7 @@ static struct pam_conv conv = NULL }; -int +static int vtysh_pam (const char *user) { int ret; From 8ccd74c29f5242f312c1e0561497558482c9be65 Mon Sep 17 00:00:00 2001 From: Hiroshi Yokoi Date: Tue, 8 Sep 2015 11:52:20 +0900 Subject: [PATCH 0811/1342] zebra: fix addr sent in ZEBRA_IPV6_NEXTHOP_LOOKUP I found that zebra doesn't set correct IPv6 address in its result because of using *addr's address. Although I'm using 0.99.22, the latest version has also use "&addr". Shouldn't it use "addr"? Signed-off-by: Hiroshi Yokoi Acked-by: Donald Sharp --- zebra/zserv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index 8ca561565..e26c8cac8 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -490,7 +490,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, /* Fill in result. */ zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, vrf_id); - stream_put (s, &addr, 16); + stream_put (s, addr, 16); if (rib) { From 782c882077b5a63213b3d160535d5e8259f6df61 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 14 Sep 2015 13:29:37 -0400 Subject: [PATCH 0812/1342] zebra: rib->nexthop_num is double incremented While reading linux kernel netlink messages, rib->nexthop_num is incremented in the read loop as well as the underlying nexthop_add() function call. This number should only be incremented in one spot. Removing the increment from the read loop and allowing the underlying code to track this data as it is already. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 33fbc0805..cbcbe7c56 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -765,7 +765,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; - rib->nexthop_num++; index = rtnh->rtnh_ifindex; gate = 0; if (rtnh->rtnh_len > sizeof (*rtnh)) @@ -968,7 +967,6 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; - rib->nexthop_num++; index = rtnh->rtnh_ifindex; gate = 0; if (rtnh->rtnh_len > sizeof (*rtnh)) From 26b663da7ea8a3efae816d6e7fda293bdc1082f5 Mon Sep 17 00:00:00 2001 From: Morgan Stewart Date: Wed, 16 Sep 2015 13:17:54 -0400 Subject: [PATCH 0813/1342] zebra: Fix leaked sockets in rtadv.c Coverity Scan #709790 In zebra/rtadv.c: rtadv_make_socket leaks socket for error cases. Added lines to close the socket for each error case or return. Signed-off-by: Morgan Stewart --- zebra/rtadv.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index be4aeb1b1..f5d5b4ade 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -534,23 +534,41 @@ rtadv_make_socket (vrf_id_t vrf_id) /* When we can't make ICMPV6 socket simply back. Router advertisement feature will not be supported. */ if (sock < 0) - return -1; + { + close (sock); + return -1; + } ret = setsockopt_ipv6_pktinfo (sock, 1); if (ret < 0) - return ret; + { + close (sock); + return ret; + } ret = setsockopt_ipv6_multicast_loop (sock, 0); if (ret < 0) - return ret; + { + close (sock); + return ret; + } ret = setsockopt_ipv6_unicast_hops (sock, 255); if (ret < 0) - return ret; + { + close (sock); + return ret; + } ret = setsockopt_ipv6_multicast_hops (sock, 255); if (ret < 0) - return ret; + { + close (sock); + return ret; + } ret = setsockopt_ipv6_hoplimit (sock, 1); if (ret < 0) - return ret; + { + close (sock); + return ret; + } ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter); From 44d03fd59eb7c9f83afcfbafbe014c95e0a8f539 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 8 Sep 2015 15:02:07 -0400 Subject: [PATCH 0814/1342] pimd: Fix leaked fd When caling pim_sock_open if the failure cause happens, however unlikely, don't leak the fd on failure. Signed-off-by: Donald Sharp --- pimd/pim_pim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 41c26a888..cd8a29031 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -371,6 +371,7 @@ static int pim_sock_open(struct in_addr ifaddr, int ifindex) return -1; if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) { + close(fd); return -2; } From e472b8a5141b91a4bb50f8ff55540cd601321572 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 8 Sep 2015 15:19:55 -0400 Subject: [PATCH 0815/1342] pimd: Remove stdout zlog changes Quagga start has unnecessary pim messages to stdout. Causing some confusion. Logging is already saving this information in pimd.log Signed-off-by: Donald Sharp --- pimd/pim_main.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 63dd63648..95c1816f7 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -187,12 +187,6 @@ int main(int argc, char** argv, char** envp) { master = thread_master_create(); - /* - * Temporarily send zlog to stdout - */ - zlog_default->maxlvl[ZLOG_DEST_STDOUT] = zlog_default->default_lvl; - zlog_notice("Boot logging temporarily directed to stdout - begin"); - zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting", QUAGGA_VERSION, PIMD_VERSION); @@ -209,17 +203,7 @@ int main(int argc, char** argv, char** envp) { pim_init(); /* - * reset zlog default, then will obey configuration file - */ - zlog_notice("Boot logging temporarily directed to stdout - end"); -#if 0 - /* this would disable logging to stdout, but config has not been - loaded yet to reconfig the logging output */ - zlog_default->maxlvl[ZLOG_DEST_STDOUT] = ZLOG_DISABLED; -#endif - - /* - Initialize zclient "update" and "lookup" sockets + * Initialize zclient "update" and "lookup" sockets */ pim_zebra_init(zebra_sock_path); From 75daab1784f515104ceef747d134981ecee7b0af Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 24 Sep 2015 10:26:55 +0100 Subject: [PATCH 0816/1342] pimd: Fix compile warning (error with Werror) on BSD * ioctl commands can vary in type between systems, cast to an unsigned long before passing to format command. --- pimd/pim_cmd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 55545c15b..880edb9a8 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2344,8 +2344,11 @@ static void show_mroute_count(struct vty *vty) if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { int e = errno; vty_out(vty, - "ioctl(SIOCGETSGCNT=%d) failure for (S,G)=(%s,%s): errno=%d: %s%s", - SIOCGETSGCNT, + "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s%s", + /* note that typeof ioctl defs can vary across platforms, from + * int, to unsigned int, to long unsigned int + */ + (unsigned long)SIOCGETSGCNT, source_str, group_str, e, From c8394ace7081ef0e71f3d162067c83c2629fc088 Mon Sep 17 00:00:00 2001 From: Morgan Stewart Date: Thu, 17 Sep 2015 19:04:30 -0400 Subject: [PATCH 0817/1342] Fixed if_add_update possible null dereference Coverity Scan #1221454 In zebra/interface.c if_data could be null dereferenced without early check. Signed-off-by: Morgan Stewart Reviewed-by: Donald Sharp --- zebra/interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/interface.c b/zebra/interface.c index 14c3e78ae..162439fa6 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -368,6 +368,8 @@ if_add_update (struct interface *ifp) struct zebra_if *if_data; if_data = ifp->info; + assert(if_data); + if (if_data->multicast == IF_ZEBRA_MULTICAST_ON) if_set_flags (ifp, IFF_MULTICAST); else if (if_data->multicast == IF_ZEBRA_MULTICAST_OFF) From 1994dc81458d646120659b543ad7ffc023cd8579 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Thu, 17 Sep 2015 10:15:59 -0400 Subject: [PATCH 0818/1342] bgpd: If route-map does not exist DENY for redistribute statements Upon usage of a route-map statement in bgp, if the route-map does not exist it turns into a implicit ALLOW, this causes issues in a wide variety of scenarios. Without this fix: ! router bgp 100 bgp router-id 10.0.2.15 redistribute static route-map FOOEY ! ip route 33.33.33.33/32 eth1 ip route 44.44.44.44/32 eth1 ! Now look at show ip bgp: show ip bgp: Network Next Hop Metric LocPrf Weight Path *> 33.33.33.33/32 0.0.0.0 0 32768 ? *> 44.44.44.44/32 0.0.0.0 0 32768 ? With this fix: show ip bgp: Network Next Hop Metric LocPrf Weight Path Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp redist_metric[afi][type]; /* Apply route-map. */ - if (bgp->rmap[afi][type].map) + if (bgp->rmap[afi][type].name) { info.peer = bgp->peer_self; info.attr = &attr_new; From d3ac733b41b69826ac4b5a86b881f33f3d383941 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Mon, 24 Aug 2015 10:19:10 -0400 Subject: [PATCH 0819/1342] bgpd: 'set comm-list delete' stops as soon as it hits a community-list entry with a deny 'set comm-list delete' stops as soon as it hits a community-list entry with a deny Reviewed By: sharpd@cumulusnetworks.com Testing Done: 'set comm-list FOO delete' stops evaluating the community-list as soon as we hit the first "delete" statement. This makes it impossible to use community-lists where you deny some subset of communities to delete and then permit all of the others. This patch changes the behavior so that we no longer exit the community-list at the first delete statement. Here is our baseline, we are receiving multiple communities from 10.1.1.2 for the 10.1.3.0/24 prefix. qct-ly6-04# show ip bgp 10.1.3.0/24 BGP routing table entry for 10.1.3.0/24 Paths: (1 available, best #1, table Default-IP-Routing-Table) Not advertised to any peer Local 10.1.1.2 (metric 20) from 10.1.1.2 (10.1.1.2) Origin IGP, metric 0, localpref 100, valid, internal, best Community: 1:1 1:2 1:3 20:1 20:2 20:3 99:1 Last update: Wed Mar 4 13:50:36 2015 qct-ly6-04# We apply the following FOO route-map inbound to this peer and soft clear the peer ! ip community-list expanded BAD_COMMS permit 99:.* ip community-list expanded BAD_COMMS deny 1:.* ip community-list expanded BAD_COMMS permit 20.* ! route-map FOO permit 10 set comm-list BAD_COMMS delete ! router bgp 10 neighbor 10.1.1.2 route-map FOO in ! qct-ly6-04# clear ip bgp * soft in qct-ly6-04# show ip bgp 10.1.3.0/24 BGP routing table entry for 10.1.3.0/24 Paths: (1 available, best #1, table Default-IP-Routing-Table) Not advertised to any peer Local 10.1.1.2 (metric 20) from 10.1.1.2 (10.1.1.2) Origin IGP, metric 0, localpref 100, valid, internal, best Community: 1:1 1:2 1:3 Last update: Wed Mar 4 13:51:12 2015 qct-ly6-04# qct-ly6-04# We deleted all communities flagged as "permit" by the BAD_COMMS community-list while leaving the ones matched by "deny 1:.*" alone. #endif /* _QUAGGA_BGP_COMMUNITY_H */ 'set comm-list delete' stops as soon as it hits a community-list entry with a deny Ticket: CM-3513 Reviewed By: sharpd@cumulusnetworks.com Testing Done: 'set comm-list FOO delete' stops evaluating the community-list as soon as we hit the first "delete" statement. This makes it impossible to use community-lists where you deny some subset of communities to delete and then permit all of the others. This patch changes the behavior so that we no longer exit the community-list at the first delete statement. Here is our baseline, we are receiving multiple communities from 10.1.1.2 for the 10.1.3.0/24 prefix. qct-ly6-04# show ip bgp 10.1.3.0/24 BGP routing table entry for 10.1.3.0/24 Paths: (1 available, best #1, table Default-IP-Routing-Table) Not advertised to any peer Local 10.1.1.2 (metric 20) from 10.1.1.2 (10.1.1.2) Origin IGP, metric 0, localpref 100, valid, internal, best Community: 1:1 1:2 1:3 20:1 20:2 20:3 99:1 Last update: Wed Mar 4 13:50:36 2015 qct-ly6-04# We apply the following FOO route-map inbound to this peer and soft clear the peer ! ip community-list expanded BAD_COMMS permit 99:.* ip community-list expanded BAD_COMMS deny 1:.* ip community-list expanded BAD_COMMS permit 20.* ! route-map FOO permit 10 set comm-list BAD_COMMS delete ! router bgp 10 neighbor 10.1.1.2 route-map FOO in ! qct-ly6-04# clear ip bgp * soft in qct-ly6-04# show ip bgp 10.1.3.0/24 BGP routing table entry for 10.1.3.0/24 Paths: (1 available, best #1, table Default-IP-Routing-Table) Not advertised to any peer Local 10.1.1.2 (metric 20) from 10.1.1.2 (10.1.1.2) Origin IGP, metric 0, localpref 100, valid, internal, best Community: 1:1 1:2 1:3 Last update: Wed Mar 4 13:51:12 2015 qct-ly6-04# qct-ly6-04# We deleted all communities flagged as "permit" by the BAD_COMMS community-list while leaving the ones matched by "deny 1:.*" alone. --- bgpd/bgp_clist.c | 212 ++++++++++++++++++++++++++++--------------- bgpd/bgp_community.c | 2 +- bgpd/bgp_community.h | 1 + 3 files changed, 139 insertions(+), 76 deletions(-) diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index b91ab81fa..db2cfa48d 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -330,6 +330,94 @@ community_list_entry_lookup (struct community_list *list, const void *arg, return NULL; } +static char * +community_str_get (struct community *com, int i) +{ + int len; + u_int32_t comval; + u_int16_t as; + u_int16_t val; + char *str; + char *pnt; + + memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); + comval = ntohl (comval); + + switch (comval) + { + case COMMUNITY_INTERNET: + len = strlen (" internet"); + break; + case COMMUNITY_NO_EXPORT: + len = strlen (" no-export"); + break; + case COMMUNITY_NO_ADVERTISE: + len = strlen (" no-advertise"); + break; + case COMMUNITY_LOCAL_AS: + len = strlen (" local-AS"); + break; + default: + len = strlen (" 65536:65535"); + break; + } + + /* Allocate memory. */ + str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len); + + switch (comval) + { + case COMMUNITY_INTERNET: + strcpy (pnt, "internet"); + pnt += strlen ("internet"); + break; + case COMMUNITY_NO_EXPORT: + strcpy (pnt, "no-export"); + pnt += strlen ("no-export"); + break; + case COMMUNITY_NO_ADVERTISE: + strcpy (pnt, "no-advertise"); + pnt += strlen ("no-advertise"); + break; + case COMMUNITY_LOCAL_AS: + strcpy (pnt, "local-AS"); + pnt += strlen ("local-AS"); + break; + default: + as = (comval >> 16) & 0xFFFF; + val = comval & 0xFFFF; + sprintf (pnt, "%u:%d", as, val); + pnt += strlen (pnt); + break; + } + + *pnt = '\0'; + + return str; +} + +/* Internal function to perform regular expression match for + * * a single community. */ +static int +community_regexp_include (regex_t * reg, struct community *com, int i) +{ + const char *str; + + /* When there is no communities attribute it is treated as empty + * string. */ + if (com == NULL || com->size == 0) + str = ""; + else + str = community_str_get (com, i); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + /* Internal function to perform regular expression match for community attribute. */ static int @@ -372,54 +460,6 @@ ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg) return 0; } -/* Delete community attribute using regular expression match. Return - modified communites attribute. */ -static struct community * -community_regexp_delete (struct community *com, regex_t * reg) -{ - int i; - u_int32_t comval; - /* Maximum is "65535:65535" + '\0'. */ - char c[12]; - const char *str; - - if (!com) - return NULL; - - i = 0; - while (i < com->size) - { - memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); - comval = ntohl (comval); - - switch (comval) - { - case COMMUNITY_INTERNET: - str = "internet"; - break; - case COMMUNITY_NO_EXPORT: - str = "no-export"; - break; - case COMMUNITY_NO_ADVERTISE: - str = "no-advertise"; - break; - case COMMUNITY_LOCAL_AS: - str = "local-AS"; - break; - default: - sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); - str = c; - break; - } - - if (regexec (reg, str, 0, NULL, 0) == 0) - community_del_val (com, com_nthval (com, i)); - else - i++; - } - return com; -} - /* When given community attribute matches to the community-list return 1 else return 0. */ int @@ -509,41 +549,63 @@ community_list_match_delete (struct community *com, struct community_list *list) { struct community_entry *entry; + u_int32_t val; + u_int32_t com_index_to_delete[com->size]; + int delete_index = 0; + int i; - for (entry = list->head; entry; entry = entry->next) + /* Loop over each community value and evaluate each against the + * community-list. If we need to delete a community value add its index to + * com_index_to_delete. + */ + for (i = 0; i < com->size; i++) { - if (entry->any) + val = community_val_get (com, i); + + for (entry = list->head; entry; entry = entry->next) { - if (entry->direct == COMMUNITY_PERMIT) + if (entry->any) { - /* This is a tricky part. Currently only - * route_set_community_delete() uses this function. In the - * function com->size is zero, it free the community - * structure. - */ - com->size = 0; + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; } - return com; - } - if ((entry->style == COMMUNITY_LIST_STANDARD) - && (community_include (entry->u.com, COMMUNITY_INTERNET) - || community_match (com, entry->u.com) )) - { + else if ((entry->style == COMMUNITY_LIST_STANDARD) + && (community_include (entry->u.com, COMMUNITY_INTERNET) + || community_include (entry->u.com, val) )) + { if (entry->direct == COMMUNITY_PERMIT) - community_delete (com, entry->u.com); - else - break; - } - else if ((entry->style == COMMUNITY_LIST_EXPANDED) - && community_regexp_match (com, entry->reg)) - { - if (entry->direct == COMMUNITY_PERMIT) - community_regexp_delete (com, entry->reg); - else - break; - } + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + + else if ((entry->style == COMMUNITY_LIST_EXPANDED) + && community_regexp_include (entry->reg, com, i)) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + } + } + + /* Delete all of the communities we flagged for deletion */ + for (i = delete_index-1; i >= 0; i--) + { + val = community_val_get (com, com_index_to_delete[i]); + community_del_val (com, &val); } + return com; } diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 1bd2dd84e..f1997bd9c 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -144,7 +144,7 @@ community_include (struct community *com, u_int32_t val) return 0; } -static u_int32_t +u_int32_t community_val_get (struct community *com, int i) { u_char *p; diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index 9e483770e..c73dab304 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -70,5 +70,6 @@ extern int community_include (struct community *, u_int32_t); extern void community_del_val (struct community *, u_int32_t *); extern unsigned long community_count (void); extern struct hash *community_hash (void); +extern u_int32_t community_val_get (struct community *com, int i); #endif /* _QUAGGA_BGP_COMMUNITY_H */ From ca8ec20b017393dbe91ff9e5ae2b7ff12872f869 Mon Sep 17 00:00:00 2001 From: Michael Rossberg Date: Tue, 29 Sep 2015 14:32:14 +0200 Subject: [PATCH 0820/1342] ospf6d: Fix for fast OSPF convergence Fixed use of OSPF_MIN_LS_ARRIVAL, which changed its unit from seconds to milliseconds --- ospf6d/ospf6_flood.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 49ed6e265..815db7b75 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -863,7 +863,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, struct timeval now, res; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &old->installed, &res); - if (res.tv_sec < OSPF_MIN_LS_ARRIVAL) + if (res.tv_sec < (OSPF_MIN_LS_ARRIVAL / 1000)) { if (is_debug) zlog_debug ("LSA can't be updated within MinLSArrival, discard"); From 3e71e369452c38c9c16a19d0edd40323e6b31023 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 21 Jun 2015 22:38:44 +0100 Subject: [PATCH 0821/1342] HACKING: rename to HACKING.md in prep for conversion to MarkDown --- HACKING.tex => HACKING.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename HACKING.tex => HACKING.md (100%) diff --git a/HACKING.tex b/HACKING.md similarity index 100% rename from HACKING.tex rename to HACKING.md From 67c3d75f5324b610352998c670f5f0cc4ba0ff2a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 21 Jun 2015 23:00:13 +0100 Subject: [PATCH 0822/1342] HACKING: Change format to MarkDown * HACKING: Converted initially from LaTeX to markdown with: 'pandoc -f latex -t markdown HACKING.tex' Then tweaked by hand to add a header with some suitable variables for the pandoc LaTeX template to make better use of the page space, and to add newpages so the title page is standalone as in the previous version. Also went through and reflowed paragraphs best as I could to make them match the previous document, to make it a little easier to verify nothing had been changed other than the markup, via diff. PDF can be generated with: 'pandoc -o HACKING.pdf HACKING.md' --- HACKING.md | 567 +++++++++++++++++++++++++---------------------------- 1 file changed, 267 insertions(+), 300 deletions(-) diff --git a/HACKING.md b/HACKING.md index be86ae18d..3a449da78 100644 --- a/HACKING.md +++ b/HACKING.md @@ -1,30 +1,26 @@ -%% -*- mode: text; -*- -%% $QuaggaId: Format:%an, %ai, %h$ $ - -\documentclass[oneside]{article} -\usepackage{parskip} -\usepackage[bookmarks,colorlinks=true]{hyperref} - -\title{Conventions for working on Quagga} - -\begin{document} -\maketitle - -This is a living document. Suggestions for updates, via the -\href{http://lists.quagga.net/mailman/listinfo/quagga-dev}{quagga-dev list}, -are welcome. - -\tableofcontents +--- +title: Conventions for working on Quagga +papersize: a4paper +geometry: scale=0.82 +fontsize: 11pt +toc: true +date: \today +include-before: + \large This is a living document. Suggestions for updates, via the + [quagga-dev list](http://lists.quagga.net/mailman/listinfo/quagga-dev), + are welcome. \newpage +... -\section{GUIDELINES FOR HACKING ON QUAGGA} -\label{sec:guidelines} +\newpage +GUIDELINES FOR HACKING ON QUAGGA {#sec:guidelines} +================================ GNU coding standards apply. Indentation follows the result of -invoking GNU indent (as of 2.2.8a) with the --nut argument. +invoking GNU indent (as of 2.2.8a) with the -–nut argument. Originally, tabs were used instead of spaces, with tabs are every 8 columns. -However, tab's interoperability issues mean space characters are now preferred for +However, tab’s interoperability issues mean space characters are now preferred for new changes. We generally only clean up whitespace when code is unmaintainable due to whitespace issues, to minimise merging conflicts. @@ -38,14 +34,14 @@ consequences. Each file in the Git repository should have a git format-placeholder (like an RCS Id keyword), somewhere very near the top, commented out appropriately -for the file type. The placeholder used for Quagga (replacing with -\$) is: +for the file type. The placeholder used for Quagga (replacing \ +with \$) is: - \verb|$QuaggaId: Format:%an, %ai, %h $| +`$QuaggaId: Format:%an, %ai, %h $` See line 2 of HACKING.tex, the source for this document, for an example. -This placeholder string will be expanded out by the `git archive' commands, +This placeholder string will be expanded out by the ‘git archive’ commands, which is used to generate the tar archives for snapshots and releases. Please document fully the proper use of a new function in the header file @@ -53,10 +49,9 @@ in which it is declared. And please consult existing headers for documentation on how to use existing functions. In particular, please consult these header files: -\begin{description} - \item{lib/log.h} logging levels and usage guidance - \item{[more to be added]} -\end{description} +lib/log.h logging levels and usage guidance + +[more to be added] If changing an exported interface, please try to deprecate the interface in an orderly manner. If at all possible, try to retain the old deprecated @@ -64,13 +59,11 @@ interface as is, or functionally equivalent. Make a note of when the interface was deprecated and guard the deprecated interface definitions in the header file, i.e.: -\begin{verbatim} -/* Deprecated: 20050406 */ -#if !defined(QUAGGA_NO_DEPRECATED_INTERFACES) -#warning "Using deprecated (interface(s)|function(s))" -... -#endif /* QUAGGA_NO_DEPRECATED_INTERFACES */ -\end{verbatim} + /* Deprecated: 20050406 */ + #if !defined(QUAGGA_NO_DEPRECATED_INTERFACES) + #warning "Using deprecated (interface(s)|function(s))" + ... + #endif /* QUAGGA_NO_DEPRECATED_INTERFACES */ This is to ensure that the core Quagga sources do not use the deprecated interfaces (you should update Quagga sources to use new interfaces, if @@ -78,167 +71,147 @@ applicable), while allowing external sources to continue to build. Deprecated interfaces should be excised in the next unstable cycle. Note: If you wish, you can test for GCC and use a function -marked with the 'deprecated' attribute. However, you must provide the +marked with the ’deprecated’ attribute. However, you must provide the warning for other compilers. -If changing or removing a command definition, \emph{ensure} that you +If changing or removing a command definition, *ensure* that you properly deprecate it - use the \_DEPRECATED form of the appropriate DEFUN -macro. This is \emph{critical}. Even if the command can no longer -function, you \emph{MUST} still implement it as a do-nothing stub. +macro. This is *critical*. Even if the command can no longer +function, you *MUST* still implement it as a do-nothing stub. Failure to follow this causes grief for systems administrators, as an upgrade may cause daemons to fail to start because of unrecognised commands. Deprecated commands should be excised in the next unstable cycle. A list of deprecated commands should be collated for each release. -See also section~\ref{sec:dll-versioning} below regarding SHARED LIBRARY +See also section [sec:dll-versioning] below regarding SHARED LIBRARY VERSIONING. -\section{YOUR FIRST CONTRIBUTIONS} +YOUR FIRST CONTRIBUTIONS +======================== Routing protocols can be very complex sometimes. Then, working with an Opensource community can be complex too, but usually friendly with anyone who is ready to be willing to do it properly. -\begin{itemize} +- First, start doing simple tasks. Quagga’s patchwork is a good place + to start with. Pickup some patches, apply them on your git trie, + review them and send your ack’t or review comments. Then, a + maintainer will apply the patch if ack’t or the author will have to + provide a new update. It help a lot to drain the patchwork queues. + See + +- The more you’ll review patches from patchwork, the more the Quagga’s + maintainers will be willing to consider some patches you will be + sending. - \item First, start doing simple tasks. Quagga's patchwork is a good place - to start with. Pickup some patches, apply them on your git trie, - review them and send your ack't or review comments. Then, a - maintainer will apply the patch if ack't or the author will - have to provide a new update. It help a lot to drain the - patchwork queues. - See \url{http://patchwork.quagga.net/project/quagga/list/} +- start using git clone, pwclient + - \item The more you'll review patches from patchwork, the more the - Quagga's maintainers will be willing to consider some patches you will - be sending. + $ pwclient list -s new + ID State Name + -- ----- ---- + 179 New [quagga-dev,6648] Re: quagga on FreeBSD 4.11 (gcc-2.95) + 181 New [quagga-dev,6660] proxy-arp patch + [...] - \item start using git clone, pwclient \url{http://patchwork.quagga.net/help/pwclient/} + $ pwclient git-am 1046 -\begin{verbatim} -$ pwclient list -s new -ID State Name --- ----- ---- -179 New [quagga-dev,6648] Re: quagga on FreeBSD 4.11 (gcc-2.95) -181 New [quagga-dev,6660] proxy-arp patch -[...] +HANDY GUIDELINES FOR MAINTAINERS +================================ -$ pwclient git-am 1046 -\end{verbatim} +Get your cloned trie: -\end{itemize} + git clone vjardin@git.sv.gnu.org:/srv/git/quagga.git -\section{HANDY GUIDELINES FOR MAINTAINERS} +Apply some ack’t patches: -Get your cloned trie: -\begin{verbatim} - git clone vjardin@git.sv.gnu.org:/srv/git/quagga.git -\end{verbatim} - -Apply some ack't patches: -\begin{verbatim} - pwclient git-am 1046 - Applying patch #1046 using 'git am' - Description: [quagga-dev,11595] zebra: route_unlock_node is missing in "show ip[v6] route " commands - Applying: zebra: route_unlock_node is missing in "show ip[v6] route " commands -\end{verbatim} - -Run a quick review. If the ack't was not done properly, you know who you have + pwclient git-am 1046 + Applying patch #1046 using 'git am' + Description: [quagga-dev,11595] zebra: route_unlock_node is missing in "show ip[v6] route " commands + Applying: zebra: route_unlock_node is missing in "show ip[v6] route " commands + +Run a quick review. If the ack’t was not done properly, you know who you have to blame. Push the patches: -\begin{verbatim} - git push -\end{verbatim} + + git push Set the patch to accepted on patchwork -\begin{verbatim} - pwclient update -s Accepted 1046 -\end{verbatim} -\section{COMPILE-TIME CONDITIONAL CODE} + pwclient update -s Accepted 1046 + +COMPILE-TIME CONDITIONAL CODE +============================= Please think very carefully before making code conditional at compile time, as it increases maintenance burdens and user confusion. In particular, -please avoid gratuitous --enable-\ldots switches to the configure script - -typically code should be good enough to be in Quagga, or it shouldn't be -there at all. +please avoid gratuitous -–enable-… switches to the configure script - +typically code should be good enough to be in Quagga, or it shouldn’t be +there at all. When code must be compile-time conditional, try have the compiler make it conditional rather than the C pre-processor - so that it will still be checked by the compiler, even if disabled. I.e. this: -\begin{verbatim} - if (SOME_SYMBOL) - frobnicate(); -\end{verbatim} + if (SOME_SYMBOL) + frobnicate(); rather than: -\begin{verbatim} - #ifdef SOME_SYMBOL - frobnicate (); - #endif /* SOME_SYMBOL */ -\end{verbatim} - -Note that the former approach requires ensuring that SOME\_SYMBOL will be -defined (watch your AC\_DEFINEs). + #ifdef SOME_SYMBOL + frobnicate (); + #endif /* SOME_SYMBOL */ +Note that the former approach requires ensuring that SOME\_SYMBOL will +be defined (watch your AC\_DEFINEs). -\section{COMMIT MESSAGES} +COMMIT MESSAGES +=============== The commit message requirements are: -\begin{itemize} +- The message *MUST* provide a suitable one-line summary followed by a + blank line as the very first line of the message, in the form: -\item The message \emph{MUST} provide a suitable one-line summary followed - by a blank line as the very first line of the message, in the form: + `topic: high-level, one line summary` - \verb|topic: high-level, one line summary| + Where topic would tend to be name of a subdirectory, and/or daemon, unless + there’s a more suitable topic (e.g. ’build’). This topic is used to + organise change summaries in release announcements. - Where topic would tend to be name of a subdirectory, and/or daemon, unless - there's a more suitable topic (e.g. 'build'). This topic is used to - organise change summaries in release announcements. +- It should have a suitable “bodyâ€, which tries to address the + following areas, so as to help reviewers and future browsers of the + code-base understand why the change is correct (note also the code + comment requirements): -\item It should have a suitable "body", which tries to address the - following areas, so as to help reviewers and future browsers of the - code-base understand why the change is correct (note also the code - comment requirements): - - \begin{itemize} - - \item The motivation for the change (does it fix a bug, if so which? + - The motivation for the change (does it fix a bug, if so which? add a feature?) - - \item The general approach taken, and trade-offs versus any other + + - The general approach taken, and trade-offs versus any other approaches. - - \item Any testing undertaken or other information affecting the confidence + + - Any testing undertaken or other information affecting the confidence that can be had in the change. - - \item Information to allow reviewers to be able to tell which specific + + - Information to allow reviewers to be able to tell which specific changes to the code are intended (and hence be able to spot any accidental unintended changes). - \end{itemize} -\end{itemize} - The one-line summary must be limited to 54 characters, and all other lines to 72 characters. Commit message bodies in the Quagga project have typically taken the following form: -\begin{itemize} -\item An optional introduction, describing the change generally. -\item A short description of each specific change made, preferably: - \begin{itemize} \item file by file - \begin{itemize} \item function by function (use of "ditto", or globs is - allowed) - \end{itemize} - \end{itemize} -\end{itemize} +- An optional introduction, describing the change generally. + +- A short description of each specific change made, preferably: + + - file by file + + - function by function (use of “dittoâ€, or globs is allowed) Contributors are strongly encouraged to follow this form. @@ -251,110 +224,109 @@ redundant. For longer patches, such a break-down may be essential. A contrived example (where the general discussion is obviously somewhat redundant, given the one-line summary): -\begin{quote}\begin{verbatim} -zebra: Enhance frob FSM to detect loss of frob - -Add a new DOWN state to the frob state machine to allow the barinator to -detect loss of frob. - -* frob.h: (struct frob) Add DOWN state flag. -* frob.c: (frob_change) set/clear DOWN appropriately on state change. -* bar.c: (barinate) Check frob for DOWN state. -\end{verbatim}\end{quote} +> zebra: Enhance frob FSM to detect loss of frob +> +> Add a new DOWN state to the frob state machine to allow the barinator to +> detect loss of frob. +> +> * frob.h: (struct frob) Add DOWN state flag. +> * frob.c: (frob_change) set/clear DOWN appropriately on state change. +> * bar.c: (barinate) Check frob for DOWN state. Please have a look at the git commit logs to get a feel for what the norms are. -Note that the commit message format follows git norms, so that ``git -log --oneline'' will have useful output. +Note that the commit message format follows git norms, so that “git log +–oneline†will have useful output. -\section{HACKING THE BUILD SYSTEM} +HACKING THE BUILD SYSTEM +======================== If you change or add to the build system (configure.ac, any Makefile.am, etc.), try to check that the following things still work: -\begin{itemize} -\item make dist -\item resulting dist tarball builds -\item out-of-tree builds -\end{itemize} +- make dist + +- resulting dist tarball builds + +- out-of-tree builds The quagga.net site relies on make dist to work to generate snapshots. It must work. Common problems are to forget to have some additional file included in the dist, or to have a make rule refer to a source file without using the srcdir variable. +RELEASE PROCEDURE +================= + +- Tag the appropriate commit with a release tag (follow existing + conventions). + + [This enables recreating the release, and is just good CM practice.] + +- Create a fresh tar archive of the quagga.net repository, and do a + test build: -\section{RELEASE PROCEDURE} + vim configure.ac + git commit -m "release: 0.99.99.99" + git tag -u 54CD2E60 quagga-0.99.99.99 + git push savannah tag quagga-0.99.99.99 -\begin{itemize} -\item Tag the appropriate commit with a release tag (follow existing - conventions). - - [This enables recreating the release, and is just good CM practice.] + git archive --prefix=quagga-release/ quagga-0.99.99.99 | tar xC /tmp + git log quagga-0.99.99.98..quagga-0.99.99.99 > \ + /tmp/quagga-release/quagga-0.99.99.99.changelog.txt + cd /tmp/quagga-release -\item Create a fresh tar archive of the quagga.net repository, and do a test - build: + autoreconf -i + ./configure + make + make dist-gzip - \begin{verbatim} - vim configure.ac - git commit -m "release: 0.99.99.99" - git tag -u 54CD2E60 quagga-0.99.99.99 - git push savannah tag quagga-0.99.99.99 + gunzip < quagga-0.99.99.99.tar.gz > quagga-0.99.99.99.tar + xz -6e < quagga-0.99.99.99.tar > quagga-0.99.99.99.tar.xz + gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar - git archive --prefix=quagga-release/ quagga-0.99.99.99 | tar xC /tmp - git log quagga-0.99.99.98..quagga-0.99.99.99 > \ - /tmp/quagga-release/quagga-0.99.99.99.changelog.txt - cd /tmp/quagga-release + scp quagga-0.99.99.99.* username@dl.sv.nongnu.org:/releases/quagga + - autoreconf -i - ./configure - make - make dist-gzip + Do NOT do this in a subdirectory of the Quagga sources, autoconf + will think it’s a sub-package and fail to include neccessary files. - gunzip < quagga-0.99.99.99.tar.gz > quagga-0.99.99.99.tar - xz -6e < quagga-0.99.99.99.tar > quagga-0.99.99.99.tar.xz - gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar +- Add the version number on https://bugzilla.quagga.net/, under + Administration, Products, “Quaggaâ€, Edit versions, Add a version. - scp quagga-0.99.99.99.* username@dl.sv.nongnu.org:/releases/quagga - \end{verbatim} +- Edit the wiki on + https://wiki.quagga.net/wiki/index.php/Release\_status - Do NOT do this in a subdirectory of the Quagga sources, autoconf will think - it's a sub-package and fail to include neccessary files. +- Post a news entry on Savannah -\item Add the version number on https://bugzilla.quagga.net/, under - Administration, Products, "Quagga", Edit versions, Add a version. -\item Edit the wiki on https://wiki.quagga.net/wiki/index.php/Release\_status -\item Post a news entry on Savannah -\item Send a mail to quagga-dev and quagga-users -\end{itemize} +- Send a mail to quagga-dev and quagga-users -The tarball which `make dist' creates is the tarball to be released! The -git-archive step ensures you're working with code corresponding to that in +The tarball which ‘make dist’ creates is the tarball to be released! The +git-archive step ensures you’re working with code corresponding to that in the official repository, and also carries out keyword expansion. If any errors occur, move tags as needed and start over from the fresh checkouts. Do not append to tarballs, as this has produced non-standards-conforming tarballs in the past. -See also: \url{http://wiki.quagga.net/index.php/Main/Processes} +See also: -[TODO: collation of a list of deprecated commands. Possibly can be scripted -to extract from vtysh/vtysh\_cmd.c] +[TODO: collation of a list of deprecated commands. Possibly can be +scripted to extract from vtysh/vtysh\_cmd.c] - -\section{TOOL VERSIONS} +TOOL VERSIONS +============= Require versions of support tools are listed in INSTALL.quagga.txt. Required versions should only be done with due deliberation, as it can cause environments to no longer be able to compile quagga. +SHARED LIBRARY VERSIONING {#sec:dll-versioning} +========================= -\section{SHARED LIBRARY VERSIONING} -\label{sec:dll-versioning} - -[this section is at the moment just gdt's opinion] +[this section is at the moment just gdt’s opinion] -Quagga builds several shared libaries (lib/libzebra, ospfd/libospf, +Quagga builds several shared libaries (lib/libzebra, ospfd/libospf, ospfclient/libsopfapiclient). These may be used by external programs, e.g. a new routing protocol that works with the zebra daemon, or ospfapi clients. The libtool info pages (node Versioning) explain @@ -372,162 +344,157 @@ There is no support intended for installing part of zebra. The core library libzebra and the included daemons should always be built and installed together. - -\section{GIT COMMIT SUBMISSION} -\label{sec:git-submission} +GIT COMMIT SUBMISSION {#sec:git-submission} +===================== The preferred method for submitting changes is to provide git commits via a publicly-accessible git repository, which the maintainers can easily pull. The commits should be in a branch based off the Quagga.net master - a -"feature branch". Ideally there should be no commits to this branch other +“feature branchâ€. Ideally there should be no commits to this branch other than those in master, and those intended to be submitted. However, merge commits to this branch from the Quagga master are permitted, though strongly discouraged - use another (potentially local and throw-away) branch to test merge with the latest Quagga master. Recommended practice is to keep different logical sets of changes on -separate branches - "topic" or "feature" branches. This allows you to still -merge them together to one branch (potentially local and/or "throw-away") +separate branches - “topic†or “feature†branches. This allows you to still +merge them together to one branch (potentially local and/or “throw-awayâ€) for testing or use, while retaining smaller, independent branches that are easier to merge. -All content guidelines in section \ref{sec:patch-submission}, PATCH +All content guidelines in section [sec:patch-submission], PATCH SUBMISSION apply. +PATCH SUBMISSION {#sec:patch-submission} +================ -\section{PATCH SUBMISSION} -\label{sec:patch-submission} - -\begin{itemize} - -\item For complex changes, contributors are strongly encouraged to first - start a design discussion on the quagga-dev list \emph{before} - starting any coding. - -\item Send a clean diff against the 'master' branch of the quagga.git - repository, in unified diff format, preferably with the '-p' argument to - show C function affected by any chunk, and with the -w and -b arguments to - minimise changes. E.g: +- For complex changes, contributors are strongly encouraged to first + start a design discussion on the quagga-dev list *before* starting + any coding. - git diff -up mybranch..remotes/quagga.net/master +- Send a clean diff against the ’master’ branch of the quagga.git + repository, in unified diff format, preferably with the ’-p’ + argument to show C function affected by any chunk, and with the -w + and -b arguments to minimise changes. E.g: - It is preferable to use git format-patch, and even more preferred to - publish a git repository (see GIT COMMIT SUBMISSION, section - \ref{sec:git-submission}). + git diff -up mybranch..remotes/quagga.net/master - If not using git format-patch, Include the commit message in the email. + It is preferable to use git format-patch, and even more preferred to + publish a git repository (see GIT COMMIT SUBMISSION, section + [sec:git-submission]). -\item After a commit, code should have comments explaining to the reviewer - why it is correct, without reference to history. The commit message - should explain why the change is correct. + If not using git format-patch, Include the commit message in the + email. -\item Include NEWS entries as appropriate. +- After a commit, code should have comments explaining to the reviewer + why it is correct, without reference to history. The commit message + should explain why the change is correct. -\item Include only one semantic change or group of changes per patch. +- Include NEWS entries as appropriate. -\item Do not make gratuitous changes to whitespace. See the w and b arguments - to diff. +- Include only one semantic change or group of changes per patch. -\item Changes should be arranged so that the least controversial and most - trivial are first, and the most complex or more controversial are - last. This will maximise how many the Quagga maintainers can merge, - even if some other commits need further work. +- Do not make gratuitous changes to whitespace. See the w and b + arguments to diff. -\item Providing a unit-test is strongly encouraged. Doing so will make it - much easier for maintainers to have confidence that they will be able - to support your change. +- Changes should be arranged so that the least controversial and most + trivial are first, and the most complex or more controversial are + last. This will maximise how many the Quagga maintainers can merge, + even if some other commits need further work. -\item New code should be arranged so that it easy to verify and test. E.g. - stateful logic should be separated out from functional logic as much as - possible: wherever possible, move complex logic out to smaller helper - functions which access no state other than their arguments. +- Providing a unit-test is strongly encouraged. Doing so will make it + much easier for maintainers to have confidence that they will be + able to support your change. -\item State on which platforms and with what daemons the patch has been - tested. Understand that if the set of testing locations is small, - and the patch might have unforeseen or hard to fix consequences that - there may be a call for testers on quagga-dev, and that the patch - may be blocked until test results appear. +- New code should be arranged so that it easy to verify and test. E.g. + stateful logic should be separated out from functional logic as much + as possible: wherever possible, move complex logic out to smaller + helper functions which access no state other than their arguments. - If there are no users for a platform on quagga-dev who are able and - willing to verify -current occasionally, that platform may be - dropped from the "should be checked" list. +- State on which platforms and with what daemons the patch has been + tested. Understand that if the set of testing locations is small, + and the patch might have unforeseen or hard to fix consequences that + there may be a call for testers on quagga-dev, and that the patch + may be blocked until test results appear. -\end{itemize} + If there are no users for a platform on quagga-dev who are able and + willing to verify -current occasionally, that platform may be + dropped from the “should be checked†list. -\section{PATCH APPLICATION} +PATCH APPLICATION +================= -\begin{itemize} +- Only apply patches that meet the submission guidelines. -\item Only apply patches that meet the submission guidelines. +- If the patch might break something, issue a call for testing on the + mailing-list. -\item If the patch might break something, issue a call for testing on the - mailing-list. +- Give an appropriate commit message (see above), and use the –author + argument to git-commit, if required, to ensure proper attribution + (you should still be listed as committer) -\item Give an appropriate commit message (see above), and use the --author - argument to git-commit, if required, to ensure proper attribution (you - should still be listed as committer) +- Immediately after commiting, double-check (with git-log and/or + gitk). If there’s a small mistake you can easily fix it with ‘git + commit –amend ..’ -\item Immediately after commiting, double-check (with git-log and/or gitk). - If there's a small mistake you can easily fix it with `git commit - --amend ..' +- When merging a branch, always use an explicit merge commit. Giving + –no-ff ensures a merge commit is created which documents “this human + decided to merge this branch at this timeâ€. -\item When merging a branch, always use an explicit merge commit. Giving - --no-ff ensures a merge commit is created which documents ``this human - decided to merge this branch at this time''. -\end{itemize} - -\section{STABLE PLATFORMS AND DAEMONS} +STABLE PLATFORMS AND DAEMONS +============================ The list of platforms that should be tested follow. This is a list derived from what quagga is thought to run on and for which maintainers can test or there are people on quagga-dev who are able and willing to verify that -current does or does not work correctly. -\begin{itemize} - \item BSD (Free, Net or Open, any platform) - \item GNU/Linux (any distribution, i386) - \item Solaris (strict alignment, any platform) - \item future: NetBSD/sparc64 -\end{itemize} +- BSD (Free, Net or Open, any platform) + +- GNU/Linux (any distribution, i386) + +- Solaris (strict alignment, any platform) + +- future: NetBSD/sparc64 The list of daemons that are thought to be stable and that should be tested are: -\begin{itemize} - \item zebra - \item bgpd - \item ripd - \item ospfd - \item ripngd -\end{itemize} +- zebra + +- bgpd + +- ripd + +- ospfd + +- ripngd + Daemons which are in a testing phase are -\begin{itemize} - \item ospf6d - \item isisd - \item watchquagga -\end{itemize} +- ospf6d -\section{IMPORT OR UPDATE VENDOR SPECIFIC ROUTING PROTOCOLS} +- isisd + +- watchquagga + +IMPORT OR UPDATE VENDOR SPECIFIC ROUTING PROTOCOLS +================================================== The source code of Quagga is based on two vendors: - \verb|zebra_org| (\url{http://www.zebra.org/}) - \verb|isisd_sf| (\url{http://isisd.sf.net/}) +`zebra_org` () `isisd_sf` +() To import code from further sources, e.g. for archival purposes without -necessarily having to review and/or fix some changeset, create a branch from -`master': +necessarily having to review and/or fix some changeset, create a branch +from ‘master’: -\begin{verbatim} - git checkout -b archive/foo master - - git commit -a "Joe Bar " - git push quagga archive/foo -\end{verbatim} + git checkout -b archive/foo master + + git commit -a "Joe Bar " + git push quagga archive/foo -presuming `quagga' corresponds to a file in your .git/remotes with +presuming ‘quagga’ corresponds to a file in your .git/remotes with configuration for the appropriate Quagga.net repository. - -\end{document} From 821df2cf18e5978cc7ab532a8695444380d08270 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 01:53:09 -0700 Subject: [PATCH 0823/1342] *: make sure zebra.h is always included first zebra.h pulls in config.h, which results in fiddling with things like __FILE_OFFSET_BITS. It must always be included first, in order to set flags that influence the compiler via . Signed-off-by: David Lamparter --- isisd/topology/random.c | 1 + isisd/topology/spacyc.c | 1 + isisd/topology/spgrid.c | 4 ++-- isisd/topology/sprand.c | 2 ++ lib/getopt.c | 4 ---- lib/getopt1.c | 4 ---- lib/stream.c | 2 +- lib/workqueue.c | 2 +- pimd/pim_cmd.c | 4 ++-- pimd/pim_igmp_join.c | 2 ++ pimd/pim_int.c | 2 ++ pimd/pim_signals.c | 3 ++- pimd/pim_sock.c | 2 +- pimd/pim_static.c | 2 ++ pimd/pim_str.c | 4 ++-- pimd/pim_time.c | 3 ++- pimd/pim_version.c | 2 ++ tests/prng.c | 2 ++ tests/test-cli.c | 2 ++ tests/test-timer-correctness.c | 4 ++-- tests/test-timer-performance.c | 5 +++-- 21 files changed, 34 insertions(+), 23 deletions(-) diff --git a/isisd/topology/random.c b/isisd/topology/random.c index c49c08202..2c457c52c 100644 --- a/isisd/topology/random.c +++ b/isisd/topology/random.c @@ -7,6 +7,7 @@ /* */ /*********************************************************************/ +#include #include #include diff --git a/isisd/topology/spacyc.c b/isisd/topology/spacyc.c index 853144737..91a4799ce 100644 --- a/isisd/topology/spacyc.c +++ b/isisd/topology/spacyc.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/isisd/topology/spgrid.c b/isisd/topology/spgrid.c index 40147fb5b..22cfa7ba4 100644 --- a/isisd/topology/spgrid.c +++ b/isisd/topology/spgrid.c @@ -1,11 +1,11 @@ +#include + #include #include #include #include "random.c" -#include - #include "thread.h" #include "vty.h" #include "log.h" diff --git a/isisd/topology/sprand.c b/isisd/topology/sprand.c index 28b58b30e..1c1eb1912 100644 --- a/isisd/topology/sprand.c +++ b/isisd/topology/sprand.c @@ -1,3 +1,5 @@ +#include + #include #include #include diff --git a/lib/getopt.c b/lib/getopt.c index 064909d31..7a58a8a8c 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -30,10 +30,6 @@ # define _NO_PROTO #endif -#ifdef HAVE_CONFIG_H -# include -#endif - #include #if !defined __STDC__ || !__STDC__ diff --git a/lib/getopt1.c b/lib/getopt1.c index fa766747a..bd3099e79 100644 --- a/lib/getopt1.c +++ b/lib/getopt1.c @@ -20,10 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include "getopt.h" diff --git a/lib/stream.c b/lib/stream.c index 9c26fea88..ca1a40f16 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -20,8 +20,8 @@ * 02111-1307, USA. */ -#include #include +#include #include "stream.h" #include "memory.h" diff --git a/lib/workqueue.c b/lib/workqueue.c index 9fc89314e..b1a5d5bfe 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -21,7 +21,7 @@ * 02111-1307, USA. */ -#include +#include #include "thread.h" #include "memory.h" #include "workqueue.h" diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 880edb9a8..69c04ec70 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -20,10 +20,10 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ -#include - #include +#include + #include "command.h" #include "if.h" #include "prefix.h" diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c index 693a42b75..b48adb755 100644 --- a/pimd/pim_igmp_join.c +++ b/pimd/pim_igmp_join.c @@ -20,6 +20,8 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include #include #include diff --git a/pimd/pim_int.c b/pimd/pim_int.c index 0bdd772ff..208075190 100644 --- a/pimd/pim_int.c +++ b/pimd/pim_int.c @@ -20,6 +20,8 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include #include #include diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c index d1350b08b..dcf4922d6 100644 --- a/pimd/pim_signals.c +++ b/pimd/pim_signals.c @@ -20,9 +20,10 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include -#include #include "sigevent.h" #include "memory.h" #include "log.h" diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 4816c567e..09b66505f 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -20,6 +20,7 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include #include "pim_mroute.h" #include @@ -31,7 +32,6 @@ #include #include -#include #include "log.h" #include "privs.h" diff --git a/pimd/pim_static.c b/pimd/pim_static.c index f2b8e856b..3ab5011bc 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -20,6 +20,8 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include "pim_static.h" #include "pim_time.h" #include "pim_str.h" diff --git a/pimd/pim_str.c b/pimd/pim_str.c index af5a184d2..3a8353cd8 100644 --- a/pimd/pim_str.c +++ b/pimd/pim_str.c @@ -20,12 +20,12 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include #include #include -#include - #include "log.h" #include "pim_str.h" diff --git a/pimd/pim_time.c b/pimd/pim_time.c index 097b470ba..4e5832cc6 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -20,11 +20,12 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include #include #include -#include #include "log.h" #include "thread.h" diff --git a/pimd/pim_version.c b/pimd/pim_version.c index fe7e56343..f3a5ee335 100644 --- a/pimd/pim_version.c +++ b/pimd/pim_version.c @@ -20,6 +20,8 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include + #include "pim_version.h" const char * const PIMD_VERSION = PIMD_VERSION_STR; diff --git a/tests/prng.c b/tests/prng.c index 8d78ea523..bdcfb07af 100644 --- a/tests/prng.c +++ b/tests/prng.c @@ -23,6 +23,8 @@ * 02111-1307, USA. */ +#include + #include #include #include diff --git a/tests/test-cli.c b/tests/test-cli.c index 3db44eec8..6fab6d52c 100644 --- a/tests/test-cli.c +++ b/tests/test-cli.c @@ -20,6 +20,8 @@ * 02111-1307, USA. */ +#include + #include "common-cli.h" DUMMY_DEFUN(cmd0, "arg ipv4 A.B.C.D"); diff --git a/tests/test-timer-correctness.c b/tests/test-timer-correctness.c index 47c0b7376..e523929be 100644 --- a/tests/test-timer-correctness.c +++ b/tests/test-timer-correctness.c @@ -23,11 +23,11 @@ * 02111-1307, USA. */ +#include + #include #include -#include - #include "memory.h" #include "pqueue.h" #include "prng.h" diff --git a/tests/test-timer-performance.c b/tests/test-timer-performance.c index a529a5ce0..ee45ede6a 100644 --- a/tests/test-timer-performance.c +++ b/tests/test-timer-performance.c @@ -22,11 +22,12 @@ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ -#include -#include #include +#include +#include + #include "thread.h" #include "pqueue.h" #include "prng.h" From 089e5eb7310683be6806726dbf7b7c94b1b66bfb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:03:36 -0700 Subject: [PATCH 0824/1342] build/solaris: drop duplicate __EXTENSION__ define __EXTENSION__ is already defined in config.h by autoconf; drop the duplicate from zebra.h. Signed-off-by: David Lamparter --- lib/zebra.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/zebra.h b/lib/zebra.h index 1ee5107e0..fe34be78a 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -27,7 +27,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifdef SUNOS_5 #define _XPG4_2 -#define __EXTENSIONS__ typedef unsigned int u_int32_t; typedef unsigned short u_int16_t; typedef unsigned char u_int8_t; From ce93c34d51ea30d1ba4f699af5601502bbbbcdf8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:11:45 -0700 Subject: [PATCH 0825/1342] ospfd: fix unused warning in ospf_write Signed-off-by: David Lamparter --- ospfd/ospf_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 73111e87b..9a8f1d611 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -644,8 +644,8 @@ ospf_write (struct thread *thread) struct listnode *node; #ifdef WANT_OSPF_WRITE_FRAGMENT static u_int16_t ipid = 0; -#endif /* WANT_OSPF_WRITE_FRAGMENT */ u_int16_t maxdatasize; +#endif /* WANT_OSPF_WRITE_FRAGMENT */ #define OSPF_WRITE_IPHL_SHIFT 2 ospf->t_write = NULL; @@ -659,7 +659,6 @@ ospf_write (struct thread *thread) /* seed ipid static with low order bits of time */ if (ipid == 0) ipid = (time(NULL) & 0xffff); -#endif /* WANT_OSPF_WRITE_FRAGMENT */ /* convenience - max OSPF data per packet, * and reliability - not more data, than our @@ -667,6 +666,7 @@ ospf_write (struct thread *thread) */ maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - sizeof (struct ip); +#endif /* WANT_OSPF_WRITE_FRAGMENT */ /* Get one packet from queue. */ op = ospf_fifo_head (oi->obuf); From a4065069e6bdd0bc7475312530b0e9457f818e0d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:12:23 -0700 Subject: [PATCH 0826/1342] ospf6d: fix uninitialized warning in SNMP Signed-off-by: David Lamparter --- ospf6d/ospf6_snmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index ef44e4c94..307d420ec 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -628,7 +628,7 @@ ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int len; oid *offset; int offsetlen; - struct ospf6_area *oa; + struct ospf6_area *oa = NULL; struct listnode *node; struct interface *iif; struct ospf6_interface *oi = NULL; From cbc3f5232af5cacd6f88f2124c864bb91e851cde Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:18:23 -0700 Subject: [PATCH 0827/1342] pimd: use IPPROTO_IP (not SOL_IP) for IP_PKTINFO Solaris uses the same socket API for IP_PKTINFO as Linux, but doesn't have a SOL_IP define. Signed-off-by: David Lamparter --- pimd/pim_sock.c | 6 +++--- pimd/pim_ssmpingd.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 09b66505f..2bb48f75a 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -80,9 +80,9 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) - /* Linux IP_PKTINFO */ + /* Linux and Solaris IP_PKTINFO */ int opt = 1; - if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { + if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); } @@ -306,7 +306,7 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, cmsg = CMSG_NXTHDR(&msgh,cmsg)) { #ifdef HAVE_IP_PKTINFO - if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { + if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg); if (to) ((struct sockaddr_in *) to)->sin_addr = i->ipi_addr; diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index 82e0722a7..d564bf57b 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -110,9 +110,9 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl) /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) - /* Linux IP_PKTINFO */ + /* Linux and Solaris IP_PKTINFO */ int opt = 1; - if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { + if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } From d8d5c60ecfab4dd609a07b4baa00d735f59002b9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:19:46 -0700 Subject: [PATCH 0828/1342] build: make libraries self-reliant libospf and libospfclient both need libzebra, so they should link against it. The days of libtool propagating upwards such dependencies are nearing their end... Signed-off-by: David Lamparter --- ospfclient/Makefile.am | 1 + ospfd/Makefile.am | 1 + 2 files changed, 2 insertions(+) diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index 8a3ad2162..1fca431a1 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -5,6 +5,7 @@ AM_CFLAGS = $(WERROR) lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 +libospfapiclient_la_LIBADD = ../ospfd/libospf.la ../lib/libzebra.la sbin_PROGRAMS = ospfclient diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 40f2cfe55..f21f50792 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -7,6 +7,7 @@ INSTALL_SDATA=@INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 +libospf_la_LIBADD = ../lib/libzebra.la sbin_PROGRAMS = ospfd From 12bbd62112724483f72c4040a4c4b585aff8eb54 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:26:44 -0700 Subject: [PATCH 0829/1342] lib: add getgrouplist() for Solaris Of course Solaris doesn't have getgrouplist()... Signed-off-by: David Lamparter --- configure.ac | 2 +- lib/privs.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 747a0c610..3003e6277 100755 --- a/configure.ac +++ b/configure.ac @@ -792,7 +792,7 @@ AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \ strtol strtoul strlcat strlcpy \ daemon snprintf vsnprintf \ if_nametoindex if_indextoname getifaddrs \ - uname fcntl]) + uname fcntl getgrouplist]) AC_CHECK_FUNCS(setproctitle, , [AC_CHECK_LIB(util, setproctitle, diff --git a/lib/privs.c b/lib/privs.c index ff0be2fe1..0ca8783dc 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -622,6 +622,41 @@ zprivs_state_null (void) return zprivs_null_state; } +#ifndef HAVE_GETGROUPLIST +/* Solaris 11 has no getgrouplist() */ +static int +getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) +{ + struct group *grp; + size_t usridx; + int pos = 0, ret; + + if (pos < *ngroups) + groups[pos] = group; + pos++; + + setgrent(); + while ((grp = getgrent())) + { + if (grp->gr_gid == group) + continue; + for (usridx = 0; grp->gr_mem[usridx] != NULL; usridx++) + if (!strcmp (grp->gr_mem[usridx], user)) + { + if (pos < *ngroups) + groups[pos] = grp->gr_gid; + pos++; + break; + } + } + endgrent(); + + ret = (pos <= *ngroups) ? pos : -1; + *ngroups = pos; + return ret; +} +#endif /* HAVE_GETGROUPLIST */ + void zprivs_init(struct zebra_privs_t *zprivs) { From 285ed0c62af4f57902d5deacc621f290fdeec276 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:46:53 -0700 Subject: [PATCH 0830/1342] build/solaris: create ioctl_solaris.h Signed-off-by: David Lamparter --- zebra/Makefile.am | 3 ++- zebra/if_ioctl_solaris.c | 3 +-- zebra/ioctl_solaris.c | 1 + zebra/ioctl_solaris.h | 29 +++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 zebra/ioctl_solaris.h diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 01779c9b3..96dc6f035 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -39,7 +39,8 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ - rt_netlink.h zebra_fpm.h zebra_fpm_private.h + rt_netlink.h zebra_fpm.h zebra_fpm_private.h \ + ioctl_solaris.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 3f33f749a..d54ed6a02 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -33,10 +33,9 @@ #include "vrf.h" #include "zebra/interface.h" +#include "zebra/ioctl_solaris.h" #include "zebra/rib.h" -void lifreq_set_name (struct lifreq *, const char *); -int if_get_flags_direct (const char *, uint64_t *, unsigned int af); static int if_get_addr (struct interface *, struct sockaddr *, const char *); static void interface_info_ioctl (struct interface *); extern struct zebra_privs_t zserv_privs; diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index 16934f063..82e39bea4 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -32,6 +32,7 @@ #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/interface.h" +#include "zebra/ioctl_solaris.h" extern struct zebra_privs_t zserv_privs; diff --git a/zebra/ioctl_solaris.h b/zebra/ioctl_solaris.h new file mode 100644 index 000000000..188986be1 --- /dev/null +++ b/zebra/ioctl_solaris.h @@ -0,0 +1,29 @@ +/* + * Interface looking up by ioctl () on Solaris. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * 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 _ZEBRA_IF_IOCTL_SOLARIS_H +#define _ZEBRA_IF_IOCTL_SOLARIS_H + +void lifreq_set_name (struct lifreq *, const char *); +int if_get_flags_direct (const char *, uint64_t *, unsigned int af); + +#endif /* _ZEBRA_IF_IOCTL_SOLARIS_H */ From 6d9362274e8ba2d57ffe17aa735eb941ac3d5fbc Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 02:59:04 -0700 Subject: [PATCH 0831/1342] zebra/solaris: fix uninitialised vars Signed-off-by: David Lamparter --- zebra/ioctl_solaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index 82e39bea4..aa2b9a4e0 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -310,7 +310,7 @@ if_get_flags_direct (const char *ifname, uint64_t *flags, unsigned int af) void if_get_flags (struct interface *ifp) { - int ret4, ret6; + int ret4 = 0, ret6 = 0; uint64_t newflags = 0; uint64_t tmpflags; From 5181a0296687a6004dd00c7c0874886c9ff0bf60 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 03:00:09 -0700 Subject: [PATCH 0832/1342] *: fix in_addr initialisers Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 2 +- bgpd/bgp_snmp.c | 2 +- ospfd/ospf_snmp.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5c832edcd..3f0910319 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1804,7 +1804,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, /* same goes for as4_aggregator */ struct aspath *as4_path = NULL; as_t as4_aggregator = 0; - struct in_addr as4_aggregator_addr = { 0 }; + struct in_addr as4_aggregator_addr = { .s_addr = 0 }; /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 0f4aeec8b..6a578347f 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -121,7 +121,7 @@ oid bgp_oid [] = { BGP4MIB }; oid bgp_trap_oid [] = { BGP4MIB, 0 }; /* IP address 0.0.0.0. */ -static struct in_addr bgp_empty_addr = {0}; +static struct in_addr bgp_empty_addr = { .s_addr = 0 }; /* Hook functions. */ static u_char *bgpVersion (struct variable *, oid [], size_t *, int, diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 604766d82..163615337 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -213,7 +213,7 @@ oid ospf_oid [] = { OSPF2MIB }; oid ospf_trap_oid [] = { OSPF2MIB, 16, 2 }; /* Not reverse mappable! */ /* IP address 0.0.0.0. */ -static struct in_addr ospf_empty_addr = {0}; +static struct in_addr ospf_empty_addr = { .s_addr = 0 }; /* Hook functions. */ static u_char *ospfGeneralGroup (struct variable *, oid *, size_t *, From ba6cd587b4114528c8d6af439c4f49c7bb95a92b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 03:00:59 -0700 Subject: [PATCH 0833/1342] isisd/solaris: fix size_t confusions Signed-off-by: David Lamparter --- isisd/isis_dlpi.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index 0a82718d3..d16667e4e 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -174,7 +174,7 @@ dlpiok (int fd, t_uscalar_t oprim) dl_ok_ack_t *doa = (dl_ok_ack_t *)dlpi_ctl; retv = dlpirctl (fd); - if (retv < DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK || + if (retv < (ssize_t)DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK || doa->dl_correct_primitive != oprim) { return -1; @@ -196,7 +196,7 @@ dlpiinfo (int fd) /* Info_req uses M_PCPROTO. */ dlpisend (fd, &dir, sizeof (dir), NULL, 0, RS_HIPRI); retv = dlpirctl (fd); - if (retv < DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK) + if (retv < (ssize_t)DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK) return -1; else return retv; @@ -251,7 +251,7 @@ dlpibind (int fd) dlpisend (fd, &dbr, sizeof (dbr), NULL, 0, 0); retv = dlpirctl (fd); - if (retv < DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK) + if (retv < (ssize_t)DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK) return -1; else return 0; @@ -287,12 +287,13 @@ dlpiaddr (int fd, u_char *addr) dlpisend (fd, &dpar, sizeof (dpar), NULL, 0, 0); retv = dlpirctl (fd); - if (retv < DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_primitive != DL_PHYS_ADDR_ACK) + if (retv < (ssize_t)DL_PHYS_ADDR_ACK_SIZE + || dpaa->dl_primitive != DL_PHYS_ADDR_ACK) return -1; if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_addr_length != ETHERADDRL || - dpaa->dl_addr_offset + dpaa->dl_addr_length > retv) + dpaa->dl_addr_offset + dpaa->dl_addr_length > (size_t)retv) return -1; bcopy((char *)dpaa + dpaa->dl_addr_offset, addr, ETHERADDRL); @@ -403,8 +404,8 @@ open_dlpi_dev (struct isis_circuit *circuit) case DL_100BT: break; default: - zlog_warn ("%s: unexpected mac type on %s: %d", __func__, - circuit->interface->name, dia->dl_mac_type); + zlog_warn ("%s: unexpected mac type on %s: %lld", __func__, + circuit->interface->name, (long long)dia->dl_mac_type); close (fd); return ISIS_WARNING; } @@ -556,13 +557,13 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) return ISIS_WARNING; } - if (ctlbuf.len < DL_UNITDATA_IND_SIZE || + if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE || dui->dl_primitive != DL_UNITDATA_IND) return ISIS_WARNING; if (dui->dl_src_addr_length != ETHERADDRL + 2 || dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE || - dui->dl_src_addr_offset + dui->dl_src_addr_length > ctlbuf.len) + dui->dl_src_addr_offset + dui->dl_src_addr_length > (size_t)ctlbuf.len) return ISIS_WARNING; memcpy (ssnpa, (char *)dui + dui->dl_src_addr_offset + @@ -588,9 +589,9 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) int buflen; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; - if (buflen > sizeof (sock_buff)) + if ((size_t)buflen > sizeof (sock_buff)) { - zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than " + zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than " "output pdu size %d on circuit %s", sizeof (sock_buff), buflen, circuit->interface->name); return ISIS_WARNING; From fe56125bbcbc0c503ae6bd0b934a4940c4693b4f Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 15 Sep 2015 19:12:31 -0700 Subject: [PATCH 0834/1342] zebra/ioctl_solaris: Fix use of prefix2str in if_prefix_add/delete_ipv6 First argument of prefix2str pointed to ifc->address->prefix, but no prefix exists in address. Should have been ifc->address. Signed-off-by: Martin Winter --- zebra/ioctl_solaris.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index aa2b9a4e0..12737cbf0 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -411,7 +411,7 @@ if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) char addrbuf[PREFIX_STRLEN]; zlog_warn ("Can't set %s on interface %s", - prefix2str(ifc->address->prefix, addrbuf, sizeof(addrbuf)), + prefix2str(ifc->address, addrbuf, sizeof(addrbuf)), ifp->name); return 0; @@ -424,7 +424,7 @@ if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) char addrbuf[PREFIX_STRLEN]; zlog_warn ("Can't delete %s on interface %s", - prefix2str(ifc->address->prefix, addrbuf, sizeof(addrbuf)), + prefix2str(ifc->address, addrbuf, sizeof(addrbuf)), ifp->name); return 0; From a2b503131b188292ede08df99309bcbef4bd1a52 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 19:35:41 -0700 Subject: [PATCH 0835/1342] solaris: no ROUNDUP Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index fd0d8fd1b..16226868d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -70,6 +70,12 @@ extern struct zebra_t zebrad; #define ROUNDUP(a) RT_ROUNDUP(a) #endif /* defined(RT_ROUNDUP) */ +#if defined(SUNOS_5) +/* Solaris has struct sockaddr_in[6] definitions at 16 / 32 bytes size, + * so the whole concept doesn't really apply. */ +#define ROUNDUP(a) (a) +#endif + /* * If ROUNDUP has not yet been defined in terms of platform-provided * defines, attempt to cope with heuristics. From da1b7eaa0ac5d590818e1cde92a9807a2f0e07f2 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 20:36:20 -0700 Subject: [PATCH 0836/1342] solaris: more warnings fixed Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 16226868d..eded2bbd7 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -140,6 +140,8 @@ extern struct zebra_t zebrad; static inline void rta_copy (union sockunion *dest, caddr_t src) { int len; + if (!dest) + return; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN len = (((struct sockaddr *)src)->sa_len > sizeof (*dest)) ? sizeof (*dest) : ((struct sockaddr *)src)->sa_len ; @@ -154,8 +156,7 @@ rta_copy (union sockunion *dest, caddr_t src) { if ((RTMADDRS) & (RTA)) \ { \ int len = SAROUNDUP ((PNT)); \ - if ( ((DEST) != NULL) && \ - af_check (((struct sockaddr *)(PNT))->sa_family)) \ + if (af_check (((struct sockaddr *)(PNT))->sa_family)) \ rta_copy((DEST), (PNT)); \ (PNT) += len; \ } @@ -163,8 +164,7 @@ rta_copy (union sockunion *dest, caddr_t src) { if ((RTMADDRS) & (RTA)) \ { \ int len = SAROUNDUP ((PNT)); \ - if ((DEST) != NULL) \ - rta_copy((DEST), (PNT)); \ + rta_copy((DEST), (PNT)); \ (PNT) += len; \ } @@ -738,7 +738,9 @@ ifam_read (struct ifa_msghdr *ifam) /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) - SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); + { + SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); + } if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, @@ -1158,7 +1160,8 @@ rtmsg_debug (struct rt_msghdr *rtm) zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup (rtm_type_str, rtm->rtm_type)); rtm_flag_dump (rtm->rtm_flags); zlog_debug ("Kernel: message seq %d", rtm->rtm_seq); - zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs); + zlog_debug ("Kernel: pid %lld, rtm_addrs 0x%x", + (long long)rtm->rtm_pid, rtm->rtm_addrs); } /* This is pretty gross, better suggestions welcome -- mhandler */ From f90ce64d68cf0ad56ff0370338ec58c883a3448d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 20:58:29 -0700 Subject: [PATCH 0837/1342] isisd/isis_dlpi: Fix warning 'fd' may be used uninitialized. Init to -1 Signed-off-by: David Lamparter --- isisd/isis_dlpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index d16667e4e..b583d10a4 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -303,7 +303,7 @@ dlpiaddr (int fd, u_char *addr) static int open_dlpi_dev (struct isis_circuit *circuit) { - int fd, unit, retval; + int fd = -1, unit, retval; char devpath[MAXPATHLEN]; dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl; ssize_t acklen; From ebd2687a531a0f9b9449f6fcf7001f53afa99d02 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 21:40:31 -0700 Subject: [PATCH 0838/1342] zebra/rtread_getmsg: fix sign warnings Signed-off-by: David Lamparter --- zebra/rtread_getmsg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 7fb916ffa..5057358aa 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -156,13 +156,13 @@ route_read (struct zebra_vrf *zvrf) /* This is normal loop termination */ if (retval == 0 && - msgdata.len >= sizeof (struct T_optmgmt_ack) && + (size_t)msgdata.len >= sizeof (struct T_optmgmt_ack) && TLIack->PRIM_type == T_OPTMGMT_ACK && TLIack->MGMT_flags == T_SUCCESS && MIB2hdr->len == 0) break; - if (msgdata.len >= sizeof (struct T_error_ack) && + if ((size_t)msgdata.len >= sizeof (struct T_error_ack) && TLIerr->PRIM_type == T_ERROR_ACK) { zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", safe_strerror ((TLIerr->TLI_error == TSYSERR) @@ -174,7 +174,7 @@ route_read (struct zebra_vrf *zvrf) like what GateD does in this instance, but not critical yet. */ if (retval != MOREDATA || - msgdata.len < sizeof (struct T_optmgmt_ack) || + (size_t)msgdata.len < sizeof (struct T_optmgmt_ack) || TLIack->PRIM_type != T_OPTMGMT_ACK || TLIack->MGMT_flags != T_SUCCESS) { errno = ENOMSG; From 8fa1d027f23115dcb1c38b09c6e46edf5b8f7238 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 21:55:38 -0700 Subject: [PATCH 0839/1342] zebra/rt_socket: Fix warnings Fix warning about unused sin_masklen / sin6_masklen Signed-off-by: David Lamparter --- zebra/rt_socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index bf21ca955..a7ef45710 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -41,6 +41,7 @@ extern int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Adjust netmask socket length. Return value is a adjusted sin_len value. */ static int @@ -63,6 +64,7 @@ sin_masklen (struct in_addr mask) len--; return len; } +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Interface between zebra message and rtm message. */ static int @@ -244,6 +246,7 @@ kernel_delete_ipv4 (struct prefix *p, struct rib *rib) #ifdef HAVE_IPV6 +#ifdef SIN6_LEN /* Calculate sin6_len value for netmask socket value. */ static int sin6_masklen (struct in6_addr mask) @@ -266,6 +269,7 @@ sin6_masklen (struct in6_addr mask) return len; } +#endif /* SIN6_LEN */ /* Interface between zebra message and rtm message. */ static int @@ -368,6 +372,8 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.", nexthop_num, error); } +#else + (void)error; #endif nexthop_num++; From 7904509bdf9ec7fad3ac1aee763ae39e7c308c52 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 15 Sep 2015 22:09:30 -0700 Subject: [PATCH 0840/1342] zebra/if_ioctl_solaris: Make foo static make interface_ioctl_ioctl() and if_get_index() static Signed-off-by: David Lamparter --- zebra/if_ioctl_solaris.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index d54ed6a02..50b4aca62 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -40,7 +40,7 @@ static int if_get_addr (struct interface *, struct sockaddr *, const char *); static void interface_info_ioctl (struct interface *); extern struct zebra_privs_t zserv_privs; -int +static int interface_list_ioctl (int af) { int ret; @@ -209,7 +209,7 @@ interface_list_ioctl (int af) } /* Get interface's index by ioctl. */ -int +static int if_get_index (struct interface *ifp) { int ret; From fc1c114aab24fe47bc6a1976c1c602d507fa4e69 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 23 Sep 2015 21:13:58 -0700 Subject: [PATCH 0841/1342] pimd: Fix warning Fix long unsigned / unsigned mixup Signed-off-by: Martin Winter --- pimd/pim_static.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 3ab5011bc..e43c59a52 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -42,7 +42,7 @@ static struct static_route * static_route_alloc() s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route)); if (!s_route) { - zlog_err("PIM XCALLOC(%lu) failure", sizeof(*s_route)); + zlog_err("PIM XCALLOC(%u) failure", sizeof(*s_route)); return 0; } return s_route; From 9fb73e8790ab0e433686643bf245ee1f0e238b99 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 22 Sep 2015 11:13:12 -0400 Subject: [PATCH 0842/1342] vtysh: Allow display of individual daemons configs When executing a 'show run' or 'write terminal' you see the entire integrated config. You have no way of knowing what an individual daemon is going to write until after you do a write of config to disk if you are not using an integrated configuration. This change allows the end-user to do such a thing. Signed-off-by: Donald Sharp --- vtysh/vtysh.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 91791e2de..783c383c8 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1808,6 +1808,34 @@ DEFUN (vtysh_write_terminal, return CMD_SUCCESS; } +DEFUN (vtysh_write_terminal_daemon, + vtysh_write_terminal_daemon_cmd, + "write terminal (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|babeld)", + "Write running configuration to memory, network, or terminal\n" + "Write to terminal\n" + "For the zebra daemon\n" + "For the rip daemon\n" + "For the ripng daemon\n" + "For the ospf daemon\n" + "For the ospfv6 daemon\n" + "For the bgp daemon\n" + "For the isis daemon\n" + "For the babel daemon\n") +{ + unsigned int i; + int ret = CMD_SUCCESS; + + for (i = 0; i < array_size(vtysh_client); i++) + { + if (strcmp(vtysh_client[i].name, argv[0]) == 0) + break; + } + + ret = vtysh_client_execute(&vtysh_client[i], "show running-config\n", stdout); + + return ret; +} + DEFUN (vtysh_integrated_config, vtysh_integrated_config_cmd, "service integrated-vtysh-config", @@ -1926,6 +1954,20 @@ ALIAS (vtysh_write_terminal, SHOW_STR "Current operating configuration\n") +ALIAS (vtysh_write_terminal_daemon, + vtysh_show_running_config_daemon_cmd, + "show running-config (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|babeld)", + SHOW_STR + "Current operating configuration\n" + "For the zebra daemon\n" + "For the rip daemon\n" + "For the ripng daemon\n" + "For the ospf daemon\n" + "For the ospfv6 daemon\n" + "For the bgp daemon\n" + "For the isis daemon\n" + "For the babel daemon\n") + DEFUN (vtysh_terminal_length, vtysh_terminal_length_cmd, "terminal length <0-512>", @@ -2447,12 +2489,14 @@ vtysh_init_vty (void) install_element (CONFIG_NODE, &vtysh_interface_vrf_cmd); install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_cmd); + install_element (ENABLE_NODE, &vtysh_show_running_config_daemon_cmd); install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); install_element (ENABLE_NODE, &vtysh_write_file_cmd); install_element (ENABLE_NODE, &vtysh_write_cmd); /* "write terminal" command. */ install_element (ENABLE_NODE, &vtysh_write_terminal_cmd); + install_element (ENABLE_NODE, &vtysh_write_terminal_daemon_cmd); install_element (CONFIG_NODE, &vtysh_integrated_config_cmd); install_element (CONFIG_NODE, &no_vtysh_integrated_config_cmd); From fd1c1a133af47ae5533a5ed41b73ff62e7aa1058 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 22 Sep 2015 14:32:53 -0400 Subject: [PATCH 0843/1342] git: add (generated) cscope files to .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 48e6b38b9..e8de25237 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ build *.loT m4/*.m4 !m4/ax_sys_weak_alias.m4 - +cscope.* From 7125293d65d73a451ec203c8c1630c236171f5a3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 24 Sep 2015 09:25:19 -0400 Subject: [PATCH 0844/1342] lib: zclient.c remove extern struct thread_master * zclient.c depended upon link time inclusion of a extern struct thread_master *master. This is a violation of the namespace of the calling daemon. If a library needs the pointer pass it in and save it for future use. This code change also makes the zclient code consistent with the other lib functions that need to schedule work on your behalf Signed-off-by: Donald Sharp --- bgpd/bgp_nexthop.c | 2 +- bgpd/bgp_zebra.c | 4 ++-- bgpd/bgp_zebra.h | 2 +- bgpd/bgpd.c | 2 +- isisd/isis_main.c | 2 +- isisd/isis_zebra.c | 4 ++-- isisd/isis_zebra.h | 2 +- lib/zclient.c | 19 +++++++++---------- lib/zclient.h | 5 ++++- ospf6d/ospf6_zebra.c | 4 ++-- ospf6d/ospf6_zebra.h | 2 +- ospf6d/ospf6d.c | 2 +- ospfd/ospf_main.c | 2 +- ospfd/ospf_zebra.c | 4 ++-- ospfd/ospf_zebra.h | 2 +- pimd/pim_main.c | 2 +- pimd/pim_zebra.c | 4 ++-- pimd/pim_zebra.h | 2 +- pimd/pim_zlookup.c | 2 +- ripd/rip_main.c | 2 +- ripd/rip_zebra.c | 4 ++-- ripd/ripd.h | 2 +- ripngd/ripng_main.c | 2 +- ripngd/ripng_zebra.c | 4 ++-- ripngd/ripngd.h | 2 +- tests/bgp_mpath_test.c | 2 +- zebra/client_main.c | 4 +++- 27 files changed, 47 insertions(+), 43 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 20302e392..33de365e8 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1402,7 +1402,7 @@ bgp_config_write_scan_time (struct vty *vty) void bgp_scan_init (void) { - zlookup = zclient_new (); + zlookup = zclient_new (master); zlookup->sock = -1; zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 261635162..e534bee86 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1094,10 +1094,10 @@ bgp_zebra_connected (struct zclient *zclient) } void -bgp_zebra_init (void) +bgp_zebra_init (struct thread_master *master) { /* Set default values. */ - zclient = zclient_new (); + zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_BGP); zclient->zebra_connected = bgp_zebra_connected; zclient->router_id_update = bgp_router_id_update; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 80991930f..50f727df6 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -25,7 +25,7 @@ Boston, MA 02111-1307, USA. */ extern struct stream *bgp_nexthop_buf; -extern void bgp_zebra_init (void); +extern void bgp_zebra_init (struct thread_master *master); extern int bgp_if_update_all (void); extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, safi_t, int *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 006803729..af8bdb451 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5421,7 +5421,7 @@ bgp_init (void) bgp_vty_init (); /* Init zebra. */ - bgp_zebra_init (); + bgp_zebra_init (master); /* BGP inits. */ bgp_attr_init (); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index e1af71f7e..fba7b1017 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -339,7 +339,7 @@ main (int argc, char **argv, char **envp) /* create the global 'isis' instance */ isis_new (1); - isis_zebra_init (); + isis_zebra_init (master); /* parse config file */ /* this is needed three times! because we have interfaces before the areas */ diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 6d0c15711..8a7841758 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -602,9 +602,9 @@ isis_zebra_connected (struct zclient *zclient) } void -isis_zebra_init () +isis_zebra_init (struct thread_master *master) { - zclient = zclient_new (); + zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_ISIS); zclient->zebra_connected = isis_zebra_connected; zclient->router_id_update = isis_router_id_update_zebra; diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 889cd9b62..001147889 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -24,7 +24,7 @@ extern struct zclient *zclient; -void isis_zebra_init (void); +void isis_zebra_init (struct thread_master *); void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info); int isis_distribute_list_update (int routetype); diff --git a/lib/zclient.c b/lib/zclient.c index 0ce46fefd..bfff9a365 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -39,8 +39,6 @@ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; /* Prototype for event manager. */ static void zclient_event (enum event, struct zclient *); -extern struct thread_master *master; - const char *zclient_serv_path = NULL; /* This file local debug flag. */ @@ -48,7 +46,7 @@ int zclient_debug = 0; /* Allocate zclient structure. */ struct zclient * -zclient_new () +zclient_new (struct thread_master *master) { struct zclient *zclient; zclient = XCALLOC (MTYPE_ZCLIENT, sizeof (struct zclient)); @@ -56,6 +54,7 @@ zclient_new () zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); zclient->wb = buffer_new(0); + zclient->master = master; return zclient; } @@ -258,8 +257,8 @@ zclient_flush_data(struct thread *thread) return zclient_failed(zclient); break; case BUFFER_PENDING: - zclient->t_write = thread_add_write(master, zclient_flush_data, - zclient, zclient->sock); + zclient->t_write = thread_add_write (zclient->master, zclient_flush_data, + zclient, zclient->sock); break; case BUFFER_EMPTY: break; @@ -284,8 +283,8 @@ zclient_send_message(struct zclient *zclient) THREAD_OFF(zclient->t_write); break; case BUFFER_PENDING: - THREAD_WRITE_ON(master, zclient->t_write, - zclient_flush_data, zclient, zclient->sock); + THREAD_WRITE_ON (zclient->master, zclient->t_write, + zclient_flush_data, zclient, zclient->sock); break; } return 0; @@ -1092,7 +1091,7 @@ zclient_event (enum event event, struct zclient *zclient) case ZCLIENT_SCHEDULE: if (! zclient->t_connect) zclient->t_connect = - thread_add_event (master, zclient_connect, zclient, 0); + thread_add_event (zclient->master, zclient_connect, zclient, 0); break; case ZCLIENT_CONNECT: if (zclient->fail >= 10) @@ -1102,12 +1101,12 @@ zclient_event (enum event event, struct zclient *zclient) zclient->fail < 3 ? 10 : 60); if (! zclient->t_connect) zclient->t_connect = - thread_add_timer (master, zclient_connect, zclient, + thread_add_timer (zclient->master, zclient_connect, zclient, zclient->fail < 3 ? 10 : 60); break; case ZCLIENT_READ: zclient->t_read = - thread_add_read (master, zclient_read, zclient, zclient->sock); + thread_add_read (zclient->master, zclient_read, zclient, zclient->sock); break; } } diff --git a/lib/zclient.h b/lib/zclient.h index 3490b3209..aa935c125 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -40,6 +40,9 @@ /* Structure for the zebra client. */ struct zclient { + /* The thread master we schedule ourselves on */ + struct thread_master *master; + /* Socket to zebra daemon. */ int sock; @@ -132,7 +135,7 @@ struct zapi_ipv4 }; /* Prototypes of zebra client service functions. */ -extern struct zclient *zclient_new (void); +extern struct zclient *zclient_new (struct thread_master *); extern void zclient_init (struct zclient *, int); extern int zclient_start (struct zclient *); extern void zclient_stop (struct zclient *); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 951e11d24..d37e50898 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -578,10 +578,10 @@ ospf6_zebra_connected (struct zclient *zclient) } void -ospf6_zebra_init (void) +ospf6_zebra_init (struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new (); + zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_OSPF6); zclient->zebra_connected = ospf6_zebra_connected; zclient->router_id_update = ospf6_router_id_update_zebra; diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index a219450e5..05694d390 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -44,7 +44,7 @@ extern void ospf6_zebra_redistribute (int); extern void ospf6_zebra_no_redistribute (int); #define ospf6_zebra_is_redistribute(type) \ vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) -extern void ospf6_zebra_init (void); +extern void ospf6_zebra_init(struct thread_master *); extern int config_write_ospf6_debug_zebra (struct vty *vty); extern void install_element_ospf6_debug_zebra (void); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 3cdd5c116..c2baa314a 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1764,7 +1764,7 @@ ospf6_init (void) ospf6_area_init (); ospf6_interface_init (); ospf6_neighbor_init (); - ospf6_zebra_init (); + ospf6_zebra_init (master); ospf6_lsa_init (); ospf6_spf_init (); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 826fc9833..10565fe6f 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -298,7 +298,7 @@ main (int argc, char **argv) /* OSPFd inits. */ ospf_if_init (); - ospf_zebra_init (); + ospf_zebra_init (master); /* OSPF vty inits. */ ospf_vty_init (); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 588f0fb5c..cf2ea81f5 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1304,10 +1304,10 @@ ospf_zebra_connected (struct zclient *zclient) } void -ospf_zebra_init () +ospf_zebra_init (struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new (); + zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_OSPF); zclient->zebra_connected = ospf_zebra_connected; zclient->router_id_update = ospf_router_id_update_zebra; diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 148f6520f..32a027161 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -72,7 +72,7 @@ extern int ospf_distance_set (struct vty *, struct ospf *, const char *, const char *, const char *); extern int ospf_distance_unset (struct vty *, struct ospf *, const char *, const char *, const char *); -extern void ospf_zebra_init (void); +extern void ospf_zebra_init (struct thread_master *); #endif /* _ZEBRA_OSPF_ZEBRA_H */ diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 95c1816f7..5f4711e86 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -205,7 +205,7 @@ int main(int argc, char** argv, char** envp) { /* * Initialize zclient "update" and "lookup" sockets */ - pim_zebra_init(zebra_sock_path); + pim_zebra_init (master, zebra_sock_path); zlog_notice("Loading configuration - begin"); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index dfc871b3b..1a3927135 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -655,7 +655,7 @@ static void pim_zebra_connected(struct zclient *zclient) zclient_send_requests(zclient, VRF_DEFAULT); } -void pim_zebra_init(char *zebra_sock_path) +void pim_zebra_init (struct thread_master *master, char *zebra_sock_path) { int i; @@ -669,7 +669,7 @@ void pim_zebra_init(char *zebra_sock_path) #endif /* Socket for receiving updates from Zebra daemon */ - qpim_zclient_update = zclient_new(); + qpim_zclient_update = zclient_new (master); qpim_zclient_update->zebra_connected = pim_zebra_connected; qpim_zclient_update->router_id_update = pim_router_id_update_zebra; diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index d624c8666..af5baef28 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -26,7 +26,7 @@ #include "pim_igmp.h" #include "pim_ifchannel.h" -void pim_zebra_init(char *zebra_sock_path); +void pim_zebra_init (struct thread_master *master, char *zebra_sock_path); void pim_scan_oil(void); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 67896d96b..297a2a8ac 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -122,7 +122,7 @@ struct zclient *zclient_lookup_new() { struct zclient *zlookup; - zlookup = zclient_new(); + zlookup = zclient_new (master); if (!zlookup) { zlog_err("%s: zclient_new() failure", __PRETTY_FUNCTION__); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 95b1f6d4a..4ead9b0ed 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -286,7 +286,7 @@ main (int argc, char **argv) /* RIP related initialization. */ rip_init (); rip_if_init (); - rip_zclient_init (); + rip_zclient_init (master); rip_peer_init (); /* Get configuration file. */ diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index de981623a..0b6c22a86 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -710,10 +710,10 @@ rip_zebra_connected (struct zclient *zclient) } void -rip_zclient_init () +rip_zclient_init (struct thread_master *master) { /* Set default value to the zebra client structure. */ - zclient = zclient_new (); + zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_RIP); zclient->zebra_connected = rip_zebra_connected; zclient->interface_add = rip_interface_add; diff --git a/ripd/ripd.h b/ripd/ripd.h index 4f40e79ab..a768ccc6a 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -389,7 +389,7 @@ extern void rip_if_down_all (void); extern void rip_route_map_init (void); extern void rip_route_map_reset (void); extern void rip_snmp_init (void); -extern void rip_zclient_init (void); +extern void rip_zclient_init (struct thread_master *); extern void rip_zclient_start (void); extern void rip_zclient_reset (void); extern void rip_offset_init (void); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index d8f224112..1c184e2c2 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -281,7 +281,7 @@ main (int argc, char **argv) /* RIPngd inits. */ ripng_init (); - zebra_init (); + zebra_init (master); ripng_peer_init (); /* Get configuration file. */ diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 58f88606c..13b185330 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -541,10 +541,10 @@ ripng_zebra_connected (struct zclient *zclient) /* Initialize zebra structure and it's commands. */ void -zebra_init () +zebra_init (struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new (); + zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_RIPNG); zclient->zebra_connected = ripng_zebra_connected; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 28ca41bc9..6cbbd84bc 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -358,7 +358,7 @@ extern void ripng_route_map_init (void); extern void ripng_route_map_reset (void); extern void ripng_terminate (void); /* zclient_init() is done by ripng_zebra.c:zebra_init() */ -extern void zebra_init (void); +extern void zebra_init (struct thread_master *); extern void ripng_zclient_start (void); extern void ripng_zclient_reset (void); extern void ripng_offset_init (void); diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index 359475374..ed54d9c11 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -376,7 +376,7 @@ static int global_test_init (void) { master = thread_master_create (); - zclient = zclient_new (); + zclient = zclient_new (master); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); diff --git a/zebra/client_main.c b/zebra/client_main.c index 06afc56d4..43ab29978 100644 --- a/zebra/client_main.c +++ b/zebra/client_main.c @@ -193,13 +193,15 @@ zebra_sim (FILE *fp) int main (int argc, char **argv) { + struct thread_master *master; FILE *fp; if (argc == 1) usage_exit (); + master = thread_master_create (); /* Establish connection to zebra. */ - zclient = zclient_new (); + zclient = zclient_new (master); zclient->enable = 1; #ifdef HAVE_TCP_ZEBRA zclient->sock = zclient_socket (); From d8aa4beab72cdd2c2d78f9e624fd4b704eec488f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 28 Sep 2015 20:10:40 -0400 Subject: [PATCH 0845/1342] vtysh: Fix Quagga.conf file read in. There exists a sequence of cli commands that are successfully read in by bgpd.conf, but not by a consolidated Quagga.conf. This issue stems from the fact that the consolidated config file attempts to match the current node + 1 node up the tree, while the individual config file searches for matches all the way up the tree. Quagga.conf read-in relies on vtysh_cmd.c command parsing which puts all nodes at CONFIG_NODE and if a match is found CMD_SUCCESS_DAEMON is returned. This signals to the parser to call the appropriate daemon with the comamnd. bgp as an example has three levels of config node's. If you are reading in a config node at the 3rd level(say address-family ipv6) then transition to another node under bgp it will not work in Quagga.conf because the code only looked up one node and was at CONFIG_BGP when it failed to find a match. Signed-off-by: Donald Sharp Reviewed-by: Daniel Walton --- lib/command.c | 69 ++++++++++++++++++++++++++++++++++++++------------- lib/command.h | 1 + vtysh/vtysh.c | 52 +------------------------------------- 3 files changed, 54 insertions(+), 68 deletions(-) diff --git a/lib/command.c b/lib/command.c index 20841604c..37767e925 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2794,34 +2794,69 @@ cmd_execute_command_strict (vector vline, struct vty *vty, return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd); } +/** + * Parse one line of config, walking up the parse tree attempting to find a match + * + * @param vty The vty context in which the command should be executed. + * @param cmd Pointer where the struct cmd_element* of the match command + * will be stored, if any. May be set to NULL if this info is + * not needed. + * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON + * or not. + * @return The status of the command that has been executed or an error code + * as to why no command could be executed. + */ +int +command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon) +{ + vector vline; + int saved_node; + int ret; + + vline = cmd_make_strvec (vty->buf); + + /* In case of comment line */ + if (vline == NULL) + return CMD_SUCCESS; + + /* Execute configuration command : this is strict match */ + ret = cmd_execute_command_strict (vline, vty, cmd); + + saved_node = vty->node; + + while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) && + ret != CMD_SUCCESS && ret != CMD_WARNING && + ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) { + vty->node = node_parent(vty->node); + ret = cmd_execute_command_strict (vline, vty, NULL); + } + + // If climbing the tree did not work then ignore the command and + // stay at the same node + if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) && + ret != CMD_SUCCESS && ret != CMD_WARNING && + ret != CMD_ERR_NOTHING_TODO) + { + vty->node = saved_node; + } + + cmd_free_strvec (vline); + + return ret; +} + /* Configration make from file. */ int config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num) { int ret; *line_num = 0; - vector vline; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { ++(*line_num); - vline = cmd_make_strvec (vty->buf); - - /* In case of comment line */ - if (vline == NULL) - continue; - /* Execute configuration command : this is strict match */ - ret = cmd_execute_command_strict (vline, vty, NULL); - - /* Try again with setting node to CONFIG_NODE */ - while (ret != CMD_SUCCESS && ret != CMD_WARNING - && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) - { - vty->node = node_parent(vty->node); - ret = cmd_execute_command_strict (vline, vty, NULL); - } - cmd_free_strvec (vline); + ret = command_config_read_one_line (vty, NULL, 0); if (ret != CMD_SUCCESS && ret != CMD_WARNING && ret != CMD_ERR_NOTHING_TODO) diff --git a/lib/command.h b/lib/command.h index bb0122fa4..6030069a4 100644 --- a/lib/command.h +++ b/lib/command.h @@ -527,6 +527,7 @@ extern void cmd_free_strvec (vector); extern vector cmd_describe_command (vector, struct vty *, int *status); extern char **cmd_complete_command (vector, struct vty *, int *status); extern const char *cmd_prompt (enum node_type); +extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node); extern int config_from_file (struct vty *, FILE *, unsigned int *line_num); extern enum node_type node_parent (enum node_type); extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 783c383c8..b55c6719b 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -251,14 +251,6 @@ vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) } } -static void -vtysh_exit_ripd_only (void) -{ - if (ripd_client) - vtysh_client_execute (ripd_client, "exit", stdout); -} - - void vtysh_pager_init (void) { @@ -457,53 +449,11 @@ int vtysh_config_from_file (struct vty *vty, FILE *fp) { int ret; - vector vline; struct cmd_element *cmd; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { - if (vty->buf[0] == '!' || vty->buf[1] == '#') - continue; - - vline = cmd_make_strvec (vty->buf); - - /* In case of comment line. */ - if (vline == NULL) - continue; - - /* Execute configuration command : this is strict match. */ - ret = cmd_execute_command_strict (vline, vty, &cmd); - - /* Try again with setting node to CONFIG_NODE. */ - if (ret != CMD_SUCCESS - && ret != CMD_SUCCESS_DAEMON - && ret != CMD_WARNING) - { - if (vty->node == KEYCHAIN_KEY_NODE) - { - vty->node = KEYCHAIN_NODE; - vtysh_exit_ripd_only (); - ret = cmd_execute_command_strict (vline, vty, &cmd); - - if (ret != CMD_SUCCESS - && ret != CMD_SUCCESS_DAEMON - && ret != CMD_WARNING) - { - vtysh_exit_ripd_only (); - vty->node = CONFIG_NODE; - ret = cmd_execute_command_strict (vline, vty, &cmd); - } - } - else - { - vtysh_execute ("end"); - vtysh_execute ("configure terminal"); - vty->node = CONFIG_NODE; - ret = cmd_execute_command_strict (vline, vty, &cmd); - } - } - - cmd_free_strvec (vline); + ret = command_config_read_one_line (vty, &cmd, 1); switch (ret) { From 26a18eb223d26011ac4f1d608f6775ed7ebf8efb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 29 Sep 2015 09:25:10 -0400 Subject: [PATCH 0846/1342] quagga: Additional centos 6 -enable-werror fixes This commit fixes these warnings: 1) bgpd/bgp_nexthop.c - dereferencing pointer 'X' does break strict-aliasing rules 2) pimd/pim_igmp_join.c - dereferencing pointer 'X' does break strict-aliasing rules 3) ripd/ripd.c - 'ifaddr.prefixlen' may be used uninitialized in this function Signed-off-by: Donald Sharp --- bgpd/bgp_nexthop.c | 6 ++---- pimd/pim_igmp_join.c | 22 ++++++++++++---------- ripd/ripd.c | 3 ++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 33de365e8..183a28b19 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -648,9 +648,9 @@ bgp_connected_add (struct connected *ifc) addr = ifc->address; + p = *(CONNECTED_PREFIX(ifc)); if (addr->family == AF_INET) { - PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) @@ -674,7 +674,6 @@ bgp_connected_add (struct connected *ifc) #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { - PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv6 ((struct prefix_ipv6 *) &p); if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) @@ -715,9 +714,9 @@ bgp_connected_delete (struct connected *ifc) addr = ifc->address; + p = *(CONNECTED_PREFIX(ifc)); if (addr->family == AF_INET) { - PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) @@ -742,7 +741,6 @@ bgp_connected_delete (struct connected *ifc) #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { - PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv6 ((struct prefix_ipv6 *) &p); if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c index 693a42b75..151b2afdb 100644 --- a/pimd/pim_igmp_join.c +++ b/pimd/pim_igmp_join.c @@ -45,18 +45,20 @@ int pim_igmp_join_source(int fd, int ifindex, struct in_addr source_addr) { struct group_source_req req; - struct sockaddr_in *group_sa = (struct sockaddr_in *) &req.gsr_group; - struct sockaddr_in *source_sa = (struct sockaddr_in *) &req.gsr_source; + struct sockaddr_in group; + struct sockaddr_in source; - memset(group_sa, 0, sizeof(*group_sa)); - group_sa->sin_family = AF_INET; - group_sa->sin_addr = group_addr; - group_sa->sin_port = htons(0); + memset(&group, 0, sizeof(group)); + group.sin_family = AF_INET; + group.sin_addr = group_addr; + group.sin_port = htons(0); + memcpy(&req.gsr_group, &group, sizeof(struct sockaddr_in)); - memset(source_sa, 0, sizeof(*source_sa)); - source_sa->sin_family = AF_INET; - source_sa->sin_addr = source_addr; - source_sa->sin_port = htons(0); + memset(&source, 0, sizeof(source)); + source.sin_family = AF_INET; + source.sin_addr = source_addr; + source.sin_port = htons(0); + memcpy(&req.gsr_source, &source, sizeof(struct sockaddr_in)); req.gsr_interface = ifindex; diff --git a/ripd/ripd.c b/ripd/ripd.c index b42ca7264..b708889f5 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1168,7 +1168,8 @@ rip_response_process (struct rip_packet *packet, int size, struct prefix_ipv4 ifaddr; struct prefix_ipv4 ifaddrclass; int subnetted; - + + memset(&ifaddr, 0, sizeof(ifaddr)); /* We don't know yet. */ subnetted = -1; From 6169559976b33a5bf120c806135c76b1b6d943ee Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 12 Oct 2015 14:33:31 -0400 Subject: [PATCH 0847/1342] tests: Fix warnings from test-stream.c test-stream is generating some compiler warnings Signed-off-by: Donald Sharp --- tests/test-stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test-stream.c b/tests/test-stream.c index 5997b47d3..7ef637475 100644 --- a/tests/test-stream.c +++ b/tests/test-stream.c @@ -24,7 +24,7 @@ #include #include -static long int ham = 0xdeadbeefdeadbeef; +static unsigned long long ham = 0xdeadbeefdeadbeef; struct thread_master *master; static void @@ -32,7 +32,7 @@ print_stream (struct stream *s) { size_t getp = stream_get_getp (s); - printf ("endp: %ld, readable: %ld, writeable: %ld\n", + printf ("endp: %zu, readable: %zu, writeable: %zu\n", stream_get_endp (s), STREAM_READABLE (s), STREAM_WRITEABLE (s)); @@ -70,7 +70,7 @@ main (void) printf ("c: 0x%hhx\n", stream_getc (s)); printf ("w: 0x%hx\n", stream_getw (s)); printf ("l: 0x%x\n", stream_getl (s)); - printf ("q: 0x%lx\n", stream_getq (s)); + printf ("q: 0x%" PRIu64 "\n", stream_getq (s)); return 0; } From 0cee0384f6c223f6cf507e980f03f2f3dd65478f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 30 Sep 2015 09:10:12 -0400 Subject: [PATCH 0848/1342] pimd: Do not display some default values as part of a show run There is no need to display igmp default values for the query-interval and the query-max-response-time-dsec Before change: ! interface swp4 description swp4 -> host-212's swp1 ip igmp ip igmp query-interval 125 ip igmp query-max-response-time-dsec 100 ip pim ssm link-detect ! After change: ! interface br1 ip igmp ip pim ssm link-detect ! Signed-off-by: Donald Sharp --- pimd/pim_vty.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 512c0e672..810dbe807 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -157,18 +157,24 @@ int pim_interface_config_write(struct vty *vty) } /* IF ip igmp query-interval */ - vty_out(vty, " %s %d%s", - PIM_CMD_IP_IGMP_QUERY_INTERVAL, - pim_ifp->igmp_default_query_interval, - VTY_NEWLINE); - ++writes; + if (pim_ifp->igmp_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) + { + vty_out(vty, " %s %d%s", + PIM_CMD_IP_IGMP_QUERY_INTERVAL, + pim_ifp->igmp_default_query_interval, + VTY_NEWLINE); + ++writes; + } /* IF ip igmp query-max-response-time */ - vty_out(vty, " %s %d%s", - PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, - pim_ifp->igmp_query_max_response_time_dsec, - VTY_NEWLINE); - ++writes; + if (pim_ifp->igmp_query_max_response_time_dsec != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) + { + vty_out(vty, " %s %d%s", + PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, + pim_ifp->igmp_query_max_response_time_dsec, + VTY_NEWLINE); + ++writes; + } /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { From f3734dd5fc00886b1d3f497d22295cea591d7685 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 30 Sep 2015 10:22:46 -0400 Subject: [PATCH 0849/1342] pimd: Cleanup zebra debugs to be protected by debug commands pimd is very chatty without any pim debugs turned on. This commit fixes a bunch of the debugs to be protected by appropriate pim debug statement. Signed-off-by: Donald Sharp --- pimd/pim_iface.c | 22 +++++++++++----------- pimd/pim_ifchannel.c | 10 ++++++---- pimd/pim_neighbor.c | 2 +- pimd/pim_rpf.c | 14 +++++++------- pimd/pim_signals.c | 4 ++-- pimd/pim_zebra.c | 2 +- pimd/pim_zlookup.c | 38 ++++++++++++++++++++------------------ 7 files changed, 48 insertions(+), 44 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 6f806a1b2..de56d04fb 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -256,14 +256,14 @@ static void on_primary_address_change(struct interface *ifp, { struct pim_interface *pim_ifp; - { + if (PIM_DEBUG_ZEBRA) { char old_str[100]; char new_str[100]; pim_inet4_dump("", old_addr, old_str, sizeof(old_str)); pim_inet4_dump("", new_addr, new_str, sizeof(new_str)); - zlog_info("%s: %s: primary address changed from %s to %s on interface %s", - __PRETTY_FUNCTION__, caller, - old_str, new_str, ifp->name); + zlog_debug("%s: %s: primary address changed from %s to %s on interface %s", + __PRETTY_FUNCTION__, caller, + old_str, new_str, ifp->name); } pim_ifp = ifp->info; @@ -329,8 +329,8 @@ static void detect_secondary_address_change(struct interface *ifp, return; changed = 1; /* true */ - zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", - __PRETTY_FUNCTION__, ifp->name); + zlog_info("FIXME T31 C15 %s: on interface %s: acting on any addr change", + __PRETTY_FUNCTION__, ifp->name); if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: on interface %s: %s", @@ -382,7 +382,7 @@ void pim_if_addr_add(struct connected *ifc) if (!if_is_operative(ifp)) return; - /* if (PIM_DEBUG_ZEBRA) */ { + if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d connected IP address %s %s", @@ -501,7 +501,7 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ifp = ifc->ifp; zassert(ifp); - /* if (PIM_DEBUG_ZEBRA) */ { + if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s", @@ -1055,14 +1055,14 @@ int pim_if_igmp_join_add(struct interface *ifp, return -4; } - { + if (PIM_DEBUG_IGMP_EVENTS) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", - __PRETTY_FUNCTION__, - source_str, group_str, ifp->name); + __PRETTY_FUNCTION__, + source_str, group_str, ifp->name); } return 0; diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index e253a0ea9..e801f4eeb 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -103,9 +103,11 @@ void pim_ifchannel_ifjoin_switch(const char *caller, enum pim_ifjoin_state old_state = ch->ifjoin_state; if (old_state == new_state) { - zlog_debug("%s calledby %s: non-transition on state %d (%s)", - __PRETTY_FUNCTION__, caller, new_state, - pim_ifchannel_ifjoin_name(new_state)); + if (PIM_DEBUG_PIM_EVENTS) { + zlog_debug("%s calledby %s: non-transition on state %d (%s)", + __PRETTY_FUNCTION__, caller, new_state, + pim_ifchannel_ifjoin_name(new_state)); + } return; } @@ -286,7 +288,7 @@ static void ifmembership_set(struct pim_ifchannel *ch, if (ch->local_ifmembership == membership) return; - /* if (PIM_DEBUG_PIM_EVENTS) */ { + if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 72a35382f..8932dc324 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -125,7 +125,7 @@ int pim_if_dr_election(struct interface *ifp) /* DR changed ? */ if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { - /* if (PIM_DEBUG_PIM_EVENTS) */ { + if (PIM_DEBUG_PIM_EVENTS) { char dr_old_str[100]; char dr_new_str[100]; pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index dedc60a55..38339da1b 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -61,7 +61,7 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, if (num_ifindex > 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", + zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", __FILE__, __PRETTY_FUNCTION__, num_ifindex, addr_str, first_ifindex); /* debug warning only, do not return */ @@ -136,22 +136,22 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, } rpf->rpf_addr = pim_rpf_find_rpf_addr(up); - if (PIM_INADDR_IS_ANY(rpf->rpf_addr)) { + if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) { /* RPF'(S,G) not found */ char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); - zlog_warn("%s %s: RPF'(%s,%s) not found: won't send join upstream", - __FILE__, __PRETTY_FUNCTION__, - src_str, grp_str); + zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream", + __FILE__, __PRETTY_FUNCTION__, + src_str, grp_str); /* warning only */ } /* detect change in pim_nexthop */ if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { - /* if (PIM_DEBUG_PIM_EVENTS) */ { + if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; char nhaddr_str[100]; @@ -176,7 +176,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, /* detect change in RPF_interface(S) */ if (save_nexthop.interface != rpf->source_nexthop.interface) { - /* if (PIM_DEBUG_PIM_EVENTS) */ { + if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c index d1350b08b..afd025965 100644 --- a/pimd/pim_signals.c +++ b/pimd/pim_signals.c @@ -36,7 +36,7 @@ static void pim_sighup() { - zlog_debug ("SIGHUP received, ignoring"); + zlog_info ("SIGHUP received, ignoring"); } static void pim_sigint() @@ -55,7 +55,7 @@ static void pim_sigterm() static void pim_sigusr1() { - zlog_debug ("SIGUSR1 received"); + zlog_info ("SIGUSR1 received"); zlog_rotate (NULL); } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 1a3927135..3ca9eddda 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -762,7 +762,7 @@ static int fib_lookup_if_vif_index(struct in_addr addr) if (num_ifindex > 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", + zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", __FILE__, __PRETTY_FUNCTION__, num_ifindex, addr_str, first_ifindex); /* debug warning only, do not return */ diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 297a2a8ac..b5b219ea3 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -283,14 +283,14 @@ static int zclient_read_nexthop(struct zclient *zlookup, nexthop_tab[num_ifindex].ifindex = 0; nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; - { + if (PIM_DEBUG_ZEBRA) { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str)); - zlog_warn("%s %s: zebra returned recursive nexthop %s for address %s", - __FILE__, __PRETTY_FUNCTION__, - nexthop_str, addr_str); + zlog_debug("%s %s: zebra returned recursive nexthop %s for address %s", + __FILE__, __PRETTY_FUNCTION__, + nexthop_str, addr_str); } ++num_ifindex; break; @@ -375,7 +375,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup, num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr); - if (num_ifindex < 1) { + if ((num_ifindex < 1) && PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s", @@ -400,15 +400,15 @@ int zclient_lookup_nexthop(struct zclient *zlookup, if (first_ifindex > 0) { /* found: first ifindex is non-recursive nexthop */ - if (lookup > 0) { + if ((lookup > 0) && PIM_DEBUG_ZEBRA) { /* Report non-recursive success after first lookup */ char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", - __FILE__, __PRETTY_FUNCTION__, - lookup, max_lookup, first_ifindex, addr_str, - nexthop_tab[0].protocol_distance, - nexthop_tab[0].route_metric); + zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", + __FILE__, __PRETTY_FUNCTION__, + lookup, max_lookup, first_ifindex, addr_str, + nexthop_tab[0].protocol_distance, + nexthop_tab[0].route_metric); /* use last address as nexthop address */ nexthop_tab[0].nexthop_addr = addr; @@ -421,12 +421,12 @@ int zclient_lookup_nexthop(struct zclient *zlookup, return num_ifindex; } - { + if (PIM_DEBUG_ZEBRA) { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_addr, nexthop_str, sizeof(nexthop_str)); - zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", + zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, nexthop_str, addr_str, nexthop_tab[0].protocol_distance, @@ -437,11 +437,13 @@ int zclient_lookup_nexthop(struct zclient *zlookup, } /* for (max_lookup) */ - char addr_str[100]; - pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", - __FILE__, __PRETTY_FUNCTION__, - lookup, max_lookup, addr_str); + if (PIM_DEBUG_ZEBRA) { + char addr_str[100]; + pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", + __FILE__, __PRETTY_FUNCTION__, + lookup, max_lookup, addr_str); + } return -2; } From dea43dee04e22d69ed57f4c85498e248a6074435 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 1 Oct 2015 12:40:51 -0400 Subject: [PATCH 0850/1342] pimd: Add knowledge of different packet types There are several additional packet types that pimd is unaware of Add code to allow pim to understand them in the future. Signed-off-by: Donald Sharp --- pimd/pim_pim.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index 6be1a3e68..4b378fb2c 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -41,8 +41,14 @@ #define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */ #define PIM_MSG_TYPE_HELLO (0) +#define PIM_MSG_TYPE_REGISTER (1) +#define PIM_MSG_TYPE_REG_STOP (2) #define PIM_MSG_TYPE_JOIN_PRUNE (3) +#define PIM_MSG_TYPE_BOOTSTRAP (4) #define PIM_MSG_TYPE_ASSERT (5) +#define PIM_MSG_TYPE_GRAFT (6) +#define PIM_MSG_TYPE_GRAFT_ACK (7) +#define PIM_MSG_TYPE_CANDIDATE (8) #define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg) From 4edf1c6aea8fd93e8fdeb2a651bf34bb24329611 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 1 Oct 2015 12:40:52 -0400 Subject: [PATCH 0851/1342] pimd: Notice when we receive a packet type we can't handle yet There are PIM packet types that have not been implemented yet. Notice when we get one of those and safely do nothing. Signed-off-by: Donald Sharp --- pimd/pim_pim.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index cd8a29031..66fc59be5 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -206,6 +206,20 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) pim_version, pim_type, pim_msg_len, checksum); } + if (pim_type == PIM_MSG_TYPE_REGISTER || + pim_type == PIM_MSG_TYPE_REG_STOP || + pim_type == PIM_MSG_TYPE_BOOTSTRAP || + pim_type == PIM_MSG_TYPE_GRAFT || + pim_type == PIM_MSG_TYPE_GRAFT_ACK || + pim_type == PIM_MSG_TYPE_CANDIDATE) + { + if (PIM_DEBUG_PIM_PACKETS) { + zlog_debug("Recv PIM packet type %d which is not currently understood", + pim_type); + } + return -1; + } + if (pim_type == PIM_MSG_TYPE_HELLO) { int result = pim_hello_recv(ifp, ip_hdr->ip_src, From a6a11765d4206a00b0875988ce352be7cdfa3617 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 2 Oct 2015 12:27:27 -0400 Subject: [PATCH 0852/1342] pimd: Cleanup interface startup This patch cleans up some interface startup, removes duplicate debug messages and protects against some always being displayed. Signed-off-by: Donald Sharp --- pimd/pim_iface.c | 47 ++++++++--------------------------------------- pimd/pim_zebra.c | 26 ++++++++++---------------- 2 files changed, 18 insertions(+), 55 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index de56d04fb..930dad00b 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -249,35 +249,6 @@ static void pim_addr_change(struct interface *ifp) pim_hello_restart_now(ifp); /* send hello and restart timer */ } -static void on_primary_address_change(struct interface *ifp, - const char *caller, - struct in_addr old_addr, - struct in_addr new_addr) -{ - struct pim_interface *pim_ifp; - - if (PIM_DEBUG_ZEBRA) { - char old_str[100]; - char new_str[100]; - pim_inet4_dump("", old_addr, old_str, sizeof(old_str)); - pim_inet4_dump("", new_addr, new_str, sizeof(new_str)); - zlog_debug("%s: %s: primary address changed from %s to %s on interface %s", - __PRETTY_FUNCTION__, caller, - old_str, new_str, ifp->name); - } - - pim_ifp = ifp->info; - if (!pim_ifp) { - return; - } - - if (!PIM_IF_TEST_PIM(pim_ifp->options)) { - return; - } - - pim_addr_change(ifp); -} - static int detect_primary_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) @@ -309,10 +280,13 @@ static int detect_primary_address_change(struct interface *ifp, } if (changed) { - struct in_addr old_addr = pim_ifp->primary_address; pim_ifp->primary_address = new_prim_addr; - on_primary_address_change(ifp, caller, old_addr, new_prim_addr); + if (!PIM_IF_TEST_PIM(pim_ifp->options)) { + return changed; + } + + pim_addr_change(ifp); } return changed; @@ -329,14 +303,9 @@ static void detect_secondary_address_change(struct interface *ifp, return; changed = 1; /* true */ - zlog_info("FIXME T31 C15 %s: on interface %s: acting on any addr change", - __PRETTY_FUNCTION__, ifp->name); - - if (PIM_DEBUG_ZEBRA) { - zlog_debug("%s: on interface %s: %s", - __PRETTY_FUNCTION__, - ifp->name, changed ? "changed" : "unchanged"); - } + if (PIM_DEBUG_ZEBRA) + zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", + __PRETTY_FUNCTION__, ifp->name); if (!changed) { return; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 3ca9eddda..3c739d28d 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -150,8 +150,6 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, if (!ifp) return 0; - zlog_info("INTERFACE UP: %s ifindex=%d", ifp->name, ifp->ifindex); - if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, @@ -182,8 +180,6 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, if (!ifp) return 0; - zlog_info("INTERFACE DOWN: %s ifindex=%d", ifp->name, ifp->ifindex); - if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, @@ -242,8 +238,6 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, struct connected *c; struct prefix *p; - zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD); - /* zebra api notifies address adds/dels events by using the same call interface_add_read below, see comments in lib/zclient.c @@ -278,17 +272,19 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, struct in_addr primary_addr = pim_find_primary_addr(c->ifp); if (primary_addr.s_addr != p->u.prefix4.s_addr) { - /* but we had a primary address already */ + if (PIM_DEBUG_ZEBRA) { + /* but we had a primary address already */ - char buf[BUFSIZ]; - char old[100]; + char buf[BUFSIZ]; + char old[100]; - prefix2str(p, buf, BUFSIZ); - pim_inet4_dump("", primary_addr, old, sizeof(old)); + prefix2str(p, buf, BUFSIZ); + pim_inet4_dump("", primary_addr, old, sizeof(old)); - zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s", - __PRETTY_FUNCTION__, - c->ifp->name, old, buf); + zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s", + __PRETTY_FUNCTION__, + c->ifp->name, old, buf); + } SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); } } @@ -304,8 +300,6 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, struct connected *c; struct prefix *p; - zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE); - /* zebra api notifies address adds/dels events by using the same call interface_add_read below, see comments in lib/zclient.c From ee162617ead116ebcda93b145a043231647b3380 Mon Sep 17 00:00:00 2001 From: Amritha Nambiar Date: Tue, 13 Oct 2015 22:08:46 -0700 Subject: [PATCH 0853/1342] isisd: Drop packet received on multiple interfaces due to the time gap in binding socket to an interface Due to the time window between opening socket and binding it to an interface, the same hello packet is delivered on multiple interfaces, unique socket per circuit is not yet established. When such hellos get processed, they form incorrect adjacencies. So, drop the packet that is received on multiple interfaces because the socket for the circuit is yet to bind to an interface. V2: Fix warning on sign comparison Signed-off-by: Amritha Nambiar --- isisd/isis_pfpacket.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index d20226458..a9ecd40ff 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -230,12 +230,24 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) LLC_LEN, MSG_PEEK, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); - if (bytesread < 0) + if ((bytesread < 0) || (s_addr.sll_ifindex != (int)circuit->interface->ifindex)) { - zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, " - "recvfrom(): %s", - circuit->interface->name, circuit->fd, bytesread, - safe_strerror (errno)); + if (bytesread < 0) + { + zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, " + "bytesread %d, recvfrom(): %s", + circuit->interface->name, circuit->fd, bytesread, + safe_strerror (errno)); + } + if (s_addr.sll_ifindex != (int)circuit->interface->ifindex) + { + zlog_warn("packet is received on multiple interfaces: " + "socket interface %d, circuit interface %d, " + "packet type %u", + s_addr.sll_ifindex, circuit->interface->ifindex, + s_addr.sll_pkttype); + } + /* get rid of the packet */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, From eeef0db2e9260fe76acb328a339025c432eb7c22 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 14 Oct 2015 08:50:38 -0400 Subject: [PATCH 0854/1342] lib: Fix duplicate variable name in smux.c and vty.c Both smux.c and vty.c have the same: static struct thread_master *master; as global variables for the file. This can and will lead to confusion name the variables something appropriate for the file it is in. Signed-off-by: Donald Sharp --- lib/smux.c | 10 +++++----- lib/vty.c | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/smux.c b/lib/smux.c index 70be49289..03da99f94 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -113,7 +113,7 @@ static struct cmd_node smux_node = }; /* thread master */ -static struct thread_master *master; +static struct thread_master *smux_master; static int oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len) @@ -1239,13 +1239,13 @@ smux_event (enum smux_event event, int sock) switch (event) { case SMUX_SCHEDULE: - smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0); + smux_connect_thread = thread_add_event (smux_master, smux_connect, NULL, 0); break; case SMUX_CONNECT: - smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10); + smux_connect_thread = thread_add_timer (smux_master, smux_connect, NULL, 10); break; case SMUX_READ: - smux_read_thread = thread_add_read (master, smux_read, NULL, sock); + smux_read_thread = thread_add_read (smux_master, smux_read, NULL, sock); break; default: break; @@ -1474,7 +1474,7 @@ void smux_init (struct thread_master *tm) { /* copy callers thread master */ - master = tm; + smux_master = tm; /* Make MIB tree. */ treelist = list_new(); diff --git a/lib/vty.c b/lib/vty.c index 5c4a23bd4..8befcb0fa 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2573,7 +2573,7 @@ vty_config_unlock (struct vty *vty) } /* Master of the threads. */ -static struct thread_master *master; +static struct thread_master *vty_master; static void vty_event (enum event event, int sock, struct vty *vty) @@ -2583,23 +2583,23 @@ vty_event (enum event event, int sock, struct vty *vty) switch (event) { case VTY_SERV: - vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); + vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock); vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; #ifdef VTYSH case VTYSH_SERV: - vty_serv_thread = thread_add_read (master, vtysh_accept, vty, sock); + vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock); vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; case VTYSH_READ: - vty->t_read = thread_add_read (master, vtysh_read, vty, sock); + vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock); break; case VTYSH_WRITE: - vty->t_write = thread_add_write (master, vtysh_write, vty, sock); + vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock); break; #endif /* VTYSH */ case VTY_READ: - vty->t_read = thread_add_read (master, vty_read, vty, sock); + vty->t_read = thread_add_read (vty_master, vty_read, vty, sock); /* Time out treatment. */ if (vty->v_timeout) @@ -2607,12 +2607,12 @@ vty_event (enum event event, int sock, struct vty *vty) if (vty->t_timeout) thread_cancel (vty->t_timeout); vty->t_timeout = - thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout); } break; case VTY_WRITE: if (! vty->t_write) - vty->t_write = thread_add_write (master, vty_flush, vty, sock); + vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock); break; case VTY_TIMEOUT_RESET: if (vty->t_timeout) @@ -2623,7 +2623,7 @@ vty_event (enum event event, int sock, struct vty *vty) if (vty->v_timeout) { vty->t_timeout = - thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout); } break; } @@ -3035,7 +3035,7 @@ vty_init (struct thread_master *master_thread) vtyvec = vector_init (VECTOR_MIN_SIZE); - master = master_thread; + vty_master = master_thread; atexit (vty_stdio_reset); From 774914f4223532256051bd6dd61cac20e8f9649f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 14 Oct 2015 08:50:39 -0400 Subject: [PATCH 0855/1342] bgpd: fix using of two pointers for struct thread_master * bgp is using both bm->master and master pointers interchangebly for thread manipulation. Since they are the same thing consolidate to one pointer. Signed-off-by: Donald Sharp --- bgpd/bgp_damp.c | 4 ++-- bgpd/bgp_dump.c | 4 ++-- bgpd/bgp_fsm.h | 10 +++++----- bgpd/bgp_main.c | 16 +++++----------- bgpd/bgp_network.c | 4 ++-- bgpd/bgp_nexthop.c | 16 ++++++++-------- bgpd/bgpd.c | 4 ++-- bgpd/bgpd.h | 2 -- 8 files changed, 26 insertions(+), 34 deletions(-) diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 05c30ff01..359fce36f 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -115,7 +115,7 @@ bgp_reuse_timer (struct thread *t) damp->t_reuse = NULL; damp->t_reuse = - thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE); t_now = bgp_clock (); @@ -447,7 +447,7 @@ bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half, /* Register reuse timer. */ if (! damp->t_reuse) damp->t_reuse = - thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE); return 0; } diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index a3c9526fd..3d88dee4b 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -156,13 +156,13 @@ bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour; interval = interval - secs_into_day % interval; /* always > 0 */ } - bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, + bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func, bgp_dump, interval); } else { /* One-off dump: execute immediately, don't affect any scheduled dumps */ - bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func, + bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func, bgp_dump, 0); } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index a749f8ea3..752d6e2b9 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -26,7 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_READ_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ - THREAD_READ_ON(master,T,F,peer,V); \ + THREAD_READ_ON(bm->master,T,F,peer,V); \ } while (0) #define BGP_READ_OFF(T) \ @@ -38,7 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_WRITE_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ - THREAD_WRITE_ON(master,(T),(F),peer,(V)); \ + THREAD_WRITE_ON(bm->master,(T),(F),peer,(V)); \ } while (0) #define BGP_WRITE_OFF(T) \ @@ -50,7 +50,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_TIMER_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ - THREAD_TIMER_ON(master,(T),(F),peer,(V)); \ + THREAD_TIMER_ON(bm->master,(T),(F),peer,(V)); \ } while (0) #define BGP_TIMER_OFF(T) \ @@ -62,13 +62,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_EVENT_ADD(P,E) \ do { \ if ((P)->status != Deleted) \ - thread_add_event (master, bgp_event, (P), (E)); \ + thread_add_event (bm->master, bgp_event, (P), (E)); \ } while (0) #define BGP_EVENT_FLUSH(P) \ do { \ assert (peer); \ - thread_cancel_event (master, (P)); \ + thread_cancel_event (bm->master, (P)); \ } while (0) /* Prototypes. */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 7c2988cd1..cacff2348 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -105,9 +105,6 @@ char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; /* Route retain mode flag. */ static int retain_mode = 0; -/* Master of threads. */ -struct thread_master *master; - /* Manually specified configuration file name. */ char *config_file = NULL; @@ -302,8 +299,8 @@ bgp_exit (int status) stream_free (bgp_nexthop_buf); /* reverse bgp_master_init */ - if (master) - thread_master_free (master); + if (bm->master) + thread_master_free (bm->master); if (zlog_default) closezlog (zlog_default); @@ -416,15 +413,12 @@ main (int argc, char **argv) } } - /* Make thread master. */ - master = bm->master; - /* Initializations. */ srandom (time (NULL)); - signal_init (master, array_size(bgp_signals), bgp_signals); + signal_init (bm->master, array_size(bgp_signals), bgp_signals); zprivs_init (&bgpd_privs); cmd_init (1); - vty_init (master); + vty_init (bm->master); memory_init (); vrf_init (); @@ -459,7 +453,7 @@ main (int argc, char **argv) bm->port); /* Start finite state machine, here we go! */ - while (thread_fetch (master, &thread)) + while (thread_fetch (bm->master, &thread)) thread_call (&thread); /* Not reached. */ diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 7059e8ae1..8621854b4 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -207,7 +207,7 @@ bgp_accept (struct thread *thread) zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } - listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock); + listener->thread = thread_add_read (bm->master, bgp_accept, listener, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); @@ -480,7 +480,7 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener)); listener->fd = sock; memcpy(&listener->su, sa, salen); - listener->thread = thread_add_read (master, bgp_accept, listener, sock); + listener->thread = thread_add_read (bm->master, bgp_accept, listener, sock); listnode_add (bm->listen_sockets, listener); return 0; diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 183a28b19..bb658afbf 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -529,7 +529,7 @@ static int bgp_scan_timer (struct thread *t) { bgp_scan_thread = - thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); + thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("Performing BGP general scanning"); @@ -1103,7 +1103,7 @@ bgp_import (struct thread *t) safi_t safi; bgp_import_thread = - thread_add_timer (master, bgp_import, NULL, bgp_import_interval); + thread_add_timer (bm->master, bgp_import, NULL, bgp_import_interval); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("Import timer expired."); @@ -1230,7 +1230,7 @@ DEFUN (bgp_scan_time, { thread_cancel (bgp_scan_thread); bgp_scan_thread = - thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); + thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); } return CMD_SUCCESS; @@ -1249,7 +1249,7 @@ DEFUN (no_bgp_scan_time, { thread_cancel (bgp_scan_thread); bgp_scan_thread = - thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); + thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); } return CMD_SUCCESS; @@ -1400,9 +1400,9 @@ bgp_config_write_scan_time (struct vty *vty) void bgp_scan_init (void) { - zlookup = zclient_new (master); + zlookup = zclient_new (bm->master); zlookup->sock = -1; - zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); + zlookup->t_connect = thread_add_event (bm->master, zlookup_connect, zlookup, 0); bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; @@ -1421,10 +1421,10 @@ bgp_scan_init (void) #endif /* HAVE_IPV6 */ /* Make BGP scan thread. */ - bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, + bgp_scan_thread = thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); /* Make BGP import there. */ - bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0); + bgp_import_thread = thread_add_timer (bm->master, bgp_import, NULL, 0); install_element (BGP_NODE, &bgp_scan_time_cmd); install_element (BGP_NODE, &no_bgp_scan_time_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index af8bdb451..3fdd9ff69 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1978,7 +1978,7 @@ bgp_create (as_t *as, const char *name) if (name) bgp->name = strdup (name); - THREAD_TIMER_ON (master, bgp->t_startup, bgp_startup_timer_expire, + THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire, bgp, bgp->restart_time); return bgp; @@ -5421,7 +5421,7 @@ bgp_init (void) bgp_vty_init (); /* Init zebra. */ - bgp_zebra_init (master); + bgp_zebra_init (bm->master); /* BGP inits. */ bgp_attr_init (); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7ae0acb30..95c16de00 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -834,8 +834,6 @@ enum bgp_clear_type extern struct bgp_master *bm; -extern struct thread_master *master; - /* Prototypes. */ extern void bgp_terminate (void); extern void bgp_reset (void); From 7bd7f55d2cbb4ddd2353fe8f2ded4853b3d2676b Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 7 Aug 2009 13:48:15 +0200 Subject: [PATCH 0856/1342] ospfd: split up network interface enable a bit, for per-interface area cmd * ospfd.c: (ospf_network_run_interface) Move out core to .. (add_ospf_interface) .. here (ospf_network_{un,}set) move redistribute update out to.. (update_redistributed) .. here, so it can be re-used in upcoming commit. Acked-by: Donald Sharp --- ospfd/ospfd.c | 126 ++++++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 55 deletions(-) diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 8c7d1c2fe..c8ad25f24 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -743,6 +743,71 @@ ospf_network_new (struct in_addr area_id, int format) return new; } +static void +add_ospf_interface (struct interface *ifp, struct ospf_area *area, + struct connected *co) +{ + struct ospf_interface *oi; + + oi = ospf_if_new (area->ospf, ifp, co->address); + oi->connected = co; + + oi->area = area; + + oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + oi->output_cost = ospf_if_get_output_cost (oi); + + /* Add pseudo neighbor. */ + ospf_nbr_add_self (oi); + + /* Relate ospf interface to ospf instance. */ + oi->ospf = area->ospf; + + /* update network type as interface flag */ + /* If network type is specified previously, + skip network type setting. */ + oi->type = IF_DEF_PARAMS (ifp)->type; + + ospf_area_add_if (oi->area, oi); + + /* if router_id is not configured, dont bring up + * interfaces. + * ospf_router_id_update() will call ospf_if_update + * whenever r-id is configured instead. + */ + if ((area->ospf->router_id.s_addr != 0) + && if_is_operative (ifp)) + ospf_if_up (oi); +} + +static void +update_redistributed (struct ospf *ospf, int add_to_ospf) +{ + struct route_node *rn; + struct external_info *ei; + + if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) + if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) + for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); + rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + { + if (add_to_ospf) + { + if (ospf_external_info_find_lsa (ospf, &ei->p)) + if (!ospf_distribute_check_connected (ospf, ei)) + ospf_external_lsa_flush (ospf, ei->type, &ei->p, + ei->ifindex /*, ei->nexthop */); + } + else + { + if (!ospf_external_info_find_lsa (ospf, &ei->p)) + if (ospf_distribute_check_connected (ospf, ei)) + ospf_external_lsa_originate (ospf, ei); + } + } +} + static void ospf_network_free (struct ospf *ospf, struct ospf_network *network) { @@ -758,7 +823,6 @@ ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_network *network; struct ospf_area *area; struct route_node *rn; - struct external_info *ei; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; rn = route_node_get (ospf->networks, (struct prefix *)p); @@ -776,16 +840,7 @@ ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, ospf_network_run ((struct prefix *)p, area); /* Update connected redistribute. */ - if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) - if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) - for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); - rn; rn = route_next (rn)) - if ((ei = rn->info) != NULL) - if (ospf_external_info_find_lsa (ospf, &ei->p)) - if (!ospf_distribute_check_connected (ospf, ei)) - ospf_external_lsa_flush (ospf, ei->type, &ei->p, - ei->ifindex /*, ei->nexthop */); - + update_redistributed(ospf, 1); /* interfaces possibly added */ ospf_area_check_free (ospf, area_id); return 1; @@ -797,7 +852,6 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, { struct route_node *rn; struct ospf_network *network; - struct external_info *ei; struct listnode *node, *nnode; struct ospf_interface *oi; @@ -844,15 +898,7 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, } /* Update connected redistribute. */ - if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) - if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) - for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); - rn; rn = route_next (rn)) - if ((ei = rn->info) != NULL) - if (!ospf_external_info_find_lsa (ospf, &ei->p)) - if (ospf_distribute_check_connected (ospf, ei)) - ospf_external_lsa_originate (ospf, ei); - + update_redistributed(ospf, 0); /* interfaces possibly removed */ return 1; } @@ -887,39 +933,9 @@ ospf_network_run_interface (struct prefix *p, struct ospf_area *area, if (p->family == co->address->family && ! ospf_if_table_lookup(ifp, co->address) && ospf_network_match_iface(co,p)) - { - struct ospf_interface *oi; - - oi = ospf_if_new (area->ospf, ifp, co->address); - oi->connected = co; - - oi->area = area; - - oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); - oi->output_cost = ospf_if_get_output_cost (oi); - - /* Add pseudo neighbor. */ - ospf_nbr_add_self (oi); - - /* Relate ospf interface to ospf instance. */ - oi->ospf = area->ospf; - - /* update network type as interface flag */ - /* If network type is specified previously, - skip network type setting. */ - oi->type = IF_DEF_PARAMS (ifp)->type; - - ospf_area_add_if (oi->area, oi); - - /* if router_id is not configured, dont bring up - * interfaces. - * ospf_router_id_update() will call ospf_if_update - * whenever r-id is configured instead. - */ - if ((area->ospf->router_id.s_addr != 0) - && if_is_operative (ifp)) - ospf_if_up (oi); - } + { + add_ospf_interface(ifp, area, co); + } } } @@ -978,7 +994,7 @@ ospf_if_update (struct ospf *ospf, struct interface *ifp) /* OSPF must be on and Router-ID must be configured. */ if (!ospf || ospf->router_id.s_addr == 0) return; - + /* Run each netowrk for this interface. */ for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) if (rn->info != NULL) From 738bce789a393efe2d3f35fd541cf149dd7f9311 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 7 Aug 2009 13:48:15 +0200 Subject: [PATCH 0857/1342] ospfd: Impl. per interface 'ip ospf area' command Use with interface command: interface ppp0 ip ospf area 0.0.0.0 This will enable OSPF on ppp0 with area 0.0.0.0 Remove with "no ip ospf area" * ospf_vty.c: add "ip ospf area (A.B.C.D|<0-4294967295>)" interface command * ospfd.c: (ospf_interface_{un,}set) new helper function to enable/disable OSPF on a specific interface. (ospf_if_update) 2 possible paths now to deal with interface updates. Acked-by: Donald Sharp --- ospfd/ospf_interface.h | 1 + ospfd/ospf_vty.c | 76 ++++++++++++++++++++++++++ ospfd/ospfd.c | 119 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 187 insertions(+), 9 deletions(-) diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index ed698c87e..a437bfbe3 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -47,6 +47,7 @@ struct ospf_if_params DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */ DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to join multicast groups) */ DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ + DECLARE_IF_PARAM (struct in_addr, if_area); /* Enable OSPF on this interface with area if_area */ DECLARE_IF_PARAM (u_char, type); /* type of interface */ #define OSPF_IF_ACTIVE 0 #define OSPF_IF_PASSIVE 1 diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index c6f3b4049..dd4d31276 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -5883,6 +5883,70 @@ ALIAS (no_ip_ospf_transmit_delay, "OSPF interface commands\n" "Link state transmit delay\n") +DEFUN (ip_ospf_area, + ip_ospf_area_cmd, + "ip ospf area (A.B.C.D|<0-4294967295>)", + "IP Information\n" + "OSPF interface commands\n" + "Enable OSPF on this interface\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") +{ + struct interface *ifp = vty->index; + int format, ret; + struct in_addr area_id; + struct ospf *ospf; + struct ospf_if_params *params; + + ret = ospf_str2area_id (argv[0], &area_id, &format); + + if (ret < 0) + { + vty_out (vty, "Please specify area by A.B.C.D|<0-4294967295>%s", + VTY_NEWLINE); + return CMD_WARNING; + } + params = IF_DEF_PARAMS (ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + { + vty_out (vty, "There is already a interface statement.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (memcmp (ifp->name, "VLINK", 5) == 0) + { + vty_out (vty, "Cannot enable OSPF on a virtual link.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + SET_IF_PARAM (params, if_area); + params->if_area = area_id; + ospf_interface_set (ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ospf_area, + no_ip_ospf_area_cmd, + "no ip ospf area", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Disable OSPF on this interface\n") +{ + struct interface *ifp = vty->index; + struct ospf *ospf; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + if (!OSPF_IF_PARAM_CONFIGURED(params, if_area)) + return CMD_SUCCESS; + + UNSET_IF_PARAM (params, if_area); + + ospf_interface_unset (ifp); + return CMD_SUCCESS; +} + DEFUN (ospf_redistribute_source, ospf_redistribute_source_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD @@ -6947,6 +7011,14 @@ config_write_interface (struct vty *vty) vty_out (vty, "%s", VTY_NEWLINE); } + /* Area print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, if_area)) + { + vty_out (vty, " ip ospf area %s%s", + inet_ntoa (params->if_area), + VTY_NEWLINE); + } + /* MTU ignore print. */ if (OSPF_IF_PARAM_CONFIGURED (params, mtu_ignore) && params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) @@ -7597,6 +7669,10 @@ ospf_vty_if_init (void) install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd); + /* "ip ospf area" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_area_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_area_cmd); + /* These commands are compatibitliy for previous version. */ install_element (INTERFACE_NODE, &ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index c8ad25f24..f6669d7f5 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -871,12 +871,17 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, /* Find interfaces that not configured already. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { + struct ospf_if_params *params; int found = 0; struct connected *co = oi->connected; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; + params = IF_DEF_PARAMS (oi->ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + continue; + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) { if (rn->info == NULL) @@ -902,6 +907,97 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, return 1; } +int +ospf_interface_set (struct interface *ifp) +{ + struct ospf_area *area; + struct listnode *cnode; + struct connected *co; + struct ospf *ospf; + struct ospf_if_params *params; + struct in_addr area_id; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; + + if ((ospf = ospf_lookup ()) == NULL) + return 1; /* Ospf not ready yet */ + + params = IF_DEF_PARAMS (ifp); + area_id = params->if_area; + + area = ospf_area_get (ospf, area_id, ret); + + for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) + { + struct ospf_interface *oi; + + if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) + continue; + + oi = ospf_if_table_lookup(ifp, co->address); + if (oi) + { /* Just adjust area for existing interface */ + ospf_area_del_if (oi->area, oi); + oi->area = area; + ospf_area_add_if (oi->area, oi); + } + else + { + add_ospf_interface(ifp, area, co); + } + } + + /* Update connected redistribute. */ + update_redistributed(ospf, 1); /* interface possibly added */ + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_interface_unset (struct interface *ifp) +{ + struct route_node *rn_oi, *rn; + struct ospf *ospf; + + if ((ospf = ospf_lookup ()) == NULL) + return 1; /* Ospf not ready yet */ + + /* Find interfaces that may need to be removed. */ + for (rn_oi = route_top (IF_OIFS (ifp)); rn_oi; rn_oi = route_next (rn_oi)) + { + struct ospf_interface *oi; + struct connected *co; + int found = 0; + + if ( (oi = rn_oi->info) == NULL) + continue; + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + co = oi->connected; + + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + if (ospf_network_match_iface(co,&rn->p)) + { + found = 1; + route_unlock_node (rn); + break; + } + } + + if (found == 0) + ospf_if_free (oi); + } + + /* Update connected redistribute. */ + update_redistributed(ospf, 0); /* interfaces possibly removed */ + return 1; + } + + /* Check whether interface matches given network * returns: 1, true. 0, false */ @@ -994,15 +1090,20 @@ ospf_if_update (struct ospf *ospf, struct interface *ifp) /* OSPF must be on and Router-ID must be configured. */ if (!ospf || ospf->router_id.s_addr == 0) return; - - /* Run each netowrk for this interface. */ - for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) - if (rn->info != NULL) - { - network = (struct ospf_network *) rn->info; - area = ospf_area_get (ospf, network->area_id, network->format); - ospf_network_run_interface (&rn->p, area, ifp); - } + + if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS (ifp), if_area)) + ospf_interface_set (ifp); + else + { + /* Run each netowrk for this interface. */ + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + if (rn->info != NULL) + { + network = (struct ospf_network *) rn->info; + area = ospf_area_get (ospf, network->area_id, network->format); + ospf_network_run_interface (&rn->p, area, ifp); + } + } } void From 8a667cf7c58a065bcd6371f4ad6f25bfb084181c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 27 Aug 2009 16:51:42 +0100 Subject: [PATCH 0858/1342] ospfd: Extend 'ip ospf area' to take address argument + rationalise ospf enable * ospfd.c: (general) Clean up the whole running of OSPF on interfaces. (add_ospf_interface) taking (struct interface *) arg is pointless here. (ospf_is_ready) new helper. (ospf_network_run_subnet) Put all the code for choosing whether to enable OSPF on a subnet, and if so which area configuration to use, here. If a subnet should not be enabled, ensure an existing oi is freed. (ospf_network_run_interface) Just call run_subnet for all subnets on an interface. (ospf_network_run) Just call run_interface for all interfaces. (ospf_if_update) Just call run_interface for the given interface. (ospf_network_unset) Just call run_subnet for existing ois. (ospf_update_interface_area) helper: update area on an oi, or create it. (ospf_interface_set) renamed to ospf_interface_area_set for clarity. Ensures OSPF is created, then into if_update. (ospf_interface_unset) renamed to ospf_interface_area_unset and collapses down to simple loop to call run_subnet for all ois. * ospf_interface.h: add a more general OSPF_IF_PARAM_IS_SET, which does the right thing and takes default config into account. * ospf_vty.c: (OSPF_VTY_GET_IF_PARAMS) new macro with common code for handling interface parameter commands - only used for 'ip ospf area' in this commit. (OSPF_VTY_PARAM_UNSET) similar ({no,}ip_ospf_area) Use said macros. * doc/ospfd.texi: add 'ip ospf area' command. Acked-by: Donald Sharp --- doc/ospfd.texi | 18 +++ ospfd/ospf_interface.h | 11 +- ospfd/ospf_vty.c | 88 ++++++++---- ospfd/ospfd.c | 302 ++++++++++++++++++++++------------------- ospfd/ospfd.h | 3 + 5 files changed, 253 insertions(+), 169 deletions(-) diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 856a2ba05..7ddc9db8e 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -216,6 +216,7 @@ OSPF domain. @deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {} @deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {} @deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {} +@anchor{OSPF network command} This command specifies the OSPF enabled interface(s). If the interface has an address from range 192.168.1.0/24 then the command below enables ospf on this interface so router can provide network information to the other @@ -239,6 +240,10 @@ Currently, if a peer prefix has been configured, then we test whether the prefix in the network command contains the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface. + +In some cases it may be more convenient to enable OSPF on a per +interface/subnet basis (@pxref{OSPF ip ospf area command}). + @end deffn @node OSPF area @@ -406,6 +411,19 @@ settings will override any per-area authentication setting. @node OSPF interface @section OSPF interface +@deffn {Interface Command} {ip ospf area @var{AREA} [@var{ADDR}]} {} +@deffnx {Interface Command} {no ip ospf area [@var{ADDR}]} {} +@anchor{OSPF ip ospf area command} + +Enable OSPF on the interface, optionally restricted to just the IP address +given by @var{ADDR}, putting it in the @var{AREA} area. Per interface area +settings take precedence to network commands (@pxref{OSPF network command}). + +If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF +via this command may result in a slight performance improvement. + +@end deffn + @deffn {Interface Command} {ip ospf authentication-key @var{AUTH_KEY}} {} @deffnx {Interface Command} {no ip ospf authentication-key} {} Set OSPF authentication key to a simple password. After setting @var{AUTH_KEY}, diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index a437bfbe3..2ed426f97 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -30,8 +30,17 @@ #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) #define IF_OIFS(I) (IF_OSPF_IF_INFO (I)->oifs) #define IF_OIFS_PARAMS(I) (IF_OSPF_IF_INFO (I)->params) - + +/* Despite the name, this macro probably is for specialist use only */ #define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) + +/* Test whether an OSPF interface parameter is set, generally, given some + * existing ospf interface + */ +#define OSPF_IF_PARAM_IS_SET(O,P) \ + (OSPF_IF_PARAM_CONFIGURED ((O)->params, P) || \ + OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp)->P)) + #define OSPF_IF_PARAM(O, P) \ (OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\ (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index dd4d31276..45a19c096 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -292,6 +292,41 @@ ospf_passive_interface_update (struct ospf *ospf, struct interface *ifp, } } +/* get the appropriate ospf parameters structure, checking if + * there's a valid interface address at the argi'th argv index + */ +enum { + VTY_SET = 0, + VTY_UNSET, +}; +#define OSPF_VTY_GET_IF_PARAMS(ifp,params,argi,addr,set) \ + (params) = IF_DEF_PARAMS ((ifp)); \ + \ + if (argc == (argi) + 1) \ + { \ + int ret = inet_aton(argv[(argi)], &(addr)); \ + if (!ret) \ + { \ + vty_out (vty, "Please specify interface address by A.B.C.D%s", \ + VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ + (params) = ospf_get_if_params ((ifp), (addr)); \ + \ + if (set) \ + ospf_if_update_params ((ifp), (addr)); \ + else if ((params) == NULL) \ + return CMD_SUCCESS; \ + } + +#define OSPF_VTY_PARAM_UNSET(params,var,ifp,addr) \ + UNSET_IF_PARAM ((params), var); \ + if ((params) != IF_DEF_PARAMS ((ifp))) \ + { \ + ospf_free_if_params ((ifp), (addr)); \ + ospf_if_update_params ((ifp), (addr)); \ + } + DEFUN (ospf_passive_interface, ospf_passive_interface_addr_cmd, "passive-interface IFNAME A.B.C.D", @@ -453,7 +488,7 @@ DEFUN (ospf_network_area, "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") { - struct ospf *ospf= vty->index; + struct ospf *ospf = vty->index; struct prefix_ipv4 p; struct in_addr area_id; int ret, format; @@ -5885,31 +5920,28 @@ ALIAS (no_ip_ospf_transmit_delay, DEFUN (ip_ospf_area, ip_ospf_area_cmd, - "ip ospf area (A.B.C.D|<0-4294967295>)", + "ip ospf area (A.B.C.D|<0-4294967295>) [A.B.C.D]", "IP Information\n" "OSPF interface commands\n" "Enable OSPF on this interface\n" "OSPF area ID in IP address format\n" - "OSPF area ID as a decimal value\n") + "OSPF area ID as a decimal value\n" + "Address of interface\n") { struct interface *ifp = vty->index; - int format, ret; struct in_addr area_id; - struct ospf *ospf; + struct in_addr addr; + int format; struct ospf_if_params *params; - ret = ospf_str2area_id (argv[0], &area_id, &format); + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); - if (ret < 0) - { - vty_out (vty, "Please specify area by A.B.C.D|<0-4294967295>%s", - VTY_NEWLINE); - return CMD_WARNING; - } - params = IF_DEF_PARAMS (ifp); + OSPF_VTY_GET_IF_PARAMS(ifp, params, 1, addr, VTY_SET); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { - vty_out (vty, "There is already a interface statement.%s", VTY_NEWLINE); + vty_out (vty, "There is already an interface area statement.%s", + VTY_NEWLINE); return CMD_WARNING; } if (memcmp (ifp->name, "VLINK", 5) == 0) @@ -5917,33 +5949,36 @@ DEFUN (ip_ospf_area, vty_out (vty, "Cannot enable OSPF on a virtual link.%s", VTY_NEWLINE); return CMD_WARNING; } - + SET_IF_PARAM (params, if_area); params->if_area = area_id; - ospf_interface_set (ifp); + ospf_interface_area_set (ifp); return CMD_SUCCESS; } DEFUN (no_ip_ospf_area, no_ip_ospf_area_cmd, - "no ip ospf area", + "no ip ospf area [A.B.C.D]", NO_STR "IP Information\n" "OSPF interface commands\n" - "Disable OSPF on this interface\n") + "Disable OSPF on this interface\n" + "Address of interface\n") { struct interface *ifp = vty->index; - struct ospf *ospf; struct ospf_if_params *params; + struct in_addr addr; - params = IF_DEF_PARAMS (ifp); + OSPF_VTY_GET_IF_PARAMS(ifp, params, 0, addr, VTY_UNSET); + if (!OSPF_IF_PARAM_CONFIGURED(params, if_area)) return CMD_SUCCESS; + + OSPF_VTY_PARAM_UNSET(params, if_area, ifp, addr); + + ospf_interface_area_unset (ifp); - UNSET_IF_PARAM (params, if_area); - - ospf_interface_unset (ifp); return CMD_SUCCESS; } @@ -7014,9 +7049,10 @@ config_write_interface (struct vty *vty) /* Area print. */ if (OSPF_IF_PARAM_CONFIGURED (params, if_area)) { - vty_out (vty, " ip ospf area %s%s", - inet_ntoa (params->if_area), - VTY_NEWLINE); + vty_out (vty, " ip ospf area %s", inet_ntoa (params->if_area)); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); } /* MTU ignore print. */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index f6669d7f5..c317ed87c 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -69,8 +69,10 @@ static void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); static void ospf_network_free (struct ospf *, struct ospf_network *); static void ospf_area_free (struct ospf_area *); static void ospf_network_run (struct prefix *, struct ospf_area *); -static void ospf_network_run_interface (struct prefix *, struct ospf_area *, - struct interface *); +static void ospf_network_run_interface (struct ospf *, struct interface *, + struct prefix *, struct ospf_area *); +static void ospf_network_run_subnet (struct ospf *, struct connected *, + struct prefix *, struct ospf_area *); static int ospf_network_match_iface (const struct connected *, const struct prefix *); static void ospf_finish_final (struct ospf *); @@ -256,6 +258,16 @@ ospf_lookup () return listgetdata (listhead (om->ospf)); } +static int +ospf_is_ready (struct ospf *ospf) +{ + /* OSPF must be on and Router-ID must be configured. */ + if (!ospf || ospf->router_id.s_addr == 0) + return 0; + + return 1; +} + static void ospf_add (struct ospf *ospf) { @@ -743,18 +755,17 @@ ospf_network_new (struct in_addr area_id, int format) return new; } -static void -add_ospf_interface (struct interface *ifp, struct ospf_area *area, - struct connected *co) +static void +add_ospf_interface (struct connected *co, struct ospf_area *area) { struct ospf_interface *oi; - oi = ospf_if_new (area->ospf, ifp, co->address); + oi = ospf_if_new (area->ospf, co->ifp, co->address); oi->connected = co; oi->area = area; - oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + oi->params = ospf_lookup_if_params (co->ifp, oi->address->u.prefix4); oi->output_cost = ospf_if_get_output_cost (oi); /* Add pseudo neighbor. */ @@ -766,7 +777,7 @@ add_ospf_interface (struct interface *ifp, struct ospf_area *area, /* update network type as interface flag */ /* If network type is specified previously, skip network type setting. */ - oi->type = IF_DEF_PARAMS (ifp)->type; + oi->type = IF_DEF_PARAMS (co->ifp)->type; ospf_area_add_if (oi->area, oi); @@ -776,7 +787,7 @@ add_ospf_interface (struct interface *ifp, struct ospf_area *area, * whenever r-id is configured instead. */ if ((area->ospf->router_id.s_addr != 0) - && if_is_operative (ifp)) + && if_is_operative (co->ifp)) ospf_if_up (oi); } @@ -797,7 +808,7 @@ update_redistributed (struct ospf *ospf, int add_to_ospf) if (ospf_external_info_find_lsa (ospf, &ei->p)) if (!ospf_distribute_check_connected (ospf, ei)) ospf_external_lsa_flush (ospf, ei->type, &ei->p, - ei->ifindex /*, ei->nexthop */); + ei->ifindex /*, ei->nexthop */); } else { @@ -840,7 +851,8 @@ ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, ospf_network_run ((struct prefix *)p, area); /* Update connected redistribute. */ - update_redistributed(ospf, 1); /* interfaces possibly added */ + update_redistributed(ospf, 1); + ospf_area_check_free (ospf, area_id); return 1; @@ -871,131 +883,64 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, /* Find interfaces that not configured already. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { - struct ospf_if_params *params; - int found = 0; - struct connected *co = oi->connected; - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; - params = IF_DEF_PARAMS (oi->ifp); - if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) - continue; - - for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) - { - if (rn->info == NULL) - continue; - - if (ospf_network_match_iface(co,&rn->p)) - { - found = 1; - route_unlock_node (rn); - break; - } - } - - if (found == 0) - { - ospf_if_free (oi); - ospf_area_check_free (ospf, area_id); - } + ospf_network_run_subnet (ospf, oi->connected, NULL, NULL); } /* Update connected redistribute. */ - update_redistributed(ospf, 0); /* interfaces possibly removed */ + update_redistributed(ospf, 0); + + ospf_area_check_free (ospf, area_id); + return 1; } -int -ospf_interface_set (struct interface *ifp) +/* Ensure there's an OSPF instance, as "ip ospf area" enabled OSPF means + * there might not be any 'router ospf' config. + * + * Otherwise, doesn't do anything different to ospf_if_update for now + */ +void +ospf_interface_area_set (struct interface *ifp) { - struct ospf_area *area; - struct listnode *cnode; - struct connected *co; - struct ospf *ospf; - struct ospf_if_params *params; - struct in_addr area_id; - int ret = OSPF_AREA_ID_FORMAT_ADDRESS; - - if ((ospf = ospf_lookup ()) == NULL) - return 1; /* Ospf not ready yet */ - - params = IF_DEF_PARAMS (ifp); - area_id = params->if_area; - - area = ospf_area_get (ospf, area_id, ret); - - for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) - { - struct ospf_interface *oi; - - if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) - continue; - - oi = ospf_if_table_lookup(ifp, co->address); - if (oi) - { /* Just adjust area for existing interface */ - ospf_area_del_if (oi->area, oi); - oi->area = area; - ospf_area_add_if (oi->area, oi); - } - else - { - add_ospf_interface(ifp, area, co); - } - } - - /* Update connected redistribute. */ - update_redistributed(ospf, 1); /* interface possibly added */ - ospf_area_check_free (ospf, area_id); - - return 1; + struct ospf *ospf = ospf_get(); + + ospf_if_update (ospf, ifp); + /* if_update does a update_redistributed */ + + return; } -int -ospf_interface_unset (struct interface *ifp) +void +ospf_interface_area_unset (struct interface *ifp) { - struct route_node *rn_oi, *rn; + struct route_node *rn_oi; struct ospf *ospf; if ((ospf = ospf_lookup ()) == NULL) - return 1; /* Ospf not ready yet */ - + return; /* Ospf not ready yet */ + /* Find interfaces that may need to be removed. */ for (rn_oi = route_top (IF_OIFS (ifp)); rn_oi; rn_oi = route_next (rn_oi)) { struct ospf_interface *oi; - struct connected *co; - int found = 0; if ( (oi = rn_oi->info) == NULL) continue; + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; - co = oi->connected; - - for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) - { - if (rn->info == NULL) - continue; - - if (ospf_network_match_iface(co,&rn->p)) - { - found = 1; - route_unlock_node (rn); - break; - } - } - - if (found == 0) - ospf_if_free (oi); + + ospf_network_run_subnet (ospf, oi->connected, NULL, NULL); } /* Update connected redistribute. */ - update_redistributed(ospf, 0); /* interfaces possibly removed */ - return 1; - } + update_redistributed (ospf, 0); /* interfaces possibly removed */ + + return; +} /* Check whether interface matches given network @@ -1009,8 +954,101 @@ ospf_network_match_iface(const struct connected *co, const struct prefix *net) } static void -ospf_network_run_interface (struct prefix *p, struct ospf_area *area, - struct interface *ifp) +ospf_update_interface_area (struct connected *co, struct ospf_area *area) +{ + struct ospf_interface *oi = ospf_if_table_lookup (co->ifp, co->address); + + /* nothing to be done case */ + if (oi && oi->area == area) + return; + + if (oi) + ospf_if_free (oi); + + add_ospf_interface (co, area); +} + +/* Run OSPF for the given subnet, taking into account the following + * possible sources of area configuration, in the given order of preference: + * + * - Whether there is interface+address specific area configuration + * - Whether there is a default area for the interface + * - Whether there is an area given as a parameter. + * - If no specific network prefix/area is supplied, whether there's + * a matching network configured. + */ +static void +ospf_network_run_subnet (struct ospf *ospf, struct connected *co, + struct prefix *p, struct ospf_area *given_area) +{ + struct ospf_interface *oi; + struct ospf_if_params *params; + struct ospf_area *area = NULL; + struct route_node *rn; + int configed = 0; + + if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY)) + return; + + if (co->address->family != AF_INET) + return; + + /* Try determine the appropriate area for this interface + address + * Start by checking interface config + */ + if (!(params = ospf_lookup_if_params (co->ifp, co->address->u.prefix4))) + params = IF_DEF_PARAMS (co->ifp); + + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + area = (ospf_area_get (ospf, params->if_area, + OSPF_AREA_ID_FORMAT_ADDRESS)); + + /* If we've found an interface and/or addr specific area, then we're + * done + */ + if (area) + { + ospf_update_interface_area (co, area); + return; + } + + /* Otherwise, only remaining possibility is a matching network statement */ + if (p) + { + assert (given_area != NULL); + + /* Which either was supplied as a parameter.. (e.g. cause a new + * network/area was just added).. + */ + if (p->family == co->address->family + && ospf_network_match_iface (co, p)) + ospf_update_interface_area (co, given_area); + + return; + } + + /* Else we have to search the existing network/area config to see + * if any match.. + */ + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + if (rn->info != NULL + && ospf_network_match_iface (co, &rn->p)) + { + struct ospf_network *network = (struct ospf_network *) rn->info; + area = ospf_area_get (ospf, network->area_id, network->format); + ospf_update_interface_area (co, area); + configed = 1; + } + + /* If the subnet isn't in any area, deconfigure */ + if (!configed && (oi = ospf_if_table_lookup (co->ifp, co->address))) + ospf_if_free (oi); +} + +static void +ospf_network_run_interface (struct ospf *ospf, struct interface *ifp, + struct prefix *p, + struct ospf_area *given_area) { struct listnode *cnode; struct connected *co; @@ -1018,21 +1056,14 @@ ospf_network_run_interface (struct prefix *p, struct ospf_area *area, if (memcmp (ifp->name, "VLINK", 5) == 0) return; + /* Network prefix without area is nonsensical */ + if (p) + assert (given_area != NULL); + /* if interface prefix is match specified prefix, then create socket and join multicast group. */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) - { - - if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) - continue; - - if (p->family == co->address->family - && ! ospf_if_table_lookup(ifp, co->address) - && ospf_network_match_iface(co,p)) - { - add_ospf_interface(ifp, area, co); - } - } + ospf_network_run_subnet (ospf, co, p, given_area); } static void @@ -1047,7 +1078,7 @@ ospf_network_run (struct prefix *p, struct ospf_area *area) /* Get target interface. */ for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) - ospf_network_run_interface (p, area, ifp); + ospf_network_run_interface (area->ospf, ifp, p, area); } void @@ -1080,30 +1111,17 @@ ospf_ls_upd_queue_empty (struct ospf_interface *oi) void ospf_if_update (struct ospf *ospf, struct interface *ifp) { - struct route_node *rn; - struct ospf_network *network; - struct ospf_area *area; - if (!ospf) ospf = ospf_lookup (); - /* OSPF must be on and Router-ID must be configured. */ - if (!ospf || ospf->router_id.s_addr == 0) + /* OSPF must be ready. */ + if (!ospf_is_ready (ospf)) return; - if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS (ifp), if_area)) - ospf_interface_set (ifp); - else - { - /* Run each netowrk for this interface. */ - for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) - if (rn->info != NULL) - { - network = (struct ospf_network *) rn->info; - area = ospf_area_get (ospf, network->area_id, network->format); - ospf_network_run_interface (&rn->p, area, ifp); - } - } + ospf_network_run_interface (ospf, ifp, NULL, NULL); + + /* Update connected redistribute. */ + update_redistributed(ospf, 1); } void diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index c50e615ff..595c04f61 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -563,6 +563,9 @@ extern struct ospf_area *ospf_area_lookup_by_area_id (struct ospf *, extern void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); extern void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); +extern void ospf_interface_area_set (struct interface *); +extern void ospf_interface_area_unset (struct interface *); + extern void ospf_route_map_init (void); extern void ospf_snmp_init (void); From 13862bfc779f6f63080c8d860f7b919b27f39b9c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 20 Oct 2015 13:47:09 +0100 Subject: [PATCH 0859/1342] Revert "Fix to take care of ordering between interface and router ospf command." This reverts commit 4bab6806914dbb4b43f376ebf966a034a0ea72cd, as Joakim's version of 'ip ospf area' and the 2 follow-up patches should avoid the issue Vipin reported. Acked-by: Donald Sharp --- ospfd/ospf_main.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 10565fe6f..1e4184ff0 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -312,15 +312,6 @@ main (int argc, char **argv) ospf_opaque_init (); #endif /* HAVE_OPAQUE_LSA */ - /* Need to initialize the default ospf structure, so the interface mode - commands can be duly processed if they are received before 'router ospf', - when quagga(ospfd) is restarted */ - if (!ospf_get()) - { - zlog_err("OSPF instance init failed: %s", strerror(errno)); - exit (1); - } - /* Get configuration file. */ vty_read_config (config_file, config_default); From 5c1791f28e2e831e4e9b92c3c2f7d8ed832cb968 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 25 Apr 2014 14:36:16 +0200 Subject: [PATCH 0860/1342] ospfd: PointToPoint neighbors are identified by router ID According to RFC 2328, section 10.5 PointToPoint neighbors should be identified by router ID instead of source IP address. Signed-off-by: Joakim Tjernlund --- ospfd/ospf_neighbor.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index c3bdf9929..23a641736 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -45,8 +45,8 @@ /* Fill in the the 'key' as appropriate to retrieve the entry for nbr * from the ospf_interface's nbrs table. Indexed by interface address - * for all cases except Virtual-link interfaces, where neighbours are - * indexed by router-ID instead. + * for all cases except Virtual-link and PointToPoint interfaces, where + * neighbours are indexed by router-ID instead. */ static void ospf_nbr_key (struct ospf_interface *oi, struct ospf_neighbor *nbr, @@ -56,7 +56,8 @@ ospf_nbr_key (struct ospf_interface *oi, struct ospf_neighbor *nbr, key->prefixlen = IPV4_MAX_BITLEN; /* vlinks are indexed by router-id */ - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + if (oi->type == OSPF_IFTYPE_VIRTUALLINK || + oi->type == OSPF_IFTYPE_POINTOPOINT) key->u.prefix4 = nbr->router_id; else key->u.prefix4 = nbr->src; @@ -291,8 +292,8 @@ ospf_nbr_count_opaque_capable (struct ospf_interface *oi) #endif /* HAVE_OPAQUE_LSA */ /* lookup nbr by address - use this only if you know you must - * otherwise use the ospf_nbr_lookup() wrapper, which deals - * with virtual link neighbours + * otherwise use the ospf_nbr_lookup() wrapper, which deals + * with virtual link and PointToPoint neighbours */ struct ospf_neighbor * ospf_nbr_lookup_by_addr (struct route_table *nbrs, @@ -384,7 +385,8 @@ struct ospf_neighbor * ospf_nbr_lookup (struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) { - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + if (oi->type == OSPF_IFTYPE_VIRTUALLINK || + oi->type == OSPF_IFTYPE_POINTOPOINT) return (ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id)); else return (ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src)); @@ -444,8 +446,9 @@ ospf_nbr_get (struct ospf_interface *oi, struct ospf_header *ospfh, key.family = AF_INET; key.prefixlen = IPV4_MAX_BITLEN; - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - key.u.prefix4 = ospfh->router_id; /* index vlink nbrs by router-id */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK || + oi->type == OSPF_IFTYPE_POINTOPOINT) + key.u.prefix4 = ospfh->router_id;/* index vlink and ptp nbrs by router-id */ else key.u.prefix4 = iph->ip_src; From 056f3760cd311faf088d6f5fe06498960788c8c7 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Wed, 10 Apr 2013 12:30:04 -0700 Subject: [PATCH 0861/1342] bgpd, lib: memory cleanups for valgrind, plus debug changes Description: We use valgrind memcheck quite a bit to spot leaks in our work with bgpd. In order to eliminate false positives, we added code in the exit path to release the remaining allocated memory. Bgpd startup log message now includes pid. Some little tweaks by Paul Jakma : * bgp_mplsvpn.c: (str2prefix_rd) do the cleanup in common code at the end and goto it. --- bgpd/bgp_aspath.c | 16 ++++++++++++---- bgpd/bgp_attr.c | 13 +++++++++++++ bgpd/bgp_main.c | 36 ++++++++++++++++++++++++++++++------ bgpd/bgp_mplsvpn.c | 35 +++++++++++++++++++---------------- bgpd/bgp_network.c | 7 +++++-- bgpd/bgp_nexthop.c | 26 +++++++++++++------------- bgpd/bgpd.c | 5 ++++- lib/routemap.c | 3 +++ 8 files changed, 99 insertions(+), 42 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 0aec3ef1c..9d49f343c 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -98,6 +98,12 @@ assegment_data_new (int num) return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } +static void +assegment_data_free (as_t *asdata) +{ + XFREE (MTYPE_AS_SEG_DATA, asdata); +} + /* Get a new segment. Note that 0 is an allowed length, * and will result in a segment with no allocated data segment. * the caller should immediately assign data to the segment, as the segment @@ -126,7 +132,7 @@ assegment_free (struct assegment *seg) return; if (seg->as) - XFREE (MTYPE_AS_SEG_DATA, seg->as); + assegment_data_free (seg->as); memset (seg, 0xfe, sizeof(struct assegment)); XFREE (MTYPE_AS_SEG, seg); @@ -194,13 +200,14 @@ assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) if (num >= AS_SEGMENT_MAX) return seg; /* we don't do huge prepends */ - newas = assegment_data_new (seg->length + num); - + if ((newas = assegment_data_new (seg->length + num)) == NULL) + return seg; + for (i = 0; i < num; i++) newas[i] = asnum; memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); - XFREE (MTYPE_AS_SEG_DATA, seg->as); + assegment_data_free (seg->as); seg->as = newas; seg->length += num; @@ -1879,6 +1886,7 @@ aspath_init (void) void aspath_finish (void) { + hash_clean (ashash, (void (*)(void *))aspath_free); hash_free (ashash); ashash = NULL; diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5c832edcd..d413e5b26 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -203,6 +203,7 @@ cluster_init (void) static void cluster_finish (void) { + hash_clean (cluster_hash, (void (*)(void *))cluster_free); hash_free (cluster_hash); cluster_hash = NULL; } @@ -279,6 +280,7 @@ transit_init (void) static void transit_finish (void) { + hash_clean (transit_hash, (void (*)(void *))transit_free); hash_free (transit_hash); transit_hash = NULL; } @@ -452,9 +454,20 @@ attrhash_init (void) attrhash = hash_create (attrhash_key_make, attrhash_cmp); } +/* + * special for hash_clean below + */ +static void +attr_vfree (void *attr) +{ + bgp_attr_extra_free ((struct attr *)attr); + XFREE (MTYPE_ATTR, attr); +} + static void attrhash_finish (void) { + hash_clean(attrhash, attr_vfree); hash_free (attrhash); attrhash = NULL; } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index cacff2348..591a6f930 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -37,6 +37,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "plist.h" #include "stream.h" #include "vrf.h" +#include "workqueue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -196,10 +197,12 @@ sigint (void) { zlog_notice ("Terminating on signal"); - if (! retain_mode) - bgp_terminate (); + if (! retain_mode) + { + bgp_terminate (); + zprivs_terminate (&bgpd_privs); + } - zprivs_terminate (&bgpd_privs); bgp_exit (0); } @@ -234,7 +237,27 @@ bgp_exit (int status) for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) bgp_delete (bgp); list_free (bm->bgp); - + bm->bgp = NULL; + + /* + * bgp_delete can re-allocate the process queues after they were + * deleted in bgp_terminate. delete them again. + * + * It might be better to ensure the RIBs (including static routes) + * are cleared by bgp_terminate() during its call to bgp_cleanup_routes(), + * which currently only deletes the kernel routes. + */ + if (bm->process_main_queue) + { + work_queue_free (bm->process_main_queue); + bm->process_main_queue = NULL; + } + if (bm->process_rsclient_queue) + { + work_queue_free (bm->process_rsclient_queue); + bm->process_rsclient_queue = NULL; + } + /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket)) { @@ -447,10 +470,11 @@ main (int argc, char **argv) vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); /* Print banner. */ - zlog_notice ("BGPd %s starting: vty@%d, bgp@%s:%d", QUAGGA_VERSION, + zlog_notice ("BGPd %s starting: vty@%d, bgp@%s:%d pid %d", QUAGGA_VERSION, vty_port, (bm->address ? bm->address : ""), - bm->port); + bm->port, + getpid ()); /* Start finite state machine, here we go! */ while (thread_fetch (bm->master, &thread)) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 8a1ed70e2..a72d5edeb 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -170,11 +170,12 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, int str2prefix_rd (const char *str, struct prefix_rd *prd) { - int ret; + int ret; /* ret of called functions */ + int lret; /* local ret, of this func */ char *p; char *p2; - struct stream *s; - char *half; + struct stream *s = NULL; + char *half = NULL; struct in_addr addr; s = stream_new (8); @@ -182,12 +183,13 @@ str2prefix_rd (const char *str, struct prefix_rd *prd) prd->family = AF_UNSPEC; prd->prefixlen = 64; + lret = 0; p = strchr (str, ':'); if (! p) - return 0; + goto out; if (! all_digit (p + 1)) - return 0; + goto out; half = XMALLOC (MTYPE_TMP, (p - str) + 1); memcpy (half, str, (p - str)); @@ -198,10 +200,8 @@ str2prefix_rd (const char *str, struct prefix_rd *prd) if (! p2) { if (! all_digit (half)) - { - XFREE (MTYPE_TMP, half); - return 0; - } + goto out; + stream_putw (s, RD_TYPE_AS); stream_putw (s, atoi (half)); stream_putl (s, atol (p + 1)); @@ -210,18 +210,21 @@ str2prefix_rd (const char *str, struct prefix_rd *prd) { ret = inet_aton (half, &addr); if (! ret) - { - XFREE (MTYPE_TMP, half); - return 0; - } + goto out; + stream_putw (s, RD_TYPE_IP); stream_put_in_addr (s, &addr); stream_putw (s, atol (p + 1)); } memcpy (prd->val, s->data, 8); - - XFREE(MTYPE_TMP, half); - return 1; + lret = 1; + +out: + if (s) + stream_free (s); + if (half) + XFREE(MTYPE_TMP, half); + return lret; } int diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 8621854b4..3c5e6c5d5 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -276,6 +276,7 @@ bgp_bind (struct peer *peer) #ifdef SO_BINDTODEVICE int ret; struct ifreq ifreq; + int myerrno; if (! peer->ifname) return 0; @@ -287,13 +288,15 @@ bgp_bind (struct peer *peer) ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof (ifreq)); - + myerrno = errno; + if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("bgp_bind: could not lower privs"); if (ret < 0) { - zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname); + zlog (peer->log, LOG_INFO, "bind to interface %s failed, errno=%d", + peer->ifname, myerrno); return ret; } #endif /* SO_BINDTODEVICE */ diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index bb658afbf..145a1d883 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1439,29 +1439,29 @@ bgp_scan_init (void) void bgp_scan_finish (void) { - /* Only the current one needs to be reset. */ - bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]); - - bgp_table_unlock (cache1_table[AFI_IP]); + if (cache1_table[AFI_IP]) + bgp_table_unlock (cache1_table[AFI_IP]); cache1_table[AFI_IP] = NULL; - bgp_table_unlock (cache2_table[AFI_IP]); + if (cache2_table[AFI_IP]) + bgp_table_unlock (cache2_table[AFI_IP]); cache2_table[AFI_IP] = NULL; - - bgp_table_unlock (bgp_connected_table[AFI_IP]); + + if (bgp_connected_table[AFI_IP]) + bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; #ifdef HAVE_IPV6 - /* Only the current one needs to be reset. */ - bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]); - - bgp_table_unlock (cache1_table[AFI_IP6]); + if (cache1_table[AFI_IP6]) + bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; - bgp_table_unlock (cache2_table[AFI_IP6]); + if (cache2_table[AFI_IP6]) + bgp_table_unlock (cache2_table[AFI_IP6]); cache2_table[AFI_IP6] = NULL; - bgp_table_unlock (bgp_connected_table[AFI_IP6]); + if (bgp_connected_table[AFI_IP6]) + bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; #endif /* HAVE_IPV6 */ } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3fdd9ff69..90e77f217 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -737,6 +737,9 @@ peer_free (struct peer *peer) if (peer->clear_node_queue) work_queue_free (peer->clear_node_queue); + if (peer->notify.data) + XFREE(MTYPE_TMP, peer->notify.data); + bgp_sync_delete (peer); memset (peer, 0, sizeof (struct peer)); @@ -1988,7 +1991,7 @@ bgp_create (as_t *as, const char *name) struct bgp * bgp_get_default (void) { - if (bm->bgp->head) + if (bm && bm->bgp && bm->bgp->head) return (listgetdata (listhead (bm->bgp))); return NULL; } diff --git a/lib/routemap.c b/lib/routemap.c index 1e1510ebd..7302e2311 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -897,6 +897,9 @@ route_map_finish (void) route_match_vec = NULL; vector_free (route_set_vec); route_set_vec = NULL; + /* cleanup route_map */ + while (route_map_master.head) + route_map_delete (route_map_master.head); } /* VTY related functions. */ From be62b17c736ea06181f2788e3011066830555610 Mon Sep 17 00:00:00 2001 From: Michael Zingg Date: Fri, 26 Oct 2012 11:18:19 +0200 Subject: [PATCH 0862/1342] isisd: Fix LSPs not being regenerated after adjacency change In isisd LSP's are not regenerated after a change in adjacency if lsp-gen-interval has expired. I have tested this on Debian 6.0 with zebra and level1 isisd with point to point links. This problem is also listed in Test ISIS-18.3 on the opensourcerouting.org wiki: http://confluence.isc.org/display/osr/ANVL+ISIS+Compliance+Test+Plan http://confluence.isc.org/display/osr/ANVL+ISIS+Results --- isisd/isis_lsp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 0b1dac181..0470c5b90 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1789,7 +1789,18 @@ lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) } else { - lsp_regenerate (area, lvl); + /* + * lsps are not regenerated if lsp_regenerate function is called + * directly. However if the lsp_regenerate call is queued for + * later execution it works. + */ + area->lsp_regenerate_pending[lvl - 1] = 1; + if (lvl == IS_LEVEL_1) + THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], + lsp_l1_refresh, area, 0); + else if (lvl == IS_LEVEL_2) + THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], + lsp_l2_refresh, area, 0); } } From ffe794426af2b142ecfed7021d34d8f868857219 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 29 Oct 2015 14:24:13 +0000 Subject: [PATCH 0863/1342] pimd: Fix size_t zlog_err format string warning * fc1c114aa / "pimd: Fix warning", the size_t arg should have a %zu format. --- pimd/pim_static.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_static.c b/pimd/pim_static.c index e43c59a52..cbbcaaa9b 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -42,7 +42,7 @@ static struct static_route * static_route_alloc() s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route)); if (!s_route) { - zlog_err("PIM XCALLOC(%u) failure", sizeof(*s_route)); + zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route)); return 0; } return s_route; From e56aab94a615a2b676473fbd09145b444a348029 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 20 Oct 2015 16:14:56 +0100 Subject: [PATCH 0864/1342] doc: Add 'OSPF Fundamentals' section to OSPF docs * ospf_fundamentals.texi: New section explaining the fundamentals of OSPF for system admins, to help them debug their networks. * {Makefile.am,ospfd.texi}: include and build previous Conflicts: doc/Makefile.am --- doc/Makefile.am | 2 +- doc/ospf_fundamentals.texi | 582 +++++++++++++++++++++++++++++++++++++ doc/ospfd.texi | 3 + 3 files changed, 586 insertions(+), 1 deletion(-) create mode 100644 doc/ospf_fundamentals.texi diff --git a/doc/Makefile.am b/doc/Makefile.am index 3ff317014..943f06b3a 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -50,7 +50,7 @@ quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ - snmptrap.texi $(figures_txt) + snmptrap.texi ospf_fundamentals.texi $(figures_txt) .png.eps: $(PNGTOEPS) $< "$@" diff --git a/doc/ospf_fundamentals.texi b/doc/ospf_fundamentals.texi new file mode 100644 index 000000000..82218e601 --- /dev/null +++ b/doc/ospf_fundamentals.texi @@ -0,0 +1,582 @@ +@c Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. +@cindex OSPF Fundamentals +@node OSPF Fundamentals +@section OSPF Fundamentals + +@cindex Link-state routing protocol +@cindex Distance-vector routing protocol +@acronym{OSPF} is, mostly, a link-state routing protocol. In contrast +to @dfn{distance-vector} protocols, such as @acronym{RIP} or +@acronym{BGP}, where routers describe available @dfn{paths} (i.e@. routes) +to each other, in @dfn{link-state} protocols routers instead +describe the state of their links to their immediate neighbouring +routers. + +@cindex Link State Announcement +@cindex Link State Advertisement +@cindex LSA flooding +@cindex Link State DataBase +Each router describes their link-state information in a message known +as an @acronym{LSA,Link State Advertisement}, which is then propogated +through to all other routers in a link-state routing domain, by a +process called @dfn{flooding}. Each router thus builds up an +@acronym{LSDB,Link State Database} of all the link-state messages. From +this collection of LSAs in the LSDB, each router can then calculate the +shortest path to any other router, based on some common metric, by +using an algorithm such as @url{http://www.cs.utexas.edu/users/EWD/, +Edgser Dijkstra}'s @acronym{SPF,Shortest Path First}. + +@cindex Link-state routing protocol advantages +By describing connectivity of a network in this way, in terms of +routers and links rather than in terms of the paths through a network, +a link-state protocol can use less bandwidth and converge more quickly +than other protocols. A link-state protocol need distribute only one +link-state message throughout the link-state domain when a link on any +single given router changes state, in order for all routers to +reconverge on the best paths through the network. In contrast, distance +vector protocols can require a progression of different path update +messages from a series of different routers in order to converge. + +@cindex Link-state routing protocol disadvantages +The disadvantage to a link-state protocol is that the process of +computing the best paths can be relatively intensive when compared to +distance-vector protocols, in which near to no computation need be done +other than (potentially) select between multiple routes. This overhead +is mostly negligible for modern embedded CPUs, even for networks with +thousands of nodes. The primary scaling overhead lies more in coping +with the ever greater frequency of LSA updates as the size of a +link-state area increases, in managing the @acronym{LSDB} and required +flooding. + +This section aims to give a distilled, but accurate, description of the +more important workings of @acronym{OSPF}@ which an administrator may need +to know to be able best configure and trouble-shoot @acronym{OSPF}@. + +@subsection OSPF Mechanisms + +@acronym{OSPF} defines a range of mechanisms, concerned with detecting, +describing and propogating state through a network. These mechanisms +will nearly all be covered in greater detail further on. They may be +broadly classed as: + +@table @dfn +@cindex OSPF Hello Protocol overview +@item The Hello Protocol + +@cindex OSPF Hello Protocol +The OSPF Hello protocol allows OSPF to quickly detect changes in +two-way reachability between routers on a link. OSPF can additionally +avail of other sources of reachability information, such as link-state +information provided by hardware, or through dedicated reachability +protocols such as @acronym{BFD,Bi-directional Forwarding Detection}. + +OSPF also uses the Hello protocol to propagate certain state between +routers sharing a link, for example: + +@itemize @bullet +@item Hello protocol configured state, such as the dead-interval. +@item Router priority, for DR/BDR election. +@item DR/BDR election results. +@item Any optional capabilities supported by each router. +@end itemize + +The Hello protocol is comparatively trivial and will not be explored in +greater detail than here. + +@cindex OSPF LSA overview +@item LSAs + +At the heart of @acronym{OSPF} are @acronym{LSA,Link State +Advertisement} messages. Despite the name, some @acronym{LSA}s do not, +strictly speaking, describe link-state information. Common +@acronym{LSA}s describe information such as: + +@itemize @bullet +@item +Routers, in terms of their links. +@item +Networks, in terms of attached routers. +@item +Routes, external to a link-state domain: + +@itemize @bullet +@item External Routes + +Routes entirely external to @acronym{OSPF}@. Routers originating such +routes are known as @acronym{ASBR,Autonomous-System Border Router} +routers. + +@item Summary Routes + +Routes which summarise routing information relating to OSPF areas +external to the OSPF link-state area at hand, originated by +@acronym{ABR,Area Boundary Router} routers. +@end itemize +@end itemize + +@item LSA Flooding +OSPF defines several related mechanisms, used to manage synchronisation of +@acronym{LSDB}s between neighbours as neighbours form adjacencies and +the propogation, or @dfn{flooding} of new or updated @acronym{LSA}s. + +@xref{OSPF Flooding}. + +@cindex OSPF Areas overview +@item Areas +OSPF provides for the protocol to be broken up into multiple smaller +and independent link-state areas. Each area must be connected to a +common backbone area by an @acronym{ABR,Area Boundary Router}. These +@acronym{ABR} routers are responsible for summarising the link-state +routing information of an area into @dfn{Summary LSAs}, possibly in a +condensed (i.e. aggregated) form, and then originating these summaries +into all other areas the @acronym{ABR} is connected to. + +Note that only summaries and external routes are passed between areas. +As these describe @emph{paths}, rather than any router link-states, +routing between areas hence is by @dfn{distance-vector}, @strong{not} +link-state. + +@xref{OSPF Areas}. +@end table + +@subsection OSPF LSAs + +@acronym{LSA}s are the core object in OSPF@. Everything else in OSPF +revolves around detecting what to describe in LSAs, when to update +them, how to flood them throughout a network and how to calculate +routes from them. + +There are a variety of different @acronym{LSA}s, for purposes such +as describing actual link-state information, describing paths (i.e. +routes), describing bandwidth usage of links for +@acronym{TE,Traffic Engineering} purposes, and even arbitrary data +by way of @emph{Opaque} @acronym{LSA}s. + +@subsubsection LSA Header +All LSAs share a common header with the following information: + +@itemize @bullet +@item Type + +Different types of @acronym{LSA}s describe different things in +@acronym{OSPF}@. Types include: + +@itemize @bullet +@item Router LSA +@item Network LSA +@item Network Summary LSA +@item Router Summary LSA +@item AS-External LSA +@end itemize + +The specifics of the different types of LSA are examined below. + +@item Advertising Router + +The Router ID of the router originating the LSA, see @ref{ospf router-id}. + +@item LSA ID + +The ID of the LSA, which is typically derived in some way from the +information the LSA describes, e.g. a Router LSA uses the Router ID as +the LSA ID, a Network LSA will have the IP address of the @acronym{DR} +as its LSA ID@. + +The combination of the Type, ID and Advertising Router ID must uniquely +identify the @acronym{LSA}@. There can however be multiple instances of +an LSA with the same Type, LSA ID and Advertising Router ID, see +@ref{OSPF LSA sequence number,,LSA Sequence Number}. + +@item Age + +A number to allow stale @acronym{LSA}s to, eventually, be purged by routers +from their @acronym{LSDB}s. + +The value nominally is one of seconds. An age of 3600, i.e. 1 hour, is +called the @dfn{MaxAge}. MaxAge LSAs are ignored in routing +calculations. LSAs must be periodically refreshed by their Advertising +Router before reaching MaxAge if they are to remain valid. + +Routers may deliberately flood LSAs with the age artificially set to +3600 to indicate an LSA is no longer valid. This is called +@dfn{flushing} of an LSA@. + +It is not abnormal to see stale LSAs in the LSDB, this can occur where +a router has shutdown without flushing its LSA(s), e.g. where it has +become disconnected from the network. Such LSAs do little harm. + +@anchor{OSPF LSA sequence number} +@item Sequence Number + +A number used to distinguish newer instances of an LSA from older instances. +@end itemize + +@subsubsection Link-State LSAs +Of all the various kinds of @acronym{LSA}s, just two types comprise the +actual link-state part of @acronym{OSPF}, Router @acronym{LSA}s and +Network @acronym{LSA}s. These LSA types are absolutely core to the +protocol. + +Instances of these LSAs are specific to the link-state area in which +they are originated. Routes calculated from these two LSA types are +called @dfn{intra-area routes}. + +@itemize @bullet +@item Router LSA + +Each OSPF Router must originate a router @acronym{LSA} to describe +itself. In it, the router lists each of its @acronym{OSPF} enabled +interfaces, for the given link-state area, in terms of: + +@itemize @bullet +@item Cost + +The output cost of that interface, scaled inversely to some commonly known +reference value, @xref{OSPF auto-cost reference-bandwidth,,auto-cost +reference-bandwidth}. + +@item Link Type +@itemize @bullet +@item Transit Network + +A link to a multi-access network, on which the router has at least one +Full adjacency with another router. + +@item @acronym{PtP,Point-to-Point} + +A link to a single remote router, with a Full adjacency. No +@acronym{DR, Designated Router} is elected on such links; no network +LSA is originated for such a link. + +@item Stub + +A link with no adjacent neighbours, or a host route. +@end itemize + +@item Link ID and Data + +These values depend on the Link Type: + +@multitable @columnfractions .18 .32 .32 +@headitem Link Type @tab Link ID @tab Link Data + +@item Transit +@tab Link IP address of the @acronym{DR} +@tab Interface IP address + +@item Point-to-Point +@tab Router ID of the remote router +@tab Local interface IP address, +or the @acronym{ifindex,MIB-II interface index} +for unnumbered links + +@item Stub +@tab IP address +@tab Subnet Mask + +@end multitable +@end itemize + +Links on a router may be listed multiple times in the Router LSA, e.g. +a @acronym{PtP} interface on which OSPF is enabled must @emph{always} +be described by a Stub link in the Router @acronym{LSA}, in addition to +being listed as PtP link in the Router @acronym{LSA} if the adjacency +with the remote router is Full. + +Stub links may also be used as a way to describe links on which OSPF is +@emph{not} spoken, known as @dfn{passive interfaces}, see @ref{OSPF +passive-interface,,passive-interface}. + +@item Network LSA + +On multi-access links (e.g. ethernets, certain kinds of ATM and X@.25 +configurations), routers elect a @acronym{DR}@. The @acronym{DR} is +responsible for originating a Network @acronym{LSA}, which helps reduce +the information needed to describe multi-access networks with multiple +routers attached. The @acronym{DR} also acts as a hub for the flooding of +@acronym{LSA}s on that link, thus reducing flooding overheads. + +The contents of the Network LSA describes the: + +@itemize @bullet +@item Subnet Mask + +As the @acronym{LSA} ID of a Network LSA must be the IP address of the +@acronym{DR}, the Subnet Mask together with the @acronym{LSA} ID gives +you the network address. + +@item Attached Routers + +Each router fully-adjacent with the @acronym{DR} is listed in the LSA, +by their Router-ID. This allows the corresponding Router @acronym{LSA}s to be +easily retrieved from the @acronym{LSDB}@. +@end itemize +@end itemize + +Summary of Link State LSAs: + +@multitable @columnfractions .18 .32 .40 +@headitem LSA Type @tab LSA ID Describes @tab LSA Data Describes + +@item Router LSA +@tab The Router ID +@tab The @acronym{OSPF} enabled links of the router, within + a specific link-state area. + +@item Network LSA +@tab The IP address of the @acronym{DR} for the network +@tab The Subnet Mask of the network, and the Router IDs of all routers + on the network. +@end multitable + +With an LSDB composed of just these two types of @acronym{LSA}, it is +possible to construct a directed graph of the connectivity between all +routers and networks in a given OSPF link-state area. So, not +surprisingly, when OSPF routers build updated routing tables, the first +stage of @acronym{SPF} calculation concerns itself only with these two +LSA types. + +@subsubsection Link-State LSA Examples + +The example below (@pxref{OSPF Link-State LSA Example}) shows two +@acronym{LSA}s, both originated by the same router (Router ID +192.168.0.49) and with the same @acronym{LSA} ID (192.168.0.49), but of +different LSA types. + +The first LSA being the router LSA describing 192.168.0.49's links: 2 links +to multi-access networks with fully-adjacent neighbours (i.e. Transit +links) and 1 being a Stub link (no adjacent neighbours). + +The second LSA being a Network LSA, for which 192.168.0.49 is the +@acronym{DR}, listing the Router IDs of 4 routers on that network which +are fully adjacent with 192.168.0.49. + +@anchor{OSPF Link-State LSA Example} +@example +# show ip ospf database router 192.168.0.49 + + OSPF Router with ID (192.168.0.53) + + + Router Link States (Area 0.0.0.0) + + LS age: 38 + Options: 0x2 : *|-|-|-|-|-|E|* + LS Flags: 0x6 + Flags: 0x2 : ASBR + LS Type: router-LSA + Link State ID: 192.168.0.49 + Advertising Router: 192.168.0.49 + LS Seq Number: 80000f90 + Checksum: 0x518b + Length: 60 + Number of Links: 3 + + Link connected to: a Transit Network + (Link ID) Designated Router address: 192.168.1.3 + (Link Data) Router Interface address: 192.168.1.3 + Number of TOS metrics: 0 + TOS 0 Metric: 10 + + Link connected to: a Transit Network + (Link ID) Designated Router address: 192.168.0.49 + (Link Data) Router Interface address: 192.168.0.49 + Number of TOS metrics: 0 + TOS 0 Metric: 10 + + Link connected to: Stub Network + (Link ID) Net: 192.168.3.190 + (Link Data) Network Mask: 255.255.255.255 + Number of TOS metrics: 0 + TOS 0 Metric: 39063 +# show ip ospf database network 192.168.0.49 + + OSPF Router with ID (192.168.0.53) + + + Net Link States (Area 0.0.0.0) + + LS age: 285 + Options: 0x2 : *|-|-|-|-|-|E|* + LS Flags: 0x6 + LS Type: network-LSA + Link State ID: 192.168.0.49 (address of Designated Router) + Advertising Router: 192.168.0.49 + LS Seq Number: 80000074 + Checksum: 0x0103 + Length: 40 + Network Mask: /29 + Attached Router: 192.168.0.49 + Attached Router: 192.168.0.52 + Attached Router: 192.168.0.53 + Attached Router: 192.168.0.54 +@end example + +Note that from one LSA, you can find the other. E.g. Given the +Network-LSA you have a list of Router IDs on that network, from which +you can then look up, in the local @acronym{LSDB}, the matching Router +LSA@. From that Router-LSA you may (potentially) find links to other +Transit networks and Routers IDs which can be used to lookup the +corresponding Router or Network LSA@. And in that fashion, one can find +all the Routers and Networks reachable from that starting @acronym{LSA}@. + +Given the Router LSA instead, you have the IP address of the +@acronym{DR} of any attached transit links. Network LSAs will have that IP +as their LSA ID, so you can then look up that Network LSA and from that +find all the attached routers on that link, leading potentially to more +links and Network and Router LSAs, etc. etc. + +From just the above two @acronym{LSA}s, one can already see the +following partial topology: +@example +@group + + + --------------------- Network: ...... + | Designated Router IP: 192.168.1.3 + | + IP: 192.168.1.3 + (transit link) + (cost: 10) + Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32 + (cost: 10) (cost: 39063) + (transit link) + IP: 192.168.0.49 + | + | +------------------------------ Network: 192.168.0.48/29 + | | | Designated Router IP: 192.168.0.49 + | | | + | | Router ID: 192.168.0.54 + | | + | Router ID: 192.168.0.53 + | +Router ID: 192.168.0.52 +@end group +@end example + +Note the Router IDs, though they look like IP addresses and often are +IP addresses, are not strictly speaking IP addresses, nor need they be +reachable addresses (though, OSPF will calculate routes to Router IDs). + +@subsubsection External LSAs + +External, or "Type 5", @acronym{LSA}s describe routing information which is +entirely external to @acronym{OSPF}, and is "injected" into +@acronym{OSPF}@. Such routing information may have come from another +routing protocol, such as RIP or BGP, they may represent static routes +or they may represent a default route. + +An @acronym{OSPF} router which originates External @acronym{LSA}s is known as an +@acronym{ASBR,AS Boundary Router}. Unlike the link-state @acronym{LSA}s, and +most other @acronym{LSA}s, which are flooded only within the area in +which they originate, External @acronym{LSA}s are flooded through-out +the @acronym{OSPF} network to all areas capable of carrying External +@acronym{LSA}s (@pxref{OSPF Areas}). + +Routes internal to OSPF (intra-area or inter-area) are always preferred +over external routes. + +The External @acronym{LSA} describes the following: + +@itemize @bullet +@item IP Network number + +The IP Network number of the route is described by the @acronym{LSA} ID +field. + +@item IP Network Mask + +The body of the External LSA describes the IP Network Mask of the +route. This, together with the @acronym{LSA} ID, describes the prefix +of the IP route concerned. + +@item Metric + +The cost of the External Route. This cost may be an OSPF cost (also +known as a "Type 1" metric), i.e. equivalent to the normal OSPF costs, +or an externally derived cost ("Type 2" metric) which is not comparable +to OSPF costs and always considered larger than any OSPF cost. Where +there are both Type 1 and 2 External routes for a route, the Type 1 is +always preferred. + +@item Forwarding Address + +The address of the router to forward packets to for the route. This may +be, and usually is, left as 0 to specify that the ASBR originating the +External @acronym{LSA} should be used. There must be an internal OSPF +route to the forwarding address, for the forwarding address to be +useable. + +@item Tag + +An arbitrary 4-bytes of data, not interpreted by OSPF, which may +carry whatever information about the route which OSPF speakers desire. +@end itemize + +@subsubsection AS External LSA Example + +To illustrate, below is an example of an External @acronym{LSA} in the +@acronym{LSDB} of an OSPF router. It describes a route to the IP prefix +of 192.168.165.0/24, originated by the ASBR with Router-ID +192.168.0.49. The metric of 20 is external to OSPF. The forwarding +address is 0, so the route should forward to the originating ASBR if +selected. + +@example +@group +# show ip ospf database external 192.168.165.0 + LS age: 995 + Options: 0x2 : *|-|-|-|-|-|E|* + LS Flags: 0x9 + LS Type: AS-external-LSA + Link State ID: 192.168.165.0 (External Network Number) + Advertising Router: 192.168.0.49 + LS Seq Number: 800001d8 + Checksum: 0xea27 + Length: 36 + Network Mask: /24 + Metric Type: 2 (Larger than any link state path) + TOS: 0 + Metric: 20 + Forward Address: 0.0.0.0 + External Route Tag: 0 +@end group +@end example + +We can add this to our partial topology from above, which now looks +like: +@example +@group + --------------------- Network: ...... + | Designated Router IP: 192.168.1.3 + | + IP: 192.168.1.3 /---- External route: 192.168.165.0/24 + (transit link) / Cost: 20 (External metric) + (cost: 10) / + Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32 + (cost: 10) (cost: 39063) + (transit link) + IP: 192.168.0.49 + | + | +------------------------------ Network: 192.168.0.48/29 + | | | Designated Router IP: 192.168.0.49 + | | | + | | Router ID: 192.168.0.54 + | | + | Router ID: 192.168.0.53 + | +Router ID: 192.168.0.52 +@end group +@end example + +@subsubsection Summary LSAs + +Summary LSAs are created by @acronym{ABR}s to summarise the destinations available within one area to other areas. These LSAs may describe IP networks, potentially in aggregated form, or @acronym{ASBR} routers. + +@anchor{OSPF Flooding} +@subsection OSPF Flooding + +@anchor{OSPF Areas} +@subsection OSPF Areas diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 7ddc9db8e..86cabe409 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -11,6 +11,7 @@ convergence times. OSPF is widely used in large networks such as networks. @menu +* OSPF Fundamentals:: * Configuring ospfd:: * OSPF router:: * OSPF area:: @@ -21,6 +22,8 @@ networks. * OSPF Configuration Examples:: @end menu +@include ospf_fundamentals.texi + @node Configuring ospfd @section Configuring ospfd From f822ad4326e8b279e028b8b2ca2282475b5e27de Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:47 -0700 Subject: [PATCH 0865/1342] bgpd: Lower the default 'timers connect' in BGP to 10 seconds Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- bgpd/bgpd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 95c16de00..be1c00761 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -751,7 +751,7 @@ struct bgp_nlri #define BGP_DEFAULT_EBGP_ROUTEADV 30 #define BGP_DEFAULT_IBGP_ROUTEADV 5 #define BGP_CLEAR_CONNECT_RETRY 20 -#define BGP_DEFAULT_CONNECT_RETRY 120 +#define BGP_DEFAULT_CONNECT_RETRY 10 /* BGP default local preference. */ #define BGP_DEFAULT_LOCAL_PREF 100 From 3ff77fe62ecdabc01f576de8c4e5d78d16e3e436 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:48 -0700 Subject: [PATCH 0866/1342] bgpd: Remove BGP's asorig timer, it is no longer used Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- bgpd/bgp_fsm.c | 8 -------- bgpd/bgp_snmp.c | 14 ++------------ bgpd/bgpd.c | 1 - bgpd/bgpd.h | 3 --- 4 files changed, 2 insertions(+), 24 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 9ac333526..182333673 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -101,7 +101,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; @@ -113,7 +112,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; @@ -133,7 +131,6 @@ bgp_timer_set (struct peer *peer) } BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; @@ -151,7 +148,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_OFF (peer->t_holdtime); } BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; @@ -174,7 +170,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; @@ -198,7 +193,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } - BGP_TIMER_OFF (peer->t_asorig); break; case Deleted: BGP_TIMER_OFF (peer->t_gr_restart); @@ -209,7 +203,6 @@ bgp_timer_set (struct peer *peer) BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); } } @@ -522,7 +515,6 @@ bgp_stop (struct peer *peer) BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); - BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); /* Stream reset. */ diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 6a578347f..662186b59 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -74,9 +74,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGPPEERKEEPALIVE 19 #define BGPPEERHOLDTIMECONFIGURED 20 #define BGPPEERKEEPALIVECONFIGURED 21 -#define BGPPEERMINASORIGINATIONINTERVAL 22 -#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23 -#define BGPPEERINUPDATEELAPSEDTIME 24 +#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 22 +#define BGPPEERINUPDATEELAPSEDTIME 23 /* BGP MIB bgpIdentifier. */ #define BGPIDENTIFIER 0 @@ -189,8 +188,6 @@ struct variable bgp_variables[] = 3, {3, 1, 20}}, {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 21}}, - {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable, - 3, {3, 1, 22}}, {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 23}}, {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable, @@ -440,9 +437,6 @@ write_bgpPeerTable (int action, u_char *var_val, peer->keepalive = intval; peer->v_keepalive = intval; break; - case BGPPEERMINASORIGINATIONINTERVAL: - peer->v_asorig = intval; - break; case BGPPEERMINROUTEADVERTISEMENTINTERVAL: peer->v_routeadv = intval; break; @@ -571,10 +565,6 @@ bgpPeerTable (struct variable *v, oid name[], size_t *length, else return SNMP_INTEGER (peer->v_keepalive); break; - case BGPPEERMINASORIGINATIONINTERVAL: - *write_method = write_bgpPeerTable; - return SNMP_INTEGER (peer->v_asorig); - break; case BGPPEERMINROUTEADVERTISEMENTINTERVAL: *write_method = write_bgpPeerTable; return SNMP_INTEGER (peer->v_routeadv); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 90e77f217..c94c381ff 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -805,7 +805,6 @@ peer_new (struct bgp *bgp) peer->fd = -1; peer->v_start = BGP_INIT_START_TIMER; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; - peer->v_asorig = BGP_DEFAULT_ASORIGINATE; peer->status = Idle; peer->ostatus = Idle; peer->weight = 0; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index be1c00761..1db2eb761 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -466,7 +466,6 @@ struct peer u_int32_t v_connect; u_int32_t v_holdtime; u_int32_t v_keepalive; - u_int32_t v_asorig; u_int32_t v_routeadv; u_int32_t v_pmax_restart; u_int32_t v_gr_restart; @@ -478,7 +477,6 @@ struct peer struct thread *t_connect; struct thread *t_holdtime; struct thread *t_keepalive; - struct thread *t_asorig; struct thread *t_routeadv; struct thread *t_pmax_restart; struct thread *t_gr_restart; @@ -747,7 +745,6 @@ struct bgp_nlri #define BGP_ERROR_START_TIMER 30 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 -#define BGP_DEFAULT_ASORIGINATE 15 #define BGP_DEFAULT_EBGP_ROUTEADV 30 #define BGP_DEFAULT_IBGP_ROUTEADV 5 #define BGP_CLEAR_CONNECT_RETRY 20 From 57fcfda56ad091a6850e190f5788361bf921699e Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:49 -0700 Subject: [PATCH 0867/1342] bgpd: Do not allow a timers connect of 0, this can hammer the CPU Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- bgpd/bgp_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4fd255fce..0b5be7302 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3402,7 +3402,7 @@ peer_timers_connect_unset_vty (struct vty *vty, const char *ip_str) DEFUN (neighbor_timers_connect, neighbor_timers_connect_cmd, - NEIGHBOR_CMD "timers connect <0-65535>", + NEIGHBOR_CMD "timers connect <1-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR "BGP per neighbor timers\n" @@ -3426,7 +3426,7 @@ DEFUN (no_neighbor_timers_connect, ALIAS (no_neighbor_timers_connect, no_neighbor_timers_connect_val_cmd, - NO_NEIGHBOR_CMD "timers connect <0-65535>", + NO_NEIGHBOR_CMD "timers connect <1-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR From c37b9bccdcc1266f52e50fa3e5a8dc81086c3fe7 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:50 -0700 Subject: [PATCH 0868/1342] bgpd: Enable "bgp log-neighbor-changes" by default Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- bgpd/bgpd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c94c381ff..c7f22e8bd 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1974,6 +1974,7 @@ bgp_create (as_t *as, const char *name) bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); bgp->as = *as; @@ -5259,8 +5260,8 @@ bgp_config_write (struct vty *vty) VTY_NEWLINE); /* BGP log-neighbor-changes. */ - if (bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) - vty_out (vty, " bgp log-neighbor-changes%s", VTY_NEWLINE); + if (!bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) + vty_out (vty, " no bgp log-neighbor-changes%s", VTY_NEWLINE); /* BGP configuration. */ if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) From 8e644534b4d20dde07306700be0503d09d30a16e Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:51 -0700 Subject: [PATCH 0869/1342] bgpd: Remove BGP_ERROR_START_TIMER, it was no longer used Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- bgpd/bgpd.h | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 1db2eb761..105912e96 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -742,7 +742,6 @@ struct bgp_nlri /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 -#define BGP_ERROR_START_TIMER 30 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 #define BGP_DEFAULT_EBGP_ROUTEADV 30 From f89b09be92bed03b1e5add55dc14ef92e94c52e1 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:52 -0700 Subject: [PATCH 0870/1342] bgpd: Lower BGP's default keepalive/holdtime to 3s/9s Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- bgpd/bgpd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 105912e96..d4c8dbd8a 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -742,8 +742,8 @@ struct bgp_nlri /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 -#define BGP_DEFAULT_HOLDTIME 180 -#define BGP_DEFAULT_KEEPALIVE 60 +#define BGP_DEFAULT_HOLDTIME 9 +#define BGP_DEFAULT_KEEPALIVE 3 #define BGP_DEFAULT_EBGP_ROUTEADV 30 #define BGP_DEFAULT_IBGP_ROUTEADV 5 #define BGP_CLEAR_CONNECT_RETRY 20 From 92e62e06ba9e03c4603538b3138298b274e3c167 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:53 -0700 Subject: [PATCH 0871/1342] ospfd: Lower the default OSPF spf timers to '0 50 5000' Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp --- lib/libospf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libospf.h b/lib/libospf.h index e8db5c133..9265ca59f 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -82,9 +82,9 @@ #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ /* SPF Throttling timer values. */ -#define OSPF_SPF_DELAY_DEFAULT 200 -#define OSPF_SPF_HOLDTIME_DEFAULT 1000 -#define OSPF_SPF_MAX_HOLDTIME_DEFAULT 10000 +#define OSPF_SPF_DELAY_DEFAULT 0 +#define OSPF_SPF_HOLDTIME_DEFAULT 50 +#define OSPF_SPF_MAX_HOLDTIME_DEFAULT 5000 #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 #define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 From 363c903435b154e989f0544d12d4ac8d50174c0b Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:42:54 -0700 Subject: [PATCH 0872/1342] bgpd: crash from not NULLing freed pointers Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp There was a crash from not NULLing out peer->hostname but I cleaned up a bunch of other suspect ones as well. --- bgpd/bgp_packet.c | 13 +++++- bgpd/bgpd.c | 105 +++++++++++++++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index e1ae494d3..4ab5b0640 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -967,8 +967,13 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, } } bgp_notify_print (peer, &bgp_notify, "sending"); + if (bgp_notify.data) - XFREE (MTYPE_TMP, bgp_notify.data); + { + XFREE (MTYPE_TMP, bgp_notify.data); + bgp_notify.data = NULL; + bgp_notify.length = 0; + } } if (BGP_DEBUG (normal, NORMAL)) @@ -1973,7 +1978,11 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size) bgp_notify_print(peer, &bgp_notify, "received"); if (bgp_notify.data) - XFREE (MTYPE_TMP, bgp_notify.data); + { + XFREE (MTYPE_TMP, bgp_notify.data); + bgp_notify.data = NULL; + bgp_notify.length = 0; + } } /* peer count update */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c7f22e8bd..60428586a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -721,21 +721,36 @@ peer_free (struct peer *peer) BGP_EVENT_FLUSH (peer); if (peer->desc) - XFREE (MTYPE_PEER_DESC, peer->desc); + { + XFREE (MTYPE_PEER_DESC, peer->desc); + peer->desc = NULL; + } /* Free allocated host character. */ if (peer->host) - XFREE (MTYPE_BGP_PEER_HOST, peer->host); - + { + XFREE (MTYPE_BGP_PEER_HOST, peer->host); + peer->host = NULL; + } + /* Update source configuration. */ if (peer->update_source) - sockunion_free (peer->update_source); + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } if (peer->update_if) - XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } if (peer->clear_node_queue) - work_queue_free (peer->clear_node_queue); + { + work_queue_free(peer->clear_node_queue); + peer->clear_node_queue = NULL; + } if (peer->notify.data) XFREE(MTYPE_TMP, peer->notify.data); @@ -1266,22 +1281,41 @@ peer_delete (struct peer *peer) /* Buffers. */ if (peer->ibuf) - stream_free (peer->ibuf); + { + stream_free (peer->ibuf); + peer->ibuf = NULL; + } + if (peer->obuf) - stream_fifo_free (peer->obuf); + { + stream_fifo_free (peer->obuf); + peer->obuf = NULL; + } + if (peer->work) - stream_free (peer->work); + { + stream_free (peer->work); + peer->work = NULL; + } + if (peer->scratch) - stream_free(peer->scratch); - peer->obuf = NULL; - peer->work = peer->scratch = peer->ibuf = NULL; + { + stream_free(peer->scratch); + peer->scratch = NULL; + } /* Local and remote addresses. */ if (peer->su_local) - sockunion_free (peer->su_local); + { + sockunion_free (peer->su_local); + peer->su_local = NULL; + } + if (peer->su_remote) - sockunion_free (peer->su_remote); - peer->su_local = peer->su_remote = NULL; + { + sockunion_free (peer->su_remote); + peer->su_remote = NULL; + } /* Free filter related memory. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) @@ -1292,31 +1326,44 @@ peer_delete (struct peer *peer) for (i = FILTER_IN; i < FILTER_MAX; i++) { if (filter->dlist[i].name) - free (filter->dlist[i].name); + { + free(filter->dlist[i].name); + filter->dlist[i].name = NULL; + } + if (filter->plist[i].name) - free (filter->plist[i].name); + { + free(filter->plist[i].name); + filter->plist[i].name = NULL; + } + if (filter->aslist[i].name) - free (filter->aslist[i].name); - - filter->dlist[i].name = NULL; - filter->plist[i].name = NULL; - filter->aslist[i].name = NULL; + { + free(filter->aslist[i].name); + filter->aslist[i].name = NULL; + } } + for (i = RMAP_IN; i < RMAP_MAX; i++) { if (filter->map[i].name) - free (filter->map[i].name); - filter->map[i].name = NULL; + { + free (filter->map[i].name); + filter->map[i].name = NULL; + } } if (filter->usmap.name) - free (filter->usmap.name); + { + free (filter->usmap.name); + filter->usmap.name = NULL; + } if (peer->default_rmap[afi][safi].name) - free (peer->default_rmap[afi][safi].name); - - filter->usmap.name = NULL; - peer->default_rmap[afi][safi].name = NULL; + { + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = NULL; + } } peer_unlock (peer); /* initial reference */ From c8af680df5beb613fd50c265773a6beb0f1768c9 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 21 Oct 2015 06:56:44 -0700 Subject: [PATCH 0873/1342] lib: Add zlog_hexdump() for debugging Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Signed-off-by: Donald Sharp --- lib/log.c | 42 ++++++++++++++++++++++++++++++++++++++++++ lib/log.h | 2 ++ 2 files changed, 44 insertions(+) diff --git a/lib/log.c b/lib/log.c index f02e4c736..10a771e1e 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1001,3 +1001,45 @@ proto_redistnum(int afi, const char *s) } return -1; } + +void +zlog_hexdump (void *mem, unsigned int len) { + unsigned long i = 0; + unsigned int j = 0; + unsigned int columns = 8; + char buf[(len * 4) + ((len/4) * 20) + 30]; + char *s = buf; + + for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0); i++) + { + /* print offset */ + if (i % columns == 0) + s += sprintf(s, "0x%016lx: ", (unsigned long)mem + i); + + /* print hex data */ + if (i < len) + s += sprintf(s, "%02x ", 0xFF & ((char*)mem)[i]); + + /* end of block, just aligning for ASCII dump */ + else + s += sprintf(s, " "); + + /* print ASCII dump */ + if (i % columns == (columns - 1)) + { + for (j = i - (columns - 1); j <= i; j++) + { + if (j >= len) /* end of block, not really printing */ + s += sprintf(s, " "); + + else if(isprint(((char*)mem)[j])) /* printable char */ + s += sprintf(s, "%c", 0xFF & ((char*)mem)[j]); + + else /* other char */ + s += sprintf(s, "."); + } + s += sprintf(s, "\n"); + } + } + zlog_debug("\n%s", buf); +} diff --git a/lib/log.h b/lib/log.h index 77cd53bc2..514884cc9 100644 --- a/lib/log.h +++ b/lib/log.h @@ -189,6 +189,8 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter); extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, char *buf, size_t buflen); +extern void zlog_hexdump(void *mem, unsigned int len); + /* structure useful for avoiding repeated rendering of the same timestamp */ struct timestamp_control { size_t len; /* length of rendered timestamp */ From bf99b420a57b7c5bf44c8ab528d0a2e416b66d81 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 21 Oct 2015 10:00:47 -0400 Subject: [PATCH 0874/1342] bgpd: Fix bgp_btoa to compile bgp_btoa was abandoned at some point in time in the past. This commit gets it to compile and to be added to /usr/bin. At this point in time no work has done for 'correctness' of execution Signed-off-by: Donald Sharp --- bgpd/Makefile.am | 4 ++++ bgpd/bgp_btoa.c | 55 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index b2614f46f..a35ad870f 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -8,6 +8,7 @@ AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libbgp.a sbin_PROGRAMS = bgpd +bin_PROGRAMS = bgp_btoa libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ @@ -26,6 +27,9 @@ noinst_HEADERS = \ bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ +bgp_btoa_SOURCES = bgp_btoa.c +bgp_btoa_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ + examplesdir = $(exampledir) dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index 7c7088145..edc80b2fe 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -25,12 +25,36 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "prefix.h" #include "command.h" +#include "memory.h" +#include "privs.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" +/* privileges */ +static zebra_capabilities_t _caps_p [] = +{ + ZCAP_BIND, + ZCAP_NET_RAW, + ZCAP_NET_ADMIN, +}; + +struct zebra_privs_t bgpd_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) + .user = QUAGGA_USER, + .group = QUAGGA_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0, +}; + enum MRT_MSG_TYPES { MSG_NULL, MSG_START, /* sender is starting up */ @@ -47,7 +71,7 @@ enum MRT_MSG_TYPES { MSG_TABLE_DUMP /* routing table dump */ }; -int +static int attr_parse (struct stream *s, u_int16_t len) { u_int flag; @@ -57,14 +81,14 @@ attr_parse (struct stream *s, u_int16_t len) lim = s->getp + len; - printf ("attr_parse s->getp %d, len %d, lim %d\n", s->getp, len, lim); + printf ("attr_parse s->getp %zd, len %d, lim %d\n", s->getp, len, lim); while (s->getp < lim) { flag = stream_getc (s); type = stream_getc (s); - if (flag & ATTR_FLAG_EXTLEN) + if (flag & BGP_ATTR_FLAG_EXTLEN) length = stream_getw (s); else length = stream_getc (s); @@ -84,27 +108,22 @@ attr_parse (struct stream *s, u_int16_t len) break; case BGP_ATTR_AS_PATH: { - struct aspath aspath; - - aspath.data = (s->data + s->getp); - aspath.length = length; - aspath.str = aspath_make_str_count (&aspath); - printf ("ASPATH: %s\n", aspath.str); - free (aspath.str); - - stream_forward (s, length); + struct aspath *aspath; + + aspath = aspath_parse (s, length, 1); + printf ("ASPATH: %s\n", aspath->str); + aspath_free(aspath); } break; - case BGP_ATTR_NEXT_HOP: + case BGP_ATTR_NEXT_HOP: { struct in_addr nexthop; nexthop.s_addr = stream_get_ipv4 (s); printf ("NEXTHOP: %s\n", inet_ntoa (nexthop)); - /* stream_forward (s, length); */ } break; default: - stream_forward (s, length); + stream_getw_from (s, length); break; } } @@ -121,7 +140,7 @@ main (int argc, char **argv) time_t now; int type; int subtype; - int len; + size_t len; int source_as; int dest_as; int ifindex; @@ -150,7 +169,7 @@ main (int argc, char **argv) stream_reset (s); ret = fread (s->data, 12, 1, fp); - if (feof (fp)) + if (!ret || feof (fp)) { printf ("END OF FILE\n"); break; @@ -213,7 +232,7 @@ main (int argc, char **argv) } } - printf ("len: %d\n", len); + printf ("len: %zd\n", len); ret = fread (s->data + 12, len, 1, fp); if (feof (fp)) From 6d853c43d9dd315eb42211150b7a4a43bae4cb62 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 21 Oct 2015 16:13:51 -0400 Subject: [PATCH 0875/1342] pimd: Limit pim hello log messages pimd was outputting allot of data surrounding pim hello packets. In addition the debugging was inconsistent and not all turned on via 'debug pim packet hello'. Signed-off-by: Donald Sharp --- pimd/pim_hello.c | 115 ++++++++++++++++++++++++++++------------------- pimd/pim_pim.c | 18 +++++--- pimd/pim_tlv.c | 36 +++++---------- 3 files changed, 89 insertions(+), 80 deletions(-) diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 128578318..bfc128b97 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -160,7 +160,8 @@ int pim_hello_recv(struct interface *ifp, uint32_t hello_option_generation_id = 0; struct list *hello_option_addr_list = 0; - on_trace(__PRETTY_FUNCTION__, ifp, src_addr); + if (PIM_DEBUG_PIM_HELLO) + on_trace(__PRETTY_FUNCTION__, ifp, src_addr); pim_ifp = ifp->info; zassert(pim_ifp); @@ -180,12 +181,14 @@ int pim_hello_recv(struct interface *ifp, int remain = tlv_pastend - tlv_curr; if (remain < PIM_TLV_MIN_SIZE) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", - __PRETTY_FUNCTION__, - remain, PIM_TLV_MIN_SIZE, - src_str, ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", + __PRETTY_FUNCTION__, + remain, PIM_TLV_MIN_SIZE, + src_str, ifp->name); + } FREE_ADDR_LIST_THEN_RETURN(-1); } @@ -195,16 +198,18 @@ int pim_hello_recv(struct interface *ifp, tlv_curr += PIM_TLV_LENGTH_SIZE; if ((tlv_curr + option_len) > tlv_pastend) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", - __PRETTY_FUNCTION__, - option_type, option_len, tlv_pastend - tlv_curr, - src_str, ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", + __PRETTY_FUNCTION__, + option_type, option_len, tlv_pastend - tlv_curr, + src_str, ifp->name); + } FREE_ADDR_LIST_THEN_RETURN(-2); } - if (PIM_DEBUG_PIM_TRACE || PIM_DEBUG_PIM_HELLO) { + if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", @@ -262,7 +267,7 @@ int pim_hello_recv(struct interface *ifp, } break; case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: - if (PIM_DEBUG_PIM_TRACE || PIM_DEBUG_PIM_HELLO) { + if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", @@ -272,13 +277,13 @@ int pim_hello_recv(struct interface *ifp, } break; default: - { + if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", - __PRETTY_FUNCTION__, - option_type, option_len, - src_str, ifp->name); + zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", + __PRETTY_FUNCTION__, + option_type, option_len, + src_str, ifp->name); } } @@ -289,7 +294,7 @@ int pim_hello_recv(struct interface *ifp, Check received PIM hello options */ - if (PIM_DEBUG_PIM_TRACE) { + if (PIM_DEBUG_PIM_HELLO) { tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME), @@ -321,11 +326,13 @@ int pim_hello_recv(struct interface *ifp, } if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: PIM hello missing holdtime from %s on interface %s", - __PRETTY_FUNCTION__, - src_str, ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: PIM hello missing holdtime from %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + } } /* @@ -345,11 +352,13 @@ int pim_hello_recv(struct interface *ifp, hello_option_generation_id, hello_option_addr_list); if (!neigh) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: failure creating PIM neighbor %s on interface %s", - __PRETTY_FUNCTION__, - src_str, ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: failure creating PIM neighbor %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + } FREE_ADDR_LIST_THEN_RETURN(-8); } @@ -372,7 +381,7 @@ int pim_hello_recv(struct interface *ifp, /* GenID mismatch, then replace neighbor */ - if (PIM_DEBUG_PIM_TRACE) { + if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", @@ -394,11 +403,13 @@ int pim_hello_recv(struct interface *ifp, hello_option_generation_id, hello_option_addr_list); if (!neigh) { - char src_str[100]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: failure re-creating PIM neighbor %s on interface %s", - __PRETTY_FUNCTION__, - src_str, ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + char src_str[100]; + pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s", + __PRETTY_FUNCTION__, + src_str, ifp->name); + } FREE_ADDR_LIST_THEN_RETURN(-9); } /* actual addr list is saved under neighbor */ @@ -445,8 +456,10 @@ int pim_hello_build_tlv(const char *ifname, PIM_MSG_OPTION_TYPE_HOLDTIME, holdtime); if (!curr) { - zlog_warn("%s: could not set PIM hello Holdtime option for interface %s", - __PRETTY_FUNCTION__, ifname); + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not set PIM hello Holdtime option for interface %s", + __PRETTY_FUNCTION__, ifname); + } return -1; } @@ -457,8 +470,10 @@ int pim_hello_build_tlv(const char *ifname, propagation_delay, override_interval); if (!tmp) { - zlog_warn("%s: could not set PIM LAN Prune Delay option for interface %s", - __PRETTY_FUNCTION__, ifname); + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s", + __PRETTY_FUNCTION__, ifname); + } return -1; } if (can_disable_join_suppression) { @@ -472,8 +487,10 @@ int pim_hello_build_tlv(const char *ifname, PIM_MSG_OPTION_TYPE_DR_PRIORITY, dr_priority); if (!curr) { - zlog_warn("%s: could not set PIM hello DR Priority option for interface %s", - __PRETTY_FUNCTION__, ifname); + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not set PIM hello DR Priority option for interface %s", + __PRETTY_FUNCTION__, ifname); + } return -2; } @@ -483,8 +500,10 @@ int pim_hello_build_tlv(const char *ifname, PIM_MSG_OPTION_TYPE_GENERATION_ID, generation_id); if (!curr) { - zlog_warn("%s: could not set PIM hello Generation ID option for interface %s", - __PRETTY_FUNCTION__, ifname); + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not set PIM hello Generation ID option for interface %s", + __PRETTY_FUNCTION__, ifname); + } return -3; } @@ -494,8 +513,10 @@ int pim_hello_build_tlv(const char *ifname, pastend, ifconnected); if (!curr) { - zlog_warn("%s: could not set PIM hello Secondary Address List option for interface %s", - __PRETTY_FUNCTION__, ifname); + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s", + __PRETTY_FUNCTION__, ifname); + } return -4; } } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 66fc59be5..a04a0afc8 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -521,7 +521,7 @@ static int hello_send(struct interface *ifp, pim_ifp = ifp->info; - if (PIM_DEBUG_PIM_PACKETS || PIM_DEBUG_PIM_HELLO) { + if (PIM_DEBUG_PIM_HELLO) { char dst_str[100]; pim_inet4_dump("", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", @@ -561,8 +561,10 @@ static int hello_send(struct interface *ifp, pim_msg, pim_msg_size, ifp->name)) { - zlog_warn("%s: could not send PIM message on interface %s", - __PRETTY_FUNCTION__, ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, ifp->name); + } return -2; } @@ -581,8 +583,10 @@ static int pim_hello_send(struct interface *ifp, if (hello_send(ifp, holdtime)) { ++pim_ifp->pim_ifstat_hello_sendfail; - zlog_warn("Could not send PIM hello on interface %s", - ifp->name); + if (PIM_DEBUG_PIM_HELLO) { + zlog_warn("Could not send PIM hello on interface %s", + ifp->name); + } return -1; } @@ -599,7 +603,7 @@ static void hello_resched(struct interface *ifp) pim_ifp = ifp->info; zassert(pim_ifp); - if (PIM_DEBUG_PIM_TRACE) { + if (PIM_DEBUG_PIM_HELLO) { zlog_debug("Rescheduling %d sec hello on interface %s", pim_ifp->pim_hello_period, ifp->name); } @@ -699,7 +703,7 @@ void pim_hello_restart_triggered(struct interface *ifp) random_msec = random() % (triggered_hello_delay_msec + 1); - if (PIM_DEBUG_PIM_EVENTS) { + if (PIM_DEBUG_PIM_HELLO) { zlog_debug("Scheduling %d msec triggered hello on interface %s", random_msec, ifp->name); } diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 95ee5ab0e..ed4dbba2e 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -38,12 +38,8 @@ uint8_t *pim_tlv_append_uint16(uint8_t *buf, { uint16_t option_len = 2; - if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%zd needed=%d", - __PRETTY_FUNCTION__, - buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); - return 0; - } + if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) + return NULL; *(uint16_t *) buf = htons(option_type); buf += 2; @@ -63,12 +59,8 @@ uint8_t *pim_tlv_append_2uint16(uint8_t *buf, { uint16_t option_len = 4; - if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%zd needed=%d", - __PRETTY_FUNCTION__, - buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); - return 0; - } + if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) + return NULL; *(uint16_t *) buf = htons(option_type); buf += 2; @@ -89,12 +81,8 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, { uint16_t option_len = 4; - if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%zd needed=%d", - __PRETTY_FUNCTION__, - buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); - return 0; - } + if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) + return NULL; *(uint16_t *) buf = htons(option_type); buf += 2; @@ -136,12 +124,8 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, if (p->family != AF_INET) continue; - if ((curr + ucast_ipv4_encoding_len) > buf_pastend) { - zlog_warn("%s: buffer overflow: left=%zd needed=%zu", - __PRETTY_FUNCTION__, - buf_pastend - curr, ucast_ipv4_encoding_len); + if ((curr + ucast_ipv4_encoding_len) > buf_pastend) return 0; - } /* Write encoded unicast IPv4 address */ *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ @@ -155,9 +139,9 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, } if (PIM_DEBUG_PIM_TRACE) { - zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %zu", - __PRETTY_FUNCTION__, - option_len / ucast_ipv4_encoding_len); + zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", + __PRETTY_FUNCTION__, + option_len / ucast_ipv4_encoding_len); } if (option_len < 1) { From 983525e8b560fc44d2214ca3f6d72af809b6ebd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 22 Oct 2015 11:35:16 +0300 Subject: [PATCH 0876/1342] zebra: fix rtadv detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GLIBC macro tests were just plain wrong. Glibc 2.1 is ancient and the support should be detected via configure.ac test, not macro test. Build with HAVE_RTADV but !RTADV is broke after vrf, so for now, just define RTADV always if HAVE_RTADV is there. Signed-off-by: Timo Teräs --- zebra/rib.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 8328f23bb..2af90db28 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -333,12 +333,8 @@ struct nexthop_vrfid }; /* Router advertisement feature. */ -#ifndef RTADV -#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) - #ifdef HAVE_RTADV - #define RTADV - #endif -#endif +#if !defined(RTADV) && defined(LINUX_IPV6) && defined(HAVE_RTADV) +# define RTADV #endif #if defined (HAVE_IPV6) && defined (RTADV) From 0edba8b6ad9c83fa0a3cc58765fe9f123f4109ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 22 Oct 2015 11:35:17 +0300 Subject: [PATCH 0877/1342] bgpd: check rtt later after the real peer is known MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OPEN message handler moves the connection from the temporary "struct peer" (used to accept it) to the real "struct peer" based on the configuration. RTT needs to be updated only to the real struct peer, and this patch moves the RTT query to point where realpeer is known. Fixes: ef757700d0 "bgpd: allow using rtt in route-map's set metric" Signed-off-by: Timo Teräs --- bgpd/bgp_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 4ab5b0640..a90e56b50 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1572,6 +1572,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Get sockname. */ bgp_getsockname (peer); + peer->rtt = sockopt_tcp_rtt (peer->fd); BGP_EVENT_ADD (peer, Receive_OPEN_message); @@ -2582,7 +2583,6 @@ bgp_read (struct thread *thread) { case BGP_MSG_OPEN: peer->open_in++; - peer->rtt = sockopt_tcp_rtt(peer->fd); bgp_open_receive (peer, size); /* XXX return value ignored! */ break; case BGP_MSG_UPDATE: From 5a2a1ec18c89daec5de6690a9b0f47c0d11a0f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 22 Oct 2015 11:35:18 +0300 Subject: [PATCH 0878/1342] bgpd: update rtt on soft clear MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtt is calculated dynamically by the kernel. Refresh it on soft clear. Fixes: ef757700d0 "bgpd: allow using rtt in route-map's set metric" Signed-off-by: Timo Teräs --- bgpd/bgpd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 60428586a..734c0df44 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "stream.h" #include "command.h" #include "sockunion.h" +#include "sockopt.h" #include "network.h" #include "memory.h" #include "filter.h" @@ -4649,6 +4650,8 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, if (! peer->afc[afi][safi]) return BGP_ERR_AF_UNCONFIGURED; + peer->rtt = sockopt_tcp_rtt (peer->fd); + if (stype == BGP_CLEAR_SOFT_RSCLIENT) { if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) From 0d7435f2138955b4b8aa9044eefbaff31ec33248 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Thu, 22 Oct 2015 11:35:20 +0300 Subject: [PATCH 0879/1342] bgpd: Add support for timer commands with peer-group syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The peer-groups parser is missing advertisement-interval and 'timers connect' Signed-off-by: Daniel Walton Reviewed-by: Timo Teräs --- bgpd/bgp_vty.c | 28 ++++++------- bgpd/bgpd.c | 104 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 105 insertions(+), 27 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0b5be7302..36fd263af 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3379,7 +3379,7 @@ peer_timers_connect_set_vty (struct vty *vty, const char *ip_str, struct peer *peer; u_int32_t connect; - peer = peer_lookup_vty (vty, ip_str); + peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; @@ -3402,9 +3402,9 @@ peer_timers_connect_unset_vty (struct vty *vty, const char *ip_str) DEFUN (neighbor_timers_connect, neighbor_timers_connect_cmd, - NEIGHBOR_CMD "timers connect <1-65535>", + NEIGHBOR_CMD2 "timers connect <1-65535>", NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") @@ -3414,10 +3414,10 @@ DEFUN (neighbor_timers_connect, DEFUN (no_neighbor_timers_connect, no_neighbor_timers_connect_cmd, - NO_NEIGHBOR_CMD "timers connect", + NO_NEIGHBOR_CMD2 "timers connect", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "BGP connect timer\n") { @@ -3426,10 +3426,10 @@ DEFUN (no_neighbor_timers_connect, ALIAS (no_neighbor_timers_connect, no_neighbor_timers_connect_val_cmd, - NO_NEIGHBOR_CMD "timers connect <1-65535>", + NO_NEIGHBOR_CMD2 "timers connect <1-65535>", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") @@ -3442,7 +3442,7 @@ peer_advertise_interval_vty (struct vty *vty, const char *ip_str, struct peer *peer; u_int32_t routeadv = 0; - peer = peer_lookup_vty (vty, ip_str); + peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; @@ -3459,9 +3459,9 @@ peer_advertise_interval_vty (struct vty *vty, const char *ip_str, DEFUN (neighbor_advertise_interval, neighbor_advertise_interval_cmd, - NEIGHBOR_CMD "advertisement-interval <0-600>", + NEIGHBOR_CMD2 "advertisement-interval <0-600>", NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "Minimum interval between sending BGP routing updates\n" "time in seconds\n") { @@ -3470,10 +3470,10 @@ DEFUN (neighbor_advertise_interval, DEFUN (no_neighbor_advertise_interval, no_neighbor_advertise_interval_cmd, - NO_NEIGHBOR_CMD "advertisement-interval", + NO_NEIGHBOR_CMD2 "advertisement-interval", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "Minimum interval between sending BGP routing updates\n") { return peer_advertise_interval_vty (vty, argv[0], NULL, 0); @@ -3481,10 +3481,10 @@ DEFUN (no_neighbor_advertise_interval, ALIAS (no_neighbor_advertise_interval, no_neighbor_advertise_interval_val_cmd, - NO_NEIGHBOR_CMD "advertisement-interval <0-600>", + NO_NEIGHBOR_CMD2 "advertisement-interval <0-600>", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "Minimum interval between sending BGP routing updates\n" "time in seconds\n") diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 734c0df44..2325f07c8 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -922,6 +922,7 @@ static void peer_as_change (struct peer *peer, as_t as) { bgp_peer_sort_t type; + struct peer *conf; /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) @@ -946,10 +947,17 @@ peer_as_change (struct peer *peer, as_t as) peer->local_as = peer->bgp->as; /* Advertisement-interval reset */ - if (peer_sort (peer) == BGP_PEER_IBGP) - peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + conf = NULL; + if (peer->group) + conf = peer->group->conf; + + if (conf && CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV)) + peer->v_routeadv = conf->routeadv; else - peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* TTL reset */ if (peer_sort (peer) == BGP_PEER_IBGP) @@ -1500,10 +1508,13 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; /* advertisement-interval reset */ - if (peer_sort (peer) == BGP_PEER_IBGP) - peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + if (CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV)) + peer->v_routeadv = conf->routeadv; else - peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* password apply */ if (conf->password && !peer->password) @@ -1859,10 +1870,13 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, if (first_member) { /* Advertisement-interval reset */ - if (peer_sort (group->conf) == BGP_PEER_IBGP) - group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; - else - group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + if (! CHECK_FLAG (group->conf->config, PEER_CONFIG_ROUTEADV)) + { + if (peer_sort (group->conf) == BGP_PEER_IBGP) + group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + } /* ebgp-multihop reset */ if (peer_sort (group->conf) == BGP_PEER_IBGP) @@ -3341,6 +3355,9 @@ peer_timers_unset (struct peer *peer) int peer_timers_connect_set (struct peer *peer, u_int32_t connect) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3354,12 +3371,26 @@ peer_timers_connect_set (struct peer *peer, u_int32_t connect) /* Set value to timer setting. */ peer->v_connect = connect; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + SET_FLAG (peer->config, PEER_CONFIG_CONNECT); + peer->connect = connect; + peer->v_connect = connect; + } return 0; } int peer_timers_connect_unset (struct peer *peer) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3370,12 +3401,26 @@ peer_timers_connect_unset (struct peer *peer) /* Set timer setting to default value. */ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; - return 0; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); + peer->connect = 0; + peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + } + return 0; } int peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3386,12 +3431,27 @@ peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) peer->routeadv = routeadv; peer->v_routeadv = routeadv; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = routeadv; + peer->v_routeadv = routeadv; + } + return 0; } int peer_advertise_interval_unset (struct peer *peer) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3402,6 +3462,22 @@ peer_advertise_interval_unset (struct peer *peer) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = 0; + + if (peer->sort == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + } return 0; } @@ -4956,7 +5032,8 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, VTY_NEWLINE); /* advertisement-interval */ - if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV)) + if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV) && + ! peer_group_active (peer)) vty_out (vty, " neighbor %s advertisement-interval %d%s", addr, peer->v_routeadv, VTY_NEWLINE); @@ -4966,7 +5043,8 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, vty_out (vty, " neighbor %s timers %d %d%s", addr, peer->keepalive, peer->holdtime, VTY_NEWLINE); - if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT)) + if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT) && + ! peer_group_active (peer)) vty_out (vty, " neighbor %s timers connect %d%s", addr, peer->connect, VTY_NEWLINE); From 929a26a7cf80b2df9981595e6bcfcfc4a970052a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Oct 2015 19:59:30 -0400 Subject: [PATCH 0880/1342] lib: Memory reporting fails over 2GB The old style mallinfo() function uses an 'int' to report memory usage data to the program. Unfortunately modern architectures can chew through 2gb of memory like a buzz saw hitting some warm butter, especially in the case of a memory leak or memory fragmentation. When a daemon uses more than 2gb of memory, just indicate it's gotten large and we don't know anymore. Pre-change behavior: Robot-1# show memory System allocator statistics: Total heap allocated: 16777216 TiB Holding block headers: 1288 KiB Used small blocks: 0 bytes Used ordinary blocks: 535 MiB Free small blocks: 768 bytes Free ordinary blocks: 16777216 TiB Ordinary blocks: 266107 Small blocks: 24 Holding blocks: 2 Post-change behavior: Robot-1# show memory System allocator statistics: Total heap allocated: 1572 KiB Holding block headers: > 2GB Used small blocks: 0 bytes Used ordinary blocks: 1443 KiB Free small blocks: 32 bytes Free ordinary blocks: 129 KiB Ordinary blocks: 2 Small blocks: 1 Holding blocks: 2 Signed-off-by: Donald Sharp --- lib/memory.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/lib/memory.c b/lib/memory.c index a9149e10f..172ddfc49 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -437,41 +437,28 @@ memory_init (void) const char * mtype_memstr (char *buf, size_t len, unsigned long bytes) { - unsigned int t, g, m, k; - + unsigned int m, k; + /* easy cases */ if (!bytes) return "0 bytes"; if (bytes == 1) return "1 byte"; - - if (sizeof (unsigned long) >= 8) - /* Hacked to make it not warn on ILP32 machines - * Shift will always be 40 at runtime. See below too */ - t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0); - else - t = 0; - g = bytes >> 30; + + /* + * When we pass the 2gb barrier mallinfo() can no longer report + * correct data so it just does something odd... + * Reporting like Terrabytes of data. Which makes users... + * edgy.. yes edgy that's the term for it. + * So let's just give up gracefully + */ + if (bytes > 0x7fffffff) + return "> 2GB"; + m = bytes >> 20; k = bytes >> 10; - - if (t > 10) - { - /* The shift will always be 39 at runtime. - * Just hacked to make it not warn on 'smaller' machines. - * Static compiler analysis should mean no extra code - */ - if (bytes & (1UL << (sizeof (unsigned long) >= 8 ? 39 : 0))) - t++; - snprintf (buf, len, "%4d TiB", t); - } - else if (g > 10) - { - if (bytes & (1 << 29)) - g++; - snprintf (buf, len, "%d GiB", g); - } - else if (m > 10) + + if (m > 10) { if (bytes & (1 << 19)) m++; From 7eb6136b2732d4782360f9f376336c6d4f667ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Mon, 2 Nov 2015 16:50:05 +0200 Subject: [PATCH 0881/1342] zebra: make ZEBRA_FLAG_CHANGED internal status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This flag is used internally in zebra only. And it makes no sense to expose it over the zclient API, as having it set from client could corrupt the internal state. Signed-off-by: Timo Teräs Acked-by: Donald Sharp --- lib/zebra.h | 1 - zebra/rib.h | 1 + zebra/zebra_rib.c | 8 ++++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/zebra.h b/lib/zebra.h index fe34be78a..a607437af 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -464,7 +464,6 @@ extern const char *zserv_command_string (unsigned int command); #define ZEBRA_FLAG_BLACKHOLE 0x04 #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 -#define ZEBRA_FLAG_CHANGED 0x20 #define ZEBRA_FLAG_STATIC 0x40 #define ZEBRA_FLAG_REJECT 0x80 diff --git a/zebra/rib.h b/zebra/rib.h index 2af90db28..6e0966aba 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -78,6 +78,7 @@ struct rib /* RIB internal status */ u_char status; #define RIB_ENTRY_REMOVED (1 << 0) +#define RIB_ENTRY_CHANGED (1 << 1) /* Nexthop information. */ u_char nexthop_num; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 084af3802..c202c5f06 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1078,7 +1078,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, /* Iterate over all nexthops of the given RIB entry and refresh their * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any * nexthop is found to toggle the ACTIVE flag, the whole rib structure - * is flagged with ZEBRA_FLAG_CHANGED. The 4th 'set' argument is + * is flagged with RIB_ENTRY_CHANGED. The 4th 'set' argument is * transparently passed to nexthop_active_check(). * * Return value is the new number of active nexthops. @@ -1091,7 +1091,7 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) unsigned int prev_active, prev_index, new_active; rib->nexthop_active_num = 0; - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { @@ -1101,7 +1101,7 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) rib->nexthop_active_num++; if (prev_active != new_active || prev_index != nexthop->ifindex) - SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + SET_FLAG (rib->status, RIB_ENTRY_CHANGED); } return rib->nexthop_active_num; } @@ -1375,7 +1375,7 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Updating existing route, select %p, fib %p", (void *)select, (void *)fib); - if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) + if (CHECK_FLAG (select->status, RIB_ENTRY_CHANGED)) { if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "updating existing route"); From b11f3b54c842117e22e2f5cf1561ea34eee8dfcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Mon, 2 Nov 2015 16:50:07 +0200 Subject: [PATCH 0882/1342] zebra: implement per-route mtu handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commits allow overriding MTU using netlink attributes on per-route basis. This is useful for routing protocols that can advertice prefix specific MTUs between routers (e.g. NHRP). Signed-off-by: Timo Teräs --- lib/zclient.c | 4 +++ lib/zclient.h | 5 ++++ zebra/connected.c | 6 ++--- zebra/kernel_socket.c | 4 +-- zebra/rib.h | 9 +++++-- zebra/rt_netlink.c | 57 ++++++++++++++++++++++++++++++++++++++----- zebra/zebra_rib.c | 9 +++++-- zebra/zebra_vty.c | 2 ++ zebra/zserv.c | 14 +++++++++-- 9 files changed, 93 insertions(+), 17 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index bfff9a365..ca6a4c750 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -562,6 +562,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, stream_putc (s, api->distance); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) stream_putl (s, api->metric); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) + stream_putl (s, api->mtu); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -616,6 +618,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, stream_putc (s, api->distance); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) stream_putl (s, api->metric); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) + stream_putl (s, api->mtu); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); diff --git a/lib/zclient.h b/lib/zclient.h index aa935c125..a14f59935 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -96,6 +96,7 @@ struct zclient #define ZAPI_MESSAGE_IFINDEX 0x02 #define ZAPI_MESSAGE_DISTANCE 0x04 #define ZAPI_MESSAGE_METRIC 0x08 +#define ZAPI_MESSAGE_MTU 0x10 /* Zserv protocol message header */ struct zserv_header @@ -131,6 +132,8 @@ struct zapi_ipv4 u_int32_t metric; + u_int32_t mtu; + vrf_id_t vrf_id; }; @@ -204,6 +207,8 @@ struct zapi_ipv6 u_int32_t metric; + u_int32_t mtu; + vrf_id_t vrf_id; }; diff --git a/zebra/connected.c b/zebra/connected.c index 244f29115..84b0d1cb8 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -192,10 +192,10 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) return; rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); + ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST); rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); + ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_MULTICAST); rib_update (ifp->vrf_id); } @@ -356,7 +356,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) #endif rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, - RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); + RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST); rib_update (ifp->vrf_id); } diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index eded2bbd7..fe9e4acb5 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -971,7 +971,7 @@ rtm_read (struct rt_msghdr *rtm) || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, - NULL, 0, VRF_DEFAULT, 0, 0, 0, SAFI_UNICAST); + NULL, 0, VRF_DEFAULT, 0, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, VRF_DEFAULT, SAFI_UNICAST); @@ -1013,7 +1013,7 @@ rtm_read (struct rt_msghdr *rtm) || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, - ifindex, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, SAFI_UNICAST); + ifindex, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, diff --git a/zebra/rib.h b/zebra/rib.h index 6e0966aba..fbf4fc42f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -66,6 +66,10 @@ struct rib /* Metric */ u_int32_t metric; + /* MTU */ + u_int32_t mtu; + u_int32_t nexthop_mtu; + /* Distance. */ u_char distance; @@ -494,7 +498,7 @@ extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, unsigned int ifindex, vrf_id_t vrf_id, int table_id, - u_int32_t, u_char, safi_t); + u_int32_t, u_int32_t, u_char, safi_t); extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t); @@ -531,7 +535,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, - int table_id, u_int32_t metric, u_char distance, safi_t safi); + int table_id, u_int32_t metric, u_int32_t mtu, + u_char distance, safi_t safi); extern int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cbcbe7c56..614f8099a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -668,6 +668,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, int index; int table; int metric; + u_int32_t mtu = 0; void *dest; void *gate; @@ -730,6 +731,18 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (tb[RTA_PRIORITY]) metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + if (tb[RTA_METRICS]) + { + struct rtattr *mxrta[RTAX_MAX+1]; + + memset (mxrta, 0, sizeof mxrta); + netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), + RTA_PAYLOAD(tb[RTA_METRICS])); + + if (mxrta[RTAX_MTU]) + mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); + } + if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; @@ -739,7 +752,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, - vrf_id, table, metric, 0, SAFI_UNICAST); + vrf_id, table, metric, mtu, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -755,6 +768,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, rib->distance = 0; rib->flags = flags; rib->metric = metric; + rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; @@ -805,7 +819,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, p.prefixlen = rtm->rtm_dst_len; rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id, - table, metric, 0, SAFI_UNICAST); + table, metric, mtu, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -841,6 +855,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int index; int table; int metric; + u_int32_t mtu = 0; void *dest; void *gate; @@ -919,8 +934,23 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); - if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY]) - metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + if (h->nlmsg_type == RTM_NEWROUTE) + { + if (tb[RTA_PRIORITY]) + metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + + if (tb[RTA_METRICS]) + { + struct rtattr *mxrta[RTAX_MAX+1]; + + memset (mxrta, 0, sizeof mxrta); + netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), + RTA_PAYLOAD(tb[RTA_METRICS])); + + if (mxrta[RTAX_MTU]) + mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); + } + } if (rtm->rtm_family == AF_INET) { @@ -941,7 +971,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, { if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id, - table, metric, 0, SAFI_UNICAST); + table, metric, mtu, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -957,6 +987,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, rib->distance = 0; rib->flags = 0; rib->metric = metric; + rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; @@ -1022,7 +1053,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, - metric, 0, SAFI_UNICAST); + metric, mtu, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, SAFI_UNICAST); @@ -1634,6 +1665,20 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, /* Metric. */ addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric); + if (rib->mtu || rib->nexthop_mtu) + { + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *) buf; + u_int32_t mtu = rib->mtu; + if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu)) + mtu = rib->nexthop_mtu; + rta->rta_type = RTA_METRICS; + rta->rta_len = RTA_LENGTH(0); + rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu); + addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta), + RTA_PAYLOAD (rta)); + } + if (discard) { if (cmd == RTM_NEWROUTE) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c202c5f06..1d098158a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -361,6 +361,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; + rib->nexthop_mtu = 0; } /* Make lookup prefix. */ @@ -469,6 +470,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, } resolved = 1; } + if (resolved && set) + rib->nexthop_mtu = match->mtu; return resolved; } else @@ -1806,7 +1809,7 @@ int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, unsigned int ifindex, vrf_id_t vrf_id, int table_id, - u_int32_t metric, u_char distance, safi_t safi) + u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) { struct rib *rib; struct rib *same = NULL; @@ -1869,6 +1872,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; + rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table_id; rib->nexthop_num = 0; @@ -2598,7 +2602,7 @@ int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, int table_id, - u_int32_t metric, u_char distance, safi_t safi) + u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) { struct rib *rib; struct rib *same = NULL; @@ -2654,6 +2658,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, rib->distance = distance; rib->flags = flags; rib->metric = metric; + rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table_id; rib->nexthop_num = 0; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6ad286ff0..b37b901d9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1290,6 +1290,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); + if (rib->mtu) + vty_out (vty, ", mtu %u", rib->mtu); vty_out (vty, ", vrf %u", rib->vrf_id); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); diff --git a/zebra/zserv.c b/zebra/zserv.c index e26c8cac8..7a75ed420 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -455,6 +455,8 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, stream_putc (s, rib->distance); SET_FLAG (zapi_flags, ZAPI_MESSAGE_METRIC); stream_putl (s, rib->metric); + SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU); + stream_putl (s, rib->mtu); } /* write real message flags value */ @@ -903,6 +905,9 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) rib->metric = stream_getl (s); + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + /* Table */ rib->table=zebrad.rtm_table_default; rib_add_ipv4_multipath (&p, rib, safi); @@ -1092,15 +1097,20 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) api.metric = stream_getl (s); else api.metric = 0; + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU)) + api.mtu = stream_getl (s); + else + api.mtu = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id, zebrad.rtm_table_default, api.metric, - api.distance, api.safi); + api.mtu, api.distance, api.safi); else rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id, zebrad.rtm_table_default, api.metric, - api.distance, api.safi); + api.mtu, api.distance, api.safi); return 0; } From d4c27d656d072fbd81003a71c4f3391c96852c60 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Nov 2015 13:26:35 -0500 Subject: [PATCH 0883/1342] zebra: Collapse struct static_ipv[4|6] into struct static_route The 'struct static_ipv4' and 'struct static_ipv6' structures are essentially the same. Collapse them into one data structure 'struct static_route'. Signed-off-by: Donald Sharp --- lib/memtypes.c | 3 +- zebra/rib.h | 53 ++++++---------------------- zebra/zebra_rib.c | 88 +++++++++++++++++++++++------------------------ zebra/zebra_vty.c | 12 +++---- 4 files changed, 61 insertions(+), 95 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index 57de5c4fd..5f78493ac 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -82,8 +82,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_NEXTHOP, "Nexthop" }, { MTYPE_RIB, "RIB" }, { MTYPE_RIB_QUEUE, "RIB process work queue" }, - { MTYPE_STATIC_IPV4, "Static IPv4 route" }, - { MTYPE_STATIC_IPV6, "Static IPv6 route" }, + { MTYPE_STATIC_ROUTE, "Static route" }, { MTYPE_RIB_DEST, "RIB destination" }, { MTYPE_RIB_TABLE_INFO, "RIB table info" }, { MTYPE_NETLINK_NAME, "Netlink name" }, diff --git a/zebra/rib.h b/zebra/rib.h index fbf4fc42f..408ceb456 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -173,11 +173,11 @@ typedef struct rib_dest_t_ RIB_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode (rn), rib, next) /* Static route information. */ -struct static_ipv4 +struct static_route { /* For linked list. */ - struct static_ipv4 *prev; - struct static_ipv4 *next; + struct static_route *prev; + struct static_route *next; /* VRF identifier. */ vrf_id_t vrf_id; @@ -187,47 +187,15 @@ struct static_ipv4 /* Flag for this static route's type. */ u_char type; -#define STATIC_IPV4_GATEWAY 1 -#define STATIC_IPV4_IFNAME 2 -#define STATIC_IPV4_BLACKHOLE 3 +#define STATIC_IPV4_GATEWAY 1 +#define STATIC_IPV4_IFNAME 2 +#define STATIC_IPV4_BLACKHOLE 3 +#define STATIC_IPV6_GATEWAY 4 +#define STATIC_IPV6_GATEWAY_IFNAME 5 +#define STATIC_IPV6_IFNAME 6 /* Nexthop value. */ - union - { - struct in_addr ipv4; - char *ifname; - } gate; - - /* bit flags */ - u_char flags; -/* - see ZEBRA_FLAG_REJECT - ZEBRA_FLAG_BLACKHOLE - */ -}; - -#ifdef HAVE_IPV6 -/* Static route information. */ -struct static_ipv6 -{ - /* For linked list. */ - struct static_ipv6 *prev; - struct static_ipv6 *next; - - /* VRF identifier. */ - vrf_id_t vrf_id; - - /* Administrative distance. */ - u_char distance; - - /* Flag for this static route's type. */ - u_char type; -#define STATIC_IPV6_GATEWAY 1 -#define STATIC_IPV6_GATEWAY_IFNAME 2 -#define STATIC_IPV6_IFNAME 3 - - /* Nexthop value. */ - struct in6_addr ipv6; + union g_addr addr; char *ifname; /* bit flags */ @@ -237,7 +205,6 @@ struct static_ipv6 ZEBRA_FLAG_BLACKHOLE */ }; -#endif /* HAVE_IPV6 */ enum nexthop_types_t { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1d098158a..50965599d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2287,7 +2287,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Install static route into rib. */ static void -static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) +static_install_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) { struct rib *rib; struct route_node *rn; @@ -2317,10 +2317,10 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); + nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); break; case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->gate.ifname); + nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: nexthop_blackhole_add (rib); @@ -2343,10 +2343,10 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); + nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); break; case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->gate.ifname); + nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: nexthop_blackhole_add (rib); @@ -2362,15 +2362,15 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) } static int -static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) +static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_route *si) { if (nexthop->type == NEXTHOP_TYPE_IPV4 && si->type == STATIC_IPV4_GATEWAY - && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4)) + && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4)) return 1; if (nexthop->type == NEXTHOP_TYPE_IFNAME && si->type == STATIC_IPV4_IFNAME - && strcmp (nexthop->ifname, si->gate.ifname) == 0) + && strcmp (nexthop->ifname, si->ifname) == 0) return 1; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE && si->type == STATIC_IPV4_BLACKHOLE) @@ -2380,7 +2380,7 @@ static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) /* Uninstall static route from RIB. */ static void -static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_ipv4 *si) +static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) { struct route_node *rn; struct rib *rib; @@ -2446,10 +2446,10 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, { u_char type = 0; struct route_node *rn; - struct static_ipv4 *si; - struct static_ipv4 *pp; - struct static_ipv4 *cp; - struct static_ipv4 *update = NULL; + struct static_route *si; + struct static_route *pp; + struct static_route *cp; + struct static_route *update = NULL; struct zebra_vrf *zvrf = vrf_info_get (vrf_id); struct route_table *stable = zvrf->stable[AFI_IP][safi]; @@ -2471,8 +2471,8 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, for (si = rn->info; si; si = si->next) { if (type == si->type - && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) - && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) { if (distance == si->distance) { @@ -2489,7 +2489,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id); /* Make new static route structure. */ - si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); + si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; @@ -2497,9 +2497,9 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, si->vrf_id = vrf_id; if (gate) - si->gate.ipv4 = *gate; + si->addr.ipv4 = *gate; if (ifname) - si->gate.ifname = XSTRDUP (0, ifname); + si->ifname = XSTRDUP (0, ifname); /* Add new static route information to the tree with sort by distance value and gateway address. */ @@ -2511,9 +2511,9 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, continue; if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) { - if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr)) + if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr)) break; - if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr)) + if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr)) continue; } } @@ -2540,7 +2540,7 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, { u_char type = 0; struct route_node *rn; - struct static_ipv4 *si; + struct static_route *si; struct route_table *stable; /* Lookup table. */ @@ -2564,8 +2564,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, /* Find same static route is the tree */ for (si = rn->info; si; si = si->next) if (type == si->type - && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) - && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) break; /* Can't find static route. */ @@ -2589,8 +2589,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, /* Free static route configuration. */ if (ifname) - XFREE (0, si->gate.ifname); - XFREE (MTYPE_STATIC_IPV4, si); + XFREE (0, si->ifname); + XFREE (MTYPE_STATIC_ROUTE, si); route_unlock_node (rn); @@ -2835,7 +2835,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* Install static route into rib. */ static void -static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) +static_install_ipv6 (struct prefix *p, struct static_route *si) { struct rib *rib; struct route_table *table; @@ -2866,13 +2866,13 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) switch (si->type) { case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->ipv6); + nexthop_ipv6_add (rib, &si->addr.ipv6); break; case STATIC_IPV6_IFNAME: nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } rib_queue_add (&zebrad, rn); @@ -2892,13 +2892,13 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) switch (si->type) { case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->ipv6); + nexthop_ipv6_add (rib, &si->addr.ipv6); break; case STATIC_IPV6_IFNAME: nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } @@ -2911,11 +2911,11 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) } static int -static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) +static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_route *si) { if (nexthop->type == NEXTHOP_TYPE_IPV6 && si->type == STATIC_IPV6_GATEWAY - && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)) + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)) return 1; if (nexthop->type == NEXTHOP_TYPE_IFNAME && si->type == STATIC_IPV6_IFNAME @@ -2923,14 +2923,14 @@ static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) return 1; if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME && si->type == STATIC_IPV6_GATEWAY_IFNAME - && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6) && strcmp (nexthop->ifname, si->ifname) == 0) return 1; return 0; } static void -static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) +static_uninstall_ipv6 (struct prefix *p, struct static_route *si) { struct route_table *table; struct route_node *rn; @@ -2998,9 +2998,9 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, vrf_id_t vrf_id) { struct route_node *rn; - struct static_ipv6 *si; - struct static_ipv6 *pp; - struct static_ipv6 *cp; + struct static_route *si; + struct static_route *pp; + struct static_route *cp; struct zebra_vrf *zvrf = vrf_info_get (vrf_id); struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]; @@ -3023,7 +3023,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, { if (distance == si->distance && type == si->type - && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { route_unlock_node (rn); @@ -3032,7 +3032,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, } /* Make new static route structure. */ - si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6)); + si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; @@ -3042,13 +3042,13 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, switch (type) { case STATIC_IPV6_GATEWAY: - si->ipv6 = *gate; + si->addr.ipv6 = *gate; break; case STATIC_IPV6_IFNAME: si->ifname = XSTRDUP (0, ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - si->ipv6 = *gate; + si->addr.ipv6 = *gate; si->ifname = XSTRDUP (0, ifname); break; } @@ -3085,7 +3085,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; - struct static_ipv6 *si; + struct static_route *si; struct route_table *stable; /* Lookup table. */ @@ -3102,7 +3102,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, for (si = rn->info; si; si = si->next) if (distance == si->distance && type == si->type - && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) break; @@ -3127,7 +3127,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Free static route configuration. */ if (ifname) XFREE (0, si->ifname); - XFREE (MTYPE_STATIC_IPV6, si); + XFREE (MTYPE_STATIC_ROUTE, si); return 1; } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b37b901d9..656f55d49 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2396,7 +2396,7 @@ static int static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) { struct route_node *rn; - struct static_ipv4 *si; + struct static_route *si; struct route_table *stable; struct zebra_vrf *zvrf; vrf_iter_t iter; @@ -2419,10 +2419,10 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) switch (si->type) { case STATIC_IPV4_GATEWAY: - vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); + vty_out (vty, " %s", inet_ntoa (si->addr.ipv4)); break; case STATIC_IPV4_IFNAME: - vty_out (vty, " %s", si->gate.ifname); + vty_out (vty, " %s", si->ifname); break; case STATIC_IPV4_BLACKHOLE: vty_out (vty, " Null0"); @@ -3727,7 +3727,7 @@ static int static_config_ipv6 (struct vty *vty) { struct route_node *rn; - struct static_ipv6 *si; + struct static_route *si; int write; char buf[BUFSIZ]; struct route_table *stable; @@ -3751,14 +3751,14 @@ static_config_ipv6 (struct vty *vty) { case STATIC_IPV6_GATEWAY: vty_out (vty, " %s", - inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ)); + inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ)); break; case STATIC_IPV6_IFNAME: vty_out (vty, " %s", si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: vty_out (vty, " %s %s", - inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), + inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ), si->ifname); break; } From 0d955affd51df42dd5ae24b0d41edd992fb59a78 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Nov 2015 13:26:36 -0500 Subject: [PATCH 0884/1342] zebra: Remove HAVE_IPV6 from rib.h and zebra_rib.c Signed-off-by: Donald Sharp --- zebra/rib.h | 13 ++++--------- zebra/zebra_rib.c | 10 ---------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 408ceb456..1d3c15c31 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -309,7 +309,7 @@ struct nexthop_vrfid # define RTADV #endif -#if defined (HAVE_IPV6) && defined (RTADV) +#if defined (RTADV) /* Structure which hold status of router advertisement. */ struct rtadv { @@ -321,7 +321,7 @@ struct rtadv struct thread *ra_read; struct thread *ra_timer; }; -#endif /* RTADV && HAVE_IPV6 */ +#endif /* RTADV */ #ifdef HAVE_NETLINK /* Socket interface to kernel */ @@ -370,9 +370,9 @@ struct zebra_vrf struct list *rid_lo_sorted_list; struct prefix rid_user_assigned; -#if defined (HAVE_IPV6) && defined (RTADV) +#if defined (RTADV) struct rtadv rtadv; -#endif /* RTADV && HAVE_IPV6 */ +#endif /* RTADV */ }; /* @@ -451,9 +451,7 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, #define ZEBRA_RIB_FOUND_CONNECTED 2 #define ZEBRA_RIB_NOTFOUND 3 -#ifdef HAVE_IPV6 extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); -#endif /* HAVE_IPV6 */ extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t); extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t); @@ -498,7 +496,6 @@ extern int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, u_char distance, vrf_id_t vrf_id); -#ifdef HAVE_IPV6 extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, @@ -524,8 +521,6 @@ extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char distance, vrf_id_t vrf_id); -#endif /* HAVE_IPV6 */ - extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 50965599d..516d9d99c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -259,7 +259,6 @@ nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, return nexthop; } -#ifdef HAVE_IPV6 struct nexthop * nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) { @@ -305,7 +304,6 @@ nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, return nexthop; } -#endif /* HAVE_IPV6 */ struct nexthop * nexthop_blackhole_add (struct rib *rib) @@ -483,7 +481,6 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, return 0; } -#ifdef HAVE_IPV6 /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static int @@ -618,7 +615,6 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } return 0; } -#endif /* HAVE_IPV6 */ struct rib * rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, @@ -886,7 +882,6 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, return ZEBRA_RIB_NOTFOUND; } -#ifdef HAVE_IPV6 struct rib * rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) { @@ -949,7 +944,6 @@ rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) } return NULL; } -#endif /* HAVE_IPV6 */ #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -1010,7 +1004,6 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; -#ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: family = AFI_IP6; if (nexthop_active_ipv6 (rib, nexthop, set, rn)) @@ -1036,7 +1029,6 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } break; -#endif /* HAVE_IPV6 */ case NEXTHOP_TYPE_BLACKHOLE: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; @@ -2597,7 +2589,6 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, return 1; } -#ifdef HAVE_IPV6 int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, @@ -3131,7 +3122,6 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, return 1; } -#endif /* HAVE_IPV6 */ /* RIB update function. */ void From 9bcdd1a252ba84424eb06e84adf7fb48ae66ce1f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Nov 2015 13:26:37 -0500 Subject: [PATCH 0885/1342] zebra: Combine static_install_ipv[4|6] Combine the static_install_ipv[4|6] function calls into static_install_route. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 141 ++++++++++++++-------------------------------- 1 file changed, 41 insertions(+), 100 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 516d9d99c..4d122c42b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1669,7 +1669,7 @@ rib_queue_init (struct zebra_t *zebra) * as a route_node will not be requeued, if already queued. * * RIBs are submitted via rib_addnode or rib_delnode which set minimal - * state, or static_install_ipv{4,6} (when an existing RIB is updated) + * state, or static_install_route (when an existing RIB is updated) * and then submit route_node to queue for best-path selection later. * Order of add/delete state changes are preserved for any given RIB. * @@ -2279,14 +2279,14 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Install static route into rib. */ static void -static_install_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) +static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) { struct rib *rib; struct route_node *rn; struct route_table *table; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, si->vrf_id); + table = zebra_vrf_table (afi, safi, si->vrf_id); if (! table) return; @@ -2308,15 +2308,24 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) route_unlock_node (rn); switch (si->type) { - case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); - break; - case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->ifname); - break; - case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); - break; + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->addr.ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); + break; } rib_queue_add (&zebrad, rn); } @@ -2334,15 +2343,24 @@ static_install_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) switch (si->type) { - case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); - break; - case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->ifname); - break; - case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); - break; + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->addr.ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); + break; } /* Save the flags of this static routes (reject, blackhole) */ @@ -2521,7 +2539,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, si->next = cp; /* Install into rib. */ - static_install_ipv4 (safi, p, si); + static_install_route (AFI_IP, safi, p, si); return 1; } @@ -2824,83 +2842,6 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } -/* Install static route into rib. */ -static void -static_install_ipv6 (struct prefix *p, struct static_route *si) -{ - struct rib *rib; - struct route_table *table; - struct route_node *rn; - - /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, si->vrf_id); - if (! table) - return; - - /* Lookup existing route */ - rn = route_node_get (table, p); - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; - } - - if (rib) - { - /* Same distance static route is there. Update it with new - nexthop. */ - route_unlock_node (rn); - - switch (si->type) - { - case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->addr.ipv6); - break; - case STATIC_IPV6_IFNAME: - nexthop_ifname_add (rib, si->ifname); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); - break; - } - rib_queue_add (&zebrad, rn); - } - else - { - /* This is new static route. */ - rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); - - rib->type = ZEBRA_ROUTE_STATIC; - rib->distance = si->distance; - rib->metric = 0; - rib->vrf_id = si->vrf_id; - rib->table = zebrad.rtm_table_default; - rib->nexthop_num = 0; - - switch (si->type) - { - case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->addr.ipv6); - break; - case STATIC_IPV6_IFNAME: - nexthop_ifname_add (rib, si->ifname); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); - break; - } - - /* Save the flags of this static routes (reject, blackhole) */ - rib->flags = si->flags; - - /* Link this rib to the tree. */ - rib_addnode (rn, rib); - } -} - static int static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_route *si) { @@ -3065,7 +3006,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->next = cp; /* Install into rib. */ - static_install_ipv6 (p, si); + static_install_route (AFI_IP6, SAFI_UNICAST, p, si); return 1; } From a979ab70e0ec51f3cf779edae509f3c52be0b0f4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Nov 2015 13:26:38 -0500 Subject: [PATCH 0886/1342] zebra: combine static_ipv[4|6]_nexthop_same into one function Combine the static_ipv[4|6]_nexthop_same into static_nexthop_same. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 4d122c42b..f0c180c99 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2372,7 +2372,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro } static int -static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_route *si) +static_nexthop_same (struct nexthop *nexthop, struct static_route *si) { if (nexthop->type == NEXTHOP_TYPE_IPV4 && si->type == STATIC_IPV4_GATEWAY @@ -2385,6 +2385,19 @@ static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_route *si) if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE && si->type == STATIC_IPV4_BLACKHOLE) return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6 + && si->type == STATIC_IPV6_GATEWAY + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFNAME + && si->type == STATIC_IPV6_IFNAME + && strcmp (nexthop->ifname, si->ifname) == 0) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + && si->type == STATIC_IPV6_GATEWAY_IFNAME + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6) + && strcmp (nexthop->ifname, si->ifname) == 0) + return 1; return 0; } @@ -2424,7 +2437,7 @@ static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) /* Lookup nexthop. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (static_ipv4_nexthop_same (nexthop, si)) + if (static_nexthop_same (nexthop, si)) break; /* Can't find nexthop. */ @@ -2842,25 +2855,6 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } -static int -static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_route *si) -{ - if (nexthop->type == NEXTHOP_TYPE_IPV6 - && si->type == STATIC_IPV6_GATEWAY - && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)) - return 1; - if (nexthop->type == NEXTHOP_TYPE_IFNAME - && si->type == STATIC_IPV6_IFNAME - && strcmp (nexthop->ifname, si->ifname) == 0) - return 1; - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME - && si->type == STATIC_IPV6_GATEWAY_IFNAME - && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6) - && strcmp (nexthop->ifname, si->ifname) == 0) - return 1; - return 0; -} - static void static_uninstall_ipv6 (struct prefix *p, struct static_route *si) { @@ -2896,7 +2890,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_route *si) /* Lookup nexthop. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (static_ipv6_nexthop_same (nexthop, si)) + if (static_nexthop_same (nexthop, si)) break; /* Can't find nexthop. */ From 949b719eac0c8b51c73f144eb035fab27a16c2a6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Nov 2015 13:26:39 -0500 Subject: [PATCH 0887/1342] zebra: Combine static_uninstall_ipv[4|6] into one function Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 69 +++-------------------------------------------- 1 file changed, 4 insertions(+), 65 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f0c180c99..6a54f11be 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2403,7 +2403,7 @@ static_nexthop_same (struct nexthop *nexthop, struct static_route *si) /* Uninstall static route from RIB. */ static void -static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) +static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) { struct route_node *rn; struct rib *rib; @@ -2411,7 +2411,7 @@ static_uninstall_ipv4 (safi_t safi, struct prefix *p, struct static_route *si) struct route_table *table; /* Lookup table. */ - table = zebra_vrf_table (AFI_IP, safi, si->vrf_id); + table = zebra_vrf_table (afi, safi, si->vrf_id); if (! table) return; @@ -2599,7 +2599,7 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, } /* Install into rib. */ - static_uninstall_ipv4 (safi, p, si); + static_uninstall_route (AFI_IP, safi, p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -2855,67 +2855,6 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } -static void -static_uninstall_ipv6 (struct prefix *p, struct static_route *si) -{ - struct route_table *table; - struct route_node *rn; - struct rib *rib; - struct nexthop *nexthop; - - /* Lookup table. */ - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, si->vrf_id); - if (! table) - return; - - /* Lookup existing route with type and distance. */ - rn = route_node_lookup (table, (struct prefix *) p); - if (! rn) - return; - - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; - } - - if (! rib) - { - route_unlock_node (rn); - return; - } - - /* Lookup nexthop. */ - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (static_nexthop_same (nexthop, si)) - break; - - /* Can't find nexthop. */ - if (! nexthop) - { - route_unlock_node (rn); - return; - } - - /* Check nexthop. */ - if (rib->nexthop_num == 1) - { - rib_delnode (rn, rib); - } - else - { - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - rib_uninstall (rn, rib); - nexthop_delete (rib, nexthop); - nexthop_free (nexthop); - rib_queue_add (&zebrad, rn); - } - /* Unlock node. */ - route_unlock_node (rn); -} /* Add static route into static route configuration. */ int @@ -3040,7 +2979,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, } /* Install into rib. */ - static_uninstall_ipv6 (p, si); + static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si); /* Unlink static route from linked list. */ if (si->prev) From c1900e09a7fdd70437f3ba0329868f1eee3f5a1a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Nov 2015 13:26:40 -0500 Subject: [PATCH 0888/1342] zebra: Fix change of distance on ipv6 route creating duplicate routes If you enter: ipv6 route 2002:44:44:44::44/128 swp1 4 ipv6 route 2002:44:44:44::44/128 swp1 99 You get: host-111# show ipv6 route Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv6, I - IS-IS, B - BGP, A - Babel, T - Table, > - selected route, * - FIB route S 2002:44:44:44::44/128 [99/0] is directly connected, swp1 S>* 2002:44:44:44::44/128 [4/0] is directly connected, swp1 This problem is fixed in the ipv4 code path. Copying the same code from the ipv4 into the ipv6 code path fixes the issue. With the fix: host-111(config)# ipv6 route 2002:44:44:44::44/128 swp1 4 host-111(config)# do show ipv6 route Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv6, I - IS-IS, B - BGP, A - Babel, T - Table, > - selected route, * - FIB route S>* 2002:44:44:44::44/128 [4/0] is directly connected, swp1 C * fe80::/64 is directly connected, swp1 C>* fe80::/64 is directly connected, eth0 host-111(config)# ipv6 route 2002:44:44:44::44/128 swp1 99 host-111(config)# do show ipv6 route Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv6, I - IS-IS, B - BGP, A - Babel, T - Table, > - selected route, * - FIB route S>* 2002:44:44:44::44/128 [99/0] is directly connected, swp1 C * fe80::/64 is directly connected, swp1 C>* fe80::/64 is directly connected, eth0 host-111(config)# Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6a54f11be..0efa88d57 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2866,6 +2866,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, struct static_route *si; struct static_route *pp; struct static_route *cp; + struct static_route *update = NULL; struct zebra_vrf *zvrf = vrf_info_get (vrf_id); struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]; @@ -2886,16 +2887,23 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Do nothing if there is a same static route. */ for (si = rn->info; si; si = si->next) { - if (distance == si->distance - && type == si->type + if (type == si->type && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { - route_unlock_node (rn); - return 0; + if (distance == si->distance) + { + route_unlock_node (rn); + return 0; + } + else + update = si; } } + if (update) + static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id); + /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); From 1ca8d40f996c0760a1a8931f54044dd7ca9e3f9c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 17:45:03 +0100 Subject: [PATCH 0889/1342] ripd, isisd: fix warnings that make the build fail These issues have been found by running buildtest.sh using GCC 5.2.0 and Clang 3.7.0 Fixes pointer checks that can never be null Signed-off-by: Christian Franke Tested-by: NetDEF CI System Signed-off-by: Donald Sharp --- isisd/isis_adjacency.c | 6 +++--- ripd/ripd.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index a485575be..b8d28b371 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -203,7 +203,7 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state if (dyn) adj_name = (const char *)dyn->name.name; else - adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown"; + adj_name = sysid_print (adj->sysid); zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", adj_name, @@ -314,8 +314,8 @@ isis_adj_print (struct isis_adjacency *adj) zlog_debug ("%s", dyn->name.name); zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d", - adj->sysid ? sysid_print (adj->sysid) : "unknown", - snpa_print (adj->snpa), adj->level, adj->hold_time); + sysid_print (adj->sysid), snpa_print (adj->snpa), + adj->level, adj->hold_time); if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { zlog_debug ("IPv4 Address(es):"); diff --git a/ripd/ripd.c b/ripd/ripd.c index b708889f5..870873d51 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2574,7 +2574,7 @@ rip_update_process (int route_type) if (IS_RIP_DEBUG_EVENT) zlog_debug("SEND UPDATE to %s ifindex %d", - (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex); + ifp->name, ifp->ifindex); /* send update on each connected network */ for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected)) From 76fbc64c5d82c6f540cb4a1ac855f9f098fa6c5f Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:41 +0100 Subject: [PATCH 0890/1342] lib: add function to get precise remaining time of timer thread Signed-off-by: Christian Franke Acked-by: Donald Sharp --- lib/thread.c | 8 ++++++++ lib/thread.h | 1 + 2 files changed, 9 insertions(+) diff --git a/lib/thread.c b/lib/thread.c index cb5133233..5e40261e6 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -662,6 +662,14 @@ thread_timer_remain_second (struct thread *thread) return 0; } +struct timeval +thread_timer_remain(struct thread *thread) +{ + quagga_get_relative(NULL); + + return timeval_subtract(thread->u.sands, relative_time); +} + #define debugargdef const char *funcname, const char *schedfrom, int fromln #define debugargpass funcname, schedfrom, fromln diff --git a/lib/thread.h b/lib/thread.h index 43ffbf603..5bc756c7a 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -209,6 +209,7 @@ extern unsigned int thread_cancel_event (struct thread_master *, void *); extern struct thread *thread_fetch (struct thread_master *, struct thread *); extern void thread_call (struct thread *); extern unsigned long thread_timer_remain_second (struct thread *); +extern struct timeval thread_timer_remain(struct thread*); extern int thread_should_yield (struct thread *); extern unsigned long timeval_elapsed (struct timeval a, struct timeval b); From dbe99e0c407bcb383d0be0c0010fefccc5b46866 Mon Sep 17 00:00:00 2001 From: Alexis Fasquel Date: Mon, 16 Nov 2015 13:55:16 -0500 Subject: [PATCH 0891/1342] bgpd: Update dump to allow Extended Time Format Allow the bgp dump functionality to handle the Extended Time format as specified in RFC 6396. Fixes a segmentation fault with multiple dump rules as well. Signed-off-by: Alexis Fasquel Acked-by: Donald Sharp Signed-off-by: Donald Sharp --- bgpd/bgp_btoa.c | 2 + bgpd/bgp_dump.c | 289 +++++++++++++++++++++------------------------- bgpd/bgp_dump.h | 4 +- doc/appendix.texi | 22 +++- doc/bgpd.texi | 29 +++-- 5 files changed, 182 insertions(+), 164 deletions(-) diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index edc80b2fe..b9ff67c54 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -192,6 +192,8 @@ main (int argc, char **argv) if (type == MSG_PROTOCOL_BGP4MP) printf ("TYPE: BGP4MP"); + else if (type == MSG_PROTOCOL_BGP4MP_ET) + printf ("TYPE: BGP4MP_ET"); else if (type == MSG_TABLE_DUMP) printf ("TYPE: MSG_TABLE_DUMP"); else diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 3d88dee4b..227fc7af0 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -37,10 +37,25 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA enum bgp_dump_type { BGP_DUMP_ALL, + BGP_DUMP_ALL_ET, BGP_DUMP_UPDATES, + BGP_DUMP_UPDATES_ET, BGP_DUMP_ROUTES }; +static const struct bgp_dump_type_map { + enum bgp_dump_type type; + const char *str; +} bgp_dump_type_map[] = + { + {BGP_DUMP_ALL, "all"}, + {BGP_DUMP_ALL_ET, "all-et"}, + {BGP_DUMP_UPDATES, "updates"}, + {BGP_DUMP_UPDATES_ET, "updates-et"}, + {BGP_DUMP_ROUTES, "routes-mrt"}, + {0, NULL}, + }; + enum MRT_MSG_TYPES { MSG_NULL, MSG_START, /* sender is starting up */ @@ -58,8 +73,6 @@ enum MRT_MSG_TYPES { MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */ }; -static int bgp_dump_interval_func (struct thread *); - struct bgp_dump { enum bgp_dump_type type; @@ -75,6 +88,9 @@ struct bgp_dump struct thread *t_interval; }; +static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump); +static int bgp_dump_interval_func (struct thread *); + /* BGP packet dump output buffer. */ struct stream *bgp_dump_obuf; @@ -87,10 +103,6 @@ struct bgp_dump bgp_dump_updates; /* BGP dump structure for 'dump bgp routes' */ struct bgp_dump bgp_dump_routes; -/* Dump whole BGP table is very heavy process. */ -struct thread *t_bgp_dump_routes; - -/* Some define for BGP packet dump. */ static FILE * bgp_dump_open_file (struct bgp_dump *bgp_dump) { @@ -171,24 +183,40 @@ bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) /* Dump common header. */ static void -bgp_dump_header (struct stream *obuf, int type, int subtype) +bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type) { - time_t now; + struct timeval clock; + long msecs; + time_t secs; + + if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET) + && type == MSG_PROTOCOL_BGP4MP) + type = MSG_PROTOCOL_BGP4MP_ET; + + gettimeofday(&clock, NULL); - /* Set header. */ - time (&now); + secs = clock.tv_sec; + msecs = clock.tv_usec; /* Put dump packet header. */ - stream_putl (obuf, now); + stream_putl (obuf, secs); stream_putw (obuf, type); stream_putw (obuf, subtype); - stream_putl (obuf, 0); /* len */ + + /* Adding microseconds for the MRT Extended Header */ + if (type == MSG_PROTOCOL_BGP4MP_ET) + stream_putl (obuf, msecs); } static void bgp_dump_set_size (struct stream *s, int type) { + /* + * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET: + * "The Microsecond Timestamp is included in the computation + * of the Length field value." (RFC6396 2011) + */ stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE); } @@ -204,7 +232,8 @@ bgp_dump_routes_index_table(struct bgp *bgp) stream_reset (obuf); /* MRT header */ - bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE); + bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE, + BGP_DUMP_ROUTES); /* Collector BGP ID */ stream_put_in_addr (obuf, &bgp->router_id); @@ -232,12 +261,10 @@ bgp_dump_routes_index_table(struct bgp *bgp) { stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); } -#ifdef HAVE_IPV6 else if (sockunion_family(&peer->su) == AF_INET6) { stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6); } -#endif /* HAVE_IPV6 */ /* Peer's BGP ID */ stream_put_in_addr (obuf, &peer->remote_id); @@ -247,13 +274,11 @@ bgp_dump_routes_index_table(struct bgp *bgp) { stream_put_in_addr (obuf, &peer->su.sin.sin_addr); } -#ifdef HAVE_IPV6 else if (sockunion_family(&peer->su) == AF_INET6) { stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); } -#endif /* HAVE_IPV6 */ /* Peer's AS number. */ /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */ @@ -309,15 +334,11 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq) /* MRT header */ if (afi == AFI_IP) - { - bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST); - } -#ifdef HAVE_IPV6 + bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST, + BGP_DUMP_ROUTES); else if (afi == AFI_IP6) - { - bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST); - } -#endif /* HAVE_IPV6 */ + bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST, + BGP_DUMP_ROUTES); /* Sequence number */ stream_putl(obuf, seq); @@ -331,13 +352,11 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq) /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8); } -#ifdef HAVE_IPV6 else if (afi == AFI_IP6) { /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8); } -#endif /* HAVE_IPV6 */ /* Save where we are now, so we can overwride the entry count later */ int sizep = stream_get_endp(obuf); @@ -396,9 +415,7 @@ bgp_dump_interval_func (struct thread *t) if (bgp_dump->type == BGP_DUMP_ROUTES) { unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0); -#ifdef HAVE_IPV6 bgp_dump_routes_func (AFI_IP6, 0, seq); -#endif /* HAVE_IPV6 */ /* Close the file now. For a RIB dump there's no point in leaving * it open until the next scheduled dump starts. */ fclose(bgp_dump->fp); bgp_dump->fp = NULL; @@ -442,7 +459,6 @@ bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4) else stream_put (obuf, empty, IPV4_MAX_BYTELEN); } -#ifdef HAVE_IPV6 else if (peer->su.sa.sa_family == AF_INET6) { /* Interface Index and Address family. */ @@ -457,7 +473,6 @@ bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4) else stream_put (obuf, empty, IPV6_MAX_BYTELEN); } -#endif /* HAVE_IPV6 */ } /* Dump BGP status change. */ @@ -474,7 +489,8 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new) obuf = bgp_dump_obuf; stream_reset (obuf); - bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4); + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4, + bgp_dump_all.type); bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/ stream_putw (obuf, status_old); @@ -505,11 +521,13 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, /* Dump header and common part. */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) { - bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4); + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4, + bgp_dump->type); } else { - bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, + bgp_dump->type); } bgp_dump_common (obuf, peer, 0); @@ -590,9 +608,28 @@ bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, { unsigned int interval; + /* Don't schedule duplicate dumps if the dump command is given twice */ + if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0 + && type == bgp_dump->type) + { + if (interval_str) + { + if (bgp_dump->interval_str && + strcmp(bgp_dump->interval_str, interval_str) == 0) + return CMD_SUCCESS; + } + else + { + if (!bgp_dump->interval_str) + return CMD_SUCCESS; + } + } + + /* Removing previous config */ + bgp_dump_unset(vty, bgp_dump); + if (interval_str) { - /* Check interval string. */ interval = bgp_dump_parse_time (interval_str); if (interval == 0) @@ -601,37 +638,26 @@ bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, return CMD_WARNING; } - /* Don't schedule duplicate dumps if the dump command is given twice */ - if (interval == bgp_dump->interval && - type == bgp_dump->type && - path && bgp_dump->filename && !strcmp (path, bgp_dump->filename)) - { - return CMD_SUCCESS; - } - - /* Set interval. */ - bgp_dump->interval = interval; - if (bgp_dump->interval_str) - free (bgp_dump->interval_str); + /* Setting interval string */ bgp_dump->interval_str = strdup (interval_str); - } else { interval = 0; } - - /* Create interval thread. */ - bgp_dump_interval_add (bgp_dump, interval); /* Set type. */ bgp_dump->type = type; + /* Set interval */ + bgp_dump->interval = interval; + /* Set file name. */ - if (bgp_dump->filename) - free (bgp_dump->filename); bgp_dump->filename = strdup (path); + /* Create interval thread. */ + bgp_dump_interval_add (bgp_dump, interval); + /* This should be called when interval is expired. */ bgp_dump_open_file (bgp_dump); @@ -641,21 +667,21 @@ bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) { - /* Set file name. */ + /* Removing file name. */ if (bgp_dump->filename) { free (bgp_dump->filename); bgp_dump->filename = NULL; } - /* This should be called when interval is expired. */ + /* Closing file. */ if (bgp_dump->fp) { fclose (bgp_dump->fp); bgp_dump->fp = NULL; } - /* Create interval thread. */ + /* Removing interval thread. */ if (bgp_dump->t_interval) { thread_cancel (bgp_dump->t_interval); @@ -664,116 +690,71 @@ bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) bgp_dump->interval = 0; + /* Removing interval string. */ if (bgp_dump->interval_str) { free (bgp_dump->interval_str); bgp_dump->interval_str = NULL; } - return CMD_SUCCESS; } DEFUN (dump_bgp_all, dump_bgp_all_cmd, - "dump bgp all PATH", + "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]", "Dump packet\n" "BGP packet dump\n" - "Dump all BGP packets\n" - "Output filename\n") -{ - return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL); -} - -DEFUN (dump_bgp_all_interval, - dump_bgp_all_interval_cmd, - "dump bgp all PATH INTERVAL", - "Dump packet\n" - "BGP packet dump\n" - "Dump all BGP packets\n" + "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n" + "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n" + "Dump whole BGP routing table\n" "Output filename\n" "Interval of output\n") { - return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]); -} + int bgp_dump_type = 0; + const char *interval = NULL; + struct bgp_dump *bgp_dump_struct = NULL; + const struct bgp_dump_type_map *map = NULL; -DEFUN (no_dump_bgp_all, - no_dump_bgp_all_cmd, - "no dump bgp all [PATH] [INTERVAL]", - NO_STR - "Dump packet\n" - "BGP packet dump\n" - "Dump all BGP packets\n") -{ - return bgp_dump_unset (vty, &bgp_dump_all); -} - -DEFUN (dump_bgp_updates, - dump_bgp_updates_cmd, - "dump bgp updates PATH", - "Dump packet\n" - "BGP packet dump\n" - "Dump BGP updates only\n" - "Output filename\n") -{ - return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL); -} + for (map = bgp_dump_type_map; map->str; map++) + if (strcmp(argv[0], map->str) == 0) + bgp_dump_type = map->type; -DEFUN (dump_bgp_updates_interval, - dump_bgp_updates_interval_cmd, - "dump bgp updates PATH INTERVAL", - "Dump packet\n" - "BGP packet dump\n" - "Dump BGP updates only\n" - "Output filename\n" - "Interval of output\n") -{ - return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]); -} - -DEFUN (no_dump_bgp_updates, - no_dump_bgp_updates_cmd, - "no dump bgp updates [PATH] [INTERVAL]", - NO_STR - "Dump packet\n" - "BGP packet dump\n" - "Dump BGP updates only\n") -{ - return bgp_dump_unset (vty, &bgp_dump_updates); -} + switch (bgp_dump_type) + { + case BGP_DUMP_ALL: + case BGP_DUMP_ALL_ET: + bgp_dump_struct = &bgp_dump_all; + break; + case BGP_DUMP_UPDATES: + case BGP_DUMP_UPDATES_ET: + bgp_dump_struct = &bgp_dump_updates; + break; + case BGP_DUMP_ROUTES: + default: + bgp_dump_struct = &bgp_dump_routes; + break; + } -DEFUN (dump_bgp_routes, - dump_bgp_routes_cmd, - "dump bgp routes-mrt PATH", - "Dump packet\n" - "BGP packet dump\n" - "Dump whole BGP routing table\n" - "Output filename\n") -{ - return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL); -} + /* When an interval is given */ + if (argc == 3) + interval = argv[2]; -DEFUN (dump_bgp_routes_interval, - dump_bgp_routes_interval_cmd, - "dump bgp routes-mrt PATH INTERVAL", - "Dump packet\n" - "BGP packet dump\n" - "Dump whole BGP routing table\n" - "Output filename\n" - "Interval of output\n") -{ - return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]); + return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type, + argv[1], interval); } -DEFUN (no_dump_bgp_routes, - no_dump_bgp_routes_cmd, - "no dump bgp routes-mrt [PATH] [INTERVAL]", +DEFUN (no_dump_bgp_all, + no_dump_bgp_all_cmd, + "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]", NO_STR - "Dump packet\n" - "BGP packet dump\n" - "Dump whole BGP routing table\n") + "Stop dump packet\n" + "Stop BGP packet dump\n" + "Stop dump process all/all-et\n" + "Stop dump process updates/updates-et\n" + "Stop dump process route-mrt\n") { - return bgp_dump_unset (vty, &bgp_dump_routes); + return bgp_dump_unset (vty, &bgp_dump_all); } /* BGP node structure. */ @@ -815,18 +796,26 @@ config_write_bgp_dump (struct vty *vty) { if (bgp_dump_all.filename) { + const char *type_str = "all"; + if (bgp_dump_all.type == BGP_DUMP_ALL_ET) + type_str = "all-et"; + if (bgp_dump_all.interval_str) - vty_out (vty, "dump bgp all %s %s%s", + vty_out (vty, "dump bgp %s %s %s%s", type_str, bgp_dump_all.filename, bgp_dump_all.interval_str, VTY_NEWLINE); else - vty_out (vty, "dump bgp all %s%s", + vty_out (vty, "dump bgp %s %s%s", type_str, bgp_dump_all.filename, VTY_NEWLINE); } if (bgp_dump_updates.filename) { + const char *type_str = "updates"; + if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET) + type_str = "updates-et"; + if (bgp_dump_updates.interval_str) - vty_out (vty, "dump bgp updates %s %s%s", + vty_out (vty, "dump bgp %s %s %s%s", type_str, bgp_dump_updates.filename, bgp_dump_updates.interval_str, VTY_NEWLINE); else @@ -839,9 +828,6 @@ config_write_bgp_dump (struct vty *vty) vty_out (vty, "dump bgp routes-mrt %s %s%s", bgp_dump_routes.filename, bgp_dump_routes.interval_str, VTY_NEWLINE); - else - vty_out (vty, "dump bgp routes-mrt %s%s", - bgp_dump_routes.filename, VTY_NEWLINE); } return 0; } @@ -860,14 +846,7 @@ bgp_dump_init (void) install_node (&bgp_dump_node, config_write_bgp_dump); install_element (CONFIG_NODE, &dump_bgp_all_cmd); - install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_all_cmd); - install_element (CONFIG_NODE, &dump_bgp_updates_cmd); - install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd); - install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd); - install_element (CONFIG_NODE, &dump_bgp_routes_cmd); - install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); - install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); } void diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h index e097c7840..d1e66d91c 100644 --- a/bgpd/bgp_dump.h +++ b/bgpd/bgp_dump.h @@ -23,7 +23,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* MRT compatible packet dump values. */ /* type value */ -#define MSG_PROTOCOL_BGP4MP 16 +#define MSG_PROTOCOL_BGP4MP 16 +#define MSG_PROTOCOL_BGP4MP_ET 17 + /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 diff --git a/doc/appendix.texi b/doc/appendix.texi index 87276c52f..3904c5f0c 100644 --- a/doc/appendix.texi +++ b/doc/appendix.texi @@ -28,6 +28,25 @@ don't need to change header format. | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group +@end example + + If `type' is PROTOCOL_BGP4MP_ET, the common header format will +contain an additional microsecond field (RFC6396 2011). + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Type | Subtype | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Microsecond | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and @@ -227,7 +246,8 @@ If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT, @group Constants: /* type value */ - #define MSG_PROTOCOL_BGP4MP 16 + #define MSG_PROTOCOL_BGP4MP 16 + #define MSG_PROTOCOL_BGP4MP_ET 17 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 7d92b5e16..5eb08510c 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -1326,21 +1326,36 @@ log file bgpd.log @node Dump BGP packets and table @section Dump BGP packets and table -@deffn Command {dump bgp all @var{path}} {} -@deffnx Command {dump bgp all @var{path} @var{interval}} {} +@deffn Command {dump bgp all @var{path} [@var{interval}]} {} +@deffnx Command {dump bgp all-et @var{path} [@var{interval}]} {} +@deffnx Command {no dump bgp all [@var{path}] [@var{interval}]} {} Dump all BGP packet and events to @var{path} file. +If @var{interval} is set, a new file will be created for echo @var{interval} of seconds. +The path @var{path} can be set with date and time formatting (strftime). +The type ‘all-et’ enables support for Extended Timestamp Header (@pxref{Packet Binary Dump Format}). +(@pxref{Packet Binary Dump Format}) @end deffn -@deffn Command {dump bgp updates @var{path}} {} -@deffnx Command {dump bgp updates @var{path} @var{interval}} {} -Dump BGP updates to @var{path} file. +@deffn Command {dump bgp updates @var{path} [@var{interval}]} {} +@deffnx Command {dump bgp updates-et @var{path} [@var{interval}]} {} +@deffnx Command {no dump bgp updates [@var{path}] [@var{interval}]} {} +Dump only BGP updates messages to @var{path} file. +If @var{interval} is set, a new file will be created for echo @var{interval} of seconds. +The path @var{path} can be set with date and time formatting (strftime). +The type ‘updates-et’ enables support for Extended Timestamp Header (@pxref{Packet Binary Dump Format}). @end deffn -@deffn Command {dump bgp routes @var{path}} {} -@deffnx Command {dump bgp routes @var{path}} {} +@deffn Command {dump bgp routes-mrt @var{path}} {} +@deffnx Command {dump bgp routes-mrt @var{path} @var{interval}} {} +@deffnx Command {no dump bgp route-mrt [@var{path}] [@var{interval}]} {} Dump whole BGP routing table to @var{path}. This is heavy process. +The path @var{path} can be set with date and time formatting (strftime). +If @var{interval} is set, a new file will be created for echo @var{interval} of seconds. @end deffn +Note: the interval variable can also be set using hours and minutes: 04h20m00. + + @node BGP Configuration Examples @section BGP Configuration Examples From abfd40d68202882696260617729518a6d2c99302 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:42 +0100 Subject: [PATCH 0892/1342] lib: don't have log functions change errno Signed-off-by: Christian Franke Acked-by: Donald Sharp --- lib/log.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/log.c b/lib/log.c index 10a771e1e..e376205df 100644 --- a/lib/log.c +++ b/lib/log.c @@ -151,6 +151,7 @@ time_print(FILE *fp, struct timestamp_control *ctl) static void vzlog (struct zlog *zl, int priority, const char *format, va_list args) { + int original_errno = errno; struct timestamp_control tsctl; tsctl.already_rendered = 0; @@ -169,6 +170,7 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) fflush (stderr); /* In this case we return at here. */ + errno = original_errno; return; } tsctl.precision = zl->timestamp_precision; @@ -216,6 +218,8 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) vty_log ((zl->record_priority ? zlog_priority[priority] : NULL), zlog_proto_names[zl->protocol], format, &tsctl, args); + + errno = original_errno; } static char * From 77277a140984aa78756cbf363606a324c84113db Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:43 +0100 Subject: [PATCH 0893/1342] isisd: annotate some function arguments with const Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_adjacency.c | 8 ++++---- isisd/isis_adjacency.h | 6 +++--- isisd/isis_dynhn.c | 6 +++--- isisd/isis_dynhn.h | 6 +++--- isisd/isis_misc.c | 10 +++++----- isisd/isis_misc.h | 10 +++++----- isisd/isis_pdu.c | 10 +++++----- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index b8d28b371..c7ab83ba0 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -52,7 +52,7 @@ extern struct isis *isis; static struct isis_adjacency * -adj_alloc (u_char * id) +adj_alloc (const u_char *id) { struct isis_adjacency *adj; @@ -63,7 +63,7 @@ adj_alloc (u_char * id) } struct isis_adjacency * -isis_new_adj (u_char * id, u_char * snpa, int level, +isis_new_adj (const u_char * id, const u_char * snpa, int level, struct isis_circuit *circuit) { struct isis_adjacency *adj; @@ -104,7 +104,7 @@ isis_new_adj (u_char * id, u_char * snpa, int level, } struct isis_adjacency * -isis_adj_lookup (u_char * sysid, struct list *adjdb) +isis_adj_lookup (const u_char * sysid, struct list *adjdb) { struct isis_adjacency *adj; struct listnode *node; @@ -117,7 +117,7 @@ isis_adj_lookup (u_char * sysid, struct list *adjdb) } struct isis_adjacency * -isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb) +isis_adj_lookup_snpa (const u_char * ssnpa, struct list *adjdb) { struct listnode *node; struct isis_adjacency *adj; diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index caa3107db..99d0c493b 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -101,10 +101,10 @@ struct isis_adjacency struct isis_circuit *circuit; /* back pointer */ }; -struct isis_adjacency *isis_adj_lookup (u_char * sysid, struct list *adjdb); -struct isis_adjacency *isis_adj_lookup_snpa (u_char * ssnpa, +struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb); +struct isis_adjacency *isis_adj_lookup_snpa (const u_char * ssnpa, struct list *adjdb); -struct isis_adjacency *isis_new_adj (u_char * id, u_char * snpa, int level, +struct isis_adjacency *isis_new_adj (const u_char * id, const u_char * snpa, int level, struct isis_circuit *circuit); void isis_delete_adj (void *adj); void isis_adj_state_change (struct isis_adjacency *adj, diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index ffb0d503f..412f098a1 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -78,7 +78,7 @@ dyn_cache_cleanup (struct thread *thread) } struct isis_dynhn * -dynhn_find_by_id (u_char * id) +dynhn_find_by_id (const u_char * id) { struct listnode *node = NULL; struct isis_dynhn *dyn = NULL; @@ -104,7 +104,7 @@ dynhn_find_by_name (const char *hostname) } void -isis_dynhn_insert (u_char * id, struct hostname *hostname, int level) +isis_dynhn_insert (const u_char * id, struct hostname *hostname, int level) { struct isis_dynhn *dyn; @@ -135,7 +135,7 @@ isis_dynhn_insert (u_char * id, struct hostname *hostname, int level) } void -isis_dynhn_remove (u_char * id) +isis_dynhn_remove (const u_char * id) { struct isis_dynhn *dyn; diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h index 379c454fc..f06a067be 100644 --- a/isisd/isis_dynhn.h +++ b/isisd/isis_dynhn.h @@ -32,9 +32,9 @@ struct isis_dynhn }; void dyn_cache_init (void); -void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level); -void isis_dynhn_remove (u_char * id); -struct isis_dynhn *dynhn_find_by_id (u_char * id); +void isis_dynhn_insert (const u_char * id, struct hostname *hostname, int level); +void isis_dynhn_remove (const u_char * id); +struct isis_dynhn *dynhn_find_by_id (const u_char * id); struct isis_dynhn *dynhn_find_by_name (const char *hostname); void dynhn_print_all (struct vty *vty); diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 2dfd7cca3..f19b44155 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -63,7 +63,7 @@ char nlpidstring[30]; * This converts the isonet to its printable format */ const char * -isonet_print (u_char * from, int len) +isonet_print (const u_char * from, int len) { int i = 0; char *pos = isonet; @@ -370,7 +370,7 @@ syst2string (int type) * Print functions - we print to static vars */ const char * -snpa_print (u_char * from) +snpa_print (const u_char * from) { int i = 0; u_char *pos = (u_char *)snpa; @@ -402,7 +402,7 @@ snpa_print (u_char * from) } const char * -sysid_print (u_char * from) +sysid_print (const u_char * from) { int i = 0; char *pos = sysid; @@ -434,7 +434,7 @@ sysid_print (u_char * from) } const char * -rawlspid_print (u_char * from) +rawlspid_print (const u_char * from) { char *pos = lspid; if (!from) @@ -553,7 +553,7 @@ unix_hostname (void) * If no dynamic hostname found then returns formatted system ID. */ const char * -print_sys_hostname (u_char *sysid) +print_sys_hostname (const u_char *sysid) { struct isis_dynhn *dyn; diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h index 0cd65a66a..37eaea154 100644 --- a/isisd/isis_misc.h +++ b/isisd/isis_misc.h @@ -41,14 +41,14 @@ int sysid2buff (u_char *, const char *); /* * Printing functions */ -const char *isonet_print (u_char *, int len); -const char *sysid_print (u_char *); -const char *snpa_print (u_char *); -const char *rawlspid_print (u_char *); +const char *isonet_print (const u_char *, int len); +const char *sysid_print (const u_char *); +const char *snpa_print (const u_char *); +const char *rawlspid_print (const u_char *); const char *time2string (u_int32_t); /* typedef struct nlpids nlpids; */ char *nlpid2string (struct nlpids *); -const char *print_sys_hostname (u_char *sysid); +const char *print_sys_hostname (const u_char *sysid); void zlog_dump_data (void *data, int len); /* diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index c50b53ffe..740855518 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -912,7 +912,7 @@ process_p2p_hello (struct isis_circuit *circuit) * Process IS-IS LAN Level 1/2 Hello PDU */ static int -process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) +process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) { int retval = ISIS_OK; struct isis_lan_hello_hdr hdr; @@ -1300,7 +1300,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) * Section 7.3.15.1 - Action on receipt of a link state PDU */ static int -process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) +process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) { struct isis_link_state_hdr *hdr; struct isis_adjacency *adj = NULL; @@ -1649,7 +1649,7 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) static int process_snp (int snp_type, int level, struct isis_circuit *circuit, - u_char * ssnpa) + const u_char *ssnpa) { int retval = ISIS_OK; int cmp, own_lsp; @@ -1945,7 +1945,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, } static int -process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa) +process_csnp (int level, struct isis_circuit *circuit, const u_char *ssnpa) { if (isis->debugs & DEBUG_SNP_PACKETS) { @@ -1969,7 +1969,7 @@ process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa) } static int -process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa) +process_psnp (int level, struct isis_circuit *circuit, const u_char *ssnpa) { if (isis->debugs & DEBUG_SNP_PACKETS) { From 390f16ee4e506f782aa48077cc8318e6fdcf4a5c Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:44 +0100 Subject: [PATCH 0894/1342] isisd: remove superfluous checks after XMALLOC etc. Signed-off-by: Christian Franke --- isisd/isis_lsp.c | 7 +------ isisd/isis_route.c | 19 ------------------- isisd/isis_spf.c | 5 ----- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 0470c5b90..8f7fc0a02 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -581,12 +581,7 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); - if (!lsp) - { - /* FIXME: set lspdbol bit */ - zlog_warn ("lsp_new(): out of memory"); - return NULL; - } + /* FIXME: Should be minimal mtu? */ lsp->pdu = stream_new (1500); if (LSP_FRAGMENT (lsp_id) == 0) diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 8ab470cef..0348a7944 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -67,10 +67,6 @@ isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) } nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop)); - if (!nexthop) - { - zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!"); - } nexthop->ifindex = ifindex; memcpy (&nexthop->ip, ip, sizeof (struct in_addr)); @@ -139,10 +135,6 @@ isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) struct isis_nexthop6 *nexthop6; nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6)); - if (!nexthop6) - { - zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!"); - } nexthop6->ifindex = ifindex; memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr)); @@ -284,11 +276,6 @@ isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth, struct listnode *node; rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info)); - if (!rinfo) - { - zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!"); - return NULL; - } if (prefix->family == AF_INET) { @@ -424,12 +411,6 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, prefix2str (prefix, (char *) buff, BUFSIZ); rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies); - if (!rinfo_new) - { - zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", - area->area_tag); - return NULL; - } if (family == AF_INET) route_node = route_node_get (area->route_table[level - 1], prefix); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 28525ce6a..0657c1c81 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -189,11 +189,6 @@ isis_vertex_new (void *id, enum vertextype vtype) struct isis_vertex *vertex; vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); - if (vertex == NULL) - { - zlog_err ("isis_vertex_new Out of memory!"); - return NULL; - } vertex->type = vtype; switch (vtype) From b461630bed1a0ed33c3a38fc485caf826ff05ce9 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:45 +0100 Subject: [PATCH 0895/1342] isisd: fix a typo in a log message Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 740855518..d63a8a65b 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1694,7 +1694,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { - zlog_warn ("Received a CSNP with bogus length %d", pdu_len); + zlog_warn ("Received a PSNP with bogus length %d", pdu_len); return ISIS_WARNING; } } From f35169ecdb481ca1e176cbb234b5294b2ca901a7 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 12 Nov 2015 14:09:08 +0100 Subject: [PATCH 0896/1342] isisd: don't corrupt memory for long hostnames Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_lsp.c | 13 ++++++++++--- isisd/isis_tlv.h | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 8f7fc0a02..050a9f987 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1225,12 +1225,19 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) /* Dynamic Hostname */ if (area->dynhostname) { + const char *hostname = unix_hostname(); + size_t hostname_len = strlen(hostname); + lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct hostname)); - memcpy (lsp->tlv_data.hostname->name, unix_hostname (), - strlen (unix_hostname ())); - lsp->tlv_data.hostname->namelen = strlen (unix_hostname ()); + strncpy((char *)lsp->tlv_data.hostname->name, hostname, + sizeof(lsp->tlv_data.hostname->name)); + if (hostname_len <= MAX_TLV_LEN) + lsp->tlv_data.hostname->namelen = hostname_len; + else + lsp->tlv_data.hostname->namelen = MAX_TLV_LEN; + tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); } diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index e092f4d6d..f5b59a796 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -112,6 +112,8 @@ #define AUTH_INFO_HDRLEN 3 +#define MAX_TLV_LEN 255 + #define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5) #define LAN_NEIGHBOURS_LEN 6 #define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */ From 912aac4f670ffd383b757995914f4d1b5e7596aa Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:47 +0100 Subject: [PATCH 0897/1342] isisd: do remove ipv6 routes from Zebra We can abort isis_zebra_route_del_ipv6 if the route in question has ISIS_ROUTE_FLAG_ZEBRA_SYNCED unset, meaning it's not in the kernel. Aborting the function if the flag is set prevents us from removing any routes. Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_zebra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 8a7841758..1201627d5 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -420,7 +420,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, struct listnode *node; struct prefix_ipv6 prefix6; - if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + if (!CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.vrf_id = VRF_DEFAULT; From 7324ae1f0daa5537dbcfded208707581b2b36335 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:04:48 +0100 Subject: [PATCH 0898/1342] isisd: initialize circuit to match area is_type New circuits should be initialized to match the is_type of their area. Also add an additional check to make sure that no IIHs are sent for levels which are not enabled. Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_circuit.c | 12 ++++++------ isisd/isis_pdu.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 2ef43ccfd..6ecaca688 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -122,13 +122,13 @@ isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area) circuit->area = area; /* - * The level for the circuit is same as for the area, unless configured - * otherwise. + * Whenever the is-type of an area is changed, the is-type of each circuit + * in that area is updated to a non-empty subset of the area is-type. + * Inversely, when configuring a new circuit, this property should be + * ensured as well. */ - if (area->is_type != IS_LEVEL_1_AND_2 && area->is_type != circuit->is_type) - zlog_warn ("circut %s is_type %d mismatch with area %s is_type %d", - circuit->interface->name, circuit->is_type, - circuit->area->area_tag, area->is_type); + if (area->is_type != IS_LEVEL_1_AND_2) + circuit->is_type = area->is_type; /* * Add the circuit into area diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index d63a8a65b..26efe4da2 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -2446,6 +2446,13 @@ send_lan_l1_hello (struct thread *thread) assert (circuit); circuit->u.bc.t_send_lan_hello[0] = NULL; + if (!(circuit->area->is_type & IS_LEVEL_1)) + { + zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area", + circuit->area->area_tag); + return 1; + } + if (circuit->u.bc.run_dr_elect[0]) retval = isis_dr_elect (circuit, 1); @@ -2469,6 +2476,13 @@ send_lan_l2_hello (struct thread *thread) assert (circuit); circuit->u.bc.t_send_lan_hello[1] = NULL; + if (!(circuit->area->is_type & IS_LEVEL_2)) + { + zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area", + circuit->area->area_tag); + return 1; + } + if (circuit->u.bc.run_dr_elect[1]) retval = isis_dr_elect (circuit, 2); From f1fc1db703c34dbeb9639c4f6ebfb096cdc3fc62 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:43:31 +0100 Subject: [PATCH 0899/1342] isisd: allow to adjust lsp-mtu Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_circuit.c | 82 ++++++++++++++++++++++++++++++++--------- isisd/isis_circuit.h | 2 + isisd/isis_constants.h | 1 - isisd/isis_lsp.c | 24 ++++++------ isisd/isis_lsp.h | 3 +- isisd/isis_pdu.c | 36 +++++------------- isisd/isisd.c | 84 ++++++++++++++++++++++++++++++++++++++++-- isisd/isisd.h | 3 +- 8 files changed, 172 insertions(+), 63 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 6ecaca688..9fe11c29f 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -578,6 +578,29 @@ isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set) } } +size_t +isis_circuit_pdu_size(struct isis_circuit *circuit) +{ + return ISO_MTU(circuit); +} + +void +isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream) +{ + size_t stream_size = isis_circuit_pdu_size(circuit); + + if (!*stream) + { + *stream = stream_new(stream_size); + } + else + { + if (STREAM_SIZE(*stream) != stream_size) + stream_resize(*stream, stream_size); + stream_reset(*stream); + } +} + int isis_circuit_up (struct isis_circuit *circuit) { @@ -592,6 +615,15 @@ isis_circuit_up (struct isis_circuit *circuit) if (circuit->is_passive) return ISIS_OK; + if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) + { + zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!", + isis_circuit_pdu_size(circuit), circuit->interface->name, + circuit->area->lsp_mtu); + isis_circuit_down(circuit); + return ISIS_ERROR; + } + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* @@ -624,9 +656,6 @@ isis_circuit_up (struct isis_circuit *circuit) circuit->u.bc.adjdb[0] = list_new (); circuit->u.bc.adjdb[1] = list_new (); - if (circuit->area->min_bcast_mtu == 0 || - ISO_MTU (circuit) < circuit->area->min_bcast_mtu) - circuit->area->min_bcast_mtu = ISO_MTU (circuit); /* * ISO 10589 - 8.4.1 Enabling of broadcast circuits */ @@ -688,11 +717,8 @@ isis_circuit_up (struct isis_circuit *circuit) } /* initialize the circuit streams after opening connection */ - if (circuit->rcv_stream == NULL) - circuit->rcv_stream = stream_new (ISO_MTU (circuit)); - - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); + isis_circuit_stream(circuit, &circuit->rcv_stream); + isis_circuit_stream(circuit, &circuit->snd_stream); #ifdef GNU_LINUX THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, @@ -1193,6 +1219,7 @@ DEFUN (ip_router_isis, struct isis_circuit *circuit; struct interface *ifp; struct isis_area *area; + int rv; ifp = (struct interface *) vty->index; assert (ifp); @@ -1221,16 +1248,25 @@ DEFUN (ip_router_isis, area = vty->index; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); - isis_circuit_if_bind (circuit, ifp); + if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) + { + vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); + rv = CMD_WARNING; + } + else + { + isis_circuit_if_bind (circuit, ifp); - circuit->ip_router = 1; - area->ip_circuits++; - circuit_update_nlpids (circuit); + circuit->ip_router = 1; + area->ip_circuits++; + circuit_update_nlpids (circuit); + rv = CMD_SUCCESS; + } vty->node = INTERFACE_NODE; vty->index = ifp; - return CMD_SUCCESS; + return rv; } DEFUN (no_ip_router_isis, @@ -1291,6 +1327,7 @@ DEFUN (ipv6_router_isis, struct isis_circuit *circuit; struct interface *ifp; struct isis_area *area; + int rv; ifp = (struct interface *) vty->index; assert (ifp); @@ -1319,16 +1356,25 @@ DEFUN (ipv6_router_isis, area = vty->index; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); - isis_circuit_if_bind (circuit, ifp); + if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) + { + vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); + rv = CMD_WARNING; + } + else + { + isis_circuit_if_bind (circuit, ifp); - circuit->ipv6_router = 1; - area->ipv6_circuits++; - circuit_update_nlpids (circuit); + circuit->ipv6_router = 1; + area->ipv6_circuits++; + circuit_update_nlpids (circuit); + rv = CMD_SUCCESS; + } vty->node = INTERFACE_NODE; vty->index = ifp; - return CMD_SUCCESS; + return rv; } DEFUN (no_ipv6_router_isis, diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index d86fee040..d88387973 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -164,5 +164,7 @@ void isis_circuit_down (struct isis_circuit *); void circuit_update_nlpids (struct isis_circuit *circuit); void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, char detail); +size_t isis_circuit_pdu_size(struct isis_circuit *circuit); +void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream); #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h index bb2c4b406..8b21894e4 100644 --- a/isisd/isis_constants.h +++ b/isisd/isis_constants.h @@ -34,7 +34,6 @@ #define ISO_SAP 0xFE #define INTRADOMAIN_ROUTEING_SELECTOR 0 #define SEQUENCE_MODULUS 4294967296 -#define RECEIVE_LSP_BUFFER_SIZE 1492 /* * implementation specific jitter values diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 050a9f987..dc18aa025 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -575,15 +575,16 @@ lsp_new_from_stream_ptr (struct stream *stream, } struct isis_lsp * -lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, - u_int8_t lsp_bits, u_int16_t checksum, int level) +lsp_new(struct isis_area *area, u_char * lsp_id, + u_int16_t rem_lifetime, u_int32_t seq_num, + u_int8_t lsp_bits, u_int16_t checksum, int level) { struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); + lsp->area = area; - /* FIXME: Should be minimal mtu? */ - lsp->pdu = stream_new (1500); + lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); if (LSP_FRAGMENT (lsp_id) == 0) lsp->lspu.frags = list_new (); lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); @@ -1131,7 +1132,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, lsp_clear_data (lsp); return lsp; } - lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, + lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, lsp_bits_generate (level, area->overload_bit, area->attached_bit), 0, level); lsp->area = area; @@ -1593,7 +1594,7 @@ lsp_generate (struct isis_area *area, int level) area->lspdb[level - 1]); } rem_lifetime = lsp_rem_lifetime (area, level); - newlsp = lsp_new (lspid, rem_lifetime, seq_num, + newlsp = lsp_new (area, lspid, rem_lifetime, seq_num, area->is_type | area->overload_bit | area->attached_bit, 0, level); newlsp->area = area; @@ -1966,7 +1967,7 @@ lsp_generate_pseudo (struct isis_circuit *circuit, int level) rem_lifetime = lsp_rem_lifetime (circuit->area, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp = lsp_new (lsp_id, rem_lifetime, 1, + lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1, circuit->area->is_type | circuit->area->attached_bit, 0, level); lsp->area = circuit->area; @@ -2356,8 +2357,7 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, lsp->area = area; lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? IS_LEVEL_1 : IS_LEVEL_2; - /* FIXME: Should be minimal mtu? */ - lsp->pdu = stream_new (1500); + lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE); @@ -2479,11 +2479,11 @@ generate_topology_lsps (struct isis_area *area) lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF); rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1); - lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit - | area->attached_bit, 0, 1); + lsp = lsp_new (area, lspid, rem_lifetime, 1, + IS_LEVEL_1 | area->overload_bit | area->attached_bit, + 0, 1); if (!lsp) return; - lsp->area = area; lsp->from_topology = 1; /* Creating LSP data based on topology info. */ diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 6e7f745d2..92a5dfe59 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -66,7 +66,8 @@ int lsp_regenerate_schedule (struct isis_area *area, int level, int lsp_generate_pseudo (struct isis_circuit *circuit, int level); int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level); -struct isis_lsp *lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, +struct isis_lsp *lsp_new (struct isis_area *area, u_char * lsp_id, + u_int16_t rem_lifetime, u_int32_t seq_num, u_int8_t lsp_bits, u_int16_t checksum, int level); struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream, diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 26efe4da2..0c3f57f6f 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1895,9 +1895,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, if (entry->rem_lifetime && entry->checksum && entry->seq_num && memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { - lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime), - 0, 0, entry->checksum, level); - lsp->area = circuit->area; + lsp = lsp_new(circuit->area, entry->lsp_id, + ntohs(entry->rem_lifetime), + 0, 0, entry->checksum, level); lsp_insert (lsp, circuit->area->lspdb[level - 1]); ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); ISIS_SET_FLAG (lsp->SSNflags, circuit); @@ -2121,10 +2121,7 @@ isis_receive (struct thread *thread) circuit = THREAD_ARG (thread); assert (circuit); - if (circuit->rcv_stream == NULL) - circuit->rcv_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->rcv_stream); + isis_circuit_stream(circuit, &circuit->rcv_stream); retval = circuit->rx (circuit, ssnpa); circuit->t_read = NULL; @@ -2160,10 +2157,7 @@ isis_receive (struct thread *thread) circuit->t_read = NULL; - if (circuit->rcv_stream == NULL) - circuit->rcv_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->rcv_stream); + isis_circuit_stream(circuit, &circuit->rcv_stream); retval = circuit->rx (circuit, ssnpa); @@ -2268,10 +2262,7 @@ send_hello (struct isis_circuit *circuit, int level) return ISIS_WARNING; } - if (!circuit->snd_stream) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->snd_stream); + isis_circuit_stream(circuit, &circuit->snd_stream); if (circuit->circ_type == CIRCUIT_T_BROADCAST) if (level == IS_LEVEL_1) @@ -2527,10 +2518,7 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, unsigned long auth_tlv_offset = 0; int retval = ISIS_OK; - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->snd_stream); + isis_circuit_stream(circuit, &circuit->snd_stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM, @@ -2854,10 +2842,7 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) unsigned long auth_tlv_offset = 0; int retval = ISIS_OK; - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->snd_stream); + isis_circuit_stream(circuit, &circuit->snd_stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, @@ -3179,10 +3164,7 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, u_int16_t length; struct isis_fixed_hdr fixed_hdr; - if (!circuit->snd_stream) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->snd_stream); + isis_circuit_stream(circuit, &circuit->snd_stream); // fill_llc_hdr (stream); if (level == IS_LEVEL_1) diff --git a/isisd/isisd.c b/isisd/isisd.c index 20b8e5012..714668960 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -158,13 +158,11 @@ isis_area_create (const char *area_tag) area->oldmetric = 0; area->newmetric = 1; area->lsp_frag_threshold = 90; + area->lsp_mtu = DEFAULT_LSP_MTU; #ifdef TOPOLOGY_GENERATE memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); #endif /* TOPOLOGY_GENERATE */ - /* FIXME: Think of a better way... */ - area->min_bcast_mtu = 1497; - area->area_tag = strdup (area_tag); listnode_add (isis->area_list, area); area->isis = isis; @@ -1545,6 +1543,76 @@ DEFUN (no_net, return area_clear_net_title (vty, argv[0]); } +static +int area_set_lsp_mtu(struct vty *vty, struct isis_area *area, unsigned int lsp_mtu) +{ + struct isis_circuit *circuit; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + { + if(lsp_mtu > isis_circuit_pdu_size(circuit)) + { + vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", + circuit->interface->name, isis_circuit_pdu_size(circuit), + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + area->lsp_mtu = lsp_mtu; + lsp_regenerate_schedule(area, IS_LEVEL_1_AND_2, 1); + + return CMD_SUCCESS; +} + +DEFUN (area_lsp_mtu, + area_lsp_mtu_cmd, + "lsp-mtu <128-4352>", + "Configure the maximum size of generated LSPs\n" + "Maximum size of generated LSPs\n") +{ + struct isis_area *area; + + area = vty->index; + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + unsigned int lsp_mtu; + + VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352); + + return area_set_lsp_mtu(vty, area, lsp_mtu); +} + +DEFUN(no_area_lsp_mtu, + no_area_lsp_mtu_cmd, + "no lsp-mtu", + NO_STR + "Configure the maximum size of generated LSPs\n") +{ + struct isis_area *area; + + area = vty->index; + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + return area_set_lsp_mtu(vty, area, DEFAULT_LSP_MTU); +} + +ALIAS(no_area_lsp_mtu, + no_area_lsp_mtu_arg_cmd, + "no lsp-mtu <128-4352>", + NO_STR + "Configure the maximum size of generated LSPs\n" + "Maximum size of generated LSPs\n"); + DEFUN (area_passwd_md5, area_passwd_md5_cmd, "area-password md5 WORD", @@ -2990,6 +3058,12 @@ isis_config_write (struct vty *vty) write++; } } + if (area->lsp_mtu != DEFAULT_LSP_MTU) + { + vty_out(vty, " lsp-mtu %u%s", area->lsp_mtu, VTY_NEWLINE); + write++; + } + /* Minimum SPF interval. */ if (area->min_spf_interval[0] == area->min_spf_interval[1]) { @@ -3223,6 +3297,10 @@ isis_init () install_element (ISIS_NODE, &is_type_cmd); install_element (ISIS_NODE, &no_is_type_cmd); + install_element (ISIS_NODE, &area_lsp_mtu_cmd); + install_element (ISIS_NODE, &no_area_lsp_mtu_cmd); + install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd); + install_element (ISIS_NODE, &area_passwd_md5_cmd); install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); install_element (ISIS_NODE, &area_passwd_clear_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 838a08bd8..6e95e8ea6 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -91,7 +91,8 @@ struct isis_area struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v6 SPTs */ struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */ #endif - unsigned int min_bcast_mtu; +#define DEFAULT_LSP_MTU 1497 + unsigned int lsp_mtu; /* Size of LSPs to generate */ struct list *circuit_list; /* IS-IS circuits */ struct flags flags; struct thread *t_tick; /* LSP walker */ From 749e87a0731ae53cf73af507afb63bab3f8e937f Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:21:44 +0100 Subject: [PATCH 0900/1342] isisd: purge on correct level Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_lsp.c | 6 +++--- isisd/isis_lsp.h | 3 ++- isisd/isis_pdu.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index dc18aa025..1c472c06c 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -2345,7 +2345,8 @@ lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level) * -> Do as in 7.3.16.4 */ void -lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, +lsp_purge_non_exist (int level, + struct isis_link_state_hdr *lsp_hdr, struct isis_area *area) { struct isis_lsp *lsp; @@ -2355,8 +2356,7 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, */ lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp->area = area; - lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? - IS_LEVEL_1 : IS_LEVEL_2; + lsp->level = level; lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 92a5dfe59..a35bfa762 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -87,7 +87,8 @@ void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, void lsp_search_and_destroy (u_char * id, dict_t * lspdb); void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level); -void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, +void lsp_purge_non_exist (int level, + struct isis_link_state_hdr *lsp_hdr, struct isis_area *area); #define LSP_EQUAL 1 diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 0c3f57f6f..d2be27b02 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1557,7 +1557,7 @@ process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) if (!lsp) { /* 7.3.16.4: initiate a purge */ - lsp_purge_non_exist (hdr, circuit->area); + lsp_purge_non_exist(level, hdr, circuit->area); return ISIS_OK; } /* 7.3.15.1 d) - If this is our own lsp and we have it */ From 80a8f72654631fe00f787c73515dc7d064251adc Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 12 Nov 2015 14:21:47 +0100 Subject: [PATCH 0901/1342] isisd: add a debug mode that traces LSP construction Signed-off-by: Christian Franke --- isisd/isis_lsp.c | 117 +++++++++++++++++++++++++++++++++++++++++++++-- isisd/isisd.c | 37 +++++++++++++++ isisd/isisd.h | 9 ++++ 3 files changed, 158 insertions(+), 5 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 1c472c06c..74a86c896 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1170,6 +1170,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) uint32_t metric; u_char zero_id[ISIS_SYS_ID_LEN + 1]; int retval = ISIS_OK; + char buf[BUFSIZ]; + + lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level); /* * Building the zero lsp @@ -1209,12 +1212,14 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) lsp->tlv_data.nlpids->count = 0; if (area->ip_circuits > 0) { + lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag); lsp->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0) { + lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag); lsp->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] = NLPID_IPV6; @@ -1239,14 +1244,22 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) else lsp->tlv_data.hostname->namelen = MAX_TLV_LEN; + lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag, + lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name); tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); } + else + { + lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag); + } /* IPv4 address and TE router ID TLVs. In case of the first one we don't * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into * LSP and this address is same as router id. */ if (isis->router_id != 0) { + inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf)); + lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf); if (lsp->tlv_data.ipv4_addrs == NULL) { lsp->tlv_data.ipv4_addrs = list_new (); @@ -1262,6 +1275,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) * TLV's are in use. */ if (area->newmetric) { + lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag); lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); lsp->tlv_data.router_id->id.s_addr = isis->router_id; @@ -1269,6 +1283,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) TE_ROUTER_ID); } } + else + { + lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag); + } memset (&tlv_data, 0, sizeof (struct tlvs)); @@ -1295,13 +1313,25 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } #endif /* TOPOLOGY_GENERATE */ + lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag); + /* * Then build lists of tlvs related to circuits */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) { + if (!circuit->interface) + lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface", + area->area_tag, circuit_type2string(circuit->circ_type), circuit); + else + lsp_debug("ISIS (%s): Processing %s circuit %s", + area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name); + if (circuit->state != C_STATE_UP) - continue; + { + lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag); + continue; + } /* * Add IPv4 internal reachability of this circuit @@ -1309,6 +1339,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) { + lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag); if (area->oldmetric) { if (tlv_data.ipv4_int_reachs == NULL) @@ -1324,6 +1355,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) masklen2ip (ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr = ((ipreach->mask.s_addr) & (ipv4->prefix.s_addr)); + inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf)); + lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d", + area->area_tag, buf, ipv4->prefixlen); listnode_add (tlv_data.ipv4_int_reachs, ipreach); } } @@ -1349,6 +1383,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) te_ipreach->control = (ipv4->prefixlen & 0x3F); memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr, (ipv4->prefixlen + 7)/8); + inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf)); + lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d", + area->area_tag, buf, ipv4->prefixlen); listnode_add (tlv_data.te_ipv4_reachs, te_ipreach); } } @@ -1382,6 +1419,11 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) ip6reach->prefix_len = ipv6->prefixlen; memcpy (&ip6prefix, &ipv6, sizeof(ip6prefix)); apply_mask_ipv6 (ip6prefix); + + inet_ntop(AF_INET6, &ip6prefix->prefix.s6_addr, buf, sizeof(buf)); + lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d", + area->area_tag, buf, ipv6->prefixlen); + memcpy (ip6reach->prefix, ip6prefix->prefix.s6_addr, sizeof (ip6reach->prefix)); listnode_add (tlv_data.ipv6_reachs, ip6reach); @@ -1411,9 +1453,18 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) is_neigh->metrics = circuit->metrics[level - 1]; if (!memcmp (is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) - XFREE (MTYPE_ISIS_TLV, is_neigh); + { + XFREE (MTYPE_ISIS_TLV, is_neigh); + lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.", + area->area_tag); + } else - listnode_add (tlv_data.is_neighs, is_neigh); + { + listnode_add (tlv_data.is_neighs, is_neigh); + lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor", + area->area_tag, sysid_print(is_neigh->neigh_id), + LSP_PSEUDO_ID(is_neigh->neigh_id)); + } } if (area->newmetric) { @@ -1437,11 +1488,25 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) SET_TE_METRIC(te_is_neigh, metric); if (!memcmp (te_is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) - XFREE (MTYPE_ISIS_TLV, te_is_neigh); + { + XFREE (MTYPE_ISIS_TLV, te_is_neigh); + lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.", + area->area_tag); + } else - listnode_add (tlv_data.te_is_neighs, te_is_neigh); + { + listnode_add (tlv_data.te_is_neighs, te_is_neigh); + lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor", + area->area_tag, sysid_print(te_is_neigh->neigh_id), + LSP_PSEUDO_ID(te_is_neigh->neigh_id)); + } } } + else + { + lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors", + area->area_tag); + } break; case CIRCUIT_T_P2P: nei = circuit->u.p2p.neighbor; @@ -1458,6 +1523,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); is_neigh->metrics = circuit->metrics[level - 1]; listnode_add (tlv_data.is_neighs, is_neigh); + lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag, + sysid_print(is_neigh->neigh_id)); } if (area->newmetric) { @@ -1474,8 +1541,15 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); listnode_add (tlv_data.te_is_neighs, te_is_neigh); + lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag, + sysid_print(te_is_neigh->neigh_id)); } } + else + { + lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors", + area->area_tag); + } break; case CIRCUIT_T_LOOPBACK: break; @@ -1484,6 +1558,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } } + lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag); + while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) { if (lsp->tlv_data.ipv4_int_reachs == NULL) @@ -1833,6 +1909,11 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, struct es_neigh *es_neigh; struct list *adj_list; struct listnode *node; + struct isis_area *area = circuit->area; + + lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d", + area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id), + circuit->interface->name, level); lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ @@ -1853,6 +1934,9 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.is_neighs, is_neigh); + lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)", + area->area_tag, sysid_print(is_neigh->neigh_id), + LSP_PSEUDO_ID(is_neigh->neigh_id)); } if (circuit->area->newmetric) { @@ -1865,6 +1949,9 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); + lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)", + area->area_tag, sysid_print(te_is_neigh->neigh_id), + LSP_PSEUDO_ID(te_is_neigh->neigh_id)); } adj_list = list_new (); @@ -1886,6 +1973,9 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.is_neighs, is_neigh); + lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)", + area->area_tag, sysid_print(is_neigh->neigh_id), + LSP_PSEUDO_ID(is_neigh->neigh_id)); } if (circuit->area->newmetric) { @@ -1893,6 +1983,9 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); + lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", + area->area_tag, sysid_print(te_is_neigh->neigh_id), + LSP_PSEUDO_ID(te_is_neigh->neigh_id)); } } else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES) @@ -1908,11 +2001,25 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.es_neighs, es_neigh); + lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)", + area->area_tag, sysid_print(es_neigh->first_es_neigh)); + } + else + { + lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match", + area->area_tag, sysid_print(adj->sysid)); } } + else + { + lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect", + area->area_tag, sysid_print(adj->sysid)); + } } list_delete (adj_list); + lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag); + /* Reset endp of stream to overwrite only TLV part of it. */ stream_reset (lsp->pdu); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); diff --git a/isisd/isisd.c b/isisd/isisd.c index 714668960..b601032a8 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -772,6 +772,8 @@ print_debug (struct vty *vty, int flags, int onoff) vty_out (vty, "IS-IS Event debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_PACKET_DUMP) vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE); + if (flags & DEBUG_LSP_GEN) + vty_out (vty, "IS-IS LSP generation debugging is %s%s", onoffs, VTY_NEWLINE); } DEFUN (show_debugging, @@ -858,6 +860,11 @@ config_write_debug (struct vty *vty) vty_out (vty, "debug isis packet-dump%s", VTY_NEWLINE); write++; } + if (flags & DEBUG_LSP_GEN) + { + vty_out (vty, "debug isis lsp-gen%s", VTY_NEWLINE); + write++; + } return write; } @@ -1174,6 +1181,32 @@ DEFUN (no_debug_isis_packet_dump, return CMD_SUCCESS; } +DEFUN (debug_isis_lsp_gen, + debug_isis_lsp_gen_cmd, + "debug isis lsp-gen", + DEBUG_STR + "IS-IS information\n" + "IS-IS generation of own LSPs\n") +{ + isis->debugs |= DEBUG_LSP_GEN; + print_debug (vty, DEBUG_LSP_GEN, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_isis_lsp_gen, + no_debug_isis_lsp_gen_cmd, + "no debug isis lsp-gen", + UNDEBUG_STR + "IS-IS information\n" + "IS-IS generation of own LSPs\n") +{ + isis->debugs &= ~DEBUG_LSP_GEN; + print_debug (vty, DEBUG_LSP_GEN, 0); + + return CMD_SUCCESS; +} + DEFUN (show_hostname, show_hostname_cmd, "show isis hostname", @@ -3260,6 +3293,8 @@ isis_init () install_element (ENABLE_NODE, &no_debug_isis_events_cmd); install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd); install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd); + install_element (ENABLE_NODE, &debug_isis_lsp_gen_cmd); + install_element (ENABLE_NODE, &no_debug_isis_lsp_gen_cmd); install_element (CONFIG_NODE, &debug_isis_adj_cmd); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd); @@ -3285,6 +3320,8 @@ isis_init () install_element (CONFIG_NODE, &no_debug_isis_events_cmd); install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd); + install_element (CONFIG_NODE, &debug_isis_lsp_gen_cmd); + install_element (CONFIG_NODE, &no_debug_isis_lsp_gen_cmd); install_element (CONFIG_NODE, &router_isis_cmd); install_element (CONFIG_NODE, &no_router_isis_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 6e95e8ea6..51a72abde 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -166,5 +166,14 @@ extern struct thread_master *master; #define DEBUG_EVENTS (1<<10) #define DEBUG_ZEBRA (1<<11) #define DEBUG_PACKET_DUMP (1<<12) +#define DEBUG_LSP_GEN (1<<13) + +#define lsp_debug(...) \ + do \ + { \ + if (isis->debugs & DEBUG_LSP_GEN) \ + zlog_debug(__VA_ARGS__); \ + } \ + while (0) #endif /* ISISD_H */ From 61010c33fd7bf3d923c5406656c0672f0336b179 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:43:34 +0100 Subject: [PATCH 0902/1342] isisd: add a slight delay to lsp_regenerate_schedule isisd implements a holdoff interval and will refrain from regenerating an lsp if the difference between the current time and its last refresh is less than the holdoff interval. Instead, it will schedule a timer to regenerate the lsp after the holdoff interval has passed. This implementation has one disadvantage in the case where there is a succession of calls to lsp_regenerate_schedule. In such a case, the first call will trigger an immediate regeneration of the lsp, while the other calls will only schedule the regeneration timer. This leads to cases where it takes holdoff interval time for information to propagate, just because the information was only available e.g. at the second call of lsp_regenerate_schedule in such a succession of calls. By not immediately regenerating an lsp if the last generation time is sufficiently long ago, but instead scheduling the regeneration with a very small delay, we allow all information from such a succession of calls to be considered. Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_circuit.c | 2 + isisd/isis_events.c | 4 ++ isisd/isis_lsp.c | 141 ++++++++++++++++++++++++++++++++----------- isisd/isisd.c | 37 ++++++++++++ isisd/isisd.h | 20 ++++++ 5 files changed, 169 insertions(+), 35 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 9fe11c29f..81c60762c 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -789,6 +789,8 @@ isis_circuit_down (struct isis_circuit *circuit) THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]); + circuit->lsp_regenerate_pending[0] = 0; + circuit->lsp_regenerate_pending[1] = 0; } else if (circuit->circ_type == CIRCUIT_T_P2P) { diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 96d5762d3..0dee9e6f5 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -110,7 +110,10 @@ area_resign_level (struct isis_area *area, int level) } #endif /* HAVE_IPV6 */ + sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", + area->area_tag, level); THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); + area->lsp_regenerate_pending[level - 1] = 0; } void @@ -245,6 +248,7 @@ circuit_resign_level (struct isis_circuit *circuit, int level) THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]); + circuit->lsp_regenerate_pending[idx] = 0; circuit->u.bc.run_dr_elect[idx] = 0; list_delete (circuit->u.bc.lan_neighs[idx]); circuit->u.bc.lan_neighs[idx] = NULL; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 74a86c896..9ac022148 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1681,10 +1681,13 @@ lsp_generate (struct isis_area *area, int level) lsp_build (newlsp, area); /* time to calculate our checksum */ lsp_seqnum_update (newlsp); + newlsp->last_generated = time(NULL); lsp_set_all_srmflags (newlsp); refresh_time = lsp_refresh_time (newlsp, rem_lifetime); + THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); + area->lsp_regenerate_pending[level - 1] = 0; if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l1_refresh, area, refresh_time); @@ -1704,6 +1707,8 @@ lsp_generate (struct isis_area *area, int level) ntohs (newlsp->lsp_header->rem_lifetime), refresh_time); } + sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.", + area->area_tag, level); return ISIS_OK; } @@ -1766,6 +1771,7 @@ lsp_regenerate (struct isis_area *area, int level) else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l2_refresh, area, refresh_time); + area->lsp_regenerate_pending[level - 1] = 0; if (isis->debugs & DEBUG_UPDATE_PACKETS) { @@ -1779,6 +1785,8 @@ lsp_regenerate (struct isis_area *area, int level) ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } + sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.", + area->area_tag, level); return ISIS_OK; } @@ -1800,6 +1808,7 @@ lsp_l1_refresh (struct thread *thread) if ((area->is_type & IS_LEVEL_1) == 0) return ISIS_ERROR; + sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag); return lsp_regenerate (area, IS_LEVEL_1); } @@ -1817,6 +1826,7 @@ lsp_l2_refresh (struct thread *thread) if ((area->is_type & IS_LEVEL_2) == 0) return ISIS_ERROR; + sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag); return lsp_regenerate (area, IS_LEVEL_2); } @@ -1826,6 +1836,7 @@ lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) struct isis_lsp *lsp; u_char id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; + long timeout; struct listnode *cnode; struct isis_circuit *circuit; int lvl; @@ -1833,6 +1844,9 @@ lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) if (area == NULL) return ISIS_ERROR; + sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs", + area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not "); + memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0; now = time (NULL); @@ -1842,29 +1856,38 @@ lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) if (!((level & lvl) && (area->is_type & lvl))) continue; + sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled", + area->area_tag, lvl); + if (area->lsp_regenerate_pending[lvl - 1]) - continue; + { + struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]); + sched_debug("ISIS (%s): Regeneration is already pending, nothing todo." + " (Due in %lld.%03lld seconds)", area->area_tag, + (long long)remain.tv_sec, (long long)remain.tv_usec / 1000); + continue; + } lsp = lsp_search (id, area->lspdb[lvl - 1]); if (!lsp) - continue; + { + sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.", + area->area_tag); + continue; + } /* * Throttle avoidance */ + sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld", + area->area_tag, (long long)lsp->last_generated, (long long)now); THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]); diff = now - lsp->last_generated; if (diff < area->lsp_gen_interval[lvl - 1]) { - area->lsp_regenerate_pending[lvl - 1] = 1; - if (lvl == IS_LEVEL_1) - THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], - lsp_l1_refresh, area, - area->lsp_gen_interval[lvl - 1] - diff); - else if (lvl == IS_LEVEL_2) - THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], - lsp_l2_refresh, area, - area->lsp_gen_interval[lvl - 1] - diff); + timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff); + sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval", + area->area_tag, timeout); } else { @@ -1873,13 +1896,21 @@ lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) * directly. However if the lsp_regenerate call is queued for * later execution it works. */ - area->lsp_regenerate_pending[lvl - 1] = 1; - if (lvl == IS_LEVEL_1) - THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], - lsp_l1_refresh, area, 0); - else if (lvl == IS_LEVEL_2) - THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], - lsp_l2_refresh, area, 0); + timeout = 100; + sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago." + " Scheduling for execution in %ld ms.", area->area_tag, timeout); + } + + area->lsp_regenerate_pending[lvl - 1] = 1; + if (lvl == IS_LEVEL_1) + { + THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1], + lsp_l1_refresh, area, timeout); + } + else if (lvl == IS_LEVEL_2) + { + THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1], + lsp_l2_refresh, area, timeout); } } @@ -2231,13 +2262,18 @@ lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level) struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; + long timeout; int lvl; + struct isis_area *area = circuit->area; if (circuit == NULL || circuit->circ_type != CIRCUIT_T_BROADCAST || circuit->state != C_STATE_UP) return ISIS_OK; + sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s", + area->area_tag, circuit_t2string(level), circuit->interface->name); + memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; LSP_FRAGMENT (lsp_id) = 0; @@ -2245,39 +2281,74 @@ lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level) for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { + sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled", + area->area_tag, lvl); + if (!((level & lvl) && (circuit->is_type & lvl))) - continue; + { + sched_debug("ISIS (%s): Level is not active on circuit", + area->area_tag); + continue; + } - if (circuit->u.bc.is_dr[lvl - 1] == 0 || - circuit->lsp_regenerate_pending[lvl - 1]) - continue; + if (circuit->u.bc.is_dr[lvl - 1] == 0) + { + sched_debug("ISIS (%s): This IS is not DR, nothing to do.", + area->area_tag); + continue; + } + + if (circuit->lsp_regenerate_pending[lvl - 1]) + { + struct timeval remain = + thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]); + sched_debug("ISIS (%s): Regenerate is already pending, nothing todo." + " (Due in %lld.%03lld seconds)", area->area_tag, + (long long)remain.tv_sec, (long long)remain.tv_usec/1000); + continue; + } lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]); if (!lsp) - continue; + { + sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.", + area->area_tag); + continue; + } /* * Throttle avoidance */ + sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld", + area->area_tag, (long long)lsp->last_generated, (long long) now); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]); diff = now - lsp->last_generated; if (diff < circuit->area->lsp_gen_interval[lvl - 1]) { - circuit->lsp_regenerate_pending[lvl - 1] = 1; - if (lvl == IS_LEVEL_1) - THREAD_TIMER_ON (master, - circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], - lsp_l1_refresh_pseudo, circuit, - circuit->area->lsp_gen_interval[lvl - 1] - diff); - else if (lvl == IS_LEVEL_2) - THREAD_TIMER_ON (master, - circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], - lsp_l2_refresh_pseudo, circuit, - circuit->area->lsp_gen_interval[lvl - 1] - diff); + timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff); + sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval", + area->area_tag, timeout); } else { - lsp_regenerate_pseudo (circuit, lvl); + timeout = 100; + sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago." + " Scheduling for execution in %ld ms.", area->area_tag, timeout); + } + + circuit->lsp_regenerate_pending[lvl - 1] = 1; + + if (lvl == IS_LEVEL_1) + { + THREAD_TIMER_MSEC_ON(master, + circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], + lsp_l1_refresh_pseudo, circuit, timeout); + } + else if (lvl == IS_LEVEL_2) + { + THREAD_TIMER_MSEC_ON(master, + circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], + lsp_l2_refresh_pseudo, circuit, timeout); } } diff --git a/isisd/isisd.c b/isisd/isisd.c index b601032a8..0a5286e34 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -774,6 +774,8 @@ print_debug (struct vty *vty, int flags, int onoff) vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_LSP_GEN) vty_out (vty, "IS-IS LSP generation debugging is %s%s", onoffs, VTY_NEWLINE); + if (flags & DEBUG_LSP_SCHED) + vty_out (vty, "IS-IS LSP scheduling debugging is %s%s", onoffs, VTY_NEWLINE); } DEFUN (show_debugging, @@ -865,6 +867,11 @@ config_write_debug (struct vty *vty) vty_out (vty, "debug isis lsp-gen%s", VTY_NEWLINE); write++; } + if (flags & DEBUG_LSP_SCHED) + { + vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE); + write++; + } return write; } @@ -1207,6 +1214,32 @@ DEFUN (no_debug_isis_lsp_gen, return CMD_SUCCESS; } +DEFUN (debug_isis_lsp_sched, + debug_isis_lsp_sched_cmd, + "debug isis lsp-sched", + DEBUG_STR + "IS-IS information\n" + "IS-IS scheduling of LSP generation\n") +{ + isis->debugs |= DEBUG_LSP_SCHED; + print_debug (vty, DEBUG_LSP_SCHED, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_isis_lsp_sched, + no_debug_isis_lsp_sched_cmd, + "no debug isis lsp-gen", + UNDEBUG_STR + "IS-IS information\n" + "IS-IS scheduling of LSP generation\n") +{ + isis->debugs &= ~DEBUG_LSP_SCHED; + print_debug (vty, DEBUG_LSP_SCHED, 0); + + return CMD_SUCCESS; +} + DEFUN (show_hostname, show_hostname_cmd, "show isis hostname", @@ -3295,6 +3328,8 @@ isis_init () install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd); install_element (ENABLE_NODE, &debug_isis_lsp_gen_cmd); install_element (ENABLE_NODE, &no_debug_isis_lsp_gen_cmd); + install_element (ENABLE_NODE, &debug_isis_lsp_sched_cmd); + install_element (ENABLE_NODE, &no_debug_isis_lsp_sched_cmd); install_element (CONFIG_NODE, &debug_isis_adj_cmd); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd); @@ -3322,6 +3357,8 @@ isis_init () install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &debug_isis_lsp_gen_cmd); install_element (CONFIG_NODE, &no_debug_isis_lsp_gen_cmd); + install_element (CONFIG_NODE, &debug_isis_lsp_sched_cmd); + install_element (CONFIG_NODE, &no_debug_isis_lsp_sched_cmd); install_element (CONFIG_NODE, &router_isis_cmd); install_element (CONFIG_NODE, &no_router_isis_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 51a72abde..96c3ba3ed 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -97,6 +97,17 @@ struct isis_area struct flags flags; struct thread *t_tick; /* LSP walker */ struct thread *t_lsp_refresh[ISIS_LEVELS]; + /* t_lsp_refresh is used in two ways: + * a) regular refresh of LSPs + * b) (possibly throttled) updates to LSPs + * + * The lsp_regenerate_pending flag tracks whether the timer is active + * for the a) or the b) case. + * + * It is of utmost importance to clear this flag when the timer is + * rescheduled for normal refresh, because otherwise, updates will + * be delayed until the next regular refresh. + */ int lsp_regenerate_pending[ISIS_LEVELS]; /* @@ -167,6 +178,7 @@ extern struct thread_master *master; #define DEBUG_ZEBRA (1<<11) #define DEBUG_PACKET_DUMP (1<<12) #define DEBUG_LSP_GEN (1<<13) +#define DEBUG_LSP_SCHED (1<<14) #define lsp_debug(...) \ do \ @@ -176,4 +188,12 @@ extern struct thread_master *master; } \ while (0) +#define sched_debug(...) \ + do \ + { \ + if (isis->debugs & DEBUG_LSP_SCHED) \ + zlog_debug(__VA_ARGS__); \ + } \ + while (0) + #endif /* ISISD_H */ From 9dfcca6122c9f4f3642241ff50029d7669af3999 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:32:11 +0100 Subject: [PATCH 0903/1342] isisd: fix assertion in LSP refresh timer calculation Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_lsp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 9ac022148..2b478b169 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1087,6 +1087,8 @@ lsp_rem_lifetime (struct isis_area *area, int level) MAX_AGE_JITTER); /* No jitter if the max refresh will be less than configure gen interval */ + /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at + * this point */ if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300)) rem_lifetime = area->max_lsp_lifetime[level - 1]; @@ -1110,7 +1112,8 @@ lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime) refresh_time > (rem_lifetime - 300)) refresh_time = rem_lifetime - 300; - assert (area->lsp_gen_interval[level - 1] < refresh_time); + /* In cornercases, refresh_time might be <= lsp_gen_interval, however + * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */ return refresh_time; } From acf9865f7fcec6a8d47df6ed7946a5e8ca398918 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 12 Nov 2015 14:24:22 +0100 Subject: [PATCH 0904/1342] isisd: add support to import routes from other protocols Signed-off-by: Christian Franke --- isisd/Makefile.am | 5 +- isisd/isis_lsp.c | 134 ++++++- isisd/isis_main.c | 5 + isisd/isis_redist.c | 821 ++++++++++++++++++++++++++++++++++++++++++ isisd/isis_redist.h | 58 +++ isisd/isis_routemap.c | 551 +++++++++++++++++++++++++--- isisd/isis_routemap.h | 25 ++ isisd/isis_tlv.c | 21 +- isisd/isis_tlv.h | 13 +- isisd/isis_zebra.c | 100 ++++- isisd/isis_zebra.h | 2 + isisd/isisd.c | 4 + isisd/isisd.h | 36 +- lib/prefix.c | 11 + lib/prefix.h | 1 + lib/routemap.h | 3 +- vtysh/extract.pl.in | 2 +- 17 files changed, 1682 insertions(+), 110 deletions(-) create mode 100644 isisd/isis_redist.c create mode 100644 isisd/isis_redist.h create mode 100644 isisd/isis_routemap.h diff --git a/isisd/Makefile.am b/isisd/Makefile.am index ff6ce3caa..5f866638d 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -16,14 +16,15 @@ libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ - isis_spf.c isis_route.c isis_routemap.c + isis_spf.c isis_redist.c isis_route.c isis_routemap.c noinst_HEADERS = \ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ - iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_route.h \ + iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ + isis_route.h isis_routemap.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 2b478b169..7c64eaca1 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -5,9 +5,10 @@ * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering + * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public Licenseas published by the Free + * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * @@ -35,6 +36,7 @@ #include "if.h" #include "checksum.h" #include "md5.h" +#include "table.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -1146,6 +1148,119 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, return lsp; } +static void +lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area, + struct tlvs *tlv_data) +{ + struct route_table *er_table; + struct route_node *rn; + struct prefix_ipv4 *ipv4; + struct isis_ext_info *info; + struct ipv4_reachability *ipreach; + struct te_ipv4_reachability *te_ipreach; + + er_table = get_ext_reach(area, AF_INET, lsp->level); + if (!er_table) + return; + + for (rn = route_top(er_table); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + + ipv4 = (struct prefix_ipv4*)&rn->p; + info = rn->info; + if (area->oldmetric) + { + if (tlv_data->ipv4_ext_reachs == NULL) + { + tlv_data->ipv4_ext_reachs = list_new(); + tlv_data->ipv4_ext_reachs->del = free_tlv; + } + ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach)); + + ipreach->prefix.s_addr = ipv4->prefix.s_addr; + masklen2ip(ipv4->prefixlen, &ipreach->mask); + ipreach->prefix.s_addr &= ipreach->mask.s_addr; + + if ((info->metric & 0x3f) != info->metric) + ipreach->metrics.metric_default = 0x3f; + else + ipreach->metrics.metric_default = info->metric; + ipreach->metrics.metric_expense = METRICS_UNSUPPORTED; + ipreach->metrics.metric_error = METRICS_UNSUPPORTED; + ipreach->metrics.metric_delay = METRICS_UNSUPPORTED; + listnode_add(tlv_data->ipv4_ext_reachs, ipreach); + } + if (area->newmetric) + { + if (tlv_data->te_ipv4_reachs == NULL) + { + tlv_data->te_ipv4_reachs = list_new(); + tlv_data->te_ipv4_reachs->del = free_tlv; + } + te_ipreach = + XCALLOC(MTYPE_ISIS_TLV, + sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen)); + if (info->metric > MAX_WIDE_PATH_METRIC) + te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC); + else + te_ipreach->te_metric = htonl(info->metric); + te_ipreach->control = ipv4->prefixlen & 0x3f; + memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr, + PSIZE(ipv4->prefixlen)); + listnode_add(tlv_data->te_ipv4_reachs, te_ipreach); + } + } +} + +static void +lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area, + struct tlvs *tlv_data) +{ + struct route_table *er_table; + struct route_node *rn; + struct prefix_ipv6 *ipv6; + struct isis_ext_info *info; + struct ipv6_reachability *ip6reach; + + er_table = get_ext_reach(area, AF_INET6, lsp->level); + if (!er_table) + return; + + for (rn = route_top(er_table); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + + ipv6 = (struct prefix_ipv6*)&rn->p; + info = rn->info; + + if (tlv_data->ipv6_reachs == NULL) + { + tlv_data->ipv6_reachs = list_new(); + tlv_data->ipv6_reachs->del = free_tlv; + } + ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach)); + if (info->metric > MAX_WIDE_PATH_METRIC) + ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC); + else + ip6reach->metric = htonl(info->metric); + ip6reach->control_info = DISTRIBUTION_EXTERNAL; + ip6reach->prefix_len = ipv6->prefixlen; + memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix)); + listnode_add(tlv_data->ipv6_reachs, ip6reach); + } +} + +static void +lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area, + struct tlvs *tlv_data) +{ + lsp_build_ext_reach_ipv4(lsp, area, tlv_data); + lsp_build_ext_reach_ipv6(lsp, area, tlv_data); +} + /* * Builds the LSP data part. This func creates a new frag whenever * area->lsp_frag_threshold is exceeded. @@ -1561,6 +1676,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } } + lsp_build_ext_reach(lsp, area, &tlv_data); + lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag); while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) @@ -1570,12 +1687,25 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs, &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN, area->lsp_frag_threshold, - tlv_add_ipv4_reachs); + tlv_add_ipv4_int_reachs); if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } + while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs)) + { + if (lsp->tlv_data.ipv4_ext_reachs == NULL) + lsp->tlv_data.ipv4_ext_reachs = list_new (); + lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs, + &lsp->tlv_data.ipv4_ext_reachs, + IPV4_REACH_LEN, area->lsp_frag_threshold, + tlv_add_ipv4_ext_reachs); + if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs)) + lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, + lsp0, area, level); + } + /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit() * for now. lsp_tlv_fit() needs to be fixed to deal with variable length * TLVs (sub TLVs!). */ diff --git a/isisd/isis_main.c b/isisd/isis_main.c index fba7b1017..3a7308795 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -34,6 +34,7 @@ #include "privs.h" #include "sigevent.h" #include "filter.h" +#include "plist.h" #include "zclient.h" #include "vrf.h" @@ -47,6 +48,7 @@ #include "isisd/isis_dynhn.h" #include "isisd/isis_spf.h" #include "isisd/isis_route.h" +#include "isisd/isis_routemap.h" #include "isisd/isis_zebra.h" /* Default configuration file name */ @@ -332,9 +334,12 @@ main (int argc, char **argv, char **envp) memory_init (); access_list_init(); vrf_init (); + prefix_list_init(); isis_init (); isis_circuit_init (); isis_spf_cmds_init (); + isis_redist_init (); + isis_route_map_init(); /* create the global 'isis' instance */ isis_new (1); diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c new file mode 100644 index 000000000..abb9ecd40 --- /dev/null +++ b/isisd/isis_redist.c @@ -0,0 +1,821 @@ +/* + * IS-IS Rout(e)ing protocol - isis_redist.c + * + * Copyright (C) 2013-2015 Christian Franke + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "if.h" +#include "linklist.h" +#include "memory.h" +#include "memtypes.h" +#include "prefix.h" +#include "routemap.h" +#include "stream.h" +#include "table.h" +#include "vty.h" + +#include "isisd/dict.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_flags.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_tlv.h" +#include "isisd/isisd.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_route.h" +#include "isisd/isis_zebra.h" + +static int +redist_protocol(int family) +{ + if (family == AF_INET) + return 0; + if (family == AF_INET6) + return 1; + + assert(!"Unsupported address family!"); +} + +static int +is_default(struct prefix *p) +{ + if (p->family == AF_INET) + if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) + return 1; + if (p->family == AF_INET6) + if (IN6_IS_ADDR_UNSPECIFIED(&p->u.prefix6) && p->prefixlen == 0) + return 1; + return 0; +} + +static struct route_table* +get_ext_info(struct isis *i, int family) +{ + int protocol = redist_protocol(family); + + return i->ext_info[protocol]; +} + +static struct isis_redist* +get_redist_settings(struct isis_area *area, int family, int type, int level) +{ + int protocol = redist_protocol(family); + + return &area->redist_settings[protocol][type][level-1]; +} + +struct route_table* +get_ext_reach(struct isis_area *area, int family, int level) +{ + int protocol = redist_protocol(family); + + return area->ext_reach[protocol][level-1]; +} + +static struct route_node * +isis_redist_route_node_create(route_table_delegate_t *delegate, + struct route_table *table) +{ + struct route_node *node; + node = XCALLOC(MTYPE_ROUTE_NODE, sizeof(*node)); + return node; +} + +static void +isis_redist_route_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node) +{ + if (node->info) + XFREE(MTYPE_ISIS, node->info); + XFREE (MTYPE_ROUTE_NODE, node); +} + +static route_table_delegate_t isis_redist_rt_delegate = { + .create_node = isis_redist_route_node_create, + .destroy_node = isis_redist_route_node_destroy +}; + +/* Install external reachability information into a + * specific area for a specific level. + * Schedule an lsp regenerate if necessary */ +static void +isis_redist_install(struct isis_area *area, int level, + struct prefix *p, struct isis_ext_info *info) +{ + int family = p->family; + struct route_table *er_table = get_ext_reach(area, family, level); + struct route_node *er_node; + + if (!er_table) + { + zlog_warn("%s: External reachability table of area %s" + " is not initialized.", __func__, area->area_tag); + return; + } + + er_node = route_node_get(er_table, p); + if (er_node->info) + { + route_unlock_node(er_node); + + /* Don't update/reschedule lsp generation if nothing changed. */ + if (!memcmp(er_node->info, info, sizeof(*info))) + return; + } + else + { + er_node->info = XMALLOC(MTYPE_ISIS, sizeof(*info)); + } + + memcpy(er_node->info, info, sizeof(*info)); + lsp_regenerate_schedule(area, level, 0); +} + +/* Remove external reachability information from a + * specific area for a specific level. + * Schedule an lsp regenerate if necessary. */ +static void +isis_redist_uninstall(struct isis_area *area, int level, struct prefix *p) +{ + int family = p->family; + struct route_table *er_table = get_ext_reach(area, family, level); + struct route_node *er_node; + + if (!er_table) + { + zlog_warn("%s: External reachability table of area %s" + " is not initialized.", __func__, area->area_tag); + return; + } + + er_node = route_node_lookup(er_table, p); + if (!er_node) + return; + else + route_unlock_node(er_node); + + if (!er_node->info) + return; + + route_unlock_node(er_node); + lsp_regenerate_schedule(area, level, 0); +} + +/* Update external reachability info of area for a given level + * and prefix, using the given redistribution settings. */ +static void +isis_redist_update_ext_reach(struct isis_area *area, int level, + struct isis_redist *redist, struct prefix *p, + struct isis_ext_info *info) +{ + struct isis_ext_info area_info; + route_map_result_t map_ret; + + memcpy(&area_info, info, sizeof(area_info)); + if (redist->metric != 0xffffffff) + area_info.metric = redist->metric; + + if (redist->map_name) + { + map_ret = route_map_apply(redist->map, p, RMAP_ISIS, &area_info); + if (map_ret == RMAP_DENYMATCH) + area_info.distance = 255; + } + + /* Allow synthesized default routes only on always orignate */ + if (area_info.origin == DEFAULT_ROUTE + && redist->redist != DEFAULT_ORIGINATE_ALWAYS) + area_info.distance = 255; + + if (area_info.distance < 255) + isis_redist_install(area, level, p, &area_info); + else + isis_redist_uninstall(area, level, p); +} + +static void +isis_redist_ensure_default(struct isis *isis, int family) +{ + struct prefix p; + struct route_table *ei_table = get_ext_info(isis, family); + struct route_node *ei_node; + struct isis_ext_info *info; + + if (family == AF_INET) + { + p.family = AF_INET; + p.prefixlen = 0; + memset(&p.u.prefix4, 0, sizeof(p.u.prefix4)); + } + else if (family == AF_INET6) + { + p.family = AF_INET6; + p.prefixlen = 0; + memset(&p.u.prefix6, 0, sizeof(p.u.prefix6)); + } + else + assert(!"Unknown family!"); + + ei_node = route_node_get(ei_table, &p); + if (ei_node->info) + { + route_unlock_node(ei_node); + return; + } + + ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info)); + + info = ei_node->info; + info->origin = DEFAULT_ROUTE; + info->distance = 254; + info->metric = MAX_WIDE_PATH_METRIC; +} + +/* Handle notification about route being added */ +void +isis_redist_add(int type, struct prefix *p, u_char distance, uint32_t metric) +{ + int family = p->family; + struct route_table *ei_table = get_ext_info(isis, family); + struct route_node *ei_node; + struct isis_ext_info *info; + struct listnode *node; + struct isis_area *area; + int level; + struct isis_redist *redist; + + char debug_buf[BUFSIZ]; + prefix2str(p, debug_buf, sizeof(debug_buf)); + + zlog_debug("%s: New route %s from %s.", __func__, debug_buf, + zebra_route_string(type)); + + if (!ei_table) + { + zlog_warn("%s: External information table not initialized.", + __func__); + return; + } + + ei_node = route_node_get(ei_table, p); + if (ei_node->info) + route_unlock_node(ei_node); + else + ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info)); + + info = ei_node->info; + info->origin = type; + info->distance = distance; + info->metric = metric; + + if (is_default(p)) + type = DEFAULT_ROUTE; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) + for (level = 1; level <= ISIS_LEVELS; level++) + { + redist = get_redist_settings(area, family, type, level); + if (!redist->redist) + continue; + + isis_redist_update_ext_reach(area, level, redist, p, info); + } +} + +void +isis_redist_delete(int type, struct prefix *p) +{ + int family = p->family; + struct route_table *ei_table = get_ext_info(isis, family); + struct route_node *ei_node; + struct listnode *node; + struct isis_area *area; + int level; + struct isis_redist *redist; + + char debug_buf[BUFSIZ]; + prefix2str(p, debug_buf, sizeof(debug_buf)); + + zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf, + zebra_route_string(type)); + + if (is_default(p)) + { + /* Don't remove default route but add synthetic route for use + * by "default-information originate always". Areas without the + * "always" setting will ignore routes with origin DEFAULT_ROUTE. */ + isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC); + return; + } + + if (!ei_table) + { + zlog_warn("%s: External information table not initialized.", + __func__); + return; + } + + ei_node = route_node_lookup(ei_table, p); + if (!ei_node || !ei_node->info) + { + char buf[BUFSIZ]; + prefix2str(p, buf, sizeof(buf)); + zlog_warn("%s: Got a delete for %s route %s, but that route" + " was never added.", __func__, zebra_route_string(type), + buf); + if (ei_node) + route_unlock_node(ei_node); + return; + } + route_unlock_node(ei_node); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) + for (level = 1; level < ISIS_LEVELS; level++) + { + redist = get_redist_settings(area, family, type, level); + if (!redist->redist) + continue; + + isis_redist_uninstall(area, level, p); + } + + route_unlock_node(ei_node); +} + +static void +isis_redist_routemap_set(struct isis_redist *redist, const char *routemap) +{ + if (redist->map_name) { + XFREE(MTYPE_ISIS, redist->map_name); + redist->map = NULL; + } + + if (routemap && strlen(routemap)) { + redist->map_name = XSTRDUP(MTYPE_ISIS, routemap); + redist->map = route_map_lookup_by_name(routemap); + } +} + +static void +isis_redist_update_zebra_subscriptions(struct isis *isis) +{ + struct listnode *node; + struct isis_area *area; + int type; + int level; + int protocol; + + char do_subscribe[ZEBRA_ROUTE_MAX + 1]; + + memset(do_subscribe, 0, sizeof(do_subscribe)); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) + for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) + for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) + for (level = 0; level < ISIS_LEVELS; level++) + if (area->redist_settings[protocol][type][level].redist) + do_subscribe[type] = 1; + + for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) + { + /* This field is actually controlling transmission of the IS-IS + * routes to Zebra and has nothing to do with redistribution, + * so skip it. */ + if (type == ZEBRA_ROUTE_ISIS) + continue; + + if (do_subscribe[type]) + isis_zebra_redistribute_set(type); + else + isis_zebra_redistribute_unset(type); + } +} + +static void +isis_redist_set(struct isis_area *area, int level, + int family, int type, uint32_t metric, + const char *routemap, int originate_type) +{ + int protocol = redist_protocol(family); + struct isis_redist *redist = get_redist_settings(area, family, type, level); + int i; + struct route_table *ei_table; + struct route_node *rn; + struct isis_ext_info *info; + + redist->redist = (type == DEFAULT_ROUTE) ? originate_type : 1; + redist->metric = metric; + isis_redist_routemap_set(redist, routemap); + + if (!area->ext_reach[protocol][level-1]) + { + area->ext_reach[protocol][level-1] = + route_table_init_with_delegate(&isis_redist_rt_delegate); + } + + for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) + if (!area->isis->ext_info[i]) + { + area->isis->ext_info[i] = + route_table_init_with_delegate(&isis_redist_rt_delegate); + } + + isis_redist_update_zebra_subscriptions(area->isis); + + if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS) + isis_redist_ensure_default(area->isis, family); + + ei_table = get_ext_info(area->isis, family); + for (rn = route_top(ei_table); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + info = rn->info; + + if (type == DEFAULT_ROUTE) + { + if (!is_default(&rn->p)) + continue; + } + else + { + if (info->origin != type) + continue; + } + + isis_redist_update_ext_reach(area, level, redist, &rn->p, info); + } +} + +static void +isis_redist_unset(struct isis_area *area, int level, + int family, int type) +{ + struct isis_redist *redist = get_redist_settings(area, family, type, level); + struct route_table *er_table = get_ext_reach(area, family, level); + struct route_node *rn; + struct isis_ext_info *info; + + if (!redist->redist) + return; + + redist->redist = 0; + if (!er_table) + { + zlog_warn("%s: External reachability table uninitialized.", __func__); + return; + } + + for (rn = route_top(er_table); rn; rn = route_next(rn)) + { + if (!rn->info) + continue; + info = rn->info; + + if (type == DEFAULT_ROUTE) + { + if (!is_default(&rn->p)) + continue; + } + else + { + if (info->origin != type) + continue; + } + + route_unlock_node(rn); + } + + lsp_regenerate_schedule(area, level, 0); + isis_redist_update_zebra_subscriptions(area->isis); +} + +void +isis_redist_area_finish(struct isis_area *area) +{ + int protocol; + int level; + int type; + + for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) + for (level = 0; level < ISIS_LEVELS; level++) + { + for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) + { + struct isis_redist *redist; + + redist = &area->redist_settings[protocol][type][level]; + redist->redist = 0; + if (redist->map_name) + XFREE(MTYPE_ISIS, redist->map_name); + } + route_table_finish(area->ext_reach[protocol][level]); + } + + isis_redist_update_zebra_subscriptions(area->isis); +} + +DEFUN(isis_redistribute, + isis_redistribute_cmd, + "redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD + " (level-1|level-2) {metric <0-16777215>|route-map WORD}", + REDIST_STR + "Redistribute IPv4 routes\n" + "Redistribute IPv6 routes\n" + QUAGGA_REDIST_HELP_STR_ISISD + "Redistribute into level-1\n" + "Redistribute into level-2\n" + "Metric for redistributed routes\n" + "ISIS default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct isis_area *area = vty->index; + int family; + int afi; + int type; + int level; + unsigned long metric; + const char *routemap; + + if (argc < 5) + return CMD_WARNING; + + family = str2family(argv[0]); + if (family < 0) + return CMD_WARNING; + + afi = family2afi(family); + if (!afi) + return CMD_WARNING; + + type = proto_redistnum(afi, argv[1]); + if (type < 0 || type == ZEBRA_ROUTE_ISIS) + return CMD_WARNING; + + if (!strcmp("level-1", argv[2])) + level = 1; + else if (!strcmp("level-2", argv[2])) + level = 2; + else + return CMD_WARNING; + + if ((area->is_type & level) != level) + { + vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE); + return CMD_WARNING; + } + + if (argv[3]) + { + char *endp; + metric = strtoul(argv[3], &endp, 10); + if (argv[3][0] == '\0' || *endp != '\0') + return CMD_WARNING; + } + else + { + metric = 0xffffffff; + } + + routemap = argv[4]; + + isis_redist_set(area, level, family, type, metric, routemap, 0); + return 0; +} + +DEFUN(no_isis_redistribute, + no_isis_redistribute_cmd, + "no redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD + " (level-1|level-2)", + NO_STR + REDIST_STR + "Redistribute IPv4 routes\n" + "Redistribute IPv6 routes\n" + QUAGGA_REDIST_HELP_STR_ISISD + "Redistribute into level-1\n" + "Redistribute into level-2\n") +{ + struct isis_area *area = vty->index; + int type; + int level; + int family; + int afi; + + if (argc < 3) + return CMD_WARNING; + + family = str2family(argv[0]); + if (family < 0) + return CMD_WARNING; + + afi = family2afi(family); + if (!afi) + return CMD_WARNING; + + type = proto_redistnum(afi, argv[1]); + if (type < 0 || type == ZEBRA_ROUTE_ISIS) + return CMD_WARNING; + + if (!strcmp("level-1", argv[2])) + level = 1; + else if (!strcmp("level-2", argv[2])) + level = 2; + else + return CMD_WARNING; + + isis_redist_unset(area, level, family, type); + return 0; +} + +DEFUN(isis_default_originate, + isis_default_originate_cmd, + "default-information originate (ipv4|ipv6) (level-1|level-2) " + "{always|metric <0-16777215>|route-map WORD}", + "Control distribution of default information\n" + "Distribute a default route\n" + "Distribute default route for IPv4\n" + "Distribute default route for IPv6\n" + "Distribute default route into level-1\n" + "Distribute default route into level-2\n" + "Always advertise default route\n" + "Metric for default route\n" + "ISIS default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct isis_area *area = vty->index; + int family; + int originate_type; + int level; + unsigned long metric; + const char *routemap; + + if (argc < 5) + return CMD_WARNING; + + family = str2family(argv[0]); + if (family < 0) + return CMD_WARNING; + + if (!strcmp("level-1", argv[1])) + level = 1; + else if (!strcmp("level-2", argv[1])) + level = 2; + else + return CMD_WARNING; + + if ((area->is_type & level) != level) + { + vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE); + return CMD_WARNING; + } + + if (argv[2] && *argv[2] != '\0') + originate_type = DEFAULT_ORIGINATE_ALWAYS; + else + originate_type = DEFAULT_ORIGINATE; + + if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS) + { + vty_out(vty, "Zebra doesn't implement default-originate for IPv6 yet%s", VTY_NEWLINE); + vty_out(vty, "so use with care or use default-originate always.%s", VTY_NEWLINE); + } + + if (argv[3]) + { + char *endp; + metric = strtoul(argv[3], &endp, 10); + if (argv[3][0] == '\0' || *endp != '\0') + return CMD_WARNING; + } + else + { + metric = 0xffffffff; + } + + routemap = argv[4]; + + isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, originate_type); + return 0; +} + +DEFUN(no_isis_default_originate, + no_isis_default_originate_cmd, + "no default-information originate (ipv4|ipv6) (level-1|level-2)", + NO_STR + "Control distribution of default information\n" + "Distribute a default route\n" + "Distribute default route for IPv4\n" + "Distribute default route for IPv6\n" + "Distribute default route into level-1\n" + "Distribute default route into level-2\n") +{ + struct isis_area *area = vty->index; + + int family; + int level; + + if (argc < 2) + return CMD_WARNING; + + family = str2family(argv[0]); + if (family < 0) + return CMD_WARNING; + + if (!strcmp("level-1", argv[1])) + level = 1; + else if (!strcmp("level-2", argv[1])) + level = 2; + else + return CMD_WARNING; + + isis_redist_unset(area, level, family, DEFAULT_ROUTE); + return 0; +} + +int +isis_redist_config_write(struct vty *vty, struct isis_area *area, + int family) +{ + int type; + int level; + int write = 0; + struct isis_redist *redist; + const char *family_str; + + if (family == AF_INET) + family_str = "ipv4"; + else if (family == AF_INET6) + family_str = "ipv6"; + else + return 0; + + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (type == ZEBRA_ROUTE_ISIS) + continue; + + for (level = 1; level <= ISIS_LEVELS; level++) + { + redist = get_redist_settings(area, family, type, level); + if (!redist->redist) + continue; + vty_out(vty, " redistribute %s %s level-%d", + family_str, zebra_route_string(type), level); + if (redist->metric != 0xffffffff) + vty_out(vty, " metric %u", redist->metric); + if (redist->map_name) + vty_out(vty, " route-map %s", redist->map_name); + vty_out(vty, "%s", VTY_NEWLINE); + write++; + } + } + + for (level = 1; level <= ISIS_LEVELS; level++) + { + redist = get_redist_settings(area, family, DEFAULT_ROUTE, level); + if (!redist->redist) + continue; + vty_out(vty, " default-information originate %s level-%d", + family_str, level); + if (redist->redist == DEFAULT_ORIGINATE_ALWAYS) + vty_out(vty, " always"); + if (redist->metric != 0xffffffff) + vty_out(vty, " metric %u", redist->metric); + if (redist->map_name) + vty_out(vty, " route-map %s", redist->map_name); + vty_out(vty, "%s", VTY_NEWLINE); + write++; + } + + return write; +} + +void +isis_redist_init(void) +{ + install_element(ISIS_NODE, &isis_redistribute_cmd); + install_element(ISIS_NODE, &no_isis_redistribute_cmd); + install_element(ISIS_NODE, &isis_default_originate_cmd); + install_element(ISIS_NODE, &no_isis_default_originate_cmd); +} diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h new file mode 100644 index 000000000..218462005 --- /dev/null +++ b/isisd/isis_redist.h @@ -0,0 +1,58 @@ +/* + * IS-IS Rout(e)ing protocol - isis_redist.h + * + * Copyright (C) 2013-2015 Christian Franke + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ISIS_REDIST_H +#define ISIS_REDIST_H + +#define REDIST_PROTOCOL_COUNT 2 + +#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX +#define DEFAULT_ORIGINATE 1 +#define DEFAULT_ORIGINATE_ALWAYS 2 + +struct isis_ext_info +{ + int origin; + uint32_t metric; + u_char distance; +}; + +struct isis_redist +{ + int redist; + uint32_t metric; + char *map_name; + struct route_map *map; +}; + +struct isis_area; +struct prefix; + +struct route_table *get_ext_reach(struct isis_area *area, + int family, int level); +void isis_redist_add(int type, struct prefix *p, + u_char distance, uint32_t metric); +void isis_redist_delete(int type, struct prefix *p); +int isis_redist_config_write(struct vty *vty, struct isis_area *area, + int family); +void isis_redist_init(void); +void isis_redist_area_finish(struct isis_area *area); + +#endif diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index 84a14ac57..3e0ab047e 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -1,13 +1,10 @@ /* - * IS-IS Rout(e)ing protocol - isis_routemap.c - * - * Copyright (C) 2001,2002 Sampo Saaristo - * Tampere University of Technology - * Institute of Communications Engineering + * IS-IS Rout(e)ing protocol - isis_routemap.c * + * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public Licenseas published by the Free + * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * @@ -20,18 +17,22 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include -#include "thread.h" +#include "command.h" +#include "filter.h" +#include "hash.h" +#include "if.h" #include "linklist.h" -#include "vty.h" #include "log.h" #include "memory.h" #include "prefix.h" -#include "hash.h" -#include "if.h" -#include "table.h" +#include "plist.h" #include "routemap.h" +#include "table.h" +#include "thread.h" +#include "vty.h" #include "isis_constants.h" #include "isis_common.h" @@ -47,60 +48,518 @@ #include "isis_spf.h" #include "isis_route.h" #include "isis_zebra.h" +#include "isis_routemap.h" -extern struct isis *isis; +static route_map_result_t +route_match_ip_address(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; -/* - * Prototypes. - */ -void isis_route_map_upd(const char *); -void isis_route_map_event(route_map_event_t, const char *); -void isis_route_map_init(void); + if (type != RMAP_ISIS) + return RMAP_NOMATCH; + alist = access_list_lookup(AFI_IP, (char*)rule); + if (access_list_apply(alist, prefix) != FILTER_DENY) + return RMAP_MATCH; -void -isis_route_map_upd (const char *name) + return RMAP_NOMATCH; +} + +static void * +route_match_ip_address_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void +route_match_ip_address_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* ------------------------------------------------------------*/ + +static route_map_result_t +route_match_ip_address_prefix_list(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type != RMAP_ISIS) + return RMAP_NOMATCH; + + plist = prefix_list_lookup(AFI_IP, (char*)rule); + if (prefix_list_apply(plist, prefix) != PREFIX_DENY) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +static void * +route_match_ip_address_prefix_list_compile(const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* ------------------------------------------------------------*/ + +static route_map_result_t +route_match_ipv6_address(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { - int i = 0; + struct access_list *alist; - if (!isis) - return; + if (type != RMAP_ISIS) + return RMAP_NOMATCH; + + alist = access_list_lookup(AFI_IP6, (char*)rule); + if (access_list_apply(alist, prefix) != FILTER_DENY) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +static void * +route_match_ipv6_address_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void +route_match_ipv6_address_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_ipv6_address_cmd = +{ + "ipv6 address", + route_match_ipv6_address, + route_match_ipv6_address_compile, + route_match_ipv6_address_free +}; + +/* ------------------------------------------------------------*/ + +static route_map_result_t +route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; - for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) + if (type != RMAP_ISIS) + return RMAP_NOMATCH; + + plist = prefix_list_lookup(AFI_IP6, (char*)rule); + if (prefix_list_apply(plist, prefix) != PREFIX_DENY) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +static void * +route_match_ipv6_address_prefix_list_compile(const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void +route_match_ipv6_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = +{ + "ipv6 address prefix-list", + route_match_ipv6_address_prefix_list, + route_match_ipv6_address_prefix_list_compile, + route_match_ipv6_address_prefix_list_free +}; + +/* ------------------------------------------------------------*/ + +static route_map_result_t +route_set_metric(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + uint32_t *metric; + struct isis_ext_info *info; + + if (type == RMAP_ISIS) { - if (isis->rmap[i].name) - isis->rmap[i].map = route_map_lookup_by_name (isis->rmap[i].name); - else - isis->rmap[i].map = NULL; + metric = rule; + info = object; + + info->metric = *metric; } - /* FIXME: do the address family sub-mode AF_INET6 here ? */ + return RMAP_OKAY; } -void -isis_route_map_event (route_map_event_t event, const char *name) +static void * +route_set_metric_compile(const char *arg) +{ + unsigned long metric; + char *endp; + uint32_t *ret; + + metric = strtoul(arg, &endp, 10); + if (arg[0] == '\0' || *endp != '\0' || metric > MAX_WIDE_PATH_METRIC) + return NULL; + + ret = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(ret)); + *ret = metric; + + return ret; +} + +static void +route_set_metric_free(void *rule) { - int type; + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free +}; - if (!isis) - return; +/* ------------------------------------------------------------*/ + +static int +isis_route_match_add(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg) +{ + int ret; - for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + ret = route_map_add_match (index, command, arg); + if (ret) { - if (isis->rmap[type].name && isis->rmap[type].map && - !strcmp (isis->rmap[type].name, name)) - { - isis_distribute_list_update (type); - } + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } } + return CMD_SUCCESS; +} + +static int +isis_route_match_delete(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + return CMD_SUCCESS; +} + +static int +isis_route_set_add(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg) +{ + int ret; + + ret = route_map_add_set(index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + return CMD_SUCCESS; +} + +static int +isis_route_set_delete (struct vty *vty, struct route_map_index *index, + const char *command, const char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + return CMD_SUCCESS; +} + +/* ------------------------------------------------------------*/ + +DEFUN(match_ip_address, + match_ip_address_cmd, + "match ip address (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + return isis_route_match_add(vty, vty->index, "ip address", argv[0]); +} + +DEFUN(no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + if (argc == 0) + return isis_route_match_delete(vty, vty->index, "ip address", NULL); + return isis_route_match_delete(vty, vty->index, "ip address", argv[0]); } +ALIAS(no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" +); + +/* ------------------------------------------------------------*/ + +DEFUN(match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return isis_route_match_add(vty, vty->index, "ip address prefix-list", argv[0]); +} + +DEFUN(no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return isis_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + return isis_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); +} + +ALIAS(no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_val_cmd, + "no match ip address prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n" +); + +/* ------------------------------------------------------------*/ + +DEFUN(match_ipv6_address, + match_ipv6_address_cmd, + "match ipv6 address WORD", + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + return isis_route_match_add(vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN(no_match_ipv6_address, + no_match_ipv6_address_val_cmd, + "no match ipv6 address WORD", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + if (argc == 0) + return isis_route_match_delete(vty, vty->index, "ipv6 address", NULL); + return isis_route_match_delete(vty, vty->index, "ipv6 address", argv[0]); +} + +ALIAS(no_match_ipv6_address, + no_match_ipv6_address_cmd, + "no match ipv6 address", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" +); + +/* ------------------------------------------------------------*/ + +DEFUN(match_ipv6_address_prefix_list, + match_ipv6_address_prefix_list_cmd, + "match ipv6 address prefix-list WORD", + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return isis_route_match_add(vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN(no_match_ipv6_address_prefix_list, + no_match_ipv6_address_prefix_list_cmd, + "no match ipv6 address prefix-list", + NO_STR + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return isis_route_match_delete (vty, vty->index, "ipv6 address prefix-list", NULL); + return isis_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +ALIAS(no_match_ipv6_address_prefix_list, + no_match_ipv6_address_prefix_list_val_cmd, + "no match ipv6 address prefix-list WORD", + NO_STR + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n" +); + +/* ------------------------------------------------------------*/ + +/* set metric already exists e.g. in the ospf routemap. vtysh doesn't cope well with different + * commands at the same node, therefore add set metric with the same 32-bit range as ospf and + * verify that the input is a valid isis metric */ +DEFUN(set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric vale for destination routing protocol\n" + "Metric value\n") +{ + return isis_route_set_add(vty, vty->index, "metric", argv[0]); +} + +DEFUN(no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + if (argc == 0) + return isis_route_set_delete(vty, vty->index, "metric", NULL); + return isis_route_set_delete(vty, vty->index, "metric", argv[0]); +} + +ALIAS(no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric vale for destination routing protocol\n" +); + void -isis_route_map_init (void) +isis_route_map_init(void) { - route_map_init (); - route_map_init_vty (); + route_map_init(); + route_map_init_vty(); + + route_map_install_match(&route_match_ip_address_cmd); + install_element(RMAP_NODE, &match_ip_address_cmd); + install_element(RMAP_NODE, &no_match_ip_address_val_cmd); + install_element(RMAP_NODE, &no_match_ip_address_cmd); + + route_map_install_match(&route_match_ip_address_prefix_list_cmd); + install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element(RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + + route_map_install_match(&route_match_ipv6_address_cmd); + install_element(RMAP_NODE, &match_ipv6_address_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_val_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_cmd); + + route_map_install_match(&route_match_ipv6_address_prefix_list_cmd); + install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_val_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); - route_map_add_hook (isis_route_map_upd); - route_map_delete_hook (isis_route_map_upd); - route_map_event_hook (isis_route_map_event); + route_map_install_set(&route_set_metric_cmd); + install_element(RMAP_NODE, &set_metric_cmd); + install_element(RMAP_NODE, &no_set_metric_val_cmd); + install_element(RMAP_NODE, &no_set_metric_cmd); } diff --git a/isisd/isis_routemap.h b/isisd/isis_routemap.h new file mode 100644 index 000000000..1cb063fee --- /dev/null +++ b/isisd/isis_routemap.h @@ -0,0 +1,25 @@ +/* + * IS-IS Rout(e)ing protocol - isis_routemap.h + * + * Copyright (C) 2013-2015 Christian Franke + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef ISIS_ROUTEMAP_H +#define ISIS_ROUTEMAP_H + +void isis_route_map_init(void); + +#endif diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 4fca072d9..8d4ea0e35 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -993,8 +993,8 @@ tlv_add_lsp_entries (struct list *lsps, struct stream *stream) return add_tlv (LSP_ENTRIES, pos - value, value, stream); } -int -tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream) +static int +tlv_add_ipv4_reachs (u_char tag, struct list *ipv4_reachs, struct stream *stream) { struct listnode *node; struct ipv4_reachability *reach; @@ -1007,7 +1007,7 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream) if (pos - value + IPV4_REACH_LEN > 255) { retval = - add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); + add_tlv (tag, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; @@ -1026,9 +1026,22 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream) pos += IPV4_MAX_BYTELEN; } - return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); + return add_tlv (tag, pos - value, value, stream); +} + +int +tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream) +{ + return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream); } +int +tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream) +{ + return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream); +} + + int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream) { diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index f5b59a796..619003a0e 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -230,11 +230,13 @@ struct ipv6_reachability /* bits in control_info */ #define CTRL_INFO_DIRECTION 0x80 -#define DIRECTION_UP 0 -#define DIRECTION_DOWN 1 +#define DIRECTION_UP 0x00 +#define DIRECTION_DOWN 0x80 + #define CTRL_INFO_DISTRIBUTION 0x40 -#define DISTRIBUTION_INTERNAL 0 -#define DISTRIBUTION_EXTERNAL 1 +#define DISTRIBUTION_INTERNAL 0x00 +#define DISTRIBUTION_EXTERNAL 0x40 + #define CTRL_INFO_SUBTLVS 0x20 #endif /* HAVE_IPV6 */ @@ -313,7 +315,8 @@ int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag); int tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream); int tlv_add_lsp_entries (struct list *lsps, struct stream *stream); -int tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream); +int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream); +int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream); int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream); #ifdef HAVE_IPV6 int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 1201627d5..8c4eef0a8 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -4,6 +4,7 @@ * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering + * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free @@ -525,11 +526,14 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, struct stream *stream; struct zapi_ipv4 api; struct prefix_ipv4 p; + struct prefix *p_generic = (struct prefix*)&p; unsigned long ifindex __attribute__ ((unused)); struct in_addr nexthop __attribute__ ((unused)); stream = zclient->ibuf; + memset(&api, 0, sizeof(api)); memset (&p, 0, sizeof (struct prefix_ipv4)); + memset(&nexthop, 0, sizeof(nexthop)); ifindex = 0; api.type = stream_getc (stream); @@ -554,31 +558,80 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, api.distance = stream_getc (stream); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (stream); - else - api.metric = 0; + + /* + * Avoid advertising a false default reachability. (A default + * route installed by IS-IS gets redistributed from zebra back + * into IS-IS causing us to start advertising default reachabity + * without this check) + */ + if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) + command = ZEBRA_IPV4_ROUTE_DELETE; if (command == ZEBRA_IPV4_ROUTE_ADD) - { - if (isis->debugs & DEBUG_ZEBRA) - zlog_debug ("IPv4 Route add from Z"); - } + isis_redist_add(api.type, p_generic, api.distance, api.metric); + else + isis_redist_delete(api.type, p_generic); return 0; } -#ifdef HAVE_IPV6 static int isis_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct stream *stream; + struct zapi_ipv6 api; + struct prefix_ipv6 p; + struct prefix *p_generic = (struct prefix*)&p; + struct in6_addr nexthop; + unsigned long ifindex __attribute__((unused)); + + stream = zclient->ibuf; + memset(&api, 0, sizeof(api)); + memset(&p, 0, sizeof(struct prefix_ipv6)); + memset(&nexthop, 0, sizeof(nexthop)); + ifindex = 0; + + api.type = stream_getc(stream); + api.flags = stream_getc(stream); + api.message = stream_getc(stream); + + p.family = AF_INET6; + p.prefixlen = stream_getc(stream); + stream_get(&p.prefix, stream, PSIZE(p.prefixlen)); + + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc(stream); /* this is always 1 */ + stream_get(&nexthop, stream, sizeof(nexthop)); + } + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc(stream); + ifindex = stream_getl(stream); + } + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc(stream); + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl(stream); + + /* + * Avoid advertising a false default reachability. (A default + * route installed by IS-IS gets redistributed from zebra back + * into IS-IS causing us to start advertising default reachabity + * without this check) + */ + if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) + command = ZEBRA_IPV6_ROUTE_DELETE; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + isis_redist_add(api.type, p_generic, api.distance, api.metric); + else + isis_redist_delete(api.type, p_generic); + return 0; } -#endif - -#define ISIS_TYPE_IS_REDISTRIBUTED(T) \ -T == ZEBRA_ROUTE_MAX ? \ - vrf_bitmap_check (zclient->default_information, VRF_DEFAULT) : \ - vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) int isis_distribute_list_update (int routetype) @@ -586,14 +639,23 @@ isis_distribute_list_update (int routetype) return 0; } -#if 0 /* Not yet. */ -static int -isis_redistribute_default_set (int routetype, int metric_type, - int metric_value) +void +isis_zebra_redistribute_set(int type) { - return 0; + if (type == DEFAULT_ROUTE) + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, VRF_DEFAULT); + else + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); +} + +void +isis_zebra_redistribute_unset(int type) +{ + if (type == DEFAULT_ROUTE) + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, VRF_DEFAULT); + else + zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); } -#endif /* 0 */ static void isis_zebra_connected (struct zclient *zclient) diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 001147889..dd36d7d51 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -28,5 +28,7 @@ void isis_zebra_init (struct thread_master *); void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info); int isis_distribute_list_update (int routetype); +void isis_zebra_redistribute_set(int type); +void isis_zebra_redistribute_unset(int type); #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index 0a5286e34..c446e7fcd 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -280,6 +280,8 @@ isis_area_destroy (struct vty *vty, const char *area_tag) } #endif /* HAVE_IPV6 */ + isis_redist_area_finish(area); + for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr)) { list_delete_node (area->area_addrs, node); @@ -3049,6 +3051,8 @@ isis_config_write (struct vty *vty) vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); write++; } + write += isis_redist_config_write(vty, area, AF_INET); + write += isis_redist_config_write(vty, area, AF_INET6); /* ISIS - Lsp generation interval */ if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1]) { diff --git a/isisd/isisd.h b/isisd/isisd.h index 96c3ba3ed..1a88efdc7 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -25,16 +25,12 @@ #define ISISD_VERSION "0.0.7" +#include "isisd/isis_redist.h" + /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ /* #define EXTREME_TLV_DEBUG */ -struct rmap -{ - char *name; - struct route_map *map; -}; - struct isis { u_long process_id; @@ -53,30 +49,7 @@ struct isis time_t uptime; /* when did we start */ struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */ - /* Redistributed external information. */ - struct route_table *external_info[ZEBRA_ROUTE_MAX + 1]; - /* Redistribute metric info. */ - struct - { - int type; /* Internal or External */ - int value; /* metric value */ - } dmetric[ZEBRA_ROUTE_MAX + 1]; - - struct - { - char *name; - struct route_map *map; - } rmap[ZEBRA_ROUTE_MAX + 1]; -#ifdef HAVE_IPV6 - struct - { - struct - { - char *name; - struct route_map *map; - } rmap[ZEBRA_ROUTE_MAX + 1]; - } inet6_afmode; -#endif + struct route_table *ext_info[REDIST_PROTOCOL_COUNT]; }; extern struct isis *isis; @@ -145,6 +118,9 @@ struct isis_area #endif /* HAVE_IPV6 */ /* Counters */ u_int32_t circuit_state_changes; + struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT] + [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS]; + struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS]; #ifdef TOPOLOGY_GENERATE struct list *topology; diff --git a/lib/prefix.c b/lib/prefix.c index 63742f393..936e9fcb2 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -187,6 +187,17 @@ prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen) return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen); } +int +str2family(const char *string) +{ + if (!strcmp("ipv4", string)) + return AF_INET; + else if (!strcmp("ipv6", string)) + return AF_INET6; + else + return -1; +} + /* Address Famiy Identifier to Address Family converter. */ int afi2family (afi_t afi) diff --git a/lib/prefix.h b/lib/prefix.h index bc8aebc55..a517d795a 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -170,6 +170,7 @@ union prefix46constptr #endif /*s6_addr32*/ /* Prototypes. */ +extern int str2family(const char *); extern int afi2family (afi_t); extern afi_t family2afi (int); diff --git a/lib/routemap.h b/lib/routemap.h index ba64553f3..2479c81ab 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -47,7 +47,8 @@ typedef enum RMAP_OSPF, RMAP_OSPF6, RMAP_BGP, - RMAP_ZEBRA + RMAP_ZEBRA, + RMAP_ISIS, } route_map_object_t; typedef enum diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 63186d738..82532da98 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -177,7 +177,7 @@ foreach (@ARGV) { } } -my $bad_cli_stomps = 76; +my $bad_cli_stomps = 89; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. From ec87416a1048d547c514b535c15616f9ed932a62 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:33:12 +0100 Subject: [PATCH 0905/1342] isisd: provide more detailed log for failed address removal Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_circuit.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 81c60762c..30aa92605 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -326,6 +326,13 @@ isis_circuit_del_addr (struct isis_circuit *circuit, prefix2str (connected->address, (char *)buf, BUFSIZ); zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); + zlog_warn ("Current ip addresses on %s:", circuit->interface->name); + for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip)) + { + prefix2str((struct prefix*)ip, (char *)buf, BUFSIZ); + zlog_warn(" %s", buf); + } + zlog_warn("End of addresses"); } prefix_ipv4_free (ipv4); @@ -369,6 +376,19 @@ isis_circuit_del_addr (struct isis_circuit *circuit, prefix2str (connected->address, (char *)buf, BUFSIZ); zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); + zlog_warn ("Current ip addresses on %s:", circuit->interface->name); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip6)) + { + prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ); + zlog_warn(" %s", buf); + } + zlog_warn(" -----"); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip6)) + { + prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ); + zlog_warn(" %s", buf); + } + zlog_warn("End of addresses"); } else if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); From cb32a19d143a21f31a13aec83415f27d9daa6a27 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:33:13 +0100 Subject: [PATCH 0906/1342] isisd: show interface's ipv6 addreses Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_circuit.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 30aa92605..a71ab2163 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -902,6 +902,10 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, if (detail == ISIS_UI_LEVEL_DETAIL) { + struct listnode *node; + struct prefix *ip_addr; + u_char buf[BUFSIZ]; + vty_out (vty, " Interface: %s", circuit->interface->name); vty_out (vty, ", State: %s", circuit_state2string (circuit->state)); if (circuit->is_passive) @@ -983,9 +987,6 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, } if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0) { - struct listnode *node; - struct prefix *ip_addr; - u_char buf[BUFSIZ]; vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr)) { @@ -993,6 +994,25 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, vty_out (vty, " %s%s", buf, VTY_NEWLINE); } } + if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) + { + vty_out(vty, " IPv6 Link-Locals:%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip_addr)) + { + prefix2str(ip_addr, (char*)buf, BUFSIZ), + vty_out(vty, " %s%s", buf, VTY_NEWLINE); + } + } + if (circuit->ipv6_link && listcount(circuit->ipv6_non_link) > 0) + { + vty_out(vty, " IPv6 Prefixes:%s", VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip_addr)) + { + prefix2str(ip_addr, (char*)buf, BUFSIZ), + vty_out(vty, " %s%s", buf, VTY_NEWLINE); + } + } + vty_out (vty, "%s", VTY_NEWLINE); } return; From e28718a8bffe0353691a2a7b2643bbeb2657fd66 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:33:14 +0100 Subject: [PATCH 0907/1342] isisd: fix IPv6 mask application Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_lsp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 7c64eaca1..6c48dcdb0 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1278,7 +1278,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) struct te_ipv4_reachability *te_ipreach; struct isis_adjacency *nei; #ifdef HAVE_IPV6 - struct prefix_ipv6 *ipv6, *ip6prefix; + struct prefix_ipv6 *ipv6, ip6prefix; struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ struct tlvs tlv_data; @@ -1535,14 +1535,14 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) ip6reach->control_info = 0; ip6reach->prefix_len = ipv6->prefixlen; - memcpy (&ip6prefix, &ipv6, sizeof(ip6prefix)); - apply_mask_ipv6 (ip6prefix); + memcpy(&ip6prefix, ipv6, sizeof(ip6prefix)); + apply_mask_ipv6(&ip6prefix); - inet_ntop(AF_INET6, &ip6prefix->prefix.s6_addr, buf, sizeof(buf)); + inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf)); lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d", area->area_tag, buf, ipv6->prefixlen); - memcpy (ip6reach->prefix, ip6prefix->prefix.s6_addr, + memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr, sizeof (ip6reach->prefix)); listnode_add (tlv_data.ipv6_reachs, ip6reach); } From 80d6b4e3e6358f52e06e576fcd927d0a009d964e Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:33:15 +0100 Subject: [PATCH 0908/1342] isisd: handle lsp confusion (ISO/IEC 10589:2002 7.3.16.2) Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_lsp.c | 14 +++++++++++++- isisd/isis_pdu.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 6c48dcdb0..730924861 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -273,7 +273,19 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, return LSP_EQUAL; } - if (ntohl (seq_num) >= ntohl (lsp->lsp_header->seq_num)) + /* + * LSPs with identical checksums should only be treated as newer if: + * a) The current LSP has a remaining lifetime != 0 and the other LSP has a + * remaining lifetime == 0. In this case, we should participate in the purge + * and should not treat the current LSP with remaining lifetime == 0 as older. + * b) The LSP has an incorrect checksum. In this case, we need to react as given + * in 7.3.16.2. + */ + if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num) + || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num) + && ( (lsp->lsp_header->rem_lifetime != 0 + && rem_lifetime == 0) + || lsp->lsp_header->checksum != checksum))) { if (isis->debugs & DEBUG_SNP_PACKETS) { diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index d2be27b02..bbf0d7314 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1309,6 +1309,7 @@ process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; uint16_t pdu_len; + int lsp_confusion; if (isis->debugs & DEBUG_UPDATE_PACKETS) { @@ -1483,6 +1484,21 @@ process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */ + /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but + * wrong checksum, initiate a purge. */ + if (lsp + && (lsp->lsp_header->seq_num == hdr->seq_num) + && (lsp->lsp_header->checksum != hdr->checksum)) + { + zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + ntohl(hdr->seq_num)); + hdr->rem_lifetime = 0; + lsp_confusion = 1; + } + else + lsp_confusion = 0; + /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */ if (hdr->rem_lifetime == 0) { @@ -1505,14 +1521,20 @@ process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) lsp_update (lsp, circuit->rcv_stream, circuit->area, level); /* ii */ lsp_set_all_srmflags (lsp); - /* iii */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* v */ ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */ - /* iv */ - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_SET_FLAG (lsp->SSNflags, circuit); + /* For the case of lsp confusion, flood the purge back to its + * originator so that it can react. Otherwise, don't reflood + * through incoming circuit as usual */ + if (!lsp_confusion) + { + /* iii */ + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + /* iv */ + if (circuit->circ_type != CIRCUIT_T_BROADCAST) + ISIS_SET_FLAG (lsp->SSNflags, circuit); + } } /* 7.3.16.4 b) 2) */ else if (comp == LSP_EQUAL) { From 812f282cc1b2c69c1d75cfbfe7983725ceaa4b15 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 10 Nov 2015 18:33:16 +0100 Subject: [PATCH 0909/1342] isisd: fix misleading wording in log The changed messages are actually located before transmission is attempted. Therefore, the tense is somewhat misleading, especially since transmission may not always succeed. Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_pdu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index bbf0d7314..4c420f3d7 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -2426,13 +2426,13 @@ send_hello (struct isis_circuit *circuit, int level) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %zd", + zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, length); } else { - zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %zd", + zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd", circuit->area->area_tag, circuit->interface->name, length); } @@ -2757,7 +2757,7 @@ send_csnp (struct isis_circuit *circuit, int level) if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %zd", + zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) @@ -3003,7 +3003,7 @@ send_psnp (int level, struct isis_circuit *circuit) if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %zd", + zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); @@ -3135,7 +3135,7 @@ send_lsp (struct thread *thread) if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug - ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," + ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x," " lifetime %us on %s", circuit->area->area_tag, lsp->level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), From 8253b73c3c71d4102c0010f63b59b2829f3b0f90 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 12 Nov 2015 14:24:28 +0100 Subject: [PATCH 0910/1342] isisd: make send_lsp more robust Signed-off-by: Christian Franke Tested-by: NetDEF CI System --- isisd/isis_bpf.c | 11 +++++- isisd/isis_dlpi.c | 30 +++++++++++--- isisd/isis_pdu.c | 92 +++++++++++++++++++++++++++---------------- isisd/isis_pfpacket.c | 29 ++++++++++---- 4 files changed, 114 insertions(+), 48 deletions(-) diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index f6176ef70..fd65608d7 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -29,6 +29,7 @@ #include #include "log.h" +#include "network.h" #include "stream.h" #include "if.h" @@ -339,8 +340,14 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) /* now we can send this */ written = write (circuit->fd, sock_buff, buflen); - - return ISIS_OK; + if (written < 0) + { + zlog_warn("IS-IS bpf: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } } int diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index b583d10a4..7c7e0909e 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -33,6 +33,7 @@ #include #include "log.h" +#include "network.h" #include "stream.h" #include "if.h" @@ -90,13 +91,14 @@ static u_short pf_filter[] = * interfaces plus the (optional; not needed) Solaris packet filter module. */ -static void +static int dlpisend (int fd, const void *cbuf, size_t cbuflen, const void *dbuf, size_t dbuflen, int flags) { const struct strbuf *ctlptr = NULL; const struct strbuf *dataptr = NULL; struct strbuf ctlbuf, databuf; + int rv; if (cbuf != NULL) { @@ -115,8 +117,16 @@ dlpisend (int fd, const void *cbuf, size_t cbuflen, } /* We assume this doesn't happen often and isn't operationally significant */ - if (putmsg (fd, ctlptr, dataptr, flags) == -1) - zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); + rv = putmsg(fd, ctlptr, dataptr, flags); + if (rv == -1 && dbuf == NULL) + { + /* + * For actual PDU transmission - recognizable buf dbuf != NULL, + * the error is passed upwards and should not be printed here. + */ + zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); + } + return rv; } static ssize_t @@ -587,6 +597,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) char *dstaddr; u_short *dstsap; int buflen; + int rv; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; if ((size_t)buflen > sizeof (sock_buff)) @@ -626,8 +637,17 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) sock_buff[2] = 0x03; memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); - dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, - sock_buff, buflen, 0); + rv = dlpisend(circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, + sock_buff, buflen, 0); + if (rv < 0) + { + zlog_warn("IS-IS dlpi: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } + return ISIS_OK; } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 4c420f3d7..0401e44a9 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -3087,15 +3087,14 @@ send_lsp (struct thread *thread) struct isis_circuit *circuit; struct isis_lsp *lsp; struct listnode *node; + int clear_srm = 1; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); - if (circuit->state != C_STATE_UP || circuit->is_passive == 1) - { - return retval; - } + if (!circuit->lsp_queue) + return ISIS_OK; node = listhead (circuit->lsp_queue); @@ -3105,28 +3104,56 @@ send_lsp (struct thread *thread) * thread gets a chance to run. */ if (!node) - { - return retval; - } + return ISIS_OK; + /* + * Delete LSP from lsp_queue. If it's still in queue, it is assumed + * as 'transmit pending', but send_lsp may never be called again. + * Retry will happen because SRM flag will not be cleared. + */ lsp = listgetdata(node); + list_delete_node (circuit->lsp_queue, node); + + /* Set the last-cleared time if the queue is empty. */ + /* TODO: Is is possible that new lsps keep being added to the queue + * that the queue is never empty? */ + if (list_isempty (circuit->lsp_queue)) + circuit->lsp_queue_last_cleared = time (NULL); + + if (circuit->state != C_STATE_UP || circuit->is_passive == 1) + goto out; /* * Do not send if levels do not match */ if (!(lsp->level & circuit->is_type)) - { - list_delete_node (circuit->lsp_queue, node); - return retval; - } + goto out; /* * Do not send if we do not have adjacencies in state up on the circuit */ if (circuit->upadjcount[lsp->level - 1] == 0) - { - list_delete_node (circuit->lsp_queue, node); - return retval; + goto out; + + /* stream_copy will assert and stop program execution if LSP is larger than + * the circuit's MTU. So handle and log this case here. */ + if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) + { + zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu" + " while interface stream size is %zu.", + circuit->area->area_tag, lsp->level, + rawlspid_print(lsp->lsp_header->lsp_id), + ntohl(lsp->lsp_header->seq_num), + ntohs(lsp->lsp_header->checksum), + ntohs(lsp->lsp_header->rem_lifetime), + circuit->interface->name, + stream_get_endp(lsp->pdu), + stream_get_size(circuit->snd_stream)); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu)); + retval = ISIS_ERROR; + goto out; } /* copy our lsp to the send buffer */ @@ -3147,32 +3174,29 @@ send_lsp (struct thread *thread) stream_get_endp (circuit->snd_stream)); } + clear_srm = 0; retval = circuit->tx (circuit, lsp->level); if (retval != ISIS_OK) { - zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed", + zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s", circuit->area->area_tag, lsp->level, - circuit->interface->name); - return retval; + circuit->interface->name, + (retval == ISIS_WARNING) ? "temporarily" : "permanently"); } - /* - * If the sending succeeded, we can del the lsp from circuits - * lsp_queue - */ - list_delete_node (circuit->lsp_queue, node); - - /* Set the last-cleared time if the queue is empty. */ - /* TODO: Is is possible that new lsps keep being added to the queue - * that the queue is never empty? */ - if (list_isempty (circuit->lsp_queue)) - circuit->lsp_queue_last_cleared = time (NULL); - - /* - * On broadcast circuits also the SRMflag can be cleared - */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); +out: + if (clear_srm + || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST) + || (retval != ISIS_OK && retval != ISIS_WARNING)) + { + /* SRM flag will trigger retransmission. We will not retransmit if we + * encountered a fatal error. + * On success, they should only be cleared if it's a broadcast circuit. + * On a P2P circuit, we will wait for the ack from the neighbor to clear + * the fag. + */ + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + } return retval; } diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index a9ecd40ff..2427047b3 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -26,6 +26,7 @@ #include #include "log.h" +#include "network.h" #include "stream.h" #include "if.h" @@ -367,8 +368,14 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) iov[1].iov_base = circuit->snd_stream->data; iov[1].iov_len = stream_get_endp (circuit->snd_stream); - sendmsg (circuit->fd, &msg, 0); - + if (sendmsg(circuit->fd, &msg, 0) < 0) + { + zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } return ISIS_OK; } @@ -376,6 +383,7 @@ int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { struct sockaddr_ll sa; + ssize_t rv; stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); @@ -391,11 +399,18 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level) /* lets try correcting the protocol */ sa.sll_protocol = htons (0x00FE); - sendto (circuit->fd, circuit->snd_stream->data, - stream_get_endp (circuit->snd_stream), 0, - (struct sockaddr *) &sa, - sizeof (struct sockaddr_ll)); - + rv = sendto(circuit->fd, circuit->snd_stream->data, + stream_get_endp (circuit->snd_stream), 0, + (struct sockaddr *) &sa, + sizeof (struct sockaddr_ll)); + if (rv < 0) + { + zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } return ISIS_OK; } From 642577340cfb7ad66d021ab2b86d72f7cdde03bc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 20 Nov 2015 08:33:30 -0500 Subject: [PATCH 0911/1342] zebra: Cleanup RTADV define The RTADV define was not being set correctly or consistently. Make the code consistent with our HAVE_IPV6 define. If the user wants to explicitly turn it off then they should run --disable-rtadv from the configure cli Signed-off-by: Donald Sharp --- zebra/interface.c | 20 ++++++++++---------- zebra/interface.h | 15 +++------------ zebra/main.c | 6 +++--- zebra/rib.h | 12 ++++-------- zebra/rtadv.c | 4 ++-- zebra/rtadv.h | 4 ++-- 6 files changed, 24 insertions(+), 37 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 162439fa6..411712d56 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -42,11 +42,11 @@ #include "zebra/debug.h" #include "zebra/irdp.h" -#ifdef RTADV +#if defined (HAVE_RTADV) /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 }; -#endif /* RTADV */ +#endif /* HAVE_RTADV */ /* Called when new interface is added. */ static int @@ -59,7 +59,7 @@ if_zebra_new_hook (struct interface *ifp) zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF; -#ifdef RTADV +#if defined (HAVE_RTADV) { /* Set default router advertise values. */ struct rtadvconf *rtadv; @@ -85,7 +85,7 @@ if_zebra_new_hook (struct interface *ifp) rtadv->AdvPrefixList = list_new (); } -#endif /* RTADV */ +#endif /* HAVE_RTADV */ /* Initialize installed address chains tree. */ zebra_if->ipv4_subnets = route_table_init (); @@ -638,7 +638,7 @@ connected_dump_vty (struct vty *vty, struct connected *connected) vty_out (vty, "%s", VTY_NEWLINE); } -#ifdef RTADV +#if defined (HAVE_RTADV) /* Dump interface ND information to vty. */ static void nd_dump_vty (struct vty *vty, struct interface *ifp) @@ -699,7 +699,7 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) VTY_NEWLINE); } } -#endif /* RTADV */ +#endif /* HAVE_RTADV */ /* Interface's information print out to vty interface. */ static void @@ -806,9 +806,9 @@ if_dump_vty (struct vty *vty, struct interface *ifp) connected_dump_vty (vty, connected); } -#ifdef RTADV +#if defined (HAVE_RTADV) nd_dump_vty (vty, ifp); -#endif /* RTADV */ +#endif /* HAVE_RTADV */ #ifdef HAVE_PROC_NET_DEV /* Statistics print out using proc file system. */ @@ -1782,9 +1782,9 @@ if_config_write (struct vty *vty) VTY_NEWLINE); } -#ifdef RTADV +#if defined (HAVE_RTADV) rtadv_config_write (vty, ifp); -#endif /* RTADV */ +#endif /* HAVE_RTADV */ #ifdef HAVE_IRDP irdp_config_write (vty, ifp); diff --git a/zebra/interface.h b/zebra/interface.h index fe2460435..936156eb2 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -37,16 +37,7 @@ #define IF_ZEBRA_SHUTDOWN_OFF 0 #define IF_ZEBRA_SHUTDOWN_ON 1 -/* Router advertisement feature. */ -#ifndef RTADV -#if (defined(LINUX_IPV6) && (!defined(__GLIBC__) || defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) - #ifdef HAVE_RTADV - #define RTADV - #endif -#endif -#endif - -#ifdef RTADV +#if defined (HAVE_RTADV) /* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */ struct rtadvconf { @@ -180,7 +171,7 @@ struct rtadvconf #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ }; -#endif /* RTADV */ +#endif /* HAVE_RTADV */ /* `zebra' daemon local interface structure. */ struct zebra_if @@ -197,7 +188,7 @@ struct zebra_if /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; -#ifdef RTADV +#if defined(HAVE_RTADV) struct rtadvconf rtadv; #endif /* RTADV */ diff --git a/zebra/main.c b/zebra/main.c index c5d1d76c5..f3c08f192 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -229,7 +229,7 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info) assert (zvrf); -#ifdef RTADV +#if defined (HAVE_RTADV) rtadv_init (zvrf); #endif kernel_init (zvrf); @@ -260,7 +260,7 @@ zebra_vrf_disable (vrf_id_t vrf_id, void **info) if_down (ifp); } -#ifdef RTADV +#if defined (HAVE_RTADV) rtadv_terminate (zvrf); #endif kernel_terminate (zvrf); @@ -405,7 +405,7 @@ main (int argc, char **argv) zebra_vty_init (); access_list_init (); prefix_list_init (); -#ifdef RTADV +#if defined (HAVE_RTADV) rtadv_cmd_init (); #endif #ifdef HAVE_IRDP diff --git a/zebra/rib.h b/zebra/rib.h index 1d3c15c31..ffe7e2ff6 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -304,12 +304,8 @@ struct nexthop_vrfid vrf_id_t vrf_id; }; -/* Router advertisement feature. */ -#if !defined(RTADV) && defined(LINUX_IPV6) && defined(HAVE_RTADV) -# define RTADV -#endif -#if defined (RTADV) +#if defined (HAVE_RTADV) /* Structure which hold status of router advertisement. */ struct rtadv { @@ -321,7 +317,7 @@ struct rtadv struct thread *ra_read; struct thread *ra_timer; }; -#endif /* RTADV */ +#endif /* HAVE_RTADV */ #ifdef HAVE_NETLINK /* Socket interface to kernel */ @@ -370,9 +366,9 @@ struct zebra_vrf struct list *rid_lo_sorted_list; struct prefix rid_user_assigned; -#if defined (RTADV) +#if defined (HAVE_RTADV) struct rtadv rtadv; -#endif /* RTADV */ +#endif /* HAVE_RTADV */ }; /* diff --git a/zebra/rtadv.c b/zebra/rtadv.c index f5d5b4ade..6b49cf622 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -41,7 +41,7 @@ extern struct zebra_privs_t zserv_privs; -#if defined (HAVE_IPV6) && defined (RTADV) +#if defined (HAVE_IPV6) && defined (HAVE_RTADV) #ifdef OPEN_BSD #include @@ -1813,4 +1813,4 @@ rtadv_cmd_init (void) { /* Empty.*/; } -#endif /* RTADV && HAVE_IPV6 */ +#endif /* HAVE_RTADV && HAVE_IPV6 */ diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 76f98cf2c..160814b20 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -27,7 +27,7 @@ #include "zebra/interface.h" /* NB: RTADV is defined in zebra/interface.h above */ -#ifdef RTADV +#if defined (HAVE_RTADV) /* Router advertisement prefix. */ struct rtadv_prefix @@ -98,7 +98,7 @@ struct nd_opt_homeagent_info { /* Home Agent info */ extern const char *rtadv_pref_strs[]; -#endif /* RTADV */ +#endif /* HAVE_RTADV */ extern void rtadv_init (struct zebra_vrf *); extern void rtadv_terminate (struct zebra_vrf *); From 76764ddcf53fa4840993c395fdf383a47ad61e8e Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 20 Nov 2015 09:05:46 -0500 Subject: [PATCH 0912/1342] isisd, lib: Fix some more compiler warnings A couple compiler warnings snuck in from the last round of work being looked at. This cleans them up Signed-off-by: Donald Sharp --- isisd/isis_bpf.c | 2 ++ lib/log.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index fd65608d7..889b4c309 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -348,6 +348,8 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) return ISIS_WARNING; return ISIS_ERROR; } + + return ISIS_OK; } int diff --git a/lib/log.c b/lib/log.c index e376205df..0914bf840 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1036,7 +1036,7 @@ zlog_hexdump (void *mem, unsigned int len) { if (j >= len) /* end of block, not really printing */ s += sprintf(s, " "); - else if(isprint(((char*)mem)[j])) /* printable char */ + else if(isprint((int)((char*)mem)[j])) /* printable char */ s += sprintf(s, "%c", 0xFF & ((char*)mem)[j]); else /* other char */ From 64e0ac29ddc43bb5b1a2999a8ebedbdff115e3ca Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 18 Nov 2015 16:00:54 +0000 Subject: [PATCH 0913/1342] bgpd: Implicit updates in BGP may require a withdrawal from zebra RIB * J Yu noted a problem with bgpd of routes not having their nexthop updated correctly. Martin Winter pinned this down to the case where a BGP route is updated from one with a valid nexthop to an invalid next-hop, using a test tool. Once the problem occurs, the incorrect route may remain, even after further UPDATEs, so long as the nexthop in the zebra RIB does not match the BGP route's nexthop. Jacqueline Yu then pinned the issue down further to being due to bgpd sending the DELETE for the route to zebra with the new nexthop after a BGP UPDATE updates an existing route, but then is found to be invalid, and zebra not finding the route as it requires a match on all attributes. * bgp_zebra.c: (bgp_zebra_withdraw) When deleting a prefix, we want it gone. Do not send additional matching attributes like the nexthop, which can only cause incorrect non-matches. Acked-by: Donald Sharp --- bgpd/bgp_zebra.c | 46 +++++----------------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e534bee86..186657bd8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -863,18 +863,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (p->family == AF_INET) { struct zapi_ipv4 api; - struct in_addr *nexthop; api.vrf_id = VRF_DEFAULT; api.flags = flags; - nexthop = &info->attr->nexthop; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; - SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; + api.nexthop_num = 0; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; @@ -882,10 +878,9 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u", + zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, - inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])), api.metric); } @@ -897,54 +892,23 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) if (p->family == AF_INET6) { struct zapi_ipv6 api; - unsigned int ifindex; - struct in6_addr *nexthop; - - assert (info->attr->extra); - ifindex = 0; - nexthop = NULL; - - /* Only global address nexthop exists. */ - if (info->attr->extra->mp_nexthop_len == 16) - nexthop = &info->attr->extra->mp_nexthop_global; - - /* If both global and link-local address present. */ - if (info->attr->extra->mp_nexthop_len == 32) - { - nexthop = &info->attr->extra->mp_nexthop_local; - if (info->peer->nexthop.ifp) - ifindex = info->peer->nexthop.ifp->ifindex; - } - - if (nexthop == NULL) - return; - - if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) - if (info->peer->ifname) - ifindex = ifname2ifindex (info->peer->ifname); - api.vrf_id = VRF_DEFAULT; api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; - SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; - SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &ifindex; + api.nexthop_num = 0; + api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; - zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %u", + zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, - inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), api.metric); } From 0d27129ac5fd70b90820e3dde05c085d1a0f63a8 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 19 Nov 2015 07:21:30 -0500 Subject: [PATCH 0914/1342] zebra: Fix non usage of VRF_DEFAULT A vrf_id was being set to 0 instead of VRF_DEFAULT Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0efa88d57..38357ffde 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3247,7 +3247,7 @@ rib_tables_iter_next (rib_tables_iter_t *iter) { case RIB_TABLES_ITER_S_INIT: - iter->vrf_id = 0; + iter->vrf_id = VRF_DEFAULT; iter->afi_safi_ix = -1; /* Fall through */ From eae18d16fefed42af33e63e096a2889b9c70b9cb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 21 Nov 2015 07:55:42 -0500 Subject: [PATCH 0915/1342] zebra: Fix solaris build issue The number of parameters to rib_add_ipv4 has been increased. Submitter of original patch failed to modify solaris code path. Signed-off-by: Donald Sharp --- zebra/rtread_getmsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 5057358aa..891539416 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -92,7 +92,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, &gateway, NULL, 0, VRF_DEFAULT, RT_TABLE_MAIN, - 0, 0, SAFI_UNICAST); + 0, 0, 0, SAFI_UNICAST); } void From a3bc7e9400b214a0f078fdb19596ba54214a1442 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 27 Jan 2016 16:54:45 +0000 Subject: [PATCH 0916/1342] bgpd: Fix VU#270232, VPNv4 NLRI parser memcpys to stack on unchecked length Address CERT vulnerability report VU#270232, memcpy to stack data structure based on length field from packet data whose length field upper-bound was not properly checked. This likely allows BGP peers that are enabled to send Labeled-VPN SAFI routes to Quagga bgpd to remotely exploit Quagga bgpd. Mitigation: Do not enable Labeled-VPN SAFI with untrusted neighbours. Impact: Labeled-VPN SAFI is not enabled by default. * bgp_mplsvpn.c: (bgp_nlri_parse_vpnv4) The prefixlen is checked for lower-bound, but not for upper-bound against received data length. The packet data is then memcpy'd to the stack based on the prefixlen. Extend the prefixlen check to ensure it is within the bound of the NLRI packet data AND the on-stack prefix structure AND the maximum size for the address family. Reported-by: Kostya Kortchinsky This commit a joint effort between: Lou Berger Donald Sharp Paul Jakma / --- bgpd/bgp_mplsvpn.c | 52 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index a72d5edeb..75c90cd77 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -101,6 +101,7 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, pnt = packet->nlri; lim = pnt + packet->length; +#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */ for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ @@ -108,17 +109,38 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, /* Fetch prefix length. */ prefixlen = *pnt++; - p.family = AF_INET; + p.family = afi2family (packet->afi); psize = PSIZE (prefixlen); - - if (prefixlen < 88) - { - zlog_err ("prefix length is less than 88: %d", prefixlen); - return -1; - } - + + /* sanity check against packet data */ + if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8 || (pnt + psize) > lim) + { + zlog_err ("prefix length (%d) is less than 88" + " or larger than received (%u)", + prefixlen, (uint)(lim-pnt)); + return -1; + } + + /* sanity check against storage for the IP address portion */ + if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u)) + { + zlog_err ("prefix length (%d) exceeds prefix storage (%zu)", + prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u)); + return -1; + } + + /* Sanity check against max bitlen of the address family */ + if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p)) + { + zlog_err ("prefix length (%d) exceeds family (%u) max byte length (%u)", + prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, + p.family, prefix_blen (&p)); + return -1; + + } + /* Copyr label to prefix. */ - tagpnt = pnt;; + tagpnt = pnt; /* Copy routing distinguisher to rd. */ memcpy (&prd.val, pnt + 3, 8); @@ -137,8 +159,9 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, return -1; } - p.prefixlen = prefixlen - 88; - memcpy (&p.u.prefix, pnt + 11, psize - 11); + p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8; + memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, + psize - VPN_PREFIXLEN_MIN_BYTES); #if 0 if (type == RD_TYPE_AS) @@ -149,9 +172,6 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); #endif /* 0 */ - if (pnt + psize > lim) - return -1; - if (attr) bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); @@ -159,12 +179,12 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } - /* Packet length consistency check. */ if (pnt != lim) return -1; - + return 0; +#undef VPN_PREFIXLEN_MIN_BYTES } int From cc216b7978b038667626afd3f70dda8f70c46e4e Mon Sep 17 00:00:00 2001 From: Gautam Kumar Date: Mon, 26 Oct 2015 13:22:12 -0700 Subject: [PATCH 0917/1342] vtysh: When the config file is close to the boundry of size of buffer vtysh hangs. --- vtysh/vtysh.c | 177 ++++++++++++++++++++++---------------------------- 1 file changed, 77 insertions(+), 100 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b55c6719b..2703bb99f 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -87,9 +87,9 @@ vclient_close (struct vtysh_client *vclient) /* Following filled with debug code to trace a problematic condition * under load - it SHOULD handle it. */ -#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): " +#define ERR_WHERE_STRING "vtysh(): vtysh_client_execute(): " static int -vtysh_client_config (struct vtysh_client *vclient, char *line) +vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) { int ret; char *buf; @@ -100,6 +100,7 @@ vtysh_client_config (struct vtysh_client *vclient, char *line) int nbytes; int i; int readln; + int numnulls = 0; if (vclient->fd < 0) return CMD_SUCCESS; @@ -145,111 +146,87 @@ vtysh_client_config (struct vtysh_client *vclient, char *line) XFREE(MTYPE_TMP, buf); return CMD_SUCCESS; } + /* If we have already seen 3 nulls, then current byte is ret code */ + if ((numnulls == 3) && (nbytes == 1)) + { + ret = pbuf[0]; + break; + } pbuf[nbytes] = '\0'; - if (nbytes >= 4) - { - i = nbytes - 4; - if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0') - { - ret = pbuf[i + 3]; - break; - } - } - pbuf += nbytes; - - /* See if a line exists in buffer, if so parse and consume it, and - * reset read position. */ - if ((eoln = strrchr(buf, '\n')) == NULL) - continue; - - if (eoln >= ((buf + bufsz) - 1)) - { - fprintf (stderr, ERR_WHERE_STRING \ - "warning - eoln beyond buffer end.\n"); - } - vtysh_config_parse(buf); - - eoln++; - left = (size_t)(buf + bufsz - eoln); - memmove(buf, eoln, left); - buf[bufsz-1] = '\0'; - pbuf = buf + strlen(buf); + /* If the config needs to be written in file or stdout */ + if (fp) + { + fputs(pbuf, fp); + fflush (fp); + } + + /* At max look last four bytes */ + if (nbytes >= 4) + { + i = nbytes - 4; + numnulls = 0; + } + else + i = 0; + + /* Count the numnulls */ + while (i < nbytes && numnulls <3) + { + if (pbuf[i++] == '\0') + numnulls++; + else + numnulls = 0; + } + /* We might have seen 3 consecutive nulls so store the ret code before updating pbuf*/ + ret = pbuf[nbytes-1]; + pbuf += nbytes; + + /* See if a line exists in buffer, if so parse and consume it, and + * reset read position. If 3 nulls has been encountered consume the buffer before + * next read. + */ + if (((eoln = strrchr(buf, '\n')) == NULL) && (numnulls<3)) + continue; + + if (eoln >= ((buf + bufsz) - 1)) + { + fprintf (stderr, ERR_WHERE_STRING \ + "warning - eoln beyond buffer end.\n"); + } + + /* If the config needs parsing, consume it */ + if(!fp) + vtysh_config_parse(buf); + + eoln++; + left = (size_t)(buf + bufsz - eoln); + /* + * This check is required since when a config line split between two consecutive reads, + * then buf will have first half of config line and current read will bring rest of the + * line. So in this case eoln will be 1 here, hence calculation of left will be wrong. + * In this case we don't need to do memmove, because we have already seen 3 nulls. + */ + if(left < bufsz) + memmove(buf, eoln, left); + + buf[bufsz-1] = '\0'; + pbuf = buf + strlen(buf); + /* got 3 or more trailing NULs? */ + if ((numnulls >=3) && (i < nbytes)) + { + break; + } } - /* Parse anything left in the buffer. */ - - vtysh_config_parse (buf); + if(!fp) + vtysh_config_parse (buf); XFREE(MTYPE_TMP, buf); return ret; } - -static int -vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) -{ - int ret; - char buf[1001]; - int nbytes; - int i; - int numnulls = 0; - - if (vclient->fd < 0) - return CMD_SUCCESS; - - ret = write (vclient->fd, line, strlen (line) + 1); - if (ret <= 0) - { - vclient_close (vclient); - return CMD_SUCCESS; - } - - while (1) - { - nbytes = read (vclient->fd, buf, sizeof(buf)-1); - - if (nbytes <= 0 && errno != EINTR) - { - vclient_close (vclient); - return CMD_SUCCESS; - } - - if (nbytes > 0) - { - if ((numnulls == 3) && (nbytes == 1)) - return buf[0]; - - buf[nbytes] = '\0'; - fputs (buf, fp); - fflush (fp); - - /* check for trailling \0\0\0, - * even if split across reads - * (see lib/vty.c::vtysh_read) - */ - if (nbytes >= 4) - { - i = nbytes-4; - numnulls = 0; - } - else - i = 0; - - while (i < nbytes && numnulls < 3) - { - if (buf[i++] == '\0') - numnulls++; - else - numnulls = 0; - } - - /* got 3 or more trailing NULs? */ - if ((numnulls >= 3) && (i < nbytes)) - return (buf[nbytes-1]); - } - } -} + void vtysh_pager_init (void) @@ -1735,7 +1712,7 @@ DEFUN (vtysh_write_terminal, vty_out (vty, "!%s", VTY_NEWLINE); for (i = 0; i < array_size(vtysh_client); i++) - vtysh_client_config (&vtysh_client[i], line); + vtysh_client_execute (&vtysh_client[i], line, NULL); /* Integrate vtysh specific configuration. */ vtysh_config_write (); @@ -1836,7 +1813,7 @@ write_config_integrated(void) } for (i = 0; i < array_size(vtysh_client); i++) - vtysh_client_config (&vtysh_client[i], line); + vtysh_client_execute (&vtysh_client[i], line, NULL); vtysh_config_dump (fp); From 68ec424eb8557f86d08fcb7ab3c5366cbf3eca0e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 25 Nov 2015 17:14:34 +0000 Subject: [PATCH 0918/1342] bgpd: OPEN parse errors should send OPEN_ERR and UNSPECIFIC subcode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CEASE NOTIFICATION for OPEN parsing errors seems, to my reading of RFC4271 §6.2 to be incorrect. * bgp_packet.c: (bgp_open_receive) OPEN/UNACEP_HOLDTIME is not an appropriate error subcode if bgp_open_option_parse returns an error. Set it to "Unspecific". Where a more specific subcode is appropriate, then lower level should send that. * bgp_open.c: (bgp_open_option_parse) Malformed OPENs should result in NOTIFICATION with OPEN error, and OPEN/UNSPECIFIC sub-code - not CEASE. (bgp_capability_{parse,orf_entry}) ditto. * bgpd.h: Add BGP_NOTIFY_OPEN_UNSPECIFIC for 0. Note that IANA lists 0 as reserved in the OPEN error sub-code registry, but RFC4271 page 32 says 0 is the "Unspecific" OPEN error subcode. Have emailed IANA, they says it's a known errate to 4271 under review. Some inspiration from Cumulus' bgpd-capability-cleanup.patch, though v different result. --- bgpd/bgp_open.c | 15 +++++++++------ bgpd/bgp_packet.c | 2 +- bgpd/bgpd.h | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index b9d6e93f3..727388283 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -235,7 +235,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", peer->host, hdr->length, entry.num); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } @@ -469,7 +469,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, if (stream_get_getp(s) + 2 > end) { zlog_info ("%s Capability length error (< header)", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } @@ -481,7 +481,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, if (start + caphdr.length > end) { zlog_info ("%s Capability length error (< length)", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } @@ -511,7 +511,8 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_minsizes[caphdr.code]); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } /* we deliberately ignore unknown codes, see below */ @@ -727,7 +728,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) if (STREAM_READABLE(s) < 2) { zlog_info ("%s Option length error", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } @@ -739,7 +741,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) if (STREAM_READABLE (s) < opt_length) { zlog_info ("%s Option length error", peer->host); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index a90e56b50..0639f4ddd 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1545,7 +1545,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); + BGP_NOTIFY_OPEN_UNSPECIFIC); return ret; } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d4c8dbd8a..2c4fb2096 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -672,6 +672,7 @@ struct bgp_nlri #define BGP_NOTIFY_HEADER_MAX 4 /* BGP_NOTIFY_OPEN_ERR sub codes. */ +#define BGP_NOTIFY_OPEN_UNSPECIFIC 0 #define BGP_NOTIFY_OPEN_UNSUP_VERSION 1 #define BGP_NOTIFY_OPEN_BAD_PEER_AS 2 #define BGP_NOTIFY_OPEN_BAD_BGP_IDENT 3 From 4078f2eb7a3a94ddb30cfd8b76b054e790aab524 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 25 Nov 2015 17:14:35 +0000 Subject: [PATCH 0919/1342] bgpd: Check capability falls on right multiple of size, where possible. * bgp_open.c: (cap_modsizes) Table of multiple a capability's data size should fall on, if applicable. (bgp_capability_parse) Check the header lengthcap_modsizes should fall on. Inspiration from Cumulus bgpd-capability-cleanup.patch patch, with a slightly different approach. Acked-by: Donald Sharp --- bgpd/bgp_open.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 727388283..ff2ae08dd 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -442,6 +442,23 @@ static const size_t cap_minsizes[] = [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry), }; +/* value the capability must be a multiple of. + * 0-data capabilities won't be checked against this. + * Other capabilities whose data doesn't fall on convenient boundaries for this + * table should be set to 1. + */ +static const size_t cap_modsizes[] = +{ + [CAPABILITY_CODE_MP] = 4, + [CAPABILITY_CODE_REFRESH] = 1, + [CAPABILITY_CODE_ORF] = 1, + [CAPABILITY_CODE_RESTART] = 1, + [CAPABILITY_CODE_AS4] = 4, + [CAPABILITY_CODE_DYNAMIC] = 1, + [CAPABILITY_CODE_REFRESH_OLD] = 1, + [CAPABILITY_CODE_ORF_OLD] = 1, +}; + /** * Parse given capability. * XXX: This is reading into a stream, but not using stream API @@ -515,6 +532,19 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } + if (caphdr.length + && caphdr.length % cap_modsizes[caphdr.code] != 0) + { + zlog_info ("%s %s Capability length error: got %u," + " expected a multiple of %u", + peer->host, + LOOKUP (capcode_str, caphdr.code), + caphdr.length, + (unsigned) cap_modsizes[caphdr.code]); + bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSPECIFIC); + return -1; + } /* we deliberately ignore unknown codes, see below */ default: break; From 321d4130a615445d0f49f41c909c92d5401fd5ff Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 25 Nov 2015 17:14:36 +0000 Subject: [PATCH 0920/1342] tests: add more AS4 capability tests + little fixes for couple of GR test cases. Reviewed-by: Donald Sharp --- tests/bgp_capability_test.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index 96f18f01f..3cfc1987a 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -311,7 +311,16 @@ static struct test_segment misc_segments[] = { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, /* AS: 2882400018 */ 6, SHOULD_PARSE, 2882400018, }, - /* 20 */ + { "AS4", + "AS4 capability: short", + { 0x41, 0x4, 0xab, 0xcd, 0xef }, /* AS: 2882400018 */ + 5, SHOULD_ERR, + }, + { "AS4", + "AS4 capability: long", + { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12, 0x12 }, + 7, SHOULD_ERR, 2882400018, + }, { "GR", "GR capability", { /* hdr */ CAPABILITY_CODE_RESTART, 0xe, @@ -328,7 +337,6 @@ static struct test_segment misc_segments[] = }, 16, SHOULD_PARSE, }, - /* 21 */ { "GR-short", "GR capability, but header length too short", { /* hdr */ 0x40, 0xa, @@ -343,9 +351,8 @@ static struct test_segment misc_segments[] = /* safi */ 0x2, /* flags */ 0x1, }, - 16, SHOULD_PARSE, + 15 /* array is 16 though */, SHOULD_ERR, }, - /* 22 */ { "GR-long", "GR capability, but header length too long", { /* hdr */ 0x40, 0xf, @@ -358,6 +365,7 @@ static struct test_segment misc_segments[] = /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, + /* flags */ 0x01, }, 16, SHOULD_ERR, }, From 91b9e8547a7c5697d5d7481f9476778077024019 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 1 Dec 2015 14:32:11 +0000 Subject: [PATCH 0921/1342] bgpd: bgp_scan shouldn't queue up route_nodes with no routes for processing * bgp_nexthop.c: (bgp_scan) There is little point queueing an rn with no routing information for processing. * bgp_route.c: (bgp_process) Do nothing on rn's with no routes. Add an assert for now, to try catch any other cases, but prob should be removed. (bgp_best_selection) rn with no routes == finish early. --- bgpd/bgp_nexthop.c | 3 ++- bgpd/bgp_route.c | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 145a1d883..607d99b11 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -496,7 +496,8 @@ bgp_scan (afi_t afi, safi_t safi) afi, SAFI_UNICAST); } } - bgp_process (bgp, rn, afi, SAFI_UNICAST); + if (rn->info) + bgp_process (bgp, rn, afi, SAFI_UNICAST); } /* Flash old cache. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 316fa5a16..e0e14eca7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1336,7 +1336,18 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info *nextri = NULL; int paths_eq, do_mpath; struct list mp_list; - + + result->old = result->new = NULL; + + if (rn->info == NULL) + { + char buf[PREFIX_STRLEN]; + zlog_warn ("%s: Called for route_node %s with no routing entries!", + __func__, + prefix2str (&(bgp_node_to_rnode (rn)->p), buf, sizeof(buf))); + return; + } + bgp_mp_list_init (&mp_list); do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS || mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS); @@ -1455,7 +1466,6 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, if (do_mpath && paths_eq) bgp_mp_list_add (&mp_list, ri); } - if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); @@ -1712,6 +1722,19 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) if (CHECK_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED)) return; + if (rn->info == NULL) + { + /* XXX: Perhaps remove before next release, after we've flushed out + * any obvious cases + */ + assert (rn->info != NULL); + char buf[PREFIX_STRLEN]; + zlog_warn ("%s: Called for route_node %s with no routing entries!", + __func__, + prefix2str (&(bgp_node_to_rnode (rn)->p), buf, sizeof(buf))); + return; + } + if ( (bm->process_main_queue == NULL) || (bm->process_rsclient_queue == NULL) ) bgp_process_queue_init (); From 6d4742bef722e6fab45fb6eb22ed2c7b7570a2e6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 25 Nov 2015 17:14:37 +0000 Subject: [PATCH 0922/1342] bgpd: make bgp_info_cmp and multiple-path decision logic more regular * bgp_route.c: (bgp_info_cmp) This function is supposed to return a preference between the given paths, and does so as binary either or. When mpath was added, the binary return value was left as is and instead an out parameter 'paths_eq' was added to indicate the mpath-equality case. It's a bit odd, as is the resulting logic in the caller. Regularise things again by making the function return a strcmp like trinary return value of -1,0,1. Get rid of the mpath specific arguments, but pass in afi/safi as part of the general context - that plus the (struct bgp *) is enough to access configuration. Update the return values. The mpath check was testing the IGP metric for equality, even though previous to the mpath changes (and consistent with the behaviour of all the other tests bar the end), equality results in continuing through to the next comparison. Just go back to the previous way - each test finds a preference to return, or continues on to let further tests have a go. (bgp_best_selection) Get rid of the (struct bgp_maxpaths_cfg *) arg, we can't add state for every optional feature to the argument list - they have to look it up as needed. Do pass through the very general afi/safi context though (saves several lookups through the route_node). Adjust for the new trinary bgp_info_cmp return value and updated args. Do the mpath clearing/accumulation in one place, in each loop. Call to bgp_info_mpath_update similarly gets updated, as there's no cfg to pass. (bgp_process_{rsclient,main}) match bgp_best_selection changes. * bgp_mpath.c: (bgp_mpath_is_configured_sort) Helper for whether mpath is enabled by peer sort. (bgp_mpath_is_configured) ditto, generally. (bgp_info_mpath_update) caller no longer has the cfg to pass in, look it up. * bgp_mpath.h: Export the above and Match .c changes. Requires commit: "bgpd: bgp_scan shouldn't queue up route_nodes with no routes for processing" Signed-off-by: Donald Sharp --- bgpd/bgp_mpath.c | 32 +++++++- bgpd/bgp_mpath.h | 4 +- bgpd/bgp_route.c | 169 ++++++++++++++++++++--------------------- tests/bgp_mpath_test.c | 22 ++++-- 4 files changed, 129 insertions(+), 98 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 7999d16b6..98b75b67d 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -39,6 +39,33 @@ #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_mpath.h" +bool +bgp_mpath_is_configured_sort (struct bgp *bgp, bgp_peer_sort_t sort, + afi_t afi, safi_t safi) +{ + struct bgp_maxpaths_cfg *cfg = &bgp->maxpaths[afi][safi]; + + /* XXX: BGP_DEFAULT_MAXPATHS is 1, and this test only seems to make sense + * if if it stays 1, so not sure the DEFAULT define is that useful. + */ + switch (sort) + { + case BGP_PEER_IBGP: + return cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS; + case BGP_PEER_EBGP: + return cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS; + default: + return false; + } +} + +bool +bgp_mpath_is_configured (struct bgp *bgp, afi_t afi, safi_t safi) +{ + return bgp_mpath_is_configured_sort (bgp, BGP_PEER_IBGP, afi, safi) + || bgp_mpath_is_configured_sort (bgp, BGP_PEER_EBGP, afi, safi); +} + /* * bgp_maximum_paths_set * @@ -395,7 +422,7 @@ bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr) void bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, struct bgp_info *old_best, struct list *mp_list, - struct bgp_maxpaths_cfg *mpath_cfg) + afi_t afi, safi_t safi) { u_int16_t maxpaths, mpath_count, old_mpath_count; struct listnode *mp_node, *mp_next_node; @@ -410,8 +437,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, old_mpath_count = 0; prev_mpath = new_best; mp_node = listhead (mp_list); + struct bgp_maxpaths_cfg *mpath_cfg; debug = BGP_DEBUG (events, EVENTS); + mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi]; + if (debug) prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf)); diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index 37b9ac8b7..2a84d5e1e 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -51,6 +51,8 @@ struct bgp_info_mpath /* Functions to support maximum-paths configuration */ extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t); extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); +bool bgp_mpath_is_configured_sort (struct bgp *, bgp_peer_sort_t, afi_t, safi_t); +bool bgp_mpath_is_configured (struct bgp *, afi_t, safi_t); /* Functions used by bgp_best_selection to record current * multipath selections @@ -61,7 +63,7 @@ extern void bgp_mp_list_add (struct list *, struct bgp_info *); extern void bgp_mp_dmed_deselect (struct bgp_info *); extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *, struct bgp_info *, struct list *, - struct bgp_maxpaths_cfg *); + afi_t, safi_t); extern void bgp_info_mpath_aggregate_update (struct bgp_info *, struct bgp_info *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e0e14eca7..8aa6daa8e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -321,10 +321,12 @@ bgp_med_value (struct attr *attr, struct bgp *bgp) } } -/* Compare two bgp route entity. br is preferable then return 1. */ +/* Compare two bgp route entity. Return -1 if new is preferred, 1 if exist + * is preferred, or 0 if they are the same (usually will only occur if + * multipath is enabled */ static int bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, - int *paths_eq) + afi_t afi, safi_t safi) { struct attr *newattr, *existattr; struct attr_extra *newattre, *existattre; @@ -345,13 +347,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, int confed_as_route; int ret; - *paths_eq = 0; - /* 0. Null check. */ if (new == NULL) - return 0; - if (exist == NULL) return 1; + if (exist == NULL) + return -1; newattr = new->attr; existattr = exist->attr; @@ -367,9 +367,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, exist_weight = existattre->weight; if (new_weight > exist_weight) - return 1; + return -1; if (new_weight < exist_weight) - return 0; + return 1; /* 2. Local preference check. */ new_pref = exist_pref = bgp->default_local_pref; @@ -380,9 +380,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, exist_pref = existattr->local_pref; if (new_pref > exist_pref) - return 1; + return -1; if (new_pref < exist_pref) - return 0; + return 1; /* 3. Local route check. We prefer: * - BGP_ROUTE_STATIC @@ -390,9 +390,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, * - BGP_ROUTE_REDISTRIBUTE */ if (! (new->sub_type == BGP_ROUTE_NORMAL)) - return 1; + return -1; if (! (exist->sub_type == BGP_ROUTE_NORMAL)) - return 0; + return 1; /* 4. AS path length check. */ if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) @@ -408,26 +408,26 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, aspath_hops += aspath_count_confeds (newattr->aspath); if ( aspath_hops < (exist_hops + exist_confeds)) - return 1; + return -1; if ( aspath_hops > (exist_hops + exist_confeds)) - return 0; + return 1; } else { int newhops = aspath_count_hops (newattr->aspath); if (newhops < exist_hops) - return 1; + return -1; if (newhops > exist_hops) - return 0; + return 1; } } /* 5. Origin check. */ if (newattr->origin < existattr->origin) - return 1; + return -1; if (newattr->origin > existattr->origin) - return 0; + return 1; /* 6. MED check. */ internal_as_route = (aspath_count_hops (newattr->aspath) == 0 @@ -448,9 +448,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, exist_med = bgp_med_value (exist->attr, bgp); if (new_med < exist_med) - return 1; + return -1; if (new_med > exist_med) - return 0; + return 1; } /* 7. Peer type check. */ @@ -459,10 +459,10 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, if (new_sort == BGP_PEER_EBGP && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) - return 1; + return -1; if (exist_sort == BGP_PEER_EBGP && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) - return 0; + return 1; /* 8. IGP metric check. */ newm = existm = 0; @@ -473,41 +473,32 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, existm = exist->extra->igpmetric; if (newm < existm) - ret = 1; + return -1; if (newm > existm) - ret = 0; + return 1; /* 9. Maximum path check. */ - if (newm == existm) + if (bgp_mpath_is_configured (bgp, afi, safi)) { if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { - - /* - * For the two paths, all comparison steps till IGP metric - * have succeeded - including AS_PATH hop count. Since 'bgp - * bestpath as-path multipath-relax' knob is on, we don't need - * an exact match of AS_PATH. Thus, mark the paths are equal. - * That will trigger both these paths to get into the multipath - * array. - */ - *paths_eq = 1; + /* + * For the two paths, all comparison steps till IGP metric + * have succeeded - including AS_PATH hop count. Since 'bgp + * bestpath as-path multipath-relax' knob is on, we don't need + * an exact match of AS_PATH. Thus, mark the paths are equal. + * That will trigger both these paths to get into the multipath + * array. + */ + return 0; } else if (new->peer->sort == BGP_PEER_IBGP) - { - if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) - *paths_eq = 1; - } + { + if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) + return 0; + } else if (new->peer->as == exist->peer->as) - *paths_eq = 1; - } - else - { - /* - * TODO: If unequal cost ibgp multipath is enabled we can - * mark the paths as equal here instead of returning - */ - return ret; + return 0; } /* 10. If both paths are external, prefer the path that was received @@ -519,9 +510,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, && exist_sort == BGP_PEER_EBGP) { if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) - return 1; + return -1; if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED)) - return 0; + return 1; } /* 11. Router-ID comparision. */ @@ -539,9 +530,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, exist_id.s_addr = exist->peer->remote_id.s_addr; if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr)) - return 1; + return -1; if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr)) - return 0; + return 1; /* 12. Cluster length comparision. */ new_cluster = exist_cluster = 0; @@ -552,32 +543,32 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, exist_cluster = existattre->cluster->length; if (new_cluster < exist_cluster) - return 1; + return -1; if (new_cluster > exist_cluster) - return 0; + return 1; /* 13. Neighbor address comparision. */ /* Do this only if neither path is "stale" as stale paths do not have * valid peer information (as the connection may or may not be up). */ if (CHECK_FLAG (exist->flags, BGP_INFO_STALE)) - return 1; + return -1; if (CHECK_FLAG (new->flags, BGP_INFO_STALE)) - return 0; + return 1; /* locally configured routes to advertise do not have su_remote */ if (new->peer->su_remote == NULL) - return 0; - if (exist->peer->su_remote == NULL) return 1; + if (exist->peer->su_remote == NULL) + return -1; ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); if (ret == 1) - return 0; - if (ret == -1) return 1; + if (ret == -1) + return -1; - return 1; + return -1; } static enum filter_type @@ -1325,8 +1316,8 @@ struct bgp_info_pair static void bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, - struct bgp_maxpaths_cfg *mpath_cfg, - struct bgp_info_pair *result) + struct bgp_info_pair *result, + afi_t afi, safi_t safi) { struct bgp_info *new_select; struct bgp_info *old_select; @@ -1334,7 +1325,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info *ri1; struct bgp_info *ri2; struct bgp_info *nextri = NULL; - int paths_eq, do_mpath; + int cmpret, do_mpath; struct list mp_list; result->old = result->new = NULL; @@ -1349,8 +1340,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, } bgp_mp_list_init (&mp_list); - do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS || - mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS); + do_mpath = bgp_mpath_is_configured (bgp, afi, safi); /* bgp deterministic-med */ new_select = NULL; @@ -1388,19 +1378,21 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, { if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED)) old_select = ri2; - if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq)) + if ((cmpret = bgp_info_cmp (bgp, ri2, new_select, afi, safi)) + == -1) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; - if (do_mpath && !paths_eq) - { - bgp_mp_list_clear (&mp_list); - bgp_mp_list_add (&mp_list, ri2); - } } - if (do_mpath && paths_eq) - bgp_mp_list_add (&mp_list, ri2); + if (do_mpath) + { + if (cmpret != 0) + bgp_mp_list_clear (&mp_list); + + if (cmpret == 0 || cmpret == -1) + bgp_mp_list_add (&mp_list, ri2); + } bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK); } @@ -1408,7 +1400,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK); bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED); - bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, afi, safi); bgp_mp_list_clear (&mp_list); } @@ -1447,28 +1439,29 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED); - if (bgp_info_cmp (bgp, ri, new_select, &paths_eq)) + if ((cmpret = bgp_info_cmp (bgp, ri, new_select, afi, safi)) == -1) { if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (new_select); new_select = ri; - - if (do_mpath && !paths_eq) - { - bgp_mp_list_clear (&mp_list); - bgp_mp_list_add (&mp_list, ri); - } } - else if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) + else if (cmpret == 1 && do_mpath + && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (ri); - if (do_mpath && paths_eq) - bgp_mp_list_add (&mp_list, ri); + if (do_mpath) + { + if (cmpret != 0) + bgp_mp_list_clear (&mp_list); + + if (cmpret == 0 || cmpret == -1) + bgp_mp_list_add (&mp_list, ri); + } } if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) - bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, afi, safi); bgp_info_mpath_aggregate_update (new_select, old_select); bgp_mp_list_clear (&mp_list); @@ -1552,7 +1545,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data) struct peer *rsclient = bgp_node_table (rn)->owner; /* Best path selection. */ - bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); + bgp_best_selection (bgp, rn, &old_and_new, afi, safi); new_select = old_and_new.new; old_select = old_and_new.old; @@ -1615,7 +1608,7 @@ bgp_process_main (struct work_queue *wq, void *data) struct peer *peer; /* Best path selection. */ - bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); + bgp_best_selection (bgp, rn, &old_and_new, afi, safi); old_select = old_and_new.old; new_select = old_and_new.new; diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index ed54d9c11..dbbf0dd66 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -194,12 +194,15 @@ testcase_t test_bgp_cfg_maximum_paths = { /*========================================================= * Testcase for bgp_mp_list */ + +struct bgp test_mp_bgp; + struct peer test_mp_list_peer[] = { - { .local_as = 1, .as = 2 }, - { .local_as = 1, .as = 2 }, - { .local_as = 1, .as = 2 }, - { .local_as = 1, .as = 2 }, - { .local_as = 1, .as = 2 }, + { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, + { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, + { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, + { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, + { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, }; int test_mp_list_peer_count = sizeof (test_mp_list_peer)/ sizeof (struct peer); struct attr test_mp_list_attr[4]; @@ -305,7 +308,10 @@ run_bgp_info_mpath_update (testcase_t *t) { struct bgp_info *new_best, *old_best, *mpath; struct list mp_list; - struct bgp_maxpaths_cfg mp_cfg = { 3, 3 }; + + test_mp_bgp.maxpaths[AFI_IP][SAFI_UNICAST].maxpaths_ebgp = 3; + test_mp_bgp.maxpaths[AFI_IP][SAFI_UNICAST].maxpaths_ibgp = 3; + int test_result = TEST_PASSED; bgp_mp_list_init (&mp_list); bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); @@ -314,7 +320,7 @@ run_bgp_info_mpath_update (testcase_t *t) bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[3]; old_best = NULL; - bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, &mp_cfg); + bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, AFI_IP, SAFI_UNICAST); bgp_mp_list_clear (&mp_list); EXPECT_TRUE (bgp_info_mpath_count (new_best) == 2, test_result); mpath = bgp_info_mpath_first (new_best); @@ -328,7 +334,7 @@ run_bgp_info_mpath_update (testcase_t *t) bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[0]; old_best = &test_mp_list_info[3]; - bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, &mp_cfg); + bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, AFI_IP, SAFI_UNICAST); bgp_mp_list_clear (&mp_list); EXPECT_TRUE (bgp_info_mpath_count (new_best) == 1, test_result); mpath = bgp_info_mpath_first (new_best); From d5062d218994885710fe02f516f0c06025b4fc9a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 2 Dec 2015 16:47:43 +0000 Subject: [PATCH 0923/1342] docs: Update bgpd docs, inc. on decision process, and with a section on MED. * bgpd.texi: Document the -l argument. Update the 'BGP decision process' table to reflect what /actually/ is implemented. Add docs on 'compare-routerid' in the bestpath section. Add a section on MED, to highlight the issues it has by default, and to highlight that it is terminally broken for its original purpose in many modern iBGP topologies. Mention the potential workarounds and fixes. * routemap.texi: set an anchor on 'set metric' so bgpd.texi can reference it. --- doc/bgpd.texi | 373 +++++++++++++++++++++++++++++++++++++++++++++- doc/routemap.texi | 1 + 2 files changed, 368 insertions(+), 6 deletions(-) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 5eb08510c..1513f7a30 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -1,6 +1,8 @@ @c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} +@c Portions: +@c Copyright @copyright{} 2015 Hewlett Packard Enterprise Development LP @c See file quagga.texi for copying conditions. @node BGP @chapter BGP @@ -18,6 +20,7 @@ BGP-4. @menu * Starting BGP:: * BGP router:: +* BGP MED:: * BGP network:: * BGP Peer:: * BGP Peer Group:: @@ -53,6 +56,13 @@ Set the bgp protocol's port number. @item -r @itemx --retain When program terminates, retain BGP routes added by zebra. + +@item -l +@itemx --listenon +Specify a specific IP address for bgpd to listen on, rather than its +default of INADDR_ANY / IN6ADDR_ANY. This can be useful to constrain bgpd +to an internal address, or to run multiple bgpd processes on one host. + @end table @node BGP router @@ -104,18 +114,65 @@ This command set distance value to @node BGP decision process @subsection BGP decision process +The decision process Quagga BGP uses to select routes is as follows: + @table @asis @item 1. Weight check +prefer higher local weight routes to lower routes. -@item 2. Local preference check. +@item 2. Local preference check +prefer higher local preference routes to lower. + +@item 3. Local route check +Prefer local routes (statics, aggregates, redistributed) to received routes. + +@item 4. AS path length check +Prefer shortest hop-count AS_PATHs. + +@item 5. Origin check +Prefer the lowest origin type route. That is, prefer IGP origin routes to +EGP, to Incomplete routes. + +@item 6. MED check +Where routes with a MED were received from the same AS, +prefer the route with the lowest MED. @xref{BGP MED}. + +@item 7. External check +Prefer the route received from an external, eBGP peer +over routes received from other types of peers. + +@item 8. IGP cost check +Prefer the route with the lower IGP cost. -@item 3. Local route check. +@item 9. Multi-path check +If multi-pathing is enabled, then check whether +the routes not yet distinguished in preference may be considered equal. If +@ref{bgp bestpath as-path multipath-relax} is set, all such routes are +considered equal, otherwise routes received via iBGP with identical AS_PATHs +or routes received from eBGP neighbours in the same AS are considered equal. -@item 4. AS path length check. +@item 10 Already-selected external check -@item 5. Origin check. +Where both routes were received from eBGP peers, then prefer the route which +is already selected. Note that this check is not applied if @ref{bgp +bestpath compare-routerid} is configured. This check can prevent some cases +of oscillation. + +@item 11. Router-ID check +Prefer the route with the lowest @w{router-ID}. If the +route has an @w{ORIGINATOR_ID} attribute, through iBGP reflection, then that +router ID is used, otherwise the @w{router-ID} of the peer the route was +received from is used. + +@item 12. Cluster-List length check +The route with the shortest cluster-list +length is used. The cluster-list reflects the iBGP reflection path the +route has taken. + +@item 13. Peer address +Prefer the route received from the peer with the higher +transport layer address, as a last-resort tie-breaker. -@item 6. MED check. @end table @deffn {BGP} {bgp bestpath as-path confed} {} @@ -125,11 +182,36 @@ decision process. @end deffn @deffn {BGP} {bgp bestpath as-path multipath-relax} {} +@anchor{bgp bestpath as-path multipath-relax} This command specifies that BGP decision process should consider paths of equal AS_PATH length candidates for multipath computation. Without the knob, the entire AS_PATH must match for multipath computation. @end deffn +@deffn {BGP} {bgp bestpath compare-routerid} {} +@anchor{bgp bestpath compare-routerid} + +Ensure that when comparing routes where both are equal on most metrics, +including local-pref, AS_PATH length, IGP cost, MED, that the tie is broken +based on router-ID. + +If this option is enabled, then the already-selected check, where +already selected eBGP routes are preferred, is skipped. + +If a route has an @w{ORIGINATOR_ID} attribute because it has been reflected, +that @w{ORIGINATOR_ID} will be used. Otherwise, the router-ID of the peer the +route was received from will be used. + +The advantage of this is that the route-selection (at this point) will be +more deterministic. The disadvantage is that a few or even one lowest-ID +router may attract all trafic to otherwise-equal paths because of this +check. It may increase the possibility of MED or IGP oscillation, unless +other measures were taken to avoid these. The exact behaviour will be +sensitive to the iBGP and reflection topology. + +@end deffn + + @node BGP route flap dampening @subsection BGP route flap dampening @@ -151,6 +233,285 @@ The route-flap damping algorithm is compatible with @cite{RFC2439}. The use of t is not recommended nowadays, see @uref{http://www.ripe.net/ripe/docs/ripe-378,,RIPE-378}. @end deffn +@node BGP MED +@section BGP MED + +The BGP MED (Multi_Exit_Discriminator) attribute has properties which can +cause subtle convergence problems in BGP. These properties and problems +have proven to be hard to understand, at least historically, and may still +not be widely understood. The following attempts to collect together and +present what is known about MED, to help operators and Quagga users in +designing and configuring their networks. + +The BGP @acronym{MED, Multi_Exit_Discriminator} attribute is intended to +allow one AS to indicate its preferences for its ingress points to another +AS. The MED attribute will not be propagated on to another AS by the +receiving AS - it is `non-transitive' in the BGP sense. + +E.g., if AS X and AS Y have 2 different BGP peering points, then AS X +might set a MED of 100 on routes advertised at one and a MED of 200 at the +other. When AS Y selects between otherwise equal routes to or via +AS X, AS Y should prefer to take the path via the lower MED peering of 100 with +AS X. Setting the MED allows an AS to influence the routing taken to it +within another, neighbouring AS. + +In this use of MED it is not really meaningful to compare the MED value on +routes where the next AS on the paths differs. E.g., if AS Y also had a +route for some destination via AS Z in addition to the routes from AS X, and +AS Z had also set a MED, it wouldn't make sense for AS Y to compare AS Z's +MED values to those of AS X. The MED values have been set by different +administrators, with different frames of reference. + +The default behaviour of BGP therefore is to not compare MED values across +routes received from different neighbouring ASes. In Quagga this is done by +comparing the neighbouring, left-most AS in the received AS_PATHs of the +routes and only comparing MED if those are the same. + +@c TeXInfo uses the old, non-UTF-8 capable, pdftex, and so +@c doesn't render TeX the unicode precedes character correctly in PDF, etc. +@c Using a TeX code on the other hand doesn't work for non-TeX outputs +@c (plaintext, e.g.). So, use an output-conditional macro. + +@iftex +@macro mprec{} +@math{\\prec} +@end macro +@end iftex + +@ifnottex +@macro mprec{} +@math{≺} +@end macro +@end ifnottex + +Unfortunately, this behaviour of MED, of sometimes being compared across +routes and sometimes not, depending on the properties of those other routes, +means MED can cause the order of preference over all the routes to be +undefined. That is, given routes A, B, and C, if A is preferred to B, and B +is preferred to C, then a well-defined order should mean the preference is +transitive (in the sense of orders @footnote{For some set of objects to have +an order, there @emph{must} be some binary ordering relation that is defined +for @emph{every} combination of those objects, and that relation @emph{must} +be transitive. I.e.@:, if the relation operator is @mprec{}, and if +a @mprec{} b and b @mprec{} c then that relation must carry over +and it @emph{must} be that a @mprec{} c for the objects to have an +order. The ordering relation may allow for equality, i.e. +a @mprec{} b and b @mprec{} a may both be true amd imply that +a and b are equal in the order and not distinguished by it, in +which case the set has a partial order. Otherwise, if there is an order, +all the objects have a distinct place in the order and the set has a total +order.}) and that A would be preferred to C. + +@c No longer need the precedes character definition +@unmacro mprec + +However, when MED is involved this need not be the case. With MED it is +possible that C is actually preferred over A. So A is preferred to B, B is +preferred to C, but C is preferred to A. This can be true even where BGP +defines a deterministic ``most preferred'' route out of the full set of +A,B,C. With MED, for any given set of routes there may be a +deterministically preferred route, but there need not be any way to arrange +them into any order of preference. With unmodified MED, the order of +preference of routes literally becomes undefined. + +That MED can induce non-transitive preferences over routes can cause issues. +Firstly, it may be perceived to cause routing table churn locally at +speakers; secondly, and more seriously, it may cause routing instability in +iBGP topologies, where sets of speakers continually oscillate between +different paths. + +The first issue arises from how speakers often implement routing decisions. +Though BGP defines a selection process that will deterministically select +the same route as best at any given speaker, even with MED, that process +requires evaluating all routes together. For performance and ease of +implementation reasons, many implementations evaluate route preferences in a +pair-wise fashion instead. Given there is no well-defined order when MED is +involved, the best route that will be chosen becomes subject to +implementation details, such as the order the routes are stored in. That +may be (locally) non-deterministic, e.g.@: it may be the order the routes +were received in. + +This indeterminism may be considered undesirable, though it need not cause +problems. It may mean additional routing churn is perceived, as sometimes +more updates may be produced than at other times in reaction to some event . + +This first issue can be fixed with a more deterministic route selection that +ensures routes are ordered by the neighbouring AS during selection. +@xref{bgp deterministic-med}. This may reduce the number of updates as +routes are received, and may in some cases reduce routing churn. Though, it +could equally deterministically produce the largest possible set of updates +in response to the most common sequence of received updates. + +A deterministic order of evaluation tends to imply an additional overhead of +sorting over any set of n routes to a destination. The implementation of +deterministic MED in Quagga scales significantly worse than most sorting +algorithms at present, with the number of paths to a given destination. +That number is often low enough to not cause any issues, but where there are +many paths, the deterministic comparison may quickly become increasingly +expensive in terms of CPU. + +Deterministic local evaluation can @emph{not} fix the second, more major, +issue of MED however. Which is that the non-transitive preference of routes +MED can cause may lead to routing instability or oscillation across multiple +speakers in iBGP topologies. This can occur with full-mesh iBGP, but is +particularly problematic in non-full-mesh iBGP topologies that further +reduce the routing information known to each speaker. This has primarily +been documented with iBGP route-reflection topologies. However, any +route-hiding technologies potentially could also exacerbate oscillation with +MED. + +This second issue occurs where speakers each have only a subset of routes, +and there are cycles in the preferences between different combinations of +routes - as the undefined order of preference of MED allows - and the routes +are distributed in a way that causes the BGP speakers to 'chase' those +cycles. This can occur even if all speakers use a deterministic order of +evaluation in route selection. + +E.g., speaker 4 in AS A might receive a route from speaker 2 in AS X, and +from speaker 3 in AS Y; while speaker 5 in AS A might receive that route +from speaker 1 in AS Y. AS Y might set a MED of 200 at speaker 1, and 100 +at speaker 3. I.e, using ASN:ID:MED to label the speakers: + +@example + + /---------------\ + X:2------|--A:4-------A:5--|-Y:1:200 + Y:3:100--|-/ | + \---------------/ + +@end example + +Assuming all other metrics are equal (AS_PATH, ORIGIN, 0 IGP costs), then +based on the RFC4271 decision process speaker 4 will choose X:2 over +Y:3:100, based on the lower ID of 2. Speaker 4 advertises X:2 to speaker 5. +Speaker 5 will continue to prefer Y:1:200 based on the ID, and advertise +this to speaker 4. Speaker 4 will now have the full set of routes, and the +Y:1:200 it receives from 5 will beat X:2, but when speaker 4 compares +Y:1:200 to Y:3:100 the MED check now becomes active as the ASes match, and +now Y:3:100 is preferred. Speaker 4 therefore now advertises Y:3:100 to 5, +which will also agrees that Y:3:100 is preferred to Y:1:200, and so +withdraws the latter route from 4. Speaker 4 now has only X:2 and Y:3:100, +and X:2 beats Y:3:100, and so speaker 4 implicitly updates its route to +speaker 5 to X:2. Speaker 5 sees that Y:1:200 beats X:2 based on the ID, +and advertises Y:1:200 to speaker 4, and the cycle continues. + +The root cause is the lack of a clear order of preference caused by how MED +sometimes is and sometimes is not compared, leading to this cycle in the +preferences between the routes: + +@example + + /---> X:2 ---beats---> Y:3:100 --\ + | | + | | + \---beats--- Y:1:200 <---beats---/ + +@end example + +This particular type of oscillation in full-mesh iBGP topologies can be +avoided by speakers preferring already selected, external routes rather than +choosing to update to new a route based on a post-MED metric (e.g. +router-ID), at the cost of a non-deterministic selection process. Quagga +implements this, as do many other implementations, so long as it is not +overridden by setting @ref{bgp bestpath compare-routerid}, and see also +@ref{BGP decision process}, . + +However, more complex and insidious cycles of oscillation are possible with +iBGP route-reflection, which are not so easily avoided. These have been +documented in various places. See, e.g., @cite{McPherson, D. and Gill, V. +and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation +Condition", IETF RFC3345}, and @cite{Flavel, A. and M. Roughan, "Stable +and flexible iBGP", ACM SIGCOMM 2009}, and @cite{Griffin, T. and G. Wilfong, +"On the correctness of IBGP configuration", ACM SIGCOMM 2002} for concrete +examples and further references. + +There is as of this writing @emph{no} known way to use MED for its original +purpose; @emph{and} reduce routing information in iBGP topologies; +@emph{and} be sure to avoid the instability problems of MED due the +non-transitive routing preferences it can induce; in general on arbitrary +networks. + +There may be iBGP topology specific ways to reduce the instability risks, +even while using MED, e.g.@: by constraining the reflection topology and by +tuning IGP costs between route-reflector clusters, see RFC3345 for details. +In the near future, the Add-Path extension to BGP may also solve MED +oscillation while still allowing MED to be used as intended, by distributing +"best-paths per neighbour AS". This would be at the cost of distributing at +least as many routes to all speakers as a full-mesh iBGP would, if not more, +while also imposing similar CPU overheads as the "Deterministic MED" feature +at each Add-Path reflector. + +More generally, the instability problems that MED can introduce on more +complex, non-full-mesh, iBGP topologies may be avoided either by: + +@itemize + +@item +Setting @ref{bgp always-compare-med}, however this allows MED to be compared +across values set by different neighbour ASes, which may not produce +coherent desirable results, of itself. + +@item +Effectively ignoring MED by setting MED to the same value (e.g.@: 0) using +@ref{routemap set metric} on all received routes, in combination with +setting @ref{bgp always-compare-med} on all speakers. This is the simplest +and most performant way to avoid MED oscillation issues, where an AS is happy +not to allow neighbours to inject this problematic metric. + +@end itemize + +As MED is evaluated after the AS_PATH length check, another possible use for +MED is for intra-AS steering of routes with equal AS_PATH length, as an +extension of the last case above. As MED is evaluated before IGP metric, +this can allow cold-potato routing to be implemented to send traffic to +preferred hand-offs with neighbours, rather than the closest hand-off +according to the IGP metric. + +Note that even if action is taken to address the MED non-transitivity +issues, other oscillations may still be possible. E.g., on IGP cost if +iBGP and IGP topologies are at cross-purposes with each other - see the +Flavel and Roughan paper above for an example. Hence the guideline that the +iBGP topology should follow the IGP topology. + +@deffn {BGP} {bgp deterministic-med} {} +@anchor{bgp deterministic-med} + +Carry out route-selection in way that produces deterministic answers +locally, even in the face of MED and the lack of a well-defined order of +preference it can induce on routes. Without this option the preferred route +with MED may be determined largely by the order that routes were received +in. + +Setting this option will have a performance cost that may be noticeable when +there are many routes for each destination. Currently in Quagga it is +implemented in a way that scales poorly as the number of routes per +destination increases. + +The default is that this option is not set. +@end deffn + +Note that there are other sources of indeterminism in the route selection +process, specifically, the preference for older and already selected routes +from eBGP peers, @xref{BGP decision process}. + +@deffn {BGP} {bgp always-compare-med} {} +@anchor{bgp always-compare-med} + +Always compare the MED on routes, even when they were received from +different neighbouring ASes. Setting this option makes the order of +preference of routes more defined, and should eliminate MED induced +oscillations. + +If using this option, it may also be desirable to use @ref{routemap set +metric} to set MED to 0 on routes received from external neighbours. + +This option can be used, together with @ref{routemap set metric} to use MED +as an intra-AS metric to steer equal-length AS_PATH routes to, e.g., desired +exit points. +@end deffn + + + @node BGP network @section BGP network @@ -188,7 +549,7 @@ This command specifies an aggregate address. @end deffn @deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {} -This command specifies an aggregate address. Resulting routes inlucde +This command specifies an aggregate address. Resulting routes include AS set. @end deffn diff --git a/doc/routemap.texi b/doc/routemap.texi index db3e72d23..7938c965f 100644 --- a/doc/routemap.texi +++ b/doc/routemap.texi @@ -171,6 +171,7 @@ Set the route's weight. @end deffn @deffn {Route-map Command} {set metric @var{metric}} {} +@anchor{routemap set metric} Set the BGP attribute MED. @end deffn From f3cfc46450cccc5ac035a5a97c5a1a5484205705 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 7 Jan 2016 09:33:28 -0500 Subject: [PATCH 0924/1342] lib, bgpd: Fixup afi_t to be an enum and cleanup zebra.h This code change does two things: 1) Removes ZEBRA_AFI_XXX #defines since they were redundant information 2) Switches afi_t to an enumerated type so that the compiler can do a bit more compile time checking. Signed-off-by: Donald Sharp --- bgpd/bgp_open.c | 40 ++++++++++++++++++++-------------------- bgpd/bgp_open.h | 1 + bgpd/bgp_routemap.c | 14 ++++++-------- lib/plist.c | 11 +++++------ lib/zebra.h | 15 +++++---------- 5 files changed, 37 insertions(+), 44 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index ff2ae08dd..38d9dc56c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -126,23 +126,23 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) { switch (afi) { - case AFI_IP: -#ifdef HAVE_IPV6 - case AFI_IP6: -#endif - switch (*safi) - { - /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ - case SAFI_MPLS_LABELED_VPN: - *safi = SAFI_MPLS_VPN; - case SAFI_UNICAST: - case SAFI_MULTICAST: - case SAFI_MPLS_VPN: - return 1; - } + case AFI_IP: + case AFI_IP6: + switch (*safi) + { + /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ + case SAFI_MPLS_LABELED_VPN: + *safi = SAFI_MPLS_VPN; + case SAFI_UNICAST: + case SAFI_MULTICAST: + case SAFI_MPLS_VPN: + return 1; + } + break; } + zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi); - + return 0; } @@ -230,7 +230,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) } /* validate number field */ - if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) + if (CAPABILITY_CODE_ORF_LEN + (entry.num * 2) > hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", @@ -432,14 +432,14 @@ static const int capcode_str_max = array_size(capcode_str); /* Minimum sizes for length field of each cap (so not inc. the header) */ static const size_t cap_minsizes[] = { - [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data), + [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, - [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry), - [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr), + [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, + [CAPABILITY_CODE_RESTART] = 6, [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, - [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry), + [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, }; /* value the capability must be a multiple of. diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 2b1382d8b..62333754b 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -82,6 +82,7 @@ struct capability_gr #define CAPABILITY_CODE_DYNAMIC_LEN 0 #define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ #define CAPABILITY_CODE_AS4_LEN 4 +#define CAPABILITY_CODE_ORF_LEN 5 /* Cooperative Route Filtering Capability. */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 20bf2ebaa..7555ca77b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2383,14 +2383,12 @@ bgp_route_map_update (const char *unused) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name) - bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = - route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); -#ifdef HAVE_IPV6 - if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) - bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = - route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); -#endif /* HAVE_IPV6 */ + if (bgp->rmap[AFI_IP][i].name) + bgp->rmap[AFI_IP][i].map = + route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); + if (bgp->rmap[AFI_IP6][i].name) + bgp->rmap[AFI_IP6][i].map = + route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); } } } diff --git a/lib/plist.c b/lib/plist.c index f9e626d8b..699c9b131 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -698,8 +698,9 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, } /* "any" is special token for matching any IPv4 addresses. */ - if (afi == AFI_IP) + switch (afi) { + case AFI_IP: if (strncmp ("any", prefix, strlen (prefix)) == 0) { ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p); @@ -715,10 +716,8 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE); return CMD_WARNING; } - } -#ifdef HAVE_IPV6 - else if (afi == AFI_IP6) - { + break; + case AFI_IP6: if (strncmp ("any", prefix, strlen (prefix)) == 0) { ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p); @@ -734,8 +733,8 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } + break; } -#endif /* HAVE_IPV6 */ /* ge and le check. */ if (genum && (genum <= p.prefixlen)) diff --git a/lib/zebra.h b/lib/zebra.h index a607437af..a9c76c6ab 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -445,11 +445,6 @@ extern int proto_redistnum(int afi, const char *s); extern const char *zserv_command_string (unsigned int command); -/* Zebra's family types. */ -#define ZEBRA_FAMILY_IPV4 1 -#define ZEBRA_FAMILY_IPV6 2 -#define ZEBRA_FAMILY_MAX 3 - /* Error codes of zebra. */ #define ZEBRA_ERR_NOERROR 0 #define ZEBRA_ERR_RTEXIST -1 @@ -483,9 +478,11 @@ extern const char *zserv_command_string (unsigned int command); #endif /* Address family numbers from RFC1700. */ -#define AFI_IP 1 -#define AFI_IP6 2 -#define AFI_MAX 3 +typedef enum { + AFI_IP = 1, + AFI_IP6 = 2, +#define AFI_MAX 3 +} afi_t; /* Subsequent Address Family Identifier. */ #define SAFI_UNICAST 1 @@ -516,8 +513,6 @@ extern const char *zserv_command_string (unsigned int command); #define SET_FLAG(V,F) (V) |= (F) #define UNSET_FLAG(V,F) (V) &= ~(F) -/* AFI and SAFI type. */ -typedef u_int16_t afi_t; typedef u_int8_t safi_t; /* Zebra types. Used in Zserv message header. */ From 7748fdc757a2181649dd4956f2767545673ef28d Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Wed, 10 Feb 2016 14:24:00 +0000 Subject: [PATCH 0925/1342] bgpd: Fix graceful restart capability minsize * bgp_open.c: cap_minsize should be CAPABILITY_CODE_RESTART_LEN for RESTART not 6. --- bgpd/bgp_open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 38d9dc56c..23090eb8e 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -435,7 +435,7 @@ static const size_t cap_minsizes[] = [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, - [CAPABILITY_CODE_RESTART] = 6, + [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, From 0490729cc033a3483fc6b0ed45085ee249cac779 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 7 Jan 2016 10:03:01 -0500 Subject: [PATCH 0926/1342] lib, bgpd, tests: Refactor FILTER_X in zebra.h lib/zebra.h has FILTER_X #define's. These do not belong there. Put them in lib/filter.h where they belong. Signed-off-by: Donald Sharp --- bgpd/bgp_advertise.c | 1 + bgpd/bgp_aspath.c | 1 + bgpd/bgp_attr.c | 1 + bgpd/bgp_btoa.c | 1 + bgpd/bgp_clist.c | 1 + bgpd/bgp_damp.c | 1 + bgpd/bgp_debug.c | 1 + bgpd/bgp_dump.c | 3 ++- bgpd/bgp_ecommunity.c | 1 + bgpd/bgp_filter.c | 9 ++------- bgpd/bgp_fsm.c | 1 + bgpd/bgp_mpath.c | 1 + bgpd/bgp_mplsvpn.c | 1 + bgpd/bgp_network.c | 1 + bgpd/bgp_nexthop.c | 1 + bgpd/bgp_open.c | 1 + bgpd/bgp_packet.c | 1 + bgpd/bgp_regex.c | 1 + bgpd/bgp_snmp.c | 1 + bgpd/bgp_table.c | 1 + bgpd/bgp_vty.c | 1 + bgpd/bgp_zebra.c | 1 + lib/filter.h | 5 +++++ lib/zebra.h | 5 ----- tests/aspath_test.c | 1 + tests/bgp_capability_test.c | 1 + tests/bgp_mp_attr_test.c | 1 + tests/bgp_mpath_test.c | 1 + tests/ecommunity_test.c | 1 + 29 files changed, 34 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index be9b4801f..ecf531f73 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "prefix.h" #include "hash.h" #include "thread.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 9d49f343c..6ab293765 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "stream.h" #include "jhash.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ef19bc434..ce8f8a080 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "hash.h" #include "jhash.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index b9ff67c54..284b28062 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "memory.h" #include "privs.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_dump.h" diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index db2cfa48d..bb06028b0 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "prefix.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 359fce36f..ac647239e 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "log.h" #include "thread.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_damp.h" diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 1d0976977..e3e5ca46a 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "str.h" #include "log.h" #include "sockunion.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 227fc7af0..1fa0e658e 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -27,8 +27,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "prefix.h" #include "thread.h" #include "linklist.h" -#include "bgpd/bgp_table.h" +#include "filter.h" +#include "bgpd/bgp_table.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 04957d41c..c76f01e3d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "prefix.h" #include "command.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index fd8ece659..26819fc15 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "memory.h" #include "buffer.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" @@ -65,18 +66,12 @@ struct as_filter char *reg_str; }; -enum as_list_type -{ - ACCESS_TYPE_STRING, - ACCESS_TYPE_NUMBER -}; - /* AS path filter list. */ struct as_list { char *name; - enum as_list_type type; + enum access_type type; struct as_list *next; struct as_list *prev; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 182333673..c4cfd58e5 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "plist.h" #include "workqueue.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 98b75b67d..9eaf3c26a 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -28,6 +28,7 @@ #include "linklist.h" #include "sockunion.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 75c90cd77..0c4533be1 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "memory.h" #include "stream.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 3c5e6c5d5..81a6a79f6 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "privs.h" #include "linklist.h" #include "network.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_fsm.h" diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 607d99b11..fa2f48822 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "hash.h" #include "jhash.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 23090eb8e..7a5f5ce0c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "command.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0639f4ddd..ec60069dc 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "sockopt.h" #include "linklist.h" #include "plist.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c index 9b65f7cb1..13fa82951 100644 --- a/bgpd/bgp_regex.c +++ b/bgpd/bgp_regex.c @@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "command.h" #include "memory.h" +#include "filter.h" #include "bgpd.h" #include "bgp_aspath.h" diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 662186b59..c4490bff0 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "thread.h" #include "smux.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 7a6c675dc..92bb95753 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "sockunion.h" #include "vty.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 36fd263af..efbd8dbbf 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "memory.h" #include "hash.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_advertise.h" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 186657bd8..4a25aa91c 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA. */ #include "zclient.h" #include "routemap.h" #include "thread.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" diff --git a/lib/filter.h b/lib/filter.h index 37535cb13..e6ccd33b3 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -25,6 +25,11 @@ #include "if.h" +/* Filter direction. */ +#define FILTER_IN 0 +#define FILTER_OUT 1 +#define FILTER_MAX 2 + /* Filter type is made by `permit', `deny' and `dynamic'. */ enum filter_type { diff --git a/lib/zebra.h b/lib/zebra.h index a9c76c6ab..5f45a3a36 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -491,11 +491,6 @@ typedef enum { #define SAFI_MPLS_VPN 4 #define SAFI_MAX 5 -/* Filter direction. */ -#define FILTER_IN 0 -#define FILTER_OUT 1 -#define FILTER_MAX 2 - /* Default Administrative Distance of each protocol. */ #define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 #define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 0aa3e47e7..5a0899ecb 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -24,6 +24,7 @@ #include "vty.h" #include "stream.h" #include "privs.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index 3cfc1987a..a3813518b 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -25,6 +25,7 @@ #include "stream.h" #include "privs.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_open.h" diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index d649e14d7..6dc6757cd 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -25,6 +25,7 @@ #include "stream.h" #include "privs.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index dbbf0dd66..a953ce9ed 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -29,6 +29,7 @@ #include "linklist.h" #include "memory.h" #include "zclient.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c index f12aa71cc..23ee40583 100644 --- a/tests/ecommunity_test.c +++ b/tests/ecommunity_test.c @@ -24,6 +24,7 @@ #include "stream.h" #include "privs.h" #include "memory.h" +#include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" From d7be042378eac103634ab62abf4b2a5ca225092d Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:43 -0500 Subject: [PATCH 0927/1342] zebra: wire up "debug zebra packet detail" There was no way to actually set ZEBRA_DEBUG_DETAIL, even though some debug output was conditional to it. Add CLI command. Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- zebra/debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra/debug.c b/zebra/debug.c index c3b00e0fa..537c47662 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -104,7 +104,7 @@ DEFUN (debug_zebra_packet, DEFUN (debug_zebra_packet_direct, debug_zebra_packet_direct_cmd, - "debug zebra packet (recv|send)", + "debug zebra packet (recv|send|detail)", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra packet\n" @@ -116,7 +116,8 @@ DEFUN (debug_zebra_packet_direct, zebra_debug_packet |= ZEBRA_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) zebra_debug_packet |= ZEBRA_DEBUG_RECV; - zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL; + if (strncmp ("detail", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_DETAIL; return CMD_SUCCESS; } From b05c6ca57130f079f8a8a6686d9d4ffa5ff440f0 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:44 -0500 Subject: [PATCH 0928/1342] zebra: make RTF_LLINFO optional to fix FreeBSD Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- zebra/kernel_socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index fe9e4acb5..790b1420a 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -242,7 +242,9 @@ static const struct message rtm_flag_str[] = {RTF_CLONING, "CLONING"}, #endif /* RTF_CLONING */ {RTF_XRESOLVE, "XRESOLVE"}, +#ifdef RTF_LLINFO {RTF_LLINFO, "LLINFO"}, +#endif /* RTF_LLINFO */ {RTF_STATIC, "STATIC"}, {RTF_BLACKHOLE, "BLACKHOLE"}, #ifdef RTF_PRIVATE From 40278bd4c51939ccf8ec06ef1f33aedf8f05e86c Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:45 -0500 Subject: [PATCH 0929/1342] zebra: additional redistribute related logging Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- zebra/redistribute.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 5ec821988..57b515e13 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -150,12 +150,18 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) - if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) - && newrib->type == type - && newrib->distance != DISTANCE_INFINITY - && zebra_check_addr (&rn->p)) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); - + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: checking: selected=%d, type=%d, distance=%d, zebra_check_addr=%d", + __func__, CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED), + newrib->type, newrib->distance, zebra_check_addr (&rn->p)); + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->type == type + && newrib->distance != DISTANCE_INFINITY + && zebra_check_addr (&rn->p)) + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); + } + #ifdef HAVE_IPV6 table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) From 672900382d47137638086bd8351b2678f589a546 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:46 -0500 Subject: [PATCH 0930/1342] lib: fix bookkeeping for libreadline malloc()s When libreadline is used, we mistakenly mix in strdup() done in libreadline with Quagga's lib/memory bookkeeping/counting, leading to counter underflows on MTYPE_TMP. Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- lib/command.c | 44 ++++++++++++++++++++++++++++---------------- lib/command.h | 1 + lib/vty.c | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/command.c b/lib/command.c index 37767e925..73a8a804d 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2364,7 +2364,7 @@ cmd_complete_sort(vector matchvec) /* Command line completion support. */ static char ** -cmd_complete_command_real (vector vline, struct vty *vty, int *status) +cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib) { unsigned int i; vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); @@ -2449,13 +2449,13 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) for (j = 0; j < vector_active (match_vector); j++) if ((token = vector_slot (match_vector, j))) - { - if ((string = - cmd_entry_function (vector_slot (vline, index), - token))) - if (cmd_unique_string (matchvec, string)) - vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); - } + { + string = cmd_entry_function (vector_slot (vline, index), token); + if (string && cmd_unique_string (matchvec, string)) + vector_set (matchvec, (islib != 0 ? + XSTRDUP (MTYPE_TMP, string) : + strdup (string) /* rl freed */)); + } } /* We don't need cmd_vector any more. */ @@ -2500,7 +2500,9 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) { char *lcdstr; - lcdstr = XMALLOC (MTYPE_TMP, lcd + 1); + lcdstr = (islib != 0 ? + XMALLOC (MTYPE_TMP, lcd + 1) : + malloc(lcd + 1)); memcpy (lcdstr, matchvec->index[0], lcd); lcdstr[lcd] = '\0'; @@ -2508,10 +2510,15 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) /* Free matchvec. */ for (i = 0; i < vector_active (matchvec); i++) - { - if (vector_slot (matchvec, i)) - XFREE (MTYPE_TMP, vector_slot (matchvec, i)); - } + { + if (vector_slot (matchvec, i)) + { + if (islib != 0) + XFREE (MTYPE_TMP, vector_slot (matchvec, i)); + else + free (vector_slot (matchvec, i)); + } + } vector_free (matchvec); /* Make new matchvec. */ @@ -2534,7 +2541,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) } char ** -cmd_complete_command (vector vline, struct vty *vty, int *status) +cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib) { char **ret; @@ -2555,15 +2562,20 @@ cmd_complete_command (vector vline, struct vty *vty, int *status) vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); } - ret = cmd_complete_command_real (shifted_vline, vty, status); + ret = cmd_complete_command_real (shifted_vline, vty, status, islib); vector_free(shifted_vline); vty->node = onode; return ret; } + return cmd_complete_command_real (vline, vty, status, islib); +} - return cmd_complete_command_real (vline, vty, status); +char ** +cmd_complete_command (vector vline, struct vty *vty, int *status) +{ + return cmd_complete_command_lib (vline, vty, status, 0); } /* return parent node */ diff --git a/lib/command.h b/lib/command.h index 6030069a4..afc2e3f29 100644 --- a/lib/command.h +++ b/lib/command.h @@ -526,6 +526,7 @@ extern vector cmd_make_strvec (const char *); extern void cmd_free_strvec (vector); extern vector cmd_describe_command (vector, struct vty *, int *status); extern char **cmd_complete_command (vector, struct vty *, int *status); +extern char **cmd_complete_command_lib (vector, struct vty *, int *status, int islib); extern const char *cmd_prompt (enum node_type); extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node); extern int config_from_file (struct vty *, FILE *, unsigned int *line_num); diff --git a/lib/vty.c b/lib/vty.c index 8befcb0fa..480d34fd6 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -873,7 +873,7 @@ vty_complete_command (struct vty *vty) if (isspace ((int) vty->buf[vty->length - 1])) vector_set (vline, NULL); - matched = cmd_complete_command (vline, vty, &ret); + matched = cmd_complete_command_lib (vline, vty, &ret, 1); cmd_free_strvec (vline); From 9248b61f54955e56212f3ae4c8a7ab704f7ad01c Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:47 -0500 Subject: [PATCH 0931/1342] lib: treat realloc of null pointer as alloc Now use zalloc rather than alloc with null. Fixes issue seen in bgp check tests. Signed-off-by: Lou Berger --- lib/memory.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/memory.c b/lib/memory.c index 172ddfc49..269520d5a 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -108,6 +108,9 @@ zrealloc (int type, void *ptr, size_t size) { void *memory; + if (ptr == NULL) /* is really alloc */ + return zcalloc(type, size); + memory = realloc (ptr, size); if (memory == NULL) zerror ("realloc", type, size); From f9ec4190f1eaf2dba355a9808bca8d7148bc8a55 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:48 -0500 Subject: [PATCH 0932/1342] lib: add "show commandtree" CLI command Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- lib/command.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/command.c b/lib/command.c index 73a8a804d..aee7d06a2 100644 --- a/lib/command.c +++ b/lib/command.c @@ -4056,6 +4056,37 @@ DEFUN (no_banner_motd, return CMD_SUCCESS; } +DEFUN (show_commandtree, + show_commandtree_cmd, + "show commandtree", + NO_STR + "Show command tree\n") +{ + /* TBD */ + vector cmd_vector; + unsigned int i; + + vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE); + + /* vector of all commands installed at this node */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + /* loop over all commands at this node */ + for (i = 0; i < vector_active(cmd_vector); ++i) + { + struct cmd_element *cmd_element; + + /* A cmd_element (seems to be) is an individual command */ + if ((cmd_element = vector_slot (cmd_vector, i)) == NULL) + continue; + + vty_out (vty, " %s%s", cmd_element->string, VTY_NEWLINE); + } + + vector_free (cmd_vector); + return CMD_SUCCESS; +} + /* Set config filename. Called from vty.c */ void host_config_set (char *filename) @@ -4124,6 +4155,7 @@ cmd_init (int terminal) install_element (VIEW_NODE, &config_terminal_length_cmd); install_element (VIEW_NODE, &config_terminal_no_length_cmd); install_element (VIEW_NODE, &show_logging_cmd); + install_element (VIEW_NODE, &show_commandtree_cmd); install_element (VIEW_NODE, &echo_cmd); install_element (RESTRICTED_NODE, &config_list_cmd); @@ -4133,6 +4165,7 @@ cmd_init (int terminal) install_element (RESTRICTED_NODE, &config_enable_cmd); install_element (RESTRICTED_NODE, &config_terminal_length_cmd); install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd); + install_element (RESTRICTED_NODE, &show_commandtree_cmd); install_element (RESTRICTED_NODE, &echo_cmd); } @@ -4145,6 +4178,7 @@ cmd_init (int terminal) } install_element (ENABLE_NODE, &show_startup_config_cmd); install_element (ENABLE_NODE, &show_version_cmd); + install_element (ENABLE_NODE, &show_commandtree_cmd); if (terminal) { @@ -4207,6 +4241,7 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_work_queues_cmd); install_element (ENABLE_NODE, &show_work_queues_cmd); } + install_element (CONFIG_NODE, &show_commandtree_cmd); srandom(time(NULL)); } From c7f7e49a4f68c92152384582ff70d64609858170 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:49 -0500 Subject: [PATCH 0933/1342] lib: add facility to log all CLI commands Signed-off-by: Lou Berger --- lib/vty.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 480d34fd6..9f4d8faf0 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -111,7 +111,7 @@ vty_out (struct vty *vty, const char *format, ...) { /* Try to write to initial buffer. */ va_start (args, format); - len = vsnprintf (buf, sizeof buf, format, args); + len = vsnprintf (buf, sizeof(buf), format, args); va_end (args); /* Initial buffer is not enough. */ @@ -401,7 +401,41 @@ vty_command (struct vty *vty, char *buf) int ret; vector vline; const char *protocolname; + char *cp; + /* + * Log non empty command lines + */ + cp = buf; + if (cp != NULL) + { + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + } + if (cp != NULL && *cp != '\0') + { + unsigned i; + char vty_str[VTY_BUFSIZ]; + char prompt_str[VTY_BUFSIZ]; + + /* format the base vty info */ + snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address); + if (vty) + for (i = 0; i < vector_active (vtyvec); i++) + if ((vty == vector_slot (vtyvec, i))) + { + snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", + i, vty->address); + break; + } + + /* format the prompt */ + snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str); + + /* now log the command */ + zlog(NULL, LOG_NOTICE, "%s%s", prompt_str, buf); + } /* Split readline string up into the vector */ vline = cmd_make_strvec (buf); @@ -1571,7 +1605,7 @@ vty_flush (struct thread *thread) erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE)); /* N.B. if width is 0, that means we don't know the window size. */ - if ((vty->lines == 0) || (vty->width == 0)) + if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0)) flushrc = buffer_flush_available(vty->obuf, vty_sock); else if (vty->status == VTY_MORELINE) flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, From 2daf7f3a8d69213f35b16a04dbe300957481a811 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:50 -0500 Subject: [PATCH 0934/1342] lib: add SAFI_ENCAP type, safi2str prefix utility Signed-off-by: Lou Berger --- lib/prefix.c | 16 ++++++++++++++++ lib/prefix.h | 1 + lib/zebra.h | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/prefix.c b/lib/prefix.c index 936e9fcb2..3e4ca1679 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -223,6 +223,22 @@ family2afi (int family) return 0; } +const char * +safi2str(safi_t safi) +{ + switch (safi) { + case SAFI_UNICAST: + return "unicast"; + case SAFI_MULTICAST: + return "multicast"; + case SAFI_ENCAP: + return "encap"; + case SAFI_MPLS_VPN: + return "vpn"; + } + return NULL; +} + /* If n includes p prefix then return 1 else return 0. */ int prefix_match (const struct prefix *n, const struct prefix *p) diff --git a/lib/prefix.h b/lib/prefix.h index a517d795a..4a3175070 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -173,6 +173,7 @@ union prefix46constptr extern int str2family(const char *); extern int afi2family (afi_t); extern afi_t family2afi (int); +extern const char *safi2str(safi_t safi); /* Check bit of the prefix. */ extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen); diff --git a/lib/zebra.h b/lib/zebra.h index 5f45a3a36..644729b74 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -489,7 +489,8 @@ typedef enum { #define SAFI_MULTICAST 2 #define SAFI_RESERVED_3 3 #define SAFI_MPLS_VPN 4 -#define SAFI_MAX 5 +#define SAFI_ENCAP 7 /* per IANA */ +#define SAFI_MAX 8 /* Default Administrative Distance of each protocol. */ #define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 From 3e841d3b49bdb475ce793eee5d82e5137dff57d3 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:51 -0500 Subject: [PATCH 0935/1342] bgpd: add nexthop length to AF macro Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- bgpd/bgp_nexthop.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 6e5350ead..c8aef58ba 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -26,6 +26,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_SCAN_INTERVAL_DEFAULT 60 #define BGP_IMPORT_INTERVAL_DEFAULT 15 +#define NEXTHOP_FAMILY(nexthop_len) ( \ + ((nexthop_len) == 4 || \ + (nexthop_len) == 12 ? AF_INET : \ + ((nexthop_len) == 16 || \ + (nexthop_len) == 24 || \ + (nexthop_len) == 48 ? AF_INET6 : \ + AF_UNSPEC)) \ +) + /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { From 4d80560a2b064182191371fd7e4304bf829a4d9f Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:52 -0500 Subject: [PATCH 0936/1342] bgpd: kill unused variable in bgp_socket() Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- bgpd/bgp_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 81a6a79f6..d11cbc3e7 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -556,7 +556,7 @@ bgp_socket (unsigned short port, const char *address) int sock; int socklen; struct sockaddr_in sin; - int ret, en; + int ret; sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) From a76d9ca3584c1751a592457c167c1e146648ceb6 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:53 -0500 Subject: [PATCH 0937/1342] bgpd: make _vpnv4 static handling SAFI-agnostic This changes the existing _vpnv4 functions for MPLS-VPN into SAFI-agnostic functions, renaming them from *_vpnv4 to *_safi. Also adds route-map support while at it. Signed-off-by: Lou Berger Reviewed-by: David Lamparter --- bgpd/bgp_mplsvpn.c | 20 ++++- bgpd/bgp_route.c | 212 ++++++++++++++++++++++++++++++++++----------- bgpd/bgp_route.h | 9 +- 3 files changed, 187 insertions(+), 54 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 0c4533be1..3eab76fc5 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -315,7 +315,22 @@ DEFUN (vpnv4_network, "BGP tag\n" "tag value\n") { - return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]); + return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (vpnv4_network_route_map, + vpnv4_network_route_map_cmd, + "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD route-map WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n" + "route map\n" + "route map name\n") +{ + return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[0], argv[1], argv[2], argv[3]); } /* For testing purpose, static route of MPLS-VPN. */ @@ -330,7 +345,7 @@ DEFUN (no_vpnv4_network, "BGP tag\n" "tag value\n") { - return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]); + return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[0], argv[1], argv[2]); } static int @@ -743,6 +758,7 @@ void bgp_mplsvpn_init (void) { install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); + install_element (BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8aa6daa8e..ff541e845 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3630,39 +3630,6 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, } } -static void -bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi, - safi_t safi, struct prefix_rd *prd, u_char *tag) -{ - struct bgp_node *rn; - struct bgp_info *new; - - rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); - - /* Make new BGP info. */ - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_STATIC; - new->peer = bgp->peer_self; - new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP); - SET_FLAG (new->flags, BGP_INFO_VALID); - new->uptime = bgp_clock (); - new->extra = bgp_info_extra_new(); - memcpy (new->extra->tag, tag, 3); - - /* Aggregate address increment. */ - bgp_aggregate_increment (bgp, p, new, afi, safi); - - /* Register new BGP information. */ - bgp_info_add (rn, new); - - /* route_node_get lock */ - bgp_unlock_node (rn); - - /* Process change. */ - bgp_process (bgp, rn, afi, safi); -} - void bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi) @@ -3711,9 +3678,12 @@ bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) } } +/* + * Used for SAFI_MPLS_VPN and SAFI_ENCAP + */ static void -bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi, - safi_t safi, struct prefix_rd *prd, u_char *tag) +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *ri; @@ -3739,6 +3709,131 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi, bgp_unlock_node (rn); } +static void +bgp_static_update_safi (struct bgp *bgp, struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *new; + struct attr *attr_new; + struct attr attr = { 0 }; + struct bgp_info *ri; + + assert (bgp_static); + + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, &bgp_static->prd); + + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + + attr.nexthop = bgp_static->igpnexthop; + attr.med = bgp_static->igpmetric; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + + /* Apply route-map. */ + if (bgp_static->rmap.name) + { + struct attr attr_tmp = attr; + struct bgp_info info; + int ret; + + info.peer = bgp->peer_self; + info.attr = &attr_tmp; + + SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); + + ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + + bgp->peer_self->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + /* Free uninterned attribute. */ + bgp_attr_flush (&attr_tmp); + + /* Unintern original. */ + aspath_unintern (&attr.aspath); + bgp_attr_extra_free (&attr); + bgp_static_withdraw_safi (bgp, p, afi, safi, &bgp_static->prd, + bgp_static->tag); + return; + } + + attr_new = bgp_attr_intern (&attr_tmp); + } + else + { + attr_new = bgp_attr_intern (&attr); + } + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + + if (ri) + { + if (attrhash_cmp (ri->attr, attr_new) && + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + { + bgp_unlock_node (rn); + bgp_attr_unintern (&attr_new); + aspath_unintern (&attr.aspath); + bgp_attr_extra_free (&attr); + return; + } + else + { + /* The attribute is changed. */ + bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); + + /* Rewrite BGP route information. */ + if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + bgp_info_restore(rn, ri); + else + bgp_aggregate_decrement (bgp, p, ri, afi, safi); + bgp_attr_unintern (&ri->attr); + ri->attr = attr_new; + ri->uptime = bgp_clock (); + + /* Process change. */ + bgp_aggregate_increment (bgp, p, ri, afi, safi); + bgp_process (bgp, rn, afi, safi); + bgp_unlock_node (rn); + aspath_unintern (&attr.aspath); + bgp_attr_extra_free (&attr); + return; + } + } + + + /* Make new BGP info. */ + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_STATIC; + new->peer = bgp->peer_self; + new->attr = attr_new; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->uptime = bgp_clock (); + new->extra = bgp_info_extra_new(); + memcpy (new->extra->tag, bgp_static->tag, 3); + + /* Aggregate address increment. */ + bgp_aggregate_increment (bgp, p, new, afi, safi); + + /* Register new BGP information. */ + bgp_info_add (rn, new); + + /* route_node_get lock */ + bgp_unlock_node (rn); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + + /* Unintern original. */ + aspath_unintern (&attr.aspath); + bgp_attr_extra_free (&attr); +} + /* Configure static BGP network. When user don't run zebra, static route should be installed as valid. */ static int @@ -3909,8 +4004,8 @@ bgp_static_delete (struct bgp *bgp) for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) { bgp_static = rn->info; - bgp_static_withdraw_vpnv4 (bgp, &rm->p, - AFI_IP, SAFI_MPLS_VPN, + bgp_static_withdraw_safi (bgp, &rm->p, + AFI_IP, safi, (struct prefix_rd *)&rn->p, bgp_static->tag); bgp_static_free (bgp_static); @@ -3929,9 +4024,15 @@ bgp_static_delete (struct bgp *bgp) } } +/* + * gpz 110624 + * Currently this is used to set static routes for VPN and ENCAP. + * I think it can probably be factored with bgp_static_set. + */ int -bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, - const char *tag_str) +bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, + const char *rd_str, const char *tag_str, + const char *rmap_str) { int ret; struct prefix p; @@ -3967,10 +4068,10 @@ bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, return CMD_WARNING; } - prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], + prn = bgp_node_get (bgp->route[AFI_IP][safi], (struct prefix *)&prd); if (prn->info == NULL) - prn->info = bgp_table_init (AFI_IP, SAFI_MPLS_VPN); + prn->info = bgp_table_init (AFI_IP, safi); else bgp_unlock_node (prn); table = prn->info; @@ -3986,11 +4087,24 @@ bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, { /* New configuration. */ bgp_static = bgp_static_new (); - bgp_static->valid = 1; - memcpy (bgp_static->tag, tag, 3); + bgp_static->backdoor = 0; + bgp_static->valid = 0; + bgp_static->igpmetric = 0; + bgp_static->igpnexthop.s_addr = 0; + memcpy(bgp_static->tag, tag, 3); + bgp_static->prd = prd; + + if (rmap_str) + { + if (bgp_static->rmap.name) + free (bgp_static->rmap.name); + bgp_static->rmap.name = strdup (rmap_str); + bgp_static->rmap.map = route_map_lookup_by_name (rmap_str); + } rn->info = bgp_static; - bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); + bgp_static->valid = 1; + bgp_static_update_safi (bgp, &p, bgp_static, AFI_IP, safi); } return CMD_SUCCESS; @@ -3998,8 +4112,8 @@ bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, /* Configure static BGP network. */ int -bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str, - const char *rd_str, const char *tag_str) +bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, + const char *rd_str, const char *tag_str) { int ret; struct bgp *bgp; @@ -4036,10 +4150,10 @@ bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str, return CMD_WARNING; } - prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], + prn = bgp_node_get (bgp->route[AFI_IP][safi], (struct prefix *)&prd); if (prn->info == NULL) - prn->info = bgp_table_init (AFI_IP, SAFI_MPLS_VPN); + prn->info = bgp_table_init (AFI_IP, safi); else bgp_unlock_node (prn); table = prn->info; @@ -4048,7 +4162,7 @@ bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str, if (rn) { - bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); + bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &prd, tag); bgp_static = rn->info; bgp_static_free (bgp_static); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3d2eea51b..0482c6fc6 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -120,6 +120,9 @@ struct bgp_static struct route_map *map; } rmap; + /* Route Distinguisher */ + struct prefix_rd prd; + /* MPLS label. */ u_char tag[3]; }; @@ -209,10 +212,10 @@ extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static afi_t, safi_t); extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); -extern int bgp_static_set_vpnv4 (struct vty *vty, const char *, - const char *, const char *); +extern int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *, + const char *, const char *, const char *); -extern int bgp_static_unset_vpnv4 (struct vty *, const char *, +extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *, const char *, const char *); /* this is primarily for MPLS-VPN */ From a03bd16eedc5077e98716509b8918ed365227e02 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:54 -0500 Subject: [PATCH 0938/1342] bgpd: handle AS4 and EOI route distinguishers Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- bgpd/bgp_mplsvpn.c | 80 ++++++++++++++++++++++++++++++++++------------ bgpd/bgp_mplsvpn.h | 2 ++ 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3eab76fc5..bbc739bba 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -54,6 +54,7 @@ decode_label (u_char *pnt) return l; } +/* type == RD_TYPE_AS */ static void decode_rd_as (u_char *pnt, struct rd_as *rd_as) { @@ -66,6 +67,20 @@ decode_rd_as (u_char *pnt, struct rd_as *rd_as) rd_as->val |= (u_int32_t) *pnt; } +/* type == RD_TYPE_AS4 */ +static void +decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int32_t) *pnt++ << 24; + rd_as->as |= (u_int32_t) *pnt++ << 16; + rd_as->as |= (u_int32_t) *pnt++ << 8; + rd_as->as |= (u_int32_t) *pnt++; + + rd_as->val = ((u_int16_t) *pnt++ << 8); + rd_as->val |= (u_int16_t) *pnt; +} + +/* type == RD_TYPE_IP */ static void decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) { @@ -149,30 +164,32 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, /* Decode RD type. */ type = decode_rd_type (pnt + 3); - /* Decode RD value. */ - if (type == RD_TYPE_AS) - decode_rd_as (pnt + 5, &rd_as); - else if (type == RD_TYPE_IP) - decode_rd_ip (pnt + 5, &rd_ip); - else - { - zlog_err ("Invalid RD type %d", type); - return -1; - } + switch (type) + { + case RD_TYPE_AS: + decode_rd_as (pnt + 5, &rd_as); + break; + + case RD_TYPE_AS4: + decode_rd_as4 (pnt + 5, &rd_as); + break; + + case RD_TYPE_IP: + decode_rd_ip (pnt + 5, &rd_ip); + break; + + case RD_TYPE_EOI: + break; + + default: + zlog_err ("Invalid RD type %d", type); + return -1; + } p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8; memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, psize - VPN_PREFIXLEN_MIN_BYTES); -#if 0 - if (type == RD_TYPE_AS) - zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val, - inet_ntoa (p.u.prefix4), p.prefixlen); - else if (type == RD_TYPE_IP) - zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip), - rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); -#endif /* 0 */ - if (attr) bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); @@ -294,12 +311,25 @@ prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); return buf; } + else if (type == RD_TYPE_AS4) + { + decode_rd_as4 (pnt + 2, &rd_as); + snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); + return buf; + } else if (type == RD_TYPE_IP) { decode_rd_ip (pnt + 2, &rd_ip); snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); return buf; } + else if (type == RD_TYPE_EOI) + { + snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", + pnt[1], /* LHI */ + pnt[2], pnt[3], pnt[4], pnt[5], pnt[6], pnt[7]); /* MAC */ + return buf; + } return NULL; } @@ -406,6 +436,8 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd) /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4 (pnt + 2, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 2, &rd_ip); @@ -413,6 +445,8 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd) if (type == RD_TYPE_AS) vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_AS4) + vty_out (vty, "%u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_IP) vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); @@ -513,15 +547,19 @@ bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type ty /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4 (pnt + 2, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 2, &rd_ip); vty_out (vty, "Route Distinguisher: "); if (type == RD_TYPE_AS) - vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + vty_out (vty, "as2 %u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_AS4) + vty_out (vty, "as4 %u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_IP) - vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + vty_out (vty, "ip %s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); vty_out (vty, "%s", VTY_NEWLINE); rd_header = 0; diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index b221c3bdd..0cb9decac 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -23,6 +23,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define RD_TYPE_AS 0 #define RD_TYPE_IP 1 +#define RD_TYPE_AS4 2 +#define RD_TYPE_EOI 0xff00 #define RD_ADDRSTRLEN 28 From 9da04bca0e994ec92b9242159bf27d89c6743354 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:55 -0500 Subject: [PATCH 0939/1342] bgpd: wire up VPNv6 protocol processing There wasn't much missing for VPNv6 to begin with; just a few bits of de- & encoding and a few lists to be updated. Signed-off-by: Lou Berger Signed-off-by: David Lamparter [Editorial note: Signed-off-by may imply an authorship claim, but need not] Edited-by: Paul Jakma / --- bgpd/bgp_attr.c | 25 +++++++++++++++++++++++++ bgpd/bgp_mplsvpn.c | 23 +++++++++++++++-------- bgpd/bgp_mplsvpn.h | 2 +- bgpd/bgp_open.c | 15 ++++++++++++++- bgpd/bgp_packet.c | 32 ++++++++++++++++++++++++++++---- bgpd/bgp_vty.c | 6 +++++- bgpd/bgpd.c | 11 ++++++++--- 7 files changed, 96 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ce8f8a080..ecf1c3146 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1535,11 +1535,36 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, stream_get (&attre->mp_nexthop_global_in, s, 4); break; #ifdef HAVE_IPV6 + case 24: + { + u_int32_t rd_high __attribute__((unused)); + u_int32_t rd_low __attribute__((unused)); + + rd_high = stream_getl (s); + rd_low = stream_getl (s); + } + /* fall through */ case 16: stream_get (&attre->mp_nexthop_global, s, 16); break; case 32: + case 48: + if (attre->mp_nexthop_len == 48) { + u_int32_t rd_high __attribute__((unused)); + u_int32_t rd_low __attribute__((unused)); + + rd_high = stream_getl (s); + rd_low = stream_getl (s); + } stream_get (&attre->mp_nexthop_global, s, 16); + + if (attre->mp_nexthop_len == 48) { + u_int32_t rd_high __attribute__((unused)); + u_int32_t rd_low __attribute__((unused)); + + rd_high = stream_getl (s); + rd_low = stream_getl (s); + } stream_get (&attre->mp_nexthop_local, s, 16); if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local)) { diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index bbc739bba..78a71e70c 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -92,13 +92,13 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) } int -bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, - struct bgp_nlri *packet) +bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; - int psize; + int psize = 0; int prefixlen; u_int16_t type; struct rd_as rd_as; @@ -191,11 +191,11 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, psize - VPN_PREFIXLEN_MIN_BYTES); if (attr) - bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); + bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); else - bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } /* Packet length consistency check. */ if (pnt != lim) @@ -480,6 +480,7 @@ static int bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int tags) { + afi_t afi = AFI_IP; struct bgp *bgp; struct bgp_table *table; struct bgp_node *rn; @@ -497,7 +498,13 @@ bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type ty return CMD_WARNING; } - for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + if ((afi != AFI_IP) && (afi != AFI_IP6)) + { + vty_out (vty, "Afi %d not supported%s", afi, VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 0cb9decac..4e9b317b7 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -43,7 +43,7 @@ struct rd_ip }; extern void bgp_mplsvpn_init (void); -extern int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *); +extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *); extern u_int32_t decode_label (u_char *); extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 7a5f5ce0c..302e4ce5d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -842,7 +842,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] - && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) + && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]) { plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", @@ -1012,6 +1013,18 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, 0); stream_putc (s, SAFI_MULTICAST); } + /* IPv6 VPN. */ + if (peer->afc[AFI_IP6][SAFI_MPLS_VPN]) + { + peer->afc_adv[AFI_IP6][SAFI_MPLS_VPN] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP6); + stream_putc (s, 0); + stream_putc (s, SAFI_MPLS_LABELED_VPN); + } #endif /* HAVE_IPV6 */ /* Route refresh. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index ec60069dc..16e1435a0 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1797,12 +1797,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (peer->afc[AFI_IP][SAFI_MULTICAST]) { if (mp_update.length - && mp_update.afi == AFI_IP + && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP + && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); @@ -1886,12 +1886,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); + bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); + bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP @@ -1900,6 +1900,30 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) { /* End-of-RIB received */ + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", + peer->host); + } + } + if (peer->afc[AFI_IP6][SAFI_MPLS_VPN]) + { + if (mp_update.length + && mp_update.afi == AFI_IP6 + && mp_update.safi == SAFI_MPLS_LABELED_VPN) + bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) + bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", peer->host); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index efbd8dbbf..6f3af9eae 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7303,11 +7303,13 @@ afi_safi_print (afi_t afi, safi_t safi) else if (afi == AFI_IP && safi == SAFI_MULTICAST) return "IPv4 Multicast"; else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) - return "VPNv4 Unicast"; + return "VPN-IPv4 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6 Multicast"; + else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) + return "VPN-IPv6 Unicast"; else return "Unknown"; } @@ -7650,6 +7652,8 @@ bgp_show_peer (struct vty *vty, struct peer *p) || p->afc_recv[AFI_IP6][SAFI_UNICAST] || p->afc_adv[AFI_IP6][SAFI_MULTICAST] || p->afc_recv[AFI_IP6][SAFI_MULTICAST] + || p->afc_adv[AFI_IP6][SAFI_MPLS_VPN] + || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN] #endif /* HAVE_IPV6 */ || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2325f07c8..c3c0dba3f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -978,6 +978,8 @@ peer_as_change (struct peer *peer, as_t as) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN], + PEER_FLAG_REFLECTOR_CLIENT); } /* local-as reset */ @@ -1394,7 +1396,8 @@ peer_group_active (struct peer *peer) || peer->af_group[AFI_IP][SAFI_MULTICAST] || peer->af_group[AFI_IP][SAFI_MPLS_VPN] || peer->af_group[AFI_IP6][SAFI_UNICAST] - || peer->af_group[AFI_IP6][SAFI_MULTICAST]) + || peer->af_group[AFI_IP6][SAFI_MULTICAST] + || peer->af_group[AFI_IP6][SAFI_MPLS_VPN]) return 1; return 0; } @@ -2335,7 +2338,8 @@ peer_active (struct peer *peer) || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_UNICAST] - || peer->afc[AFI_IP6][SAFI_MULTICAST]) + || peer->afc[AFI_IP6][SAFI_MULTICAST] + || peer->afc[AFI_IP6][SAFI_MPLS_VPN]) return 1; return 0; } @@ -2348,7 +2352,8 @@ peer_active_nego (struct peer *peer) || peer->afc_nego[AFI_IP][SAFI_MULTICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] - || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) + || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]) return 1; return 0; } From 13c378d96a57017f5995b2e0df46cfc31123f0e8 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:56 -0500 Subject: [PATCH 0940/1342] bgpd, lib, vtysh: hook up bgp VPNv6 CLI node Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- bgpd/bgp_vty.c | 112 ++++++++++++++++++++++++++++++++++++++++++- bgpd/bgpd.c | 15 ++++-- lib/command.c | 5 +- lib/command.h | 1 + lib/vty.c | 1 + vtysh/vtysh.c | 42 +++++++++++++++- vtysh/vtysh_config.c | 3 ++ 7 files changed, 171 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 6f3af9eae..304da2536 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -57,8 +57,15 @@ extern struct in_addr router_id_zebra; afi_t bgp_node_afi (struct vty *vty) { - if (vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) - return AFI_IP6; + switch (vty->node) + { + case BGP_IPV6_NODE: + case BGP_IPV6M_NODE: + case BGP_VPNV6_NODE: + return AFI_IP6; + break; + } + return AFI_IP; } @@ -67,6 +74,8 @@ bgp_node_afi (struct vty *vty) safi_t bgp_node_safi (struct vty *vty) { + if (vty->node == BGP_VPNV6_NODE) + return SAFI_MPLS_VPN; if (vty->node == BGP_VPNV4_NODE) return SAFI_MPLS_VPN; if (vty->node == BGP_IPV4M_NODE || vty->node == BGP_IPV6M_NODE) @@ -4285,6 +4294,23 @@ ALIAS (address_family_vpnv4, "Address family\n" "Address Family Modifier\n") +DEFUN (address_family_vpnv6, + address_family_vpnv6_cmd, + "address-family vpnv6", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_VPNV6_NODE; + return CMD_SUCCESS; +} + +ALIAS (address_family_vpnv6, + address_family_vpnv6_unicast_cmd, + "address-family vpnv6 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") + DEFUN (exit_address_family, exit_address_family_cmd, "exit-address-family", @@ -4293,6 +4319,7 @@ DEFUN (exit_address_family, if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE + || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) vty->node = BGP_NODE; @@ -9116,6 +9143,13 @@ static struct cmd_node bgp_vpnv4_node = 1 }; +static struct cmd_node bgp_vpnv6_node = +{ + BGP_VPNV6_NODE, + "%s(config-router-af-vpnv6)# ", + 1 +}; + static void community_list_vty (void); void @@ -9128,6 +9162,7 @@ bgp_vty_init (void) install_node (&bgp_ipv6_unicast_node, NULL); install_node (&bgp_ipv6_multicast_node, NULL); install_node (&bgp_vpnv4_node, NULL); + install_node (&bgp_vpnv6_node, NULL); /* Install default VTY commands to new nodes. */ install_default (BGP_NODE); @@ -9136,6 +9171,7 @@ bgp_vty_init (void) install_default (BGP_IPV6_NODE); install_default (BGP_IPV6M_NODE); install_default (BGP_VPNV4_NODE); + install_default (BGP_VPNV6_NODE); /* "bgp multiple-instance" commands. */ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); @@ -9294,6 +9330,7 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &neighbor_activate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element (BGP_NODE, &no_neighbor_activate_cmd); @@ -9302,6 +9339,7 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group set" commands. */ install_element (BGP_NODE, &neighbor_set_peer_group_cmd); @@ -9310,6 +9348,7 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd); /* "no neighbor peer-group unset" commands. */ install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd); @@ -9318,6 +9357,7 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd); @@ -9332,6 +9372,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element (BGP_NODE, &neighbor_attr_unchanged_cmd); @@ -9467,6 +9509,29 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged10_cmd); + /* "nexthop-local unchanged" commands */ install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); @@ -9489,6 +9554,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor remove-private-AS" commands. */ install_element (BGP_NODE, &neighbor_remove_private_as_cmd); @@ -9503,6 +9570,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_remove_private_as_cmd); /* "neighbor send-community" commands.*/ install_element (BGP_NODE, &neighbor_send_community_cmd); @@ -9529,6 +9598,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_send_community_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd); /* "neighbor route-reflector" commands.*/ install_element (BGP_NODE, &neighbor_route_reflector_client_cmd); @@ -9543,6 +9616,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element (BGP_NODE, &neighbor_route_server_client_cmd); @@ -9557,6 +9632,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor passive" commands. */ install_element (BGP_NODE, &neighbor_passive_cmd); @@ -9685,6 +9762,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd); /* "neighbor prefix-list" commands. */ install_element (BGP_NODE, &neighbor_prefix_list_cmd); @@ -9699,6 +9778,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element (BGP_NODE, &neighbor_filter_list_cmd); @@ -9713,6 +9794,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element (BGP_NODE, &neighbor_route_map_cmd); @@ -9727,6 +9810,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element (BGP_NODE, &neighbor_unsuppress_map_cmd); @@ -9741,6 +9826,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor maximum-prefix" commands. */ install_element (BGP_NODE, &neighbor_maximum_prefix_cmd); @@ -9822,6 +9909,20 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + /* "neighbor allowas-in" */ install_element (BGP_NODE, &neighbor_allowas_in_cmd); install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd); @@ -9841,6 +9942,9 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); /* address-family commands. */ install_element (BGP_NODE, &address_family_ipv4_cmd); @@ -9852,12 +9956,16 @@ bgp_vty_init (void) install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); + install_element (BGP_NODE, &address_family_vpnv6_cmd); + install_element (BGP_NODE, &address_family_vpnv6_unicast_cmd); + /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); + install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); /* "clear ip bgp commands" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c3c0dba3f..d9c32cee5 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5286,10 +5286,14 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, } else if (afi == AFI_IP6) { - vty_out (vty, "ipv6"); - - if (safi == SAFI_MULTICAST) - vty_out (vty, " multicast"); + if (safi == SAFI_MPLS_VPN) + vty_out (vty, "vpnv6"); + else + { + vty_out (vty, "ipv6"); + if (safi == SAFI_MULTICAST) + vty_out (vty, " multicast"); + } } vty_out (vty, "%s", VTY_NEWLINE); @@ -5531,6 +5535,9 @@ bgp_config_write (struct vty *vty) /* IPv6 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST); + /* IPv6 VPN configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN); + write++; } return write; diff --git a/lib/command.c b/lib/command.c index aee7d06a2..dbcef5ee8 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2590,6 +2590,7 @@ node_parent ( enum node_type node ) switch (node) { case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: @@ -2957,9 +2958,10 @@ DEFUN (config_exit, case VTY_NODE: vty->node = CONFIG_NODE; break; - case BGP_VPNV4_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: + case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: vty->node = BGP_NODE; @@ -3000,6 +3002,7 @@ DEFUN (config_end, case BABEL_NODE: case BGP_NODE: case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: diff --git a/lib/command.h b/lib/command.h index afc2e3f29..b5c73abe4 100644 --- a/lib/command.h +++ b/lib/command.h @@ -82,6 +82,7 @@ enum node_type BABEL_NODE, /* Babel protocol mode node. */ BGP_NODE, /* BGP protocol mode which includes BGP4+ */ BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ + BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */ BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ BGP_IPV6_NODE, /* BGP IPv6 address family */ diff --git a/lib/vty.c b/lib/vty.c index 9f4d8faf0..f695b7222 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -737,6 +737,7 @@ vty_end_config (struct vty *vty) case BABEL_NODE: case BGP_NODE: case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2703bb99f..418e5d767 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -280,7 +280,8 @@ vtysh_execute_func (const char *line, int pager) * to move into node in the vtysh where it succeeded. */ if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING) { - if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_IPV4_NODE + if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE + || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE || saved_node == BGP_IPV6M_NODE) && (tried == 1)) @@ -684,6 +685,12 @@ static struct cmd_node bgp_vpnv4_node = "%s(config-router-af)# " }; +static struct cmd_node bgp_vpnv6_node = +{ + BGP_VPNV6_NODE, + "%s(config-router-af)# " +}; + static struct cmd_node bgp_ipv4_node = { BGP_IPV4_NODE, @@ -818,6 +825,29 @@ DEFUNSH (VTYSH_BGPD, return CMD_SUCCESS; } +DEFUNSH (VTYSH_BGPD, + address_family_vpnv6, + address_family_vpnv6_cmd, + "address-family vpnv6", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_VPNV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_vpnv6_unicast, + address_family_vpnv6_unicast_cmd, + "address-family vpnv6 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_VPNV6_NODE; + return CMD_SUCCESS; +} + DEFUNSH (VTYSH_BGPD, address_family_ipv4_unicast, address_family_ipv4_unicast_cmd, @@ -1043,6 +1073,7 @@ vtysh_exit (struct vty *vty) vty->node = CONFIG_NODE; break; case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: @@ -1081,6 +1112,7 @@ DEFUNSH (VTYSH_BGPD, if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE + || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) vty->node = BGP_NODE; @@ -2275,6 +2307,7 @@ vtysh_init_vty (void) install_node (&rmap_node, NULL); install_node (&zebra_node, NULL); install_node (&bgp_vpnv4_node, NULL); + install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); /* #ifdef HAVE_IPV6 */ @@ -2301,6 +2334,7 @@ vtysh_init_vty (void) vtysh_install_default (RMAP_NODE); vtysh_install_default (ZEBRA_NODE); vtysh_install_default (BGP_VPNV4_NODE); + vtysh_install_default (BGP_VPNV6_NODE); vtysh_install_default (BGP_IPV4_NODE); vtysh_install_default (BGP_IPV4M_NODE); vtysh_install_default (BGP_IPV6_NODE); @@ -2337,6 +2371,8 @@ vtysh_init_vty (void) install_element (BGP_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_VPNV4_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_VPNV6_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); @@ -2368,6 +2404,7 @@ vtysh_init_vty (void) install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd); install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd); + install_element (BGP_VPNV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element (ISIS_NODE, &vtysh_end_all_cmd); @@ -2394,6 +2431,8 @@ vtysh_init_vty (void) install_element (CONFIG_NODE, &router_bgp_view_cmd); install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); + install_element (BGP_NODE, &address_family_vpnv6_cmd); + install_element (BGP_NODE, &address_family_vpnv6_unicast_cmd); install_element (BGP_NODE, &address_family_ipv4_unicast_cmd); install_element (BGP_NODE, &address_family_ipv4_multicast_cmd); #ifdef HAVE_IPV6 @@ -2401,6 +2440,7 @@ vtysh_init_vty (void) install_element (BGP_NODE, &address_family_ipv6_unicast_cmd); #endif install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); + install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 94dc995cc..dcbb70f4a 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -169,6 +169,9 @@ vtysh_config_parse_line (const char *line) if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0) config = config_get (BGP_VPNV4_NODE, line); + else if (strncmp (line, " address-family vpn6", + strlen (" address-family vpn6")) == 0) + config = config_get (BGP_VPNV6_NODE, line); else if (strncmp (line, " address-family ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0) config = config_get (BGP_IPV4M_NODE, line); From 82dd707988b7481e203cab058c92f0b3041dd558 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:57 -0500 Subject: [PATCH 0941/1342] bgpd: improve cleanup in bgp_delete() Signed-off-by: Lou Berger --- bgpd/bgp_nexthop.c | 21 +++++++++ bgpd/bgp_nexthop.h | 2 + bgpd/bgp_route.c | 105 ++++++++++++++++++++++++++++++++++++-------- bgpd/bgp_route.h | 3 ++ bgpd/bgp_routemap.c | 3 ++ bgpd/bgp_vty.c | 4 +- bgpd/bgp_zebra.c | 10 +++++ bgpd/bgp_zebra.h | 1 + bgpd/bgpd.c | 19 ++++++++ bgpd/bgpd.h | 1 + vtysh/vtysh.c | 2 +- 11 files changed, 150 insertions(+), 21 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index fa2f48822..d1c5c8643 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -591,6 +591,14 @@ bgp_address_init (void) bgp_address_hash_cmp); } +void +bgp_address_destroy (void) +{ + hash_clean(bgp_address_hash, NULL); + hash_free(bgp_address_hash); + bgp_address_hash = NULL; +} + static void bgp_address_add (struct prefix *p) { @@ -1467,3 +1475,16 @@ bgp_scan_finish (void) bgp_connected_table[AFI_IP6] = NULL; #endif /* HAVE_IPV6 */ } + +void +bgp_scan_destroy (void) +{ + if (zlookup == NULL) + return; + THREAD_OFF(bgp_import_thread); + THREAD_OFF(bgp_scan_thread); + THREAD_OFF(zlookup->t_connect); + bgp_scan_finish(); + zclient_free (zlookup); + zlookup = NULL; +} diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index c8aef58ba..85c5a5d07 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -66,5 +66,7 @@ extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (struct attr *); extern void bgp_address_init (void); +extern void bgp_address_destroy (void); +extern void bgp_scan_destroy (void); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ff541e845..868fbe56e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3051,6 +3051,57 @@ bgp_clear_route_all (struct peer *peer) bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); } +/* + * Finish freeing things when exiting + */ +static void +bgp_drain_workqueue_immediate (struct work_queue *wq) +{ + if (!wq) + return; + + if (!wq->thread) + { + /* + * no thread implies no queued items + */ + assert(!wq->items->count); + return; + } + + while (wq->items->count) + { + if (wq->thread) + thread_cancel(wq->thread); + work_queue_run(wq->thread); + } +} + +/* + * Special function to process clear node queue when bgpd is exiting + * and the thread scheduler is no longer running. + */ +void +bgp_peer_clear_node_queue_drain_immediate(struct peer *peer) +{ + if (!peer) + return; + + bgp_drain_workqueue_immediate(peer->clear_node_queue); +} + +/* + * The work queues are not specific to a BGP instance, but the + * items in them refer to BGP instances, so this should be called + * before each BGP instance is deleted. + */ +void +bgp_process_queues_drain_immediate(void) +{ + bgp_drain_workqueue_immediate(bm->process_main_queue); + bgp_drain_workqueue_immediate(bm->process_rsclient_queue); +} + void bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi) { @@ -3091,35 +3142,53 @@ bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi) } } +static void +bgp_cleanup_table(struct bgp_table *table, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_info *next; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ri = rn->info; ri; ri = next) + { + next = ri->next; + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_withdraw (&rn->p, ri, safi); + } +} + /* Delete all kernel routes. */ void bgp_cleanup_routes (void) { struct bgp *bgp; struct listnode *node, *nnode; - struct bgp_node *rn; - struct bgp_table *table; - struct bgp_info *ri; + afi_t afi; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { - table = bgp->rib[AFI_IP][SAFI_UNICAST]; - - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - for (ri = rn->info; ri; ri = ri->next) - if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) - && ri->type == ZEBRA_ROUTE_BGP - && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); + for (afi = AFI_IP; afi < AFI_MAX; ++afi) + { + struct bgp_node *rn; - table = bgp->rib[AFI_IP6][SAFI_UNICAST]; + bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST); - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - for (ri = rn->info; ri; ri = ri->next) - if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) - && ri->type == ZEBRA_ROUTE_BGP - && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); + /* + * VPN and ENCAP tables are two-level (RD is top level) + */ + for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn; + rn = bgp_route_next (rn)) + if (rn->info) + { + bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN); + bgp_table_finish ((struct bgp_table **)&(rn->info)); + rn->info = NULL; + bgp_unlock_node(rn); + } + } } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 0482c6fc6..5a93b445a 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -244,4 +244,7 @@ extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); +extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer); +extern void bgp_process_queues_drain_immediate (void); + #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 7555ca77b..b449cae0c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2295,6 +2295,9 @@ bgp_route_map_update (const char *unused) struct bgp_node *bn; struct bgp_static *bgp_static; + if (bm->bgp == NULL) /* may be called during cleanup */ + return; + /* For neighbor route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 304da2536..041a6a1fa 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9825,9 +9825,9 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd); - install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); - install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor maximum-prefix" commands. */ install_element (BGP_NODE, &neighbor_maximum_prefix_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4a25aa91c..1be4440a4 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1081,3 +1081,13 @@ bgp_zebra_init (struct thread_master *master) bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } + +void +bgp_zebra_destroy(void) +{ + if (zclient == NULL) + return; + zclient_stop(zclient); + zclient_free(zclient); + zclient = NULL; +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 50f727df6..ff9b375b0 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA. */ extern struct stream *bgp_nexthop_buf; extern void bgp_zebra_init (struct thread_master *master); +extern void bgp_zebra_destroy (void); extern int bgp_if_update_all (void); extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, safi_t, int *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d9c32cee5..636f56934 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1377,6 +1377,9 @@ peer_delete (struct peer *peer) } } + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETING)) + bgp_peer_clear_node_queue_drain_immediate(peer); + peer_unlock (peer); /* initial reference */ return 0; @@ -2165,6 +2168,8 @@ bgp_delete (struct bgp *bgp) afi_t afi; int i; + SET_FLAG(bgp->flags, BGP_FLAG_DELETING); + THREAD_OFF (bgp->t_startup); /* Delete static route. */ @@ -2206,7 +2211,21 @@ bgp_delete (struct bgp *bgp) peer_delete(bgp->peer_self); bgp->peer_self = NULL; } + + /* + * Free pending deleted routes. Unfortunately, it also has to process + * all the pending activity for other instances of struct bgp. + * + * This call was added to achieve clean memory allocation at exit, + * for the sake of valgrind. + */ + bgp_process_queues_drain_immediate(); + + bgp_zebra_destroy(); + bgp_scan_destroy(); + bgp_address_destroy(); + /* Remove visibility via the master list - there may however still be * routes to be processed still referencing the struct bgp. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 2c4fb2096..0b3d449c0 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -123,6 +123,7 @@ struct bgp #define BGP_FLAG_GRACEFUL_RESTART (1 << 12) #define BGP_FLAG_ASPATH_CONFED (1 << 13) #define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14) +#define BGP_FLAG_DELETING (1 << 15) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 418e5d767..a39889d00 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -280,7 +280,7 @@ vtysh_execute_func (const char *line, int pager) * to move into node in the vtysh where it succeeded. */ if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING) { - if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE + if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE || saved_node == BGP_IPV6M_NODE) From d5d5e3e04fc41b9a89b7ce9049fd322bdbde2e4d Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:58 -0500 Subject: [PATCH 0942/1342] bgpd: tests - add null pointer protection to fix bgp test failures Signed-off-by: Lou Berger --- bgpd/bgp_nexthop.c | 3 +++ tests/bgp_mpath_test.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index d1c5c8643..bb07eace1 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -594,6 +594,9 @@ bgp_address_init (void) void bgp_address_destroy (void) { + if (bgp_address_hash == NULL) + return; + hash_clean(bgp_address_hash, NULL); hash_free(bgp_address_hash); bgp_address_hash = NULL; diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index a953ce9ed..174d29987 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -395,7 +395,8 @@ global_test_init (void) static int global_test_cleanup (void) { - zclient_free (zclient); + if (zclient != NULL) + zclient_free (zclient); thread_master_free (master); return 0; } From 050defe816e4bd4cac7b028f69e45cb1974ca96d Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:41:59 -0500 Subject: [PATCH 0943/1342] bgpd: general MP/SAFI improvements This fixes some minor mixups particularly in MPLS-related SAFIs, as well as doing some stylistic changes & adding comments. Signed-off-by: Lou Berger Reviewed-by: David Lamparter --- bgpd/bgp_attr.c | 79 +++++++++++++++++++++++++++------------------ bgpd/bgp_attr.h | 2 ++ bgpd/bgp_mplsvpn.c | 19 +++-------- bgpd/bgp_mplsvpn.h | 1 - bgpd/bgp_packet.c | 23 +++++++++---- bgpd/bgp_route.c | 35 ++++++++++++++------ bgpd/bgp_route.h | 2 +- bgpd/bgp_routemap.c | 1 + 8 files changed, 98 insertions(+), 64 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ecf1c3146..a25ea7640 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1613,7 +1613,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, if (safi != SAFI_MPLS_LABELED_VPN) { - ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); + ret = bgp_nlri_sanity_check (peer, afi, safi, stream_pnt (s), nlri_len); if (ret < 0) { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", @@ -1662,7 +1662,7 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, if (safi != SAFI_MPLS_LABELED_VPN) { - ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); + ret = bgp_nlri_sanity_check (peer, afi, safi, stream_pnt (s), withdraw_len); if (ret < 0) return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -2160,8 +2160,9 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, stream_putc (s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); stream_putw (s, 0); /* Marker: Attribute length. */ - stream_putw (s, afi); /* AFI */ - stream_putc (s, safi); /* SAFI */ + + stream_putw (s, afi); + stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi); /* Nexthop */ switch (afi) @@ -2169,17 +2170,17 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, case AFI_IP: switch (safi) { - case SAFI_UNICAST: case SAFI_MULTICAST: stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); break; case SAFI_MPLS_VPN: stream_putc (s, 12); - stream_putl (s, 0); + stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; + case SAFI_UNICAST: /* invalid for IPv4 */ default: break; } @@ -2199,6 +2200,28 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, if (attre->mp_nexthop_len == 32) stream_put (s, &attre->mp_nexthop_local, 16); } + break; + case SAFI_MPLS_VPN: + { + struct attr_extra *attre = attr->extra; + + assert (attr->extra); + if (attre->mp_nexthop_len == 16) { + stream_putc (s, 24); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attre->mp_nexthop_global, 16); + } else if (attre->mp_nexthop_len == 32) { + stream_putc (s, 48); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attre->mp_nexthop_global, 16); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attre->mp_nexthop_local, 16); + } + } + break; default: break; } @@ -2218,20 +2241,25 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag) { - switch (safi) + if (safi == SAFI_MPLS_VPN) { - case SAFI_MPLS_VPN: /* Tag, RD, Prefix write. */ stream_putc (s, p->prefixlen + 88); stream_put (s, tag, 3); stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); - break; - default: - /* Prefix write. */ - stream_put_prefix (s, p); - break; } + else + stream_put_prefix (s, p); +} + +size_t +bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p) +{ + int size = PSIZE (p->prefixlen); + if (safi == SAFI_MPLS_VPN) + size += 88; + return size; } void @@ -2255,7 +2283,6 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, int send_as4_path = 0; int send_as4_aggregator = 0; int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; - size_t mpattrlen_pos = 0; if (! bgp) bgp = bgp_get_default (); @@ -2265,6 +2292,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (p && !(afi == AFI_IP && safi == SAFI_UNICAST)) { + size_t mpattrlen_pos = 0; mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr); bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag); bgp_packet_mpattr_end(s, mpattrlen_pos); @@ -2338,7 +2366,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, send_as4_path = 1; /* we'll do this later, at the correct place */ /* Nexthop attribute. */ - if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP && + safi == SAFI_UNICAST) /* only write NH attr for unicast safi */ { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_NEXT_HOP); @@ -2612,8 +2641,7 @@ bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi) stream_putw (s, 0); /* Length of this attribute. */ stream_putw (s, afi); - safi = (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi; - stream_putc (s, safi); + stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi); return attrlen_pnt; } @@ -2622,26 +2650,13 @@ bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { - if (safi == SAFI_MPLS_VPN) - { - stream_putc (s, p->prefixlen + 88); - stream_put (s, tag, 3); - stream_put (s, prd->val, 8); - stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); - } - else - stream_put_prefix (s, p); + bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag); } void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt) { - bgp_size_t size; - - /* Set MP attribute length. Don't count the (2) bytes used to encode - the attr length */ - size = stream_get_endp (s) - attrlen_pnt - 2; - stream_putw_at (s, attrlen_pnt, size); + bgp_packet_mpattr_end (s, attrlen_pnt); } /* Initialization of attribute. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index b59fa8e4d..6fdf1c1ac 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -205,6 +205,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi, extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag); +extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, + struct prefix *p); extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep); extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 78a71e70c..e92266513 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -178,13 +178,10 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, decode_rd_ip (pnt + 5, &rd_ip); break; - case RD_TYPE_EOI: - break; - - default: - zlog_err ("Invalid RD type %d", type); - return -1; - } + default: + zlog_err ("Unknown RD type %d", type); + break; /* just report */ + } p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8; memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, @@ -323,14 +320,6 @@ prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); return buf; } - else if (type == RD_TYPE_EOI) - { - snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", - pnt[1], /* LHI */ - pnt[2], pnt[3], pnt[4], pnt[5], pnt[6], pnt[7]); /* MAC */ - return buf; - } - return NULL; } diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 4e9b317b7..3299b9cb9 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -24,7 +24,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define RD_TYPE_AS 0 #define RD_TYPE_IP 1 #define RD_TYPE_AS4 2 -#define RD_TYPE_EOI 0xff00 #define RD_ADDRSTRLEN 28 diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 16e1435a0..841eaab88 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -172,16 +172,24 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) /* When remaining space can't include NLRI and it's length. */ if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <= - (BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen))) + (BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size(afi,safi,&rn->p))) break; /* If packet is empty, set attribute. */ if (stream_empty (s)) { + struct prefix_rd *prd = NULL; + u_char *tag = NULL; struct peer *from = NULL; + if (rn->prn) + prd = (struct prefix_rd *) &rn->prn->p; if (binfo) - from = binfo->peer; + { + from = binfo->peer; + if (binfo->extra) + tag = binfo->extra->tag; + } /* 1: Write the BGP message header - 16 bytes marker, 2 bytes length, * one byte message type. @@ -204,8 +212,8 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, - NULL, afi, safi, - from, NULL, NULL); + &rn->p, afi, safi, + from, prd, tag); } if (afi == AFI_IP && safi == SAFI_UNICAST) @@ -1653,7 +1661,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { - ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); + ret = bgp_nlri_sanity_check (peer, AFI_IP, SAFI_UNICAST, stream_pnt (s), withdraw_len); if (ret < 0) return -1; @@ -1713,6 +1721,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) { bgp_attr_unintern_sub (&attr); + bgp_attr_flush (&attr); return -1; } } @@ -1744,10 +1753,11 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (update_len) { /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); + ret = bgp_nlri_sanity_check (peer, AFI_IP, SAFI_UNICAST, stream_pnt (s), update_len); if (ret < 0) { bgp_attr_unintern_sub (&attr); + bgp_attr_flush (&attr); return -1; } @@ -1933,6 +1943,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&attr); + bgp_attr_flush (&attr); /* If peering is stopped due to some reason, do not generate BGP event. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 868fbe56e..b024d80d8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1480,6 +1480,9 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, struct attr attr; struct attr_extra extra; + memset (&attr, 0, sizeof(struct attr)); + memset (&extra, 0, sizeof(struct attr_extra)); + p = &rn->p; /* Announce route to Established peer. */ @@ -1519,6 +1522,7 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, break; } + bgp_attr_flush (&attr); return 0; } @@ -1661,7 +1665,7 @@ bgp_process_main (struct work_queue *wq, void *data) } } - /* Reap old select bgp_info, it it has been removed */ + /* Reap old select bgp_info, if it has been removed */ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); @@ -1869,7 +1873,7 @@ bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, static void bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, - afi_t afi, safi_t safi) + afi_t afi, safi_t safi, struct prefix_rd *prd) { int status = BGP_DAMP_NONE; @@ -1991,7 +1995,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); - + bgp_attr_flush(&new_attr); return; } @@ -2099,7 +2103,7 @@ bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) - bgp_rib_withdraw (rn, ri, peer, afi, safi); + bgp_rib_withdraw (rn, ri, peer, afi, safi, prd); else if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s Can't find the route %s/%d", peer->host, @@ -2274,6 +2278,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); + bgp_attr_flush (&new_attr); return 0; } @@ -2326,6 +2331,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); + bgp_attr_flush (&new_attr); + /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP) @@ -2355,6 +2362,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, else bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + bgp_attr_flush (&new_attr); + /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); @@ -2410,6 +2419,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* route_node_get lock */ bgp_unlock_node (rn); + bgp_attr_flush (&new_attr); + /* If maximum prefix count is configured and current prefix count exeed it. */ if (bgp_maximum_prefix_overflow (peer, afi, safi, 0)) @@ -2434,6 +2445,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_rib_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); + bgp_attr_flush (&new_attr); return 0; } @@ -2520,7 +2532,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) - bgp_rib_withdraw (rn, ri, peer, afi, safi); + bgp_rib_withdraw (rn, ri, peer, afi, safi, prd); else if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s Can't find the route %s/%d", peer->host, @@ -3006,8 +3018,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, * unlock happens at the end of this function. */ if (!peer->clear_node_queue->thread) - peer_lock (peer); - + peer_lock (peer); /* bgp_clear_node_complete */ switch (purpose) { case BGP_CLEAR_ROUTE_NORMAL: @@ -3026,6 +3037,11 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, break; case BGP_CLEAR_ROUTE_MY_RSCLIENT: + /* + * gpz 091009: TBD why don't we have special handling for + * SAFI_MPLS_VPN here in the original quagga code? + * (and, by extension, for SAFI_ENCAP) + */ bgp_clear_route_table (peer, afi, safi, NULL, peer, purpose); break; @@ -3304,8 +3320,8 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) /* NLRI encode syntax check routine. */ int -bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, - bgp_size_t length) +bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi, + u_char *pnt, bgp_size_t length) { u_char *end; u_char prefixlen; @@ -6739,6 +6755,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, struct bgp_info *ri; struct bgp_table *table; + memset (&match, 0, sizeof (struct prefix)); /* keep valgrind happy */ /* Check IP address argument. */ ret = str2prefix (ip_str, &match); if (! ret) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 5a93b445a..8e9bcbd1c 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -196,7 +196,7 @@ extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *); extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); -extern int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t); +extern int bgp_nlri_sanity_check (struct peer *, int, safi_t, u_char *, bgp_size_t); extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b449cae0c..a6d5a0e1c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2090,6 +2090,7 @@ route_set_vpnv4_nexthop (void *rule, struct prefix *prefix, /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address; + (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = 4; } return RMAP_OKAY; From 5a81fc9ae610ff343902ebabc12237d6e40d91cb Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:00 -0500 Subject: [PATCH 0944/1342] bgpd: encap: extend extcommunity handling Add code to print ENCAP communities. Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- bgpd/bgp_ecommunity.c | 37 ++++++++++++++++++++++++++++--------- bgpd/bgp_ecommunity.h | 6 +++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index c76f01e3d..5d69b42c3 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -643,15 +643,34 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) /* High-order octet of type. */ encode = *pnt++; - if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP - && encode != ECOMMUNITY_ENCODE_AS4) - { - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - } - + + switch (encode) + { + case ECOMMUNITY_ENCODE_AS: + case ECOMMUNITY_ENCODE_IP: + case ECOMMUNITY_ENCODE_AS4: + break; + + case ECOMMUNITY_ENCODE_OPAQUE: + if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) + { + uint16_t tunneltype; + memcpy (&tunneltype, pnt + 5, 2); + tunneltype = ntohs(tunneltype); + len = sprintf (str_buf + str_pnt, "ET:%d", tunneltype); + str_pnt += len; + first = 0; + continue; + } + /* fall through */ + + default: + len = sprintf (str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + } + /* Low-order octet of type. */ type = *pnt++; if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN) diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 92affccca..993fd5acf 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -25,11 +25,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 #define ECOMMUNITY_ENCODE_AS4 0x02 +#define ECOMMUNITY_ENCODE_OPAQUE 0x03 -/* Low-order octet of the Extended Communityes type field. */ +/* Low-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 +/* Low-order octet of the Extended Communities type field for OPAQUE types */ +#define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c + /* Extended communities attribute string format. */ #define ECOMMUNITY_FORMAT_ROUTE_MAP 0 #define ECOMMUNITY_FORMAT_COMMUNITY_LIST 1 From c3741789530ee824693fd606356acac2ad695f83 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:01 -0500 Subject: [PATCH 0945/1342] bgpd: encap: add attribute handling Signed-off-by: Lou Berger Reviewed-by: David Lamparter --- bgpd/Makefile.am | 6 +- bgpd/bgp_attr.c | 327 ++++++++++++++- bgpd/bgp_attr.h | 16 + bgpd/bgp_encap_tlv.c | 874 +++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_encap_tlv.h | 177 +++++++++ bgpd/bgp_encap_types.h | 174 ++++++++ bgpd/bgpd.h | 1 + lib/memtypes.c | 1 + 8 files changed, 1573 insertions(+), 3 deletions(-) create mode 100644 bgpd/bgp_encap_tlv.c create mode 100644 bgpd/bgp_encap_tlv.h create mode 100644 bgpd/bgp_encap_types.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index a35ad870f..82c69eac4 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -15,14 +15,16 @@ libbgp_a_SOURCES = \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ - bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c + bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ + bgp_encap_tlv.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ - bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h + bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ + bgp_encap_tlv.h bgp_encap_types.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a25ea7640..b019347bf 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -39,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" +#include "table.h" +#include "bgp_encap_types.h" /* Attribute strings for logging. */ static const struct message attr_str [] = @@ -62,6 +64,7 @@ static const struct message attr_str [] = { BGP_ATTR_AS4_PATH, "AS4_PATH" }, { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, + { BGP_ATTR_ENCAP, "ENCAP" }, }; static const int attr_str_max = array_size(attr_str); @@ -209,6 +212,105 @@ cluster_finish (void) cluster_hash = NULL; } +struct bgp_attr_encap_subtlv * +encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) +{ + struct bgp_attr_encap_subtlv *new; + struct bgp_attr_encap_subtlv *tail; + struct bgp_attr_encap_subtlv *p; + + for (p = orig, tail = new = NULL; p; p = p->next) { + int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length; + if (tail) { + tail->next = XCALLOC(MTYPE_ENCAP_TLV, size); + tail = tail->next; + } else { + tail = new = XCALLOC(MTYPE_ENCAP_TLV, size); + } + assert(tail); + memcpy(tail, p, size); + tail->next = NULL; + } + + return new; +} + +static void +encap_free(struct bgp_attr_encap_subtlv *p) +{ + struct bgp_attr_encap_subtlv *next; + while (p) { + next = p->next; + p->next = NULL; + XFREE(MTYPE_ENCAP_TLV, p); + p = next; + } +} + +void +bgp_attr_flush_encap(struct attr *attr) +{ + if (!attr || !attr->extra) + return; + + if (attr->extra->encap_subtlvs) { + encap_free(attr->extra->encap_subtlvs); + attr->extra->encap_subtlvs = NULL; + } +} + +/* + * Compare encap sub-tlv chains + * + * 1 = equivalent + * 0 = not equivalent + * + * This algorithm could be made faster if needed + */ +static int +encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2) +{ + struct bgp_attr_encap_subtlv *p; + struct bgp_attr_encap_subtlv *q; + + if (!h1 && !h2) + return 1; + if (h1 && !h2) + return 0; + if (!h1 && h2) + return 0; + if (h1 == h2) + return 1; + + for (p = h1; p; p = p->next) { + for (q = h2; q; q = q->next) { + if ((p->type == q->type) && + (p->length == q->length) && + !memcmp(p->value, q->value, p->length)) { + + break; + } + } + if (!q) + return 0; + } + + for (p = h2; p; p = p->next) { + for (q = h1; q; q = q->next) { + if ((p->type == q->type) && + (p->length == q->length) && + !memcmp(p->value, q->value, p->length)) { + + break; + } + } + if (!q) + return 0; + } + + return 1; +} + /* Unknown transit attribute. */ static struct hash *transit_hash; @@ -300,6 +402,10 @@ bgp_attr_extra_free (struct attr *attr) { if (attr->extra) { + if (attr->extra->encap_subtlvs) { + encap_free(attr->extra->encap_subtlvs); + attr->extra->encap_subtlvs = NULL; + } XFREE (MTYPE_ATTR_EXTRA, attr->extra); attr->extra = NULL; } @@ -335,13 +441,20 @@ bgp_attr_dup (struct attr *new, struct attr *orig) { new->extra = extra; memset(new->extra, 0, sizeof(struct attr_extra)); - if (orig->extra) + if (orig->extra) { *new->extra = *orig->extra; + if (orig->extra->encap_subtlvs) { + new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); + } + } } else if (orig->extra) { new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; + if (orig->extra->encap_subtlvs) { + new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); + } } } @@ -438,6 +551,8 @@ attrhash_cmp (const void *p1, const void *p2) && ae1->ecommunity == ae2->ecommunity && ae1->cluster == ae2->cluster && ae1->transit == ae2->transit + && (ae1->encap_tunneltype == ae2->encap_tunneltype) + && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs) && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) return 1; else if (ae1 || ae2) @@ -503,6 +618,10 @@ bgp_attr_hash_alloc (void *p) { attr->extra = bgp_attr_extra_new (); *attr->extra = *val->extra; + + if (attr->extra->encap_subtlvs) { + attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs); + } } attr->refcnt = 0; return attr; @@ -592,6 +711,9 @@ bgp_attr_default_intern (u_char origin) struct attr attr; struct attr *new; + memset (&attr, 0, sizeof (struct attr)); + bgp_attr_extra_get (&attr); + bgp_attr_default_set(&attr, origin); new = bgp_attr_intern (&attr); @@ -731,6 +853,8 @@ bgp_attr_flush (struct attr *attr) cluster_free (attre->cluster); if (attre->transit && ! attre->transit->refcnt) transit_free (attre->transit); + encap_free(attre->encap_subtlvs); + attre->encap_subtlvs = NULL; } } @@ -1710,6 +1834,122 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) return BGP_ATTR_PARSE_PROCEED; } +/* Parse Tunnel Encap attribute in an UPDATE */ +static int +bgp_attr_encap( + uint8_t type, + struct peer *peer, /* IN */ + bgp_size_t length, /* IN: attr's length field */ + struct attr *attr, /* IN: caller already allocated */ + u_char flag, /* IN: attr's flags field */ + u_char *startp) +{ + bgp_size_t total; + struct attr_extra *attre = NULL; + struct bgp_attr_encap_subtlv *stlv_last = NULL; + uint16_t tunneltype; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) + || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) + { + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute flag isn't optional and transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + if (BGP_ATTR_ENCAP == type) { + /* read outer TLV type and length */ + uint16_t tlv_length; + + if (length < 4) { + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute not long enough to contain outer T,L"); + bgp_notify_send_with_data(peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + return -1; + } + tunneltype = stream_getw (BGP_INPUT (peer)); + tlv_length = stream_getw (BGP_INPUT (peer)); + length -= 4; + + if (tlv_length != length) { + zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)", + __func__, tlv_length, length); + } + } + + while (length >= 4) { + uint16_t subtype; + uint16_t sublength; + struct bgp_attr_encap_subtlv *tlv; + + subtype = stream_getw (BGP_INPUT (peer)); + sublength = stream_getw (BGP_INPUT (peer)); + length -= 4; + + if (sublength > length) { + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", + sublength, length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + return -1; + } + + /* alloc and copy sub-tlv */ + /* TBD make sure these are freed when attributes are released */ + tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength); + tlv->type = subtype; + tlv->length = sublength; + stream_get(tlv->value, peer->ibuf, sublength); + length -= sublength; + + /* attach tlv to encap chain */ + if (!attre) { + attre = bgp_attr_extra_get(attr); + if (BGP_ATTR_ENCAP == type) { + for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next; + stlv_last = stlv_last->next); + if (stlv_last) { + stlv_last->next = tlv; + } else { + attre->encap_subtlvs = tlv; + } + } + } else { + stlv_last->next = tlv; + } + stlv_last = tlv; + } + + if (attre && (BGP_ATTR_ENCAP == type)) { + attre->encap_tunneltype = tunneltype; + } + + if (length) { + /* spurious leftover data */ + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute length is bad: %d leftover octets", length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + return -1; + } + + return 0; +} + /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) @@ -2008,6 +2248,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (&attr_args); break; + case BGP_ATTR_ENCAP: + ret = bgp_attr_encap (type, peer, length, attr, flag, startp); + break; default: ret = bgp_attr_unknown (&attr_args); break; @@ -2262,6 +2505,88 @@ bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p) return size; } +/* + * Encodes the tunnel encapsulation attribute + */ +static void +bgp_packet_mpattr_tea( + struct bgp *bgp, + struct peer *peer, + struct stream *s, + struct attr *attr, + uint8_t attrtype) +{ + unsigned int attrlenfield = 0; + struct bgp_attr_encap_subtlv *subtlvs; + struct bgp_attr_encap_subtlv *st; + const char *attrname; + + if (!attr || !attr->extra) + return; + + switch (attrtype) { + case BGP_ATTR_ENCAP: + attrname = "Tunnel Encap"; + subtlvs = attr->extra->encap_subtlvs; + + /* + * The tunnel encap attr has an "outer" tlv. + * T = tunneltype, + * L = total length of subtlvs, + * V = concatenated subtlvs. + */ + attrlenfield = 2 + 2; /* T + L */ + break; + + default: + assert(0); + } + + + /* compute attr length */ + for (st = subtlvs; st; st = st->next) { + attrlenfield += (4 + st->length); + } + + /* if no tlvs, don't make attr */ + if (!attrlenfield) + return; + + if (attrlenfield > 0xffff) { + zlog (peer->log, LOG_ERR, + "%s attribute is too long (length=%d), can't send it", + attrname, + attrlenfield); + return; + } + + if (attrlenfield > 0xff) { + /* 2-octet length field */ + stream_putc (s, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, attrtype); + stream_putw (s, attrlenfield & 0xffff); + } else { + /* 1-octet length field */ + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, attrtype); + stream_putc (s, attrlenfield & 0xff); + } + + if (attrtype == BGP_ATTR_ENCAP) { + /* write outer T+L */ + stream_putw(s, attr->extra->encap_tunneltype); + stream_putw(s, attrlenfield - 4); + } + + /* write each sub-tlv */ + for (st = subtlvs; st; st = st->next) { + stream_putw (s, st->type); + stream_putw (s, st->length); + stream_put (s, st->value, st->length); + } +} + void bgp_packet_mpattr_end (struct stream *s, size_t sizep) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6fdf1c1ac..6a134de4f 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -47,6 +47,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_ATTR_MIN_LEN 3 /* Attribute flag, type length. */ #define BGP_ATTR_DEFAULT_WEIGHT 32768 +struct bgp_attr_encap_subtlv { + struct bgp_attr_encap_subtlv *next; /* for chaining */ + uint16_t type; + uint16_t length; + uint8_t value[1]; /* will be extended */ +}; + /* Additional/uncommon BGP attributes. * lazily allocated as and when a struct attr * requires it. @@ -85,6 +92,9 @@ struct attr_extra /* MP Nexthop length */ u_char mp_nexthop_len; + + uint16_t encap_tunneltype; /* grr */ + struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ }; /* BGP core attribute structure. */ @@ -194,6 +204,12 @@ extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); +extern struct bgp_attr_encap_subtlv * +encap_tlv_dup(struct bgp_attr_encap_subtlv *orig); + +extern void +bgp_attr_flush_encap(struct attr *attr); + /** * Set of functions to encode MP_REACH_NLRI and MP_UNREACH_NLRI attributes. * Typical call sequence is to call _start(), followed by multiple _prefix(), diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c new file mode 100644 index 000000000..058b41eb5 --- /dev/null +++ b/bgpd/bgp_encap_tlv.c @@ -0,0 +1,874 @@ +/* + * Copyright 2015, LabN Consulting, L.L.C. + * + * This program 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 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "memory.h" +#include "prefix.h" +#include "vty.h" +#include "filter.h" + +#include "bgpd.h" +#include "bgp_attr.h" + +#include "bgp_encap_types.h" +#include "bgp_encap_tlv.h" + +/*********************************************************************** + * SUBTLV ENCODE + ***********************************************************************/ + +/* rfc5512 4.1 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_encap_l2tpv3_over_ip( + struct bgp_tea_subtlv_encap_l2tpv3_over_ip *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 4 + st->cookie_length; + + /* sanity check */ + assert(st->cookie_length <= sizeof(st->cookie)); + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; + new->length = total; + p = new->value; + + *p++ = (st->sessionid & 0xff000000) >> 24; + *p++ = (st->sessionid & 0xff0000) >> 16; + *p++ = (st->sessionid & 0xff00) >> 8; + *p++ = (st->sessionid & 0xff); + memcpy(p, st->cookie, st->cookie_length); + return new; +} + +/* rfc5512 4.1 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_encap_gre( + struct bgp_tea_subtlv_encap_gre_key *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 4; + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; + new->length = total; + p = new->value; + + *p++ = (st->gre_key & 0xff000000) >> 24; + *p++ = (st->gre_key & 0xff0000) >> 16; + *p++ = (st->gre_key & 0xff00) >> 8; + *p++ = (st->gre_key & 0xff); + return new; +} + +static struct bgp_attr_encap_subtlv * +subtlv_encode_encap_pbb( + struct bgp_tea_subtlv_encap_pbb *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 1 + 3 + 6 + 2; /* flags + isid + madaddr + vid */ + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; + new->length = total; + p = new->value; + + *p++ = (st->flag_isid? 0x80: 0) | + (st->flag_vid? 0x40: 0) | + 0; + if (st->flag_isid) { + *p = (st->isid & 0xff0000) >> 16; + *(p+1) = (st->isid & 0xff00) >> 8; + *(p+2) = (st->isid & 0xff); + } + p += 3; + memcpy(p, st->macaddr, 6); + p += 6; + if (st->flag_vid) { + *p++ = (st->vid & 0xf00) >> 8; + *p++ = st->vid & 0xff; + } + return new; +} + +/* rfc5512 4.2 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_proto_type( + struct bgp_tea_subtlv_proto_type *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 2; + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE; + new->length = total; + p = new->value; + + *p++ = (st->proto & 0xff00) >> 8; + *p++ = (st->proto & 0xff); + return new; +} + +/* rfc5512 4.3 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_color( + struct bgp_tea_subtlv_color *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 8; + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_COLOR; + new->length = total; + p = new->value; + + *p++ = 0x03; /* transitive*/ + *p++ = 0x0b; + *p++ = 0; /* reserved */ + *p++ = 0; /* reserved */ + + *p++ = (st->color & 0xff000000) >> 24; + *p++ = (st->color & 0xff0000) >> 16; + *p++ = (st->color & 0xff00) >> 8; + *p++ = (st->color & 0xff); + + return new; +} + +/* rfc 5566 4. */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_ipsec_ta( + struct bgp_tea_subtlv_ipsec_ta *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 2 + st->authenticator_length; + + /* sanity check */ + assert(st->authenticator_length <= sizeof(st->value)); + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA; + new->length = total; + p = new->value; + + *p++ = (st->authenticator_type & 0xff00) >> 8; + *p++ = st->authenticator_type & 0xff; + memcpy(p, st->value, st->authenticator_length); + return new; +} + + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV ENCODE + ***********************************************************************/ + +/* + * requires "extra" and "last" to be defined in caller + */ +#define ENC_SUBTLV(flag, function, field) do {\ + struct bgp_attr_encap_subtlv *new;\ + if (CHECK_FLAG(bet->valid_subtlvs, (flag))) {\ + new = function(&bet->field);\ + if (last) {\ + last->next = new;\ + } else {\ + extra->encap_subtlvs = new;\ + }\ + last = new;\ + }\ +} while (0) + +void +bgp_encap_type_l2tpv3overip_to_tlv( + struct bgp_encap_type_l2tpv3_over_ip *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP; + + assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); + + ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_l2tpv3_over_ip, st_encap); + ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); + ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); +} + +void +bgp_encap_type_gre_to_tlv( + struct bgp_encap_type_gre *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_GRE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_gre, st_encap); + ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); + ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); +} + +void +bgp_encap_type_ip_in_ip_to_tlv( + struct bgp_encap_type_ip_in_ip *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP; + + ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); + ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); +} + +void +bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_encap_type_transmit_tunnel_endpoint *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT; + + /* no subtlvs for this type */ +} + +void +bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( + struct bgp_encap_type_ipsec_in_tunnel_mode *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); +} + +void +bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); +} + +void +bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); +} + +void +bgp_encap_type_pbb_to_tlv( + struct bgp_encap_type_pbb *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_PBB; + + assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); + ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_pbb, st_encap); +} + +void +bgp_encap_type_vxlan_to_tlv( + struct bgp_encap_type_vxlan *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN; +} + +void +bgp_encap_type_nvgre_to_tlv( + struct bgp_encap_type_nvgre *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE; +} + +void +bgp_encap_type_mpls_to_tlv( + struct bgp_encap_type_mpls *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS; +} + +void +bgp_encap_type_mpls_in_gre_to_tlv( + struct bgp_encap_type_mpls_in_gre *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE; +} + +void +bgp_encap_type_vxlan_gpe_to_tlv( + struct bgp_encap_type_vxlan_gpe *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE; +} + +void +bgp_encap_type_mpls_in_udp_to_tlv( + struct bgp_encap_type_mpls_in_udp *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP; +} + + +/*********************************************************************** + * SUBTLV DECODE + ***********************************************************************/ +/* rfc5512 4.1 */ +static int +subtlv_decode_encap_l2tpv3_over_ip( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_encap_l2tpv3_over_ip *st) +{ + if (subtlv->length < 4) { + zlog_debug("%s, subtlv length %d is less than 4", + __func__, subtlv->length); + return -1; + } + + st->sessionid = (subtlv->value[0] << 24) | + (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]; + st->cookie_length = subtlv->length - 4; + if (st->cookie_length > sizeof(st->cookie)) { + zlog_debug("%s, subtlv length %d is greater than %d", + __func__, st->cookie_length, (int)sizeof(st->cookie)); + return -1; + } + memcpy(st->cookie, subtlv->value + 4, st->cookie_length); + return 0; +} + +/* rfc5512 4.1 */ +static int +subtlv_decode_encap_gre( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_encap_gre_key *st) +{ + if (subtlv->length != 4) { + zlog_debug("%s, subtlv length %d does not equal 4", + __func__, subtlv->length); + return -1; + } + st->gre_key = (subtlv->value[0] << 24) | + (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]; + return 0; +} + +static int +subtlv_decode_encap_pbb( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_encap_pbb *st) +{ + if (subtlv->length != 1 + 3 + 6 + 2) { + zlog_debug("%s, subtlv length %d does not equal %d", + __func__, subtlv->length, 1 + 3 + 6 + 2); + return -1; + } + if (subtlv->value[0] & 0x80) { + st->flag_isid = 1; + st->isid = (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]; + } + if (subtlv->value[0] & 0x40) { + st->flag_vid = 1; + st->vid = ((subtlv->value[10] & 0x0f) << 8) | subtlv->value[11]; + } + memcpy(st->macaddr, subtlv->value + 4, 6); + return 0; +} + +/* rfc5512 4.2 */ +static int +subtlv_decode_proto_type( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_proto_type *st) +{ + if (subtlv->length != 2) { + zlog_debug("%s, subtlv length %d does not equal 2", + __func__, subtlv->length); + return -1; + } + st->proto = (subtlv->value[0] << 8) | subtlv->value[1]; + return 0; +} + +/* rfc5512 4.3 */ +static int +subtlv_decode_color( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_color *st) +{ + if (subtlv->length != 8) { + zlog_debug("%s, subtlv length %d does not equal 8", + __func__, subtlv->length); + return -1; + } + if ((subtlv->value[0] != 0x03) || + (subtlv->value[1] != 0x0b) || + (subtlv->value[2] != 0) || + (subtlv->value[3] != 0)) { + zlog_debug("%s, subtlv value 1st 4 bytes are not 0x030b0000", __func__); + return -1; + } + st->color = (subtlv->value[4] << 24) | + (subtlv->value[5] << 16) | + (subtlv->value[6] << 8) | + subtlv->value[7]; + return 0; +} + +/* rfc 5566 4. */ +static int +subtlv_decode_ipsec_ta( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_ipsec_ta *st) +{ + st->authenticator_length = subtlv->length - 2; + if (st->authenticator_length > sizeof(st->value)) { + zlog_debug("%s, authenticator length %d exceeds storage maximum %d", + __func__, st->authenticator_length, (int)sizeof(st->value)); + return -1; + } + st->authenticator_type = (subtlv->value[0] << 8) | subtlv->value[1]; + memcpy(st->value, subtlv->value + 2, st->authenticator_length); + return 0; +} + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV DECODE + ***********************************************************************/ + +int +tlv_to_bgp_encap_type_l2tpv3overip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_l2tpv3_over_ip *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: + rc |= subtlv_decode_encap_l2tpv3_over_ip(st, &bet->st_encap); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + break; + + case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: + rc |= subtlv_decode_proto_type(st, &bet->st_proto); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + break; + + case BGP_ENCAP_SUBTLV_TYPE_COLOR: + rc |= subtlv_decode_color(st, &bet->st_color); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_gre( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_gre *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: + rc |= subtlv_decode_encap_gre(st, &bet->st_encap); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + break; + + case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: + rc |= subtlv_decode_proto_type(st, &bet->st_proto); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + break; + + case BGP_ENCAP_SUBTLV_TYPE_COLOR: + rc |= subtlv_decode_color(st, &bet->st_color); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_ip_in_ip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ip_in_ip *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: + rc |= subtlv_decode_proto_type(st, &bet->st_proto); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + break; + + case BGP_ENCAP_SUBTLV_TYPE_COLOR: + rc |= subtlv_decode_color(st, &bet->st_color); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_transmit_tunnel_endpoint *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ipsec_in_tunnel_mode *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: + rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: + rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: + rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_vxlan( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_nvgre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_nvgre *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls_in_gre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_gre *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_vxlan_gpe( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan_gpe *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls_in_udp( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_udp *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_pbb( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_pbb *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: + rc |= subtlv_decode_encap_pbb(st, &bet->st_encap); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + diff --git a/bgpd/bgp_encap_tlv.h b/bgpd/bgp_encap_tlv.h new file mode 100644 index 000000000..d94d544d2 --- /dev/null +++ b/bgpd/bgp_encap_tlv.h @@ -0,0 +1,177 @@ +/* + * Copyright 2015, LabN Consulting, L.L.C. + * + * This program 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 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _QUAGGA_BGP_ENCAP_TLV_H +#define _QUAGGA_BGP_ENCAP_TLV_H + + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV ENCODE + ***********************************************************************/ + +extern void +bgp_encap_type_l2tpv3overip_to_tlv( + struct bgp_encap_type_l2tpv3_over_ip *bet, + struct attr *attr); + +extern void +bgp_encap_type_gre_to_tlv( + struct bgp_encap_type_gre *bet, + struct attr *attr); + +extern void +bgp_encap_type_ip_in_ip_to_tlv( + struct bgp_encap_type_ip_in_ip *bet, + struct attr *attr); + +extern void +bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_encap_type_transmit_tunnel_endpoint *bet, + struct attr *attr); + +extern void +bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( + struct bgp_encap_type_ipsec_in_tunnel_mode *bet, + struct attr *attr); + +extern void +bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, + struct attr *attr); + +extern void +bgp_encap_type_pbb_to_tlv( + struct bgp_encap_type_pbb *bet, + struct attr *attr); + +extern void +bgp_encap_type_vxlan_to_tlv( + struct bgp_encap_type_vxlan *bet, + struct attr *attr); + +extern void +bgp_encap_type_nvgre_to_tlv( + struct bgp_encap_type_nvgre *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_to_tlv( + struct bgp_encap_type_mpls *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_in_gre_to_tlv( + struct bgp_encap_type_mpls_in_gre *bet, + struct attr *attr); + +extern void +bgp_encap_type_vxlan_gpe_to_tlv( + struct bgp_encap_type_vxlan_gpe *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_in_udp_to_tlv( + struct bgp_encap_type_mpls_in_udp *bet, + struct attr *attr); + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV DECODE + ***********************************************************************/ + +extern int +tlv_to_bgp_encap_type_l2tpv3overip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_l2tpv3_over_ip *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_gre( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_gre *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_ip_in_ip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ip_in_ip *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_transmit_tunnel_endpoint *bet); + +extern int +tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ipsec_in_tunnel_mode *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet); + +extern int +tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet); + +extern int +tlv_to_bgp_encap_type_vxlan( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan *bet); + +extern int +tlv_to_bgp_encap_type_nvgre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_nvgre *bet); + +extern int +tlv_to_bgp_encap_type_mpls( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls *bet); + +extern int +tlv_to_bgp_encap_type_mpls( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls *bet); + +extern int +tlv_to_bgp_encap_type_mpls_in_gre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_gre *bet); + +extern int +tlv_to_bgp_encap_type_vxlan_gpe( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan_gpe *bet); + +extern int +tlv_to_bgp_encap_type_mpls_in_udp( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_udp *bet); + +extern int +tlv_to_bgp_encap_type_pbb( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_pbb *bet); /* caller-allocated */ + +#endif /* _QUAGGA_BGP_ENCAP_TLV_H */ diff --git a/bgpd/bgp_encap_types.h b/bgpd/bgp_encap_types.h new file mode 100644 index 000000000..c81b72979 --- /dev/null +++ b/bgpd/bgp_encap_types.h @@ -0,0 +1,174 @@ +/* + * Copyright 2015, LabN Consulting, L.L.C. + * + * This program 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 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _QUAGGA_BGP_ENCAP_TYPES_H +#define _QUAGGA_BGP_ENCAP_TYPES_H + +/* from http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#tunnel-types */ +typedef enum { + BGP_ENCAP_TYPE_RESERVED=0, + BGP_ENCAP_TYPE_L2TPV3_OVER_IP=1, + BGP_ENCAP_TYPE_GRE=2, + BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT=3, + BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE=4, + BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE=5, + BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE=6, + BGP_ENCAP_TYPE_IP_IN_IP=7, + BGP_ENCAP_TYPE_VXLAN=8, + BGP_ENCAP_TYPE_NVGRE=9, + BGP_ENCAP_TYPE_MPLS=10, + BGP_ENCAP_TYPE_MPLS_IN_GRE=11, + BGP_ENCAP_TYPE_VXLAN_GPE=12, + BGP_ENCAP_TYPE_MPLS_IN_UDP=13, + BGP_ENCAP_TYPE_PBB +} bgp_encap_types; + +typedef enum { + BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION=1, + BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE=2, + BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA=3, + BGP_ENCAP_SUBTLV_TYPE_COLOR=4, +} bgp_encap_subtlv_types; + +/* + * Tunnel Encapsulation Attribute subtlvs + */ +struct bgp_tea_subtlv_encap_l2tpv3_over_ip { + uint32_t sessionid; + uint8_t cookie_length; + uint8_t cookie[8]; +}; + +struct bgp_tea_subtlv_encap_gre_key { + uint32_t gre_key; +}; + +struct bgp_tea_subtlv_encap_pbb { + uint32_t flag_isid:1; + uint32_t flag_vid:1; + uint32_t isid:24; + uint16_t vid:12; + uint8_t macaddr[6]; +}; + +struct bgp_tea_subtlv_proto_type { + uint16_t proto; /* ether-type */ +}; + +struct bgp_tea_subtlv_color { + uint32_t color; +}; + +/* + * This is the length of the value part of the ipsec tunnel authenticator + * subtlv. Currently we only support the length for authenticator type 1. + */ +#define BGP_ENCAP_SUBTLV_IPSEC_TA_SIZE 20 + +struct bgp_tea_subtlv_ipsec_ta { + uint16_t authenticator_type; /* only type 1 is supported so far */ + uint8_t authenticator_length; /* octets in value field */ + uint8_t value[BGP_ENCAP_SUBTLV_IPSEC_TA_SIZE]; +}; + +/* + * Subtlv valid flags + * TBD change names to add "VALID" + */ +#define BGP_TEA_SUBTLV_ENCAP 0x00000001 +#define BGP_TEA_SUBTLV_PROTO_TYPE 0x00000002 +#define BGP_TEA_SUBTLV_COLOR 0x00000004 +#define BGP_TEA_SUBTLV_IPSEC_TA 0x00000008 + + +/* + * Tunnel Type-specific APIs + */ +struct bgp_encap_type_reserved { +}; + +struct bgp_encap_type_l2tpv3_over_ip { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_encap_l2tpv3_over_ip st_encap; + struct bgp_tea_subtlv_proto_type st_proto; /* optional */ + struct bgp_tea_subtlv_color st_color; /* optional */ +}; + +struct bgp_encap_type_gre { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_encap_gre_key st_encap; /* optional */ + struct bgp_tea_subtlv_proto_type st_proto; /* optional */ + struct bgp_tea_subtlv_color st_color; /* optional */ +}; + +struct bgp_encap_type_ip_in_ip { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_proto_type st_proto; /* optional */ + struct bgp_tea_subtlv_color st_color; /* optional */ +}; + +struct bgp_encap_type_transmit_tunnel_endpoint { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_ipsec_in_tunnel_mode { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ +}; + +struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ +}; + +struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ +}; + +struct bgp_encap_type_vxlan { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_nvgre { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_mpls { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_mpls_in_gre { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_vxlan_gpe { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_mpls_in_udp { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_pbb { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_encap_pbb st_encap; +}; + +#endif /* _QUAGGA_BGP_ENCAP_TYPES_H */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0b3d449c0..eb6389506 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -648,6 +648,7 @@ struct bgp_nlri #define BGP_ATTR_AS4_PATH 17 #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 +#define BGP_ATTR_ENCAP 23 /* BGP update origin. */ #define BGP_ORIGIN_IGP 0 diff --git a/lib/memtypes.c b/lib/memtypes.c index 5f78493ac..6df144803 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -154,6 +154,7 @@ struct memory_list memory_list_bgp[] = { MTYPE_BGP_REGEXP, "BGP regexp" }, { MTYPE_BGP_AGGREGATE, "BGP aggregate" }, { MTYPE_BGP_ADDR, "BGP own address" }, + { MTYPE_ENCAP_TLV, "ENCAP TLV", }, { -1, NULL } }; From 298cc2f688dbadf0a447fcd06ae8e20fa5006ce4 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:02 -0500 Subject: [PATCH 0946/1342] bgpd: encap: add encap SAFI (RFC5512) Adds RFC5512 and Encapsulation Attribute. Signed-off-by: Lou Berger --- bgpd/Makefile.am | 4 +- bgpd/bgp_attr.c | 44 +- bgpd/bgp_encap.c | 992 +++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_encap.h | 34 ++ bgpd/bgp_encap_tlv.c | 162 ++++++- bgpd/bgp_encap_types.h | 38 ++ bgpd/bgp_open.c | 32 +- bgpd/bgp_packet.c | 53 ++- bgpd/bgp_route.c | 255 +++++++---- bgpd/bgp_vty.c | 222 +++++++++ bgpd/bgpd.c | 19 +- 11 files changed, 1740 insertions(+), 115 deletions(-) create mode 100644 bgpd/bgp_encap.c create mode 100644 bgpd/bgp_encap.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 82c69eac4..7da4dd873 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -16,7 +16,7 @@ libbgp_a_SOURCES = \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ - bgp_encap_tlv.c + bgp_encap.c bgp_encap_tlv.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ @@ -24,7 +24,7 @@ noinst_HEADERS = \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ - bgp_encap_tlv.h bgp_encap_types.h + bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b019347bf..5dc118be6 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1891,9 +1891,11 @@ bgp_attr_encap( uint16_t sublength; struct bgp_attr_encap_subtlv *tlv; - subtype = stream_getw (BGP_INPUT (peer)); - sublength = stream_getw (BGP_INPUT (peer)); - length -= 4; + if (BGP_ATTR_ENCAP == type) { + subtype = stream_getc (BGP_INPUT (peer)); + sublength = stream_getc (BGP_INPUT (peer)); + length -= 2; + } if (sublength > length) { zlog (peer->log, LOG_ERR, @@ -2423,6 +2425,10 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, stream_putl (s, 0); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; + case SAFI_ENCAP: + stream_putc (s, 4); + stream_put (s, &attr->extra->mp_nexthop_global_in, 4); + break; case SAFI_UNICAST: /* invalid for IPv4 */ default: break; @@ -2465,6 +2471,11 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, } } break; + case SAFI_ENCAP: + assert (attr->extra); + stream_putc (s, 16); + stream_put (s, &attr->extra->mp_nexthop_global, 16); + break; default: break; } @@ -2517,6 +2528,7 @@ bgp_packet_mpattr_tea( uint8_t attrtype) { unsigned int attrlenfield = 0; + unsigned int attrhdrlen = 0; struct bgp_attr_encap_subtlv *subtlvs; struct bgp_attr_encap_subtlv *st; const char *attrname; @@ -2536,6 +2548,7 @@ bgp_packet_mpattr_tea( * V = concatenated subtlvs. */ attrlenfield = 2 + 2; /* T + L */ + attrhdrlen = 1 + 1; /* subTLV T + L */ break; default: @@ -2543,15 +2556,15 @@ bgp_packet_mpattr_tea( } + /* if no tlvs, don't make attr */ + if (subtlvs == NULL) + return; + /* compute attr length */ for (st = subtlvs; st; st = st->next) { - attrlenfield += (4 + st->length); + attrlenfield += (attrhdrlen + st->length); } - /* if no tlvs, don't make attr */ - if (!attrlenfield) - return; - if (attrlenfield > 0xffff) { zlog (peer->log, LOG_ERR, "%s attribute is too long (length=%d), can't send it", @@ -2581,8 +2594,10 @@ bgp_packet_mpattr_tea( /* write each sub-tlv */ for (st = subtlvs; st; st = st->next) { - stream_putw (s, st->type); - stream_putw (s, st->length); + if (attrtype == BGP_ATTR_ENCAP) { + stream_putc (s, st->type); + stream_putc (s, st->length); + } stream_put (s, st->value, st->length); } } @@ -2944,7 +2959,14 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } - + + if ((afi == AFI_IP || afi == AFI_IP6) && + (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) + { + /* Tunnel Encap attribute */ + bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP); + } + /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c new file mode 100644 index 000000000..f93650846 --- /dev/null +++ b/bgpd/bgp_encap.c @@ -0,0 +1,992 @@ + +/* + * This file created by LabN Consulting, L.L.C. + * + * + * This file is based on bgp_mplsvpn.c which is Copyright (C) 2000 + * Kunihiro Ishiguro + * + */ + +/* + +This file is part of GNU Zebra. + +GNU Zebra 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. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "prefix.h" +#include "log.h" +#include "memory.h" +#include "stream.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_vty.h" +#include "bgpd/bgp_encap.h" + +static u_int16_t +decode_rd_type (u_char *pnt) +{ + u_int16_t v; + + v = ((u_int16_t) *pnt++ << 8); + v |= (u_int16_t) *pnt; + return v; +} + + +static void +decode_rd_as (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int16_t) *pnt++ << 8; + rd_as->as |= (u_int16_t) *pnt++; + + rd_as->val = ((u_int32_t) *pnt++) << 24; + rd_as->val |= ((u_int32_t) *pnt++) << 16; + rd_as->val |= ((u_int32_t) *pnt++) << 8; + rd_as->val |= (u_int32_t) *pnt; +} + +static void +decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int32_t) *pnt++ << 24; + rd_as->as |= (u_int32_t) *pnt++ << 16; + rd_as->as |= (u_int32_t) *pnt++ << 8; + rd_as->as |= (u_int32_t) *pnt++; + + rd_as->val = ((u_int32_t) *pnt++ << 8); + rd_as->val |= (u_int32_t) *pnt; +} + +static void +decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) +{ + memcpy (&rd_ip->ip, pnt, 4); + pnt += 4; + + rd_ip->val = ((u_int16_t) *pnt++ << 8); + rd_ip->val |= (u_int16_t) *pnt; +} + +static void +ecom2prd(struct ecommunity *ecom, struct prefix_rd *prd) +{ + int i; + + memset(prd, 0, sizeof(struct prefix_rd)); + prd->family = AF_UNSPEC; + prd->prefixlen = 64; + + if (!ecom) + return; + + for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) { + + uint8_t *ep; + + ep = ecom->val + i; + + switch (ep[0]) { + default: + continue; + + case 0x80: + case 0x81: + case 0x82: + if (ep[1] == 0x0) { + prd->val[1] = ep[0] & 0x03; + memcpy(prd->val + 2, ep + 2, 6); + return; + } + } + } +} + +int +bgp_nlri_parse_encap( + afi_t afi, + struct peer *peer, + struct attr *attr, /* Need even for withdraw */ + struct bgp_nlri *packet, + int withdraw) /* 0=update, !0 = withdraw */ +{ + u_char *pnt; + u_char *lim; + struct prefix p; + int psize = 0; + int prefixlen; + struct rd_as rd_as; + struct rd_ip rd_ip; + struct prefix_rd prd; + struct ecommunity *pEcom = NULL; + u_int16_t rdtype = 0xffff; + char buf[BUFSIZ]; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + /* Make prefix_rd */ + if (attr && attr->extra && attr->extra->ecommunity) + pEcom = attr->extra->ecommunity; + + ecom2prd(pEcom, &prd); + memset(&rd_as, 0, sizeof(rd_as)); + memset(&rd_ip, 0, sizeof(rd_ip)); + + if (pEcom) { + + rdtype = (prd.val[0] << 8) | prd.val[1]; + + /* Decode RD value. */ + if (rdtype == RD_TYPE_AS) + decode_rd_as (prd.val + 2, &rd_as); + else if (rdtype == RD_TYPE_IP) + decode_rd_ip (prd.val + 2, &rd_ip); + else if (rdtype == RD_TYPE_AS4) + decode_rd_as4 (prd.val + 2, &rd_as); + else + { + zlog_err ("Invalid RD type %d", rdtype); + } + + } + + /* + * NB: this code was based on the MPLS VPN code, which supported RDs. + * For the moment we are retaining the underlying RIB structure that + * keeps a per-RD radix tree, but since the RDs are not carried over + * the wire, we set the RD internally to 0. + */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memset(prd.val, 0, sizeof(prd.val)); + + pnt = packet->nlri; + lim = pnt + packet->length; + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + + /* Fetch prefix length. */ + prefixlen = *pnt++; + p.family = afi2family(afi); + if (p.family == 0) { + /* bad afi, shouldn't happen */ + zlog_warn("%s: bad afi %d, dropping incoming route", __func__, afi); + continue; + } + psize = PSIZE (prefixlen); + + p.prefixlen = prefixlen; + memcpy (&p.u.prefix, pnt, psize); + + if (pnt + psize > lim) + return -1; + + + if (rdtype == RD_TYPE_AS) + zlog_info ("rd-as %u:%u prefix %s/%d", rd_as.as, rd_as.val, + inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), + p.prefixlen); + else if (rdtype == RD_TYPE_IP) + zlog_info ("rd-ip %s:%u prefix %s/%d", inet_ntoa (rd_ip.ip), + rd_ip.val, + inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), + p.prefixlen); + else if (rdtype == RD_TYPE_AS4) + zlog_info ("rd-as4 %u:%u prefix %s/%d", rd_as.as, rd_as.val, + inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), + p.prefixlen); + else + zlog_info ("rd unknown, default to 0:0 prefix %s/%d", + inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), + p.prefixlen); + + if (!withdraw) { + bgp_update (peer, &p, attr, afi, SAFI_ENCAP, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); + } else { + bgp_withdraw (peer, &p, attr, afi, SAFI_ENCAP, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL); + } + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} + + +/* TBD: these routes should probably all be host routes */ + +/* For testing purpose, static route of ENCAP. */ +DEFUN (encap_network, + encap_network_cmd, + "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "ENCAP Route Distinguisher\n" + "BGP tag\n" + "tag value\n") +{ + return bgp_static_set_safi (SAFI_ENCAP, vty, argv[0], argv[1], argv[2], NULL); +} + +/* For testing purpose, static route of ENCAP. */ +DEFUN (no_encap_network, + no_encap_network_cmd, + "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "ENCAP Route Distinguisher\n" + "BGP tag\n" + "tag value\n") +{ + return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[0], argv[1], argv[2]); +} + +static int +show_adj_route_encap (struct vty *vty, struct peer *peer, struct prefix_rd *prd) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct attr *attr; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_ENCAP]); rn; + rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + if ((attr = rm->info) != NULL) + { + if (header) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + vty_out (vty, "Route Distinguisher: "); + + /* Decode RD type. */ + type = decode_rd_type (pnt); + + switch (type) { + + case RD_TYPE_AS: + decode_rd_as (pnt + 2, &rd_as); + vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + break; + + case RD_TYPE_IP: + decode_rd_ip (pnt + 2, &rd_ip); + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + break; + + default: + vty_out (vty, "unknown RD type"); + } + + + vty_out (vty, "%s", VTY_NEWLINE); + rd_header = 0; + } + route_vty_out_tmp (vty, &rm->p, attr, SAFI_ENCAP); + } + } + } + return CMD_SUCCESS; +} + +enum bgp_show_type +{ + bgp_show_type_normal, + bgp_show_type_regexp, + bgp_show_type_prefix_list, + bgp_show_type_filter_list, + bgp_show_type_neighbor, + bgp_show_type_cidr_only, + bgp_show_type_prefix_longer, + bgp_show_type_community_all, + bgp_show_type_community, + bgp_show_type_community_exact, + bgp_show_type_community_list, + bgp_show_type_community_list_exact +}; + +static int +bgp_show_encap ( + struct vty *vty, + afi_t afi, + struct prefix_rd *prd, + enum bgp_show_type type, + void *output_arg, + int tags) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; + + unsigned long output_count = 0; + unsigned long total_count = 0; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if ((afi != AFI_IP) && (afi != AFI_IP6)) { + vty_out (vty, "Afi %d not supported%s", afi, VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[afi][SAFI_ENCAP]); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + for (ri = rm->info; ri; ri = ri->next) + { + total_count++; + if (type == bgp_show_type_neighbor) + { + union sockunion *su = output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (header) + { + if (tags) + vty_out (vty, v4_header_tag, VTY_NEWLINE); + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + + vty_out (vty, "Route Distinguisher: "); + + switch (type) { + + case RD_TYPE_AS: + decode_rd_as (pnt + 2, &rd_as); + vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + break; + + case RD_TYPE_IP: + decode_rd_ip (pnt + 2, &rd_ip); + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + break; + + default: + vty_out (vty, "Unknown RD type"); + break; + } + + vty_out (vty, "%s", VTY_NEWLINE); + rd_header = 0; + } + if (tags) + route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_ENCAP); + else + route_vty_out (vty, &rm->p, ri, 0, SAFI_ENCAP); + output_count++; + } + } + } + + if (output_count == 0) + { + vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); + } + else + vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", + VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (show_bgp_ipv4_encap, + show_bgp_ipv4_encap_cmd, + "show bgp ipv4 encap", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n") +{ + return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap, + show_bgp_ipv6_encap_cmd, + "show bgp ipv6 encap", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n") +{ + return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0); +} +#endif + +DEFUN (show_bgp_ipv4_encap_rd, + show_bgp_ipv4_encap_rd_cmd, + "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 0); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_rd, + show_bgp_ipv6_encap_rd_cmd, + "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 0); +} +#endif + +DEFUN (show_bgp_ipv4_encap_tags, + show_bgp_ipv4_encap_tags_cmd, + "show bgp ipv4 encap tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 1); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_tags, + show_bgp_ipv6_encap_tags_cmd, + "show bgp ipv6 encap tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 1); +} +#endif + +DEFUN (show_bgp_ipv4_encap_rd_tags, + show_bgp_ipv4_encap_rd_tags_cmd, + "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 1); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_rd_tags, + show_bgp_ipv6_encap_rd_tags_cmd, + "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 1); +} +#endif + +DEFUN (show_bgp_ipv4_encap_neighbor_routes, + show_bgp_ipv4_encap_neighbor_routes_cmd, + "show bgp ipv4 encap neighbors A.B.C.D routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + union sockunion *su; + struct peer *peer; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_neighbor_routes, + show_bgp_ipv6_encap_neighbor_routes_cmd, + "show bgp ipv6 encap neighbors A.B.C.D routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + union sockunion *su; + struct peer *peer; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_neighbor, su, 0); +} +#endif + +DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, + show_bgp_ipv4_encap_rd_neighbor_routes_cmd, + "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + int ret; + union sockunion *su; + struct peer *peer; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + su = sockunion_str2su (argv[1]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_neighbor, su, 0); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, + show_bgp_ipv6_encap_rd_neighbor_routes_cmd, + "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + int ret; + union sockunion *su; + struct peer *peer; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + su = sockunion_str2su (argv[1]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_neighbor, su, 0); +} +#endif + +DEFUN (show_bgp_ipv4_encap_neighbor_advertised_routes, + show_bgp_ipv4_encap_neighbor_advertised_routes_cmd, + "show bgp ipv4 encap neighbors A.B.C.D advertised-routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + union sockunion su; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_encap (vty, peer, NULL); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_neighbor_advertised_routes, + show_bgp_ipv6_encap_neighbor_advertised_routes_cmd, + "show bgp ipv6 encap neighbors A.B.C.D advertised-routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + union sockunion su; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_encap (vty, peer, NULL); +} +#endif + +DEFUN (show_bgp_ipv4_encap_rd_neighbor_advertised_routes, + show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd, + "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_encap (vty, peer, &prd); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_rd_neighbor_advertised_routes, + show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd, + "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display ENCAP NLRI specific information\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_encap (vty, peer, &prd); +} +#endif + +void +bgp_encap_init (void) +{ + //install_element (BGP_ENCAP_NODE, &encap_network_cmd); + //install_element (BGP_ENCAP_NODE, &no_encap_network_cmd); + + + install_element (VIEW_NODE, &show_bgp_ipv4_encap_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); + +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_ipv6_encap_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); +#endif + + + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); + +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); +#endif + + +} diff --git a/bgpd/bgp_encap.h b/bgpd/bgp_encap.h new file mode 100644 index 000000000..6f43b7b3b --- /dev/null +++ b/bgpd/bgp_encap.h @@ -0,0 +1,34 @@ +/* + * + * Copyright 2009-2015, LabN Consulting, L.L.C. + * + * + * This program 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 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _QUAGGA_BGP_ENCAP_H +#define _QUAGGA_BGP_ENCAP_H + +extern void bgp_encap_init (void); +extern int bgp_nlri_parse_encap ( + afi_t, + struct peer *, + struct attr *, + struct bgp_nlri *, + int withdraw); + +#include "bgp_encap_types.h" +#endif /* _QUAGGA_BGP_ENCAP_H */ diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c index 058b41eb5..347b4b3ce 100644 --- a/bgpd/bgp_encap_tlv.c +++ b/bgpd/bgp_encap_tlv.c @@ -196,6 +196,34 @@ subtlv_encode_ipsec_ta( return new; } +/* draft-rosen-idr-tunnel-encaps 2.1 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_remote_endpoint( + struct bgp_tea_subtlv_remote_endpoint *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + + int total = (st->family==AF_INET?8:20); + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT; + new->length = total; + p = new->value; + if (st->family == AF_INET) { + memcpy (p, &(st->ip_address.v4.s_addr), 4); + p+=4; + } else { + assert (st->family == AF_INET6); + memcpy (p, &(st->ip_address.v6.s6_addr), 16); + p+=16; + } + memcpy (p, &(st->as4), 4); + return new; +} /*********************************************************************** * TUNNEL TYPE-SPECIFIC TLV ENCODE @@ -235,6 +263,7 @@ bgp_encap_type_l2tpv3overip_to_tlv( ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_l2tpv3_over_ip, st_encap); ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); + ENC_SUBTLV(BGP_TEA_SUBTLV_REMOTE_ENDPOINT, subtlv_encode_remote_endpoint, st_endpoint); } void @@ -253,6 +282,7 @@ bgp_encap_type_gre_to_tlv( ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_gre, st_encap); ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); + ENC_SUBTLV(BGP_TEA_SUBTLV_REMOTE_ENDPOINT, subtlv_encode_remote_endpoint, st_endpoint); } void @@ -270,6 +300,7 @@ bgp_encap_type_ip_in_ip_to_tlv( ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); + ENC_SUBTLV(BGP_TEA_SUBTLV_REMOTE_ENDPOINT, subtlv_encode_remote_endpoint, st_endpoint); } void @@ -542,6 +573,36 @@ subtlv_decode_ipsec_ta( return 0; } +/* draft-rosen-idr-tunnel-encaps 2.1 */ +static int +subtlv_decode_remote_endpoint( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_remote_endpoint *st) +{ + int i; + if (subtlv->length != 8 && subtlv->length != 20 ) { + zlog_debug("%s, subtlv length %d does not equal 8 or 20", + __func__, subtlv->length); + return -1; + } + if (subtlv->length == 8) { + st->family = AF_INET; + st->ip_address.v4.s_addr = ((subtlv->value[0] << 24) | + (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]); + } else { + st->family = AF_INET6; + memcpy (&(st->ip_address.v6.s6_addr), subtlv->value, 16); + } + i = subtlv->length - 4; + st->as4 = ((subtlv->value[i] << 24) | + (subtlv->value[i+1] << 16) | + (subtlv->value[i+2] << 8) | + subtlv->value[i+3]); + return 0; +} + /*********************************************************************** * TUNNEL TYPE-SPECIFIC TLV DECODE ***********************************************************************/ @@ -558,17 +619,22 @@ tlv_to_bgp_encap_type_l2tpv3overip( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: rc |= subtlv_decode_encap_l2tpv3_over_ip(st, &bet->st_encap); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_ENCAP); break; case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: rc |= subtlv_decode_proto_type(st, &bet->st_proto); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_PROTO_TYPE); break; case BGP_ENCAP_SUBTLV_TYPE_COLOR: rc |= subtlv_decode_color(st, &bet->st_color); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_COLOR); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: @@ -592,17 +658,22 @@ tlv_to_bgp_encap_type_gre( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: rc |= subtlv_decode_encap_gre(st, &bet->st_encap); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_ENCAP); break; case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: rc |= subtlv_decode_proto_type(st, &bet->st_proto); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_PROTO_TYPE); break; case BGP_ENCAP_SUBTLV_TYPE_COLOR: rc |= subtlv_decode_color(st, &bet->st_color); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_COLOR); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: @@ -626,12 +697,17 @@ tlv_to_bgp_encap_type_ip_in_ip( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: rc |= subtlv_decode_proto_type(st, &bet->st_proto); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_PROTO_TYPE); break; case BGP_ENCAP_SUBTLV_TYPE_COLOR: rc |= subtlv_decode_color(st, &bet->st_color); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_COLOR); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: @@ -653,6 +729,12 @@ tlv_to_bgp_encap_type_transmit_tunnel_endpoint( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -674,7 +756,12 @@ tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_IPSEC_TA); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: @@ -698,7 +785,12 @@ tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_IPSEC_TA); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: @@ -722,7 +814,12 @@ tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_IPSEC_TA); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: @@ -744,6 +841,12 @@ tlv_to_bgp_encap_type_vxlan( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -763,6 +866,12 @@ tlv_to_bgp_encap_type_nvgre( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -782,6 +891,12 @@ tlv_to_bgp_encap_type_mpls( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -801,6 +916,12 @@ tlv_to_bgp_encap_type_mpls_in_gre( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -820,6 +941,12 @@ tlv_to_bgp_encap_type_vxlan_gpe( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -839,6 +966,12 @@ tlv_to_bgp_encap_type_mpls_in_udp( for (st = stlv; st; st = st->next) { switch (st->type) { + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); + break; + default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; @@ -860,7 +993,12 @@ tlv_to_bgp_encap_type_pbb( switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: rc |= subtlv_decode_encap_pbb(st, &bet->st_encap); - bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_ENCAP); + break; + + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); + SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: diff --git a/bgpd/bgp_encap_types.h b/bgpd/bgp_encap_types.h index c81b72979..603ff9d2d 100644 --- a/bgpd/bgp_encap_types.h +++ b/bgpd/bgp_encap_types.h @@ -44,6 +44,7 @@ typedef enum { BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE=2, BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA=3, BGP_ENCAP_SUBTLV_TYPE_COLOR=4, + BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT=6 /* speculative, IANA assignment TBD */ } bgp_encap_subtlv_types; /* @@ -75,6 +76,16 @@ struct bgp_tea_subtlv_color { uint32_t color; }; +/* per draft-rosen-idr-tunnel-encaps */ +struct bgp_tea_subtlv_remote_endpoint { + u_char family; /* IPv4 or IPv6 */ + union { + struct in_addr v4; + struct in6_addr v6; + } ip_address; + as_t as4; /* always 4 bytes */ +}; + /* * This is the length of the value part of the ipsec tunnel authenticator * subtlv. Currently we only support the length for authenticator type 1. @@ -95,12 +106,18 @@ struct bgp_tea_subtlv_ipsec_ta { #define BGP_TEA_SUBTLV_PROTO_TYPE 0x00000002 #define BGP_TEA_SUBTLV_COLOR 0x00000004 #define BGP_TEA_SUBTLV_IPSEC_TA 0x00000008 +#define BGP_TEA_SUBTLV_REMOTE_ENDPOINT 0x00000010 +#define CHECK_SUBTLV_FLAG(ptr, flag) CHECK_FLAG((ptr)->valid_subtlvs, (flag)) +#define SET_SUBTLV_FLAG(ptr, flag) SET_FLAG((ptr)->valid_subtlvs, (flag)) +#define UNSET_SUBTLV_FLAG(ptr, flag) UNSET_FLAG((ptr)->valid_subtlvs, (flag)) /* * Tunnel Type-specific APIs */ struct bgp_encap_type_reserved { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_l2tpv3_over_ip { @@ -108,6 +125,7 @@ struct bgp_encap_type_l2tpv3_over_ip { struct bgp_tea_subtlv_encap_l2tpv3_over_ip st_encap; struct bgp_tea_subtlv_proto_type st_proto; /* optional */ struct bgp_tea_subtlv_color st_color; /* optional */ + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_gre { @@ -115,59 +133,79 @@ struct bgp_encap_type_gre { struct bgp_tea_subtlv_encap_gre_key st_encap; /* optional */ struct bgp_tea_subtlv_proto_type st_proto; /* optional */ struct bgp_tea_subtlv_color st_color; /* optional */ + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_ip_in_ip { uint32_t valid_subtlvs; struct bgp_tea_subtlv_proto_type st_proto; /* optional */ struct bgp_tea_subtlv_color st_color; /* optional */ + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_transmit_tunnel_endpoint { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_ipsec_in_tunnel_mode { uint32_t valid_subtlvs; struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode { uint32_t valid_subtlvs; struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode { uint32_t valid_subtlvs; struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_vxlan { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_nvgre { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_mpls { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_mpls_in_gre { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_vxlan_gpe { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_mpls_in_udp { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_pbb { uint32_t valid_subtlvs; + struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ struct bgp_tea_subtlv_encap_pbb st_encap; }; diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 302e4ce5d..1c2ebd6d9 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -97,6 +97,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer) case SAFI_MPLS_LABELED_VPN: vty_out (vty, "SAFI MPLS-labeled VPN"); break; + case SAFI_ENCAP: + vty_out (vty, "SAFI ENCAP"); + break; default: vty_out (vty, "SAFI Unknown %d ", mpc.safi); break; @@ -137,6 +140,7 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_MPLS_VPN: + case SAFI_ENCAP: return 1; } break; @@ -841,9 +845,11 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] + && ! peer->afc_nego[AFI_IP][SAFI_ENCAP] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] - && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]) + && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] + && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]) { plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", @@ -988,6 +994,18 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, 0); stream_putc (s, SAFI_MPLS_LABELED_VPN); } + /* ENCAP */ + if (peer->afc[AFI_IP][SAFI_ENCAP]) + { + peer->afc_adv[AFI_IP][SAFI_ENCAP] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP); + stream_putc (s, 0); + stream_putc (s, SAFI_ENCAP); + } #ifdef HAVE_IPV6 /* IPv6 unicast. */ if (peer->afc[AFI_IP6][SAFI_UNICAST]) @@ -1025,6 +1043,18 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, 0); stream_putc (s, SAFI_MPLS_LABELED_VPN); } + /* IPv6 ENCAP. */ + if (peer->afc[AFI_IP6][SAFI_ENCAP]) + { + peer->afc_adv[AFI_IP6][SAFI_ENCAP] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP6); + stream_putc (s, 0); + stream_putc (s, SAFI_ENCAP); + } #endif /* HAVE_IPV6 */ /* Route refresh. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 841eaab88..1d18779bf 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -47,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_encap.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" @@ -212,7 +213,9 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, - &rn->p, afi, safi, + ((afi == AFI_IP && safi == SAFI_UNICAST) ? + &rn->p : NULL), + afi, safi, from, prd, tag); } @@ -1939,6 +1942,54 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) peer->host); } } + if (peer->afc[AFI_IP][SAFI_ENCAP]) + { + if (mp_update.length + && mp_update.afi == AFI_IP + && mp_update.safi == SAFI_ENCAP) + bgp_nlri_parse_encap (mp_update.afi, peer, &attr, &mp_update, 0); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == SAFI_ENCAP) + bgp_nlri_parse_encap (mp_withdraw.afi, peer, &attr, &mp_withdraw, 1); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s", + peer->host); + } + } + if (peer->afc[AFI_IP6][SAFI_ENCAP]) + { + if (mp_update.length + && mp_update.afi == AFI_IP6 + && mp_update.safi == SAFI_ENCAP) + bgp_nlri_parse_encap (mp_update.afi, peer, &attr, &mp_update, 0); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_ENCAP) + bgp_nlri_parse_encap (mp_withdraw.afi, peer, &attr, &mp_withdraw, 1); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s", + peer->host); + } + } /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b024d80d8..a780e9de2 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -71,7 +71,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix if (!table) return NULL; - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) { prn = bgp_node_get (table, (struct prefix *) prd); @@ -84,7 +84,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix rn = bgp_node_get (table, p); - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) rn->prn = prn; return rn; @@ -980,13 +980,24 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)); } + +#define NEXTHOP_IS_V4 (\ + (safi != SAFI_ENCAP && p->family == AF_INET) || \ + (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 4)) + +#ifdef HAVE_IPV6 +#define NEXTHOP_IS_V6 (\ + (safi != SAFI_ENCAP && p->family == AF_INET6) || \ + (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 16)) +#endif + /* next-hop-set */ if (transparent || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL)) || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) - && ((p->family == AF_INET && attr->nexthop.s_addr) + && ((NEXTHOP_IS_V4 && attr->nexthop.s_addr) #ifdef HAVE_IPV6 - || (p->family == AF_INET6 && + || (NEXTHOP_IS_V6 && ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ ))) @@ -994,18 +1005,18 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, /* NEXT-HOP Unchanged. */ } else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) - || (p->family == AF_INET && attr->nexthop.s_addr == 0) + || (NEXTHOP_IS_V4 && attr->nexthop.s_addr == 0) #ifdef HAVE_IPV6 - || (p->family == AF_INET6 && + || (NEXTHOP_IS_V6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ || (peer->sort == BGP_PEER_EBGP && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) { /* Set IPv4 nexthop. */ - if (p->family == AF_INET) + if (NEXTHOP_IS_V4) { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) memcpy (&attr->extra->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN); else @@ -1013,7 +1024,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } #ifdef HAVE_IPV6 /* Set IPv6 nexthop. */ - if (p->family == AF_INET6) + if (NEXTHOP_IS_V6) { /* IPv6 global nexthop must be included. */ memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global, @@ -1024,7 +1035,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } #ifdef HAVE_IPV6 - if (p->family == AF_INET6) + if (p->family == AF_INET6 && safi != SAFI_ENCAP) { /* Left nexthop_local unchanged if so configured. */ if ( CHECK_FLAG (peer->af_flags[afi][safi], @@ -1214,7 +1225,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, /* Set IPv4 nexthop. */ if (p->family == AF_INET) { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); else @@ -2657,10 +2668,12 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, struct attr attr; struct attr_extra extra; + memset(&extra, 0, sizeof(extra)); + if (! table) table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; - if (safi != SAFI_MPLS_VPN + if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) bgp_default_originate (peer, afi, safi, 0); @@ -2678,6 +2691,8 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, else bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); } + + bgp_attr_flush_encap(&attr); } void @@ -2696,7 +2711,7 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) return; - if (safi != SAFI_MPLS_VPN) + if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) bgp_announce_table (peer, afi, safi, NULL, 0); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; @@ -2746,7 +2761,7 @@ bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) struct bgp_table *table; struct bgp_node *rn; - if (safi != SAFI_MPLS_VPN) + if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL, NULL); else @@ -2805,7 +2820,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) if (peer->status != Established) return; - if (safi != SAFI_MPLS_VPN) + if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; @@ -3022,7 +3037,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, switch (purpose) { case BGP_CLEAR_ROUTE_NORMAL: - if (safi != SAFI_MPLS_VPN) + if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) bgp_clear_route_table (peer, afi, safi, NULL, NULL, purpose); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; @@ -3197,13 +3212,27 @@ bgp_cleanup_routes (void) */ for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) - if (rn->info) + { + if (rn->info) { - bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN); - bgp_table_finish ((struct bgp_table **)&(rn->info)); - rn->info = NULL; - bgp_unlock_node(rn); + bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN); + bgp_table_finish ((struct bgp_table **)&(rn->info)); + rn->info = NULL; + bgp_unlock_node(rn); } + } + + for (rn = bgp_table_top(bgp->rib[afi][SAFI_ENCAP]); rn; + rn = bgp_route_next (rn)) + { + if (rn->info) + { + bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_ENCAP); + bgp_table_finish ((struct bgp_table **)&(rn->info)); + rn->info = NULL; + bgp_unlock_node(rn); + } + } } } } @@ -3335,11 +3364,22 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi, while (pnt < end) { + int badlength; prefixlen = *pnt++; /* Prefix length check. */ - if ((afi == AFI_IP && prefixlen > 32) - || (afi == AFI_IP6 && prefixlen > 128)) + badlength = 0; + if (safi == SAFI_ENCAP) { + if (prefixlen > 128) + badlength = 1; + } else { + if ((afi == AFI_IP && prefixlen > 32) || + (afi == AFI_IP6 && prefixlen > 128)) { + + badlength = 1; + } + } + if (badlength) { plog_err (peer->log, "%s [Error] Update packet error (wrong prefix length %d)", @@ -4082,7 +4122,7 @@ bgp_static_delete (struct bgp *bgp) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) { table = rn->info; @@ -4938,7 +4978,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) return; table = bgp->aggregate[afi][safi]; @@ -4975,7 +5015,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) return; table = bgp->aggregate[afi][safi]; @@ -5918,30 +5958,71 @@ route_vty_out (struct vty *vty, struct prefix *p, attr = binfo->attr; if (attr) { - if (p->family == AF_INET) - { - if (safi == SAFI_MPLS_VPN) - vty_out (vty, "%-16s", - inet_ntoa (attr->extra->mp_nexthop_global_in)); - else - vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); + + /* + * NEXTHOP start + */ + + /* + * For ENCAP routes, nexthop address family is not + * neccessarily the same as the prefix address family. + * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field + */ + if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) { + if (attr->extra) { + char buf[BUFSIZ]; + int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len); + + switch (af) { + case AF_INET: + vty_out (vty, "%s", inet_ntop(af, + &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); + break; +#if HAVE_IPV6 + case AF_INET6: + vty_out (vty, "%s", inet_ntop(af, + &attr->extra->mp_nexthop_global, buf, BUFSIZ)); + break; +#endif + + default: + vty_out(vty, "?"); + } + } else { + vty_out(vty, "?"); } + } else { + + if (p->family == AF_INET) + { + vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); + } #ifdef HAVE_IPV6 - else if (p->family == AF_INET6) - { - int len; - char buf[BUFSIZ]; + else if (p->family == AF_INET6) + { + int len; + char buf[BUFSIZ]; - len = vty_out (vty, "%s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, - buf, BUFSIZ)); - len = 16 - len; - if (len < 1) - vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); - else - vty_out (vty, "%*s", len, " "); - } + len = vty_out (vty, "%s", + inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, + buf, BUFSIZ)); + len = 16 - len; + if (len < 1) + vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); + else + vty_out (vty, "%*s", len, " "); + } #endif /* HAVE_IPV6 */ + else + { + vty_out(vty, "?"); + } + } + + /* + * NEXTHOP end + */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, "%10u", attr->med); @@ -5983,7 +6064,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, { if (p->family == AF_INET) { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else @@ -6056,7 +6137,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, { if (p->family == AF_INET) { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else @@ -6239,7 +6320,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, /* Line2 display Next-hop, Neighbor, Router-id */ if (p->family == AF_INET) { - vty_out (vty, " %s", safi == SAFI_MPLS_VPN ? + vty_out (vty, " %s", ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) ? inet_ntoa (attr->extra->mp_nexthop_global_in) : inet_ntoa (attr->nexthop)); } @@ -6675,12 +6756,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, int no_advertise = 0; int local_as = 0; int first = 0; + int printrd = ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)); p = &rn->p; vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", - (safi == SAFI_MPLS_VPN ? - prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), - safi == SAFI_MPLS_VPN ? ":" : "", + (printrd ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), + printrd ? ":" : "", inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), p->prefixlen, VTY_NEWLINE); @@ -6766,7 +6847,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, match.family = afi2family (afi); - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) { for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn)) { @@ -6790,12 +6871,12 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, if (header) { route_vty_out_detail_header (vty, bgp, rm, (struct prefix_rd *)&rn->p, - AFI_IP, SAFI_MPLS_VPN); + AFI_IP, safi); header = 0; } display++; - route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN); + route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, safi); } bgp_unlock_node (rm); @@ -9835,22 +9916,28 @@ bgp_table_stats_vty (struct vty *vty, const char *name, afi_str, VTY_NEWLINE); return CMD_WARNING; } - if (strncmp (safi_str, "m", 1) == 0) - safi = SAFI_MULTICAST; - else if (strncmp (safi_str, "u", 1) == 0) - safi = SAFI_UNICAST; - else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0) - safi = SAFI_MPLS_LABELED_VPN; - else - { - vty_out (vty, "%% Invalid subsequent address family %s%s", + switch (safi_str[0]) { + case 'm': + safi = SAFI_MULTICAST; + break; + case 'u': + safi = SAFI_UNICAST; + break; + case 'v': + safi = SAFI_MPLS_LABELED_VPN; + break; + case 'e': + safi = SAFI_ENCAP; + break; + default: + vty_out (vty, "%% Invalid subsequent address family %s%s", safi_str, VTY_NEWLINE); - return CMD_WARNING; - } + return CMD_WARNING; + } } else { - vty_out (vty, "%% Invalid address family %s%s", + vty_out (vty, "%% Invalid address family \"%s\"%s", afi_str, VTY_NEWLINE); return CMD_WARNING; } @@ -9860,30 +9947,23 @@ bgp_table_stats_vty (struct vty *vty, const char *name, DEFUN (show_bgp_statistics, show_bgp_statistics_cmd, - "show bgp (ipv4|ipv6) (unicast|multicast) statistics", + "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", SHOW_STR BGP_STR "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "BGP RIB advertisement statistics\n") { return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); } -ALIAS (show_bgp_statistics, - show_bgp_statistics_vpnv4_cmd, - "show bgp (ipv4) (vpnv4) statistics", - SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "BGP RIB advertisement statistics\n") - DEFUN (show_bgp_statistics_view, show_bgp_statistics_view_cmd, - "show bgp view WORD (ipv4|ipv6) (unicast|multicast) statistics", + "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", SHOW_STR BGP_STR "BGP view\n" @@ -9891,20 +9971,24 @@ DEFUN (show_bgp_statistics_view, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "BGP RIB advertisement statistics\n") { return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); } +#if 0 /* added as options to above command */ ALIAS (show_bgp_statistics_view, - show_bgp_statistics_view_vpnv4_cmd, - "show bgp view WORD (ipv4) (vpnv4) statistics", + show_bgp_statistics_view_encap_cmd, + "show bgp view WORD (ipv4) (encap) statistics", SHOW_STR BGP_STR "BGP view\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") +#endif enum bgp_pcounts { @@ -12408,9 +12492,9 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name, match.family = afi2family (afi); - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) { - for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + for (rn = bgp_table_top (bgp->rib[AFI_IP][safi]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; @@ -12527,6 +12611,7 @@ DEFUN (clear_ip_bgp_dampening_address_mask, SAFI_UNICAST, NULL, 0); } +/* also used for encap safi */ static int bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) @@ -12578,7 +12663,7 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp, struct bgp_aggregate *bgp_aggregate; char buf[SU_ADDRSTRLEN]; - if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + if (afi == AFI_IP && ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))) return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write); /* Network configuration. */ @@ -13302,9 +13387,9 @@ bgp_route_init (void) /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); - install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); + //install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); - install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); + //install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); /* old command */ install_element (VIEW_NODE, &show_ipv6_bgp_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 041a6a1fa..e0f1c2b41 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4802,6 +4802,33 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_out, "Address Family Modifier\n" "Soft reconfig outbound update\n") +DEFUN (clear_ip_bgp_all_encap_soft_out, + clear_ip_bgp_all_encap_soft_out_cmd, + "clear ip bgp * encap unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_encap_soft_out, + clear_ip_bgp_all_encap_out_cmd, + "clear ip bgp * encap unicast out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n") + DEFUN (clear_bgp_all_soft_out, clear_bgp_all_soft_out_cmd, "clear bgp * soft out", @@ -4940,6 +4967,33 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, "Address Family Modifier\n" "Soft reconfig outbound update\n") +DEFUN (clear_ip_bgp_peer_encap_soft_out, + clear_ip_bgp_peer_encap_soft_out_cmd, + "clear ip bgp A.B.C.D encap unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_encap_soft_out, + clear_ip_bgp_peer_encap_out_cmd, + "clear ip bgp A.B.C.D encap unicast out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n") + DEFUN (clear_bgp_peer_soft_out, clear_bgp_peer_soft_out_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft out", @@ -5267,6 +5321,33 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out, "Address Family modifier\n" "Soft reconfig outbound update\n") +DEFUN (clear_ip_bgp_as_encap_soft_out, + clear_ip_bgp_as_encap_soft_out_cmd, + "clear ip bgp " CMD_AS_RANGE " encap unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_encap_soft_out, + clear_ip_bgp_as_encap_out_cmd, + "clear ip bgp " CMD_AS_RANGE " encap unicast out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + DEFUN (clear_bgp_as_soft_out, clear_bgp_as_soft_out_cmd, "clear bgp " CMD_AS_RANGE " soft out", @@ -5503,6 +5584,33 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_in, "Address Family Modifier\n" "Soft reconfig inbound update\n") +DEFUN (clear_ip_bgp_all_encap_soft_in, + clear_ip_bgp_all_encap_soft_in_cmd, + "clear ip bgp * encap unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_encap_soft_in, + clear_ip_bgp_all_encap_in_cmd, + "clear ip bgp * encap unicast in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n") + DEFUN (clear_bgp_all_soft_in, clear_bgp_all_soft_in_cmd, "clear bgp * soft in", @@ -5699,6 +5807,33 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, "Address Family Modifier\n" "Soft reconfig inbound update\n") +DEFUN (clear_ip_bgp_peer_encap_soft_in, + clear_ip_bgp_peer_encap_soft_in_cmd, + "clear ip bgp A.B.C.D encap unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_encap_soft_in, + clear_ip_bgp_peer_encap_in_cmd, + "clear ip bgp A.B.C.D encap unicast in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n") + DEFUN (clear_bgp_peer_soft_in, clear_bgp_peer_soft_in_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft in", @@ -6206,6 +6341,33 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in, "Address Family modifier\n" "Soft reconfig inbound update\n") +DEFUN (clear_ip_bgp_as_encap_soft_in, + clear_ip_bgp_as_encap_soft_in_cmd, + "clear ip bgp " CMD_AS_RANGE " encap unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_encap_soft_in, + clear_ip_bgp_as_encap_in_cmd, + "clear ip bgp " CMD_AS_RANGE " encap unicast in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + DEFUN (clear_bgp_as_soft_in, clear_bgp_as_soft_in_cmd, "clear bgp " CMD_AS_RANGE " soft in", @@ -6356,6 +6518,21 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft, BGP_CLEAR_SOFT_BOTH, argv[0]); } +DEFUN (clear_ip_bgp_all_encap_soft, + clear_ip_bgp_all_encap_soft_cmd, + "clear ip bgp * encap unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + DEFUN (clear_bgp_all_soft, clear_bgp_all_soft_cmd, "clear bgp * soft", @@ -6439,6 +6616,21 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft, BGP_CLEAR_SOFT_BOTH, argv[0]); } +DEFUN (clear_ip_bgp_peer_encap_soft, + clear_ip_bgp_peer_encap_soft_cmd, + "clear ip bgp A.B.C.D encap unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + DEFUN (clear_bgp_peer_soft, clear_bgp_peer_soft_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft", @@ -6622,6 +6814,21 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft, BGP_CLEAR_SOFT_BOTH, argv[0]); } +DEFUN (clear_ip_bgp_as_encap_soft, + clear_ip_bgp_as_encap_soft_cmd, + "clear ip bgp " CMD_AS_RANGE " encap unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + DEFUN (clear_bgp_as_soft, clear_bgp_as_soft_cmd, "clear bgp " CMD_AS_RANGE " soft", @@ -10029,6 +10236,12 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_in_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd); @@ -10092,6 +10305,12 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_out_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd); @@ -10132,6 +10351,9 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 636f56934..e70d33774 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "plist.h" #include "linklist.h" #include "workqueue.h" +#include "table.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -55,6 +56,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_encap.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" @@ -974,12 +976,16 @@ peer_as_change (struct peer *peer, as_t as) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP], + PEER_FLAG_REFLECTOR_CLIENT); } /* local-as reset */ @@ -1398,9 +1404,11 @@ peer_group_active (struct peer *peer) if (peer->af_group[AFI_IP][SAFI_UNICAST] || peer->af_group[AFI_IP][SAFI_MULTICAST] || peer->af_group[AFI_IP][SAFI_MPLS_VPN] + || peer->af_group[AFI_IP][SAFI_ENCAP] || peer->af_group[AFI_IP6][SAFI_UNICAST] || peer->af_group[AFI_IP6][SAFI_MULTICAST] - || peer->af_group[AFI_IP6][SAFI_MPLS_VPN]) + || peer->af_group[AFI_IP6][SAFI_MPLS_VPN] + || peer->af_group[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } @@ -2356,9 +2364,11 @@ peer_active (struct peer *peer) if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] + || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] - || peer->afc[AFI_IP6][SAFI_MPLS_VPN]) + || peer->afc[AFI_IP6][SAFI_MPLS_VPN] + || peer->afc[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } @@ -2370,9 +2380,11 @@ peer_active_nego (struct peer *peer) if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MULTICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] + || peer->afc_nego[AFI_IP][SAFI_ENCAP] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] - || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]) + || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] + || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } @@ -5594,6 +5606,7 @@ bgp_init (void) bgp_address_init (); bgp_scan_init (); bgp_mplsvpn_init (); + bgp_encap_init (); /* Access list initialize. */ access_list_init (); From 637035710a2f8e1e5944ee714135b7f88ac15ac4 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:03 -0500 Subject: [PATCH 0947/1342] bgp: Reorg cleanup to align process and bgp instance init/destroy Signed-off-by: Lou Berger --- bgpd/bgp_main.c | 6 +++--- bgpd/bgpd.c | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 591a6f930..11c73ceae 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -227,7 +227,6 @@ bgp_exit (int status) struct listnode *node, *nnode; int *socket; struct interface *ifp; - extern struct zclient *zclient; extern struct zclient *zlookup; /* it only makes sense for this to be called on a clean exit */ @@ -314,8 +313,9 @@ bgp_exit (int status) vrf_terminate (); cmd_terminate (); vty_terminate (); - if (zclient) - zclient_free (zclient); + bgp_address_destroy(); + bgp_scan_destroy(); + bgp_zebra_destroy(); if (zlookup) zclient_free (zlookup); if (bgp_nexthop_buf) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e70d33774..3caeeff9f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2229,11 +2229,6 @@ bgp_delete (struct bgp *bgp) */ bgp_process_queues_drain_immediate(); - bgp_zebra_destroy(); - bgp_scan_destroy(); - bgp_address_destroy(); - - /* Remove visibility via the master list - there may however still be * routes to be processed still referencing the struct bgp. */ From a3fda886cdd48b6d8c421ebb1401142fa9ee93b0 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:04 -0500 Subject: [PATCH 0948/1342] bgpd, lib, vtysh: hook up bgp ENCAP CLI node Signed-off-by: Lou Berger Signed-off-by: David Lamparter --- bgpd/bgp_encap.c | 5 +- bgpd/bgp_vty.c | 242 +++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_vty.h | 6 ++ bgpd/bgpd.c | 14 ++- lib/command.c | 6 ++ lib/command.h | 2 + lib/vty.c | 2 + vtysh/extract.pl.in | 3 + vtysh/vtysh.c | 64 ++++++++++++ vtysh/vtysh_config.c | 6 ++ 10 files changed, 346 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index f93650846..48e231221 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -943,9 +943,8 @@ DEFUN (show_bgp_ipv6_encap_rd_neighbor_advertised_routes, void bgp_encap_init (void) { - //install_element (BGP_ENCAP_NODE, &encap_network_cmd); - //install_element (BGP_ENCAP_NODE, &no_encap_network_cmd); - + install_element (BGP_ENCAP_NODE, &encap_network_cmd); + install_element (BGP_ENCAP_NODE, &no_encap_network_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e0f1c2b41..1a1a9b9b2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -62,6 +62,7 @@ bgp_node_afi (struct vty *vty) case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_VPNV6_NODE: + case BGP_ENCAPV6_NODE: return AFI_IP6; break; } @@ -74,6 +75,10 @@ bgp_node_afi (struct vty *vty) safi_t bgp_node_safi (struct vty *vty) { + if (vty->node == BGP_ENCAP_NODE) + return SAFI_ENCAP; + if (vty->node == BGP_ENCAPV6_NODE) + return SAFI_ENCAP; if (vty->node == BGP_VPNV6_NODE) return SAFI_MPLS_VPN; if (vty->node == BGP_VPNV4_NODE) @@ -83,6 +88,44 @@ bgp_node_safi (struct vty *vty) return SAFI_UNICAST; } +int +bgp_parse_afi(const char *str, afi_t *afi) +{ + if (!strcmp(str, "ipv4")) { + *afi = AFI_IP; + return 0; + } +#ifdef HAVE_IPV6 + if (!strcmp(str, "ipv6")) { + *afi = AFI_IP6; + return 0; + } +#endif /* HAVE_IPV6 */ + return -1; +} + +int +bgp_parse_safi(const char *str, safi_t *safi) +{ + if (!strcmp(str, "encap")) { + *safi = SAFI_ENCAP; + return 0; + } + if (!strcmp(str, "multicast")) { + *safi = SAFI_MULTICAST; + return 0; + } + if (!strcmp(str, "unicast")) { + *safi = SAFI_UNICAST; + return 0; + } + if (!strcmp(str, "vpn")) { + *safi = SAFI_MPLS_VPN; + return 0; + } + return -1; +} + static int peer_address_self_check (union sockunion *su) { @@ -4311,12 +4354,41 @@ ALIAS (address_family_vpnv6, "Address family\n" "Address Family Modifier\n") +DEFUN (address_family_encap, + address_family_encap_cmd, + "address-family encap", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_ENCAP_NODE; + return CMD_SUCCESS; +} + +ALIAS (address_family_encap, + address_family_encapv4_cmd, + "address-family encapv4", + "Enter Address Family command mode\n" + "Address family\n") + +DEFUN (address_family_encapv6, + address_family_encapv6_cmd, + "address-family encapv6", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_ENCAPV6_NODE; + return CMD_SUCCESS; +} + DEFUN (exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { + /* should match list in command.c:config_exit */ if (vty->node == BGP_IPV4_NODE + || vty->node == BGP_ENCAP_NODE + || vty->node == BGP_ENCAPV6_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_VPNV6_NODE @@ -7538,12 +7610,16 @@ afi_safi_print (afi_t afi, safi_t safi) return "IPv4 Multicast"; else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) return "VPN-IPv4 Unicast"; + else if (afi == AFI_IP && safi == SAFI_ENCAP) + return "ENCAP-IPv4 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6 Multicast"; else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) return "VPN-IPv6 Unicast"; + else if (afi == AFI_IP6 && safi == SAFI_ENCAP) + return "ENCAP-IPv6 Unicast"; else return "Unknown"; } @@ -7888,7 +7964,11 @@ bgp_show_peer (struct vty *vty, struct peer *p) || p->afc_recv[AFI_IP6][SAFI_MULTICAST] || p->afc_adv[AFI_IP6][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN] + || p->afc_adv[AFI_IP6][SAFI_ENCAP] + || p->afc_recv[AFI_IP6][SAFI_ENCAP] #endif /* HAVE_IPV6 */ + || p->afc_adv[AFI_IP][SAFI_ENCAP] + || p->afc_recv[AFI_IP][SAFI_ENCAP] || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) { @@ -9357,6 +9437,20 @@ static struct cmd_node bgp_vpnv6_node = 1 }; +static struct cmd_node bgp_encap_node = +{ + BGP_ENCAP_NODE, + "%s(config-router-af-encap)# ", + 1 +}; + +static struct cmd_node bgp_encapv6_node = +{ + BGP_ENCAPV6_NODE, + "%s(config-router-af-encapv6)# ", + 1 +}; + static void community_list_vty (void); void @@ -9370,6 +9464,8 @@ bgp_vty_init (void) install_node (&bgp_ipv6_multicast_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_vpnv6_node, NULL); + install_node (&bgp_encap_node, NULL); + install_node (&bgp_encapv6_node, NULL); /* Install default VTY commands to new nodes. */ install_default (BGP_NODE); @@ -9379,6 +9475,8 @@ bgp_vty_init (void) install_default (BGP_IPV6M_NODE); install_default (BGP_VPNV4_NODE); install_default (BGP_VPNV6_NODE); + install_default (BGP_ENCAP_NODE); + install_default (BGP_ENCAPV6_NODE); /* "bgp multiple-instance" commands. */ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); @@ -9538,6 +9636,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element (BGP_NODE, &no_neighbor_activate_cmd); @@ -9547,6 +9647,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group set" commands. */ install_element (BGP_NODE, &neighbor_set_peer_group_cmd); @@ -9556,6 +9658,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_set_peer_group_cmd); /* "no neighbor peer-group unset" commands. */ install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd); @@ -9565,6 +9669,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_set_peer_group_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd); @@ -9581,6 +9687,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element (BGP_NODE, &neighbor_attr_unchanged_cmd); @@ -9739,6 +9849,52 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged10_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged10_cmd); + + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged10_cmd); + /* "nexthop-local unchanged" commands */ install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); @@ -9763,6 +9919,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor remove-private-AS" commands. */ install_element (BGP_NODE, &neighbor_remove_private_as_cmd); @@ -9779,6 +9939,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_VPNV6_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_remove_private_as_cmd); /* "neighbor send-community" commands.*/ install_element (BGP_NODE, &neighbor_send_community_cmd); @@ -9809,6 +9973,14 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &neighbor_send_community_type_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_send_community_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_send_community_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_send_community_type_cmd); /* "neighbor route-reflector" commands.*/ install_element (BGP_NODE, &neighbor_route_reflector_client_cmd); @@ -9825,6 +9997,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element (BGP_NODE, &neighbor_route_server_client_cmd); @@ -9841,6 +10017,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor passive" commands. */ install_element (BGP_NODE, &neighbor_passive_cmd); @@ -9971,6 +10151,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_distribute_list_cmd); /* "neighbor prefix-list" commands. */ install_element (BGP_NODE, &neighbor_prefix_list_cmd); @@ -9987,6 +10171,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element (BGP_NODE, &neighbor_filter_list_cmd); @@ -10003,6 +10191,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_filter_list_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_filter_list_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element (BGP_NODE, &neighbor_route_map_cmd); @@ -10019,6 +10211,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_route_map_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_route_map_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element (BGP_NODE, &neighbor_unsuppress_map_cmd); @@ -10035,6 +10231,10 @@ bgp_vty_init (void) install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor maximum-prefix" commands. */ install_element (BGP_NODE, &neighbor_maximum_prefix_cmd); @@ -10130,6 +10330,34 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + + install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + /* "neighbor allowas-in" */ install_element (BGP_NODE, &neighbor_allowas_in_cmd); install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd); @@ -10152,6 +10380,12 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_ENCAP_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_ENCAP_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_ENCAPV6_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_ENCAPV6_NODE, &no_neighbor_allowas_in_cmd); /* address-family commands. */ install_element (BGP_NODE, &address_family_ipv4_cmd); @@ -10166,6 +10400,12 @@ bgp_vty_init (void) install_element (BGP_NODE, &address_family_vpnv6_cmd); install_element (BGP_NODE, &address_family_vpnv6_unicast_cmd); + install_element (BGP_NODE, &address_family_encap_cmd); + install_element (BGP_NODE, &address_family_encapv4_cmd); +#ifdef HAVE_IPV6 + install_element (BGP_NODE, &address_family_encapv6_cmd); +#endif + /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); @@ -10173,6 +10413,8 @@ bgp_vty_init (void) install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); + install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); + install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd); /* "clear ip bgp commands" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 2df8aaa5d..7329c5fd9 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -26,4 +26,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern void bgp_vty_init (void); extern const char *afi_safi_print (afi_t, safi_t); +extern int +bgp_parse_afi(const char *str, afi_t *afi); + +extern int +bgp_parse_safi(const char *str, safi_t *safi); + #endif /* _QUAGGA_BGP_VTY_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3caeeff9f..249d20f32 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5308,12 +5308,16 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, if (safi == SAFI_MULTICAST) vty_out (vty, "ipv4 multicast"); else if (safi == SAFI_MPLS_VPN) - vty_out (vty, "vpnv4 unicast"); + vty_out (vty, "vpnv4"); + else if (safi == SAFI_ENCAP) + vty_out (vty, "encap"); } else if (afi == AFI_IP6) { if (safi == SAFI_MPLS_VPN) vty_out (vty, "vpnv6"); + else if (safi == SAFI_ENCAP) + vty_out (vty, "encapv6"); else { vty_out (vty, "ipv6"); @@ -5555,6 +5559,9 @@ bgp_config_write (struct vty *vty) /* IPv4 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN); + /* ENCAPv4 configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_ENCAP); + /* IPv6 unicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST); @@ -5564,6 +5571,11 @@ bgp_config_write (struct vty *vty) /* IPv6 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN); + /* ENCAPv6 configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP); + + vty_out (vty, " exit%s", VTY_NEWLINE); + write++; } return write; diff --git a/lib/command.c b/lib/command.c index dbcef5ee8..80893602d 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2591,6 +2591,8 @@ node_parent ( enum node_type node ) { case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: @@ -2962,6 +2964,8 @@ DEFUN (config_exit, case BGP_IPV4M_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: vty->node = BGP_NODE; @@ -3001,6 +3005,8 @@ DEFUN (config_end, case RIPNG_NODE: case BABEL_NODE: case BGP_NODE: + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_IPV4_NODE: diff --git a/lib/command.h b/lib/command.h index b5c73abe4..fd55f2d54 100644 --- a/lib/command.h +++ b/lib/command.h @@ -87,6 +87,8 @@ enum node_type BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ BGP_IPV6_NODE, /* BGP IPv6 address family */ BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */ + BGP_ENCAP_NODE, /* BGP ENCAP SAFI */ + BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ ISIS_NODE, /* ISIS protocol mode */ diff --git a/lib/vty.c b/lib/vty.c index f695b7222..e4510f850 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -738,6 +738,8 @@ vty_end_config (struct vty *vty) case BGP_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 82532da98..ca869b643 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -49,6 +49,9 @@ $ignore{'"address-family ipv6 unicast"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; +$ignore{'"address-family encap"'} = "ignore"; +$ignore{'"address-family encapv4"'} = "ignore"; +$ignore{'"address-family encapv6"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; $ignore{'"key chain WORD"'} = "ignore"; $ignore{'"key <0-2147483647>"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index a39889d00..63b596a58 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -281,6 +281,7 @@ vtysh_execute_func (const char *line, int pager) if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING) { if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE + || saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE || saved_node == BGP_IPV6M_NODE) @@ -691,6 +692,18 @@ static struct cmd_node bgp_vpnv6_node = "%s(config-router-af)# " }; +static struct cmd_node bgp_encap_node = +{ + BGP_ENCAP_NODE, + "%s(config-router-af)# " +}; + +static struct cmd_node bgp_encapv6_node = +{ + BGP_ENCAPV6_NODE, + "%s(config-router-af)# " +}; + static struct cmd_node bgp_ipv4_node = { BGP_IPV4_NODE, @@ -848,6 +861,39 @@ DEFUNSH (VTYSH_BGPD, return CMD_SUCCESS; } +DEFUNSH (VTYSH_BGPD, + address_family_encap, + address_family_encap_cmd, + "address-family encap", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_ENCAP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_encapv4, + address_family_encapv4_cmd, + "address-family encapv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_ENCAP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_encapv6, + address_family_encapv6_cmd, + "address-family encapv6", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_ENCAPV6_NODE; + return CMD_SUCCESS; +} + DEFUNSH (VTYSH_BGPD, address_family_ipv4_unicast, address_family_ipv4_unicast_cmd, @@ -1074,6 +1120,8 @@ vtysh_exit (struct vty *vty) break; case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: @@ -1113,6 +1161,8 @@ DEFUNSH (VTYSH_BGPD, || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_VPNV6_NODE + || vty->node == BGP_ENCAP_NODE + || vty->node == BGP_ENCAPV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) vty->node = BGP_NODE; @@ -2308,6 +2358,8 @@ vtysh_init_vty (void) install_node (&zebra_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_vpnv6_node, NULL); + install_node (&bgp_encap_node, NULL); + install_node (&bgp_encapv6_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); /* #ifdef HAVE_IPV6 */ @@ -2335,6 +2387,8 @@ vtysh_init_vty (void) vtysh_install_default (ZEBRA_NODE); vtysh_install_default (BGP_VPNV4_NODE); vtysh_install_default (BGP_VPNV6_NODE); + vtysh_install_default (BGP_ENCAP_NODE); + vtysh_install_default (BGP_ENCAPV6_NODE); vtysh_install_default (BGP_IPV4_NODE); vtysh_install_default (BGP_IPV4M_NODE); vtysh_install_default (BGP_IPV6_NODE); @@ -2373,6 +2427,10 @@ vtysh_init_vty (void) install_element (BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_VPNV6_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_ENCAP_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_ENCAP_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_ENCAPV6_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_ENCAPV6_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); @@ -2405,6 +2463,8 @@ vtysh_init_vty (void) install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd); install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element (BGP_VPNV6_NODE, &vtysh_end_all_cmd); + install_element (BGP_ENCAP_NODE, &vtysh_end_all_cmd); + install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element (ISIS_NODE, &vtysh_end_all_cmd); @@ -2433,6 +2493,8 @@ vtysh_init_vty (void) install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); install_element (BGP_NODE, &address_family_vpnv6_cmd); install_element (BGP_NODE, &address_family_vpnv6_unicast_cmd); + install_element (BGP_NODE, &address_family_encap_cmd); + install_element (BGP_NODE, &address_family_encapv6_cmd); install_element (BGP_NODE, &address_family_ipv4_unicast_cmd); install_element (BGP_NODE, &address_family_ipv4_multicast_cmd); #ifdef HAVE_IPV6 @@ -2441,6 +2503,8 @@ vtysh_init_vty (void) #endif install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); + install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); + install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index dcbb70f4a..a069164b2 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -172,6 +172,12 @@ vtysh_config_parse_line (const char *line) else if (strncmp (line, " address-family vpn6", strlen (" address-family vpn6")) == 0) config = config_get (BGP_VPNV6_NODE, line); + else if (strncmp (line, " address-family encapv6", + strlen (" address-family encapv6")) == 0) + config = config_get (BGP_ENCAPV6_NODE, line); + else if (strncmp (line, " address-family encap", + strlen (" address-family encap")) == 0) + config = config_get (BGP_ENCAP_NODE, line); else if (strncmp (line, " address-family ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0) config = config_get (BGP_IPV4M_NODE, line); From 135ca1502cc54d9ad00b60b3410a0932bfeceb29 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:05 -0500 Subject: [PATCH 0949/1342] bgpd: cleanup vty bgp_node_afi/safi utils Signed-off-by: Lou Berger --- bgpd/bgp_vty.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1a1a9b9b2..94796c743 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -57,17 +57,20 @@ extern struct in_addr router_id_zebra; afi_t bgp_node_afi (struct vty *vty) { + afi_t afi; switch (vty->node) { case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_VPNV6_NODE: case BGP_ENCAPV6_NODE: - return AFI_IP6; + afi = AFI_IP6; + break; + default: + afi = AFI_IP; break; } - - return AFI_IP; + return afi; } /* Utility function to get subsequent address family from current @@ -75,17 +78,26 @@ bgp_node_afi (struct vty *vty) safi_t bgp_node_safi (struct vty *vty) { - if (vty->node == BGP_ENCAP_NODE) - return SAFI_ENCAP; - if (vty->node == BGP_ENCAPV6_NODE) - return SAFI_ENCAP; - if (vty->node == BGP_VPNV6_NODE) - return SAFI_MPLS_VPN; - if (vty->node == BGP_VPNV4_NODE) - return SAFI_MPLS_VPN; - if (vty->node == BGP_IPV4M_NODE || vty->node == BGP_IPV6M_NODE) - return SAFI_MULTICAST; - return SAFI_UNICAST; + safi_t safi; + switch (vty->node) + { + case BGP_ENCAP_NODE: + case BGP_ENCAPV6_NODE: + safi = SAFI_ENCAP; + break; + case BGP_VPNV4_NODE: + case BGP_VPNV6_NODE: + safi = SAFI_MPLS_VPN; + break; + case BGP_IPV4M_NODE: + case BGP_IPV6M_NODE: + safi = SAFI_MULTICAST; + break; + default: + safi = SAFI_UNICAST; + break; + } + return safi; } int From 35c36863f42e3c3e61a0cae400ffa80905c96d45 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:06 -0500 Subject: [PATCH 0950/1342] bgpd: VPNv6 show commands Signed-off-by: Lou Berger --- bgpd/bgp_mplsvpn.c | 406 +++++++++++++++++++++++++++++++++++---------- bgpd/bgp_route.c | 321 ++++++++++++----------------------- 2 files changed, 427 insertions(+), 300 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index e92266513..9f06538ec 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -466,10 +466,14 @@ enum bgp_show_type }; static int -bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, - void *output_arg, int tags) +bgp_show_mpls_vpn( + struct vty *vty, + afi_t afi, + struct prefix_rd *prd, + enum bgp_show_type type, + void *output_arg, + int tags) { - afi_t afi = AFI_IP; struct bgp *bgp; struct bgp_table *table; struct bgp_node *rn; @@ -570,25 +574,37 @@ bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type ty return CMD_SUCCESS; } -DEFUN (show_ip_bgp_vpnv4_all, - show_ip_bgp_vpnv4_all_cmd, - "show ip bgp vpnv4 all", +DEFUN (show_bgp_ipv4_vpn, + show_bgp_ipv4_vpn_cmd, + "show bgp ipv4 vpn", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n") + "Address Family\n" + "Display VPN NLRI specific information\n") { - return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0); + return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0); } -DEFUN (show_ip_bgp_vpnv4_rd, - show_ip_bgp_vpnv4_rd_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_vpn, + show_bgp_ipv6_vpn_cmd, + "show bgp ipv6 vpn", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" + "Address Family\n" + "Display VPN NLRI specific information\n") +{ + return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0); +} +#endif + +DEFUN (show_bgp_ipv4_vpn_rd, + show_bgp_ipv4_vpn_rd_cmd, + "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn", + SHOW_STR + BGP_STR + "Address Family\n" + "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n") { @@ -601,29 +617,84 @@ DEFUN (show_ip_bgp_vpnv4_rd, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0); + return bgp_show_mpls_vpn (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 0); } -DEFUN (show_ip_bgp_vpnv4_all_tags, - show_ip_bgp_vpnv4_all_tags_cmd, - "show ip bgp vpnv4 all tags", +DEFUN (show_bgp_ipv6_vpn_rd, + show_bgp_ipv6_vpn_rd_cmd, + "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" + "Address Family\n" + "Display VPN NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_mpls_vpn (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 0); +} + + +DEFUN (show_bgp_ipv4_vpn_tags, + show_bgp_ipv4_vpn_tags_cmd, + "show bgp ipv4 vpn tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display VPN NLRI specific information\n" "Display BGP tags for prefixes\n") { - return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 1); + return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 1); } +DEFUN (show_bgp_ipv6_vpn_tags, + show_bgp_ipv6_vpn_tags_cmd, + "show bgp ipv6 vpn tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display VPN NLRI specific information\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 1); +} + +DEFUN (show_bgp_ipv4_vpn_rd_tags, + show_bgp_ipv4_vpn_rd_tags_cmd, + "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + BGP_STR + "Address Family\n" + "Display VPN NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int ret; + struct prefix_rd prd; -DEFUN (show_ip_bgp_vpnv4_rd_tags, - show_ip_bgp_vpnv4_rd_tags_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_mpls_vpn (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 1); +} +DEFUN (show_bgp_ipv6_vpn_rd_tags, + show_bgp_ipv6_vpn_rd_tags_cmd, + "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn tags", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") @@ -637,19 +708,19 @@ DEFUN (show_ip_bgp_vpnv4_rd_tags, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1); + return bgp_show_mpls_vpn (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 1); } -DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, - show_ip_bgp_vpnv4_all_neighbor_routes_cmd, - "show ip bgp vpnv4 all neighbors A.B.C.D routes", +DEFUN (show_bgp_ipv4_vpn_neighbor_routes, + show_bgp_ipv4_vpn_neighbor_routes_cmd, + "show bgp ipv4 vpn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" + "Neighbor to display information about\n" "Display routes learned from neighbor\n") { union sockunion su; @@ -670,35 +741,28 @@ DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0); + return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0); } -DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, - show_ip_bgp_vpnv4_rd_neighbor_routes_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_vpn_neighbor_routes, + show_bgp_ipv6_vpn_neighbor_routes_cmd, + "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" + "Neighbor to display information about\n" "Display routes learned from neighbor\n") { - int ret; union sockunion su; struct peer *peer; - struct prefix_rd prd; - ret = str2prefix_rd (argv[0], &prd); - if (! ret) - { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } + int ret; - ret = str2sockunion (argv[1], &su); + ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); @@ -706,23 +770,23 @@ DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, } peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + if (! peer || ! peer->afc[AFI_IP6][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0); + return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_neighbor, &su, 0); } +#endif -DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, - show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd, - "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", +DEFUN (show_bgp_ipv4_vpn_neighbor_advertised_routes, + show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd, + "show bgp ipv4 vpn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") @@ -746,29 +810,59 @@ DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, return show_adj_route_vpn (vty, peer, NULL); } +DEFUN (show_bgp_ipv6_vpn_neighbor_advertised_routes, + show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd, + "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display VPN NLRI specific information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + union sockunion su; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, NULL); +} DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, - show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", + show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd, + "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" + "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { int ret; struct peer *peer; struct prefix_rd prd; union sockunion su; - ret = str2sockunion (argv[1], &su); if (ret < 0) { - vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + vty_out (vty, "%% Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); @@ -787,6 +881,129 @@ DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, return show_adj_route_vpn (vty, peer, &prd); } +DEFUN (show_ip_bgp_vpnv6_rd_neighbor_advertised_routes, + show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd, + "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Display VPN NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, &prd); +} + +DEFUN (show_bgp_ipv4_vpn_rd_neighbor_routes, + show_bgp_ipv4_vpn_rd_neighbor_routes_cmd, + "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Address Family modifier\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + int ret; + union sockunion *su; + struct peer *peer; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + su = sockunion_str2su (argv[1]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_mpls_vpn (vty, AFI_IP, &prd, bgp_show_type_neighbor, su, 0); +} +DEFUN (show_bgp_ipv6_vpn_rd_neighbor_routes, + show_bgp_ipv6_vpn_rd_neighbor_routes_cmd, + "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Address Family\n" + "Address Family modifier\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + int ret; + union sockunion *su; + struct peer *peer; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + su = sockunion_str2su (argv[1]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP6][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_mpls_vpn (vty, AFI_IP6, &prd, bgp_show_type_neighbor, su, 0); +} void bgp_mplsvpn_init (void) @@ -795,22 +1012,43 @@ bgp_mplsvpn_init (void) install_element (BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); - - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); - - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd); + +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_tags_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); +#endif + + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd); + +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_tags_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); +#endif } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a780e9de2..c28de7be0 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6950,21 +6950,10 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, } /* BGP route print out function. */ -DEFUN (show_ip_bgp, - show_ip_bgp_cmd, - "show ip bgp", - SHOW_STR - IP_STR - BGP_STR) -{ - return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); -} - -DEFUN (show_ip_bgp_ipv4, - show_ip_bgp_ipv4_cmd, - "show ip bgp ipv4 (unicast|multicast)", +DEFUN (show_bgp_ipv4_safi, + show_bgp_ipv4_safi_cmd, + "show bgp ipv4 (unicast|multicast)", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -6977,31 +6966,10 @@ DEFUN (show_ip_bgp_ipv4, return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } -ALIAS (show_ip_bgp_ipv4, - show_bgp_ipv4_safi_cmd, - "show bgp ipv4 (unicast|multicast)", - SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n") - -DEFUN (show_ip_bgp_route, - show_ip_bgp_route_cmd, - "show ip bgp A.B.C.D", - SHOW_STR - IP_STR - BGP_STR - "Network in the BGP routing table to display\n") -{ - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); -} - -DEFUN (show_ip_bgp_ipv4_route, - show_ip_bgp_ipv4_route_cmd, - "show ip bgp ipv4 (unicast|multicast) A.B.C.D", +DEFUN (show_bgp_ipv4_safi_route, + show_bgp_ipv4_safi_route_cmd, + "show bgp ipv4 (unicast|multicast) A.B.C.D", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -7014,36 +6982,39 @@ DEFUN (show_ip_bgp_ipv4_route, return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } -ALIAS (show_ip_bgp_ipv4_route, - show_bgp_ipv4_safi_route_cmd, - "show bgp ipv4 (unicast|multicast) A.B.C.D", +DEFUN (show_bgp_ipv4_vpn_route, + show_bgp_ipv4_vpn_route_cmd, + "show bgp ipv4 vpn A.B.C.D", SHOW_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); +} -DEFUN (show_ip_bgp_vpnv4_all_route, - show_ip_bgp_vpnv4_all_route_cmd, - "show ip bgp vpnv4 all A.B.C.D", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_vpn_route, + show_bgp_ipv6_vpn_route_cmd, + "show bgp ipv6 vpn X:X::X:X", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" + "Address Family\n" + "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0); } +#endif -DEFUN (show_ip_bgp_vpnv4_rd_route, - show_ip_bgp_vpnv4_rd_route_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", +DEFUN (show_bgp_ipv4_vpn_rd_route, + show_bgp_ipv4_vpn_rd_route_cmd, + "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn A.B.C.D", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" + IP_STR + "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Network in the BGP routing table to display\n") @@ -7060,15 +7031,27 @@ DEFUN (show_ip_bgp_vpnv4_rd_route, return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); } -DEFUN (show_ip_bgp_prefix, - show_ip_bgp_prefix_cmd, - "show ip bgp A.B.C.D/M", +DEFUN (show_bgp_ipv6_vpn_rd_route, + show_bgp_ipv6_vpn_rd_route_cmd, + "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn X:X::X:X", SHOW_STR - IP_STR BGP_STR - "IP prefix /, e.g., 35.0.0.0/8\n") + "Address Family\n" + "Display VPN NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MPLS_VPN, &prd, 0); } DEFUN (show_ip_bgp_ipv4_prefix, @@ -7156,87 +7139,58 @@ DEFUN (show_ip_bgp_view, return bgp_show (vty, bgp, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } -DEFUN (show_ip_bgp_view_route, - show_ip_bgp_view_route_cmd, - "show ip bgp view WORD A.B.C.D", +DEFUN (show_bgp_ipv4_prefix, + show_bgp_ipv4_prefix_cmd, + "show bgp ipv4 A.B.C.D/M", SHOW_STR - IP_STR BGP_STR - "BGP view\n" - "View name\n" - "Network in the BGP routing table to display\n") -{ - return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); -} - -DEFUN (show_ip_bgp_view_prefix, - show_ip_bgp_view_prefix_cmd, - "show ip bgp view WORD A.B.C.D/M", - SHOW_STR IP_STR - BGP_STR - "BGP view\n" - "View name\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); -} - -#ifdef HAVE_IPV6 -DEFUN (show_bgp, - show_bgp_cmd, - "show bgp", - SHOW_STR - BGP_STR) -{ - return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, - NULL); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); } -ALIAS (show_bgp, - show_bgp_ipv6_cmd, - "show bgp ipv6", - SHOW_STR - BGP_STR - "Address family\n") - -DEFUN (show_bgp_ipv6_safi, - show_bgp_ipv6_safi_cmd, - "show bgp ipv6 (unicast|multicast)", +DEFUN (show_bgp_ipv4_safi_prefix, + show_bgp_ipv4_safi_prefix_cmd, + "show bgp ipv4 (unicast|multicast) A.B.C.D/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" - "Address Family modifier\n") + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, - NULL); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); - return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } -/* old command */ -DEFUN (show_ipv6_bgp, - show_ipv6_bgp_cmd, - "show ipv6 bgp", +DEFUN (show_bgp_ipv4_vpn_prefix, + show_bgp_ipv4_vpn_prefix_cmd, + "show bgp ipv4 vpn A.B.C.D/M", SHOW_STR + BGP_STR IP_STR - BGP_STR) + "Display VPN NLRI specific information\n" + "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, - NULL); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); } -DEFUN (show_bgp_route, - show_bgp_route_cmd, - "show bgp X:X::X:X", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_vpn_prefix, + show_bgp_ipv6_vpn_prefix_cmd, + "show bgp ipv6 vpn X:X::X:X/M", SHOW_STR BGP_STR - "Network in the BGP routing table to display\n") + "Address Family\n" + "Display VPN NLRI specific information\n" + "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1); } +#endif ALIAS (show_bgp_route, show_bgp_ipv6_route_cmd, @@ -7262,36 +7216,44 @@ DEFUN (show_bgp_ipv6_safi_route, return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } -/* old command */ -DEFUN (show_ipv6_bgp_route, - show_ipv6_bgp_route_cmd, - "show ipv6 bgp X:X::X:X", +DEFUN (show_bgp_ipv6_route, + show_bgp_ipv6_route_cmd, + "show bgp ipv6 X:X::X:X", SHOW_STR - IP_STR BGP_STR + "Address family\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); } -DEFUN (show_bgp_prefix, - show_bgp_prefix_cmd, - "show bgp X:X::X:X/M", +DEFUN (show_bgp_ipv6_safi_route, + show_bgp_ipv6_safi_route_cmd, + "show bgp ipv6 (unicast|multicast) X:X::X:X", SHOW_STR BGP_STR - "IPv6 prefix /\n") + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } -ALIAS (show_bgp_prefix, +/* new002 */ +DEFUN (show_bgp_ipv6_prefix, show_bgp_ipv6_prefix_cmd, "show bgp ipv6 X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" - "IPv6 prefix /\n") - + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} DEFUN (show_bgp_ipv6_safi_prefix, show_bgp_ipv6_safi_prefix_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X/M", @@ -7308,25 +7270,14 @@ DEFUN (show_bgp_ipv6_safi_prefix, return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } -/* old command */ -DEFUN (show_ipv6_bgp_prefix, - show_ipv6_bgp_prefix_cmd, - "show ipv6 bgp X:X::X:X/M", - SHOW_STR - IP_STR - BGP_STR - "IPv6 prefix /, e.g., 3ffe::/16\n") -{ - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); -} - DEFUN (show_bgp_view, - show_bgp_view_cmd, - "show bgp view WORD", + show_bgp_view_ipv6_cmd, + "show bgp view WORD ipv6", SHOW_STR - BGP_STR + BGP_STR "BGP view\n" - "View name\n") + "View name\n" + "Address family\n") { struct bgp *bgp; @@ -7340,29 +7291,8 @@ DEFUN (show_bgp_view, return bgp_show (vty, bgp, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } - -ALIAS (show_bgp_view, - show_bgp_view_ipv6_cmd, - "show bgp view WORD ipv6", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n") DEFUN (show_bgp_view_route, - show_bgp_view_route_cmd, - "show bgp view WORD X:X::X:X", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Network in the BGP routing table to display\n") -{ - return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); -} - -ALIAS (show_bgp_view_route, show_bgp_view_ipv6_route_cmd, "show bgp view WORD ipv6 X:X::X:X", SHOW_STR @@ -7371,20 +7301,11 @@ ALIAS (show_bgp_view_route, "View name\n" "Address family\n" "Network in the BGP routing table to display\n") - -DEFUN (show_bgp_view_prefix, - show_bgp_view_prefix_cmd, - "show bgp view WORD X:X::X:X/M", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "IPv6 prefix /\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } -ALIAS (show_bgp_view_prefix, +DEFUN (show_bgp_view_prefix, show_bgp_view_ipv6_prefix_cmd, "show bgp view WORD ipv6 X:X::X:X/M", SHOW_STR @@ -7393,42 +7314,10 @@ ALIAS (show_bgp_view_prefix, "View name\n" "Address family\n" "IPv6 prefix /\n") - -/* old command */ -DEFUN (show_ipv6_mbgp, - show_ipv6_mbgp_cmd, - "show ipv6 mbgp", - SHOW_STR - IP_STR - MBGP_STR) { - return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, - NULL); -} - -/* old command */ -DEFUN (show_ipv6_mbgp_route, - show_ipv6_mbgp_route_cmd, - "show ipv6 mbgp X:X::X:X", - SHOW_STR - IP_STR - MBGP_STR - "Network in the MBGP routing table to display\n") -{ - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } -/* old command */ -DEFUN (show_ipv6_mbgp_prefix, - show_ipv6_mbgp_prefix_cmd, - "show ipv6 mbgp X:X::X:X/M", - SHOW_STR - IP_STR - MBGP_STR - "IPv6 prefix /, e.g., 3ffe::/16\n") -{ - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); -} #endif @@ -7603,12 +7492,12 @@ bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi, return bgp_show (vty, NULL, afi, safi, type, plist); } -DEFUN (show_ip_bgp_prefix_list, - show_ip_bgp_prefix_list_cmd, - "show ip bgp prefix-list WORD", +DEFUN (show_bgp_ipv4_prefix_list, + show_bgp_ipv4_prefix_list_cmd, + "show bgp ipv4 prefix-list WORD", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { From 651b402d32b52ecf7ea1d979bf83b88ff799e134 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:07 -0500 Subject: [PATCH 0951/1342] bgpd: encap show commands Signed-off-by: Lou Berger --- bgpd/bgp_route.c | 3920 ++++++++++++++++++++++------------------------ bgpd/bgp_vty.c | 832 +++++----- 2 files changed, 2276 insertions(+), 2476 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c28de7be0..0ea7ced86 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7054,90 +7054,91 @@ DEFUN (show_bgp_ipv6_vpn_rd_route, return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MPLS_VPN, &prd, 0); } -DEFUN (show_ip_bgp_ipv4_prefix, - show_ip_bgp_ipv4_prefix_cmd, - "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", +DEFUN (show_bgp_ipv4_encap_route, + show_bgp_ipv4_encap_route_cmd, + "show bgp ipv4 encap A.B.C.D", SHOW_STR - IP_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "IP prefix /, e.g., 35.0.0.0/8\n") + IP_STR + "Display ENCAP NLRI specific information\n" + "Network in the BGP routing table to display\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); - - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0); } -ALIAS (show_ip_bgp_ipv4_prefix, - show_bgp_ipv4_safi_prefix_cmd, - "show bgp ipv4 (unicast|multicast) A.B.C.D/M", - SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "IP prefix /, e.g., 35.0.0.0/8\n") - -DEFUN (show_ip_bgp_vpnv4_all_prefix, - show_ip_bgp_vpnv4_all_prefix_cmd, - "show ip bgp vpnv4 all A.B.C.D/M", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_route, + show_bgp_ipv6_encap_route_cmd, + "show bgp ipv6 encap X:X::X:X", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" - "IP prefix /, e.g., 35.0.0.0/8\n") + IP6_STR + "Display ENCAP NLRI specific information\n" + "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0); } +#endif -DEFUN (show_ip_bgp_vpnv4_rd_prefix, - show_ip_bgp_vpnv4_rd_prefix_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", +DEFUN (show_bgp_ipv4_safi_rd_route, + show_bgp_ipv4_safi_rd_route_cmd, + "show bgp ipv4 (encap|vpn) rd ASN:nn_or_IP-address:nn A.B.C.D", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - "IP prefix /, e.g., 35.0.0.0/8\n") + "ENCAP Route Distinguisher\n" + "Network in the BGP routing table to display\n") { int ret; struct prefix_rd prd; + safi_t safi; - ret = str2prefix_rd (argv[0], &prd); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + ret = str2prefix_rd (argv[1], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); + return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0); } -DEFUN (show_ip_bgp_view, - show_ip_bgp_view_cmd, - "show ip bgp view WORD", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_rd_route, + show_bgp_ipv6_safi_rd_route_cmd, + "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X", SHOW_STR - IP_STR BGP_STR - "BGP view\n" - "View name\n") + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "Network in the BGP routing table to display\n") { - struct bgp *bgp; - - /* BGP structure lookup. */ - bgp = bgp_lookup_by_name (argv[0]); - if (bgp == NULL) - { - vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } + int ret; + struct prefix_rd prd; + safi_t safi; - return bgp_show (vty, bgp, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + ret = str2prefix_rd (argv[1], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0); } +#endif DEFUN (show_bgp_ipv4_prefix, show_bgp_ipv4_prefix_cmd, @@ -7192,28 +7193,227 @@ DEFUN (show_bgp_ipv6_vpn_prefix, } #endif -ALIAS (show_bgp_route, - show_bgp_ipv6_route_cmd, - "show bgp ipv6 X:X::X:X", +DEFUN (show_bgp_ipv4_encap_prefix, + show_bgp_ipv4_encap_prefix_cmd, + "show bgp ipv4 encap A.B.C.D/M", SHOW_STR BGP_STR - "Address family\n" + IP_STR + "Display ENCAP NLRI specific information\n" + "Display information about ENCAP NLRIs\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_encap_prefix, + show_bgp_ipv6_encap_prefix_cmd, + "show bgp ipv6 encap X:X::X:X/M", + SHOW_STR + BGP_STR + IP_STR + "Display ENCAP NLRI specific information\n" + "Display information about ENCAP NLRIs\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1); +} +#endif + +DEFUN (show_bgp_ipv4_safi_rd_prefix, + show_bgp_ipv4_safi_rd_prefix_cmd, + "show bgp ipv4 (encap|vpn) rd ASN:nn_or_IP-address:nn A.B.C.D/M", + SHOW_STR + BGP_STR + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_rd prd; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[1], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_rd_prefix, + show_bgp_ipv6_safi_rd_prefix_cmd, + "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X/M", + SHOW_STR + BGP_STR + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display information for a route distinguisher\n" + "ENCAP Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_rd prd; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[1], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1); +} +#endif + +DEFUN (show_bgp_afi_safi_view, + show_bgp_afi_safi_view_cmd, + "show bgp view WORD (ipv4|ipv6) (encap|mulicast|unicast|vpn)", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address Family\n" + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + ) +{ + struct bgp *bgp; + safi_t safi; + afi_t afi; + + if (bgp_parse_afi(argv[1], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + if (bgp_parse_safi(argv[2], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, bgp, afi, safi, bgp_show_type_normal, NULL); +} + +DEFUN (show_bgp_view_afi_safi_route, + show_bgp_view_afi_safi_route_cmd, + "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) A.B.C.D", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address Family\n" + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Network in the BGP routing table to display\n") +{ + safi_t safi; + afi_t afi; -DEFUN (show_bgp_ipv6_safi_route, - show_bgp_ipv6_safi_route_cmd, - "show bgp ipv6 (unicast|multicast) X:X::X:X", + if (bgp_parse_afi(argv[1], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + if (bgp_parse_safi(argv[2], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 0); +} + +DEFUN (show_bgp_view_afi_safi_prefix, + show_bgp_view_afi_safi_prefix_cmd, + "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) A.B.C.D/M", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address Family\n" + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + safi_t safi; + afi_t afi; + + if (bgp_parse_afi(argv[1], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + if (bgp_parse_safi(argv[2], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 1); +} + +/* new001 */ +DEFUN (show_bgp_afi, + show_bgp_afi_cmd, + "show bgp (ipv4|ipv6)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family\n") +{ + afi_t afi; + + if (bgp_parse_afi(argv[0], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show (vty, NULL, afi, SAFI_UNICAST, bgp_show_type_normal, + NULL); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi, + show_bgp_ipv6_safi_cmd, + "show bgp ipv6 (unicast|multicast)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" - "Address Family modifier\n" - "Network in the BGP routing table to display\n") + "Address Family modifier\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0); + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, + NULL); - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_ipv6_route, @@ -7366,78 +7566,133 @@ bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi, return rc; } -DEFUN (show_ip_bgp_regexp, - show_ip_bgp_regexp_cmd, - "show ip bgp regexp .LINE", +DEFUN (show_bgp_ipv4_safi_flap_regexp, + show_bgp_ipv4_safi_flap_regexp_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { - return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, - bgp_show_type_regexp); + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP, safi, + bgp_show_type_flap_regexp); } -DEFUN (show_ip_bgp_flap_regexp, - show_ip_bgp_flap_regexp_cmd, - "show ip bgp flap-statistics regexp .LINE", +ALIAS (show_bgp_ipv4_safi_flap_regexp, + show_bgp_ipv4_safi_damp_flap_regexp_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics regexp .LINE", SHOW_STR + BGP_STR IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_regexp, + show_bgp_ipv6_safi_flap_regexp_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", + SHOW_STR BGP_STR + IPV6_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { - return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, - bgp_show_type_flap_regexp); + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP6, safi, + bgp_show_type_flap_regexp); } -ALIAS (show_ip_bgp_flap_regexp, - show_ip_bgp_damp_flap_regexp_cmd, - "show ip bgp dampening flap-statistics regexp .LINE", +ALIAS (show_bgp_ipv6_safi_flap_regexp, + show_bgp_ipv6_safi_damp_flap_regexp_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics regexp .LINE", SHOW_STR - IP_STR BGP_STR + IPV6_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") +#endif -DEFUN (show_ip_bgp_ipv4_regexp, - show_ip_bgp_ipv4_regexp_cmd, - "show ip bgp ipv4 (unicast|multicast) regexp .LINE", +DEFUN (show_bgp_ipv4_safi_regexp, + show_bgp_ipv4_safi_regexp_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) regexp .LINE", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, - bgp_show_type_regexp); + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } - return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP, safi, bgp_show_type_regexp); } - #ifdef HAVE_IPV6 -DEFUN (show_bgp_regexp, - show_bgp_regexp_cmd, - "show bgp regexp .LINE", +DEFUN (show_bgp_ipv6_safi_regexp, + show_bgp_ipv6_safi_regexp_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) regexp .LINE", SHOW_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { - return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP6, safi, bgp_show_type_regexp); } -ALIAS (show_bgp_regexp, +DEFUN (show_bgp_ipv6_regexp, show_bgp_ipv6_regexp_cmd, "show bgp ipv6 regexp .LINE", SHOW_STR @@ -7445,34 +7700,11 @@ ALIAS (show_bgp_regexp, "Address family\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") - -/* old command */ -DEFUN (show_ipv6_bgp_regexp, - show_ipv6_bgp_regexp_cmd, - "show ipv6 bgp regexp .LINE", - SHOW_STR - IP_STR - BGP_STR - "Display routes matching the AS path regular expression\n" - "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, bgp_show_type_regexp); } -/* old command */ -DEFUN (show_ipv6_mbgp_regexp, - show_ipv6_mbgp_regexp_cmd, - "show ipv6 mbgp regexp .LINE", - SHOW_STR - IP_STR - BGP_STR - "Display routes matching the AS path regular expression\n" - "A regular-expression to match the MBGP AS paths\n") -{ - return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, - bgp_show_type_regexp); -} #endif /* HAVE_IPV6 */ static int @@ -7505,65 +7737,128 @@ DEFUN (show_bgp_ipv4_prefix_list, bgp_show_type_prefix_list); } -DEFUN (show_ip_bgp_flap_prefix_list, - show_ip_bgp_flap_prefix_list_cmd, - "show ip bgp flap-statistics prefix-list WORD", +DEFUN (show_bgp_ipv4_safi_flap_prefix_list, + show_bgp_ipv4_safi_flap_prefix_list_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { - return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_list (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_prefix_list); } -ALIAS (show_ip_bgp_flap_prefix_list, - show_ip_bgp_damp_flap_prefix_list_cmd, - "show ip bgp dampening flap-statistics prefix-list WORD", +ALIAS (show_bgp_ipv4_safi_flap_prefix_list, + show_bgp_ipv4_safi_damp_flap_prefix_list_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics prefix-list WORD", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") -DEFUN (show_ip_bgp_ipv4_prefix_list, - show_ip_bgp_ipv4_prefix_list_cmd, - "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_prefix_list, + show_bgp_ipv6_safi_flap_prefix_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", SHOW_STR - IP_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" + IPV6_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, - bgp_show_type_prefix_list); - - return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, - bgp_show_type_prefix_list); + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_list (vty, argv[1], AFI_IP6, safi, + bgp_show_type_flap_prefix_list); } +ALIAS (show_bgp_ipv6_safi_flap_prefix_list, + show_bgp_ipv6_safi_damp_flap_prefix_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics prefix-list WORD", + SHOW_STR + BGP_STR + IPV6_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +#endif +DEFUN (show_bgp_ipv4_safi_prefix_list, + show_bgp_ipv4_safi_prefix_list_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) prefix-list WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_list (vty, argv[1], AFI_IP, safi, + bgp_show_type_prefix_list); +} #ifdef HAVE_IPV6 -DEFUN (show_bgp_prefix_list, - show_bgp_prefix_list_cmd, - "show bgp prefix-list WORD", +DEFUN (show_bgp_ipv6_safi_prefix_list, + show_bgp_ipv6_safi_prefix_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) prefix-list WORD", SHOW_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes conforming to the prefix-list\n" - "IPv6 prefix-list name\n") + "IP prefix-list name\n") { - return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_list (vty, argv[1], AFI_IP6, safi, bgp_show_type_prefix_list); } -ALIAS (show_bgp_prefix_list, +DEFUN (show_bgp_prefix_list, show_bgp_ipv6_prefix_list_cmd, "show bgp ipv6 prefix-list WORD", SHOW_STR @@ -7571,34 +7866,11 @@ ALIAS (show_bgp_prefix_list, "Address family\n" "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") - -/* old command */ -DEFUN (show_ipv6_bgp_prefix_list, - show_ipv6_bgp_prefix_list_cmd, - "show ipv6 bgp prefix-list WORD", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the prefix-list\n" - "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_list); } -/* old command */ -DEFUN (show_ipv6_mbgp_prefix_list, - show_ipv6_mbgp_prefix_list_cmd, - "show ipv6 mbgp prefix-list WORD", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the prefix-list\n" - "IPv6 prefix-list name\n") -{ - return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, - bgp_show_type_prefix_list); -} #endif /* HAVE_IPV6 */ static int @@ -7617,12 +7889,12 @@ bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi, return bgp_show (vty, NULL, afi, safi, type, as_list); } -DEFUN (show_ip_bgp_filter_list, - show_ip_bgp_filter_list_cmd, - "show ip bgp filter-list WORD", +DEFUN (show_bgp_ipv4_filter_list, + show_bgp_ipv4_filter_list_cmd, + "show bgp ipv4 filter-list WORD", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { @@ -7630,100 +7902,142 @@ DEFUN (show_ip_bgp_filter_list, bgp_show_type_filter_list); } -DEFUN (show_ip_bgp_flap_filter_list, - show_ip_bgp_flap_filter_list_cmd, - "show ip bgp flap-statistics filter-list WORD", +DEFUN (show_bgp_ipv4_safi_flap_filter_list, + show_bgp_ipv4_safi_flap_filter_list_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { - return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_filter_list (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_filter_list); } -ALIAS (show_ip_bgp_flap_filter_list, - show_ip_bgp_damp_flap_filter_list_cmd, - "show ip bgp dampening flap-statistics filter-list WORD", +ALIAS (show_bgp_ipv4_safi_flap_filter_list, + show_bgp_ipv4_safi_damp_flap_filter_list_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics filter-list WORD", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") -DEFUN (show_ip_bgp_ipv4_filter_list, - show_ip_bgp_ipv4_filter_list_cmd, - "show ip bgp ipv4 (unicast|multicast) filter-list WORD", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_filter_list, + show_bgp_ipv6_safi_flap_filter_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", SHOW_STR - IP_STR BGP_STR - "Address family\n" + IPV6_STR + "Address Family modifier\n" + "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" + "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, - bgp_show_type_filter_list); - - return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, - bgp_show_type_filter_list); -} + safi_t safi; -#ifdef HAVE_IPV6 -DEFUN (show_bgp_filter_list, - show_bgp_filter_list_cmd, - "show bgp filter-list WORD", + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_filter_list (vty, argv[1], AFI_IP6, safi, + bgp_show_type_flap_filter_list); +} +ALIAS (show_bgp_ipv6_safi_flap_filter_list, + show_bgp_ipv6_safi_damp_flap_filter_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics filter-list WORD", SHOW_STR BGP_STR + IPV6_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") -{ - return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, - bgp_show_type_filter_list); -} +#endif -ALIAS (show_bgp_filter_list, - show_bgp_ipv6_filter_list_cmd, - "show bgp ipv6 filter-list WORD", +DEFUN (show_bgp_ipv4_safi_filter_list, + show_bgp_ipv4_safi_filter_list_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) filter-list WORD", SHOW_STR BGP_STR - "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") +{ + safi_t safi; -/* old command */ -DEFUN (show_ipv6_bgp_filter_list, - show_ipv6_bgp_filter_list_cmd, - "show ipv6 bgp filter-list WORD", + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_filter_list (vty, argv[1], AFI_IP, safi, + bgp_show_type_filter_list); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_filter_list, + show_bgp_ipv6_safi_filter_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) filter-list WORD", SHOW_STR - IPV6_STR BGP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { - return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, - bgp_show_type_filter_list); + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_filter_list (vty, argv[1], AFI_IP6, safi, + bgp_show_type_filter_list); } -/* old command */ -DEFUN (show_ipv6_mbgp_filter_list, - show_ipv6_mbgp_filter_list_cmd, - "show ipv6 mbgp filter-list WORD", +DEFUN (show_bgp_filter_list, + show_bgp_ipv6_filter_list_cmd, + "show bgp ipv6 filter-list WORD", SHOW_STR - IPV6_STR - MBGP_STR + BGP_STR + "Address family\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { - return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_filter_list); } + #endif /* HAVE_IPV6 */ DEFUN (show_ip_bgp_dampening_info, @@ -7755,12 +8069,12 @@ bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, return bgp_show (vty, NULL, afi, safi, type, rmap); } -DEFUN (show_ip_bgp_route_map, - show_ip_bgp_route_map_cmd, - "show ip bgp route-map WORD", +DEFUN (show_bgp_ipv4_route_map, + show_bgp_ipv4_route_map_cmd, + "show bgp ipv4 route-map WORD", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the route-map\n" "A route-map to match on\n") { @@ -7768,64 +8082,127 @@ DEFUN (show_ip_bgp_route_map, bgp_show_type_route_map); } -DEFUN (show_ip_bgp_flap_route_map, - show_ip_bgp_flap_route_map_cmd, - "show ip bgp flap-statistics route-map WORD", +DEFUN (show_bgp_ipv4_safi_flap_route_map, + show_bgp_ipv4_safi_flap_route_map_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") { - return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route_map (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_route_map); } -ALIAS (show_ip_bgp_flap_route_map, - show_ip_bgp_damp_flap_route_map_cmd, - "show ip bgp dampening flap-statistics route-map WORD", +ALIAS (show_bgp_ipv4_safi_flap_route_map, + show_bgp_ipv4_safi_damp_flap_route_map_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics route-map WORD", SHOW_STR + BGP_STR IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_route_map, + show_bgp_ipv6_safi_flap_route_map_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", + SHOW_STR + BGP_STR + IPV6_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route_map (vty, argv[1], AFI_IP6, safi, + bgp_show_type_flap_route_map); +} +ALIAS (show_bgp_ipv6_safi_flap_route_map, + show_bgp_ipv6_safi_damp_flap_route_map_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics route-map WORD", + SHOW_STR BGP_STR + IPV6_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") +#endif -DEFUN (show_ip_bgp_ipv4_route_map, - show_ip_bgp_ipv4_route_map_cmd, - "show ip bgp ipv4 (unicast|multicast) route-map WORD", +DEFUN (show_bgp_ipv4_safi_route_map, + show_bgp_ipv4_safi_route_map_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) route-map WORD", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, - bgp_show_type_route_map); - - return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route_map (vty, argv[1], AFI_IP, safi, bgp_show_type_route_map); } - -DEFUN (show_bgp_route_map, - show_bgp_route_map_cmd, - "show bgp route-map WORD", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_route_map, + show_bgp_ipv6_safi_route_map_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) route-map WORD", SHOW_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") { - return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, + safi_t safi; + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route_map (vty, argv[1], AFI_IP6, safi, bgp_show_type_route_map); } -ALIAS (show_bgp_route_map, +DEFUN (show_bgp_ipv6_route_map, show_bgp_ipv6_route_map_cmd, "show bgp ipv6 route-map WORD", SHOW_STR @@ -7833,47 +8210,64 @@ ALIAS (show_bgp_route_map, "Address family\n" "Display routes matching the route-map\n" "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_route_map); +} +#endif -DEFUN (show_ip_bgp_cidr_only, - show_ip_bgp_cidr_only_cmd, - "show ip bgp cidr-only", +DEFUN (show_bgp_ipv4_cidr_only, + show_bgp_ipv4_cidr_only_cmd, + "show bgp ipv4 cidr-only", SHOW_STR - IP_STR BGP_STR + IP_STR "Display only routes with non-natural netmasks\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } -DEFUN (show_ip_bgp_flap_cidr_only, - show_ip_bgp_flap_cidr_only_cmd, - "show ip bgp flap-statistics cidr-only", +DEFUN (show_bgp_ipv4_safi_flap_cidr_only, + show_bgp_ipv4_safi_flap_cidr_only_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics cidr-only", SHOW_STR - IP_STR BGP_STR + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") { - return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, - bgp_show_type_flap_cidr_only, NULL); + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show (vty, NULL, AFI_IP, safi, bgp_show_type_flap_cidr_only, NULL); } -ALIAS (show_ip_bgp_flap_cidr_only, - show_ip_bgp_damp_flap_cidr_only_cmd, - "show ip bgp dampening flap-statistics cidr-only", +ALIAS (show_bgp_ipv4_safi_flap_cidr_only, + show_bgp_ipv4_safi_damp_flap_cidr_only_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics cidr-only", SHOW_STR - IP_STR BGP_STR + "Address Family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") -DEFUN (show_ip_bgp_ipv4_cidr_only, - show_ip_bgp_ipv4_cidr_only_cmd, - "show ip bgp ipv4 (unicast|multicast) cidr-only", +DEFUN (show_bgp_ipv4_safi_cidr_only, + show_bgp_ipv4_safi_cidr_only_cmd, + "show bgp ipv4 (unicast|multicast) cidr-only", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -7888,83 +8282,64 @@ DEFUN (show_ip_bgp_ipv4_cidr_only, bgp_show_type_cidr_only, NULL); } -DEFUN (show_ip_bgp_community_all, - show_ip_bgp_community_all_cmd, - "show ip bgp community", - SHOW_STR - IP_STR - BGP_STR - "Display routes matching the communities\n") -{ - return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, - bgp_show_type_community_all, NULL); -} - -DEFUN (show_ip_bgp_ipv4_community_all, - show_ip_bgp_ipv4_community_all_cmd, - "show ip bgp ipv4 (unicast|multicast) community", +/* new046 */ +DEFUN (show_bgp_afi_safi_community_all, + show_bgp_afi_safi_community_all_cmd, +#ifdef HAVE_IPV6 + "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) community", +#else + "show bgp ipv4 (encap|multicast|unicast|vpn) community", +#endif SHOW_STR - IP_STR BGP_STR "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address Family modifier\n" + "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, - bgp_show_type_community_all, NULL); - - return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, - bgp_show_type_community_all, NULL); -} + safi_t safi; + afi_t afi; -#ifdef HAVE_IPV6 -DEFUN (show_bgp_community_all, - show_bgp_community_all_cmd, - "show bgp community", - SHOW_STR - BGP_STR - "Display routes matching the communities\n") -{ - return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, - bgp_show_type_community_all, NULL); -} + if (bgp_parse_afi(argv[0], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + if (bgp_parse_safi(argv[1], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } -ALIAS (show_bgp_community_all, - show_bgp_ipv6_community_all_cmd, - "show bgp ipv6 community", + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_all, NULL); +} +DEFUN (show_bgp_afi_community_all, + show_bgp_afi_community_all_cmd, +#ifdef HAVE_IPV6 + "show bgp (ipv4|ipv6) community", +#else + "show bgp ipv4 community", +#endif SHOW_STR BGP_STR "Address family\n" - "Display routes matching the communities\n") - -/* old command */ -DEFUN (show_ipv6_bgp_community_all, - show_ipv6_bgp_community_all_cmd, - "show ipv6 bgp community", - SHOW_STR - IPV6_STR - BGP_STR +#ifdef HAVE_IPV6 + "Address family\n" +#endif "Display routes matching the communities\n") { - return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, - bgp_show_type_community_all, NULL); -} + afi_t afi; + safi_t safi = SAFI_UNICAST; -/* old command */ -DEFUN (show_ipv6_mbgp_community_all, - show_ipv6_mbgp_community_all_cmd, - "show ipv6 mbgp community", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n") -{ - return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, - bgp_show_type_community_all, NULL); + if (bgp_parse_afi(argv[0], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_all, NULL); } -#endif /* HAVE_IPV6 */ static int bgp_show_community (struct vty *vty, const char *view_name, int argc, @@ -8029,12 +8404,12 @@ bgp_show_community (struct vty *vty, const char *view_name, int argc, bgp_show_type_community), com); } -DEFUN (show_ip_bgp_community, - show_ip_bgp_community_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", +DEFUN (show_bgp_ipv4_community, + show_bgp_ipv4_community_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8044,12 +8419,12 @@ DEFUN (show_ip_bgp_community, return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } -ALIAS (show_ip_bgp_community, - show_ip_bgp_community2_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_ipv4_community, + show_bgp_ipv4_community2_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8060,12 +8435,12 @@ ALIAS (show_ip_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_ip_bgp_community, - show_ip_bgp_community3_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_ipv4_community, + show_bgp_ipv4_community3_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8080,12 +8455,12 @@ ALIAS (show_ip_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_ip_bgp_community, - show_ip_bgp_community4_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_ipv4_community, + show_bgp_ipv4_community4_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8104,11 +8479,10 @@ ALIAS (show_ip_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -DEFUN (show_ip_bgp_ipv4_community, - show_ip_bgp_ipv4_community_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +DEFUN (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8125,11 +8499,10 @@ DEFUN (show_ip_bgp_ipv4_community, return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } -ALIAS (show_ip_bgp_ipv4_community, - show_ip_bgp_ipv4_community2_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community2_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8144,11 +8517,10 @@ ALIAS (show_ip_bgp_ipv4_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_ip_bgp_ipv4_community, - show_ip_bgp_ipv4_community3_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community3_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8167,11 +8539,10 @@ ALIAS (show_ip_bgp_ipv4_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_ip_bgp_ipv4_community, - show_ip_bgp_ipv4_community4_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community4_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8196,13 +8567,19 @@ ALIAS (show_ip_bgp_ipv4_community, DEFUN (show_bgp_view_afi_safi_community_all, show_bgp_view_afi_safi_community_all_cmd, +#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", +#else + "show bgp view WORD ipv4 (unicast|multicast) community", +#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" +#ifdef HAVE_IPV6 "Address family\n" +#endif "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") @@ -8219,20 +8596,31 @@ DEFUN (show_bgp_view_afi_safi_community_all, return CMD_WARNING; } +#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; +#endif return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); } DEFUN (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community_cmd, +#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" +#ifdef HAVE_IPV6 "Address family\n" +#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -8244,20 +8632,32 @@ DEFUN (show_bgp_view_afi_safi_community, int afi; int safi; +#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); +#endif } ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community2_cmd, +#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" +#ifdef HAVE_IPV6 "Address family\n" +#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -8272,13 +8672,19 @@ ALIAS (show_bgp_view_afi_safi_community, ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community3_cmd, +#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" +#ifdef HAVE_IPV6 "Address family\n" +#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -8297,13 +8703,19 @@ ALIAS (show_bgp_view_afi_safi_community, ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community4_cmd, +#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" +#ifdef HAVE_IPV6 "Address family\n" +#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -8324,12 +8736,12 @@ ALIAS (show_bgp_view_afi_safi_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -DEFUN (show_ip_bgp_community_exact, - show_ip_bgp_community_exact_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", +DEFUN (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8340,12 +8752,12 @@ DEFUN (show_ip_bgp_community_exact, return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } -ALIAS (show_ip_bgp_community_exact, - show_ip_bgp_community2_exact_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community2_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8357,12 +8769,12 @@ ALIAS (show_ip_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -ALIAS (show_ip_bgp_community_exact, - show_ip_bgp_community3_exact_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community3_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8378,12 +8790,12 @@ ALIAS (show_ip_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -ALIAS (show_ip_bgp_community_exact, - show_ip_bgp_community4_exact_cmd, - "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community4_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8403,11 +8815,10 @@ ALIAS (show_ip_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -DEFUN (show_ip_bgp_ipv4_community_exact, - show_ip_bgp_ipv4_community_exact_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", +DEFUN (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8425,11 +8836,10 @@ DEFUN (show_ip_bgp_ipv4_community_exact, return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } -ALIAS (show_ip_bgp_ipv4_community_exact, - show_ip_bgp_ipv4_community2_exact_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community2_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8445,11 +8855,10 @@ ALIAS (show_ip_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -ALIAS (show_ip_bgp_ipv4_community_exact, - show_ip_bgp_ipv4_community3_exact_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community3_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8469,11 +8878,10 @@ ALIAS (show_ip_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -ALIAS (show_ip_bgp_ipv4_community_exact, - show_ip_bgp_ipv4_community4_exact_cmd, - "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community4_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8497,54 +8905,43 @@ ALIAS (show_ip_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -#ifdef HAVE_IPV6 -DEFUN (show_bgp_community, - show_bgp_community_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") -{ - return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); -} -ALIAS (show_bgp_community, +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_community, show_bgp_ipv6_community_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") +{ + safi_t safi; -ALIAS (show_bgp_community, - show_bgp_community2_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community (vty, NULL, argc-1, argv+1, 0, AFI_IP6, safi); +} -ALIAS (show_bgp_community, +ALIAS (show_bgp_ipv6_community, show_bgp_ipv6_community2_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8555,31 +8952,16 @@ ALIAS (show_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_community, - show_bgp_community3_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -ALIAS (show_bgp_community, +ALIAS (show_bgp_ipv6_community, show_bgp_ipv6_community3_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8594,35 +8976,16 @@ ALIAS (show_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_community, - show_bgp_community4_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -ALIAS (show_bgp_community, +ALIAS (show_bgp_ipv6_community, show_bgp_ipv6_community4_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8641,135 +9004,44 @@ ALIAS (show_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -/* old command */ -DEFUN (show_ipv6_bgp_community, - show_ipv6_bgp_community_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") -{ - return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); -} - -/* old command */ -ALIAS (show_ipv6_bgp_community, - show_ipv6_bgp_community2_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -/* old command */ -ALIAS (show_ipv6_bgp_community, - show_ipv6_bgp_community3_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -/* old command */ -ALIAS (show_ipv6_bgp_community, - show_ipv6_bgp_community4_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") DEFUN (show_bgp_community_exact, - show_bgp_community_exact_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") -{ - return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); -} - -ALIAS (show_bgp_community_exact, show_bgp_ipv6_community_exact_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community (vty, NULL, argc-1, argv+1, 1, AFI_IP6, safi); +} -ALIAS (show_bgp_community_exact, - show_bgp_community2_exact_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_ipv6_community2_exact_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8781,32 +9053,16 @@ ALIAS (show_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -ALIAS (show_bgp_community_exact, - show_bgp_community3_exact_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - ALIAS (show_bgp_community_exact, show_bgp_ipv6_community3_exact_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8823,10 +9079,15 @@ ALIAS (show_bgp_community_exact, "Exact match of the communities") ALIAS (show_bgp_community_exact, - show_bgp_community4_exact_cmd, - "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + show_bgp_ipv6_community4_exact_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8845,276 +9106,7 @@ ALIAS (show_bgp_community_exact, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") - -ALIAS (show_bgp_community_exact, - show_bgp_ipv6_community4_exact_cmd, - "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - BGP_STR - "Address family\n" - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -/* old command */ -DEFUN (show_ipv6_bgp_community_exact, - show_ipv6_bgp_community_exact_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") -{ - return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); -} - -/* old command */ -ALIAS (show_ipv6_bgp_community_exact, - show_ipv6_bgp_community2_exact_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -/* old command */ -ALIAS (show_ipv6_bgp_community_exact, - show_ipv6_bgp_community3_exact_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -/* old command */ -ALIAS (show_ipv6_bgp_community_exact, - show_ipv6_bgp_community4_exact_cmd, - "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -/* old command */ -DEFUN (show_ipv6_mbgp_community, - show_ipv6_mbgp_community_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") -{ - return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); -} - -/* old command */ -ALIAS (show_ipv6_mbgp_community, - show_ipv6_mbgp_community2_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -/* old command */ -ALIAS (show_ipv6_mbgp_community, - show_ipv6_mbgp_community3_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -/* old command */ -ALIAS (show_ipv6_mbgp_community, - show_ipv6_mbgp_community4_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") - -/* old command */ -DEFUN (show_ipv6_mbgp_community_exact, - show_ipv6_mbgp_community_exact_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") -{ - return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); -} - -/* old command */ -ALIAS (show_ipv6_mbgp_community_exact, - show_ipv6_mbgp_community2_exact_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -/* old command */ -ALIAS (show_ipv6_mbgp_community_exact, - show_ipv6_mbgp_community3_exact_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") -/* old command */ -ALIAS (show_ipv6_mbgp_community_exact, - show_ipv6_mbgp_community4_exact_cmd, - "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") #endif /* HAVE_IPV6 */ static int @@ -9136,12 +9128,12 @@ bgp_show_community_list (struct vty *vty, const char *com, int exact, bgp_show_type_community_list), list); } -DEFUN (show_ip_bgp_community_list, - show_ip_bgp_community_list_cmd, - "show ip bgp community-list (<1-500>|WORD)", +DEFUN (show_bgp_ipv4_community_list, + show_bgp_ipv4_community_list_cmd, + "show bgp ipv4 community-list (<1-500>|WORD)", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") @@ -9149,11 +9141,10 @@ DEFUN (show_ip_bgp_community_list, return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); } -DEFUN (show_ip_bgp_ipv4_community_list, - show_ip_bgp_ipv4_community_list_cmd, - "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", +DEFUN (show_bgp_ipv4_safi_community_list, + show_bgp_ipv4_safi_community_list_cmd, + "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -9168,12 +9159,12 @@ DEFUN (show_ip_bgp_ipv4_community_list, return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); } -DEFUN (show_ip_bgp_community_list_exact, - show_ip_bgp_community_list_exact_cmd, - "show ip bgp community-list (<1-500>|WORD) exact-match", +DEFUN (show_bgp_ipv4_community_list_exact, + show_bgp_ipv4_community_list_exact_cmd, + "show bgp ipv4 community-list (<1-500>|WORD) exact-match", SHOW_STR - IP_STR BGP_STR + IP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" @@ -9182,11 +9173,10 @@ DEFUN (show_ip_bgp_community_list_exact, return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); } -DEFUN (show_ip_bgp_ipv4_community_list_exact, - show_ip_bgp_ipv4_community_list_exact_cmd, - "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", +DEFUN (show_bgp_ipv4_safi_community_list_exact, + show_bgp_ipv4_safi_community_list_exact_cmd, + "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -9205,102 +9195,49 @@ DEFUN (show_ip_bgp_ipv4_community_list_exact, #ifdef HAVE_IPV6 DEFUN (show_bgp_community_list, show_bgp_community_list_cmd, - "show bgp community-list (<1-500>|WORD)", - SHOW_STR - BGP_STR - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n") -{ - return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); -} - -ALIAS (show_bgp_community_list, - show_bgp_ipv6_community_list_cmd, - "show bgp ipv6 community-list (<1-500>|WORD)", + "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") - -/* old command */ -DEFUN (show_ipv6_bgp_community_list, - show_ipv6_bgp_community_list_cmd, - "show ipv6 bgp community-list WORD", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the community-list\n" - "community-list name\n") { - return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); -} + safi_t safi; -/* old command */ -DEFUN (show_ipv6_mbgp_community_list, - show_ipv6_mbgp_community_list_cmd, - "show ipv6 mbgp community-list WORD", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the community-list\n" - "community-list name\n") -{ - return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community_list (vty, argv[1], 0, AFI_IP6, safi); } DEFUN (show_bgp_community_list_exact, - show_bgp_community_list_exact_cmd, - "show bgp community-list (<1-500>|WORD) exact-match", - SHOW_STR - BGP_STR - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n" - "Exact match of the communities\n") -{ - return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); -} - -ALIAS (show_bgp_community_list_exact, show_bgp_ipv6_community_list_exact_cmd, - "show bgp ipv6 community-list (<1-500>|WORD) exact-match", + "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") - -/* old command */ -DEFUN (show_ipv6_bgp_community_list_exact, - show_ipv6_bgp_community_list_exact_cmd, - "show ipv6 bgp community-list WORD exact-match", - SHOW_STR - IPV6_STR - BGP_STR - "Display routes matching the community-list\n" - "community-list name\n" - "Exact match of the communities\n") { - return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); -} + safi_t safi; -/* old command */ -DEFUN (show_ipv6_mbgp_community_list_exact, - show_ipv6_mbgp_community_list_exact_cmd, - "show ipv6 mbgp community-list WORD exact-match", - SHOW_STR - IPV6_STR - MBGP_STR - "Display routes matching the community-list\n" - "community-list name\n" - "Exact match of the communities\n") -{ - return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi); } #endif /* HAVE_IPV6 */ @@ -9325,12 +9262,12 @@ bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, return ret; } -DEFUN (show_ip_bgp_prefix_longer, - show_ip_bgp_prefix_longer_cmd, - "show ip bgp A.B.C.D/M longer-prefixes", +DEFUN (show_bgp_ipv4_prefix_longer, + show_bgp_ipv4_prefix_longer_cmd, + "show bgp ipv4 A.B.C.D/M longer-prefixes", SHOW_STR - IP_STR BGP_STR + IP_STR "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { @@ -9338,146 +9275,296 @@ DEFUN (show_ip_bgp_prefix_longer, bgp_show_type_prefix_longer); } -DEFUN (show_ip_bgp_flap_prefix_longer, - show_ip_bgp_flap_prefix_longer_cmd, - "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", +DEFUN (show_bgp_ipv4_safi_flap_prefix_longer, + show_bgp_ipv4_safi_flap_prefix_longer_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M longer-prefixes", SHOW_STR - IP_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { - return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_prefix_longer); } -ALIAS (show_ip_bgp_flap_prefix_longer, - show_ip_bgp_damp_flap_prefix_longer_cmd, - "show ip bgp dampening flap-statistics A.B.C.D/M longer-prefixes", +ALIAS (show_bgp_ipv4_safi_flap_prefix_longer, + show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_prefix_longer, + show_bgp_ipv6_safi_flap_prefix_longer_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, + bgp_show_type_flap_prefix_longer); +} +ALIAS (show_bgp_ipv6_safi_flap_prefix_longer, + show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M longer-prefixes", SHOW_STR - IP_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") +#endif -DEFUN (show_ip_bgp_ipv4_prefix_longer, - show_ip_bgp_ipv4_prefix_longer_cmd, - "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", +DEFUN (show_bgp_ipv4_safi_prefix_longer, + show_bgp_ipv4_safi_prefix_longer_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) A.B.C.D/M longer-prefixes", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_prefix_longer); +} - return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, - bgp_show_type_prefix_longer); +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_prefix_longer, + show_bgp_ipv6_safi_prefix_longer_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, + bgp_show_type_prefix_longer); } +#endif -DEFUN (show_ip_bgp_flap_address, - show_ip_bgp_flap_address_cmd, - "show ip bgp flap-statistics A.B.C.D", +DEFUN (show_bgp_ipv4_safi_flap_address, + show_bgp_ipv4_safi_flap_address_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", SHOW_STR - IP_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") { - return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_address); } +ALIAS (show_bgp_ipv4_safi_flap_address, + show_bgp_ipv4_safi_damp_flap_address_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_flap_address, + show_bgp_ipv6_flap_address_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +{ + safi_t safi; -ALIAS (show_ip_bgp_flap_address, - show_ip_bgp_damp_flap_address_cmd, - "show ip bgp dampening flap-statistics A.B.C.D", + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, + bgp_show_type_flap_address); +} +ALIAS (show_bgp_ipv6_flap_address, + show_bgp_ipv6_damp_flap_address_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", SHOW_STR - IP_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") +#endif -DEFUN (show_ip_bgp_flap_prefix, - show_ip_bgp_flap_prefix_cmd, - "show ip bgp flap-statistics A.B.C.D/M", +DEFUN (show_bgp_ipv4_safi_flap_prefix, + show_bgp_ipv4_safi_flap_prefix_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M", SHOW_STR - IP_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, safi, bgp_show_type_flap_prefix); } -ALIAS (show_ip_bgp_flap_prefix, - show_ip_bgp_damp_flap_prefix_cmd, - "show ip bgp dampening flap-statistics A.B.C.D/M", +ALIAS (show_bgp_ipv4_safi_flap_prefix, + show_bgp_ipv4_safi_damp_flap_prefix_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M", SHOW_STR - IP_STR BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") #ifdef HAVE_IPV6 -DEFUN (show_bgp_prefix_longer, - show_bgp_prefix_longer_cmd, - "show bgp X:X::X:X/M longer-prefixes", +DEFUN (show_bgp_ipv6_safi_flap_prefix, + show_bgp_ipv6_safi_flap_prefix_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M", SHOW_STR BGP_STR - "IPv6 prefix /\n" - "Display route and more specific routes\n") + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, - bgp_show_type_prefix_longer); + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, safi, + bgp_show_type_flap_prefix); } -ALIAS (show_bgp_prefix_longer, - show_bgp_ipv6_prefix_longer_cmd, - "show bgp ipv6 X:X::X:X/M longer-prefixes", +ALIAS (show_bgp_ipv6_safi_flap_prefix, + show_bgp_ipv6_safi_damp_flap_prefix_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" - "IPv6 prefix /\n" - "Display route and more specific routes\n") + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") -/* old command */ -DEFUN (show_ipv6_bgp_prefix_longer, - show_ipv6_bgp_prefix_longer_cmd, - "show ipv6 bgp X:X::X:X/M longer-prefixes", +DEFUN (show_bgp_ipv6_prefix_longer, + show_bgp_ipv6_prefix_longer_cmd, + "show bgp ipv6 X:X::X:X/M longer-prefixes", SHOW_STR - IPV6_STR BGP_STR - "IPv6 prefix /, e.g., 3ffe::/16\n" + "Address family\n" + "IPv6 prefix /\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } -/* old command */ -DEFUN (show_ipv6_mbgp_prefix_longer, - show_ipv6_mbgp_prefix_longer_cmd, - "show ipv6 mbgp X:X::X:X/M longer-prefixes", - SHOW_STR - IPV6_STR - MBGP_STR - "IPv6 prefix /, e.g., 3ffe::/16\n" - "Display route and more specific routes\n") -{ - return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, - bgp_show_type_prefix_longer); -} #endif /* HAVE_IPV6 */ static struct peer * @@ -10024,12 +10111,13 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) return CMD_SUCCESS; } -DEFUN (show_ip_bgp_neighbor_prefix_counts, - show_ip_bgp_neighbor_prefix_counts_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_neighbor_prefix_counts, + show_bgp_ipv6_neighbor_prefix_counts_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR - IP_STR BGP_STR + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -10041,58 +10129,74 @@ DEFUN (show_ip_bgp_neighbor_prefix_counts, if (! peer) return CMD_WARNING; - return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); + return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); } - -DEFUN (show_bgp_ipv6_neighbor_prefix_counts, - show_bgp_ipv6_neighbor_prefix_counts_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", +#endif + +DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts, + show_bgp_ipv4_safi_neighbor_prefix_counts_cmd, + "show bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR BGP_STR "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") { struct peer *peer; + safi_t safi; - peer = peer_lookup_in_view (vty, NULL, argv[0]); - if (! peer) + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) return CMD_WARNING; - - return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); -} -DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts, - show_ip_bgp_ipv4_neighbor_prefix_counts_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", + return bgp_peer_counts (vty, peer, AFI_IP, safi); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts, + show_bgp_ipv6_safi_neighbor_prefix_counts_cmd, + "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") { struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - if (strncmp (argv[0], "m", 1) == 0) - return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST); - - return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); + return bgp_peer_counts (vty, peer, AFI_IP6, safi); } +#endif -DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts, - show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd, - "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", +DEFUN (show_ip_bgp_encap_neighbor_prefix_counts, + show_ip_bgp_encap_neighbor_prefix_counts_cmd, + "show ip bgp encap all neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR IP_STR BGP_STR @@ -10110,7 +10214,7 @@ DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts, if (! peer) return CMD_WARNING; - return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN); + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_ENCAP); } @@ -10224,50 +10328,39 @@ peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int return CMD_SUCCESS; } -DEFUN (show_ip_bgp_view_neighbor_advertised_route, - show_ip_bgp_view_neighbor_advertised_route_cmd, - "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", +DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route, + show_bgp_ipv4_safi_neighbor_advertised_route_cmd, + "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR - IP_STR BGP_STR - "BGP view\n" - "View name\n" + "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; + safi_t safi; - if (argc == 2) - peer = peer_lookup_in_view (vty, argv[0], argv[1]); - else - peer = peer_lookup_in_view (vty, NULL, argv[0]); - - if (! peer) + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; - - return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); -} + } -ALIAS (show_ip_bgp_view_neighbor_advertised_route, - show_ip_bgp_neighbor_advertised_route_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", - SHOW_STR - IP_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n") + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; -DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, - show_ip_bgp_ipv4_neighbor_advertised_route_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", + return peer_adj_routes (vty, peer, AFI_IP, safi, 0); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route, + show_bgp_ipv6_safi_neighbor_advertised_route_cmd, + "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR - IP_STR BGP_STR - "Address family\n" + "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" @@ -10276,25 +10369,28 @@ DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - if (strncmp (argv[0], "m", 1) == 0) - return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 0); - - return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); + return peer_adj_routes (vty, peer, AFI_IP6, safi, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_advertised_route, - show_bgp_view_neighbor_advertised_route_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", + show_bgp_view_ipv6_neighbor_advertised_route_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -10313,26 +10409,14 @@ DEFUN (show_bgp_view_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0); } -ALIAS (show_bgp_view_neighbor_advertised_route, - show_bgp_view_ipv6_neighbor_advertised_route_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n") - DEFUN (show_bgp_view_neighbor_received_routes, - show_bgp_view_neighbor_received_routes_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", + show_bgp_view_ipv6_neighbor_received_routes_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -10351,29 +10435,6 @@ DEFUN (show_bgp_view_neighbor_received_routes, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); } -ALIAS (show_bgp_view_neighbor_received_routes, - show_bgp_view_ipv6_neighbor_received_routes_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the received routes from neighbor\n") - -ALIAS (show_bgp_view_neighbor_advertised_route, - show_bgp_neighbor_advertised_route_cmd, - "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", - SHOW_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n") - ALIAS (show_bgp_view_neighbor_advertised_route, show_bgp_ipv6_neighbor_advertised_route_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", @@ -10385,102 +10446,69 @@ ALIAS (show_bgp_view_neighbor_advertised_route, "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") -/* old command */ -ALIAS (show_bgp_view_neighbor_advertised_route, - ipv6_bgp_neighbor_advertised_route_cmd, - "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", - SHOW_STR - IPV6_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n") - -/* old command */ -DEFUN (ipv6_mbgp_neighbor_advertised_route, - ipv6_mbgp_neighbor_advertised_route_cmd, - "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", - SHOW_STR - IPV6_STR - MBGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n") -{ - struct peer *peer; - - peer = peer_lookup_in_view (vty, NULL, argv[0]); - if (! peer) - return CMD_WARNING; - - return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0); -} #endif /* HAVE_IPV6 */ -DEFUN (show_ip_bgp_view_neighbor_received_routes, - show_ip_bgp_view_neighbor_received_routes_cmd, - "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", + +DEFUN (show_bgp_ipv4_safi_neighbor_received_routes, + show_bgp_ipv4_safi_neighbor_received_routes_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR - IP_STR BGP_STR - "BGP view\n" - "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") { struct peer *peer; + safi_t safi; - if (argc == 2) - peer = peer_lookup_in_view (vty, argv[0], argv[1]); - else - peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - - return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); + + return peer_adj_routes (vty, peer, AFI_IP, safi, 1); } - -ALIAS (show_ip_bgp_view_neighbor_received_routes, - show_ip_bgp_neighbor_received_routes_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", - SHOW_STR - IP_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the received routes from neighbor\n") - -DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, - show_ip_bgp_ipv4_neighbor_received_routes_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_received_routes, + show_bgp_ipv6_safi_neighbor_received_routes_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") { struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - if (strncmp (argv[0], "m", 1) == 0) - return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 1); - - return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); + return peer_adj_routes (vty, peer, AFI_IP6, safi, 1); } +#endif DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, @@ -10516,12 +10544,16 @@ DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, return peer_adj_routes (vty, peer, afi, safi, in); } -DEFUN (show_ip_bgp_neighbor_received_prefix_filter, - show_ip_bgp_neighbor_received_prefix_filter_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +DEFUN (show_bgp_ipv4_safi_neighbor_received_prefix_filter, + show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -10532,11 +10564,17 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter, union sockunion su; struct peer *peer; int count, ret; + safi_t safi; - ret = str2sockunion (argv[0], &su); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2sockunion (argv[1], &su); if (ret < 0) { - vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } @@ -10544,24 +10582,24 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter, if (! peer) return CMD_WARNING; - sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, safi); count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); - if (count) - { - vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + if (count) { + vty_out (vty, "Address family: IPv4 %s%s", safi2str(safi), VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP, name); - } + } return CMD_SUCCESS; } - -DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, - show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_received_prefix_filter, + show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR - IP_STR BGP_STR - "Address family\n" + IP_STR + "Address Family modifier\n" + "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" @@ -10574,6 +10612,12 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, union sockunion su; struct peer *peer; int count, ret; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } ret = str2sockunion (argv[1], &su); if (ret < 0) @@ -10586,42 +10630,16 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, if (! peer) return CMD_WARNING; - if (strncmp (argv[0], "m", 1) == 0) - { - sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST); - count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); - if (count) - { - vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE); - prefix_bgp_show_prefix_list (vty, AFI_IP, name); - } - } - else - { - sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); - count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); - if (count) - { - vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); - prefix_bgp_show_prefix_list (vty, AFI_IP, name); - } - } + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, safi); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) { + vty_out (vty, "Address family: IPv6 %s%s", safi2str(safi), VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } return CMD_SUCCESS; } - -#ifdef HAVE_IPV6 -ALIAS (show_bgp_view_neighbor_received_routes, - show_bgp_neighbor_received_routes_cmd, - "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", - SHOW_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the received routes from neighbor\n") - ALIAS (show_bgp_view_neighbor_received_routes, show_bgp_ipv6_neighbor_received_routes_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", @@ -10634,10 +10652,11 @@ ALIAS (show_bgp_view_neighbor_received_routes, "Display the received routes from neighbor\n") DEFUN (show_bgp_neighbor_received_prefix_filter, - show_bgp_neighbor_received_prefix_filter_cmd, - "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + show_bgp_ipv6_neighbor_received_prefix_filter_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -10656,73 +10675,29 @@ DEFUN (show_bgp_neighbor_received_prefix_filter, return CMD_WARNING; } - peer = peer_lookup (NULL, &su); - if (! peer) - return CMD_WARNING; - - sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); - count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); - if (count) - { - vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); - prefix_bgp_show_prefix_list (vty, AFI_IP6, name); - } - - return CMD_SUCCESS; -} - -ALIAS (show_bgp_neighbor_received_prefix_filter, - show_bgp_ipv6_neighbor_received_prefix_filter_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", - SHOW_STR - BGP_STR - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display information received from a BGP neighbor\n" - "Display the prefixlist filter\n") - -/* old command */ -ALIAS (show_bgp_view_neighbor_received_routes, - ipv6_bgp_neighbor_received_routes_cmd, - "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", - SHOW_STR - IPV6_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the received routes from neighbor\n") - -/* old command */ -DEFUN (ipv6_mbgp_neighbor_received_routes, - ipv6_mbgp_neighbor_received_routes_cmd, - "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", - SHOW_STR - IPV6_STR - MBGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the received routes from neighbor\n") -{ - struct peer *peer; - - peer = peer_lookup_in_view (vty, NULL, argv[0]); + peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; - return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 1); + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; } DEFUN (show_bgp_view_neighbor_received_prefix_filter, - show_bgp_view_neighbor_received_prefix_filter_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "BGP view\n" "View name\n" + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -10764,20 +10739,6 @@ DEFUN (show_bgp_view_neighbor_received_prefix_filter, return CMD_SUCCESS; } - -ALIAS (show_bgp_view_neighbor_received_prefix_filter, - show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display information received from a BGP neighbor\n" - "Display the prefixlist filter\n") #endif /* HAVE_IPV6 */ static int @@ -10793,74 +10754,132 @@ bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, return bgp_show (vty, peer->bgp, afi, safi, type, &peer->su); } -DEFUN (show_ip_bgp_neighbor_routes, - show_ip_bgp_neighbor_routes_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", +DEFUN (show_bgp_ipv4_safi_neighbor_flap, + show_bgp_ipv4_safi_neighbor_flap_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR - IP_STR BGP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" - "Display routes learned from neighbor\n") + "Display flap statistics of the routes learned from neighbor\n") { struct peer *peer; + safi_t safi; - peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, - bgp_show_type_neighbor); + return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, + bgp_show_type_flap_neighbor); } - -DEFUN (show_ip_bgp_neighbor_flap, - show_ip_bgp_neighbor_flap_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_flap, + show_bgp_ipv6_safi_neighbor_flap_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR - IP_STR BGP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") { struct peer *peer; + safi_t safi; - peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_flap_neighbor); } +#endif -DEFUN (show_ip_bgp_neighbor_damp, - show_ip_bgp_neighbor_damp_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", +DEFUN (show_bgp_ipv4_safi_neighbor_damp, + show_bgp_ipv4_safi_neighbor_damp_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR - IP_STR BGP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") { struct peer *peer; + safi_t safi; - peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, + bgp_show_type_damp_neighbor); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_damp, + show_bgp_ipv6_safi_neighbor_damp_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + BGP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") +{ + struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_damp_neighbor); } +#endif -DEFUN (show_ip_bgp_ipv4_neighbor_routes, - show_ip_bgp_ipv4_neighbor_routes_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", +DEFUN (show_bgp_ipv4_safi_neighbor_routes, + show_bgp_ipv4_safi_neighbor_routes_cmd, + "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -10871,69 +10890,50 @@ DEFUN (show_ip_bgp_ipv4_neighbor_routes, "Display routes learned from neighbor\n") { struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_MULTICAST, - bgp_show_type_neighbor); - - return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_neighbor); } - -DEFUN (show_ip_bgp_view_rsclient, - show_ip_bgp_view_rsclient_cmd, - "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_routes, + show_bgp_ipv6_safi_neighbor_routes_cmd, + "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR - IP_STR BGP_STR - "BGP view\n" - "View name\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR) + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR + "Display routes learned from neighbor\n") { - struct bgp_table *table; struct peer *peer; + safi_t safi; - if (argc == 2) - peer = peer_lookup_in_view (vty, argv[0], argv[1]); - else - peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - - if (! peer->afc[AFI_IP][SAFI_UNICAST]) - { - vty_out (vty, "%% Activate the neighbor for the address family first%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], - PEER_FLAG_RSERVER_CLIENT)) - { - vty_out (vty, "%% Neighbor is not a Route-Server client%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - table = peer->rib[AFI_IP][SAFI_UNICAST]; - - return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); + + return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, + bgp_show_type_neighbor); } - -ALIAS (show_ip_bgp_view_rsclient, - show_ip_bgp_rsclient_cmd, - "show ip bgp rsclient (A.B.C.D|X:X::X:X)", - SHOW_STR - IP_STR - BGP_STR - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR) +#endif DEFUN (show_bgp_view_ipv4_safi_rsclient, show_bgp_view_ipv4_safi_rsclient_cmd, @@ -10994,6 +10994,7 @@ ALIAS (show_bgp_view_ipv4_safi_rsclient, "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) +#if 0 /* from 0.99.24.1 merge */ DEFUN (show_ip_bgp_view_rsclient_route, show_ip_bgp_view_rsclient_route_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", @@ -11008,64 +11009,7 @@ DEFUN (show_ip_bgp_view_rsclient_route, { struct bgp *bgp; struct peer *peer; - - /* BGP structure lookup. */ - if (argc == 3) - { - bgp = bgp_lookup_by_name (argv[0]); - if (bgp == NULL) - { - vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - } - else - { - bgp = bgp_get_default (); - if (bgp == NULL) - { - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (argc == 3) - peer = peer_lookup_in_view (vty, argv[0], argv[1]); - else - peer = peer_lookup_in_view (vty, NULL, argv[0]); - - if (! peer) - return CMD_WARNING; - - if (! peer->afc[AFI_IP][SAFI_UNICAST]) - { - vty_out (vty, "%% Activate the neighbor for the address family first%s", - VTY_NEWLINE); - return CMD_WARNING; -} - - if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], - PEER_FLAG_RSERVER_CLIENT)) - { - vty_out (vty, "%% Neighbor is not a Route-Server client%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], - (argc == 3) ? argv[2] : argv[1], - AFI_IP, SAFI_UNICAST, NULL, 0); -} - -ALIAS (show_ip_bgp_view_rsclient_route, - show_ip_bgp_rsclient_route_cmd, - "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", - SHOW_STR - IP_STR - BGP_STR - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR - "Network in the BGP routing table to display\n") +#endif DEFUN (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_view_ipv4_safi_rsclient_route_cmd, @@ -11132,94 +11076,38 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_route, } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], - (argc == 4) ? argv[3] : argv[2], - AFI_IP, safi, NULL, 0); -} - -ALIAS (show_bgp_view_ipv4_safi_rsclient_route, - show_bgp_ipv4_safi_rsclient_route_cmd, - "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", - SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR - "Network in the BGP routing table to display\n") - -DEFUN (show_ip_bgp_view_rsclient_prefix, - show_ip_bgp_view_rsclient_prefix_cmd, - "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR - "IP prefix /, e.g., 35.0.0.0/8\n") -{ - struct bgp *bgp; - struct peer *peer; - - /* BGP structure lookup. */ - if (argc == 3) - { - bgp = bgp_lookup_by_name (argv[0]); - if (bgp == NULL) - { - vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - } - else - { - bgp = bgp_get_default (); - if (bgp == NULL) - { - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (argc == 3) - peer = peer_lookup_in_view (vty, argv[0], argv[1]); - else - peer = peer_lookup_in_view (vty, NULL, argv[0]); - - if (! peer) - return CMD_WARNING; - - if (! peer->afc[AFI_IP][SAFI_UNICAST]) - { - vty_out (vty, "%% Activate the neighbor for the address family first%s", - VTY_NEWLINE); - return CMD_WARNING; -} - - if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], - PEER_FLAG_RSERVER_CLIENT)) -{ - vty_out (vty, "%% Neighbor is not a Route-Server client%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], - (argc == 3) ? argv[2] : argv[1], - AFI_IP, SAFI_UNICAST, NULL, 1); + (argc == 4) ? argv[3] : argv[2], + AFI_IP, safi, NULL, 0); } -ALIAS (show_ip_bgp_view_rsclient_prefix, - show_ip_bgp_rsclient_prefix_cmd, - "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", +ALIAS (show_bgp_view_ipv4_safi_rsclient_route, + show_bgp_ipv4_safi_rsclient_route_cmd, + "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + +#if 0 /* from 0.99.24.1 merge */ +DEFUN (show_ip_bgp_view_rsclient_prefix, + show_ip_bgp_view_rsclient_prefix_cmd, + "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR IP_STR BGP_STR + "BGP view\n" + "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") +{ + struct bgp *bgp; + struct peer *peer; +#endif DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_view_ipv4_safi_rsclient_prefix_cmd, @@ -11304,12 +11192,13 @@ ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, #ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_routes, - show_bgp_view_neighbor_routes_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes", + show_bgp_view_ipv6_neighbor_routes_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -11329,26 +11218,14 @@ DEFUN (show_bgp_view_neighbor_routes, bgp_show_type_neighbor); } -ALIAS (show_bgp_view_neighbor_routes, - show_bgp_view_ipv6_neighbor_routes_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display routes learned from neighbor\n") - DEFUN (show_bgp_view_neighbor_damp, - show_bgp_view_neighbor_damp_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes", + show_bgp_view_ipv6_neighbor_damp_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" + "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" @@ -11368,9 +11245,9 @@ DEFUN (show_bgp_view_neighbor_damp, bgp_show_type_damp_neighbor); } -ALIAS (show_bgp_view_neighbor_damp, - show_bgp_view_ipv6_neighbor_damp_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", +DEFUN (show_bgp_view_neighbor_flap, + show_bgp_view_ipv6_neighbor_flap_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "BGP view\n" @@ -11380,18 +11257,6 @@ ALIAS (show_bgp_view_neighbor_damp, "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") - -DEFUN (show_bgp_view_neighbor_flap, - show_bgp_view_neighbor_flap_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display flap statistics of the routes learned from neighbor\n") { struct peer *peer; @@ -11407,30 +11272,6 @@ DEFUN (show_bgp_view_neighbor_flap, bgp_show_type_flap_neighbor); } -ALIAS (show_bgp_view_neighbor_flap, - show_bgp_view_ipv6_neighbor_flap_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display flap statistics of the routes learned from neighbor\n") - -ALIAS (show_bgp_view_neighbor_routes, - show_bgp_neighbor_routes_cmd, - "show bgp neighbors (A.B.C.D|X:X::X:X) routes", - SHOW_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display routes learned from neighbor\n") - - ALIAS (show_bgp_view_neighbor_routes, show_bgp_ipv6_neighbor_routes_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", @@ -11442,50 +11283,6 @@ ALIAS (show_bgp_view_neighbor_routes, "Neighbor to display information about\n" "Display routes learned from neighbor\n") -/* old command */ -ALIAS (show_bgp_view_neighbor_routes, - ipv6_bgp_neighbor_routes_cmd, - "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", - SHOW_STR - IPV6_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display routes learned from neighbor\n") - -/* old command */ -DEFUN (ipv6_mbgp_neighbor_routes, - ipv6_mbgp_neighbor_routes_cmd, - "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", - SHOW_STR - IPV6_STR - MBGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display routes learned from neighbor\n") -{ - struct peer *peer; - - peer = peer_lookup_in_view (vty, NULL, argv[0]); - if (! peer) - return CMD_WARNING; - - return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_MULTICAST, - bgp_show_type_neighbor); -} - -ALIAS (show_bgp_view_neighbor_flap, - show_bgp_neighbor_flap_cmd, - "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", - SHOW_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display flap statistics of the routes learned from neighbor\n") - ALIAS (show_bgp_view_neighbor_flap, show_bgp_ipv6_neighbor_flap_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", @@ -11497,16 +11294,6 @@ ALIAS (show_bgp_view_neighbor_flap, "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") -ALIAS (show_bgp_view_neighbor_damp, - show_bgp_neighbor_damp_cmd, - "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", - SHOW_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the dampened routes received from neighbor\n") - ALIAS (show_bgp_view_neighbor_damp, show_bgp_ipv6_neighbor_damp_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", @@ -11518,18 +11305,62 @@ ALIAS (show_bgp_view_neighbor_damp, "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") -DEFUN (show_bgp_view_rsclient, - show_bgp_view_rsclient_cmd, - "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", +#endif /* HAVE_IPV6 */ + +DEFUN (show_bgp_view_ipv4_rsclient, + show_bgp_view_ipv4_rsclient_cmd, + "show bgp view WORD ipv4 rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" + "Address Family\n" "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR) + NEIGHBOR_ADDR_STR2) { - struct bgp_table *table; - struct peer *peer; + struct bgp_table *table; + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP][SAFI_UNICAST]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); +} +DEFUN (show_bgp_view_ipv6_rsclient, + show_bgp_view_ipv6_rsclient_cmd, + "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address Family\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR2) +{ + struct bgp_table *table; + struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); @@ -11559,13 +11390,24 @@ DEFUN (show_bgp_view_rsclient, return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } -ALIAS (show_bgp_view_rsclient, - show_bgp_rsclient_cmd, - "show bgp rsclient (A.B.C.D|X:X::X:X)", +ALIAS (show_bgp_view_ipv4_rsclient, + show_bgp_ipv4_rsclient_cmd, + "show bgp ipv4 rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR + "Address Family\n" "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR) + NEIGHBOR_ADDR_STR2) + +#ifdef HAVE_IPV6 +ALIAS (show_bgp_view_ipv6_rsclient, + show_bgp_ipv6_rsclient_cmd, + "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Address Family\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR2) DEFUN (show_bgp_view_ipv6_safi_rsclient, show_bgp_view_ipv6_safi_rsclient_cmd, @@ -11626,13 +11468,15 @@ ALIAS (show_bgp_view_ipv6_safi_rsclient, "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) + DEFUN (show_bgp_view_rsclient_route, show_bgp_view_rsclient_route_cmd, - "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "BGP view\n" - "View name\n" + "BGP view name\n" + "IP6_STR" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") @@ -11690,9 +11534,10 @@ DEFUN (show_bgp_view_rsclient_route, ALIAS (show_bgp_view_rsclient_route, show_bgp_rsclient_route_cmd, - "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR + IP6_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") @@ -11778,13 +11623,15 @@ ALIAS (show_bgp_view_ipv6_safi_rsclient_route, NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") + DEFUN (show_bgp_view_rsclient_prefix, show_bgp_view_rsclient_prefix_cmd, - "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" + IP6_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") @@ -11842,7 +11689,7 @@ DEFUN (show_bgp_view_rsclient_prefix, ALIAS (show_bgp_view_rsclient_prefix, show_bgp_rsclient_prefix_cmd, - "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "Information about Route Server Client\n" @@ -12294,47 +12141,143 @@ ALIAS (bgp_damp_unset, "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") -DEFUN (show_ip_bgp_dampened_paths, - show_ip_bgp_dampened_paths_cmd, - "show ip bgp dampened-paths", +DEFUN (show_bgp_ipv4_safi_dampened_paths, + show_bgp_ipv4_safi_dampened_paths_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampened-paths", SHOW_STR - IP_STR BGP_STR + IP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display paths suppressed due to dampening\n") { - return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths, - NULL); -} + safi_t safi; -ALIAS (show_ip_bgp_dampened_paths, - show_ip_bgp_damp_dampened_paths_cmd, - "show ip bgp dampening dampened-paths", + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, NULL, AFI_IP, safi, bgp_show_type_dampend_paths, NULL); +} +ALIAS (show_bgp_ipv4_safi_dampened_paths, + show_bgp_ipv4_safi_damp_dampened_paths_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening dampened-paths", SHOW_STR + BGP_STR IP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display paths suppressed due to dampening\n") +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_dampened_paths, + show_bgp_ipv6_safi_dampened_paths_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampened-paths", + SHOW_STR + BGP_STR + IPV6_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display paths suppressed due to dampening\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, NULL, AFI_IP6, safi, bgp_show_type_dampend_paths, NULL); +} +ALIAS (show_bgp_ipv6_safi_dampened_paths, + show_bgp_ipv6_safi_damp_dampened_paths_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening dampened-paths", + SHOW_STR BGP_STR + IPV6_STR + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") +#endif -DEFUN (show_ip_bgp_flap_statistics, - show_ip_bgp_flap_statistics_cmd, - "show ip bgp flap-statistics", +DEFUN (show_bgp_ipv4_safi_flap_statistics, + show_bgp_ipv4_safi_flap_statistics_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics", SHOW_STR - IP_STR BGP_STR + "Address Family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display flap statistics of routes\n") { - return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, - bgp_show_type_flap_statistics, NULL); + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, NULL, AFI_IP, safi, bgp_show_type_flap_statistics, NULL); } +ALIAS (show_bgp_ipv4_safi_flap_statistics, + show_bgp_ipv4_safi_damp_flap_statistics_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics", + SHOW_STR + BGP_STR + "Address Family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n") +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_statistics, + show_bgp_ipv6_safi_flap_statistics_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics", + SHOW_STR + BGP_STR + "Address Family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } -ALIAS (show_ip_bgp_flap_statistics, - show_ip_bgp_damp_flap_statistics_cmd, - "show ip bgp dampening flap-statistics", + return bgp_show (vty, NULL, AFI_IP6, safi, bgp_show_type_flap_statistics, NULL); +} +ALIAS (show_bgp_ipv6_safi_flap_statistics, + show_bgp_ipv6_safi_damp_flap_statistics_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics", SHOW_STR - IP_STR BGP_STR + "Address Family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") +#endif /* Display specified route of BGP table. */ static int @@ -12786,248 +12729,280 @@ bgp_route_init (void) install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd); - install_element (VIEW_NODE, &show_ip_bgp_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd); - install_element (VIEW_NODE, &show_ip_bgp_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_rd_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_rd_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); - install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); - install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_afi_safi_view_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_cidr_only_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_cidr_only_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community4_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); - install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); - install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd); - install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_address_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); - install_element (VIEW_NODE, &show_ip_bgp_damp_flap_route_map_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); - install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_dampened_paths_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_dampened_paths_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_statistics_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_statistics_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_address_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_flap_address_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_address_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd); - install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); - install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* Restricted node: VIEW_NODE - (set of dangerous commands) */ - install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_rd_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_rd_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rd_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rd_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_view_prefix_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community2_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community3_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community4_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_community4_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rd_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rd_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_afi_safi_view_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_cidr_only_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cidr_only_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community4_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_address_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_address_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_flap_address_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_address_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* BGP dampening clear commands */ @@ -13037,9 +13012,8 @@ bgp_route_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); /* prefix count */ - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_prefix_counts_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_prefix_counts_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd); @@ -13066,84 +13040,49 @@ bgp_route_init (void) install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd); - install_element (VIEW_NODE, &show_bgp_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd); - install_element (VIEW_NODE, &show_bgp_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd); - install_element (VIEW_NODE, &show_bgp_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd); - install_element (VIEW_NODE, &show_bgp_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); - install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); - install_element (VIEW_NODE, &show_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); - install_element (VIEW_NODE, &show_bgp_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); - install_element (VIEW_NODE, &show_bgp_community_all_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); - install_element (VIEW_NODE, &show_bgp_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); - install_element (VIEW_NODE, &show_bgp_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); - install_element (VIEW_NODE, &show_bgp_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); - install_element (VIEW_NODE, &show_bgp_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); - install_element (VIEW_NODE, &show_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_community_list_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); - install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); - install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); - install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); - install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); - install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); - install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd); - install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); - install_element (VIEW_NODE, &show_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); - install_element (VIEW_NODE, &show_bgp_view_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); - install_element (VIEW_NODE, &show_bgp_view_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd); - install_element (VIEW_NODE, &show_bgp_view_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd); - install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); - install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); - install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); - install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); - install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); - install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv4_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); @@ -13153,121 +13092,74 @@ bgp_route_init (void) /* Restricted: * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev) */ - install_element (RESTRICTED_NODE, &show_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd); - install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); - install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd); - install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd); - install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd); - install_element (ENABLE_NODE, &show_bgp_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd); - install_element (ENABLE_NODE, &show_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_route_map_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_community_all_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); - install_element (ENABLE_NODE, &show_bgp_community_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); - install_element (ENABLE_NODE, &show_bgp_community2_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_community3_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_community4_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); - install_element (ENABLE_NODE, &show_bgp_view_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv4_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); @@ -13276,103 +13168,7 @@ bgp_route_init (void) /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); - //install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); - install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); - //install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); - - /* old command */ - install_element (VIEW_NODE, &show_ipv6_bgp_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); - - /* old command */ - install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); - - /* old command */ - install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); - install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); - - /* old command */ - install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); - install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); - - /* old command */ - install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); - install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); #endif /* HAVE_IPV6 */ install_element (BGP_NODE, &bgp_distance_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 94796c743..2df230966 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7394,35 +7394,10 @@ bgp_show_summary_vty (struct vty *vty, const char *name, } /* `show ip bgp summary' commands. */ -DEFUN (show_ip_bgp_summary, - show_ip_bgp_summary_cmd, - "show ip bgp summary", - SHOW_STR - IP_STR - BGP_STR - "Summary of BGP neighbor status\n") -{ - return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); -} - -DEFUN (show_ip_bgp_instance_summary, - show_ip_bgp_instance_summary_cmd, - "show ip bgp view WORD summary", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Summary of BGP neighbor status\n") -{ - return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); -} - -DEFUN (show_ip_bgp_ipv4_summary, - show_ip_bgp_ipv4_summary_cmd, - "show ip bgp ipv4 (unicast|multicast) summary", +DEFUN (show_bgp_ipv4_safi_summary, + show_bgp_ipv4_safi_summary_cmd, + "show bgp ipv4 (unicast|multicast) summary", SHOW_STR - IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -7435,21 +7410,10 @@ DEFUN (show_ip_bgp_ipv4_summary, return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } -ALIAS (show_ip_bgp_ipv4_summary, - show_bgp_ipv4_safi_summary_cmd, - "show bgp ipv4 (unicast|multicast) summary", - SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Summary of BGP neighbor status\n") - -DEFUN (show_ip_bgp_instance_ipv4_summary, - show_ip_bgp_instance_ipv4_summary_cmd, - "show ip bgp view WORD ipv4 (unicast|multicast) summary", +DEFUN (show_bgp_instance_ipv4_safi_summary, + show_bgp_instance_ipv4_safi_summary_cmd, + "show bgp view WORD ipv4 (unicast|multicast) summary", SHOW_STR - IP_STR BGP_STR "BGP view\n" "View name\n" @@ -7464,66 +7428,64 @@ DEFUN (show_ip_bgp_instance_ipv4_summary, return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } -ALIAS (show_ip_bgp_instance_ipv4_summary, - show_bgp_instance_ipv4_safi_summary_cmd, - "show bgp view WORD ipv4 (unicast|multicast) summary", +DEFUN (show_bgp_ipv4_vpn_summary, + show_bgp_ipv4_vpn_summary_cmd, + "show bgp ipv4 vpn summary", SHOW_STR BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" + "IPv4\n" + "Display VPN NLRI specific information\n" "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} -DEFUN (show_ip_bgp_vpnv4_all_summary, - show_ip_bgp_vpnv4_all_summary_cmd, - "show ip bgp vpnv4 all summary", +#ifdef HAVE_IPV6 + +/* `show ip bgp summary' commands. */ +DEFUN (show_bgp_ipv6_vpn_summary, + show_bgp_ipv6_vpn_summary_cmd, + "show bgp ipv6 vpn summary", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" + "IPv6\n" + "Display VPN NLRI specific information\n" "Summary of BGP neighbor status\n") { - return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); } +#endif -DEFUN (show_ip_bgp_vpnv4_rd_summary, - show_ip_bgp_vpnv4_rd_summary_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", +DEFUN (show_bgp_ipv4_encap_summary, + show_bgp_ipv4_encap_summary_cmd, + "show bgp ipv4 encap summary", SHOW_STR - IP_STR BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" + "IPv4\n" + "Display ENCAP NLRI specific information\n" "Summary of BGP neighbor status\n") { - int ret; - struct prefix_rd prd; - - ret = str2prefix_rd (argv[0], &prd); - if (! ret) - { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } - - return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); } #ifdef HAVE_IPV6 -DEFUN (show_bgp_summary, - show_bgp_summary_cmd, - "show bgp summary", + +DEFUN (show_bgp_ipv6_encap_summary, + show_bgp_ipv6_encap_summary_cmd, + "show bgp ipv6 encap summary", SHOW_STR BGP_STR + "IPv6\n" + "Display ENCAP NLRI specific information\n" "Summary of BGP neighbor status\n") { - return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); } +#endif + + + DEFUN (show_bgp_instance_summary, show_bgp_instance_summary_cmd, "show bgp view WORD summary", @@ -7533,26 +7495,93 @@ DEFUN (show_bgp_instance_summary, "View name\n" "Summary of BGP neighbor status\n") { - return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); + +#ifdef HAVE_IPV6 + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); +#endif + return CMD_SUCCESS; } -ALIAS (show_bgp_summary, - show_bgp_ipv6_summary_cmd, - "show bgp ipv6 summary", +DEFUN (show_bgp_instance_ipv4_summary, + show_bgp_instance_ipv4_summary_cmd, + "show bgp view WORD ipv4 summary", SHOW_STR BGP_STR - "Address family\n" + IP_STR + "Address Family modifier\n" + "Address Family modifier\n" + "BGP view\n" + "View name\n" "Summary of BGP neighbor status\n") +{ + vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); + + return CMD_SUCCESS; +} + -ALIAS (show_bgp_instance_summary, +#ifdef HAVE_IPV6 +DEFUN (show_bgp_instance_ipv6_summary, show_bgp_instance_ipv6_summary_cmd, "show bgp view WORD ipv6 summary", SHOW_STR BGP_STR + IPV6_STR + "Address Family modifier\n" + "Address Family modifier\n" "BGP view\n" "View name\n" - "Address family\n" "Summary of BGP neighbor status\n") +{ + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); + + return CMD_SUCCESS; +} DEFUN (show_bgp_ipv6_safi_summary, show_bgp_ipv6_safi_summary_cmd, @@ -7588,30 +7617,152 @@ DEFUN (show_bgp_instance_ipv6_safi_summary, return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } -/* old command */ -DEFUN (show_ipv6_bgp_summary, - show_ipv6_bgp_summary_cmd, - "show ipv6 bgp summary", +#endif /* HAVE_IPV6 */ + +/* variations of show bgp [...] summary */ + +/* This one is for the 0-keyword variant */ +DEFUN (show_bgp_summary, + show_bgp_summary_cmd, + "show bgp summary", SHOW_STR - IPV6_STR BGP_STR "Summary of BGP neighbor status\n") { - return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); + +#ifdef HAVE_IPV6 + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); +#endif + return CMD_SUCCESS; } -/* old command */ -DEFUN (show_ipv6_mbgp_summary, - show_ipv6_mbgp_summary_cmd, - "show ipv6 mbgp summary", +DEFUN (show_bgp_summary_1w, + show_bgp_summary_1w_cmd, +#ifdef HAVE_IPV6 + "show bgp (ipv4|ipv6|unicast|multicast|vpn|encap) summary", +#else + "show bgp (ipv4|unicast|multicast|vpn|encap) summary", +#endif SHOW_STR - IPV6_STR - MBGP_STR + BGP_STR + IP_STR +#ifdef HAVE_IPV6 + IP6_STR +#endif + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" "Summary of BGP neighbor status\n") { - return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); + if (strcmp (argv[0], "ipv4") == 0) { + vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); + return CMD_SUCCESS; + } +#ifdef HAVE_IPV6 + if (strcmp (argv[0], "ipv6") == 0) { + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); + return CMD_SUCCESS; + } +#endif + if (strcmp (argv[0], "unicast") == 0) { + vty_out(vty, "IPv4 Unicast Summary:%s", VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +#ifdef HAVE_IPV6 + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "IPv6 Unicast Summary:%s", VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +#endif + return CMD_SUCCESS; + } + if (strcmp (argv[0], "multicast") == 0) { + vty_out(vty, "IPv4 Multicast Summary:%s", VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); +#ifdef HAVE_IPV6 + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "IPv6 Multicast Summary:%s", VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); +#endif + return CMD_SUCCESS; + } + if (strcmp (argv[0], "vpn") == 0) { + vty_out(vty, "IPv4 VPN Summary:%s", VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +#ifdef HAVE_IPV6 + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "IPv6 VPN Summary:%s", VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); +#endif + return CMD_SUCCESS; + } + if (strcmp (argv[0], "encap") == 0) { + vty_out(vty, "IPv4 Encap Summary:%s", VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); +#ifdef HAVE_IPV6 + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, "IPv6 Encap Summary:%s", VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); +#endif + return CMD_SUCCESS; + } + vty_out(vty, "Unknown keyword: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; } -#endif /* HAVE_IPV6 */ + + const char * afi_safi_print (afi_t afi, safi_t safi) @@ -8345,145 +8496,33 @@ bgp_show_neighbor_vty (struct vty *vty, const char *name, } /* "show ip bgp neighbors" commands. */ -DEFUN (show_ip_bgp_neighbors, - show_ip_bgp_neighbors_cmd, - "show ip bgp neighbors", - SHOW_STR - IP_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n") -{ - return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); -} - -ALIAS (show_ip_bgp_neighbors, - show_ip_bgp_ipv4_neighbors_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors", - SHOW_STR - IP_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Detailed information on TCP and BGP neighbor connections\n") - -ALIAS (show_ip_bgp_neighbors, - show_ip_bgp_vpnv4_all_neighbors_cmd, - "show ip bgp vpnv4 all neighbors", - SHOW_STR - IP_STR - BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" - "Detailed information on TCP and BGP neighbor connections\n") - -ALIAS (show_ip_bgp_neighbors, - show_ip_bgp_vpnv4_rd_neighbors_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", - SHOW_STR - IP_STR - BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - "Detailed information on TCP and BGP neighbor connections\n") - -ALIAS (show_ip_bgp_neighbors, +DEFUN (show_bgp_neighbors, show_bgp_neighbors_cmd, "show bgp neighbors", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n") - -ALIAS (show_ip_bgp_neighbors, - show_bgp_ipv6_neighbors_cmd, - "show bgp ipv6 neighbors", - SHOW_STR - BGP_STR - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n") - -DEFUN (show_ip_bgp_neighbors_peer, - show_ip_bgp_neighbors_peer_cmd, - "show ip bgp neighbors (A.B.C.D|X:X::X:X)", - SHOW_STR - IP_STR - BGP_STR - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n") { - return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); + return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); } -ALIAS (show_ip_bgp_neighbors_peer, - show_ip_bgp_ipv4_neighbors_peer_cmd, - "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", - SHOW_STR - IP_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n") - -ALIAS (show_ip_bgp_neighbors_peer, - show_ip_bgp_vpnv4_all_neighbors_peer_cmd, - "show ip bgp vpnv4 all neighbors A.B.C.D", - SHOW_STR - IP_STR - BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n") - -ALIAS (show_ip_bgp_neighbors_peer, - show_ip_bgp_vpnv4_rd_neighbors_peer_cmd, - "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", - SHOW_STR - IP_STR - BGP_STR - "Display VPNv4 NLRI specific information\n" - "Display information about all VPNv4 NLRIs\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n") - -ALIAS (show_ip_bgp_neighbors_peer, +DEFUN (show_bgp_neighbors_peer, show_bgp_neighbors_peer_cmd, +#ifdef HAVE_IPV6 "show bgp neighbors (A.B.C.D|X:X::X:X)", +#else + "show bgp neighbors (A.B.C.D)", +#endif /* HAVE_IPV6 */ SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") - -ALIAS (show_ip_bgp_neighbors_peer, - show_bgp_ipv6_neighbors_peer_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", - SHOW_STR - BGP_STR - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n") - -DEFUN (show_ip_bgp_instance_neighbors, - show_ip_bgp_instance_neighbors_cmd, - "show ip bgp view WORD neighbors", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Detailed information on TCP and BGP neighbor connections\n") { - return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); + return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); } -ALIAS (show_ip_bgp_instance_neighbors, +DEFUN (show_bgp_instance_neighbors, show_bgp_instance_neighbors_cmd, "show bgp view WORD neighbors", SHOW_STR @@ -8491,8 +8530,11 @@ ALIAS (show_ip_bgp_instance_neighbors, "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") +{ + return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); +} -ALIAS (show_ip_bgp_instance_neighbors, +ALIAS (show_bgp_instance_neighbors, show_bgp_instance_ipv6_neighbors_cmd, "show bgp view WORD ipv6 neighbors", SHOW_STR @@ -8502,11 +8544,14 @@ ALIAS (show_ip_bgp_instance_neighbors, "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") -DEFUN (show_ip_bgp_instance_neighbors_peer, - show_ip_bgp_instance_neighbors_peer_cmd, - "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", +DEFUN (show_bgp_instance_neighbors_peer, + show_bgp_instance_neighbors_peer_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", +#else + "show bgp view WORD neighbors (A.B.C.D)", +#endif SHOW_STR - IP_STR BGP_STR "BGP view\n" "View name\n" @@ -8517,18 +8562,7 @@ DEFUN (show_ip_bgp_instance_neighbors_peer, return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]); } -ALIAS (show_ip_bgp_instance_neighbors_peer, - show_bgp_instance_neighbors_peer_cmd, - "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n") - -ALIAS (show_ip_bgp_instance_neighbors_peer, +ALIAS (show_bgp_instance_neighbors_peer, show_bgp_instance_ipv6_neighbors_peer_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X)", SHOW_STR @@ -8543,11 +8577,10 @@ ALIAS (show_ip_bgp_instance_neighbors_peer, /* Show BGP's AS paths internal data. There are both `show ip bgp paths' and `show ip mbgp paths'. Those functions results are the same.*/ -DEFUN (show_ip_bgp_paths, - show_ip_bgp_paths_cmd, - "show ip bgp paths", +DEFUN (show_bgp_ipv4_paths, + show_bgp_ipv4_paths_cmd, + "show bgp paths", SHOW_STR - IP_STR BGP_STR "Path information\n") { @@ -8556,23 +8589,6 @@ DEFUN (show_ip_bgp_paths, return CMD_SUCCESS; } -DEFUN (show_ip_bgp_ipv4_paths, - show_ip_bgp_ipv4_paths_cmd, - "show ip bgp ipv4 (unicast|multicast) paths", - SHOW_STR - IP_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Path information\n") -{ - vty_out (vty, "Address Refcnt Path\r\n"); - aspath_print_all_vty (vty); - - return CMD_SUCCESS; -} - #include "hash.h" static void @@ -8756,69 +8772,6 @@ bgp_show_rsclient_summary_vty (struct vty *vty, const char *name, } /* 'show bgp rsclient' commands. */ -DEFUN (show_ip_bgp_rsclient_summary, - show_ip_bgp_rsclient_summary_cmd, - "show ip bgp rsclient summary", - SHOW_STR - IP_STR - BGP_STR - "Information about Route Server Clients\n" - "Summary of all Route Server Clients\n") -{ - return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); -} - -DEFUN (show_ip_bgp_instance_rsclient_summary, - show_ip_bgp_instance_rsclient_summary_cmd, - "show ip bgp view WORD rsclient summary", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Information about Route Server Clients\n" - "Summary of all Route Server Clients\n") -{ - return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); -} - -DEFUN (show_ip_bgp_ipv4_rsclient_summary, - show_ip_bgp_ipv4_rsclient_summary_cmd, - "show ip bgp ipv4 (unicast|multicast) rsclient summary", - SHOW_STR - IP_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Information about Route Server Clients\n" - "Summary of all Route Server Clients\n") -{ - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); - - return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); -} - -DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, - show_ip_bgp_instance_ipv4_rsclient_summary_cmd, - "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Information about Route Server Clients\n" - "Summary of all Route Server Clients\n") -{ - if (strncmp (argv[1], "m", 1) == 0) - return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); - - return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); -} DEFUN (show_bgp_instance_ipv4_safi_rsclient_summary, show_bgp_instance_ipv4_safi_rsclient_summary_cmd, @@ -8855,7 +8808,6 @@ ALIAS (show_bgp_instance_ipv4_safi_rsclient_summary, "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_rsclient_summary, show_bgp_rsclient_summary_cmd, "show bgp rsclient summary", @@ -8864,7 +8816,34 @@ DEFUN (show_bgp_rsclient_summary, "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { - return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); + +#ifdef HAVE_IPV6 + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); +#endif + return CMD_SUCCESS; } DEFUN (show_bgp_instance_rsclient_summary, @@ -8877,10 +8856,38 @@ DEFUN (show_bgp_instance_rsclient_summary, "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { - return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); + vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); + +#ifdef HAVE_IPV6 + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); +#endif + return CMD_SUCCESS; } -ALIAS (show_bgp_rsclient_summary, +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_rsclient_summary, show_bgp_ipv6_rsclient_summary_cmd, "show bgp ipv6 rsclient summary", SHOW_STR @@ -8888,8 +8895,24 @@ ALIAS (show_bgp_rsclient_summary, "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") +{ + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); + + return CMD_SUCCESS; +} -ALIAS (show_bgp_instance_rsclient_summary, +DEFUN (show_bgp_instance_ipv6_rsclient_summary, show_bgp_instance_ipv6_rsclient_summary_cmd, "show bgp view WORD ipv6 rsclient summary", SHOW_STR @@ -8899,6 +8922,22 @@ ALIAS (show_bgp_instance_rsclient_summary, "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") +{ + vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "---------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); + vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); + vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-----------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); + vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); + vty_out(vty, "-------------------%s", VTY_NEWLINE); + bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); + + return CMD_SUCCESS; +} DEFUN (show_bgp_instance_ipv6_safi_rsclient_summary, show_bgp_instance_ipv6_safi_rsclient_summary_cmd, @@ -8929,7 +8968,7 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, "show bgp ipv6 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR - "Address family\n" + IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" @@ -10639,157 +10678,122 @@ bgp_vty_init (void) #endif /* HAVE_IPV6 */ /* "show ip bgp summary" commands. */ - install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_bgp_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_summary_cmd); + + install_element (VIEW_NODE, &show_bgp_summary_1w_cmd); + install_element (RESTRICTED_NODE, &show_bgp_summary_1w_cmd); + install_element (ENABLE_NODE, &show_bgp_summary_1w_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv4_summary_cmd); + + install_element (VIEW_NODE, &show_bgp_ipv4_vpn_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_encap_summary_cmd); #ifdef HAVE_IPV6 - install_element (VIEW_NODE, &show_bgp_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_vpn_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_encap_summary_cmd); +#endif + install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); +#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ - install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); + + install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_summary_cmd); #ifdef HAVE_IPV6 - install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd); +#endif + install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd); +#ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ - install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); + + install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_encap_summary_cmd); #ifdef HAVE_IPV6 - install_element (ENABLE_NODE, &show_bgp_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_encap_summary_cmd); +#endif + install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); +#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp neighbors" commands. */ - install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); - install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_neighbors_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_neighbors_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); - install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd); - install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_neighbors_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_peer_cmd); +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); - /* Old commands. */ - install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); - install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp rsclient" commands. */ - install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd); - install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp paths" commands. */ - install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); - install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_paths_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_paths_cmd); /* "show ip bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); From bf1ae6c683a53d7f43c273afb55d52ccc233296b Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:08 -0500 Subject: [PATCH 0952/1342] bgpd: drop machineparse / random "show" improvements Signed-off-by: Lou Berger --- bgpd/bgp_mplsvpn.c | 14 ++++++++++++++ bgpd/bgp_route.c | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 9f06538ec..99e86b43d 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -484,6 +484,9 @@ bgp_show_mpls_vpn( char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; + unsigned long output_count = 0; + unsigned long total_count = 0; + bgp = bgp_get_default (); if (bgp == NULL) { @@ -509,6 +512,7 @@ bgp_show_mpls_vpn( for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) for (ri = rm->info; ri; ri = ri->next) { + total_count++; if (type == bgp_show_type_neighbor) { union sockunion *su = output_arg; @@ -568,9 +572,19 @@ bgp_show_mpls_vpn( route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); else route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); + output_count++; } } } + + if (output_count == 0) + { + vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); + } + else + vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", + VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); + return CMD_SUCCESS; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0ea7ced86..7890e3aa3 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5940,8 +5940,12 @@ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo) /* called from terminal list command */ void -route_vty_out (struct vty *vty, struct prefix *p, - struct bgp_info *binfo, int display, safi_t safi) +route_vty_out( + struct vty *vty, + struct prefix *p, + struct bgp_info *binfo, + int display, + safi_t safi) { struct attr *attr; @@ -5949,7 +5953,7 @@ route_vty_out (struct vty *vty, struct prefix *p, route_vty_short_status_out (vty, binfo); /* print prefix and mask */ - if (! display) + if (!display) route_vty_out_route (p, vty); else vty_out (vty, "%*s", 17, " "); @@ -6025,14 +6029,14 @@ route_vty_out (struct vty *vty, struct prefix *p, if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) - vty_out (vty, "%10u", attr->med); + vty_out (vty, "%10u ", attr->med); else - vty_out (vty, " "); + vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) - vty_out (vty, "%7u", attr->local_pref); + vty_out (vty, "%7u ", attr->local_pref); else - vty_out (vty, " "); + vty_out (vty, " "); vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0)); @@ -6090,12 +6094,12 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, #endif /* HAVE_IPV6 */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) - vty_out (vty, "%10u", attr->med); + vty_out (vty, "%10u ", attr->med); else vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) - vty_out (vty, "%7u", attr->local_pref); + vty_out (vty, "%7u ", attr->local_pref); else vty_out (vty, " "); @@ -6346,7 +6350,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, vty_out (vty, " (inaccessible)"); else if (binfo->extra && binfo->extra->igpmetric) vty_out (vty, " (metric %u)", binfo->extra->igpmetric); - vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); + if (!sockunion2str (&binfo->peer->su, buf, sizeof(buf))) { + buf[0] = '?'; + buf[1] = 0; + } + vty_out (vty, " from %s", buf); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); else @@ -6500,9 +6508,11 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router int header = 1; int display; unsigned long output_count; + unsigned long total_count; /* This is first entry point, so reset total line. */ output_count = 0; + total_count = 0; /* Start processing of routes. */ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) @@ -6512,6 +6522,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router for (ri = rn->info; ri; ri = ri->next) { + total_count++; if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix @@ -6706,11 +6717,11 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router if (output_count == 0) { if (type == bgp_show_type_normal) - vty_out (vty, "No BGP network exists%s", VTY_NEWLINE); + vty_out (vty, "No BGP prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); } else - vty_out (vty, "%sTotal number of prefixes %ld%s", - VTY_NEWLINE, output_count, VTY_NEWLINE); + vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", + VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); return CMD_SUCCESS; } @@ -9786,7 +9797,7 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) if (!bgp->rib[afi][safi]) { - vty_out (vty, "%% No RIB exist for the AFI/SAFI%s", VTY_NEWLINE); + vty_out (vty, "%% No RIB exists for the AFI/SAFI%s", VTY_NEWLINE); return CMD_WARNING; } @@ -9877,7 +9888,7 @@ bgp_table_stats_vty (struct vty *vty, const char *name, if (!bgp) { - vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); + vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp (afi_str, "ipv", 3) == 0) From f9b6c3938642090ffa1cae8b7125abff2b1e9fb0 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:09 -0500 Subject: [PATCH 0953/1342] bgpd: Add back old forms of 'show ' for compatibility Signed-off-by: Lou Berger --- bgpd/bgp_route.c | 6821 +++++++++++++++++++++++++++++++++++----------- bgpd/bgp_vty.c | 459 +++- 2 files changed, 5703 insertions(+), 1577 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7890e3aa3..93c613fa1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6961,6 +6961,248 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, } /* BGP route print out function. */ +DEFUN (show_ip_bgp, + show_ip_bgp_cmd, + "show ip bgp", + SHOW_STR + IP_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); +} + +DEFUN (show_ip_bgp_ipv4, + show_ip_bgp_ipv4_cmd, + "show ip bgp ipv4 (unicast|multicast)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_normal, + NULL); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); +} + +DEFUN (show_ip_bgp_route, + show_ip_bgp_route_cmd, + "show ip bgp A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_ipv4_route, + show_ip_bgp_ipv4_route_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_route, + show_ip_bgp_vpnv4_all_route_cmd, + "show ip bgp vpnv4 all A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd_route, + show_ip_bgp_vpnv4_rd_route_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Network in the BGP routing table to display\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); +} + +DEFUN (show_ip_bgp_prefix, + show_ip_bgp_prefix_cmd, + "show ip bgp A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_ipv4_prefix, + show_ip_bgp_ipv4_prefix_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_prefix, + show_ip_bgp_vpnv4_all_prefix_cmd, + "show ip bgp vpnv4 all A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_prefix, + show_ip_bgp_vpnv4_rd_prefix_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); +} + +DEFUN (show_ip_bgp_view, + show_ip_bgp_view_cmd, + "show ip bgp view WORD", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n") +{ + struct bgp *bgp; + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, bgp, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); +} + +DEFUN (show_ip_bgp_view_route, + show_ip_bgp_view_route_cmd, + "show ip bgp view WORD A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_view_prefix, + show_ip_bgp_view_prefix_cmd, + "show ip bgp view WORD A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_bgp, + show_bgp_cmd, + "show bgp", + SHOW_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, + NULL); +} + +ALIAS (show_bgp, + show_bgp_ipv6_cmd, + "show bgp ipv6", + SHOW_STR + BGP_STR + "Address family\n") + +/* old command */ +DEFUN (show_ipv6_bgp, + show_ipv6_bgp_cmd, + "show ipv6 bgp", + SHOW_STR + IP_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, + NULL); +} + +DEFUN (show_bgp_route, + show_bgp_route_cmd, + "show bgp X:X::X:X", + SHOW_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + DEFUN (show_bgp_ipv4_safi, show_bgp_ipv4_safi_cmd, "show bgp ipv4 (unicast|multicast)", @@ -7454,6 +7696,29 @@ DEFUN (show_bgp_ipv6_safi_route, return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } +/* old command */ +DEFUN (show_ipv6_bgp_route, + show_ipv6_bgp_route_cmd, + "show ipv6 bgp X:X::X:X", + SHOW_STR + IP_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_bgp_prefix, + show_bgp_prefix_cmd, + "show bgp X:X::X:X/M", + SHOW_STR + BGP_STR + "IPv6 prefix /\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + + /* new002 */ DEFUN (show_bgp_ipv6_prefix, show_bgp_ipv6_prefix_cmd, @@ -7481,7 +7746,40 @@ DEFUN (show_bgp_ipv6_safi_prefix, return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } +/* old command */ +DEFUN (show_ipv6_bgp_prefix, + show_ipv6_bgp_prefix_cmd, + "show ipv6 bgp X:X::X:X/M", + SHOW_STR + IP_STR + BGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + DEFUN (show_bgp_view, + show_bgp_view_cmd, + "show bgp view WORD", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n") +{ + struct bgp *bgp; + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, bgp, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); +} + +DEFUN (show_bgp_view_ipv6, show_bgp_view_ipv6_cmd, "show bgp view WORD ipv6", SHOW_STR @@ -7504,6 +7802,18 @@ DEFUN (show_bgp_view, } DEFUN (show_bgp_view_route, + show_bgp_view_route_cmd, + "show bgp view WORD X:X::X:X", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_bgp_view_ipv6_route, show_bgp_view_ipv6_route_cmd, "show bgp view WORD ipv6 X:X::X:X", SHOW_STR @@ -7516,7 +7826,55 @@ DEFUN (show_bgp_view_route, return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } +/* old command */ +DEFUN (show_ipv6_mbgp, + show_ipv6_mbgp_cmd, + "show ipv6 mbgp", + SHOW_STR + IP_STR + MBGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, + NULL); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_route, + show_ipv6_mbgp_route_cmd, + "show ipv6 mbgp X:X::X:X", + SHOW_STR + IP_STR + MBGP_STR + "Network in the MBGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix, + show_ipv6_mbgp_prefix_cmd, + "show ipv6 mbgp X:X::X:X/M", + SHOW_STR + IP_STR + MBGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); +} + DEFUN (show_bgp_view_prefix, + show_bgp_view_prefix_cmd, + "show bgp view WORD X:X::X:X/M", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "IPv6 prefix /\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_bgp_view_ipv6_prefix, show_bgp_view_ipv6_prefix_cmd, "show bgp view WORD ipv6 X:X::X:X/M", SHOW_STR @@ -7577,15 +7935,116 @@ bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi, return rc; } -DEFUN (show_bgp_ipv4_safi_flap_regexp, - show_bgp_ipv4_safi_flap_regexp_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", + +DEFUN (show_ip_bgp_regexp, + show_ip_bgp_regexp_cmd, + "show ip bgp regexp .LINE", SHOW_STR - BGP_STR IP_STR - "Address Family Modifier\n" - "Address Family Modifier\n" - "Address Family Modifier\n" + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_regexp); +} + +DEFUN (show_ip_bgp_flap_regexp, + show_ip_bgp_flap_regexp_cmd, + "show ip bgp flap-statistics regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_regexp); +} + +ALIAS (show_ip_bgp_flap_regexp, + show_ip_bgp_damp_flap_regexp_cmd, + "show ip bgp dampening flap-statistics regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFUN (show_ip_bgp_ipv4_regexp, + show_ip_bgp_ipv4_regexp_cmd, + "show ip bgp ipv4 (unicast|multicast) regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, + bgp_show_type_regexp); + + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_regexp); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_regexp, + show_bgp_regexp_cmd, + "show bgp regexp .LINE", + SHOW_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + bgp_show_type_regexp); +} + +/* old command */ +DEFUN (show_ipv6_bgp_regexp, + show_ipv6_bgp_regexp_cmd, + "show ipv6 bgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + bgp_show_type_regexp); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_regexp, + show_ipv6_mbgp_regexp_cmd, + "show ipv6 mbgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the MBGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_regexp); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_bgp_ipv4_safi_flap_regexp, + show_bgp_ipv4_safi_flap_regexp_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", + SHOW_STR + BGP_STR + IP_STR + "Address Family Modifier\n" + "Address Family Modifier\n" + "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" @@ -7734,6 +8193,114 @@ bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi, return bgp_show (vty, NULL, afi, safi, type, plist); } +DEFUN (show_ip_bgp_prefix_list, + show_ip_bgp_prefix_list_cmd, + "show ip bgp prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +DEFUN (show_ip_bgp_flap_prefix_list, + show_ip_bgp_flap_prefix_list_cmd, + "show ip bgp flap-statistics prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix_list); +} + +ALIAS (show_ip_bgp_flap_prefix_list, + show_ip_bgp_damp_flap_prefix_list_cmd, + "show ip bgp dampening flap-statistics prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") + +DEFUN (show_ip_bgp_ipv4_prefix_list, + show_ip_bgp_ipv4_prefix_list_cmd, + "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_prefix_list); + + return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_list, + show_bgp_prefix_list_cmd, + "show bgp prefix-list WORD", + SHOW_STR + BGP_STR + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +ALIAS (show_bgp_prefix_list, + show_bgp_ipv6_prefix_list_cmd, + "show bgp ipv6 prefix-list WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_list, + show_ipv6_bgp_prefix_list_cmd, + "show ipv6 bgp prefix-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_list, + show_ipv6_mbgp_prefix_list_cmd, + "show ipv6 mbgp prefix-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_prefix_list); +} +#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_prefix_list, show_bgp_ipv4_prefix_list_cmd, @@ -7869,19 +8436,6 @@ DEFUN (show_bgp_ipv6_safi_prefix_list, bgp_show_type_prefix_list); } -DEFUN (show_bgp_prefix_list, - show_bgp_ipv6_prefix_list_cmd, - "show bgp ipv6 prefix-list WORD", - SHOW_STR - BGP_STR - "Address family\n" - "Display routes conforming to the prefix-list\n" - "IPv6 prefix-list name\n") -{ - return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, - bgp_show_type_prefix_list); -} - #endif /* HAVE_IPV6 */ static int @@ -7900,6 +8454,118 @@ bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi, return bgp_show (vty, NULL, afi, safi, type, as_list); } +DEFUN (show_ip_bgp_filter_list, + show_ip_bgp_filter_list_cmd, + "show ip bgp filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +DEFUN (show_ip_bgp_flap_filter_list, + show_ip_bgp_flap_filter_list_cmd, + "show ip bgp flap-statistics filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_filter_list); +} + +ALIAS (show_ip_bgp_flap_filter_list, + show_ip_bgp_damp_flap_filter_list_cmd, + "show ip bgp dampening flap-statistics filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFUN (show_ip_bgp_ipv4_filter_list, + show_ip_bgp_ipv4_filter_list_cmd, + "show ip bgp ipv4 (unicast|multicast) filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_filter_list); + + return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_filter_list, + show_bgp_filter_list_cmd, + "show bgp filter-list WORD", + SHOW_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +/* old command */ +DEFUN (show_ipv6_bgp_filter_list, + show_ipv6_bgp_filter_list_cmd, + "show ipv6 bgp filter-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_filter_list, + show_ipv6_mbgp_filter_list_cmd, + "show ipv6 mbgp filter-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_filter_list); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_ip_bgp_dampening_info, + show_ip_bgp_dampening_params_cmd, + "show ip bgp dampening parameters", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display detail of configured dampening parameters\n") +{ + return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); +} + DEFUN (show_bgp_ipv4_filter_list, show_bgp_ipv4_filter_list_cmd, "show bgp ipv4 filter-list WORD", @@ -8036,7 +8702,7 @@ DEFUN (show_bgp_ipv6_safi_filter_list, bgp_show_type_filter_list); } -DEFUN (show_bgp_filter_list, +DEFUN (show_bgp_ipv6_filter_list, show_bgp_ipv6_filter_list_cmd, "show bgp ipv6 filter-list WORD", SHOW_STR @@ -8051,18 +8717,6 @@ DEFUN (show_bgp_filter_list, #endif /* HAVE_IPV6 */ -DEFUN (show_ip_bgp_dampening_info, - show_ip_bgp_dampening_params_cmd, - "show ip bgp dampening parameters", - SHOW_STR - IP_STR - BGP_STR - "Display detailed information about dampening\n" - "Display detail of configured dampening parameters\n") -{ - return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); -} - static int bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -8080,6 +8734,208 @@ bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, return bgp_show (vty, NULL, afi, safi, type, rmap); } +DEFUN (show_ip_bgp_route_map, + show_ip_bgp_route_map_cmd, + "show ip bgp route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_ip_bgp_flap_route_map, + show_ip_bgp_flap_route_map_cmd, + "show ip bgp flap-statistics route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_route_map); +} + +ALIAS (show_ip_bgp_flap_route_map, + show_ip_bgp_damp_flap_route_map_cmd, + "show ip bgp dampening flap-statistics route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFUN (show_ip_bgp_ipv4_route_map, + show_ip_bgp_ipv4_route_map_cmd, + "show ip bgp ipv4 (unicast|multicast) route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_route_map); + + return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_bgp_route_map, + show_bgp_route_map_cmd, + "show bgp route-map WORD", + SHOW_STR + BGP_STR + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_ip_bgp_cidr_only, + show_ip_bgp_cidr_only_cmd, + "show ip bgp cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display only routes with non-natural netmasks\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_cidr_only, NULL); +} + +DEFUN (show_ip_bgp_flap_cidr_only, + show_ip_bgp_flap_cidr_only_cmd, + "show ip bgp flap-statistics cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display only routes with non-natural netmasks\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_cidr_only, NULL); +} + +ALIAS (show_ip_bgp_flap_cidr_only, + show_ip_bgp_damp_flap_cidr_only_cmd, + "show ip bgp dampening flap-statistics cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display only routes with non-natural netmasks\n") + +DEFUN (show_ip_bgp_ipv4_cidr_only, + show_ip_bgp_ipv4_cidr_only_cmd, + "show ip bgp ipv4 (unicast|multicast) cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display only routes with non-natural netmasks\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_cidr_only, NULL); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_cidr_only, NULL); +} + +DEFUN (show_ip_bgp_community_all, + show_ip_bgp_community_all_cmd, + "show ip bgp community", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_community_all, NULL); +} + +DEFUN (show_ip_bgp_ipv4_community_all, + show_ip_bgp_ipv4_community_all_cmd, + "show ip bgp ipv4 (unicast|multicast) community", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_community_all, NULL); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_community_all, NULL); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_all, + show_bgp_community_all_cmd, + "show bgp community", + SHOW_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_community_all, NULL); +} + +ALIAS (show_bgp_community_all, + show_bgp_ipv6_community_all_cmd, + "show bgp ipv6 community", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_all, + show_ipv6_bgp_community_all_cmd, + "show ipv6 bgp community", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_community_all, NULL); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_all, + show_ipv6_mbgp_community_all_cmd, + "show ipv6 mbgp community", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_community_all, NULL); +} +#endif /* HAVE_IPV6 */ + DEFUN (show_bgp_ipv4_route_map, show_bgp_ipv4_route_map_cmd, "show bgp ipv4 route-map WORD", @@ -8415,12 +9271,12 @@ bgp_show_community (struct vty *vty, const char *view_name, int argc, bgp_show_type_community), com); } -DEFUN (show_bgp_ipv4_community, - show_bgp_ipv4_community_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export)", +DEFUN (show_ip_bgp_community, + show_ip_bgp_community_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - BGP_STR IP_STR + BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8430,12 +9286,12 @@ DEFUN (show_bgp_ipv4_community, return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } -ALIAS (show_bgp_ipv4_community, - show_bgp_ipv4_community2_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_ip_bgp_community, + show_ip_bgp_community2_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - BGP_STR IP_STR + BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8446,12 +9302,12 @@ ALIAS (show_bgp_ipv4_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_ipv4_community, - show_bgp_ipv4_community3_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_ip_bgp_community, + show_ip_bgp_community3_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - BGP_STR IP_STR + BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8466,12 +9322,12 @@ ALIAS (show_bgp_ipv4_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_ipv4_community, - show_bgp_ipv4_community4_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_ip_bgp_community, + show_ip_bgp_community4_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - BGP_STR IP_STR + BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8490,10 +9346,11 @@ ALIAS (show_bgp_ipv4_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -DEFUN (show_bgp_ipv4_safi_community, - show_bgp_ipv4_safi_community_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +DEFUN (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8510,10 +9367,11 @@ DEFUN (show_bgp_ipv4_safi_community, return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } -ALIAS (show_bgp_ipv4_safi_community, - show_bgp_ipv4_safi_community2_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community2_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8528,10 +9386,11 @@ ALIAS (show_bgp_ipv4_safi_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_ipv4_safi_community, - show_bgp_ipv4_safi_community3_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community3_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8550,10 +9409,11 @@ ALIAS (show_bgp_ipv4_safi_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_ipv4_safi_community, - show_bgp_ipv4_safi_community4_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community4_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IP_STR BGP_STR "Address family\n" "Address Family modifier\n" @@ -8576,101 +9436,28 @@ ALIAS (show_bgp_ipv4_safi_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -DEFUN (show_bgp_view_afi_safi_community_all, - show_bgp_view_afi_safi_community_all_cmd, -#ifdef HAVE_IPV6 - "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", -#else - "show bgp view WORD ipv4 (unicast|multicast) community", -#endif +DEFUN (show_ip_bgp_community_exact, + show_ip_bgp_community_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IP_STR BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" -#ifdef HAVE_IPV6 - "Address family\n" -#endif - "Address Family modifier\n" - "Address Family modifier\n" - "Display routes matching the communities\n") + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") { - int afi; - int safi; - struct bgp *bgp; - - /* BGP structure lookup. */ - bgp = bgp_lookup_by_name (argv[0]); - if (bgp == NULL) - { - vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - -#ifdef HAVE_IPV6 - afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; - safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; -#endif - return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } -DEFUN (show_bgp_view_afi_safi_community, - show_bgp_view_afi_safi_community_cmd, -#ifdef HAVE_IPV6 - "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", -#endif +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community2_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IP_STR BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" -#ifdef HAVE_IPV6 - "Address family\n" -#endif - "Address family modifier\n" - "Address family modifier\n" - "Display routes matching the communities\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") -{ - int afi; - int safi; - -#ifdef HAVE_IPV6 - afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; - safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); -#endif -} - -ALIAS (show_bgp_view_afi_safi_community, - show_bgp_view_afi_safi_community2_cmd, -#ifdef HAVE_IPV6 - "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" -#ifdef HAVE_IPV6 - "Address family\n" -#endif - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8679,25 +9466,15 @@ ALIAS (show_bgp_view_afi_safi_community, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -ALIAS (show_bgp_view_afi_safi_community, - show_bgp_view_afi_safi_community3_cmd, -#ifdef HAVE_IPV6 - "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community3_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IP_STR BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" -#ifdef HAVE_IPV6 - "Address family\n" -#endif - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8710,25 +9487,15 @@ ALIAS (show_bgp_view_afi_safi_community, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -ALIAS (show_bgp_view_afi_safi_community, - show_bgp_view_afi_safi_community4_cmd, -#ifdef HAVE_IPV6 - "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community4_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IP_STR BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" -#ifdef HAVE_IPV6 - "Address family\n" -#endif - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8745,14 +9512,18 @@ ALIAS (show_bgp_view_afi_safi_community, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n") + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_ipv4_community_exact, - show_bgp_ipv4_community_exact_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) exact-match", +DEFUN (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8760,15 +9531,21 @@ DEFUN (show_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") { + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } -ALIAS (show_bgp_ipv4_community_exact, - show_bgp_ipv4_community2_exact_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community2_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8780,12 +9557,15 @@ ALIAS (show_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -ALIAS (show_bgp_ipv4_community_exact, - show_bgp_ipv4_community3_exact_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community3_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8800,13 +9580,16 @@ ALIAS (show_bgp_ipv4_community_exact, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") - -ALIAS (show_bgp_ipv4_community_exact, - show_bgp_ipv4_community4_exact_cmd, - "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community4_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8826,54 +9609,38 @@ ALIAS (show_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -DEFUN (show_bgp_ipv4_safi_community4_exact, - show_bgp_ipv4_safi_community_exact_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community, + show_bgp_community_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") + "Do not export to next AS (well-known community)\n") { - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); - - return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); } -ALIAS (show_bgp_ipv4_safi_community4_exact, - show_bgp_ipv4_safi_community2_exact_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_community, + show_bgp_ipv6_community_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") + "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_ipv4_safi_community4_exact, - show_bgp_ipv4_safi_community3_exact_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +ALIAS (show_bgp_community, + show_bgp_community2_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8882,21 +9649,14 @@ ALIAS (show_bgp_ipv4_safi_community4_exact, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "community number\n" - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -ALIAS (show_bgp_ipv4_safi_community4_exact, - show_bgp_ipv4_safi_community4_exact_cmd, - "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_ipv6_community2_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8905,7 +9665,14 @@ ALIAS (show_bgp_ipv4_safi_community4_exact, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, + show_bgp_community3_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" @@ -8914,45 +9681,17 @@ ALIAS (show_bgp_ipv4_safi_community4_exact, "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - - -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_community, - show_bgp_ipv6_community_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export)", - SHOW_STR - BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -{ - safi_t safi; - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_community (vty, NULL, argc-1, argv+1, 0, AFI_IP6, safi); -} - -ALIAS (show_bgp_ipv6_community, - show_bgp_ipv6_community2_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +ALIAS (show_bgp_community, + show_bgp_ipv6_community3_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8961,18 +9700,17 @@ ALIAS (show_bgp_ipv6_community, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") - -ALIAS (show_bgp_ipv6_community, - show_bgp_ipv6_community3_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + +ALIAS (show_bgp_community, + show_bgp_community4_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -8985,18 +9723,18 @@ ALIAS (show_bgp_ipv6_community, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_ipv6_community, +ALIAS (show_bgp_community, show_bgp_ipv6_community4_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -9015,44 +9753,29 @@ ALIAS (show_bgp_ipv6_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") - -DEFUN (show_bgp_community_exact, - show_bgp_ipv6_community_exact_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) exact-match", +/* old command */ +DEFUN (show_ipv6_bgp_community, + show_ipv6_bgp_community_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") + "Do not export to next AS (well-known community)\n") { - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_community (vty, NULL, argc-1, argv+1, 1, AFI_IP6, safi); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); } - -ALIAS (show_bgp_community_exact, - show_bgp_ipv6_community2_exact_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community2_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -9061,19 +9784,15 @@ ALIAS (show_bgp_community_exact, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") + "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_community_exact, - show_bgp_ipv6_community3_exact_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community3_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -9086,19 +9805,15 @@ ALIAS (show_bgp_community_exact, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") + "Do not export to next AS (well-known community)\n") -ALIAS (show_bgp_community_exact, - show_bgp_ipv6_community4_exact_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community4_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" @@ -9115,674 +9830,2383 @@ ALIAS (show_bgp_community_exact, "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Exact match of the communities") - -#endif /* HAVE_IPV6 */ - -static int -bgp_show_community_list (struct vty *vty, const char *com, int exact, - afi_t afi, safi_t safi) -{ - struct community_list *list; - - list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_MASTER); - if (list == NULL) - { - vty_out (vty, "%% %s is not a valid community-list name%s", com, - VTY_NEWLINE); - return CMD_WARNING; - } - - return bgp_show (vty, NULL, afi, safi, - (exact ? bgp_show_type_community_list_exact : - bgp_show_type_community_list), list); -} + "Do not export to next AS (well-known community)\n") -DEFUN (show_bgp_ipv4_community_list, - show_bgp_ipv4_community_list_cmd, - "show bgp ipv4 community-list (<1-500>|WORD)", +DEFUN (show_bgp_community_exact, + show_bgp_community_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR - IP_STR - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n") + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") { - return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); } -DEFUN (show_bgp_ipv4_safi_community_list, - show_bgp_ipv4_safi_community_list_cmd, - "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n") -{ - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST); - - return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_ipv4_community_list_exact, - show_bgp_ipv4_community_list_exact_cmd, - "show bgp ipv4 community-list (<1-500>|WORD) exact-match", +ALIAS (show_bgp_community_exact, + show_bgp_community2_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR - IP_STR - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n" - "Exact match of the communities\n") -{ - return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_ipv4_safi_community_list_exact, - show_bgp_ipv4_safi_community_list_exact_cmd, - "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community2_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n" - "Exact match of the communities\n") -{ - if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST); - - return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -#ifdef HAVE_IPV6 -DEFUN (show_bgp_community_list, - show_bgp_community_list_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD)", +ALIAS (show_bgp_community_exact, + show_bgp_community3_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR - "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n") -{ - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_community_list (vty, argv[1], 0, AFI_IP6, safi); -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_community_list_exact, - show_bgp_ipv6_community_list_exact_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD) exact-match", +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community3_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Address family modifier\n" - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n" - "Exact match of the communities\n") -{ - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi); -} -#endif /* HAVE_IPV6 */ - -static int -bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, - safi_t safi, enum bgp_show_type type) -{ - int ret; - struct prefix *p; - - p = prefix_new(); - - ret = str2prefix (prefix, p); - if (! ret) - { - vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); - return CMD_WARNING; - } - - ret = bgp_show (vty, NULL, afi, safi, type, p); - prefix_free(p); - return ret; -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_ipv4_prefix_longer, - show_bgp_ipv4_prefix_longer_cmd, - "show bgp ipv4 A.B.C.D/M longer-prefixes", +ALIAS (show_bgp_community_exact, + show_bgp_community4_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR - IP_STR - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") -{ - return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, - bgp_show_type_prefix_longer); -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_ipv4_safi_flap_prefix_longer, - show_bgp_ipv4_safi_flap_prefix_longer_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M longer-prefixes", +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community4_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") -{ - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, - bgp_show_type_flap_prefix_longer); -} + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -ALIAS (show_bgp_ipv4_safi_flap_prefix_longer, - show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M longer-prefixes", +/* old command */ +DEFUN (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_safi_flap_prefix_longer, - show_bgp_ipv6_safi_flap_prefix_longer_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M longer-prefixes", +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community2_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") -{ - safi_t safi; + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, - bgp_show_type_flap_prefix_longer); -} -ALIAS (show_bgp_ipv6_safi_flap_prefix_longer, - show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M longer-prefixes", +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community3_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") -#endif + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") -DEFUN (show_bgp_ipv4_safi_prefix_longer, - show_bgp_ipv4_safi_prefix_longer_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) A.B.C.D/M longer-prefixes", +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community4_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR + IPV6_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +DEFUN (show_ipv6_mbgp_community, + show_ipv6_mbgp_community_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") { - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, - bgp_show_type_prefix_longer); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); } -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_safi_prefix_longer, - show_bgp_ipv6_safi_prefix_longer_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) X:X::X:X/M longer-prefixes", +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community2_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "IP prefix /, e.g., 35.0.0.0/8\n" - "Display route and more specific routes\n") -{ - safi_t safi; + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community3_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") - return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, - bgp_show_type_prefix_longer); -} -#endif +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community4_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") -DEFUN (show_bgp_ipv4_safi_flap_address, - show_bgp_ipv4_safi_flap_address_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", +/* old command */ +DEFUN (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display flap statistics of routes\n" - "Network in the BGP routing table to display\n") + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") { - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, - bgp_show_type_flap_address); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); } -ALIAS (show_bgp_ipv4_safi_flap_address, - show_bgp_ipv4_safi_damp_flap_address_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community2_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "Network in the BGP routing table to display\n") -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_flap_address, - show_bgp_ipv6_flap_address_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community3_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display flap statistics of routes\n" - "Network in the BGP routing table to display\n") -{ - safi_t safi; + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, - bgp_show_type_flap_address); -} -ALIAS (show_bgp_ipv6_flap_address, - show_bgp_ipv6_damp_flap_address_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community4_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "Network in the BGP routing table to display\n") -#endif + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +#endif /* HAVE_IPV6 */ -DEFUN (show_bgp_ipv4_safi_flap_prefix, - show_bgp_ipv4_safi_flap_prefix_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M", +DEFUN (show_bgp_ipv4_community, + show_bgp_ipv4_community_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n") + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") { - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_prefix_longer (vty, argv[0], AFI_IP, safi, - bgp_show_type_flap_prefix); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } -ALIAS (show_bgp_ipv4_safi_flap_prefix, - show_bgp_ipv4_safi_damp_flap_prefix_cmd, - "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M", +ALIAS (show_bgp_ipv4_community, + show_bgp_ipv4_community2_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n") + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_ipv4_community, + show_bgp_ipv4_community3_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_ipv4_community, + show_bgp_ipv4_community4_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_safi_flap_prefix, - show_bgp_ipv6_safi_flap_prefix_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M", +DEFUN (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n") + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") { - safi_t safi; - - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, safi, - bgp_show_type_flap_prefix); + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } -ALIAS (show_bgp_ipv6_safi_flap_prefix, - show_bgp_ipv6_safi_damp_flap_prefix_cmd, - "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M", +ALIAS (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community2_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community3_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "IP prefix /, e.g., 35.0.0.0/8\n") - -DEFUN (show_bgp_ipv6_prefix_longer, - show_bgp_ipv6_prefix_longer_cmd, - "show bgp ipv6 X:X::X:X/M longer-prefixes", + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_ipv4_safi_community, + show_bgp_ipv4_safi_community4_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" - "IPv6 prefix /\n" - "Display route and more specific routes\n") + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFUN (show_bgp_view_afi_safi_community_all, + show_bgp_view_afi_safi_community_all_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", +#else + "show bgp view WORD ipv4 (unicast|multicast) community", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n") +{ + int afi; + int safi; + struct bgp *bgp; + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + +#ifdef HAVE_IPV6 + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; +#endif + return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); +} + +DEFUN (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + int afi; + int safi; + +#ifdef HAVE_IPV6 + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); +#endif +} + +ALIAS (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community2_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community3_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community4_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFUN (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community2_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community3_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_ipv4_community_exact, + show_bgp_ipv4_community4_exact_cmd, + "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFUN (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community2_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community3_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_ipv4_safi_community4_exact, + show_bgp_ipv4_safi_community4_exact_cmd, + "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_community, + show_bgp_ipv6_safi_community_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community (vty, NULL, argc-1, argv+1, 0, AFI_IP6, safi); +} + +ALIAS (show_bgp_ipv6_safi_community, + show_bgp_ipv6_safi_community2_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_ipv6_safi_community, + show_bgp_ipv6_safi_community3_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_ipv6_safi_community, + show_bgp_ipv6_safi_community4_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + + +DEFUN (show_bgp_ipv6_safi_community_exact, + show_bgp_ipv6_safi_community_exact_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community (vty, NULL, argc-1, argv+1, 1, AFI_IP6, safi); +} + + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_safi_community2_exact_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_safi_community3_exact_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_safi_community4_exact_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +#endif /* HAVE_IPV6 */ + +static int +bgp_show_community_list (struct vty *vty, const char *com, int exact, + afi_t afi, safi_t safi) +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_MASTER); + if (list == NULL) + { + vty_out (vty, "%% %s is not a valid community-list name%s", com, + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, NULL, afi, safi, + (exact ? bgp_show_type_community_list_exact : + bgp_show_type_community_list), list); +} + +DEFUN (show_ip_bgp_community_list, + show_ip_bgp_community_list_cmd, + "show ip bgp community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_community_list, + show_ip_bgp_ipv4_community_list_cmd, + "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_community_list_exact, + show_ip_bgp_community_list_exact_cmd, + "show ip bgp community-list (<1-500>|WORD) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_community_list_exact, + show_ip_bgp_ipv4_community_list_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_list, + show_bgp_community_list_cmd, + "show bgp community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_list, + show_bgp_ipv6_community_list_cmd, + "show bgp ipv6 community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_list, + show_ipv6_bgp_community_list_cmd, + "show ipv6 bgp community-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_list, + show_ipv6_mbgp_community_list_cmd, + "show ipv6 mbgp community-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the community-list\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST); +} + +DEFUN (show_bgp_community_list_exact, + show_bgp_community_list_exact_cmd, + "show bgp community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_list_exact, + show_bgp_ipv6_community_list_exact_cmd, + "show bgp ipv6 community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_list_exact, + show_ipv6_bgp_community_list_exact_cmd, + "show ipv6 bgp community-list WORD exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_list_exact, + show_ipv6_mbgp_community_list_exact_cmd, + "show ipv6 mbgp community-list WORD exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the community-list\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_bgp_ipv4_community_list, + show_bgp_ipv4_community_list_cmd, + "show bgp ipv4 community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv4_safi_community_list, + show_bgp_ipv4_safi_community_list_cmd, + "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv4_community_list_exact, + show_bgp_ipv4_community_list_exact_cmd, + "show bgp ipv4 community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv4_safi_community_list_exact, + show_bgp_ipv4_safi_community_list_exact_cmd, + "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_community_list, + show_bgp_ipv6_safi_community_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community_list (vty, argv[1], 0, AFI_IP6, safi); +} + +DEFUN (show_bgp_ipv6_safi_community_list_exact, + show_bgp_ipv6_safi_community_list_exact_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi); +} +#endif /* HAVE_IPV6 */ + +static int +bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + int ret; + struct prefix *p; + + p = prefix_new(); + + ret = str2prefix (prefix, p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = bgp_show (vty, NULL, afi, safi, type, p); + prefix_free(p); + return ret; +} + +DEFUN (show_ip_bgp_prefix_longer, + show_ip_bgp_prefix_longer_cmd, + "show ip bgp A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_prefix_longer, + show_ip_bgp_flap_prefix_longer_cmd, + "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix_longer); +} + +ALIAS (show_ip_bgp_flap_prefix_longer, + show_ip_bgp_damp_flap_prefix_longer_cmd, + "show ip bgp dampening flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +DEFUN (show_ip_bgp_ipv4_prefix_longer, + show_ip_bgp_ipv4_prefix_longer_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_prefix_longer); + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_address, + show_ip_bgp_flap_address_cmd, + "show ip bgp flap-statistics A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_address); +} + +ALIAS (show_ip_bgp_flap_address, + show_ip_bgp_damp_flap_address_cmd, + "show ip bgp dampening flap-statistics A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") + +DEFUN (show_ip_bgp_flap_prefix, + show_ip_bgp_flap_prefix_cmd, + "show ip bgp flap-statistics A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix); +} + +ALIAS (show_ip_bgp_flap_prefix, + show_ip_bgp_damp_flap_prefix_cmd, + "show ip bgp dampening flap-statistics A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_longer, + show_bgp_prefix_longer_cmd, + "show bgp X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "IPv6 prefix /\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_longer, + show_ipv6_bgp_prefix_longer_cmd, + "show ipv6 bgp X:X::X:X/M longer-prefixes", + SHOW_STR + IPV6_STR + BGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_longer, + show_ipv6_mbgp_prefix_longer_cmd, + "show ipv6 mbgp X:X::X:X/M longer-prefixes", + SHOW_STR + IPV6_STR + MBGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_prefix_longer); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_bgp_ipv4_prefix_longer, + show_bgp_ipv4_prefix_longer_cmd, + "show bgp ipv4 A.B.C.D/M longer-prefixes", + SHOW_STR + BGP_STR + IP_STR + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_bgp_ipv4_safi_flap_prefix_longer, + show_bgp_ipv4_safi_flap_prefix_longer_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, + bgp_show_type_flap_prefix_longer); +} + +ALIAS (show_bgp_ipv4_safi_flap_prefix_longer, + show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_prefix_longer, + show_bgp_ipv6_safi_flap_prefix_longer_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, + bgp_show_type_flap_prefix_longer); +} +ALIAS (show_bgp_ipv6_safi_flap_prefix_longer, + show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +#endif + +DEFUN (show_bgp_ipv4_safi_prefix_longer, + show_bgp_ipv4_safi_prefix_longer_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) A.B.C.D/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, + bgp_show_type_prefix_longer); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_prefix_longer, + show_bgp_ipv6_safi_prefix_longer_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, + bgp_show_type_prefix_longer); +} +#endif + +DEFUN (show_bgp_ipv4_safi_flap_address, + show_bgp_ipv4_safi_flap_address_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, + bgp_show_type_flap_address); +} +ALIAS (show_bgp_ipv4_safi_flap_address, + show_bgp_ipv4_safi_damp_flap_address_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_flap_address, + show_bgp_ipv6_flap_address_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, + bgp_show_type_flap_address); +} +ALIAS (show_bgp_ipv6_flap_address, + show_bgp_ipv6_damp_flap_address_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +#endif + +DEFUN (show_bgp_ipv4_safi_flap_prefix, + show_bgp_ipv4_safi_flap_prefix_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, safi, + bgp_show_type_flap_prefix); +} + +ALIAS (show_bgp_ipv4_safi_flap_prefix, + show_bgp_ipv4_safi_damp_flap_prefix_cmd, + "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_flap_prefix, + show_bgp_ipv6_safi_flap_prefix_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, safi, + bgp_show_type_flap_prefix); +} + +ALIAS (show_bgp_ipv6_safi_flap_prefix, + show_bgp_ipv6_safi_damp_flap_prefix_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFUN (show_bgp_ipv6_prefix_longer, + show_bgp_ipv6_prefix_longer_cmd, + "show bgp ipv6 X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "IPv6 prefix /\n" + "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } -#endif /* HAVE_IPV6 */ - -static struct peer * -peer_lookup_in_view (struct vty *vty, const char *view_name, - const char *ip_str) +#endif /* HAVE_IPV6 */ + +static struct peer * +peer_lookup_in_view (struct vty *vty, const char *view_name, + const char *ip_str) +{ + int ret; + struct bgp *bgp; + struct peer *peer; + union sockunion su; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (! bgp) + { + vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return NULL; + } + } + else + { + bgp = bgp_get_default (); + if (! bgp) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return NULL; + } + } + + /* Get peer sockunion. */ + ret = str2sockunion (ip_str, &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); + return NULL; + } + + /* Peer structure lookup. */ + peer = peer_lookup (bgp, &su); + if (! peer) + { + vty_out (vty, "No such neighbor%s", VTY_NEWLINE); + return NULL; + } + + return peer; +} + +enum bgp_stats +{ + BGP_STATS_MAXBITLEN = 0, + BGP_STATS_RIB, + BGP_STATS_PREFIXES, + BGP_STATS_TOTPLEN, + BGP_STATS_UNAGGREGATEABLE, + BGP_STATS_MAX_AGGREGATEABLE, + BGP_STATS_AGGREGATES, + BGP_STATS_SPACE, + BGP_STATS_ASPATH_COUNT, + BGP_STATS_ASPATH_MAXHOPS, + BGP_STATS_ASPATH_TOTHOPS, + BGP_STATS_ASPATH_MAXSIZE, + BGP_STATS_ASPATH_TOTSIZE, + BGP_STATS_ASN_HIGHEST, + BGP_STATS_MAX, +}; + +static const char *table_stats_strs[] = +{ + [BGP_STATS_PREFIXES] = "Total Prefixes", + [BGP_STATS_TOTPLEN] = "Average prefix length", + [BGP_STATS_RIB] = "Total Advertisements", + [BGP_STATS_UNAGGREGATEABLE] = "Unaggregateable prefixes", + [BGP_STATS_MAX_AGGREGATEABLE] = "Maximum aggregateable prefixes", + [BGP_STATS_AGGREGATES] = "BGP Aggregate advertisements", + [BGP_STATS_SPACE] = "Address space advertised", + [BGP_STATS_ASPATH_COUNT] = "Advertisements with paths", + [BGP_STATS_ASPATH_MAXHOPS] = "Longest AS-Path (hops)", + [BGP_STATS_ASPATH_MAXSIZE] = "Largest AS-Path (bytes)", + [BGP_STATS_ASPATH_TOTHOPS] = "Average AS-Path length (hops)", + [BGP_STATS_ASPATH_TOTSIZE] = "Average AS-Path size (bytes)", + [BGP_STATS_ASN_HIGHEST] = "Highest public ASN", + [BGP_STATS_MAX] = NULL, +}; + +struct bgp_table_stats +{ + struct bgp_table *table; + unsigned long long counts[BGP_STATS_MAX]; +}; + +#if 0 +#define TALLY_SIGFIG 100000 +static unsigned long +ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) +{ + unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); + unsigned long res = (newtot * TALLY_SIGFIG) / count; + unsigned long ret = newtot / count; + + if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) + return ret + 1; + else + return ret; +} +#endif + +static int +bgp_table_stats_walker (struct thread *t) { - int ret; - struct bgp *bgp; - struct peer *peer; - union sockunion su; + struct bgp_node *rn; + struct bgp_node *top; + struct bgp_table_stats *ts = THREAD_ARG (t); + unsigned int space = 0; + + if (!(top = bgp_table_top (ts->table))) + return 0; - /* BGP structure lookup. */ - if (view_name) + switch (top->p.family) { - bgp = bgp_lookup_by_name (view_name); - if (! bgp) + case AF_INET: + space = IPV4_MAX_BITLEN; + break; + case AF_INET6: + space = IPV6_MAX_BITLEN; + break; + } + + ts->counts[BGP_STATS_MAXBITLEN] = space; + + for (rn = top; rn; rn = bgp_route_next (rn)) + { + struct bgp_info *ri; + struct bgp_node *prn = bgp_node_parent_nolock (rn); + unsigned int rinum = 0; + + if (rn == top) + continue; + + if (!rn->info) + continue; + + ts->counts[BGP_STATS_PREFIXES]++; + ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen; + +#if 0 + ts->counts[BGP_STATS_AVGPLEN] + = ravg_tally (ts->counts[BGP_STATS_PREFIXES], + ts->counts[BGP_STATS_AVGPLEN], + rn->p.prefixlen); +#endif + + /* check if the prefix is included by any other announcements */ + while (prn && !prn->info) + prn = bgp_node_parent_nolock (prn); + + if (prn == NULL || prn == top) { - vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); - return NULL; - } + ts->counts[BGP_STATS_UNAGGREGATEABLE]++; + /* announced address space */ + if (space) + ts->counts[BGP_STATS_SPACE] += 1 << (space - rn->p.prefixlen); + } + else if (prn->info) + ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; + + for (ri = rn->info; ri; ri = ri->next) + { + rinum++; + ts->counts[BGP_STATS_RIB]++; + + if (ri->attr && + (CHECK_FLAG (ri->attr->flag, + ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)))) + ts->counts[BGP_STATS_AGGREGATES]++; + + /* as-path stats */ + if (ri->attr && ri->attr->aspath) + { + unsigned int hops = aspath_count_hops (ri->attr->aspath); + unsigned int size = aspath_size (ri->attr->aspath); + as_t highest = aspath_highest (ri->attr->aspath); + + ts->counts[BGP_STATS_ASPATH_COUNT]++; + + if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS]) + ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops; + + if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE]) + ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size; + + ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; + ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; +#if 0 + ts->counts[BGP_STATS_ASPATH_AVGHOPS] + = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], + ts->counts[BGP_STATS_ASPATH_AVGHOPS], + hops); + ts->counts[BGP_STATS_ASPATH_AVGSIZE] + = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], + ts->counts[BGP_STATS_ASPATH_AVGSIZE], + size); +#endif + if (highest > ts->counts[BGP_STATS_ASN_HIGHEST]) + ts->counts[BGP_STATS_ASN_HIGHEST] = highest; + } + } } - else + return 0; +} + +static int +bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct bgp_table_stats ts; + unsigned int i; + + if (!bgp->rib[afi][safi]) { - bgp = bgp_get_default (); - if (! bgp) + vty_out (vty, "%% No RIB exists for the AFI/SAFI%s", VTY_NEWLINE); + return CMD_WARNING; + } + + memset (&ts, 0, sizeof (ts)); + ts.table = bgp->rib[afi][safi]; + thread_execute (bm->master, bgp_table_stats_walker, &ts, 0); + + vty_out (vty, "BGP %s RIB statistics%s%s", + afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE); + + for (i = 0; i < BGP_STATS_MAX; i++) + { + if (!table_stats_strs[i]) + continue; + + switch (i) { - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return NULL; +#if 0 + case BGP_STATS_ASPATH_AVGHOPS: + case BGP_STATS_ASPATH_AVGSIZE: + case BGP_STATS_AVGPLEN: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12.2f", + (float)ts.counts[i] / (float)TALLY_SIGFIG); + break; +#endif + case BGP_STATS_ASPATH_TOTHOPS: + case BGP_STATS_ASPATH_TOTSIZE: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12.2f", + ts.counts[i] ? + (float)ts.counts[i] / + (float)ts.counts[BGP_STATS_ASPATH_COUNT] + : 0); + break; + case BGP_STATS_TOTPLEN: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12.2f", + ts.counts[i] ? + (float)ts.counts[i] / + (float)ts.counts[BGP_STATS_PREFIXES] + : 0); + break; + case BGP_STATS_SPACE: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12llu%s", ts.counts[i], VTY_NEWLINE); + if (ts.counts[BGP_STATS_MAXBITLEN] < 9) + break; + vty_out (vty, "%30s: ", "%% announced "); + vty_out (vty, "%12.2f%s", + 100 * (float)ts.counts[BGP_STATS_SPACE] / + (float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]), + VTY_NEWLINE); + vty_out (vty, "%30s: ", "/8 equivalent "); + vty_out (vty, "%12.2f%s", + (float)ts.counts[BGP_STATS_SPACE] / + (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)), + VTY_NEWLINE); + if (ts.counts[BGP_STATS_MAXBITLEN] < 25) + break; + vty_out (vty, "%30s: ", "/24 equivalent "); + vty_out (vty, "%12.2f", + (float)ts.counts[BGP_STATS_SPACE] / + (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24))); + break; + default: + vty_out (vty, "%-30s: ", table_stats_strs[i]); + vty_out (vty, "%12llu", ts.counts[i]); } + + vty_out (vty, "%s", VTY_NEWLINE); } + return CMD_SUCCESS; +} - /* Get peer sockunion. */ - ret = str2sockunion (ip_str, &su); - if (ret < 0) +static int +bgp_table_stats_vty (struct vty *vty, const char *name, + const char *afi_str, const char *safi_str) +{ + struct bgp *bgp; + afi_t afi; + safi_t safi; + + if (name) + bgp = bgp_lookup_by_name (name); + else + bgp = bgp_get_default (); + + if (!bgp) { - vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); - return NULL; + vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (strncmp (afi_str, "ipv", 3) == 0) + { + if (strncmp (afi_str, "ipv4", 4) == 0) + afi = AFI_IP; + else if (strncmp (afi_str, "ipv6", 4) == 0) + afi = AFI_IP6; + else + { + vty_out (vty, "%% Invalid address family %s%s", + afi_str, VTY_NEWLINE); + return CMD_WARNING; + } + switch (safi_str[0]) { + case 'm': + safi = SAFI_MULTICAST; + break; + case 'u': + safi = SAFI_UNICAST; + break; + case 'v': + safi = SAFI_MPLS_LABELED_VPN; + break; + case 'e': + safi = SAFI_ENCAP; + break; + default: + vty_out (vty, "%% Invalid subsequent address family %s%s", + safi_str, VTY_NEWLINE); + return CMD_WARNING; + } } - - /* Peer structure lookup. */ - peer = peer_lookup (bgp, &su); - if (! peer) + else { - vty_out (vty, "No such neighbor%s", VTY_NEWLINE); - return NULL; + vty_out (vty, "%% Invalid address family \"%s\"%s", + afi_str, VTY_NEWLINE); + return CMD_WARNING; } - - return peer; + + return bgp_table_stats (vty, bgp, afi, safi); } -enum bgp_stats +DEFUN (show_bgp_statistics, + show_bgp_statistics_cmd, + "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", + SHOW_STR + BGP_STR + "Address family\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") { - BGP_STATS_MAXBITLEN = 0, - BGP_STATS_RIB, - BGP_STATS_PREFIXES, - BGP_STATS_TOTPLEN, - BGP_STATS_UNAGGREGATEABLE, - BGP_STATS_MAX_AGGREGATEABLE, - BGP_STATS_AGGREGATES, - BGP_STATS_SPACE, - BGP_STATS_ASPATH_COUNT, - BGP_STATS_ASPATH_MAXHOPS, - BGP_STATS_ASPATH_TOTHOPS, - BGP_STATS_ASPATH_MAXSIZE, - BGP_STATS_ASPATH_TOTSIZE, - BGP_STATS_ASN_HIGHEST, - BGP_STATS_MAX, -}; + return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); +} -static const char *table_stats_strs[] = +ALIAS (show_bgp_statistics, + show_bgp_statistics_vpnv4_cmd, + "show bgp (ipv4) (vpnv4) statistics", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") + +DEFUN (show_bgp_statistics_view, + show_bgp_statistics_view_cmd, + "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", + SHOW_STR + BGP_STR + "BGP view\n" + "Address family\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") { - [BGP_STATS_PREFIXES] = "Total Prefixes", - [BGP_STATS_TOTPLEN] = "Average prefix length", - [BGP_STATS_RIB] = "Total Advertisements", - [BGP_STATS_UNAGGREGATEABLE] = "Unaggregateable prefixes", - [BGP_STATS_MAX_AGGREGATEABLE] = "Maximum aggregateable prefixes", - [BGP_STATS_AGGREGATES] = "BGP Aggregate advertisements", - [BGP_STATS_SPACE] = "Address space advertised", - [BGP_STATS_ASPATH_COUNT] = "Advertisements with paths", - [BGP_STATS_ASPATH_MAXHOPS] = "Longest AS-Path (hops)", - [BGP_STATS_ASPATH_MAXSIZE] = "Largest AS-Path (bytes)", - [BGP_STATS_ASPATH_TOTHOPS] = "Average AS-Path length (hops)", - [BGP_STATS_ASPATH_TOTSIZE] = "Average AS-Path size (bytes)", - [BGP_STATS_ASN_HIGHEST] = "Highest public ASN", - [BGP_STATS_MAX] = NULL, + return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); +} + +ALIAS (show_bgp_statistics_view, + show_bgp_statistics_view_vpnv4_cmd, + "show bgp view WORD (ipv4) (vpnv4) statistics", + SHOW_STR + BGP_STR + "BGP view\n" + "Address family\n" + "Address Family modifier\n" + "BGP RIB advertisement statistics\n") + +enum bgp_pcounts +{ + PCOUNT_ADJ_IN = 0, + PCOUNT_DAMPED, + PCOUNT_REMOVED, + PCOUNT_HISTORY, + PCOUNT_STALE, + PCOUNT_VALID, + PCOUNT_ALL, + PCOUNT_COUNTED, + PCOUNT_PFCNT, /* the figure we display to users */ + PCOUNT_MAX, }; -struct bgp_table_stats +static const char *pcount_strs[] = { - struct bgp_table *table; - unsigned long long counts[BGP_STATS_MAX]; + [PCOUNT_ADJ_IN] = "Adj-in", + [PCOUNT_DAMPED] = "Damped", + [PCOUNT_REMOVED] = "Removed", + [PCOUNT_HISTORY] = "History", + [PCOUNT_STALE] = "Stale", + [PCOUNT_VALID] = "Valid", + [PCOUNT_ALL] = "All RIB", + [PCOUNT_COUNTED] = "PfxCt counted", + [PCOUNT_PFCNT] = "Useable", + [PCOUNT_MAX] = NULL, }; -#if 0 -#define TALLY_SIGFIG 100000 -static unsigned long -ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) +struct peer_pcounts { - unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); - unsigned long res = (newtot * TALLY_SIGFIG) / count; - unsigned long ret = newtot / count; - - if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) - return ret + 1; - else - return ret; -} -#endif + unsigned int count[PCOUNT_MAX]; + const struct peer *peer; + const struct bgp_table *table; +}; static int -bgp_table_stats_walker (struct thread *t) +bgp_peer_count_walker (struct thread *t) { struct bgp_node *rn; - struct bgp_node *top; - struct bgp_table_stats *ts = THREAD_ARG (t); - unsigned int space = 0; + struct peer_pcounts *pc = THREAD_ARG (t); + const struct peer *peer = pc->peer; - if (!(top = bgp_table_top (ts->table))) - return 0; - - switch (top->p.family) - { - case AF_INET: - space = IPV4_MAX_BITLEN; - break; - case AF_INET6: - space = IPV6_MAX_BITLEN; - break; - } - - ts->counts[BGP_STATS_MAXBITLEN] = space; - - for (rn = top; rn; rn = bgp_route_next (rn)) + for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn)) { + struct bgp_adj_in *ain; struct bgp_info *ri; - struct bgp_node *prn = bgp_node_parent_nolock (rn); - unsigned int rinum = 0; - - if (rn == top) - continue; - - if (!rn->info) - continue; - ts->counts[BGP_STATS_PREFIXES]++; - ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen; + for (ain = rn->adj_in; ain; ain = ain->next) + if (ain->peer == peer) + pc->count[PCOUNT_ADJ_IN]++; -#if 0 - ts->counts[BGP_STATS_AVGPLEN] - = ravg_tally (ts->counts[BGP_STATS_PREFIXES], - ts->counts[BGP_STATS_AVGPLEN], - rn->p.prefixlen); -#endif - - /* check if the prefix is included by any other announcements */ - while (prn && !prn->info) - prn = bgp_node_parent_nolock (prn); - - if (prn == NULL || prn == top) - { - ts->counts[BGP_STATS_UNAGGREGATEABLE]++; - /* announced address space */ - if (space) - ts->counts[BGP_STATS_SPACE] += 1 << (space - rn->p.prefixlen); - } - else if (prn->info) - ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; - for (ri = rn->info; ri; ri = ri->next) { - rinum++; - ts->counts[BGP_STATS_RIB]++; + char buf[SU_ADDRSTRLEN]; - if (ri->attr && - (CHECK_FLAG (ri->attr->flag, - ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)))) - ts->counts[BGP_STATS_AGGREGATES]++; + if (ri->peer != peer) + continue; - /* as-path stats */ - if (ri->attr && ri->attr->aspath) + pc->count[PCOUNT_ALL]++; + + if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)) + pc->count[PCOUNT_DAMPED]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + pc->count[PCOUNT_HISTORY]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)) + pc->count[PCOUNT_REMOVED]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) + pc->count[PCOUNT_STALE]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_VALID)) + pc->count[PCOUNT_VALID]++; + if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + pc->count[PCOUNT_PFCNT]++; + + if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { - unsigned int hops = aspath_count_hops (ri->attr->aspath); - unsigned int size = aspath_size (ri->attr->aspath); - as_t highest = aspath_highest (ri->attr->aspath); - - ts->counts[BGP_STATS_ASPATH_COUNT]++; - - if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS]) - ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops; - - if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE]) - ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size; - - ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; - ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; -#if 0 - ts->counts[BGP_STATS_ASPATH_AVGHOPS] - = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], - ts->counts[BGP_STATS_ASPATH_AVGHOPS], - hops); - ts->counts[BGP_STATS_ASPATH_AVGSIZE] - = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], - ts->counts[BGP_STATS_ASPATH_AVGSIZE], - size); -#endif - if (highest > ts->counts[BGP_STATS_ASN_HIGHEST]) - ts->counts[BGP_STATS_ASN_HIGHEST] = highest; + pc->count[PCOUNT_COUNTED]++; + if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + plog_warn (peer->log, + "%s [pcount] %s/%d is counted but flags 0x%x", + peer->host, + inet_ntop(rn->p.family, &rn->p.u.prefix, + buf, SU_ADDRSTRLEN), + rn->p.prefixlen, + ri->flags); + } + else + { + if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) + plog_warn (peer->log, + "%s [pcount] %s/%d not counted but flags 0x%x", + peer->host, + inet_ntop(rn->p.family, &rn->p.u.prefix, + buf, SU_ADDRSTRLEN), + rn->p.prefixlen, + ri->flags); } } } @@ -9790,424 +12214,674 @@ bgp_table_stats_walker (struct thread *t) } static int -bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) +bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) { - struct bgp_table_stats ts; + struct peer_pcounts pcounts = { .peer = peer }; unsigned int i; - if (!bgp->rib[afi][safi]) + if (!peer || !peer->bgp || !peer->afc[afi][safi] + || !peer->bgp->rib[afi][safi]) { - vty_out (vty, "%% No RIB exists for the AFI/SAFI%s", VTY_NEWLINE); + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - memset (&ts, 0, sizeof (ts)); - ts.table = bgp->rib[afi][safi]; - thread_execute (bm->master, bgp_table_stats_walker, &ts, 0); - - vty_out (vty, "BGP %s RIB statistics%s%s", - afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE); + memset (&pcounts, 0, sizeof(pcounts)); + pcounts.peer = peer; + pcounts.table = peer->bgp->rib[afi][safi]; - for (i = 0; i < BGP_STATS_MAX; i++) + /* in-place call via thread subsystem so as to record execution time + * stats for the thread-walk (i.e. ensure this can't be blamed on + * on just vty_read()). + */ + thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0); + + vty_out (vty, "Prefix counts for %s, %s%s", + peer->host, afi_safi_print (afi, safi), VTY_NEWLINE); + vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE); + vty_out (vty, "%sCounts from RIB table walk:%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (i = 0; i < PCOUNT_MAX; i++) + vty_out (vty, "%20s: %-10d%s", + pcount_strs[i], pcounts.count[i], VTY_NEWLINE); + + if (pcounts.count[PCOUNT_PFCNT] != peer->pcount[afi][safi]) { - if (!table_stats_strs[i]) - continue; - - switch (i) - { -#if 0 - case BGP_STATS_ASPATH_AVGHOPS: - case BGP_STATS_ASPATH_AVGSIZE: - case BGP_STATS_AVGPLEN: - vty_out (vty, "%-30s: ", table_stats_strs[i]); - vty_out (vty, "%12.2f", - (float)ts.counts[i] / (float)TALLY_SIGFIG); - break; -#endif - case BGP_STATS_ASPATH_TOTHOPS: - case BGP_STATS_ASPATH_TOTSIZE: - vty_out (vty, "%-30s: ", table_stats_strs[i]); - vty_out (vty, "%12.2f", - ts.counts[i] ? - (float)ts.counts[i] / - (float)ts.counts[BGP_STATS_ASPATH_COUNT] - : 0); - break; - case BGP_STATS_TOTPLEN: - vty_out (vty, "%-30s: ", table_stats_strs[i]); - vty_out (vty, "%12.2f", - ts.counts[i] ? - (float)ts.counts[i] / - (float)ts.counts[BGP_STATS_PREFIXES] - : 0); - break; - case BGP_STATS_SPACE: - vty_out (vty, "%-30s: ", table_stats_strs[i]); - vty_out (vty, "%12llu%s", ts.counts[i], VTY_NEWLINE); - if (ts.counts[BGP_STATS_MAXBITLEN] < 9) - break; - vty_out (vty, "%30s: ", "%% announced "); - vty_out (vty, "%12.2f%s", - 100 * (float)ts.counts[BGP_STATS_SPACE] / - (float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]), - VTY_NEWLINE); - vty_out (vty, "%30s: ", "/8 equivalent "); - vty_out (vty, "%12.2f%s", - (float)ts.counts[BGP_STATS_SPACE] / - (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)), - VTY_NEWLINE); - if (ts.counts[BGP_STATS_MAXBITLEN] < 25) - break; - vty_out (vty, "%30s: ", "/24 equivalent "); - vty_out (vty, "%12.2f", - (float)ts.counts[BGP_STATS_SPACE] / - (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24))); - break; - default: - vty_out (vty, "%-30s: ", table_stats_strs[i]); - vty_out (vty, "%12llu", ts.counts[i]); - } - - vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s [pcount] PfxCt drift!%s", + peer->host, VTY_NEWLINE); + vty_out (vty, "Please report this bug, with the above command output%s", + VTY_NEWLINE); } + return CMD_SUCCESS; } -static int -bgp_table_stats_vty (struct vty *vty, const char *name, - const char *afi_str, const char *safi_str) +DEFUN (show_ip_bgp_neighbor_prefix_counts, + show_ip_bgp_neighbor_prefix_counts_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") { - struct bgp *bgp; - afi_t afi; - safi_t safi; + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv6_neighbor_prefix_counts, + show_bgp_ipv6_neighbor_prefix_counts_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts, + show_ip_bgp_ipv4_neighbor_prefix_counts_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; + + if (strncmp (argv[0], "m", 1) == 0) + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST); + + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts, + show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd, + "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; - if (name) - bgp = bgp_lookup_by_name (name); - else - bgp = bgp_get_default (); + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN); +} - if (!bgp) - { - vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); - return CMD_WARNING; - } - if (strncmp (afi_str, "ipv", 3) == 0) - { - if (strncmp (afi_str, "ipv4", 4) == 0) - afi = AFI_IP; - else if (strncmp (afi_str, "ipv6", 4) == 0) - afi = AFI_IP6; - else - { - vty_out (vty, "%% Invalid address family %s%s", - afi_str, VTY_NEWLINE); - return CMD_WARNING; - } - switch (safi_str[0]) { - case 'm': - safi = SAFI_MULTICAST; - break; - case 'u': - safi = SAFI_UNICAST; - break; - case 'v': - safi = SAFI_MPLS_LABELED_VPN; - break; - case 'e': - safi = SAFI_ENCAP; - break; - default: - vty_out (vty, "%% Invalid subsequent address family %s%s", - safi_str, VTY_NEWLINE); - return CMD_WARNING; - } - } - else - { - vty_out (vty, "%% Invalid address family \"%s\"%s", - afi_str, VTY_NEWLINE); - return CMD_WARNING; - } +DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts, + show_bgp_ipv4_safi_neighbor_prefix_counts_cmd, + "show bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") +{ + struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } - return bgp_table_stats (vty, bgp, afi, safi); -} + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; -DEFUN (show_bgp_statistics, - show_bgp_statistics_cmd, - "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", + return bgp_peer_counts (vty, peer, AFI_IP, safi); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts, + show_bgp_ipv6_safi_neighbor_prefix_counts_cmd, + "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR BGP_STR "Address family\n" - "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" - "BGP RIB advertisement statistics\n") + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") { - return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); + struct peer *peer; + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP6, safi); } +#endif -DEFUN (show_bgp_statistics_view, - show_bgp_statistics_view_cmd, - "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", +DEFUN (show_ip_bgp_encap_neighbor_prefix_counts, + show_ip_bgp_encap_neighbor_prefix_counts_cmd, + "show ip bgp encap all neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR + IP_STR BGP_STR - "BGP view\n" - "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "BGP RIB advertisement statistics\n") + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display detailed prefix count information\n") { - return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_peer_counts (vty, peer, AFI_IP, SAFI_ENCAP); } -#if 0 /* added as options to above command */ -ALIAS (show_bgp_statistics_view, - show_bgp_statistics_view_encap_cmd, - "show bgp view WORD (ipv4) (encap) statistics", - SHOW_STR - BGP_STR - "BGP view\n" - "Address family\n" - "Address Family modifier\n" - "BGP RIB advertisement statistics\n") -#endif -enum bgp_pcounts +static void +show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, + int in) { - PCOUNT_ADJ_IN = 0, - PCOUNT_DAMPED, - PCOUNT_REMOVED, - PCOUNT_HISTORY, - PCOUNT_STALE, - PCOUNT_VALID, - PCOUNT_ALL, - PCOUNT_COUNTED, - PCOUNT_PFCNT, /* the figure we display to users */ - PCOUNT_MAX, -}; + struct bgp_table *table; + struct bgp_adj_in *ain; + struct bgp_adj_out *adj; + unsigned long output_count; + struct bgp_node *rn; + int header1 = 1; + struct bgp *bgp; + int header2 = 1; -static const char *pcount_strs[] = -{ - [PCOUNT_ADJ_IN] = "Adj-in", - [PCOUNT_DAMPED] = "Damped", - [PCOUNT_REMOVED] = "Removed", - [PCOUNT_HISTORY] = "History", - [PCOUNT_STALE] = "Stale", - [PCOUNT_VALID] = "Valid", - [PCOUNT_ALL] = "All RIB", - [PCOUNT_COUNTED] = "PfxCt counted", - [PCOUNT_PFCNT] = "Useable", - [PCOUNT_MAX] = NULL, -}; + bgp = peer->bgp; -struct peer_pcounts -{ - unsigned int count[PCOUNT_MAX]; - const struct peer *peer; - const struct bgp_table *table; -}; + if (! bgp) + return; -static int -bgp_peer_count_walker (struct thread *t) -{ - struct bgp_node *rn; - struct peer_pcounts *pc = THREAD_ARG (t); - const struct peer *peer = pc->peer; - - for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn)) + table = bgp->rib[afi][safi]; + + output_count = 0; + + if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], + PEER_STATUS_DEFAULT_ORIGINATE)) { - struct bgp_adj_in *ain; - struct bgp_info *ri; - - for (ain = rn->adj_in; ain; ain = ain->next) - if (ain->peer == peer) - pc->count[PCOUNT_ADJ_IN]++; + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - for (ri = rn->info; ri; ri = ri->next) - { - char buf[SU_ADDRSTRLEN]; - - if (ri->peer != peer) - continue; - - pc->count[PCOUNT_ALL]++; - - if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)) - pc->count[PCOUNT_DAMPED]++; - if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) - pc->count[PCOUNT_HISTORY]++; - if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)) - pc->count[PCOUNT_REMOVED]++; - if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) - pc->count[PCOUNT_STALE]++; - if (CHECK_FLAG (ri->flags, BGP_INFO_VALID)) - pc->count[PCOUNT_VALID]++; - if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) - pc->count[PCOUNT_PFCNT]++; - - if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) - { - pc->count[PCOUNT_COUNTED]++; - if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) - plog_warn (peer->log, - "%s [pcount] %s/%d is counted but flags 0x%x", - peer->host, - inet_ntop(rn->p.family, &rn->p.u.prefix, - buf, SU_ADDRSTRLEN), - rn->p.prefixlen, - ri->flags); - } - else - { - if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) - plog_warn (peer->log, - "%s [pcount] %s/%d not counted but flags 0x%x", - peer->host, - inet_ntop(rn->p.family, &rn->p.u.prefix, - buf, SU_ADDRSTRLEN), - rn->p.prefixlen, - ri->flags); - } - } + vty_out (vty, "Originating default network 0.0.0.0%s%s", + VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; } - return 0; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if (in) + { + for (ain = rn->adj_in; ain; ain = ain->next) + if (ain->peer == peer) + { + if (header1) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; + } + if (header2) + { + vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); + header2 = 0; + } + if (ain->attr) + { + route_vty_out_tmp (vty, &rn->p, ain->attr, safi); + output_count++; + } + } + } + else + { + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + { + if (header1) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; + } + if (header2) + { + vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); + header2 = 0; + } + if (adj->attr) + { + route_vty_out_tmp (vty, &rn->p, adj->attr, safi); + output_count++; + } + } + } + + if (output_count != 0) + vty_out (vty, "%sTotal number of prefixes %ld%s", + VTY_NEWLINE, output_count, VTY_NEWLINE); } static int -bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) -{ - struct peer_pcounts pcounts = { .peer = peer }; - unsigned int i; - - if (!peer || !peer->bgp || !peer->afc[afi][safi] - || !peer->bgp->rib[afi][safi]) +peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in) +{ + if (! peer || ! peer->afc[afi][safi]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (in && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) { - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + vty_out (vty, "%% Inbound soft reconfiguration not enabled%s", + VTY_NEWLINE); return CMD_WARNING; } - - memset (&pcounts, 0, sizeof(pcounts)); - pcounts.peer = peer; - pcounts.table = peer->bgp->rib[afi][safi]; - - /* in-place call via thread subsystem so as to record execution time - * stats for the thread-walk (i.e. ensure this can't be blamed on - * on just vty_read()). - */ - thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0); - - vty_out (vty, "Prefix counts for %s, %s%s", - peer->host, afi_safi_print (afi, safi), VTY_NEWLINE); - vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE); - vty_out (vty, "%sCounts from RIB table walk:%s%s", - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - for (i = 0; i < PCOUNT_MAX; i++) - vty_out (vty, "%20s: %-10d%s", - pcount_strs[i], pcounts.count[i], VTY_NEWLINE); + show_adj_route (vty, peer, afi, safi, in); - if (pcounts.count[PCOUNT_PFCNT] != peer->pcount[afi][safi]) - { - vty_out (vty, "%s [pcount] PfxCt drift!%s", - peer->host, VTY_NEWLINE); - vty_out (vty, "Please report this bug, with the above command output%s", - VTY_NEWLINE); - } - return CMD_SUCCESS; } -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_neighbor_prefix_counts, - show_bgp_ipv6_neighbor_prefix_counts_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", +DEFUN (show_ip_bgp_view_neighbor_advertised_route, + show_ip_bgp_view_neighbor_advertised_route_cmd, + "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR + IP_STR BGP_STR - "Address family\n" + "BGP view\n" + "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" - "Display detailed prefix count information\n") + "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; - peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) return CMD_WARNING; - return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); + return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); } -#endif -DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts, - show_bgp_ipv4_safi_neighbor_prefix_counts_cmd, - "show bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", +ALIAS (show_ip_bgp_view_neighbor_advertised_route, + show_ip_bgp_neighbor_advertised_route_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, + show_ip_bgp_ipv4_neighbor_advertised_route_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR + IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" - "Display detailed prefix count information\n") + "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; - safi_t safi; - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) return CMD_WARNING; - } - peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (strncmp (argv[0], "m", 1) == 0) + return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 0); + + return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_view_neighbor_advertised_route, + show_bgp_view_neighbor_advertised_route_cmd, + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0); +} + +DEFUN (show_bgp_view_neighbor_received_routes, + show_bgp_view_neighbor_received_routes_cmd, + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); +} + +ALIAS (show_bgp_view_neighbor_advertised_route, + show_bgp_neighbor_advertised_route_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +ALIAS (show_bgp_view_neighbor_advertised_route, + show_bgp_ipv6_neighbor_advertised_route_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +/* old command */ +ALIAS (show_bgp_view_neighbor_advertised_route, + ipv6_bgp_neighbor_advertised_route_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_advertised_route, + ipv6_mbgp_neighbor_advertised_route_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_ip_bgp_view_neighbor_received_routes, + show_ip_bgp_view_neighbor_received_routes_cmd, + "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); +} + +ALIAS (show_ip_bgp_view_neighbor_received_routes, + show_ip_bgp_neighbor_received_routes_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +ALIAS (show_bgp_view_neighbor_received_routes, + show_bgp_ipv6_neighbor_received_routes_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFUN (show_bgp_neighbor_received_prefix_filter, + show_bgp_neighbor_received_prefix_filter_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion su; + struct peer *peer; + int count, ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; +} + +/* old command */ +ALIAS (show_bgp_view_neighbor_received_routes, + ipv6_bgp_neighbor_received_routes_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_received_routes, + ipv6_mbgp_neighbor_received_routes_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; - return bgp_peer_counts (vty, peer, AFI_IP, safi); + return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 1); } -#ifdef HAVE_IPV6 -DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts, - show_bgp_ipv6_safi_neighbor_prefix_counts_cmd, - "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", + +DEFUN (show_bgp_view_neighbor_received_prefix_filter, + show_bgp_view_neighbor_received_prefix_filter_cmd, + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Address Family modifier\n" + "BGP view\n" + "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" - "Display detailed prefix count information\n") + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") { + char name[BUFSIZ]; + union sockunion su; struct peer *peer; - safi_t safi; + struct bgp *bgp; + int count, ret; - if (bgp_parse_safi(argv[0], &safi)) { - vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup_in_view (vty, NULL, argv[1]); + peer = peer_lookup (bgp, &su); if (! peer) return CMD_WARNING; - return bgp_peer_counts (vty, peer, AFI_IP6, safi); + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; } -#endif -DEFUN (show_ip_bgp_encap_neighbor_prefix_counts, - show_ip_bgp_encap_neighbor_prefix_counts_cmd, - "show ip bgp encap all neighbors (A.B.C.D|X:X::X:X) prefix-counts", + +DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, + show_ip_bgp_ipv4_neighbor_received_routes_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR IP_STR BGP_STR @@ -10217,126 +12891,18 @@ DEFUN (show_ip_bgp_encap_neighbor_prefix_counts, "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" - "Display detailed prefix count information\n") + "Display the received routes from neighbor\n") { struct peer *peer; - peer = peer_lookup_in_view (vty, NULL, argv[0]); + peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; - return bgp_peer_counts (vty, peer, AFI_IP, SAFI_ENCAP); -} - - -static void -show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, - int in) -{ - struct bgp_table *table; - struct bgp_adj_in *ain; - struct bgp_adj_out *adj; - unsigned long output_count; - struct bgp_node *rn; - int header1 = 1; - struct bgp *bgp; - int header2 = 1; - - bgp = peer->bgp; - - if (! bgp) - return; - - table = bgp->rib[afi][safi]; - - output_count = 0; - - if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], - PEER_STATUS_DEFAULT_ORIGINATE)) - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - - vty_out (vty, "Originating default network 0.0.0.0%s%s", - VTY_NEWLINE, VTY_NEWLINE); - header1 = 0; - } - - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - if (in) - { - for (ain = rn->adj_in; ain; ain = ain->next) - if (ain->peer == peer) - { - if (header1) - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - header1 = 0; - } - if (header2) - { - vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); - header2 = 0; - } - if (ain->attr) - { - route_vty_out_tmp (vty, &rn->p, ain->attr, safi); - output_count++; - } - } - } - else - { - for (adj = rn->adj_out; adj; adj = adj->next) - if (adj->peer == peer) - { - if (header1) - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - header1 = 0; - } - if (header2) - { - vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); - header2 = 0; - } - if (adj->attr) - { - route_vty_out_tmp (vty, &rn->p, adj->attr, safi); - output_count++; - } - } - } - - if (output_count != 0) - vty_out (vty, "%sTotal number of prefixes %ld%s", - VTY_NEWLINE, output_count, VTY_NEWLINE); -} - -static int -peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in) -{ - if (! peer || ! peer->afc[afi][safi]) - { - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (in && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) - { - vty_out (vty, "%% Inbound soft reconfiguration not enabled%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - show_adj_route (vty, peer, afi, safi, in); + if (strncmp (argv[0], "m", 1) == 0) + return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 1); - return CMD_SUCCESS; + return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); } DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route, @@ -10394,7 +12960,7 @@ DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP6, safi, 0); } -DEFUN (show_bgp_view_neighbor_advertised_route, +DEFUN (show_bgp_view_ipv6_neighbor_advertised_route, show_bgp_view_ipv6_neighbor_advertised_route_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR @@ -10420,7 +12986,7 @@ DEFUN (show_bgp_view_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0); } -DEFUN (show_bgp_view_neighbor_received_routes, +DEFUN (show_bgp_view_ipv6_neighbor_received_routes, show_bgp_view_ipv6_neighbor_received_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR @@ -10445,18 +13011,6 @@ DEFUN (show_bgp_view_neighbor_received_routes, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); } - -ALIAS (show_bgp_view_neighbor_advertised_route, - show_bgp_ipv6_neighbor_advertised_route_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", - SHOW_STR - BGP_STR - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n") - #endif /* HAVE_IPV6 */ @@ -10538,23 +13092,127 @@ DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, "Display the advertised routes to neighbor\n" "Display the received routes from neighbor\n") { - int afi; - int safi; - int in; + int afi; + int safi; + int in; + struct peer *peer; + + peer = peer_lookup_in_view (vty, argv[0], argv[3]); + + if (! peer) + return CMD_WARNING; + + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0; + + return peer_adj_routes (vty, peer, afi, safi, in); +} + +DEFUN (show_ip_bgp_neighbor_received_prefix_filter, + show_ip_bgp_neighbor_received_prefix_filter_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion su; + struct peer *peer; + int count, ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, + show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion su; struct peer *peer; + int count, ret; - peer = peer_lookup_in_view (vty, argv[0], argv[3]); + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; - afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; - safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0; + if (strncmp (argv[0], "m", 1) == 0) + { + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + } + else + { + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + } - return peer_adj_routes (vty, peer, afi, safi, in); + return CMD_SUCCESS; } +ALIAS (show_bgp_view_neighbor_received_routes, + show_bgp_neighbor_received_routes_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + DEFUN (show_bgp_ipv4_safi_neighbor_received_prefix_filter, show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", @@ -10637,134 +13295,396 @@ DEFUN (show_bgp_ipv6_safi_neighbor_received_prefix_filter, return CMD_WARNING; } - peer = peer_lookup (NULL, &su); - if (! peer) - return CMD_WARNING; - - sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, safi); - count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); - if (count) { - vty_out (vty, "Address family: IPv6 %s%s", safi2str(safi), VTY_NEWLINE); - prefix_bgp_show_prefix_list (vty, AFI_IP6, name); - } + peer = peer_lookup (NULL, &su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, safi); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) { + vty_out (vty, "Address family: IPv6 %s%s", safi2str(safi), VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; +} + +DEFUN (show_bgp_ipv6_neighbor_received_prefix_filter, + show_bgp_ipv6_neighbor_received_prefix_filter_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion su; + struct peer *peer; + int count, ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; +} + +DEFUN (show_bgp_view_ipv6_neighbor_received_prefix_filter, + show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd, + "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion su; + struct peer *peer; + struct bgp *bgp; + int count, ret; + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (bgp, &su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; +} +#endif /* HAVE_IPV6 */ + +static int +bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + if (! peer || ! peer->afc[afi][safi]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, peer->bgp, afi, safi, type, &peer->su); +} +DEFUN (show_ip_bgp_neighbor_routes, + show_ip_bgp_neighbor_routes_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_flap, + show_ip_bgp_neighbor_flap_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display flap statistics of the routes learned from neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_damp, + show_ip_bgp_neighbor_damp_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + bgp_show_type_damp_neighbor); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_routes, + show_ip_bgp_ipv4_neighbor_routes_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; + + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_MULTICAST, + bgp_show_type_neighbor); + + return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +DEFUN (show_ip_bgp_view_rsclient, + show_ip_bgp_view_rsclient_cmd, + "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) +{ + struct bgp_table *table; + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP][SAFI_UNICAST]; - return CMD_SUCCESS; + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } -ALIAS (show_bgp_view_neighbor_received_routes, - show_bgp_ipv6_neighbor_received_routes_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", +ALIAS (show_ip_bgp_view_rsclient, + show_ip_bgp_rsclient_cmd, + "show ip bgp rsclient (A.B.C.D|X:X::X:X)", SHOW_STR + IP_STR BGP_STR - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the received routes from neighbor\n") + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) -DEFUN (show_bgp_neighbor_received_prefix_filter, - show_bgp_ipv6_neighbor_received_prefix_filter_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +DEFUN (show_bgp_view_ipv4_safi_rsclient, + show_bgp_view_ipv4_safi_rsclient_cmd, + "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR + "BGP view\n" + "View name\n" "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display information received from a BGP neighbor\n" - "Display the prefixlist filter\n") + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) { - char name[BUFSIZ]; - union sockunion su; + struct bgp_table *table; struct peer *peer; - int count, ret; + safi_t safi; - ret = str2sockunion (argv[0], &su); - if (ret < 0) - { - vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } + if (argc == 3) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } - peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; - sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); - count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); - if (count) + if (! peer->afc[AFI_IP][safi]) { - vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); - prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; } - return CMD_SUCCESS; + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP][safi]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } -DEFUN (show_bgp_view_neighbor_received_prefix_filter, - show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd, - "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +ALIAS (show_bgp_view_ipv4_safi_rsclient, + show_bgp_ipv4_safi_rsclient_cmd, + "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) + +DEFUN (show_ip_bgp_view_rsclient_route, + show_ip_bgp_view_rsclient_route_cmd, + "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR + IP_STR BGP_STR "BGP view\n" "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display information received from a BGP neighbor\n" - "Display the prefixlist filter\n") + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") { - char name[BUFSIZ]; - union sockunion su; - struct peer *peer; struct bgp *bgp; - int count, ret; + struct peer *peer; /* BGP structure lookup. */ - bgp = bgp_lookup_by_name (argv[0]); - if (bgp == NULL) - { + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } - - ret = str2sockunion (argv[1], &su); - if (ret < 0) + } + else { - vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); - return CMD_WARNING; + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } } - peer = peer_lookup (bgp, &su); + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) return CMD_WARNING; - sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); - count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); - if (count) + if (! peer->afc[AFI_IP][SAFI_UNICAST]) { - vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); - prefix_bgp_show_prefix_list (vty, AFI_IP6, name); - } - - return CMD_SUCCESS; + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; } -#endif /* HAVE_IPV6 */ -static int -bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, - safi_t safi, enum bgp_show_type type) -{ - if (! peer || ! peer->afc[afi][safi]) + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) { - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); return CMD_WARNING; } - return bgp_show (vty, peer->bgp, afi, safi, type, &peer->su); + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP, SAFI_UNICAST, NULL, 0); } +ALIAS (show_ip_bgp_view_rsclient_route, + show_ip_bgp_rsclient_route_cmd, + "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + DEFUN (show_bgp_ipv4_safi_neighbor_flap, show_bgp_ipv4_safi_neighbor_flap_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", @@ -10937,90 +13857,14 @@ DEFUN (show_bgp_ipv6_safi_neighbor_routes, return CMD_WARNING; } - peer = peer_lookup_in_view (vty, NULL, argv[1]); - if (! peer) - return CMD_WARNING; - - return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, - bgp_show_type_neighbor); -} -#endif - -DEFUN (show_bgp_view_ipv4_safi_rsclient, - show_bgp_view_ipv4_safi_rsclient_cmd, - "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR) -{ - struct bgp_table *table; - struct peer *peer; - safi_t safi; - - if (argc == 3) { - peer = peer_lookup_in_view (vty, argv[0], argv[2]); - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - } else { - peer = peer_lookup_in_view (vty, NULL, argv[1]); - safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - } - - if (! peer) - return CMD_WARNING; - - if (! peer->afc[AFI_IP][safi]) - { - vty_out (vty, "%% Activate the neighbor for the address family first%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], - PEER_FLAG_RSERVER_CLIENT)) - { - vty_out (vty, "%% Neighbor is not a Route-Server client%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - table = peer->rib[AFI_IP][safi]; - - return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); -} - -ALIAS (show_bgp_view_ipv4_safi_rsclient, - show_bgp_ipv4_safi_rsclient_cmd, - "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", - SHOW_STR - BGP_STR - "Address family\n" - "Address Family modifier\n" - "Address Family modifier\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR) - -#if 0 /* from 0.99.24.1 merge */ -DEFUN (show_ip_bgp_view_rsclient_route, - show_ip_bgp_view_rsclient_route_cmd, - "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR - "Network in the BGP routing table to display\n") -{ - struct bgp *bgp; - struct peer *peer; -#endif + peer = peer_lookup_in_view (vty, NULL, argv[1]); + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, + bgp_show_type_neighbor); +} +#endif DEFUN (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_view_ipv4_safi_rsclient_route_cmd, @@ -11103,22 +13947,6 @@ ALIAS (show_bgp_view_ipv4_safi_rsclient_route, NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") -#if 0 /* from 0.99.24.1 merge */ -DEFUN (show_ip_bgp_view_rsclient_prefix, - show_ip_bgp_view_rsclient_prefix_cmd, - "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", - SHOW_STR - IP_STR - BGP_STR - "BGP view\n" - "View name\n" - "Information about Route Server Client\n" - NEIGHBOR_ADDR_STR - "IP prefix /, e.g., 35.0.0.0/8\n") -{ - struct bgp *bgp; - struct peer *peer; -#endif DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_view_ipv4_safi_rsclient_prefix_cmd, @@ -11189,6 +14017,79 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, AFI_IP, safi, NULL, 1); } +DEFUN (show_ip_bgp_view_rsclient_prefix, + show_ip_bgp_view_rsclient_prefix_cmd, + "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) +{ + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_ip_bgp_view_rsclient_prefix, + show_ip_bgp_rsclient_prefix_cmd, + "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix /, e.g., 35.0.0.0/8\n") + ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_ipv4_safi_rsclient_prefix_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", @@ -11202,7 +14103,7 @@ ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, "IP prefix /, e.g., 35.0.0.0/8\n") #ifdef HAVE_IPV6 -DEFUN (show_bgp_view_neighbor_routes, +DEFUN (show_bgp_view_ipv6_neighbor_routes, show_bgp_view_ipv6_neighbor_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR @@ -11230,6 +14131,32 @@ DEFUN (show_bgp_view_neighbor_routes, } DEFUN (show_bgp_view_neighbor_damp, + show_bgp_view_neighbor_damp_cmd, + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") +{ + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, + bgp_show_type_damp_neighbor); +} + +DEFUN (show_bgp_view_ipv6_neighbor_damp, show_bgp_view_ipv6_neighbor_damp_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR @@ -11256,7 +14183,7 @@ DEFUN (show_bgp_view_neighbor_damp, bgp_show_type_damp_neighbor); } -DEFUN (show_bgp_view_neighbor_flap, +DEFUN (show_bgp_view_ipv6_neighbor_flap, show_bgp_view_ipv6_neighbor_flap_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR @@ -11283,6 +14210,88 @@ DEFUN (show_bgp_view_neighbor_flap, bgp_show_type_flap_neighbor); } +DEFUN (show_bgp_view_neighbor_flap, + show_bgp_view_neighbor_flap_cmd, + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display flap statistics of the routes learned from neighbor\n") +{ + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, + bgp_show_type_flap_neighbor); +} + +ALIAS (show_bgp_view_neighbor_flap, + show_bgp_neighbor_flap_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display flap statistics of the routes learned from neighbor\n") + +ALIAS (show_bgp_view_neighbor_damp, + show_bgp_neighbor_damp_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") + +DEFUN (show_bgp_view_neighbor_routes, + show_bgp_view_neighbor_routes_cmd, + "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +ALIAS (show_bgp_view_neighbor_routes, + show_bgp_neighbor_routes_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + ALIAS (show_bgp_view_neighbor_routes, show_bgp_ipv6_neighbor_routes_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", @@ -11294,6 +14303,40 @@ ALIAS (show_bgp_view_neighbor_routes, "Neighbor to display information about\n" "Display routes learned from neighbor\n") +/* old command */ +ALIAS (show_bgp_view_neighbor_routes, + ipv6_bgp_neighbor_routes_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_routes, + ipv6_mbgp_neighbor_routes_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + struct peer *peer; + + peer = peer_lookup_in_view (vty, NULL, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_neighbor); +} + ALIAS (show_bgp_view_neighbor_flap, show_bgp_ipv6_neighbor_flap_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", @@ -11305,18 +14348,67 @@ ALIAS (show_bgp_view_neighbor_flap, "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") -ALIAS (show_bgp_view_neighbor_damp, - show_bgp_ipv6_neighbor_damp_cmd, - "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", +ALIAS (show_bgp_view_neighbor_damp, + show_bgp_ipv6_neighbor_damp_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") + +#endif /* HAVE_IPV6 */ + +DEFUN (show_bgp_view_rsclient, + show_bgp_view_rsclient_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) +{ + struct bgp_table *table; + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP6][SAFI_UNICAST]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); +} + +ALIAS (show_bgp_view_rsclient, + show_bgp_rsclient_cmd, + "show bgp rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Neighbor to display information about\n" - "Display the dampened routes received from neighbor\n") - -#endif /* HAVE_IPV6 */ + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_ipv4_rsclient, show_bgp_view_ipv4_rsclient_cmd, @@ -11479,9 +14571,70 @@ ALIAS (show_bgp_view_ipv6_safi_rsclient, "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) - DEFUN (show_bgp_view_rsclient_route, show_bgp_view_rsclient_route_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_bgp_view_ipv6_rsclient_route, + show_bgp_view_ipv6_rsclient_route_cmd, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR @@ -11543,8 +14696,17 @@ DEFUN (show_bgp_view_rsclient_route, AFI_IP6, SAFI_UNICAST, NULL, 0); } -ALIAS (show_bgp_view_rsclient_route, +ALIAS (show_bgp_view_ipv6_rsclient_route, show_bgp_rsclient_route_cmd, + "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + SHOW_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + +ALIAS (show_bgp_view_ipv6_rsclient_route, + show_bgp_ipv6_rsclient_route_cmd, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR @@ -11637,6 +14799,68 @@ ALIAS (show_bgp_view_ipv6_safi_rsclient_route, DEFUN (show_bgp_view_rsclient_prefix, show_bgp_view_rsclient_prefix_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_bgp_view_ipv6_rsclient_prefix, + show_bgp_view_ipv6_rsclient_prefix_cmd, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR @@ -11698,8 +14922,17 @@ DEFUN (show_bgp_view_rsclient_prefix, AFI_IP6, SAFI_UNICAST, NULL, 1); } -ALIAS (show_bgp_view_rsclient_prefix, +ALIAS (show_bgp_view_ipv6_rsclient_prefix, show_bgp_rsclient_prefix_cmd, + "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + SHOW_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") + +ALIAS (show_bgp_view_ipv6_rsclient_prefix, + show_bgp_ipv6_rsclient_prefix_cmd, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR @@ -12152,6 +15385,48 @@ ALIAS (bgp_damp_unset, "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") +DEFUN (show_ip_bgp_dampened_paths, + show_ip_bgp_dampened_paths_cmd, + "show ip bgp dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Display paths suppressed due to dampening\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths, + NULL); +} + +ALIAS (show_ip_bgp_dampened_paths, + show_ip_bgp_damp_dampened_paths_cmd, + "show ip bgp dampening dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display paths suppressed due to dampening\n") + +DEFUN (show_ip_bgp_flap_statistics, + show_ip_bgp_flap_statistics_cmd, + "show ip bgp flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_statistics, NULL); +} + +ALIAS (show_ip_bgp_flap_statistics, + show_ip_bgp_damp_flap_statistics_cmd, + "show ip bgp dampening flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Display detailed information about dampening\n" + "Display flap statistics of routes\n") + DEFUN (show_bgp_ipv4_safi_dampened_paths, show_bgp_ipv4_safi_dampened_paths_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampened-paths", @@ -13060,14 +16335,14 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); @@ -13079,9 +16354,9 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_ipv4_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd); - install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); - install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd); @@ -13095,9 +16370,9 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_view_ipv4_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); - install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); - install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Restricted: @@ -13107,24 +16382,24 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); - install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); - install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); - install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); - install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd); @@ -13136,16 +16411,16 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); @@ -13156,9 +16431,9 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_bgp_ipv4_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd); @@ -13172,9 +16447,9 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_bgp_view_ipv4_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Statistics */ @@ -13248,6 +16523,428 @@ bgp_route_init (void) install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd); #endif + + /* old style commands */ + install_element (VIEW_NODE, &show_ip_bgp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd); + install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_address_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_damp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community2_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community3_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community4_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_address_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); + install_element (VIEW_NODE, &show_bgp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_cmd); + install_element (VIEW_NODE, &show_bgp_route_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_community_cmd); + install_element (VIEW_NODE, &show_bgp_community2_cmd); + install_element (VIEW_NODE, &show_bgp_community3_cmd); + install_element (VIEW_NODE, &show_bgp_community4_cmd); + install_element (VIEW_NODE, &show_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_view_cmd); + install_element (VIEW_NODE, &show_bgp_view_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); + install_element (RESTRICTED_NODE, &show_bgp_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); + install_element (ENABLE_NODE, &show_bgp_route_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_community_cmd); + install_element (ENABLE_NODE, &show_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_view_cmd); + install_element (ENABLE_NODE, &show_bgp_view_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_view_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); + /* old with name safi collision */ + install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); + + install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); + + install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); } void diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 2df230966..e271210d6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7394,6 +7394,103 @@ bgp_show_summary_vty (struct vty *vty, const char *name, } /* `show ip bgp summary' commands. */ +DEFUN (show_ip_bgp_summary, + show_ip_bgp_summary_cmd, + "show ip bgp summary", + SHOW_STR + IP_STR + BGP_STR + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_summary, + show_ip_bgp_instance_summary_cmd, + "show ip bgp view WORD summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_summary, + show_ip_bgp_ipv4_summary_cmd, + "show ip bgp ipv4 (unicast|multicast) summary", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_ipv4_summary, + show_ip_bgp_instance_ipv4_summary_cmd, + "show ip bgp view WORD ipv4 (unicast|multicast) summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + else + return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_vpnv4_all_summary, + show_ip_bgp_vpnv4_all_summary_cmd, + "show ip bgp vpnv4 all summary", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} + +DEFUN (show_ip_bgp_vpnv4_rd_summary, + show_ip_bgp_vpnv4_rd_summary_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Summary of BGP neighbor status\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} + DEFUN (show_bgp_ipv4_safi_summary, show_bgp_ipv4_safi_summary_cmd, "show bgp ipv4 (unicast|multicast) summary", @@ -7617,6 +7714,29 @@ DEFUN (show_bgp_instance_ipv6_safi_summary, return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } +/* old command */ +DEFUN (show_ipv6_bgp_summary, + show_ipv6_bgp_summary_cmd, + "show ipv6 bgp summary", + SHOW_STR + IPV6_STR + BGP_STR + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_summary, + show_ipv6_mbgp_summary_cmd, + "show ipv6 mbgp summary", + SHOW_STR + IPV6_STR + MBGP_STR + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); +} #endif /* HAVE_IPV6 */ /* variations of show bgp [...] summary */ @@ -7659,6 +7779,14 @@ DEFUN (show_bgp_summary, return CMD_SUCCESS; } +ALIAS (show_bgp_summary, + show_bgp_ipv6_summary_cmd, + "show bgp ipv6 summary", + SHOW_STR + BGP_STR + "Address family\n" + "Summary of BGP neighbor status\n") + DEFUN (show_bgp_summary_1w, show_bgp_summary_1w_cmd, #ifdef HAVE_IPV6 @@ -8495,7 +8623,186 @@ bgp_show_neighbor_vty (struct vty *vty, const char *name, return CMD_SUCCESS; } -/* "show ip bgp neighbors" commands. */ +/* "show ip bgp neighbors" commands. */DEFUN (show_ip_bgp_neighbors, + show_ip_bgp_neighbors_cmd, + "show ip bgp neighbors", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n") +{ + return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); +} + +ALIAS (show_ip_bgp_neighbors, + show_ip_bgp_ipv4_neighbors_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, + show_ip_bgp_vpnv4_all_neighbors_cmd, + "show ip bgp vpnv4 all neighbors", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, + show_ip_bgp_vpnv4_rd_neighbors_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, + show_bgp_ipv6_neighbors_cmd, + "show bgp ipv6 neighbors", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFUN (show_ip_bgp_neighbors_peer, + show_ip_bgp_neighbors_peer_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") +{ + return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); +} + +ALIAS (show_ip_bgp_neighbors_peer, + show_ip_bgp_ipv4_neighbors_peer_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, + show_ip_bgp_vpnv4_all_neighbors_peer_cmd, + "show ip bgp vpnv4 all neighbors A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, + show_ip_bgp_vpnv4_rd_neighbors_peer_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, + show_bgp_ipv6_neighbors_peer_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +DEFUN (show_ip_bgp_instance_neighbors, + show_ip_bgp_instance_neighbors_cmd, + "show ip bgp view WORD neighbors", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n") +{ + return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); +} + +ALIAS (show_ip_bgp_instance_neighbors, + show_bgp_instance_ipv6_neighbors_cmd, + "show bgp view WORD ipv6 neighbors", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFUN (show_ip_bgp_instance_neighbors_peer, + show_ip_bgp_instance_neighbors_peer_cmd, + "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") +{ + return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]); +} + +/* Show BGP's AS paths internal data. There are both `show ip bgp + paths' and `show ip mbgp paths'. Those functions results are the + same.*/ +DEFUN (show_ip_bgp_paths, + show_ip_bgp_paths_cmd, + "show ip bgp paths", + SHOW_STR + IP_STR + BGP_STR + "Path information\n") +{ + vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); + aspath_print_all_vty (vty); + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_paths, + show_ip_bgp_ipv4_paths_cmd, + "show ip bgp ipv4 (unicast|multicast) paths", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Path information\n") +{ + vty_out (vty, "Address Refcnt Path\r\n"); + aspath_print_all_vty (vty); + + return CMD_SUCCESS; +} + DEFUN (show_bgp_neighbors, show_bgp_neighbors_cmd, "show bgp neighbors", @@ -8534,16 +8841,6 @@ DEFUN (show_bgp_instance_neighbors, return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); } -ALIAS (show_bgp_instance_neighbors, - show_bgp_instance_ipv6_neighbors_cmd, - "show bgp view WORD ipv6 neighbors", - SHOW_STR - BGP_STR - "BGP view\n" - "View name\n" - "Address family\n" - "Detailed information on TCP and BGP neighbor connections\n") - DEFUN (show_bgp_instance_neighbors_peer, show_bgp_instance_neighbors_peer_cmd, #ifdef HAVE_IPV6 @@ -8772,6 +9069,69 @@ bgp_show_rsclient_summary_vty (struct vty *vty, const char *name, } /* 'show bgp rsclient' commands. */ +DEFUN (show_ip_bgp_rsclient_summary, + show_ip_bgp_rsclient_summary_cmd, + "show ip bgp rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_rsclient_summary, + show_ip_bgp_instance_rsclient_summary_cmd, + "show ip bgp view WORD rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_rsclient_summary, + show_ip_bgp_ipv4_rsclient_summary_cmd, + "show ip bgp ipv4 (unicast|multicast) rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, + show_ip_bgp_instance_ipv4_rsclient_summary_cmd, + "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} DEFUN (show_bgp_instance_ipv4_safi_rsclient_summary, show_bgp_instance_ipv4_safi_rsclient_summary_cmd, @@ -10712,7 +11072,6 @@ bgp_vty_init (void) #ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd); - install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd); #endif install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); @@ -10779,12 +11138,10 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); - install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); @@ -10840,7 +11197,79 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_views_cmd); install_element (RESTRICTED_NODE, &show_bgp_views_cmd); install_element (ENABLE_NODE, &show_bgp_views_cmd); - + + /* non afi/safi forms of commands */ + install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); /* Community-list. */ community_list_vty (); } From 544ec70f66d0ec081dadde79bec1f25c2241f57f Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:10 -0500 Subject: [PATCH 0954/1342] doc: Add AFI/SAFI show commands to manual Signed-off-by: Lou Berger --- doc/bgpd.texi | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 1513f7a30..c02e9f5a5 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -771,6 +771,31 @@ This command bind specific peer to peer group @var{word}. @node BGP Address Family @section BGP Address Family +Multiprotocol BGP enables BGP to carry routing information for multiple +Network Layer protocols. BGP supports multiple Address Family +Identifier (AFI), namely IPv4 and IPv6. Support is also provided for +multiple sets of per-AFI information via Subsequent Address Family +Identifiers (SAFI). In addition to unicast information, VPN information +@cite{RFC4364} and @cite{RFC4659}, and Encapsulation information +@cite{RFC5512} is supported. + +@deffn {Command} {show ip bgp vpnv4 all} {} +@deffnx {Command} {show ipv6 bgp vpn all} {} +Print active IPV4 or IPV6 routes advertised via the VPN SAFI. +@end deffn + +@deffn {Command} {show ip bgp encap all} {} +@deffnx {Command} {show ipv6 bgp encap all} {} +Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI. +@end deffn + +@deffn {Command} {show bgp ipv4 encap summary} {} +@deffnx {Command} {show bgp ipv4 vpn summary} {} +@deffnx {Command} {show bgp ipv6 encap summary} {} +@deffnx {Command} {show bgp ipv6 vpn summary} {} +Print a summary of neighbor connections for the specified AFI/SAFI combination. +@end deffn + @c ----------------------------------------------------------------------- @node Autonomous System @section Autonomous System From 205e6744f2dc2909dd494c9ce8acb82821459f1f Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:11 -0500 Subject: [PATCH 0955/1342] bgpd: remove HAVE_IPV6 conditionals Signed-off-by: Lou Berger Tested-by: NetDEF CI System --- bgpd/bgp_attr.c | 17 +--- bgpd/bgp_attr.h | 2 - bgpd/bgp_debug.c | 2 - bgpd/bgp_encap.c | 31 ++----- bgpd/bgp_mpath.c | 4 - bgpd/bgp_mplsvpn.c | 8 -- bgpd/bgp_network.c | 51 ----------- bgpd/bgp_nexthop.c | 26 ------ bgpd/bgp_open.c | 2 - bgpd/bgp_packet.c | 4 - bgpd/bgp_route.c | 213 ++++---------------------------------------- bgpd/bgp_routemap.c | 8 -- bgpd/bgp_table.h | 4 - bgpd/bgp_vty.c | 100 ++------------------- bgpd/bgp_zebra.c | 18 +--- bgpd/bgp_zebra.h | 2 - bgpd/bgpd.h | 2 - 17 files changed, 33 insertions(+), 461 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5dc118be6..888f11a19 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -511,11 +511,9 @@ attrhash_key_make (void *p) if (extra->transit) MIX(transit_hash_key_make (extra->transit)); -#ifdef HAVE_IPV6 MIX(extra->mp_nexthop_len); key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); -#endif /* HAVE_IPV6 */ } return key; @@ -542,11 +540,9 @@ attrhash_cmp (const void *p1, const void *p2) && ae1->aggregator_as == ae2->aggregator_as && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr && ae1->weight == ae2->weight -#ifdef HAVE_IPV6 && ae1->mp_nexthop_len == ae2->mp_nexthop_len && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) -#endif /* HAVE_IPV6 */ && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) && ae1->ecommunity == ae2->ecommunity && ae1->cluster == ae2->cluster @@ -696,9 +692,7 @@ bgp_attr_default_set (struct attr *attr, u_char origin) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); -#ifdef HAVE_IPV6 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; -#endif return attr; } @@ -757,9 +751,8 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, } attre.weight = BGP_ATTR_DEFAULT_WEIGHT; -#ifdef HAVE_IPV6 attre.mp_nexthop_len = IPV6_MAX_BYTELEN; -#endif + if (! as_set) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); @@ -1658,7 +1651,6 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, stream_getl (s); /* RD low */ stream_get (&attre->mp_nexthop_global_in, s, 4); break; -#ifdef HAVE_IPV6 case 24: { u_int32_t rd_high __attribute__((unused)); @@ -1705,7 +1697,6 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, attre->mp_nexthop_len = 16; } break; -#endif /* HAVE_IPV6 */ default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); @@ -2434,7 +2425,6 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, break; } break; -#ifdef HAVE_IPV6 case AFI_IP6: switch (safi) { @@ -2480,7 +2470,6 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, break; } break; -#endif /*HAVE_IPV6*/ default: break; } @@ -3063,9 +3052,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, /* Nexthop attribute. */ /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ if(prefix != NULL -#ifdef HAVE_IPV6 && prefix->family != AF_INET6 -#endif /* HAVE_IPV6 */ ) { stream_putc (s, BGP_ATTR_FLAG_TRANS); @@ -3129,7 +3116,6 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_put (s, attr->community->val, attr->community->size * 4); } -#ifdef HAVE_IPV6 /* Add a MP_NLRI attribute to dump the IPv6 next hop */ if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) ) @@ -3161,7 +3147,6 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, /* Set MP attribute length. */ stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } -#endif /* HAVE_IPV6 */ /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6a134de4f..fe6c2a1a1 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -61,10 +61,8 @@ struct bgp_attr_encap_subtlv { struct attr_extra { /* Multi-Protocol Nexthop, AFI IPv6 */ -#ifdef HAVE_IPV6 struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_local; -#endif /* HAVE_IPV6 */ /* Extended Communities attribute. */ struct ecommunity *ecommunity; diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index e3e5ca46a..60e2777ec 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -175,7 +175,6 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s", bgp_origin_str[attr->origin]); -#ifdef HAVE_IPV6 if (attr->extra) { char addrbuf[BUFSIZ]; @@ -192,7 +191,6 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, addrbuf, BUFSIZ)); } -#endif /* HAVE_IPV6 */ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 48e231221..d0beb1ba6 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -511,7 +511,7 @@ DEFUN (show_bgp_ipv4_encap, { return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap, show_bgp_ipv6_encap_cmd, "show bgp ipv6 encap", @@ -522,7 +522,6 @@ DEFUN (show_bgp_ipv6_encap, { return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0); } -#endif DEFUN (show_bgp_ipv4_encap_rd, show_bgp_ipv4_encap_rd_cmd, @@ -545,7 +544,7 @@ DEFUN (show_bgp_ipv4_encap_rd, } return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 0); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_rd, show_bgp_ipv6_encap_rd_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn", @@ -568,7 +567,6 @@ DEFUN (show_bgp_ipv6_encap_rd, } return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 0); } -#endif DEFUN (show_bgp_ipv4_encap_tags, show_bgp_ipv4_encap_tags_cmd, @@ -581,7 +579,7 @@ DEFUN (show_bgp_ipv4_encap_tags, { return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 1); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_tags, show_bgp_ipv6_encap_tags_cmd, "show bgp ipv6 encap tags", @@ -593,7 +591,7 @@ DEFUN (show_bgp_ipv6_encap_tags, { return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 1); } -#endif + DEFUN (show_bgp_ipv4_encap_rd_tags, show_bgp_ipv4_encap_rd_tags_cmd, @@ -617,7 +615,7 @@ DEFUN (show_bgp_ipv4_encap_rd_tags, } return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 1); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_rd_tags, show_bgp_ipv6_encap_rd_tags_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn tags", @@ -640,7 +638,6 @@ DEFUN (show_bgp_ipv6_encap_rd_tags, } return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 1); } -#endif DEFUN (show_bgp_ipv4_encap_neighbor_routes, show_bgp_ipv4_encap_neighbor_routes_cmd, @@ -672,7 +669,7 @@ DEFUN (show_bgp_ipv4_encap_neighbor_routes, return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_neighbor_routes, show_bgp_ipv6_encap_neighbor_routes_cmd, "show bgp ipv6 encap neighbors A.B.C.D routes", @@ -703,7 +700,6 @@ DEFUN (show_bgp_ipv6_encap_neighbor_routes, return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_neighbor, su, 0); } -#endif DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, show_bgp_ipv4_encap_rd_neighbor_routes_cmd, @@ -747,7 +743,7 @@ DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_neighbor, su, 0); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, show_bgp_ipv6_encap_rd_neighbor_routes_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", @@ -790,7 +786,6 @@ DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_neighbor, su, 0); } -#endif DEFUN (show_bgp_ipv4_encap_neighbor_advertised_routes, show_bgp_ipv4_encap_neighbor_advertised_routes_cmd, @@ -822,7 +817,7 @@ DEFUN (show_bgp_ipv4_encap_neighbor_advertised_routes, return show_adj_route_encap (vty, peer, NULL); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_neighbor_advertised_routes, show_bgp_ipv6_encap_neighbor_advertised_routes_cmd, "show bgp ipv6 encap neighbors A.B.C.D advertised-routes", @@ -853,7 +848,6 @@ DEFUN (show_bgp_ipv6_encap_neighbor_advertised_routes, return show_adj_route_encap (vty, peer, NULL); } -#endif DEFUN (show_bgp_ipv4_encap_rd_neighbor_advertised_routes, show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd, @@ -896,7 +890,7 @@ DEFUN (show_bgp_ipv4_encap_rd_neighbor_advertised_routes, return show_adj_route_encap (vty, peer, &prd); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_encap_rd_neighbor_advertised_routes, show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", @@ -938,7 +932,6 @@ DEFUN (show_bgp_ipv6_encap_rd_neighbor_advertised_routes, return show_adj_route_encap (vty, peer, &prd); } -#endif void bgp_encap_init (void) @@ -955,7 +948,6 @@ bgp_encap_init (void) install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_ipv6_encap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_tags_cmd); @@ -964,8 +956,6 @@ bgp_encap_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); -#endif - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_cmd); @@ -976,7 +966,6 @@ bgp_encap_init (void) install_element (ENABLE_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_encap_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_encap_tags_cmd); @@ -985,7 +974,5 @@ bgp_encap_init (void) install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); -#endif - } diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 9eaf3c26a..73b93cebb 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -148,7 +148,6 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in); break; -#ifdef HAVE_IPV6 case 16: compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); @@ -160,7 +159,6 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local); break; -#endif /* HAVE_IPV6 */ } } @@ -746,10 +744,8 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, /* Zap multipath attr nexthop so we set nexthop to self */ attr.nexthop.s_addr = 0; -#ifdef HAVE_IPV6 if (attr.extra) memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); -#endif /* HAVE_IPV6 */ /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 99e86b43d..f8b43df88 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -599,7 +599,6 @@ DEFUN (show_bgp_ipv4_vpn, return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_vpn, show_bgp_ipv6_vpn_cmd, "show bgp ipv6 vpn", @@ -610,7 +609,6 @@ DEFUN (show_bgp_ipv6_vpn, { return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0); } -#endif DEFUN (show_bgp_ipv4_vpn_rd, show_bgp_ipv4_vpn_rd_cmd, @@ -758,7 +756,6 @@ DEFUN (show_bgp_ipv4_vpn_neighbor_routes, return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_vpn_neighbor_routes, show_bgp_ipv6_vpn_neighbor_routes_cmd, "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) routes", @@ -792,7 +789,6 @@ DEFUN (show_bgp_ipv6_vpn_neighbor_routes, return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_neighbor, &su, 0); } -#endif DEFUN (show_bgp_ipv4_vpn_neighbor_advertised_routes, show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd, @@ -1035,7 +1031,6 @@ bgp_mplsvpn_init (void) install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_ipv6_vpn_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_tags_cmd); @@ -1044,7 +1039,6 @@ bgp_mplsvpn_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); -#endif install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_cmd); @@ -1055,7 +1049,6 @@ bgp_mplsvpn_init (void) install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_tags_cmd); @@ -1064,5 +1057,4 @@ bgp_mplsvpn_init (void) install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); -#endif } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index d11cbc3e7..7a2271398 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -387,10 +387,8 @@ bgp_connect (struct peer *peer) zlog_err ("%s: could not raise privs", __func__); if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); -# ifdef HAVE_IPV6 else if (sockunion_family (&peer->su) == AF_INET6) setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); -# endif if (bgpd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs", __func__); #endif @@ -404,10 +402,8 @@ bgp_connect (struct peer *peer) /* Update source bind. */ bgp_update_source (peer); -#ifdef HAVE_IPV6 if (peer->ifname) ifindex = ifname2ifindex (peer->ifname); -#endif /* HAVE_IPV6 */ if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect start to %s fd %d", @@ -455,10 +451,8 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); -# ifdef HAVE_IPV6 else if (sa->sa_family == AF_INET6) setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); -# endif #endif sockopt_v6only (sa->sa_family, sock); @@ -491,7 +485,6 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) } /* IPv6 supported version of BGP server socket setup. */ -#ifdef HAVE_IPV6 int bgp_socket (unsigned short port, const char *address) { @@ -548,50 +541,6 @@ bgp_socket (unsigned short port, const char *address) return 0; } -#else -/* Traditional IPv4 only version. */ -int -bgp_socket (unsigned short port, const char *address) -{ - int sock; - int socklen; - struct sockaddr_in sin; - int ret; - - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock < 0) - { - zlog_err ("socket: %s", safe_strerror (errno)); - return sock; - } - - /* if we intend to implement ttl-security, this socket needs ttl=255 */ - sockopt_ttl (AF_INET, sock, MAXTTL); - - memset (&sin, 0, sizeof (struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons (port); - socklen = sizeof (struct sockaddr_in); - - if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1)) - { - zlog_err("bgp_socket: could not parse ip address %s: %s", - address, safe_strerror (errno)); - return ret; - } -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = socklen; -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - - ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen); - if (ret < 0) - { - close (sock); - return ret; - } - return sock; -} -#endif /* HAVE_IPV6 */ void bgp_close (void) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index bb07eace1..24068141c 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -43,9 +43,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ struct bgp_nexthop_cache *zlookup_query (struct in_addr); -#ifdef HAVE_IPV6 struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); -#endif /* HAVE_IPV6 */ /* Only one BGP scan thread are activated at the same time. */ static struct thread *bgp_scan_thread = NULL; @@ -133,7 +131,6 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) if (next1->ifindex != next2->ifindex) return 0; break; -#ifdef HAVE_IPV6 case ZEBRA_NEXTHOP_IPV6: if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) return 0; @@ -145,7 +142,6 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) if (next1->ifindex != next2->ifindex) return 0; break; -#endif /* HAVE_IPV6 */ default: /* do nothing */ break; @@ -197,7 +193,6 @@ bgp_nexthop_onlink (afi_t afi, struct attr *attr) return 1; } } -#ifdef HAVE_IPV6 else if (afi == AFI_IP6) { if (attr->extra->mp_nexthop_len == 32) @@ -216,11 +211,9 @@ bgp_nexthop_onlink (afi_t afi, struct attr *attr) } } } -#endif /* HAVE_IPV6 */ return 0; } -#ifdef HAVE_IPV6 /* Check specified next-hop is reachable or not. */ static int bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, @@ -305,7 +298,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, return bnc->valid; } -#endif /* HAVE_IPV6 */ /* Check specified next-hop is reachable or not. */ int @@ -325,10 +317,8 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, return 1; } -#ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); -#endif /* HAVE_IPV6 */ addr = ri->attr->nexthop; @@ -538,9 +528,7 @@ bgp_scan_timer (struct thread *t) bgp_scan (AFI_IP, SAFI_UNICAST); -#ifdef HAVE_IPV6 bgp_scan (AFI_IP6, SAFI_UNICAST); -#endif /* HAVE_IPV6 */ return 0; } @@ -684,7 +672,6 @@ bgp_connected_add (struct connected *ifc) rn->info = bc; } } -#ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { apply_mask_ipv6 ((struct prefix_ipv6 *) &p); @@ -708,7 +695,6 @@ bgp_connected_add (struct connected *ifc) rn->info = bc; } } -#endif /* HAVE_IPV6 */ } void @@ -751,7 +737,6 @@ bgp_connected_delete (struct connected *ifc) bgp_unlock_node (rn); bgp_unlock_node (rn); } -#ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { apply_mask_ipv6 ((struct prefix_ipv6 *) &p); @@ -776,7 +761,6 @@ bgp_connected_delete (struct connected *ifc) bgp_unlock_node (rn); bgp_unlock_node (rn); } -#endif /* HAVE_IPV6 */ } int @@ -899,7 +883,6 @@ zlookup_query (struct in_addr addr) return zlookup_read (); } -#ifdef HAVE_IPV6 static struct bgp_nexthop_cache * zlookup_read_ipv6 (void) { @@ -1002,7 +985,6 @@ zlookup_query_ipv6 (struct in6_addr *addr) return zlookup_read_ipv6 (); } -#endif /* HAVE_IPV6 */ static int bgp_import_check (struct prefix *p, u_int32_t *igpmetric, @@ -1321,7 +1303,6 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } -#ifdef HAVE_IPV6 { for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); rn; @@ -1353,7 +1334,6 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) VTY_NEWLINE); } } -#endif /* HAVE_IPV6 */ vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_connected_table[AFI_IP]); @@ -1363,7 +1343,6 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); -#ifdef HAVE_IPV6 { for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); rn; @@ -1374,7 +1353,6 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) rn->p.prefixlen, VTY_NEWLINE); } -#endif /* HAVE_IPV6 */ return CMD_SUCCESS; } @@ -1426,12 +1404,10 @@ bgp_scan_init (void) bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); -#ifdef HAVE_IPV6 cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); cache2_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); -#endif /* HAVE_IPV6 */ /* Make BGP scan thread. */ bgp_scan_thread = thread_add_timer (bm->master, bgp_scan_timer, @@ -1464,7 +1440,6 @@ bgp_scan_finish (void) bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; -#ifdef HAVE_IPV6 if (cache1_table[AFI_IP6]) bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; @@ -1476,7 +1451,6 @@ bgp_scan_finish (void) if (bgp_connected_table[AFI_IP6]) bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; -#endif /* HAVE_IPV6 */ } void diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 1c2ebd6d9..7b8b6577e 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -1006,7 +1006,6 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, 0); stream_putc (s, SAFI_ENCAP); } -#ifdef HAVE_IPV6 /* IPv6 unicast. */ if (peer->afc[AFI_IP6][SAFI_UNICAST]) { @@ -1055,7 +1054,6 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, 0); stream_putc (s, SAFI_ENCAP); } -#endif /* HAVE_IPV6 */ /* Route refresh. */ SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 1d18779bf..26e4d8ffc 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -449,10 +449,8 @@ bgp_default_update_send (struct peer *peer, struct attr *attr, if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); -#ifdef HAVE_IPV6 else str2prefix ("::/0", &p); -#endif /* HAVE_IPV6 */ /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_OUT)) @@ -518,10 +516,8 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); -#ifdef HAVE_IPV6 else str2prefix ("::/0", &p); -#endif /* HAVE_IPV6 */ total_attr_len = 0; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 93c613fa1..0dcae61ea 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -838,10 +838,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, { if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) return 0; -#ifdef HAVE_IPV6 else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; -#endif /* HAVE_IPV6 */ } /* Transparency check. */ @@ -985,31 +983,25 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, (safi != SAFI_ENCAP && p->family == AF_INET) || \ (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 4)) -#ifdef HAVE_IPV6 #define NEXTHOP_IS_V6 (\ (safi != SAFI_ENCAP && p->family == AF_INET6) || \ (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 16)) -#endif /* next-hop-set */ if (transparent || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL)) || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && ((NEXTHOP_IS_V4 && attr->nexthop.s_addr) -#ifdef HAVE_IPV6 || (NEXTHOP_IS_V6 && ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) -#endif /* HAVE_IPV6 */ ))) { /* NEXT-HOP Unchanged. */ } else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) || (NEXTHOP_IS_V4 && attr->nexthop.s_addr == 0) -#ifdef HAVE_IPV6 || (NEXTHOP_IS_V6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) -#endif /* HAVE_IPV6 */ || (peer->sort == BGP_PEER_EBGP && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) { @@ -1022,7 +1014,6 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, else memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); } -#ifdef HAVE_IPV6 /* Set IPv6 nexthop. */ if (NEXTHOP_IS_V6) { @@ -1031,10 +1022,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } -#endif /* HAVE_IPV6 */ } -#ifdef HAVE_IPV6 if (p->family == AF_INET6 && safi != SAFI_ENCAP) { /* Left nexthop_local unchanged if so configured. */ @@ -1073,7 +1062,6 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } } -#endif /* HAVE_IPV6 */ /* If this is EBGP peer and remove-private-AS is set. */ if (peer->sort == BGP_PEER_EBGP @@ -1154,10 +1142,8 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, { if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) return 0; -#ifdef HAVE_IPV6 else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; -#endif /* HAVE_IPV6 */ } /* If the attribute has originator-id and it is same as remote @@ -1216,10 +1202,8 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, /* next-hop-set */ if ((p->family == AF_INET && attr->nexthop.s_addr == 0) -#ifdef HAVE_IPV6 || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) -#endif /* HAVE_IPV6 */ ) { /* Set IPv4 nexthop. */ @@ -1231,7 +1215,6 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, else memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); } -#ifdef HAVE_IPV6 /* Set IPv6 nexthop. */ if (p->family == AF_INET6) { @@ -1240,10 +1223,8 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } -#endif /* HAVE_IPV6 */ } -#ifdef HAVE_IPV6 if (p->family == AF_INET6) { struct attr_extra *attre = attr->extra; @@ -1285,8 +1266,6 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, } } -#endif /* HAVE_IPV6 */ - /* If this is EBGP peer and remove-private-AS is set. */ if (rsclient->sort == BGP_PEER_EBGP @@ -2581,7 +2560,6 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); -#ifdef HAVE_IPV6 else if (afi == AFI_IP6) { struct attr_extra *ae = attr.extra; @@ -2603,7 +2581,6 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) ae->mp_nexthop_len = 32; } } -#endif /* HAVE_IPV6 */ if (peer->default_rmap[afi][safi].name) { @@ -3309,7 +3286,6 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) } } -#ifdef HAVE_IPV6 /* Check address. */ if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST) { @@ -3324,7 +3300,6 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) continue; } } -#endif /* HAVE_IPV6 */ /* Normal process. */ if (attr) @@ -3978,14 +3953,12 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } -#ifdef HAVE_IPV6 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { vty_out (vty, "%% Malformed prefix (link-local address)%s", VTY_NEWLINE); return CMD_WARNING; } -#endif /* HAVE_IPV6 */ apply_mask (&p); @@ -4071,14 +4044,12 @@ bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str, vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } -#ifdef HAVE_IPV6 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { vty_out (vty, "%% Malformed prefix (link-local address)%s", VTY_NEWLINE); return CMD_WARNING; } -#endif /* HAVE_IPV6 */ apply_mask (&p); @@ -4576,7 +4547,6 @@ ALIAS (no_bgp_network_mask_natural, "Network number\n" "Specify a BGP backdoor route\n") -#ifdef HAVE_IPV6 DEFUN (ipv6_bgp_network, ipv6_bgp_network_cmd, "network X:X::X:X/M", @@ -4634,7 +4604,6 @@ ALIAS (no_ipv6_bgp_network, BGP_STR "Specify a network to announce via BGP\n" "IPv6 prefix /, e.g., 3ffe::/16\n") -#endif /* HAVE_IPV6 */ /* stubs for removed AS-Pathlimit commands, kept for config compatibility */ ALIAS_DEPRECATED (bgp_network, @@ -4741,7 +4710,6 @@ ALIAS_DEPRECATED (no_bgp_network_mask_natural, "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") -#ifdef HAVE_IPV6 ALIAS_DEPRECATED (ipv6_bgp_network, ipv6_bgp_network_ttl_cmd, "network X:X::X:X/M pathlimit <0-255>", @@ -4757,7 +4725,6 @@ ALIAS_DEPRECATED (no_ipv6_bgp_network, "IPv6 prefix /\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") -#endif /* HAVE_IPV6 */ /* Aggreagete address: @@ -5585,7 +5552,6 @@ ALIAS (no_aggregate_address_mask, "Filter more specific routes from updates\n" "Generate AS set path information\n") -#ifdef HAVE_IPV6 DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, "aggregate-address X:X::X:X/M", @@ -5662,7 +5628,6 @@ ALIAS (no_ipv6_aggregate_address_summary_only, "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") -#endif /* HAVE_IPV6 */ /* Redistribute route treatment. */ void @@ -5686,14 +5651,12 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, if (nexthop) attr.nexthop = *nexthop; -#ifdef HAVE_IPV6 if (nexthop6) { struct attr_extra *extra = bgp_attr_extra_get(&attr); extra->mp_nexthop_global = *nexthop6; extra->mp_nexthop_len = 16; } -#endif attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); @@ -5982,13 +5945,10 @@ route_vty_out( vty_out (vty, "%s", inet_ntop(af, &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); break; -#if HAVE_IPV6 case AF_INET6: vty_out (vty, "%s", inet_ntop(af, &attr->extra->mp_nexthop_global, buf, BUFSIZ)); break; -#endif - default: vty_out(vty, "?"); } @@ -6001,7 +5961,6 @@ route_vty_out( { vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } -#ifdef HAVE_IPV6 else if (p->family == AF_INET6) { int len; @@ -6016,7 +5975,6 @@ route_vty_out( else vty_out (vty, "%*s", len, " "); } -#endif /* HAVE_IPV6 */ else { vty_out(vty, "?"); @@ -6074,7 +6032,6 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } -#ifdef HAVE_IPV6 else if (p->family == AF_INET6) { int len; @@ -6091,7 +6048,6 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, else vty_out (vty, "%*s", len, " "); } -#endif /* HAVE_IPV6 */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, "%10u ", attr->med); @@ -6147,7 +6103,6 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } -#ifdef HAVE_IPV6 else if (p->family == AF_INET6) { assert (attr->extra); @@ -6165,7 +6120,6 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, buf1, BUFSIZ)); } -#endif /* HAVE_IPV6 */ } label = decode_label (binfo->extra->tag); @@ -6328,7 +6282,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, inet_ntoa (attr->extra->mp_nexthop_global_in) : inet_ntoa (attr->nexthop)); } -#ifdef HAVE_IPV6 else { assert (attr->extra); @@ -6336,7 +6289,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, INET6_ADDRSTRLEN)); } -#endif /* HAVE_IPV6 */ if (binfo->peer == bgp->peer_self) { @@ -6362,7 +6314,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } vty_out (vty, "%s", VTY_NEWLINE); -#ifdef HAVE_IPV6 /* display nexthop local */ if (attr->extra && attr->extra->mp_nexthop_len == 32) { @@ -6371,7 +6322,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } -#endif /* HAVE_IPV6 */ /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */ vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]); @@ -7247,7 +7197,6 @@ DEFUN (show_bgp_ipv4_vpn_route, return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_vpn_route, show_bgp_ipv6_vpn_route_cmd, "show bgp ipv6 vpn X:X::X:X", @@ -7259,7 +7208,6 @@ DEFUN (show_bgp_ipv6_vpn_route, { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0); } -#endif DEFUN (show_bgp_ipv4_vpn_rd_route, show_bgp_ipv4_vpn_rd_route_cmd, @@ -7319,7 +7267,6 @@ DEFUN (show_bgp_ipv4_encap_route, return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_encap_route, show_bgp_ipv6_encap_route_cmd, "show bgp ipv6 encap X:X::X:X", @@ -7331,7 +7278,6 @@ DEFUN (show_bgp_ipv6_encap_route, { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0); } -#endif DEFUN (show_bgp_ipv4_safi_rd_route, show_bgp_ipv4_safi_rd_route_cmd, @@ -7362,7 +7308,6 @@ DEFUN (show_bgp_ipv4_safi_rd_route, return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_rd_route, show_bgp_ipv6_safi_rd_route_cmd, "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X", @@ -7391,7 +7336,6 @@ DEFUN (show_bgp_ipv6_safi_rd_route, } return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0); } -#endif DEFUN (show_bgp_ipv4_prefix, show_bgp_ipv4_prefix_cmd, @@ -7432,7 +7376,6 @@ DEFUN (show_bgp_ipv4_vpn_prefix, return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_vpn_prefix, show_bgp_ipv6_vpn_prefix_cmd, "show bgp ipv6 vpn X:X::X:X/M", @@ -7444,7 +7387,6 @@ DEFUN (show_bgp_ipv6_vpn_prefix, { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1); } -#endif DEFUN (show_bgp_ipv4_encap_prefix, show_bgp_ipv4_encap_prefix_cmd, @@ -7459,7 +7401,6 @@ DEFUN (show_bgp_ipv4_encap_prefix, return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_encap_prefix, show_bgp_ipv6_encap_prefix_cmd, "show bgp ipv6 encap X:X::X:X/M", @@ -7472,7 +7413,6 @@ DEFUN (show_bgp_ipv6_encap_prefix, { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1); } -#endif DEFUN (show_bgp_ipv4_safi_rd_prefix, show_bgp_ipv4_safi_rd_prefix_cmd, @@ -7504,7 +7444,6 @@ DEFUN (show_bgp_ipv4_safi_rd_prefix, return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_rd_prefix, show_bgp_ipv6_safi_rd_prefix_cmd, "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X/M", @@ -7534,7 +7473,6 @@ DEFUN (show_bgp_ipv6_safi_rd_prefix, } return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1); } -#endif DEFUN (show_bgp_afi_safi_view, show_bgp_afi_safi_view_cmd, @@ -7652,7 +7590,6 @@ DEFUN (show_bgp_afi, NULL); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi, show_bgp_ipv6_safi_cmd, "show bgp ipv6 (unicast|multicast)", @@ -7887,9 +7824,6 @@ DEFUN (show_bgp_view_ipv6_prefix, return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } -#endif - - static int bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -7994,7 +7928,6 @@ DEFUN (show_ip_bgp_ipv4_regexp, bgp_show_type_regexp); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_regexp, show_bgp_regexp_cmd, "show bgp regexp .LINE", @@ -8034,7 +7967,6 @@ DEFUN (show_ipv6_mbgp_regexp, return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, bgp_show_type_regexp); } -#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_safi_flap_regexp, show_bgp_ipv4_safi_flap_regexp_cmd, @@ -8075,7 +8007,6 @@ ALIAS (show_bgp_ipv4_safi_flap_regexp, "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_flap_regexp, show_bgp_ipv6_safi_flap_regexp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", @@ -8114,7 +8045,6 @@ ALIAS (show_bgp_ipv6_safi_flap_regexp, "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") -#endif DEFUN (show_bgp_ipv4_safi_regexp, show_bgp_ipv4_safi_regexp_cmd, @@ -8138,7 +8068,7 @@ DEFUN (show_bgp_ipv4_safi_regexp, return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP, safi, bgp_show_type_regexp); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_regexp, show_bgp_ipv6_safi_regexp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) regexp .LINE", @@ -8175,8 +8105,6 @@ DEFUN (show_bgp_ipv6_regexp, bgp_show_type_regexp); } -#endif /* HAVE_IPV6 */ - static int bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -8251,7 +8179,6 @@ DEFUN (show_ip_bgp_ipv4_prefix_list, bgp_show_type_prefix_list); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_list, show_bgp_prefix_list_cmd, "show bgp prefix-list WORD", @@ -8300,7 +8227,6 @@ DEFUN (show_ipv6_mbgp_prefix_list, return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_prefix_list); } -#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_prefix_list, show_bgp_ipv4_prefix_list_cmd, @@ -8353,7 +8279,6 @@ ALIAS (show_bgp_ipv4_safi_flap_prefix_list, "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_flap_prefix_list, show_bgp_ipv6_safi_flap_prefix_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", @@ -8390,7 +8315,6 @@ ALIAS (show_bgp_ipv6_safi_flap_prefix_list, "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") -#endif DEFUN (show_bgp_ipv4_safi_prefix_list, show_bgp_ipv4_safi_prefix_list_cmd, @@ -8413,7 +8337,7 @@ DEFUN (show_bgp_ipv4_safi_prefix_list, return bgp_show_prefix_list (vty, argv[1], AFI_IP, safi, bgp_show_type_prefix_list); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_prefix_list, show_bgp_ipv6_safi_prefix_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) prefix-list WORD", @@ -8436,8 +8360,6 @@ DEFUN (show_bgp_ipv6_safi_prefix_list, bgp_show_type_prefix_list); } -#endif /* HAVE_IPV6 */ - static int bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -8512,7 +8434,6 @@ DEFUN (show_ip_bgp_ipv4_filter_list, bgp_show_type_filter_list); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_filter_list, show_bgp_filter_list_cmd, "show bgp filter-list WORD", @@ -8552,7 +8473,6 @@ DEFUN (show_ipv6_mbgp_filter_list, return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_filter_list); } -#endif /* HAVE_IPV6 */ DEFUN (show_ip_bgp_dampening_info, show_ip_bgp_dampening_params_cmd, @@ -8618,7 +8538,6 @@ ALIAS (show_bgp_ipv4_safi_flap_filter_list, "Display routes conforming to the filter-list\n" "Regular expression access list name\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_flap_filter_list, show_bgp_ipv6_safi_flap_filter_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", @@ -8656,7 +8575,6 @@ ALIAS (show_bgp_ipv6_safi_flap_filter_list, "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") -#endif DEFUN (show_bgp_ipv4_safi_filter_list, show_bgp_ipv4_safi_filter_list_cmd, @@ -8679,7 +8597,7 @@ DEFUN (show_bgp_ipv4_safi_filter_list, return bgp_show_filter_list (vty, argv[1], AFI_IP, safi, bgp_show_type_filter_list); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_filter_list, show_bgp_ipv6_safi_filter_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) filter-list WORD", @@ -8715,8 +8633,6 @@ DEFUN (show_bgp_ipv6_filter_list, bgp_show_type_filter_list); } -#endif /* HAVE_IPV6 */ - static int bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -8889,7 +8805,6 @@ DEFUN (show_ip_bgp_ipv4_community_all, bgp_show_type_community_all, NULL); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_community_all, show_bgp_community_all_cmd, "show bgp community", @@ -8934,7 +8849,6 @@ DEFUN (show_ipv6_mbgp_community_all, return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_community_all, NULL); } -#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_route_map, show_bgp_ipv4_route_map_cmd, @@ -8986,7 +8900,7 @@ ALIAS (show_bgp_ipv4_safi_flap_route_map, "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_flap_route_map, show_bgp_ipv6_safi_flap_route_map_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", @@ -9023,7 +8937,6 @@ ALIAS (show_bgp_ipv6_safi_flap_route_map, "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") -#endif DEFUN (show_bgp_ipv4_safi_route_map, show_bgp_ipv4_safi_route_map_cmd, @@ -9046,7 +8959,7 @@ DEFUN (show_bgp_ipv4_safi_route_map, return bgp_show_route_map (vty, argv[1], AFI_IP, safi, bgp_show_type_route_map); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_route_map, show_bgp_ipv6_safi_route_map_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) route-map WORD", @@ -9081,7 +8994,6 @@ DEFUN (show_bgp_ipv6_route_map, return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_route_map); } -#endif DEFUN (show_bgp_ipv4_cidr_only, show_bgp_ipv4_cidr_only_cmd, @@ -9152,17 +9064,11 @@ DEFUN (show_bgp_ipv4_safi_cidr_only, /* new046 */ DEFUN (show_bgp_afi_safi_community_all, show_bgp_afi_safi_community_all_cmd, -#ifdef HAVE_IPV6 "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) community", -#else - "show bgp ipv4 (encap|multicast|unicast|vpn) community", -#endif SHOW_STR BGP_STR "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" @@ -9185,17 +9091,11 @@ DEFUN (show_bgp_afi_safi_community_all, } DEFUN (show_bgp_afi_community_all, show_bgp_afi_community_all_cmd, -#ifdef HAVE_IPV6 "show bgp (ipv4|ipv6) community", -#else - "show bgp ipv4 community", -#endif SHOW_STR BGP_STR "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Display routes matching the communities\n") { afi_t afi; @@ -9609,7 +9509,6 @@ ALIAS (show_ip_bgp_ipv4_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -#ifdef HAVE_IPV6 DEFUN (show_bgp_community, show_bgp_community_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export)", @@ -10227,7 +10126,6 @@ ALIAS (show_ipv6_mbgp_community_exact, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") -#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_community, show_bgp_ipv4_community_cmd, @@ -10392,19 +10290,13 @@ ALIAS (show_bgp_ipv4_safi_community, DEFUN (show_bgp_view_afi_safi_community_all, show_bgp_view_afi_safi_community_all_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", -#else - "show bgp view WORD ipv4 (unicast|multicast) community", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") @@ -10421,31 +10313,20 @@ DEFUN (show_bgp_view_afi_safi_community_all, return CMD_WARNING; } -#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; -#endif return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); } DEFUN (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -10457,32 +10338,20 @@ DEFUN (show_bgp_view_afi_safi_community, int afi; int safi; -#ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); -#else - afi = AFI_IP; - safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; - return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); -#endif } ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community2_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -10497,19 +10366,13 @@ ALIAS (show_bgp_view_afi_safi_community, ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community3_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -10528,19 +10391,13 @@ ALIAS (show_bgp_view_afi_safi_community, ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community4_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#else - "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", -#endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" -#ifdef HAVE_IPV6 "Address family\n" -#endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" @@ -10730,8 +10587,6 @@ ALIAS (show_bgp_ipv4_safi_community4_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") - -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_community, show_bgp_ipv6_safi_community_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export)", @@ -10932,8 +10787,6 @@ ALIAS (show_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") -#endif /* HAVE_IPV6 */ - static int bgp_show_community_list (struct vty *vty, const char *com, int exact, afi_t afi, safi_t safi) @@ -11019,7 +10872,6 @@ DEFUN (show_ip_bgp_ipv4_community_list_exact, return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_community_list, show_bgp_community_list_cmd, "show bgp community-list (<1-500>|WORD)", @@ -11119,7 +10971,6 @@ DEFUN (show_ipv6_mbgp_community_list_exact, { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); } -#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_community_list, show_bgp_ipv4_community_list_cmd, @@ -11185,7 +11036,6 @@ DEFUN (show_bgp_ipv4_safi_community_list_exact, return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_community_list, show_bgp_ipv6_safi_community_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD)", @@ -11232,7 +11082,6 @@ DEFUN (show_bgp_ipv6_safi_community_list_exact, } return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi); } -#endif /* HAVE_IPV6 */ static int bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, @@ -11359,7 +11208,6 @@ ALIAS (show_ip_bgp_flap_prefix, "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_longer, show_bgp_prefix_longer_cmd, "show bgp X:X::X:X/M longer-prefixes", @@ -11399,7 +11247,6 @@ DEFUN (show_ipv6_mbgp_prefix_longer, return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_prefix_longer); } -#endif /* HAVE_IPV6 */ DEFUN (show_bgp_ipv4_prefix_longer, show_bgp_ipv4_prefix_longer_cmd, @@ -11453,7 +11300,6 @@ ALIAS (show_bgp_ipv4_safi_flap_prefix_longer, "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_flap_prefix_longer, show_bgp_ipv6_safi_flap_prefix_longer_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M longer-prefixes", @@ -11491,7 +11337,6 @@ ALIAS (show_bgp_ipv6_safi_flap_prefix_longer, "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") -#endif DEFUN (show_bgp_ipv4_safi_prefix_longer, show_bgp_ipv4_safi_prefix_longer_cmd, @@ -11517,7 +11362,6 @@ DEFUN (show_bgp_ipv4_safi_prefix_longer, bgp_show_type_prefix_longer); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_prefix_longer, show_bgp_ipv6_safi_prefix_longer_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) X:X::X:X/M longer-prefixes", @@ -11541,7 +11385,6 @@ DEFUN (show_bgp_ipv6_safi_prefix_longer, return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, bgp_show_type_prefix_longer); } -#endif DEFUN (show_bgp_ipv4_safi_flap_address, show_bgp_ipv4_safi_flap_address_cmd, @@ -11578,7 +11421,7 @@ ALIAS (show_bgp_ipv4_safi_flap_address, "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_flap_address, show_bgp_ipv6_flap_address_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", @@ -11614,7 +11457,6 @@ ALIAS (show_bgp_ipv6_flap_address, "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") -#endif DEFUN (show_bgp_ipv4_safi_flap_prefix, show_bgp_ipv4_safi_flap_prefix_cmd, @@ -11653,7 +11495,6 @@ ALIAS (show_bgp_ipv4_safi_flap_prefix, "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_safi_flap_prefix, show_bgp_ipv6_safi_flap_prefix_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M", @@ -11704,8 +11545,6 @@ DEFUN (show_bgp_ipv6_prefix_longer, bgp_show_type_prefix_longer); } -#endif /* HAVE_IPV6 */ - static struct peer * peer_lookup_in_view (struct vty *vty, const char *view_name, const char *ip_str) @@ -12375,7 +12214,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts, return bgp_peer_counts (vty, peer, AFI_IP, safi); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts, show_bgp_ipv6_safi_neighbor_prefix_counts_cmd, "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", @@ -12405,7 +12244,6 @@ DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts, return bgp_peer_counts (vty, peer, AFI_IP6, safi); } -#endif DEFUN (show_ip_bgp_encap_neighbor_prefix_counts, show_ip_bgp_encap_neighbor_prefix_counts_cmd, @@ -12604,7 +12442,6 @@ DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); } -#ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_advertised_route, show_bgp_view_neighbor_advertised_route_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", @@ -12708,7 +12545,6 @@ DEFUN (ipv6_mbgp_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0); } -#endif /* HAVE_IPV6 */ DEFUN (show_ip_bgp_view_neighbor_received_routes, show_ip_bgp_view_neighbor_received_routes_cmd, @@ -12931,7 +12767,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route, return peer_adj_routes (vty, peer, AFI_IP, safi, 0); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route, show_bgp_ipv6_safi_neighbor_advertised_route_cmd, "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", @@ -13011,8 +12847,6 @@ DEFUN (show_bgp_view_ipv6_neighbor_received_routes, return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); } -#endif /* HAVE_IPV6 */ - DEFUN (show_bgp_ipv4_safi_neighbor_received_routes, show_bgp_ipv4_safi_neighbor_received_routes_cmd, @@ -13043,7 +12877,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_received_routes, return peer_adj_routes (vty, peer, AFI_IP, safi, 1); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_received_routes, show_bgp_ipv6_safi_neighbor_received_routes_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", @@ -13073,7 +12907,6 @@ DEFUN (show_bgp_ipv6_safi_neighbor_received_routes, return peer_adj_routes (vty, peer, AFI_IP6, safi, 1); } -#endif DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, @@ -13260,7 +13093,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_received_prefix_filter, return CMD_SUCCESS; } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_received_prefix_filter, show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", @@ -13397,7 +13230,6 @@ DEFUN (show_bgp_view_ipv6_neighbor_received_prefix_filter, return CMD_SUCCESS; } -#endif /* HAVE_IPV6 */ static int bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, @@ -13714,7 +13546,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_flap, return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_flap_neighbor); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_flap, show_bgp_ipv6_safi_neighbor_flap_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", @@ -13744,7 +13576,6 @@ DEFUN (show_bgp_ipv6_safi_neighbor_flap, return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_flap_neighbor); } -#endif DEFUN (show_bgp_ipv4_safi_neighbor_damp, show_bgp_ipv4_safi_neighbor_damp_cmd, @@ -13775,7 +13606,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_damp, return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_damp_neighbor); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_damp, show_bgp_ipv6_safi_neighbor_damp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", @@ -13805,7 +13636,6 @@ DEFUN (show_bgp_ipv6_safi_neighbor_damp, return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_damp_neighbor); } -#endif DEFUN (show_bgp_ipv4_safi_neighbor_routes, show_bgp_ipv4_safi_neighbor_routes_cmd, @@ -13835,7 +13665,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_routes, return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_neighbor); } -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_neighbor_routes, show_bgp_ipv6_safi_neighbor_routes_cmd, "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", @@ -13864,7 +13694,6 @@ DEFUN (show_bgp_ipv6_safi_neighbor_routes, return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_neighbor); } -#endif DEFUN (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_view_ipv4_safi_rsclient_route_cmd, @@ -14102,7 +13931,6 @@ ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") -#ifdef HAVE_IPV6 DEFUN (show_bgp_view_ipv6_neighbor_routes, show_bgp_view_ipv6_neighbor_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", @@ -14359,8 +14187,6 @@ ALIAS (show_bgp_view_neighbor_damp, "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") -#endif /* HAVE_IPV6 */ - DEFUN (show_bgp_view_rsclient, show_bgp_view_rsclient_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", @@ -14502,7 +14328,6 @@ ALIAS (show_bgp_view_ipv4_rsclient, "Information about Route Server Client\n" NEIGHBOR_ADDR_STR2) -#ifdef HAVE_IPV6 ALIAS (show_bgp_view_ipv6_rsclient, show_bgp_ipv6_rsclient_cmd, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X)", @@ -15021,8 +14846,6 @@ ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix, NEIGHBOR_ADDR_STR "IP prefix /, e.g., 3ffe::/16\n") -#endif /* HAVE_IPV6 */ - struct bgp_table *bgp_distance_table; struct bgp_distance @@ -15460,7 +15283,7 @@ ALIAS (show_bgp_ipv4_safi_dampened_paths, "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_dampened_paths, show_bgp_ipv6_safi_dampened_paths_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampened-paths", @@ -15494,7 +15317,6 @@ ALIAS (show_bgp_ipv6_safi_dampened_paths, "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") -#endif DEFUN (show_bgp_ipv4_safi_flap_statistics, show_bgp_ipv4_safi_flap_statistics_cmd, @@ -15529,7 +15351,7 @@ ALIAS (show_bgp_ipv4_safi_flap_statistics, "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") -#ifdef HAVE_IPV6 + DEFUN (show_bgp_ipv6_safi_flap_statistics, show_bgp_ipv6_safi_flap_statistics_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics", @@ -15563,7 +15385,6 @@ ALIAS (show_bgp_ipv6_safi_flap_statistics, "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") -#endif /* Display specified route of BGP table. */ static int @@ -16300,7 +16121,6 @@ bgp_route_init (void) /* prefix count */ install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_prefix_counts_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_prefix_counts_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd); /* New config IPv6 BGP commands. */ @@ -16455,7 +16275,6 @@ bgp_route_init (void) /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); -#endif /* HAVE_IPV6 */ install_element (BGP_NODE, &bgp_distance_cmd); install_element (BGP_NODE, &no_bgp_distance_cmd); @@ -16519,10 +16338,8 @@ bgp_route_init (void) install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); -#ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd); -#endif /* old style commands */ install_element (VIEW_NODE, &show_ip_bgp_cmd); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index a6d5a0e1c..39fa08c86 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1710,7 +1710,6 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = route_set_aggregator_as_free, }; -#ifdef HAVE_IPV6 /* `match ipv6 address IP_ACCESS_LIST' */ static route_map_result_t @@ -2071,8 +2070,6 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = route_set_ipv6_nexthop_peer_free }; -#endif /* HAVE_IPV6 */ - /* `set vpnv4 nexthop A.B.C.D' */ static route_map_result_t @@ -3568,8 +3565,6 @@ ALIAS (no_set_aggregator_as, "AS number\n" "IP address of aggregator\n") - -#ifdef HAVE_IPV6 DEFUN (match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD", @@ -3737,7 +3732,6 @@ ALIAS (no_set_ipv6_nexthop_local, "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") -#endif /* HAVE_IPV6 */ DEFUN (set_vpnv4_nexthop, set_vpnv4_nexthop_cmd, @@ -3998,7 +3992,6 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_originator_id_cmd); install_element (RMAP_NODE, &no_set_originator_id_val_cmd); -#ifdef HAVE_IPV6 route_map_install_match (&route_match_ipv6_address_cmd); route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); @@ -4020,7 +4013,6 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd); -#endif /* HAVE_IPV6 */ /* AS-Pathlimit: functionality removed, commands kept for * compatibility. diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 209a18c92..bee129632 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -265,8 +265,6 @@ bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) addr)); } -#ifdef HAVE_IPV6 - /* * bgp_node_match_ipv6 */ @@ -277,8 +275,6 @@ bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) addr)); } -#endif /* HAVE_IPV6 */ - static inline unsigned long bgp_table_count (const struct bgp_table *const table) { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e271210d6..987ff298c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -107,12 +107,10 @@ bgp_parse_afi(const char *str, afi_t *afi) *afi = AFI_IP; return 0; } -#ifdef HAVE_IPV6 if (!strcmp(str, "ipv6")) { *afi = AFI_IP6; return 0; } -#endif /* HAVE_IPV6 */ return -1; } @@ -145,10 +143,8 @@ peer_address_self_check (union sockunion *su) if (su->sa.sa_family == AF_INET) ifp = if_lookup_by_ipv4_exact (&su->sin.sin_addr); -#ifdef HAVE_IPV6 else if (su->sa.sa_family == AF_INET6) ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr); -#endif /* HAVE IPV6 */ if (ifp) return 1; @@ -6935,7 +6931,6 @@ ALIAS (clear_bgp_as_soft, "Soft reconfig\n") /* RS-client soft reconfiguration. */ -#ifdef HAVE_IPV6 DEFUN (clear_bgp_all_rsclient, clear_bgp_all_rsclient_cmd, "clear bgp * rsclient", @@ -6981,7 +6976,6 @@ ALIAS (clear_bgp_all_rsclient, "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") -#endif /* HAVE_IPV6 */ DEFUN (clear_ip_bgp_all_rsclient, clear_ip_bgp_all_rsclient_cmd, @@ -7011,7 +7005,6 @@ ALIAS (clear_ip_bgp_all_rsclient, "Clear all peers\n" "Soft reconfig for rsclient RIB\n") -#ifdef HAVE_IPV6 DEFUN (clear_bgp_peer_rsclient, clear_bgp_peer_rsclient_cmd, "clear bgp (A.B.C.D|X:X::X:X) rsclient", @@ -7061,7 +7054,6 @@ ALIAS (clear_bgp_peer_rsclient, "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") -#endif /* HAVE_IPV6 */ DEFUN (clear_ip_bgp_peer_rsclient, clear_ip_bgp_peer_rsclient_cmd, @@ -7537,8 +7529,6 @@ DEFUN (show_bgp_ipv4_vpn_summary, return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); } -#ifdef HAVE_IPV6 - /* `show ip bgp summary' commands. */ DEFUN (show_bgp_ipv6_vpn_summary, show_bgp_ipv6_vpn_summary_cmd, @@ -7551,7 +7541,6 @@ DEFUN (show_bgp_ipv6_vpn_summary, { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); } -#endif DEFUN (show_bgp_ipv4_encap_summary, show_bgp_ipv4_encap_summary_cmd, @@ -7565,8 +7554,6 @@ DEFUN (show_bgp_ipv4_encap_summary, return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); } -#ifdef HAVE_IPV6 - DEFUN (show_bgp_ipv6_encap_summary, show_bgp_ipv6_encap_summary_cmd, "show bgp ipv6 encap summary", @@ -7579,10 +7566,6 @@ DEFUN (show_bgp_ipv6_encap_summary, return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); } -#endif - - - DEFUN (show_bgp_instance_summary, show_bgp_instance_summary_cmd, "show bgp view WORD summary", @@ -7605,7 +7588,6 @@ DEFUN (show_bgp_instance_summary, vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); -#ifdef HAVE_IPV6 vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); @@ -7618,7 +7600,7 @@ DEFUN (show_bgp_instance_summary, vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); -#endif + return CMD_SUCCESS; } @@ -7650,8 +7632,6 @@ DEFUN (show_bgp_instance_ipv4_summary, return CMD_SUCCESS; } - -#ifdef HAVE_IPV6 DEFUN (show_bgp_instance_ipv6_summary, show_bgp_instance_ipv6_summary_cmd, "show bgp view WORD ipv6 summary", @@ -7737,7 +7717,6 @@ DEFUN (show_ipv6_mbgp_summary, { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); } -#endif /* HAVE_IPV6 */ /* variations of show bgp [...] summary */ @@ -7762,7 +7741,6 @@ DEFUN (show_bgp_summary, vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); -#ifdef HAVE_IPV6 vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); @@ -7775,7 +7753,7 @@ DEFUN (show_bgp_summary, vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); -#endif + return CMD_SUCCESS; } @@ -7789,17 +7767,11 @@ ALIAS (show_bgp_summary, DEFUN (show_bgp_summary_1w, show_bgp_summary_1w_cmd, -#ifdef HAVE_IPV6 "show bgp (ipv4|ipv6|unicast|multicast|vpn|encap) summary", -#else - "show bgp (ipv4|unicast|multicast|vpn|encap) summary", -#endif SHOW_STR BGP_STR IP_STR -#ifdef HAVE_IPV6 IP6_STR -#endif "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" @@ -7821,7 +7793,7 @@ DEFUN (show_bgp_summary_1w, bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); return CMD_SUCCESS; } -#ifdef HAVE_IPV6 + if (strcmp (argv[0], "ipv6") == 0) { vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); @@ -7837,53 +7809,45 @@ DEFUN (show_bgp_summary_1w, bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } -#endif + if (strcmp (argv[0], "unicast") == 0) { vty_out(vty, "IPv4 Unicast Summary:%s", VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); -#ifdef HAVE_IPV6 vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 Unicast Summary:%s", VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); -#endif return CMD_SUCCESS; } if (strcmp (argv[0], "multicast") == 0) { vty_out(vty, "IPv4 Multicast Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); -#ifdef HAVE_IPV6 vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 Multicast Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); -#endif return CMD_SUCCESS; } if (strcmp (argv[0], "vpn") == 0) { vty_out(vty, "IPv4 VPN Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); -#ifdef HAVE_IPV6 vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 VPN Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); -#endif return CMD_SUCCESS; } if (strcmp (argv[0], "encap") == 0) { vty_out(vty, "IPv4 Encap Summary:%s", VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); -#ifdef HAVE_IPV6 vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 Encap Summary:%s", VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); -#endif return CMD_SUCCESS; } vty_out(vty, "Unknown keyword: %s%s", argv[0], VTY_NEWLINE); @@ -8248,7 +8212,6 @@ bgp_show_peer (struct vty *vty, struct peer *p) || p->afc_recv[AFI_IP][SAFI_UNICAST] || p->afc_adv[AFI_IP][SAFI_MULTICAST] || p->afc_recv[AFI_IP][SAFI_MULTICAST] -#ifdef HAVE_IPV6 || p->afc_adv[AFI_IP6][SAFI_UNICAST] || p->afc_recv[AFI_IP6][SAFI_UNICAST] || p->afc_adv[AFI_IP6][SAFI_MULTICAST] @@ -8257,7 +8220,6 @@ bgp_show_peer (struct vty *vty, struct peer *p) || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN] || p->afc_adv[AFI_IP6][SAFI_ENCAP] || p->afc_recv[AFI_IP6][SAFI_ENCAP] -#endif /* HAVE_IPV6 */ || p->afc_adv[AFI_IP][SAFI_ENCAP] || p->afc_recv[AFI_IP][SAFI_ENCAP] || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] @@ -8513,7 +8475,6 @@ bgp_show_peer (struct vty *vty, struct peer *p) vty_out (vty, "Nexthop: %s%s", inet_ntop (AF_INET, &p->nexthop.v4, buf1, BUFSIZ), VTY_NEWLINE); -#ifdef HAVE_IPV6 vty_out (vty, "Nexthop global: %s%s", inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ), VTY_NEWLINE); @@ -8523,7 +8484,6 @@ bgp_show_peer (struct vty *vty, struct peer *p) vty_out (vty, "BGP connection: %s%s", p->shared_network ? "shared network" : "non shared network", VTY_NEWLINE); -#endif /* HAVE_IPV6 */ } /* TCP metrics. */ @@ -8815,11 +8775,7 @@ DEFUN (show_bgp_neighbors, DEFUN (show_bgp_neighbors_peer, show_bgp_neighbors_peer_cmd, -#ifdef HAVE_IPV6 "show bgp neighbors (A.B.C.D|X:X::X:X)", -#else - "show bgp neighbors (A.B.C.D)", -#endif /* HAVE_IPV6 */ SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" @@ -8843,11 +8799,7 @@ DEFUN (show_bgp_instance_neighbors, DEFUN (show_bgp_instance_neighbors_peer, show_bgp_instance_neighbors_peer_cmd, -#ifdef HAVE_IPV6 "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", -#else - "show bgp view WORD neighbors (A.B.C.D)", -#endif SHOW_STR BGP_STR "BGP view\n" @@ -9189,7 +9141,6 @@ DEFUN (show_bgp_rsclient_summary, vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); -#ifdef HAVE_IPV6 vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); @@ -9202,7 +9153,7 @@ DEFUN (show_bgp_rsclient_summary, vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); -#endif + return CMD_SUCCESS; } @@ -9229,7 +9180,6 @@ DEFUN (show_bgp_instance_rsclient_summary, vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); -#ifdef HAVE_IPV6 vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); @@ -9242,11 +9192,10 @@ DEFUN (show_bgp_instance_rsclient_summary, vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); -#endif + return CMD_SUCCESS; } -#ifdef HAVE_IPV6 DEFUN (show_bgp_ipv6_rsclient_summary, show_bgp_ipv6_rsclient_summary_cmd, "show bgp ipv6 rsclient summary", @@ -9334,8 +9283,6 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") -#endif /* HAVE IPV6 */ - /* Redistribute VTY commands. */ DEFUN (bgp_redistribute_ipv4, @@ -9550,7 +9497,6 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric, "Route map reference\n" "Pointer to route-map entries\n") -#ifdef HAVE_IPV6 DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD, @@ -9763,7 +9709,6 @@ ALIAS (no_bgp_redistribute_ipv6_rmap_metric, "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") -#endif /* HAVE_IPV6 */ int bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, @@ -10801,10 +10746,8 @@ bgp_vty_init (void) /* address-family commands. */ install_element (BGP_NODE, &address_family_ipv4_cmd); install_element (BGP_NODE, &address_family_ipv4_safi_cmd); -#ifdef HAVE_IPV6 install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_safi_cmd); -#endif /* HAVE_IPV6 */ install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); @@ -10813,9 +10756,7 @@ bgp_vty_init (void) install_element (BGP_NODE, &address_family_encap_cmd); install_element (BGP_NODE, &address_family_encapv4_cmd); -#ifdef HAVE_IPV6 install_element (BGP_NODE, &address_family_encapv6_cmd); -#endif /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); @@ -10834,7 +10775,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd); @@ -10846,7 +10786,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd); install_element (ENABLE_NODE, &clear_bgp_as_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd); -#endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft in" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd); @@ -10895,7 +10834,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_in_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_all_in_cmd); @@ -10927,7 +10865,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd); -#endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft out" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd); @@ -10964,7 +10901,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_out_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_all_out_cmd); @@ -10986,7 +10922,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd); -#endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd); @@ -11007,7 +10942,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd); @@ -11019,14 +10953,12 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd); -#endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor rsclient" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd); @@ -11035,7 +10967,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd); -#endif /* HAVE_IPV6 */ /* "show ip bgp summary" commands. */ install_element (VIEW_NODE, &show_bgp_summary_cmd); @@ -11052,51 +10983,39 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_ipv4_vpn_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_summary_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_ipv6_vpn_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_summary_cmd); -#endif install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); -#endif /* HAVE_IPV6 */ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_summary_cmd); -#ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd); -#endif install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); -#ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); -#endif /* HAVE_IPV6 */ install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_encap_summary_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_encap_summary_cmd); -#endif install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); -#ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); -#endif /* HAVE_IPV6 */ /* "show ip bgp neighbors" commands. */ install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); @@ -11110,15 +11029,12 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_peer_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); -#endif /* HAVE_IPV6 */ - /* "show ip bgp rsclient" commands. */ install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); @@ -11133,7 +11049,6 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); -#ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); @@ -11146,7 +11061,6 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); -#endif /* HAVE_IPV6 */ /* "show ip bgp paths" commands. */ install_element (VIEW_NODE, &show_bgp_ipv4_paths_cmd); @@ -11171,7 +11085,6 @@ bgp_vty_init (void) install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd); -#ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd); @@ -11182,7 +11095,6 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd); -#endif /* HAVE_IPV6 */ /* ttl_security commands */ install_element (BGP_NODE, &neighbor_ttl_security_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1be4440a4..af312e3ca 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -305,7 +305,6 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, return 0; } -#ifdef HAVE_IPV6 /* Zebra route add and delete treatment. */ static int zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, @@ -387,7 +386,6 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, return 0; } -#endif /* HAVE_IPV6 */ struct interface * if_lookup_by_ipv4 (struct in_addr *addr) @@ -440,7 +438,6 @@ if_lookup_by_ipv4_exact (struct in_addr *addr) return NULL; } -#ifdef HAVE_IPV6 struct interface * if_lookup_by_ipv6 (struct in6_addr *addr) { @@ -533,7 +530,6 @@ if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) } return 0; } -#endif /* HAVE_IPV6 */ static int if_get_ipv4_address (struct interface *ifp, struct in_addr *addr) @@ -573,7 +569,6 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, nexthop->v4 = local->sin.sin_addr; ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); } -#ifdef HAVE_IPV6 if (local->sa.sa_family == AF_INET6) { if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) @@ -584,7 +579,6 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, else ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); } -#endif /* HAVE_IPV6 */ if (!ifp) return -1; @@ -594,7 +588,6 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, /* IPv4 connection. */ if (local->sa.sa_family == AF_INET) { -#ifdef HAVE_IPV6 /* IPv6 nexthop*/ ret = if_get_ipv6_global (ifp, &nexthop->v6_global); @@ -603,10 +596,8 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, if_get_ipv6_local (ifp, &nexthop->v6_global); else if_get_ipv6_local (ifp, &nexthop->v6_local); -#endif /* HAVE_IPV6 */ } -#ifdef HAVE_IPV6 /* IPv6 connection. */ if (local->sa.sa_family == AF_INET6) { @@ -663,7 +654,6 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0); } #endif /* KAME */ -#endif /* HAVE_IPV6 */ return ret; } @@ -763,7 +753,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, (struct prefix_ipv4 *) p, &api); } -#ifdef HAVE_IPV6 + /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { @@ -833,7 +823,6 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, (struct prefix_ipv6 *) p, &api); } -#endif /* HAVE_IPV6 */ } void @@ -888,7 +877,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); } -#ifdef HAVE_IPV6 + /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { @@ -916,7 +905,6 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, (struct prefix_ipv6 *) p, &api); } -#endif /* HAVE_IPV6 */ } /* Other routes redistribution into BGP. */ @@ -1074,10 +1062,8 @@ bgp_zebra_init (struct thread_master *master) zclient->ipv4_route_delete = zebra_read_ipv4; zclient->interface_up = bgp_interface_up; zclient->interface_down = bgp_interface_down; -#ifdef HAVE_IPV6 zclient->ipv6_route_add = zebra_read_ipv6; zclient->ipv6_route_delete = zebra_read_ipv6; -#endif /* HAVE_IPV6 */ bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index ff9b375b0..e69a0bc57 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -44,9 +44,7 @@ extern int bgp_redistribute_metric_unset (struct bgp *, afi_t, int); extern struct interface *if_lookup_by_ipv4 (struct in_addr *); extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *); -#ifdef HAVE_IPV6 extern struct interface *if_lookup_by_ipv6 (struct in6_addr *); extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); -#endif /* HAVE_IPV6 */ #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index eb6389506..455034f56 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -205,10 +205,8 @@ struct bgp_nexthop { struct interface *ifp; struct in_addr v4; -#ifdef HAVE_IPV6 struct in6_addr v6_global; struct in6_addr v6_local; -#endif /* HAVE_IPV6 */ }; /* BGP router distinguisher value. */ From b0d02889624eaafa0984873dcd78c086418bdf13 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Jan 2016 07:37:14 -0500 Subject: [PATCH 0956/1342] lib, bgpd: Remove 'struct fifo' from lib/zebra.h The 'struct fifo' and it's accompanying #defines do not belong in lib/zebra.h. Move them into their own header. Signed-off-by: Donald Sharp --- bgpd/bgp_advertise.h | 2 ++ lib/Makefile.am | 2 +- lib/fifo.h | 62 ++++++++++++++++++++++++++++++++++++++++++++ lib/zebra.h | 39 ---------------------------- 4 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 lib/fifo.h diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index adbbe3074..51ba62679 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_ADVERTISE_H #define _QUAGGA_BGP_ADVERTISE_H +#include + /* BGP advertise attribute. */ struct bgp_advertise_attr { diff --git a/lib/Makefile.am b/lib/Makefile.am index ac51fc625..57e859d6d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -28,7 +28,7 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h libospf.h vrf.h + workqueue.h route_types.h libospf.h vrf.h fifo.h noinst_HEADERS = \ plist_int.h diff --git a/lib/fifo.h b/lib/fifo.h new file mode 100644 index 000000000..6be75b761 --- /dev/null +++ b/lib/fifo.h @@ -0,0 +1,62 @@ +/* FIFO common header. + Copyright (C) 2015 Kunihiro Ishiguro + +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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ +#ifndef __LIB_FIFO_H__ +#define __LIB_FIFO_H__ + +/* FIFO -- first in first out structure and macros. */ +struct fifo +{ + struct fifo *next; + struct fifo *prev; +}; + +#define FIFO_INIT(F) \ + do { \ + struct fifo *Xfifo = (struct fifo *)(F); \ + Xfifo->next = Xfifo->prev = Xfifo; \ + } while (0) + +#define FIFO_ADD(F,N) \ + do { \ + struct fifo *Xfifo = (struct fifo *)(F); \ + struct fifo *Xnode = (struct fifo *)(N); \ + Xnode->next = Xfifo; \ + Xnode->prev = Xfifo->prev; \ + Xfifo->prev = Xfifo->prev->next = Xnode; \ + } while (0) + +#define FIFO_DEL(N) \ + do { \ + struct fifo *Xnode = (struct fifo *)(N); \ + Xnode->prev->next = Xnode->next; \ + Xnode->next->prev = Xnode->prev; \ + } while (0) + +#define FIFO_HEAD(F) \ + ((((struct fifo *)(F))->next == (struct fifo *)(F)) \ + ? NULL : (F)->next) + +#define FIFO_EMPTY(F) \ + (((struct fifo *)(F))->next == (struct fifo *)(F)) + +#define FIFO_TOP(F) \ + (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) + +#endif /* __LIB_FIFO_H__ */ diff --git a/lib/zebra.h b/lib/zebra.h index 644729b74..1754b34da 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -518,43 +518,4 @@ typedef u_int16_t zebra_command_t; /* VRF ID type. */ typedef u_int16_t vrf_id_t; -/* FIFO -- first in first out structure and macros. */ -struct fifo -{ - struct fifo *next; - struct fifo *prev; -}; - -#define FIFO_INIT(F) \ - do { \ - struct fifo *Xfifo = (struct fifo *)(F); \ - Xfifo->next = Xfifo->prev = Xfifo; \ - } while (0) - -#define FIFO_ADD(F,N) \ - do { \ - struct fifo *Xfifo = (struct fifo *)(F); \ - struct fifo *Xnode = (struct fifo *)(N); \ - Xnode->next = Xfifo; \ - Xnode->prev = Xfifo->prev; \ - Xfifo->prev = Xfifo->prev->next = Xnode; \ - } while (0) - -#define FIFO_DEL(N) \ - do { \ - struct fifo *Xnode = (struct fifo *)(N); \ - Xnode->prev->next = Xnode->next; \ - Xnode->next->prev = Xnode->prev; \ - } while (0) - -#define FIFO_HEAD(F) \ - ((((struct fifo *)(F))->next == (struct fifo *)(F)) \ - ? NULL : (F)->next) - -#define FIFO_EMPTY(F) \ - (((struct fifo *)(F))->next == (struct fifo *)(F)) - -#define FIFO_TOP(F) \ - (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) - #endif /* _ZEBRA_H */ From 0abf6796c3d8ae8f5ea8624668424bc1554de25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 15 Jan 2016 17:36:29 +0200 Subject: [PATCH 0957/1342] zebra: atomic FIB updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the kernel API so that route changes are atomically updated using change/replaces messages instead of first sending a withdraw followed with update. Same for zclient updates, changes are sent as single ADD instead of DELETE + ADD. Signed-off-by: Timo Teräs --- zebra/kernel_null.c | 14 +- zebra/kernel_socket.c | 8 +- zebra/rt.h | 9 +- zebra/rt_netlink.c | 40 +++-- zebra/rt_socket.c | 74 ++++------ zebra/zebra_rib.c | 333 +++++++++++++++--------------------------- 6 files changed, 171 insertions(+), 307 deletions(-) diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 58d2c3ae7..1a16a75a4 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -30,19 +30,7 @@ #include "zebra/connected.h" #include "zebra/rib.h" -int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; } -#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA -#pragma weak kernel_delete_ipv4 = kernel_add_ipv4 -#else -int kernel_delete_ipv4 (struct prefix *a, struct rib *b) { return 0; } -#endif - -int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } -#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA -#pragma weak kernel_delete_ipv6 = kernel_add_ipv6 -#else -int kernel_delete_ipv6 (struct prefix *a, struct rib *b) { return 0; } -#endif +int kernel_route_rib (struct prefix *a, struct rib *old, struct rib *new) { return 0; } int kernel_add_route (struct prefix_ipv4 *a, struct in_addr *b, int c, int d) { return 0; } diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 790b1420a..ba03498cc 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -861,7 +861,7 @@ rtm_read (struct rt_msghdr *rtm) return; #endif - if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) + if ((rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) && ! (flags & RTF_UP)) return; /* This is connected route. */ @@ -1072,14 +1072,14 @@ rtm_write (int message, ifp = if_lookup_by_index (index); - if (gate && message == RTM_ADD) + if (gate && (message == RTM_ADD || message == RTM_CHANGE)) msg.rtm.rtm_flags |= RTF_GATEWAY; /* When RTF_CLONING is unavailable on BSD, should we set some * other flag instead? */ #ifdef RTF_CLONING - if (! gate && message == RTM_ADD && ifp && + if (! gate && (message == RTM_ADD || message == RTM_CHANGE) && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; #endif /* RTF_CLONING */ @@ -1104,7 +1104,7 @@ rtm_write (int message, if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; - else if (message == RTM_ADD) + else if (message == RTM_ADD || message == RTM_CHANGE) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ diff --git a/zebra/rt.h b/zebra/rt.h index 7faa127b8..8c1c476d6 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -27,16 +27,9 @@ #include "if.h" #include "zebra/rib.h" -extern int kernel_add_ipv4 (struct prefix *, struct rib *); -extern int kernel_delete_ipv4 (struct prefix *, struct rib *); +extern int kernel_route_rib (struct prefix *, struct rib *, struct rib *); extern int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int); extern int kernel_address_add_ipv4 (struct interface *, struct connected *); extern int kernel_address_delete_ipv4 (struct interface *, struct connected *); -#ifdef HAVE_IPV6 -extern int kernel_add_ipv6 (struct prefix *, struct rib *); -extern int kernel_delete_ipv6 (struct prefix *, struct rib *); - -#endif /* HAVE_IPV6 */ - #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 614f8099a..4625ceabb 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1607,8 +1607,7 @@ _netlink_route_debug( /* Routing table change via netlink interface. */ static int -netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, - int family) +netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) { int bytelen; struct sockaddr_nl snl; @@ -1616,6 +1615,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, int recursing; int nexthop_num; int discard; + int family = PREFIX_FAMILY(p); const char *routedesc; struct @@ -1632,7 +1632,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = rib->table; @@ -1803,30 +1803,26 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, } int -kernel_add_ipv4 (struct prefix *p, struct rib *rib) +kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { - return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET); -} + int ret; -int -kernel_delete_ipv4 (struct prefix *p, struct rib *rib) -{ - return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET); -} + if (!old && new) + return netlink_route_multipath (RTM_NEWROUTE, p, new); + if (old && !new) + return netlink_route_multipath (RTM_DELROUTE, p, old); -#ifdef HAVE_IPV6 -int -kernel_add_ipv6 (struct prefix *p, struct rib *rib) -{ - return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6); -} + /* Replace, can be done atomically if metric does not change; + * netlink uses [prefix, tos, priority] to identify prefix */ + if (old->metric == new->metric) + return netlink_route_multipath (RTM_NEWROUTE, p, new); -int -kernel_delete_ipv6 (struct prefix *p, struct rib *rib) -{ - return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); + /* Add + delete so the prefix does not disappear temporarily */ + ret = netlink_route_multipath (RTM_NEWROUTE, p, new); + if (netlink_route_multipath (RTM_DELROUTE, p, old) < 0) + ret = -1; + return ret; } -#endif /* HAVE_IPV6 */ /* Interface address modification. */ static int diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index a7ef45710..4d0a7db58 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -216,34 +216,6 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) return 0; /*XXX*/ } -int -kernel_add_ipv4 (struct prefix *p, struct rib *rib) -{ - int route; - - if (zserv_privs.change(ZPRIVS_RAISE)) - zlog (NULL, LOG_ERR, "Can't raise privileges"); - route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); - if (zserv_privs.change(ZPRIVS_LOWER)) - zlog (NULL, LOG_ERR, "Can't lower privileges"); - - return route; -} - -int -kernel_delete_ipv4 (struct prefix *p, struct rib *rib) -{ - int route; - - if (zserv_privs.change(ZPRIVS_RAISE)) - zlog (NULL, LOG_ERR, "Can't raise privileges"); - route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); - if (zserv_privs.change(ZPRIVS_LOWER)) - zlog (NULL, LOG_ERR, "Can't lower privileges"); - - return route; -} - #ifdef HAVE_IPV6 #ifdef SIN6_LEN @@ -273,8 +245,7 @@ sin6_masklen (struct in6_addr mask) /* Interface between zebra message and rtm message. */ static int -kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, - int family) +kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib, int family) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; @@ -369,7 +340,7 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, #if 0 if (error) { - zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.", + zlog_info ("kernel_rtm_ipv6(): nexthop %d add error=%d.", nexthop_num, error); } #else @@ -383,38 +354,45 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop."); + zlog_debug ("kernel_rtm_ipv6(): No useful nexthop."); return 0; } return 0; /*XXX*/ } +#endif + int -kernel_add_ipv6 (struct prefix *p, struct rib *rib) +kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { - int route; - - if (zserv_privs.change(ZPRIVS_RAISE)) - zlog (NULL, LOG_ERR, "Can't raise privileges"); - route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); - if (zserv_privs.change(ZPRIVS_LOWER)) - zlog (NULL, LOG_ERR, "Can't lower privileges"); + struct rib *rib; + int route = 0, cmd; - return route; -} + if (!old && new) + cmd = RTM_ADD; + else if (old && !new) + cmd = RTM_DELETE; + else + cmd = RTM_CHANGE; -int -kernel_delete_ipv6 (struct prefix *p, struct rib *rib) -{ - int route; + rib = new ? new : old; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); - route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); + + switch (PREFIX_FAMILY(p)) + { + case AF_INET: + route = kernel_rtm_ipv4 (cmd, p, rib, AF_INET); + break; + case AF_INET6: + route = kernel_rtm_ipv6 (cmd, p, rib, AF_INET6); + break; + } + if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } -#endif /* HAVE_IPV6 */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 38357ffde..7cce13fe4 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1103,49 +1103,8 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) -static void -rib_install_kernel (struct route_node *rn, struct rib *rib) -{ - int ret = 0; - struct nexthop *nexthop, *tnexthop; - rib_table_info_t *info = rn->table->info; - int recursing; - - if (info->safi != SAFI_UNICAST) - { - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - return; - } - - /* - * Make sure we update the FPM any time we send new information to - * the kernel. - */ - zfpm_trigger_update (rn, "installing in kernel"); - switch (PREFIX_FAMILY (&rn->p)) - { - case AF_INET: - ret = kernel_add_ipv4 (&rn->p, rib); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - ret = kernel_add_ipv6 (&rn->p, rib); - break; -#endif /* HAVE_IPV6 */ - } - - /* This condition is never met, if we are using rt_socket.c */ - if (ret < 0) - { - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } -} - -/* Uninstall the route from kernel. */ static int -rib_uninstall_kernel (struct route_node *rn, struct rib *rib) +rib_update_kernel (struct route_node *rn, struct rib *old, struct rib *new) { int ret = 0; struct nexthop *nexthop, *tnexthop; @@ -1154,31 +1113,31 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - return ret; + if (new) + for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + if (old) + for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return 0; } /* * Make sure we update the FPM any time we send new information to * the kernel. */ - zfpm_trigger_update (rn, "uninstalling from kernel"); + zfpm_trigger_update (rn, "updating in kernel"); - switch (PREFIX_FAMILY (&rn->p)) - { - case AF_INET: - ret = kernel_delete_ipv4 (&rn->p, rib); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - ret = kernel_delete_ipv6 (&rn->p, rib); - break; -#endif /* HAVE_IPV6 */ - } + ret = kernel_route_rib (&rn->p, old, new); - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + /* This condition is never met, if we are using rt_socket.c */ + if (ret < 0 && new) + for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + if (old) + for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); return ret; } @@ -1196,7 +1155,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib) redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) - rib_uninstall_kernel (rn, rib); + rib_update_kernel (rn, rib, NULL); UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); } } @@ -1261,15 +1220,56 @@ rib_gc_dest (struct route_node *rn) return 1; } +/* Check if 'alternate' RIB entry is better than 'current'. */ +static struct rib * +rib_choose_best (struct rib *current, struct rib *alternate) +{ + if (current == NULL) + return alternate; + + /* filter route selection in following order: + * - connected beats other types + * - lower distance beats higher + * - lower metric beats higher for equal distance + * - last, hence oldest, route wins tie break. + */ + + /* Connected routes. Pick the last connected + * route of the set of lowest metric connected routes. + */ + if (alternate->type == ZEBRA_ROUTE_CONNECT) + { + if (current->type != ZEBRA_ROUTE_CONNECT + || alternate->metric <= current->metric) + return alternate; + + return current; + } + + if (current->type == ZEBRA_ROUTE_CONNECT) + return current; + + /* higher distance loses */ + if (alternate->distance < current->distance) + return alternate; + if (current->distance < alternate->distance) + return current; + + /* metric tie-breaks equal distance */ + if (alternate->metric <= current->metric) + return alternate; + + return current; +} + /* Core function for processing routing information base. */ static void rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; - struct rib *fib = NULL; - struct rib *select = NULL; - struct rib *del = NULL; + struct rib *old_fib = NULL; + struct rib *new_fib = NULL; int installed = 0; struct nexthop *nexthop = NULL, *tnexthop; int recursing; @@ -1279,32 +1279,18 @@ rib_process (struct route_node *rn) info = rn->table->info; - RNODE_FOREACH_RIB_SAFE (rn, rib, next) + RNODE_FOREACH_RIB (rn, rib) { /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { - assert (fib == NULL); - fib = rib; + assert (old_fib == NULL); + old_fib = rib; } - - /* Unlock removed routes, so they'll be freed, bar the FIB entry, - * which we need to do do further work with below. - */ + + /* Skip deleted entries from selection */ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - { - if (rib != fib) - { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "rn %p, removing rib %p", - (void *)rn, (void *)rib); - rib_unlink (rn, rib); - } - else - del = rib; - - continue; - } + continue; /* Skip unreachable nexthop. */ if (! nexthop_active_update (rn, rib, 0)) @@ -1314,150 +1300,73 @@ rib_process (struct route_node *rn) if (rib->distance == DISTANCE_INFINITY) continue; - /* Newly selected rib, the common case. */ - if (!select) - { - select = rib; - continue; - } - - /* filter route selection in following order: - * - connected beats other types - * - lower distance beats higher - * - lower metric beats higher for equal distance - * - last, hence oldest, route wins tie break. - */ - - /* Connected routes. Pick the last connected - * route of the set of lowest metric connected routes. - */ - if (rib->type == ZEBRA_ROUTE_CONNECT) - { - if (select->type != ZEBRA_ROUTE_CONNECT - || rib->metric <= select->metric) - select = rib; - continue; - } - else if (select->type == ZEBRA_ROUTE_CONNECT) - continue; - - /* higher distance loses */ - if (rib->distance > select->distance) - continue; - - /* lower wins */ - if (rib->distance < select->distance) - { - select = rib; - continue; - } - - /* metric tie-breaks equal distance */ - if (rib->metric <= select->metric) - select = rib; + new_fib = rib_choose_best(new_fib, rib); } /* RNODE_FOREACH_RIB_SAFE */ /* After the cycle is finished, the following pointers will be set: - * select --- the winner RIB entry, if any was found, otherwise NULL - * fib --- the SELECTED RIB entry, if any, otherwise NULL - * del --- equal to fib, if fib is queued for deletion, NULL otherwise - * rib --- NULL + * old_fib --- RIB entry currently having SELECTED + * new_fib --- RIB entry that is newly SELECTED */ - /* Same RIB entry is selected. Update FIB and finish. */ - if (select && select == fib) - { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Updating existing route, select %p, fib %p", - (void *)select, (void *)fib); - if (CHECK_FLAG (select->status, RIB_ENTRY_CHANGED)) - { - if (info->safi == SAFI_UNICAST) - zfpm_trigger_update (rn, "updating existing route"); - - redistribute_delete (&rn->p, select); - if (! RIB_SYSTEM_ROUTE (select)) - rib_uninstall_kernel (rn, select); - - /* Set real nexthop. */ - nexthop_active_update (rn, select, 1); - - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select); - redistribute_add (&rn->p, select); - } - else if (! RIB_SYSTEM_ROUTE (select)) - { - /* Housekeeping code to deal with - race conditions in kernel with linux - netlink reporting interface up before IPv4 or IPv6 protocol - is ready to add routes. - This makes sure the routes are IN the kernel. - */ - - for (ALL_NEXTHOPS_RO(select->nexthop, nexthop, tnexthop, recursing)) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - { - installed = 1; - break; - } - if (! installed) - rib_install_kernel (rn, select); - } - goto end; - } + /* Set real nexthops. */ + if (new_fib) + nexthop_active_update (rn, new_fib, 1); - /* At this point we either haven't found the best RIB entry or it is - * different from what we currently intend to flag with SELECTED. In both - * cases, if a RIB block is present in FIB, it should be withdrawn. - */ - if (fib) + /* Update kernel if FIB entry has changed */ + if (old_fib != new_fib + || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED))) { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Removing existing route, fib %p", (void *)fib); + if (old_fib && old_fib != new_fib) + { + if (! new_fib) + redistribute_delete (&rn->p, old_fib); - if (info->safi == SAFI_UNICAST) - zfpm_trigger_update (rn, "removing existing route"); + if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib))) + rib_update_kernel (rn, old_fib, NULL); + UNSET_FLAG (old_fib->flags, ZEBRA_FLAG_SELECTED); + } - redistribute_delete (&rn->p, fib); - if (! RIB_SYSTEM_ROUTE (fib)) - rib_uninstall_kernel (rn, fib); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + if (new_fib) + { + /* Install new or replace existing FIB entry */ + SET_FLAG (new_fib->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, new_fib); - /* Set real nexthop. */ - nexthop_active_update (rn, fib, 1); - } + if (! RIB_SYSTEM_ROUTE (new_fib)) + rib_update_kernel (rn, old_fib, new_fib); + } - /* Regardless of some RIB entry being SELECTED or not before, now we can - * tell, that if a new winner exists, FIB is still not updated with this - * data, but ready to be. - */ - if (select) + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "updating existing route"); + } + else if (old_fib == new_fib && new_fib && ! RIB_SYSTEM_ROUTE (new_fib)) { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Adding route, select %p", (void *)select); - - if (info->safi == SAFI_UNICAST) - zfpm_trigger_update (rn, "new route selected"); - - /* Set real nexthop. */ - nexthop_active_update (rn, select, 1); - - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select); - SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); - redistribute_add (&rn->p, select); + /* Housekeeping code to deal with race conditions in kernel with + * linux netlink reporting interface up before IPv4 or IPv6 protocol + * is ready to add routes. This makes sure routes are IN the kernel. + */ + for (ALL_NEXTHOPS_RO(new_fib->nexthop, nexthop, tnexthop, recursing)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + installed = 1; + break; + } + if (! installed) + rib_update_kernel (rn, NULL, new_fib); } - /* FIB route was removed, should be deleted */ - if (del) + /* Remove all RIB entries queued for removal */ + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, "Deleting fib %p, rn %p", (void *)del, (void *)rn); - rib_unlink (rn, del); + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + { + if (IS_ZEBRA_DEBUG_RIB) + rnode_debug (rn, "rn %p, removing rib %p", + (void *)rn, (void *)rib); + rib_unlink (rn, rib); + } } -end: if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "rn %p dequeued", (void *)rn); @@ -3082,7 +2991,7 @@ rib_sweep_table (struct route_table *table) if (rib->type == ZEBRA_ROUTE_KERNEL && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) { - ret = rib_uninstall_kernel (rn, rib); + ret = rib_update_kernel (rn, rib, NULL); if (! ret) rib_delnode (rn, rib); } @@ -3165,7 +3074,7 @@ rib_close_table (struct route_table *table) zfpm_trigger_update (rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) - rib_uninstall_kernel (rn, rib); + rib_update_kernel (rn, rib, NULL); } } From 82a6635ca580ccd3c31551c960ec3de816b6c15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 15 Jan 2016 17:36:30 +0200 Subject: [PATCH 0958/1342] zebra: use link scope for interface routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In linux, 'scope' is a hint of distance of the IP. And this is evident from the fact that only lower scope can be used as recursive via lookup result. This changes all interface routes scope to link so kernel will allow regular routes to use it as via. Then we do not need to use the 'onlink' attribute. Signed-off-by: Timo Teräs --- zebra/rt_netlink.c | 6 +++++- zebra/zebra_rib.c | 21 ++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4625ceabb..6e22d63f8 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1638,7 +1638,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) req.r.rtm_table = rib->table; req.r.rtm_dst_len = p->prefixlen; req.r.rtm_protocol = RTPROT_ZEBRA; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_scope = RT_SCOPE_LINK; if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; @@ -1706,6 +1706,10 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) continue; + if (nexthop->type != NEXTHOP_TYPE_IFINDEX && + nexthop->type != NEXTHOP_TYPE_IFNAME) + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + nexthop_num++; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7cce13fe4..926408721 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -439,26 +439,17 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, { resolved_hop->type = newhop->type; resolved_hop->gate.ipv4 = newhop->gate.ipv4; - - if (newhop->ifindex) - { - resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; - resolved_hop->ifindex = newhop->ifindex; - } + resolved_hop->ifindex = newhop->ifindex; } - /* If the resolving route is an interface route, - * it means the gateway we are looking up is connected - * to that interface. (The actual network is _not_ onlink). - * Therefore, the resolved route should have the original - * gateway as nexthop as it is directly connected. - * - * On Linux, we have to set the onlink netlink flag because - * otherwise, the kernel won't accept the route. */ + /* If the resolving route is an interface route, it + * means the gateway we are looking up is connected + * to that interface. Therefore, the resolved route + * should have the original gateway as nexthop as it + * is directly connected. */ if (newhop->type == NEXTHOP_TYPE_IFINDEX || newhop->type == NEXTHOP_TYPE_IFNAME) { - resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; resolved_hop->gate.ipv4 = nexthop->gate.ipv4; resolved_hop->ifindex = newhop->ifindex; From 325823a5f07d6850318e52f6e66691eca59d24fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 15 Jan 2016 17:36:31 +0200 Subject: [PATCH 0959/1342] zebra: support FIB override routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FIB override routes are for routing protocols that establish shortcut routes, or establish point-to-point routes that should not be redistributed. Namely this is useful NHRP daemon to come. Zebra is extended to select two entries from RIB the "best" entry from routing protocols, and the FIB entry to install to kernel. FIB override routes are never selected as best entry, and thus are never adverticed to other routing daemons. The best FIB override, or if it does not exist the otherwise best RIB is selected as FIB entry to be installed. Signed-off-by: Timo Teräs Acked-by: Donald Sharp --- lib/zebra.h | 1 + zebra/rib.h | 1 + zebra/zebra_fpm.c | 2 +- zebra/zebra_rib.c | 82 ++++++++++++++++++++++++++++++++++------------- zebra/zebra_vty.c | 4 +++ zebra/zserv.c | 12 +++---- 6 files changed, 71 insertions(+), 31 deletions(-) diff --git a/lib/zebra.h b/lib/zebra.h index 1754b34da..d9802830d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -459,6 +459,7 @@ extern const char *zserv_command_string (unsigned int command); #define ZEBRA_FLAG_BLACKHOLE 0x04 #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 +#define ZEBRA_FLAG_FIB_OVERRIDE 0x20 #define ZEBRA_FLAG_STATIC 0x40 #define ZEBRA_FLAG_REJECT 0x80 diff --git a/zebra/rib.h b/zebra/rib.h index ffe7e2ff6..67ffe8de6 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -83,6 +83,7 @@ struct rib u_char status; #define RIB_ENTRY_REMOVED (1 << 0) #define RIB_ENTRY_CHANGED (1 << 1) +#define RIB_ENTRY_SELECTED_FIB (1 << 2) /* Nexthop information. */ u_char nexthop_num; diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 292dbb638..cb04f21ae 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -889,7 +889,7 @@ zfpm_route_for_update (rib_dest_t *dest) RIB_DEST_FOREACH_ROUTE (dest, rib) { - if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; return rib; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 926408721..d06382c3f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -387,7 +387,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -521,7 +521,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -633,7 +633,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -778,7 +778,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -838,7 +838,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -904,7 +904,7 @@ rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -1139,7 +1139,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib) { rib_table_info_t *info = rn->table->info; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "rib_uninstall"); @@ -1259,6 +1259,8 @@ rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; + struct rib *old_selected = NULL; + struct rib *new_selected = NULL; struct rib *old_fib = NULL; struct rib *new_fib = NULL; int installed = 0; @@ -1274,6 +1276,11 @@ rib_process (struct route_node *rn) { /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + assert (old_selected == NULL); + old_selected = rib; + } + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { assert (old_fib == NULL); old_fib = rib; @@ -1291,17 +1298,31 @@ rib_process (struct route_node *rn) if (rib->distance == DISTANCE_INFINITY) continue; - new_fib = rib_choose_best(new_fib, rib); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) + new_fib = rib_choose_best(new_fib, rib); + else + new_selected = rib_choose_best(new_selected, rib); } /* RNODE_FOREACH_RIB_SAFE */ + /* If no FIB override route, use the selected route also for FIB */ + if (new_fib == NULL) + new_fib = new_selected; + /* After the cycle is finished, the following pointers will be set: - * old_fib --- RIB entry currently having SELECTED - * new_fib --- RIB entry that is newly SELECTED + * old_selected --- RIB entry currently having SELECTED + * new_selected --- RIB entry that is newly SELECTED + * old_fib --- RIB entry currently in kernel FIB + * new_fib --- RIB entry that is newly to be in kernel FIB + * + * new_selected will get SELECTED flag, and is going to be redistributed + * the zclients. new_fib (which can be new_selected) will be installed in kernel. */ /* Set real nexthops. */ if (new_fib) nexthop_active_update (rn, new_fib, 1); + if (new_selected && new_selected != new_fib) + nexthop_active_update (rn, new_selected, 1); /* Update kernel if FIB entry has changed */ if (old_fib != new_fib @@ -1309,20 +1330,15 @@ rib_process (struct route_node *rn) { if (old_fib && old_fib != new_fib) { - if (! new_fib) - redistribute_delete (&rn->p, old_fib); - if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib))) rib_update_kernel (rn, old_fib, NULL); - UNSET_FLAG (old_fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (old_fib->status, RIB_ENTRY_SELECTED_FIB); } if (new_fib) { /* Install new or replace existing FIB entry */ - SET_FLAG (new_fib->flags, ZEBRA_FLAG_SELECTED); - redistribute_add (&rn->p, new_fib); - + SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB); if (! RIB_SYSTEM_ROUTE (new_fib)) rib_update_kernel (rn, old_fib, new_fib); } @@ -1346,6 +1362,26 @@ rib_process (struct route_node *rn) rib_update_kernel (rn, NULL, new_fib); } + /* Redistribute SELECTED entry */ + if (old_selected != new_selected + || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED))) + { + if (old_selected) + { + if (! new_selected) + redistribute_delete (&rn->p, old_selected); + if (old_selected != new_selected) + UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED); + } + + if (new_selected) + { + /* Install new or replace existing redistributed entry */ + SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, new_selected); + } + } + /* Remove all RIB entries queued for removal */ RNODE_FOREACH_RIB_SAFE (rn, rib, next) { @@ -1947,7 +1983,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) */ RNODE_FOREACH_RIB (rn, rib) { - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) && ! RIB_SYSTEM_ROUTE (rib)) { changed = 1; @@ -2098,7 +2134,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) @@ -2146,7 +2182,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); } else { @@ -2675,7 +2711,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) @@ -2724,7 +2760,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); } else { @@ -3058,7 +3094,7 @@ rib_close_table (struct route_table *table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { - if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; if (info->safi == SAFI_UNICAST) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 656f55d49..21b92ea9e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1295,6 +1295,10 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) vty_out (vty, ", vrf %u", rib->vrf_id); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) + vty_out (vty, ", fib-override"); + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) + vty_out (vty, ", fib"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) diff --git a/zebra/zserv.c b/zebra/zserv.c index 7a75ed420..600b0e5c7 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -397,8 +397,7 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - || nexthop_has_fib_child(nexthop)) + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX); @@ -504,7 +503,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, * are looking up. Therefore, we will just iterate over the top * chain of nexthops. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) @@ -574,7 +573,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, * are looking up. Therefore, we will just iterate over the top * chain of nexthops. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) @@ -644,7 +643,7 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, * are looking up. Therefore, we will just iterate over the top * chain of nexthops. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) @@ -709,8 +708,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - || nexthop_has_fib_child(nexthop)) + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) From 4d3ae716ce86c28e3979c9ae57c4e717ac5e27e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 15 Jan 2016 17:36:32 +0200 Subject: [PATCH 0960/1342] zebra: remove metric from kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It simplifies things as we can do atomic replace of route prefix. And it seems there's some race condition somewhere that can result in an incorrect change request leaving prefixes in kernel when they were intended to be replaced/deleted. Signed-off-by: Timo Teräs Acked-by: Donald Sharp --- zebra/rt_netlink.c | 40 +++++++++++----------------------------- zebra/rt_netlink.h | 1 + 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6e22d63f8..930271d0a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -667,7 +667,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, int index; int table; - int metric; u_int32_t mtu = 0; void *dest; @@ -709,7 +708,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, flags |= ZEBRA_FLAG_SELFROUTE; index = 0; - metric = 0; dest = NULL; gate = NULL; src = NULL; @@ -728,9 +726,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); - if (tb[RTA_PRIORITY]) - metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); - if (tb[RTA_METRICS]) { struct rtattr *mxrta[RTAX_MAX+1]; @@ -752,7 +747,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, - vrf_id, table, metric, mtu, 0, SAFI_UNICAST); + vrf_id, table, 0, mtu, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -767,7 +762,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, rib->type = ZEBRA_ROUTE_KERNEL; rib->distance = 0; rib->flags = flags; - rib->metric = metric; + rib->metric = 0; rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; @@ -819,7 +814,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, p.prefixlen = rtm->rtm_dst_len; rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id, - table, metric, mtu, 0, SAFI_UNICAST); + table, 0, mtu, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -854,7 +849,6 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int index; int table; - int metric; u_int32_t mtu = 0; void *dest; @@ -915,7 +909,6 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, } index = 0; - metric = 0; dest = NULL; gate = NULL; src = NULL; @@ -936,9 +929,6 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (h->nlmsg_type == RTM_NEWROUTE) { - if (tb[RTA_PRIORITY]) - metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); - if (tb[RTA_METRICS]) { struct rtattr *mxrta[RTAX_MAX+1]; @@ -971,7 +961,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, { if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id, - table, metric, mtu, 0, SAFI_UNICAST); + table, 0, mtu, 0, SAFI_UNICAST); else { /* This is a multipath route */ @@ -986,7 +976,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, rib->type = ZEBRA_ROUTE_KERNEL; rib->distance = 0; rib->flags = 0; - rib->metric = metric; + rib->metric = 0; rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; @@ -1053,7 +1043,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, - metric, mtu, 0, SAFI_UNICAST); + 0, mtu, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, SAFI_UNICAST); @@ -1663,7 +1653,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); /* Metric. */ - addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric); + addattr32 (&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); if (rib->mtu || rib->nexthop_mtu) { @@ -1809,23 +1799,15 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) int kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { - int ret; - if (!old && new) return netlink_route_multipath (RTM_NEWROUTE, p, new); if (old && !new) return netlink_route_multipath (RTM_DELROUTE, p, old); - /* Replace, can be done atomically if metric does not change; - * netlink uses [prefix, tos, priority] to identify prefix */ - if (old->metric == new->metric) - return netlink_route_multipath (RTM_NEWROUTE, p, new); - - /* Add + delete so the prefix does not disappear temporarily */ - ret = netlink_route_multipath (RTM_NEWROUTE, p, new); - if (netlink_route_multipath (RTM_DELROUTE, p, old) < 0) - ret = -1; - return ret; + /* Replace, can be done atomically if metric does not change; + * netlink uses [prefix, tos, priority] to identify prefix. + * Now metric is not sent to kernel, so we can just do atomic replace. */ + return netlink_route_multipath (RTM_NEWROUTE, p, new); } /* Interface address modification. */ diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 40fa8eb4b..63fbbe784 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -25,6 +25,7 @@ #ifdef HAVE_NETLINK #define NL_PKT_BUF_SIZE 8192 +#define NL_DEFAULT_ROUTE_METRIC 20 extern int addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data); From 954c7d6bcd04c2cf037965adda0f9d11afdcd165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 15 Jan 2016 17:36:33 +0200 Subject: [PATCH 0961/1342] lib, zebra: unify link layer type and hardware address handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the BSD specific usage of struct sockaddr_dl hardware address. This unifies to use explict hw_addr member for the address, and zebra specific enumeration for the link layer type. Additionally the zapi is updated to never send platform specific structures over the wire, but the ll_type along with hw_addr_len and hw_addr are now sent for all platforms. Based on initial work by Paul Jakma. Signed-off-by: Timo Teräs Signed-off-by: Donald Sharp --- isisd/isis_circuit.c | 10 ------ lib/if.c | 60 ++++++++++++++++++++++++++++++++++ lib/if.h | 75 ++++++++++++++++++++++++++++++++++++------- lib/zclient.c | 5 +-- zebra/interface.c | 18 +---------- zebra/interface.h | 10 ++++++ zebra/kernel_socket.c | 43 ++++++++++++++++++++++--- zebra/rt_netlink.c | 65 ++++++++++++++++++++++++++++++++++++- zebra/rtadv.c | 19 ----------- zebra/zserv.c | 5 +-- 10 files changed, 238 insertions(+), 72 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index a71ab2163..a48afd2b8 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -649,15 +649,6 @@ isis_circuit_up (struct isis_circuit *circuit) /* * Get the Hardware Address */ -#ifdef HAVE_STRUCT_SOCKADDR_DL -#ifndef SUNOS_5 - if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) - zlog_warn ("unsupported link layer"); - else - memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), - ETH_ALEN); -#endif -#else if (circuit->interface->hw_addr_len != ETH_ALEN) { zlog_warn ("unsupported link layer"); @@ -671,7 +662,6 @@ isis_circuit_up (struct isis_circuit *circuit) circuit->interface->ifindex, ISO_MTU (circuit), snpa_print (circuit->u.bc.snpa)); #endif /* EXTREME_DEBUG */ -#endif /* HAVE_STRUCT_SOCKADDR_DL */ circuit->u.bc.adjdb[0] = list_new (); circuit->u.bc.adjdb[1] = list_new (); diff --git a/lib/if.c b/lib/if.c index 4d4b6564b..342621238 100644 --- a/lib/if.c +++ b/lib/if.c @@ -1065,3 +1065,63 @@ if_terminate (vrf_id_t vrf_id, struct list **intf_list) if (vrf_id == VRF_DEFAULT) iflist = NULL; } + +const char * +if_link_type_str (enum zebra_link_type llt) +{ + switch (llt) + { +#define llts(T,S) case (T): return (S) + llts(ZEBRA_LLT_UNKNOWN, "Unknown"); + llts(ZEBRA_LLT_ETHER, "Ethernet"); + llts(ZEBRA_LLT_EETHER, "Experimental Ethernet"); + llts(ZEBRA_LLT_AX25, "AX.25 Level 2"); + llts(ZEBRA_LLT_PRONET, "PROnet token ring"); + llts(ZEBRA_LLT_IEEE802, "IEEE 802.2 Ethernet/TR/TB"); + llts(ZEBRA_LLT_ARCNET, "ARCnet"); + llts(ZEBRA_LLT_APPLETLK, "AppleTalk"); + llts(ZEBRA_LLT_DLCI, "Frame Relay DLCI"); + llts(ZEBRA_LLT_ATM, "ATM"); + llts(ZEBRA_LLT_METRICOM, "Metricom STRIP"); + llts(ZEBRA_LLT_IEEE1394, "IEEE 1394 IPv4"); + llts(ZEBRA_LLT_EUI64, "EUI-64"); + llts(ZEBRA_LLT_INFINIBAND, "InfiniBand"); + llts(ZEBRA_LLT_SLIP, "SLIP"); + llts(ZEBRA_LLT_CSLIP, "Compressed SLIP"); + llts(ZEBRA_LLT_SLIP6, "SLIPv6"); + llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6"); + llts(ZEBRA_LLT_ROSE, "ROSE packet radio"); + llts(ZEBRA_LLT_X25, "CCITT X.25"); + llts(ZEBRA_LLT_PPP, "PPP"); + llts(ZEBRA_LLT_CHDLC, "Cisco HDLC"); + llts(ZEBRA_LLT_RAWHDLC, "Raw HDLC"); + llts(ZEBRA_LLT_LAPB, "LAPB"); + llts(ZEBRA_LLT_IPIP, "IPIP Tunnel"); + llts(ZEBRA_LLT_IPIP6, "IPIP6 Tunnel"); + llts(ZEBRA_LLT_FRAD, "FRAD"); + llts(ZEBRA_LLT_SKIP, "SKIP vif"); + llts(ZEBRA_LLT_LOOPBACK, "Loopback"); + llts(ZEBRA_LLT_LOCALTLK, "Localtalk"); + llts(ZEBRA_LLT_FDDI, "FDDI"); + llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT"); + llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel"); + llts(ZEBRA_LLT_IPGRE, "GRE over IP"); + llts(ZEBRA_LLT_PIMREG, "PIMSM registration"); + llts(ZEBRA_LLT_HIPPI, "HiPPI"); + llts(ZEBRA_LLT_IRDA, "IrDA"); + llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP"); + llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop"); + llts(ZEBRA_LLT_FCPL, "Fibre-Channel Public Loop"); + llts(ZEBRA_LLT_FCFABRIC, "Fibre-Channel Fabric"); + llts(ZEBRA_LLT_IEEE802_TR, "IEEE 802.2 Token Ring"); + llts(ZEBRA_LLT_IEEE80211, "IEEE 802.11"); + llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap"); + llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4"); + llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy"); + default: + zlog_warn ("Unknown value %d", llt); + return "Unknown type!"; +#undef llts + } + return NULL; +} diff --git a/lib/if.h b/lib/if.h index ad85dcad7..0cb2202a7 100644 --- a/lib/if.h +++ b/lib/if.h @@ -23,6 +23,66 @@ Boston, MA 02111-1307, USA. */ #include "linklist.h" +/* Interface link-layer type, if known. Derived from: + * + * net/if_arp.h on various platforms - Linux especially. + * http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml + * + * Some of the more obviously defunct technologies left out. + */ +enum zebra_link_type { + ZEBRA_LLT_UNKNOWN = 0, + ZEBRA_LLT_ETHER, + ZEBRA_LLT_EETHER, + ZEBRA_LLT_AX25, + ZEBRA_LLT_PRONET, + ZEBRA_LLT_IEEE802, + ZEBRA_LLT_ARCNET, + ZEBRA_LLT_APPLETLK, + ZEBRA_LLT_DLCI, + ZEBRA_LLT_ATM, + ZEBRA_LLT_METRICOM, + ZEBRA_LLT_IEEE1394, + ZEBRA_LLT_EUI64, + ZEBRA_LLT_INFINIBAND, + ZEBRA_LLT_SLIP, + ZEBRA_LLT_CSLIP, + ZEBRA_LLT_SLIP6, + ZEBRA_LLT_CSLIP6, + ZEBRA_LLT_RSRVD, + ZEBRA_LLT_ADAPT, + ZEBRA_LLT_ROSE, + ZEBRA_LLT_X25, + ZEBRA_LLT_PPP, + ZEBRA_LLT_CHDLC, + ZEBRA_LLT_LAPB, + ZEBRA_LLT_RAWHDLC, + ZEBRA_LLT_IPIP, + ZEBRA_LLT_IPIP6, + ZEBRA_LLT_FRAD, + ZEBRA_LLT_SKIP, + ZEBRA_LLT_LOOPBACK, + ZEBRA_LLT_LOCALTLK, + ZEBRA_LLT_FDDI, + ZEBRA_LLT_SIT, + ZEBRA_LLT_IPDDP, + ZEBRA_LLT_IPGRE, + ZEBRA_LLT_IP6GRE, + ZEBRA_LLT_PIMREG, + ZEBRA_LLT_HIPPI, + ZEBRA_LLT_ECONET, + ZEBRA_LLT_IRDA, + ZEBRA_LLT_FCPP, + ZEBRA_LLT_FCAL, + ZEBRA_LLT_FCPL, + ZEBRA_LLT_FCFABRIC, + ZEBRA_LLT_IEEE802_TR, + ZEBRA_LLT_IEEE80211, + ZEBRA_LLT_IEEE80211_RADIOTAP, + ZEBRA_LLT_IEEE802154, + ZEBRA_LLT_IEEE802154_PHY, +}; + /* Interface name length. @@ -101,20 +161,10 @@ struct interface unsigned int mtu; /* IPv4 MTU */ unsigned int mtu6; /* IPv6 MTU - probably, but not neccessarily same as mtu */ - /* Hardware address. */ -#ifdef HAVE_STRUCT_SOCKADDR_DL - union { - /* note that sdl_storage is never accessed, it only exists to make space. - * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits - * best with C aliasing rules. */ - struct sockaddr_dl sdl; - struct sockaddr_storage sdl_storage; - }; -#else - unsigned short hw_type; + /* Link-layer information and hardware address */ + enum zebra_link_type ll_type; u_char hw_addr[INTERFACE_HWADDR_MAX]; int hw_addr_len; -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* interface bandwidth, kbits */ unsigned int bandwidth; @@ -304,6 +354,7 @@ extern void if_init (vrf_id_t, struct list **); extern void if_terminate (vrf_id_t, struct list **); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); +extern const char *if_link_type_str (enum zebra_link_type); /* Please use ifindex2ifname instead of if_indextoname where possible; ifindex2ifname uses internal interface info, whereas if_indextoname must diff --git a/lib/zclient.c b/lib/zclient.c index ca6a4c750..bd93d06e5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -791,13 +791,10 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->mtu = stream_getl (s); ifp->mtu6 = stream_getl (s); ifp->bandwidth = stream_getl (s); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage)); -#else + ifp->ll_type = stream_getl (s); ifp->hw_addr_len = stream_getl (s); if (ifp->hw_addr_len) stream_get (ifp->hw_addr, s, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ } static int diff --git a/zebra/interface.c b/zebra/interface.c index 411712d56..8a9225ac1 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -705,9 +705,6 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) static void if_dump_vty (struct vty *vty, struct interface *ifp) { -#ifdef HAVE_STRUCT_SOCKADDR_DL - struct sockaddr_dl *sdl; -#endif /* HAVE_STRUCT_SOCKADDR_DL */ struct connected *connected; struct listnode *node; struct route_node *rn; @@ -759,19 +756,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp) if_flag_dump (ifp->flags), VTY_NEWLINE); /* Hardware address. */ -#ifdef HAVE_STRUCT_SOCKADDR_DL - sdl = &ifp->sdl; - if (sdl != NULL && sdl->sdl_alen != 0) - { - int i; - u_char *ptr; - - vty_out (vty, " HWaddr: "); - for (i = 0, ptr = (u_char *)LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++) - vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr); - vty_out (vty, "%s", VTY_NEWLINE); - } -#else + vty_out (vty, " Type: %s%s", if_link_type_str (ifp->ll_type), VTY_NEWLINE); if (ifp->hw_addr_len != 0) { int i; @@ -781,7 +766,6 @@ if_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]); vty_out (vty, "%s", VTY_NEWLINE); } -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* Bandwidth in kbps */ if (ifp->bandwidth != 0) diff --git a/zebra/interface.h b/zebra/interface.h index 936156eb2..dbb33c559 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -196,6 +196,16 @@ struct zebra_if struct irdp_interface irdp; #endif +#ifdef HAVE_STRUCT_SOCKADDR_DL + union { + /* note that sdl_storage is never accessed, it only exists to make space. + * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits + * best with C aliasing rules. */ + struct sockaddr_dl sdl; + struct sockaddr_storage sdl_storage; + }; +#endif + #ifdef SUNOS_5 /* the real IFF_UP state of the primary interface. * need this to differentiate between all interfaces being diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index ba03498cc..10cc48c41 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -20,6 +20,7 @@ */ #include +#include #include "if.h" #include "prefix.h" @@ -378,6 +379,29 @@ bsd_linkdetect_translate (struct if_msghdr *ifm) } #endif /* HAVE_BSD_IFI_LINK_STATE */ +static enum zebra_link_type +sdl_to_zebra_link_type (unsigned int sdlt) +{ + switch (sdlt) + { + case IFT_ETHER: return ZEBRA_LLT_ETHER; + case IFT_X25: return ZEBRA_LLT_X25; + case IFT_FDDI: return ZEBRA_LLT_FDDI; + case IFT_PPP: return ZEBRA_LLT_PPP; + case IFT_LOOP: return ZEBRA_LLT_LOOPBACK; + case IFT_SLIP: return ZEBRA_LLT_SLIP; + case IFT_ARCNET: return ZEBRA_LLT_ARCNET; + case IFT_ATM: return ZEBRA_LLT_ATM; + case IFT_LOCALTALK: return ZEBRA_LLT_LOCALTLK; + case IFT_HIPPI: return ZEBRA_LLT_HIPPI; +#ifdef IFT_IEEE1394 + case IFT_IEEE1394: return ZEBRA_LLT_IEEE1394; +#endif + + default: return ZEBRA_LLT_UNKNOWN; + } +} + /* * Handle struct if_msghdr obtained from reading routing socket or * sysctl (from interface_list). There may or may not be sockaddrs @@ -534,14 +558,23 @@ ifm_read (struct if_msghdr *ifm) * is fine here. * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid */ + ifp->ll_type = ZEBRA_LLT_UNKNOWN; + ifp->hw_addr_len = 0; if (ifnlen) - { + { #ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN - memcpy (&ifp->sdl, sdl, sdl->sdl_len); + memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sdl->sdl_len); #else - memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sizeof (struct sockaddr_dl)); #endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */ - } + + ifp->ll_type = sdl_to_zebra_link_type (sdl->sdl_type); + if (sdl->sdl_alen <= sizeof(ifp->hw_addr)) + { + memcpy (ifp->hw_addr, LLADDR(sdl), sdl->sdl_alen); + ifp->hw_addr_len = sdl->sdl_alen; + } + } if_add_update (ifp); } @@ -1099,7 +1132,7 @@ rtm_write (int message, __func__, dest_buf, mask_buf, index); return -1; } - gate = (union sockunion *) & ifp->sdl; + gate = (union sockunion *) &((struct zebra_if *)ifp->info)->sdl; } if (mask) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 930271d0a..b164c7ac5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -20,6 +20,7 @@ */ #include +#include /* Hack for GNU libc version 2. */ #ifndef MSG_TRUNC @@ -462,6 +463,68 @@ netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) } } +static enum zebra_link_type +netlink_to_zebra_link_type (unsigned int hwt) +{ + switch (hwt) + { + case ARPHRD_ETHER: return ZEBRA_LLT_ETHER; + case ARPHRD_EETHER: return ZEBRA_LLT_EETHER; + case ARPHRD_AX25: return ZEBRA_LLT_AX25; + case ARPHRD_PRONET: return ZEBRA_LLT_PRONET; + case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802; + case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET; + case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK; + case ARPHRD_DLCI: return ZEBRA_LLT_DLCI; + case ARPHRD_ATM: return ZEBRA_LLT_ATM; + case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM; + case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394; + case ARPHRD_EUI64: return ZEBRA_LLT_EUI64; + case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND; + case ARPHRD_SLIP: return ZEBRA_LLT_SLIP; + case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP; + case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6; + case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6; + case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD; + case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT; + case ARPHRD_ROSE: return ZEBRA_LLT_ROSE; + case ARPHRD_X25: return ZEBRA_LLT_X25; + case ARPHRD_PPP: return ZEBRA_LLT_PPP; + case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC; + case ARPHRD_LAPB: return ZEBRA_LLT_LAPB; + case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC; + case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP; + case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6; + case ARPHRD_FRAD: return ZEBRA_LLT_FRAD; + case ARPHRD_SKIP: return ZEBRA_LLT_SKIP; + case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK; + case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK; + case ARPHRD_FDDI: return ZEBRA_LLT_FDDI; + case ARPHRD_SIT: return ZEBRA_LLT_SIT; + case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP; + case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE; + case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG; + case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI; + case ARPHRD_ECONET: return ZEBRA_LLT_ECONET; + case ARPHRD_IRDA: return ZEBRA_LLT_IRDA; + case ARPHRD_FCPP: return ZEBRA_LLT_FCPP; + case ARPHRD_FCAL: return ZEBRA_LLT_FCAL; + case ARPHRD_FCPL: return ZEBRA_LLT_FCPL; + case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC; + case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR; + case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211; + case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154; +#ifdef ARPHRD_IP6GRE + case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE; +#endif +#ifdef ARPHRD_IEEE802154_PHY + case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY; +#endif + + default: return ZEBRA_LLT_UNKNOWN; + } +} + /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int @@ -509,7 +572,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, ifp->metric = 0; /* Hardware type and address. */ - ifp->hw_type = ifi->ifi_type; + ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type); netlink_interface_update_hw_addr (tb, ifp); if_add_update (ifp); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 6b49cf622..7bb930557 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -294,24 +294,6 @@ rtadv_send_packet (int sock, struct interface *ifp) } /* Hardware address. */ -#ifdef HAVE_STRUCT_SOCKADDR_DL - sdl = &ifp->sdl; - if (sdl != NULL && sdl->sdl_alen != 0) - { - buf[len++] = ND_OPT_SOURCE_LINKADDR; - - /* Option length should be rounded up to next octet if - the link address does not end on an octet boundary. */ - buf[len++] = (sdl->sdl_alen + 9) >> 3; - - memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen); - len += sdl->sdl_alen; - - /* Pad option to end on an octet boundary. */ - memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7); - len += -(sdl->sdl_alen + 2) & 0x7; - } -#else if (ifp->hw_addr_len != 0) { buf[len++] = ND_OPT_SOURCE_LINKADDR; @@ -327,7 +309,6 @@ rtadv_send_packet (int sock, struct interface *ifp) memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7); len += -(ifp->hw_addr_len + 2) & 0x7; } -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* MTU */ if (zif->rtadv.AdvLinkMTU) diff --git a/zebra/zserv.c b/zebra/zserv.c index 600b0e5c7..2fd10d9b0 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -154,13 +154,10 @@ zserv_encode_interface (struct stream *s, struct interface *ifp) stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); -#else + stream_putl (s, ifp->ll_type); stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); From 9099f9b2a66e86f8a90d7fe18f61bd2bb1bc6744 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 18 Jan 2016 10:12:10 +0000 Subject: [PATCH 0962/1342] *: use an ifindex_t type, defined in lib/if.h, for ifindex values --- bgpd/bgp_btoa.c | 2 +- bgpd/bgp_network.c | 2 +- bgpd/bgp_zebra.c | 2 +- bgpd/bgpd.h | 2 +- isisd/isis_route.c | 10 +++++----- isisd/isis_route.h | 4 ++-- isisd/isis_zebra.c | 8 ++++---- lib/if.c | 26 +++++++++++++------------- lib/if.h | 22 ++++++++++++---------- lib/sockopt.c | 17 ++++++++--------- lib/sockopt.h | 9 ++++----- lib/sockunion.c | 2 +- lib/sockunion.h | 4 +++- lib/zclient.c | 2 +- lib/zclient.h | 4 ++-- ospf6d/ospf6_asbr.c | 5 +++-- ospf6d/ospf6_asbr.h | 6 +++--- ospf6d/ospf6_interface.c | 2 +- ospf6d/ospf6_message.c | 2 +- ospf6d/ospf6_neighbor.h | 2 +- ospf6d/ospf6_network.c | 6 +++--- ospf6d/ospf6_network.h | 6 +++--- ospf6d/ospf6_route.h | 2 +- ospf6d/ospf6_snmp.c | 12 ++++++------ ospf6d/ospf6_spf.c | 8 ++++++-- ospf6d/ospf6_zebra.c | 2 +- ospfd/ospf_asbr.c | 2 +- ospfd/ospf_asbr.h | 4 ++-- ospfd/ospf_lsa.c | 2 +- ospfd/ospf_lsa.h | 2 +- ospfd/ospf_network.c | 12 +++++------- ospfd/ospf_network.h | 10 +++++----- ospfd/ospf_packet.c | 2 +- ospfd/ospf_route.h | 2 +- ospfd/ospf_snmp.c | 30 +++++++++++++++--------------- pimd/pim_iface.c | 4 ++-- pimd/pim_iface.h | 4 ++-- pimd/pim_igmp.c | 5 +++-- pimd/pim_igmp_join.c | 3 ++- pimd/pim_igmp_join.h | 3 ++- pimd/pim_pim.c | 4 ++-- pimd/pim_sock.c | 6 +++--- pimd/pim_sock.h | 6 +++--- pimd/pim_ssmpingd.c | 2 +- pimd/pim_zebra.c | 8 ++++---- pimd/pim_zlookup.h | 2 +- pimd/test_igmpv3_join.c | 4 ++-- ripd/rip_interface.c | 4 ++-- ripd/ripd.c | 8 ++++---- ripd/ripd.h | 8 ++++---- ripngd/ripng_zebra.c | 2 +- ripngd/ripngd.c | 8 ++++---- ripngd/ripngd.h | 6 +++--- zebra/kernel_socket.c | 2 +- zebra/rib.h | 14 +++++++------- zebra/rt_netlink.c | 2 +- zebra/rt_socket.c | 4 ++-- zebra/rtadv.c | 6 +++--- zebra/test_main.c | 2 +- zebra/zebra_rib.c | 21 ++++++++++++--------- zebra/zebra_routemap.c | 2 +- zebra/zserv.c | 2 +- 62 files changed, 194 insertions(+), 183 deletions(-) diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index 284b28062..b408efdd1 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -144,7 +144,7 @@ main (int argc, char **argv) size_t len; int source_as; int dest_as; - int ifindex; + ifindex_t ifindex; int family; struct in_addr sip; struct in_addr dip; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 7a2271398..51a6f6022 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -365,7 +365,7 @@ bgp_update_source (struct peer *peer) int bgp_connect (struct peer *peer) { - unsigned int ifindex = 0; + ifindex_t ifindex = 0; /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index af312e3ca..4ec15d0dc 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -757,7 +757,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { - unsigned int ifindex; + ifindex_t ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 455034f56..5be5a19c7 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -340,7 +340,7 @@ struct peer time_t readtime; /* Last read time */ time_t resettime; /* Last reset time */ - unsigned int ifindex; /* ifindex of the BGP connection. */ + ifindex_t ifindex; /* ifindex of the BGP connection. */ char *ifname; /* bind interface name. */ char *update_if; union sockunion *update_source; diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 0348a7944..9cca80920 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -50,7 +50,7 @@ #include "isis_zebra.h" static struct isis_nexthop * -isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) +isis_nexthop_create (struct in_addr *ip, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop *nexthop; @@ -91,7 +91,7 @@ isis_nexthop_delete (struct isis_nexthop *nexthop) static int nexthoplookup (struct list *nexthops, struct in_addr *ip, - unsigned int ifindex) + ifindex_t ifindex) { struct listnode *node; struct isis_nexthop *nh; @@ -130,7 +130,7 @@ nexthops_print (struct list *nhs) #ifdef HAVE_IPV6 static struct isis_nexthop6 * -isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) +isis_nexthop6_new (struct in6_addr *ip6, ifindex_t ifindex) { struct isis_nexthop6 *nexthop6; @@ -144,7 +144,7 @@ isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) } static struct isis_nexthop6 * -isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex) +isis_nexthop6_create (struct in6_addr *ip6, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop6 *nexthop6; @@ -181,7 +181,7 @@ isis_nexthop6_delete (struct isis_nexthop6 *nexthop6) static int nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6, - unsigned int ifindex) + ifindex_t ifindex) { struct listnode *node; struct isis_nexthop6 *nh6; diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 5adea2293..0d2379cbe 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -28,7 +28,7 @@ #ifdef HAVE_IPV6 struct isis_nexthop6 { - unsigned int ifindex; + ifindex_t ifindex; struct in6_addr ip6; struct in6_addr router_address6; unsigned int lock; @@ -37,7 +37,7 @@ struct isis_nexthop6 struct isis_nexthop { - unsigned int ifindex; + ifindex_t ifindex; struct in_addr ip; struct in_addr router_address; unsigned int lock; diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 8c4eef0a8..6c398cf54 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -329,7 +329,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, { struct zapi_ipv6 api; struct in6_addr **nexthop_list; - unsigned int *ifindex_list; + ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; @@ -365,7 +365,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); - ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); + ifindex_list = (ifindex_t *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_add_route_ipv6: out of memory!"); @@ -415,7 +415,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, { struct zapi_ipv6 api; struct in6_addr **nexthop_list; - unsigned int *ifindex_list; + ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; @@ -445,7 +445,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); - ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); + ifindex_list = (ifindex_t *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); diff --git a/lib/if.c b/lib/if.c index 342621238..44b8586e4 100644 --- a/lib/if.c +++ b/lib/if.c @@ -189,41 +189,41 @@ if_add_hook (int type, int (*func)(struct interface *ifp)) /* Interface existance check by index. */ struct interface * -if_lookup_by_index_vrf (unsigned int index, vrf_id_t vrf_id) +if_lookup_by_index_vrf (ifindex_t ifindex, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { - if (ifp->ifindex == index) + if (ifp->ifindex == ifindex) return ifp; } return NULL; } struct interface * -if_lookup_by_index (unsigned int index) +if_lookup_by_index (ifindex_t ifindex) { - return if_lookup_by_index_vrf (index, VRF_DEFAULT); + return if_lookup_by_index_vrf (ifindex, VRF_DEFAULT); } const char * -ifindex2ifname_vrf (unsigned int index, vrf_id_t vrf_id) +ifindex2ifname_vrf (ifindex_t ifindex, vrf_id_t vrf_id) { struct interface *ifp; - return ((ifp = if_lookup_by_index_vrf (index, vrf_id)) != NULL) ? + return ((ifp = if_lookup_by_index_vrf (ifindex, vrf_id)) != NULL) ? ifp->name : "unknown"; } const char * -ifindex2ifname (unsigned int index) +ifindex2ifname (ifindex_t ifindex) { - return ifindex2ifname_vrf (index, VRF_DEFAULT); + return ifindex2ifname_vrf (ifindex, VRF_DEFAULT); } -unsigned int +ifindex_t ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id) { struct interface *ifp; @@ -232,7 +232,7 @@ ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id) : IFINDEX_INTERNAL; } -unsigned int +ifindex_t ifname2ifindex (const char *name) { return ifname2ifindex_vrf (name, VRF_DEFAULT); @@ -928,7 +928,7 @@ connected_add_by_prefix (struct interface *ifp, struct prefix *p, } #ifndef HAVE_IF_NAMETOINDEX -unsigned int +ifindex_t if_nametoindex (const char *name) { struct interface *ifp; @@ -940,7 +940,7 @@ if_nametoindex (const char *name) #ifndef HAVE_IF_INDEXTONAME char * -if_indextoname (unsigned int ifindex, char *name) +if_indextoname (ifindex_t ifindex, char *name) { struct interface *ifp; @@ -1005,7 +1005,7 @@ ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp) /* Lookup interface by interface's IP address or interface index. */ static struct interface * -ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) +ifaddr_ipv4_lookup (struct in_addr *addr, ifindex_t ifindex) { struct prefix_ipv4 p; struct route_node *rn; diff --git a/lib/if.h b/lib/if.h index 0cb2202a7..b3d14ba4e 100644 --- a/lib/if.h +++ b/lib/if.h @@ -21,6 +21,7 @@ Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_IF_H #define _ZEBRA_IF_H +#include "zebra.h" #include "linklist.h" /* Interface link-layer type, if known. Derived from: @@ -96,6 +97,8 @@ enum zebra_link_type { #define INTERFACE_NAMSIZ 20 #define INTERFACE_HWADDR_MAX 20 +typedef signed int ifindex_t; + #ifdef HAVE_PROC_NET_DEV struct if_stats { @@ -142,7 +145,7 @@ struct interface /* Interface index (should be IFINDEX_INTERNAL for non-kernel or deleted interfaces). */ - unsigned int ifindex; + ifindex_t ifindex; #define IFINDEX_INTERNAL 0 /* Zebra internal interface status */ @@ -294,15 +297,14 @@ struct connected /* Prototypes. */ extern int if_cmp_func (struct interface *, struct interface *); extern struct interface *if_create (const char *name, int namelen); -extern struct interface *if_lookup_by_index (unsigned int); +extern struct interface *if_lookup_by_index (ifindex_t); extern struct interface *if_lookup_exact_address (struct in_addr); extern struct interface *if_lookup_address (struct in_addr); extern struct interface *if_lookup_prefix (struct prefix *prefix); extern struct interface *if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id); -extern struct interface *if_lookup_by_index_vrf (unsigned int, - vrf_id_t vrf_id); +extern struct interface *if_lookup_by_index_vrf (ifindex_t, vrf_id_t vrf_id); extern struct interface *if_lookup_exact_address_vrf (struct in_addr, vrf_id_t vrf_id); extern struct interface *if_lookup_address_vrf (struct in_addr, @@ -359,14 +361,14 @@ extern const char *if_link_type_str (enum zebra_link_type); /* Please use ifindex2ifname instead of if_indextoname where possible; ifindex2ifname uses internal interface info, whereas if_indextoname must make a system call. */ -extern const char *ifindex2ifname (unsigned int); -extern const char *ifindex2ifname_vrf (unsigned int, vrf_id_t vrf_id); +extern const char *ifindex2ifname (ifindex_t); +extern const char *ifindex2ifname_vrf (ifindex_t, vrf_id_t vrf_id); /* Please use ifname2ifindex instead of if_nametoindex where possible; ifname2ifindex uses internal interface info, whereas if_nametoindex must make a system call. */ -extern unsigned int ifname2ifindex(const char *ifname); -extern unsigned int ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id); +extern ifindex_t ifname2ifindex(const char *ifname); +extern ifindex_t ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id); /* Connected address functions. */ extern struct connected *connected_new (void); @@ -381,10 +383,10 @@ extern struct connected *connected_lookup_address (struct interface *, struct in_addr); #ifndef HAVE_IF_NAMETOINDEX -extern unsigned int if_nametoindex (const char *); +extern ifindex_t if_nametoindex (const char *); #endif #ifndef HAVE_IF_INDEXTONAME -extern char *if_indextoname (unsigned int, char *); +extern char *if_indextoname (ifindex_t, char *); #endif /* Exported variables. */ diff --git a/lib/sockopt.c b/lib/sockopt.c index 257271bc0..301423711 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -220,7 +220,7 @@ int setsockopt_ipv4_multicast(int sock, int optname, unsigned int mcast_addr, - unsigned int ifindex) + ifindex_t ifindex) { #ifdef HAVE_RFC3678 struct group_req gr; @@ -318,8 +318,7 @@ setsockopt_ipv4_multicast(int sock, * Set IP_MULTICAST_IF socket option in an OS-dependent manner. */ int -setsockopt_ipv4_multicast_if(int sock, - unsigned int ifindex) +setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex) { #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX @@ -345,7 +344,7 @@ setsockopt_ipv4_multicast_if(int sock, } static int -setsockopt_ipv4_ifindex (int sock, int val) +setsockopt_ipv4_ifindex (int sock, ifindex_t val) { int ret; @@ -381,7 +380,7 @@ setsockopt_ipv4_tos(int sock, int tos) int -setsockopt_ifindex (int af, int sock, int val) +setsockopt_ifindex (int af, int sock, ifindex_t val) { int ret = -1; @@ -408,11 +407,11 @@ setsockopt_ifindex (int af, int sock, int val) * Returns the interface index (small integer >= 1) if it can be * determined, or else 0. */ -static int +static ifindex_t getsockopt_ipv4_ifindex (struct msghdr *msgh) { /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */ - int ifindex = -1; + ifindex_t ifindex = -1; #if defined(IP_PKTINFO) /* Linux pktinfo based ifindex retrieval */ @@ -432,7 +431,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) struct sockaddr_dl *sdl; #else /* SUNOS_5 uses an integer with the index. */ - int *ifindex_p; + ifindex_t *ifindex_p; #endif /* SUNOS_5 */ #ifndef SUNOS_5 @@ -473,7 +472,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) } /* return ifindex, 0 if none found */ -int +ifindex_t getsockopt_ifindex (int af, struct msghdr *msgh) { switch (af) diff --git a/lib/sockopt.h b/lib/sockopt.h index cb14efc7b..a9b8acaac 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -83,16 +83,15 @@ extern int setsockopt_ipv6_tclass (int, int); (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) -extern int setsockopt_ipv4_multicast_if(int sock, - unsigned int ifindex); +extern int setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, unsigned int mcast_addr, - unsigned int ifindex); + ifindex_t ifindex); extern int setsockopt_ipv4_tos(int sock, int tos); /* Ask for, and get, ifindex, by whatever method is supported. */ -extern int setsockopt_ifindex (int, int, int); -extern int getsockopt_ifindex (int, struct msghdr *); +extern int setsockopt_ifindex (int, int, ifindex_t); +extern ifindex_t getsockopt_ifindex (int, struct msghdr *); /* swab the fields in iph between the host order and system order expected * for IP_HDRINCL. diff --git a/lib/sockunion.c b/lib/sockunion.c index 492c36ec5..4a22c6386 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -291,7 +291,7 @@ sockunion_log (const union sockunion *su, char *buf, size_t len) 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, const union sockunion *peersu, unsigned short port, - unsigned int ifindex) + ifindex_t ifindex) { int ret; int val; diff --git a/lib/sockunion.h b/lib/sockunion.h index a6f964fec..b91c57175 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -23,6 +23,8 @@ #ifndef _ZEBRA_SOCKUNION_H #define _ZEBRA_SOCKUNION_H +#include "if.h" + #if 0 union sockunion { struct sockinet { @@ -109,7 +111,7 @@ extern int sockunion_socket (const union sockunion *su); extern const char *inet_sutop (const union sockunion *su, char *str); extern enum connect_result sockunion_connect (int fd, const union sockunion *su, unsigned short port, - unsigned int); + ifindex_t); extern union sockunion *sockunion_getsockname (int); extern union sockunion *sockunion_getpeername (int); extern union sockunion *sockunion_dup (const union sockunion *); diff --git a/lib/zclient.c b/lib/zclient.c index bd93d06e5..9188c0183 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -811,7 +811,7 @@ memconstant(const void *s, int c, size_t n) struct connected * zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) { - unsigned int ifindex; + ifindex_t ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; diff --git a/lib/zclient.h b/lib/zclient.h index a14f59935..d069eb22b 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -126,7 +126,7 @@ struct zapi_ipv4 struct in_addr **nexthop; u_char ifindex_num; - unsigned int *ifindex; + ifindex_t *ifindex; u_char distance; @@ -201,7 +201,7 @@ struct zapi_ipv6 struct in6_addr **nexthop; u_char ifindex_num; - unsigned int *ifindex; + ifindex_t *ifindex; u_char distance; diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index b1620d4a5..6eca142de 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -411,7 +411,7 @@ ospf6_asbr_redistribute_unset (int type) } void -ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, +ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop) { int ret; @@ -557,7 +557,8 @@ ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, } void -ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) +ospf6_asbr_redistribute_remove (int type, ifindex_t ifindex, + struct prefix *prefix) { struct ospf6_route *match; struct ospf6_external_info *info = NULL; diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 73770cc00..f3df90b1f 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -49,7 +49,7 @@ struct ospf6_external_info struct in6_addr forwarding; /* u_int32_t tag; */ - unsigned int ifindex; + ifindex_t ifindex; }; /* AS-External-LSA */ @@ -79,11 +79,11 @@ extern void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry); extern int ospf6_asbr_is_asbr (struct ospf6 *o); -extern void ospf6_asbr_redistribute_add (int type, int ifindex, +extern void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop); -extern void ospf6_asbr_redistribute_remove (int type, int ifindex, +extern void ospf6_asbr_redistribute_remove (int type, ifindex_t ifindex, struct prefix *prefix); extern int ospf6_redistribute_config_write (struct vty *vty); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index c9c90117b..26f68ac54 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -59,7 +59,7 @@ const char *ospf6_interface_state_str[] = }; struct ospf6_interface * -ospf6_interface_lookup_by_ifindex (int ifindex) +ospf6_interface_lookup_by_ifindex (ifindex_t ifindex) { struct ospf6_interface *oi; struct interface *ifp; diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index e71b4101b..d382f038a 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1515,7 +1515,7 @@ ospf6_receive (struct thread *thread) unsigned int len; char srcname[64], dstname[64]; struct in6_addr src, dst; - unsigned int ifindex; + ifindex_t ifindex; struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 93ffa289b..54b7ffe0d 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -53,7 +53,7 @@ struct ospf6_neighbor u_int32_t router_id; /* Neighbor Interface ID */ - u_int32_t ifindex; + ifindex_t ifindex; /* Router Priority of this neighbor */ u_char priority; diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index e0be38b32..a77375029 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -113,7 +113,7 @@ ospf6_serv_sock (void) /* ospf6 set socket option */ void -ospf6_sso (u_int ifindex, struct in6_addr *group, int option) +ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; int ret; @@ -150,7 +150,7 @@ iov_totallen (struct iovec *iov) int ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, - unsigned int *ifindex, struct iovec *message) + ifindex_t *ifindex, struct iovec *message) { int retval; struct msghdr smsghdr; @@ -208,7 +208,7 @@ ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, int ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, - unsigned int *ifindex, struct iovec *message) + ifindex_t *ifindex, struct iovec *message) { int retval; struct msghdr rmsghdr; diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 127bf45c7..f4b74faa7 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -29,12 +29,12 @@ extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock (void); -extern void ospf6_sso (u_int ifindex, struct in6_addr *group, int option); +extern void ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, - unsigned int *, struct iovec *); + ifindex_t *, struct iovec *); extern int ospf6_recvmsg (struct in6_addr *, struct in6_addr *, - unsigned int *, struct iovec *); + ifindex_t *, struct iovec *); #endif /* OSPF6_NETWORK_H */ diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 42eb69ea8..2fb2c1d71 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -41,7 +41,7 @@ extern unsigned char conf_debug_ospf6_route; struct ospf6_nexthop { /* Interface index */ - unsigned int ifindex; + ifindex_t ifindex; /* IP address, if any */ struct in6_addr address; diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 307d420ec..266031e7f 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -623,7 +623,7 @@ ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; - u_int32_t ifindex, area_id, id, instid, adv_router; + ifindex_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; @@ -835,7 +835,8 @@ static u_char * ospfv3IfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - unsigned int ifindex, instid; + ifindex_t ifindex = 0; + unsigned int instid = 0; struct ospf6_interface *oi = NULL; struct ospf6_lsa *lsa = NULL; struct interface *iif; @@ -849,8 +850,6 @@ ospfv3IfEntry (struct variable *v, oid *name, size_t *length, == MATCH_FAILED) return NULL; - ifindex = instid = 0; - /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; @@ -988,7 +987,8 @@ static u_char * ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - unsigned int ifindex, instid, rtrid; + ifindex_t ifindex = 0; + unsigned int instid, rtrid; struct ospf6_interface *oi = NULL; struct ospf6_neighbor *on = NULL; struct interface *iif; @@ -1001,7 +1001,7 @@ ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, == MATCH_FAILED) return NULL; - ifindex = instid = rtrid = 0; + instid = rtrid = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 88e128536..858398eb7 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -225,7 +225,8 @@ static void ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, caddr_t lsdesc) { - int i, ifindex; + int i; + ifindex_t ifindex; struct ospf6_interface *oi; u_int16_t type; u_int32_t adv_router; @@ -235,7 +236,10 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, assert (VERTEX_IS_TYPE (ROUTER, w)); ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex : - ROUTER_LSDESC_GET_IFID (lsdesc)); + /* v is the local router & the interface_id is a local ifindex */ + (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc)); + assert (ifindex >= 0); + oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL) { diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index d37e50898..30b6fc6ff 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -368,7 +368,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) char buf[64]; int nhcount; struct in6_addr **nexthops; - unsigned int *ifindexes; + ifindex_t *ifindexes; int i, ret = 0; struct prefix_ipv6 *dest; diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 8bef1754f..122e70b4e 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -135,7 +135,7 @@ ospf_route_map_set_compare (struct route_map_set_values *values1, /* Add an External info for AS-external-LSA. */ struct external_info * ospf_external_info_add (u_char type, struct prefix_ipv4 p, - unsigned int ifindex, struct in_addr nexthop) + ifindex_t ifindex, struct in_addr nexthop) { struct external_info *new; struct route_node *rn; diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 724acf481..d151cb149 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -39,7 +39,7 @@ struct external_info struct prefix_ipv4 p; /* Interface index. */ - unsigned int ifindex; + ifindex_t ifindex; /* Nexthop address. */ struct in_addr nexthop; @@ -61,7 +61,7 @@ extern int ospf_route_map_set_compare (struct route_map_set_values *, struct route_map_set_values *); extern struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, - unsigned int, + ifindex_t, struct in_addr); extern void ospf_external_info_delete (u_char, struct prefix_ipv4); extern struct external_info *ospf_external_info_lookup (u_char, diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index e62a4e7b9..6bd8c3e9a 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2206,7 +2206,7 @@ ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p) void ospf_external_lsa_flush (struct ospf *ospf, u_char type, struct prefix_ipv4 *p, - unsigned int ifindex /*, struct in_addr nexthop */) + ifindex_t ifindex /*, struct in_addr nexthop */) { struct ospf_lsa *lsa; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index dd3b91a57..c94072400 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -283,7 +283,7 @@ extern struct ospf_lsa *ospf_lsa_install (struct ospf *, extern void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p); extern void ospf_external_lsa_flush (struct ospf *, u_char, struct prefix_ipv4 *, - unsigned int /* , struct in_addr nexthop */); + ifindex_t /* , struct in_addr nexthop */); extern struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *); diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 900a5667d..02ddf92f0 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -48,7 +48,7 @@ extern struct zebra_privs_t ospfd_privs; /* Join to the OSPF ALL SPF ROUTERS multicast group. */ int ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, - unsigned int ifindex) + ifindex_t ifindex) { int ret; @@ -69,7 +69,7 @@ ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, int ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, - unsigned int ifindex) + ifindex_t ifindex) { int ret; @@ -89,8 +89,7 @@ ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, /* Join to the OSPF ALL Designated ROUTERS multicast group. */ int -ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int - ifindex) +ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; @@ -110,8 +109,7 @@ ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int } int -ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int - ifindex) +ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; @@ -130,7 +128,7 @@ ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int } int -ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) +ospf_if_ipmulticast (struct ospf *top, struct prefix *p, ifindex_t ifindex) { u_char val; int ret, len; diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h index e0a5c69d5..8257adb4a 100644 --- a/ospfd/ospf_network.h +++ b/ospfd/ospf_network.h @@ -25,14 +25,14 @@ /* Prototypes. */ extern int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, - unsigned int); + ifindex_t); extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, - unsigned int); + ifindex_t); extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *, - unsigned int); + ifindex_t); extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, - unsigned int); -extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); + ifindex_t); +extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, ifindex_t); extern int ospf_sock_init (void); extern void ospf_adjust_sndbuflen (struct ospf *, unsigned int); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 9a8f1d611..117401c0b 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2125,7 +2125,7 @@ ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) int ret; struct ip *iph; u_int16_t ip_len; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; struct iovec iov; /* Header and data both require alignment. */ char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 6c202b0cc..d509e4ae7 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -39,7 +39,7 @@ struct ospf_path { struct in_addr nexthop; struct in_addr adv_router; - unsigned int ifindex; + ifindex_t ifindex; }; /* Below is the structure linked to every diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 163615337..ebeffa8ea 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1413,7 +1413,7 @@ struct list *ospf_snmp_iflist; struct ospf_snmp_if { struct in_addr addr; - unsigned int ifindex; + ifindex_t ifindex; struct interface *ifp; }; @@ -1455,7 +1455,7 @@ ospf_snmp_if_update (struct interface *ifp) struct prefix *p; struct ospf_snmp_if *osif; struct in_addr *addr; - unsigned int ifindex; + ifindex_t ifindex; ospf_snmp_if_delete (ifp); @@ -1530,7 +1530,7 @@ ospf_snmp_is_if_have_addr (struct interface *ifp) } static struct ospf_interface * -ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) +ospf_snmp_if_lookup (struct in_addr *ifaddr, ifindex_t *ifindex) { struct listnode *node; struct ospf_snmp_if *osif; @@ -1554,8 +1554,8 @@ ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) } static struct ospf_interface * -ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex, - int ifaddr_next, int ifindex_next) +ospf_snmp_if_lookup_next (struct in_addr *ifaddr, ifindex_t *ifindex, + int ifaddr_next, ifindex_t ifindex_next) { struct ospf_snmp_if *osif; struct listnode *nn; @@ -1638,11 +1638,11 @@ ospf_snmp_iftype (struct interface *ifp) static struct ospf_interface * ospfIfLookup (struct variable *v, oid *name, size_t *length, - struct in_addr *ifaddr, unsigned int *ifindex, int exact) + struct in_addr *ifaddr, ifindex_t *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; - int ifindex_next = 0; + ifindex_t ifindex_next = 0; struct ospf_interface *oi; oid *offset; @@ -1694,7 +1694,7 @@ static u_char * ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - unsigned int ifindex; + ifindex_t ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; @@ -1802,11 +1802,11 @@ ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, static struct ospf_interface * ospfIfMetricLookup (struct variable *v, oid *name, size_t *length, - struct in_addr *ifaddr, unsigned int *ifindex, int exact) + struct in_addr *ifaddr, ifindex_t *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; - int ifindex_next = 0; + ifindex_t ifindex_next = 0; struct ospf_interface *oi; oid *offset; int metric; @@ -1866,7 +1866,7 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { /* Currently we support metric 1 only. */ - unsigned int ifindex; + ifindex_t ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; @@ -2133,7 +2133,7 @@ ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, static struct ospf_neighbor * ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, - unsigned int *ifindex) + ifindex_t *ifindex) { struct listnode *node, *nnode; struct ospf_interface *oi; @@ -2161,7 +2161,7 @@ ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, } static struct ospf_neighbor * -ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, +ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, ifindex_t *ifindex, int first) { struct listnode *nn; @@ -2208,7 +2208,7 @@ ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, static struct ospf_neighbor * ospfNbrLookup (struct variable *v, oid *name, size_t *length, - struct in_addr *nbr_addr, unsigned int *ifindex, int exact) + struct in_addr *nbr_addr, ifindex_t *ifindex, int exact) { unsigned int len; int first; @@ -2303,7 +2303,7 @@ ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct in_addr nbr_addr; - unsigned int ifindex; + ifindex_t ifindex; struct ospf_neighbor *nbr; struct ospf_interface *oi; diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 930dad00b..2533d0fd7 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -759,7 +759,7 @@ struct interface *pim_if_find_by_vif_index(int vif_index) /* pim_if_add_vif() uses ifindex as vif_index */ -int pim_if_find_vifindex_by_ifindex(int ifindex) +int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex) { return ifindex; } @@ -910,7 +910,7 @@ static struct igmp_join *igmp_join_find(struct list *join_list, } static int igmp_join_sock(const char *ifname, - int ifindex, + ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr) { diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 8806fdd93..8cad3d135 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -122,8 +122,8 @@ int pim_if_del_vif(struct interface *ifp); void pim_if_add_vif_all(void); void pim_if_del_vif_all(void); -struct interface *pim_if_find_by_vif_index(int vif_index); -int pim_if_find_vifindex_by_ifindex(int ifindex); +struct interface *pim_if_find_by_vif_index(ifindex_t vif_index); +int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex); int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 4fd3edcb8..7baf2e36b 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -47,7 +47,8 @@ static void group_timer_off(struct igmp_group *group); static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr); -static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_options) +static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, + uint32_t pim_options) { int fd; int join = 0; @@ -952,7 +953,7 @@ static int pim_igmp_read(struct thread *t) socklen_t tolen = sizeof(to); uint8_t buf[PIM_IGMP_BUFSIZE_READ]; int len; - int ifindex = -1; + ifindex_t ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c index 62e32c601..042818a67 100644 --- a/pimd/pim_igmp_join.c +++ b/pimd/pim_igmp_join.c @@ -26,6 +26,7 @@ #include #include +#include "zebra.h" #include "pim_igmp_join.h" #ifndef SOL_IP @@ -42,7 +43,7 @@ struct group_source_req }; #endif -int pim_igmp_join_source(int fd, int ifindex, +int pim_igmp_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr) { diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h index 1127af120..67779fffd 100644 --- a/pimd/pim_igmp_join.h +++ b/pimd/pim_igmp_join.h @@ -24,8 +24,9 @@ #define PIM_IGMP_JOIN_H #include +#include "if.h" -int pim_igmp_join_source(int fd, int ifindex, +int pim_igmp_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index a04a0afc8..c52247578 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -269,7 +269,7 @@ static int pim_sock_read(struct thread *t) socklen_t tolen = sizeof(to); uint8_t buf[PIM_PIM_BUFSIZE_READ]; int len; - int ifindex = -1; + ifindex_t ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); @@ -376,7 +376,7 @@ static void pim_sock_read_on(struct interface *ifp) pim_ifp->pim_sock_fd); } -static int pim_sock_open(struct in_addr ifaddr, int ifindex) +static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex) { int fd; diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 2bb48f75a..ceae4f207 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -180,7 +180,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) } int pim_socket_join(int fd, struct in_addr group, - struct in_addr ifaddr, int ifindex) + struct in_addr ifaddr, ifindex_t ifindex) { int ret; @@ -228,7 +228,7 @@ int pim_socket_join(int fd, struct in_addr group, return ret; } -int pim_socket_join_source(int fd, int ifindex, +int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname) @@ -252,7 +252,7 @@ int pim_socket_join_source(int fd, int ifindex, int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, - int *ifindex) + ifindex_t *ifindex) { struct msghdr msgh; struct cmsghdr *cmsg; diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index cfe39ad1e..622fb47cb 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -40,15 +40,15 @@ int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop); int pim_socket_join(int fd, struct in_addr group, - struct in_addr ifaddr, int ifindex); -int pim_socket_join_source(int fd, int ifindex, + struct in_addr ifaddr, ifindex_t ifindex); +int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, - int *ifindex); + ifindex_t *ifindex); int pim_socket_mcastloop_get(int fd); diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index d564bf57b..fe88eba27 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -250,7 +250,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); - int ifindex = -1; + ifindex_t ifindex = -1; uint8_t buf[1000]; int len; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 3c739d28d..8f85b17bb 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -524,7 +524,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, { struct stream *s; struct zapi_ipv4 api; - unsigned long ifindex; + ifindex_t ifindex; struct in_addr nexthop; struct prefix_ipv4 p; int min_len = 4; @@ -604,7 +604,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: add %s %s/%d " - "nexthop %s ifindex %ld metric%s %u distance%s %u", + "nexthop %s ifindex %d metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), @@ -621,7 +621,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: delete %s %s/%d " - "nexthop %s ifindex %ld metric%s %u distance%s %u", + "nexthop %s ifindex %d metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), @@ -737,7 +737,7 @@ static int fib_lookup_if_vif_index(struct in_addr addr) struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; int num_ifindex; int vif_index; - int first_ifindex; + ifindex_t first_ifindex; num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, diff --git a/pimd/pim_zlookup.h b/pimd/pim_zlookup.h index 1f184942c..f2be6d4fa 100644 --- a/pimd/pim_zlookup.h +++ b/pimd/pim_zlookup.h @@ -31,7 +31,7 @@ struct pim_zlookup_nexthop { struct in_addr nexthop_addr; - int ifindex; + ifindex_t ifindex; uint32_t route_metric; uint8_t protocol_distance; }; diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c index fe64fbc00..81026aecc 100644 --- a/pimd/test_igmpv3_join.c +++ b/pimd/test_igmpv3_join.c @@ -37,7 +37,7 @@ const char *prog_name = 0; static int iface_solve_index(const char *ifname) { struct if_nameindex *ini; - int ifindex = -1; + ifindex_t ifindex = -1; int i; if (!ifname) @@ -77,7 +77,7 @@ int main(int argc, const char *argv[]) const char *ifname; const char *group; const char *source; - int ifindex; + ifindex_t ifindex; int result; int fd; diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 00612df43..7bdcf46a1 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -74,7 +74,7 @@ static int ipv4_multicast_join (int sock, struct in_addr group, struct in_addr ifa, - unsigned int ifindex) + ifindex_t ifindex) { int ret; @@ -95,7 +95,7 @@ static int ipv4_multicast_leave (int sock, struct in_addr group, struct in_addr ifa, - unsigned int ifindex) + ifindex_t ifindex) { int ret; diff --git a/ripd/ripd.c b/ripd/ripd.c index 870873d51..82b1adaeb 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1577,7 +1577,7 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, /* Add redistributed route to RIP table. */ void rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, - unsigned int ifindex, struct in_addr *nexthop, + ifindex_t ifindex, struct in_addr *nexthop, unsigned int metric, unsigned char distance) { int ret; @@ -1651,7 +1651,7 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, /* Delete redistributed route from RIP table. */ void rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, - unsigned int ifindex) + ifindex_t ifindex) { int ret; struct route_node *rp; @@ -1793,7 +1793,7 @@ setsockopt_pktinfo (int sock) /* Read RIP packet by recvmsg function. */ int rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, - int *ifindex) + ifindex_t *ifindex) { int ret; struct msghdr msg; @@ -1834,7 +1834,7 @@ rip_read_new (struct thread *t) int sock; char buf[RIP_PACKET_MAXSIZ]; struct sockaddr_in from; - unsigned int ifindex; + ifindex_t ifindex; /* Fetch socket then register myself. */ sock = THREAD_FD (t); diff --git a/ripd/ripd.h b/ripd/ripd.h index a768ccc6a..dbed342db 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -198,7 +198,7 @@ struct rip_info struct in_addr from; /* Which interface does this route come from. */ - unsigned int ifindex; + ifindex_t ifindex; /* Metric of this route. */ u_int32_t metric; @@ -224,7 +224,7 @@ struct rip_info u_char metric_set; u_int32_t metric_out; u_short tag_out; - unsigned int ifindex_out; + ifindex_t ifindex_out; struct route_node *rp; @@ -400,9 +400,9 @@ extern int rip_request_send (struct sockaddr_in *, struct interface *, u_char, extern int rip_neighbor_lookup (struct sockaddr_in *); extern int rip_redistribute_check (int); -extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, +extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, ifindex_t, struct in_addr *, unsigned int, unsigned char); -extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); +extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, ifindex_t); extern void rip_redistribute_withdraw (int); extern void rip_zebra_ipv4_add (struct route_node *); extern void rip_zebra_ipv4_delete (struct route_node *); diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 13b185330..a48539e5f 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -42,7 +42,7 @@ static void ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) { static struct in6_addr **nexthops = NULL; - static unsigned int *ifindexes = NULL; + static ifindex_t *ifindexes = NULL; static unsigned int nexthops_len = 0; struct list *list = (struct list *)rp->info; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 97a139281..d27d45b22 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -229,7 +229,7 @@ ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, /* Receive UDP RIPng packet from socket. */ static int ripng_recv_packet (int sock, u_char *buf, int bufsize, - struct sockaddr_in6 *from, unsigned int *ifindex, + struct sockaddr_in6 *from, ifindex_t *ifindex, int *hoplimit) { int ret; @@ -971,7 +971,7 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, /* Add redistributed route to RIPng table. */ void ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, - unsigned int ifindex, struct in6_addr *nexthop) + ifindex_t ifindex, struct in6_addr *nexthop) { struct route_node *rp; struct ripng_info *rinfo = NULL, newinfo; @@ -1041,7 +1041,7 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, /* Delete redistributed route to RIPng table. */ void ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, - unsigned int ifindex) + ifindex_t ifindex) { struct route_node *rp; struct ripng_info *rinfo; @@ -1359,7 +1359,7 @@ ripng_read (struct thread *thread) int sock; struct sockaddr_in6 from; struct ripng_packet *packet; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; struct interface *ifp; int hoplimit = -1; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 6cbbd84bc..75b542e97 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -176,7 +176,7 @@ struct ripng_info struct in6_addr from; /* Which interface does this route come from. */ - unsigned int ifindex; + ifindex_t ifindex; /* Metric of this route. */ u_char metric; @@ -384,9 +384,9 @@ extern void ripng_info_free (struct ripng_info *rinfo); extern void ripng_event (enum ripng_event, int); extern int ripng_request (struct interface *ifp); extern void ripng_redistribute_add (int, int, struct prefix_ipv6 *, - unsigned int, struct in6_addr *); + ifindex_t, struct in6_addr *); extern void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, - unsigned int); + ifindex_t); extern void ripng_redistribute_withdraw (int type); extern void ripng_distribute_update_interface (struct interface *); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 10cc48c41..5e68c5675 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1020,7 +1020,7 @@ rtm_read (struct rt_msghdr *rtm) if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) return; struct prefix_ipv6 p; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; p.family = AF_INET6; p.prefix = dest.sin6.sin6_addr; diff --git a/zebra/rib.h b/zebra/rib.h index 67ffe8de6..1dacc7f78 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -228,7 +228,7 @@ struct nexthop /* Interface index. */ char *ifname; - unsigned int ifindex; + ifindex_t ifindex; enum nexthop_types_t type; @@ -425,7 +425,7 @@ extern void multicast_mode_ipv4_set (enum multicast_mode mode); extern enum multicast_mode multicast_mode_ipv4_get (void); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); -extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); +extern struct nexthop *nexthop_ifindex_add (struct rib *, ifindex_t); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, @@ -433,7 +433,7 @@ extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, struct in_addr *, struct in_addr *, - unsigned int); + ifindex_t); extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); extern void rib_lookup_and_pushup (struct prefix_ipv4 *); @@ -459,13 +459,13 @@ extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); * also implicitly withdraw equal prefix of same type. */ extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, vrf_id_t vrf_id, int table_id, + ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t, u_int32_t, u_char, safi_t); extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t); extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, + struct in_addr *gate, ifindex_t ifindex, vrf_id_t, safi_t safi); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, @@ -495,13 +495,13 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, + struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi); extern int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, safi_t safi); + struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, safi_t safi); extern struct rib *rib_lookup_ipv6 (struct in6_addr *, vrf_id_t); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b164c7ac5..2539d614a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -69,7 +69,7 @@ extern u_int32_t nl_rcvbufsize; /* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void -set_ifindex(struct interface *ifp, unsigned int ifi_index) +set_ifindex(struct interface *ifp, ifindex_t ifi_index) { struct interface *oifp; diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 4d0a7db58..78ec9e579 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -76,7 +76,7 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; int gate = 0; int error; char prefix_buf[PREFIX_STRLEN]; @@ -252,7 +252,7 @@ kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib, int family) struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; int gate = 0; int error; diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 7bb930557..9450f9a92 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -70,7 +70,7 @@ static int if_leave_all_router (int, struct interface *); static int rtadv_recv_packet (int sock, u_char *buf, int buflen, - struct sockaddr_in6 *from, unsigned int *ifindex, + struct sockaddr_in6 *from, ifindex_t *ifindex, int *hoplimit) { int ret; @@ -408,7 +408,7 @@ rtadv_process_advert (void) } static void -rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, +rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex, int hoplimit, vrf_id_t vrf_id) { struct icmp6_hdr *icmph; @@ -472,7 +472,7 @@ rtadv_read (struct thread *thread) int len; u_char buf[RTADV_MSG_SIZE]; struct sockaddr_in6 from; - unsigned int ifindex = 0; + ifindex_t ifindex = 0; int hoplimit = -1; struct zebra_vrf *zvrf = THREAD_ARG (thread); diff --git a/zebra/test_main.c b/zebra/test_main.c index 448d1ef9f..09f53adfb 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -105,7 +105,7 @@ usage (char *progname, int status) exit (status); } -static unsigned int test_ifindex = 0; +static ifindex_t test_ifindex = 0; /* testrib commands */ DEFUN (test_interface_state, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d06382c3f..1650dabf0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -198,7 +198,7 @@ nexthops_free (struct nexthop *nexthop) } struct nexthop * -nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) +nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) { struct nexthop *nexthop; @@ -243,7 +243,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) struct nexthop * nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, - struct in_addr *src, unsigned int ifindex) + struct in_addr *src, ifindex_t ifindex) { struct nexthop *nexthop; @@ -291,7 +291,7 @@ nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, static struct nexthop * nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, - unsigned int ifindex) + ifindex_t ifindex) { struct nexthop *nexthop; @@ -1074,8 +1074,9 @@ static int nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { struct nexthop *nexthop; - unsigned int prev_active, prev_index, new_active; - + unsigned int prev_active, new_active; + ifindex_t prev_index; + rib->nexthop_active_num = 0; UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); @@ -1736,7 +1737,7 @@ rib_delnode (struct route_node *rn, struct rib *rib) int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, vrf_id_t vrf_id, int table_id, + ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) { struct rib *rib; @@ -2076,7 +2077,8 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, safi_t safi) + struct in_addr *gate, ifindex_t ifindex, + vrf_id_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -2558,7 +2560,7 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, + struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) { @@ -2666,7 +2668,8 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id, safi_t safi) + struct in6_addr *gate, ifindex_t ifindex, + vrf_id_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index bd9be5323..da9cb1308 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -134,7 +134,7 @@ route_match_interface (void *rule, struct prefix *prefix, struct nexthop_vrfid *nh_vrf; struct nexthop *nexthop; char *ifname = rule; - unsigned int ifindex; + ifindex_t ifindex; if (type == RMAP_ZEBRA) { diff --git a/zebra/zserv.c b/zebra/zserv.c index 2fd10d9b0..e624ef2f6 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -827,7 +827,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) u_char nexthop_num; u_char nexthop_type; struct stream *s; - unsigned int ifindex; + ifindex_t ifindex; u_char ifname_len; safi_t safi; From 2e320423337c628bfeb814ec15fd5f575ebc5eed Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 13 Jan 2016 10:49:50 -0800 Subject: [PATCH 0963/1342] doc, vtysh: Fixup of history handling This fix does two things: 1) If the ${HOME}/.history_quagga file does not exist, create it for history storing. 2) Allow vtysh -c "..." commands to be stored in history file as well Signed-off-by: Donald Sharp --- doc/vtysh.1 | 3 +++ vtysh/vtysh_main.c | 32 ++++++++++++++++++++++++++++++-- vtysh/vtysh_user.c | 10 ++++++++++ vtysh/vtysh_user.h | 2 ++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/doc/vtysh.1 b/doc/vtysh.1 index de4913e51..a2afa9ff1 100644 --- a/doc/vtysh.1 +++ b/doc/vtysh.1 @@ -76,6 +76,9 @@ config file. .BI /usr/local/etc/Quagga.conf The default location of the integrated Quagga routing engine config file if integrated config file is in use (not default). +.TP +.BI ${HOME}/.history_quagga +Location of history of commands entered via cli .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index aa7d02187..02a19b7c2 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -223,6 +223,7 @@ main (int argc, char **argv, char **env) struct cmd_rec *tail = NULL; int echo_command = 0; int no_error = 0; + char *homedir = NULL; /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); @@ -317,6 +318,27 @@ main (int argc, char **argv, char **env) exit(1); } + /* + * Setup history file for use by both -c and regular input + * If we can't find the home directory, then don't store + * the history information + */ + homedir = vtysh_get_home (); + if (homedir) + { + snprintf(history_file, sizeof(history_file), "%s/.history_quagga", homedir); + if (read_history (history_file) != 0) + { + int fp; + + fp = open (history_file, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fp) + close (fp); + + read_history (history_file); + } + } + /* If eval mode. */ if (cmd) { @@ -332,6 +354,9 @@ main (int argc, char **argv, char **env) { *eol = '\0'; + add_history (cmd->line); + append_history (1, history_file); + if (echo_command) printf("%s%s\n", vtysh_prompt(), cmd->line); @@ -348,6 +373,9 @@ main (int argc, char **argv, char **env) cmd->line = eol+1; } + add_history (cmd->line); + append_history (1, history_file); + if (echo_command) printf("%s%s\n", vtysh_prompt(), cmd->line); @@ -368,6 +396,8 @@ main (int argc, char **argv, char **env) XFREE(0, cr); } } + + history_truncate_file(history_file,1000); exit (0); } @@ -397,8 +427,6 @@ main (int argc, char **argv, char **env) sigsetjmp (jmpbuf, 1); jmpflag = 1; - snprintf(history_file, sizeof(history_file), "%s/.history_quagga", getenv("HOME")); - read_history(history_file); /* Main command loop. */ while (vtysh_rl_gets ()) vtysh_execute (line_read); diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 7e10d68ed..239a633f4 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -191,6 +191,16 @@ vtysh_auth (void) return 0; } +char * +vtysh_get_home (void) +{ + struct passwd *passwd; + + passwd = getpwuid (getuid ()); + + return passwd ? passwd->pw_dir : NULL; +} + void vtysh_user_init (void) { diff --git a/vtysh/vtysh_user.h b/vtysh/vtysh_user.h index c485c23f0..a6c8b99b5 100644 --- a/vtysh/vtysh_user.h +++ b/vtysh/vtysh_user.h @@ -25,4 +25,6 @@ int vtysh_auth (void); void vtysh_user_init (void); +char *vtysh_get_home (void); + #endif /* _VTYSH_USER_H */ From 36fef5708d074a3ef41f34d324c309c45bae119b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 16 Dec 2015 14:22:10 -0500 Subject: [PATCH 0964/1342] ospfd: Remove HAVE_OPAQUE_LSA HAVE_OPAQUE_LSA is used by default and you have to actively turn it off except that OPAQUE_LSA is an industry standard and used pretty much everywhere. There is no need to have special #defines for this anymore. Signed-off-by: Donald Sharp --- configure.ac | 15 +++------------ ospfd/ospf_api.c | 3 --- ospfd/ospf_apiserver.c | 3 --- ospfd/ospf_dump.c | 2 -- ospfd/ospf_flood.c | 28 ---------------------------- ospfd/ospf_interface.c | 8 -------- ospfd/ospf_interface.h | 4 ---- ospfd/ospf_ism.c | 2 -- ospfd/ospf_lsa.c | 30 ------------------------------ ospfd/ospf_lsa.h | 6 ------ ospfd/ospf_main.c | 2 -- ospfd/ospf_neighbor.c | 2 -- ospfd/ospf_neighbor.h | 2 -- ospfd/ospf_nsm.c | 10 ---------- ospfd/ospf_opaque.c | 2 -- ospfd/ospf_packet.c | 24 ------------------------ ospfd/ospf_te.c | 3 --- ospfd/ospf_vty.c | 39 --------------------------------------- ospfd/ospfd.c | 14 -------------- ospfd/ospfd.h | 10 ---------- 20 files changed, 3 insertions(+), 206 deletions(-) diff --git a/configure.ac b/configure.ac index 3003e6277..5808db30a 100755 --- a/configure.ac +++ b/configure.ac @@ -254,8 +254,6 @@ AC_ARG_WITH(libpam, AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh])) AC_ARG_ENABLE(tcp-zebra, AS_HELP_STRING([--enable-tcp-zebra], [enable TCP/IP socket connection between zebra and protocol daemon])) -AC_ARG_ENABLE(opaque-lsa, - AS_HELP_STRING([--disable-opaque-lsa],[do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370)])) AC_ARG_ENABLE(ospfapi, AS_HELP_STRING([--disable-ospfapi], [do not build OSPFAPI to access the OSPF LSA Database])) AC_ARG_ENABLE(ospfclient, @@ -325,12 +323,7 @@ if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi -if test "${enable_opaque_lsa}" != "no"; then - AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) -fi - if test "${enable_ospf_te}" != "no"; then - AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) AC_DEFINE(HAVE_OSPF_TE,,OSPF TE) fi @@ -1155,16 +1148,14 @@ fi AM_CONDITIONAL(WATCHQUAGGA, test "x$WATCHQUAGGA" = "xwatchquagga") OSPFCLIENT="" -if test "${enable_opaque_lsa}" != "no"; then - if test "${enable_ospfapi}" != "no";then +if test "${enable_ospfapi}" != "no";then AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI) - if test "${enable_ospfclient}" != "no";then + if test "${enable_ospfclient}" != "no";then OSPFCLIENT="ospfclient" - fi fi - fi + AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") case "${enable_ripngd}" in diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index cbb234ae6..e92f162eb 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -23,9 +23,6 @@ #include #ifdef SUPPORT_OSPF_API -#ifndef HAVE_OPAQUE_LSA -#error "Core Opaque-LSA module must be configured." -#endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 92f68f75f..aac8ef4b8 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -23,9 +23,6 @@ #include #ifdef SUPPORT_OSPF_API -#ifndef HAVE_OPAQUE_LSA -#error "Core Opaque-LSA module must be configured." -#endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index ac93f1d3e..fb43210a1 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -619,13 +619,11 @@ ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length) case OSPF_AS_NSSA_LSA: ospf_as_external_lsa_dump (s, length); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_dump (s, length); break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index df19adff4..8de497411 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -138,9 +138,7 @@ ospf_process_self_originated_lsa (struct ospf *ospf, ospf_router_lsa_update_area (area); return; case OSPF_NETWORK_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: -#endif /* HAVE_OPAQUE_LSA */ /* We must find the interface the LSA could belong to. If the interface is no more a broadcast type or we are no more the DR, we flush the LSA otherwise -- create the new instance and @@ -160,13 +158,11 @@ ospf_process_self_originated_lsa (struct ospf *ospf, return; } -#ifdef HAVE_OPAQUE_LSA if (new->data->type == OSPF_OPAQUE_LINK_LSA) { ospf_opaque_lsa_refresh (new); return; } -#endif /* HAVE_OPAQUE_LSA */ if (oi->network_lsa_self) oi->network_lsa_self->data->ls_seqnum = new->data->ls_seqnum; @@ -193,14 +189,12 @@ ospf_process_self_originated_lsa (struct ospf *ospf, else ospf_lsa_flush_as (ospf, new); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AREA_LSA: ospf_opaque_lsa_refresh (new); break; case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */ break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -281,25 +275,17 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, interface. */ lsa_ack_flag = ospf_flood_through (ospf, nbr, new); -#ifdef HAVE_OPAQUE_LSA /* Remove the current database copy from all neighbors' Link state retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does ^^^^^^^^^^^^^^^^^^^^^^^ not have area ID. All other (even NSSA's) do have area ID. */ -#else /* HAVE_OPAQUE_LSA */ - /* Remove the current database copy from all neighbors' Link state - retransmission lists. Only AS_EXTERNAL does not have area ID. - All other (even NSSA's) do have area ID. */ -#endif /* HAVE_OPAQUE_LSA */ if (current) { switch (current->data->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ ospf_ls_retransmit_delete_nbr_as (ospf, current); break; default: @@ -421,7 +407,6 @@ ospf_flood_through_interface (struct ospf_interface *oi, } } -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type)) { if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) @@ -431,7 +416,6 @@ ospf_flood_through_interface (struct ospf_interface *oi, continue; } } -#endif /* HAVE_OPAQUE_LSA */ /* If the new LSA was received from this neighbor, examine the next neighbor. */ @@ -566,7 +550,6 @@ ospf_flood_through_area (struct ospf_area *area, oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; -#ifdef HAVE_OPAQUE_LSA if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi)) { /* @@ -578,7 +561,6 @@ ospf_flood_through_area (struct ospf_area *area, (void *)lsa->oi, (void *)oi); continue; } -#endif /* HAVE_OPAQUE_LSA */ if (ospf_flood_through_interface (oi, inbr, lsa)) lsa_ack_flag = 1; @@ -688,16 +670,12 @@ ospf_flood_through (struct ospf *ospf, case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ case OSPF_OPAQUE_AREA_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ @@ -727,9 +705,7 @@ ospf_flood_through (struct ospf *ospf, switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ @@ -1006,16 +982,12 @@ ospf_lsa_flush (struct ospf *ospf, struct ospf_lsa *lsa) case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: -#endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_area (lsa, lsa->area); break; case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_as (ospf, lsa); break; default: diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index f41c4f168..f4242b0b3 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -241,9 +241,7 @@ ospf_if_new (struct ospf *ospf, struct interface *ifp, struct prefix *p) oi->crypt_seqnum = time (NULL); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_init (oi); -#endif /* HAVE_OPAQUE_LSA */ oi->ospf = ospf; @@ -305,9 +303,7 @@ ospf_if_free (struct ospf_interface *oi) assert (oi->state == ISM_Down); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_term (oi); -#endif /* HAVE_OPAQUE_LSA */ /* Free Pseudo Neighbour */ ospf_nbr_delete (oi->nbr_self); @@ -686,9 +682,7 @@ ospf_if_new_hook (struct interface *ifp) SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET; -#ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_new_if (ifp); -#endif /* HAVE_OPAQUE_LSA */ return rc; } @@ -697,9 +691,7 @@ ospf_if_delete_hook (struct interface *ifp) { int rc = 0; struct route_node *rn; -#ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_del_if (ifp); -#endif /* HAVE_OPAQUE_LSA */ route_table_finish (IF_OIFS (ifp)); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 2ed426f97..69b9b4069 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -193,9 +193,7 @@ struct ospf_interface /* self-originated LSAs. */ struct ospf_lsa *network_lsa_self; /* network-LSA. */ -#ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-9 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ struct route_table *ls_upd_queue; @@ -216,9 +214,7 @@ struct ospf_interface struct thread *t_ls_ack; /* timer */ struct thread *t_ls_ack_direct; /* event */ struct thread *t_ls_upd_event; /* event */ -#ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ int on_write_q; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 9649df8dc..ae6d0cdbc 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -593,9 +593,7 @@ ism_change_state (struct ospf_interface *oi, int state) oi->network_lsa_self = NULL; } -#ifdef HAVE_OPAQUE_LSA ospf_opaque_ism_change (oi, old_state); -#endif /* HAVE_OPAQUE_LSA */ /* Check area border status. */ ospf_check_abr_status (oi->ospf); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 6bd8c3e9a..634bc4351 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2594,11 +2594,9 @@ ospf_discard_from_db (struct ospf *ospf, ospf_ase_unregister_external_lsa (old, ospf); ospf_ls_retransmit_delete_nbr_as (ospf, old); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (ospf, old); break; -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: ospf_ls_retransmit_delete_nbr_area (old->area, old); ospf_ase_unregister_external_lsa (old, ospf); @@ -2632,9 +2630,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, lsdb = ospf->lsdb; break; case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsdb = ospf->lsdb; break; default: @@ -2746,7 +2742,6 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, case OSPF_AS_EXTERNAL_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: if (IS_LSA_SELF (lsa)) lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ @@ -2759,7 +2754,6 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_install (lsa, rt_recalc); break; -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); default: /* type-6,8,9....nothing special */ @@ -2777,9 +2771,7 @@ ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: zlog_debug ("LSA[%s]: Install %s", dump_lsa_key (new), @@ -3013,7 +3005,6 @@ ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) switch (lsa->data->type) { -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: @@ -3026,7 +3017,6 @@ ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) * topology, and thus, routing recalculation is not needed here. */ break; -#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: ospf_ase_incremental_update (ospf, lsa); @@ -3067,12 +3057,10 @@ ospf_lsa_maxage_walker (struct thread *thread) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); } @@ -3082,10 +3070,8 @@ ospf_lsa_maxage_walker (struct thread *thread) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ } OSPF_TIMER_ON (ospf->t_maxage_walker, ospf_lsa_maxage_walker, @@ -3138,15 +3124,11 @@ ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: -#endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, adv_router); default: break; @@ -3182,13 +3164,11 @@ ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* Currently not used. */ break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -3201,14 +3181,12 @@ ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) { struct ospf_lsa *match; -#ifdef HAVE_OPAQUE_LSA /* * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) * is redefined to have two subfields; opaque-type and opaque-id. * However, it is harmless to treat the two sub fields together, as if * they two were forming a unique LSA-ID. */ -#endif /* HAVE_OPAQUE_LSA */ match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router); @@ -3359,14 +3337,12 @@ ospf_lsa_flush_schedule (struct ospf *ospf, struct ospf_lsa *lsa) switch (lsa->data->type) { -#ifdef HAVE_OPAQUE_LSA /* Opaque wants to be notified of flushes */ case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (lsa); break; -#endif /* HAVE_OPAQUE_LSA */ default: ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush (ospf, lsa); @@ -3426,22 +3402,18 @@ ospf_flush_self_originated_lsas_now (struct ospf *ospf) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ } if (need_to_flush_ase) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); -#endif /* HAVE_OPAQUE_LSA */ } /* @@ -3650,13 +3622,11 @@ ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) else ospf_lsa_flush_as (ospf, lsa); break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_refresh (lsa); break; -#endif /* HAVE_OPAQUE_LSA */ default: break; } diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index c94072400..3c87962f2 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -27,11 +27,7 @@ /* OSPF LSA Range definition. */ #define OSPF_MIN_LSA 1 /* begin range here */ -#if defined (HAVE_OPAQUE_LSA) #define OSPF_MAX_LSA 12 -#else -#define OSPF_MAX_LSA 8 -#endif /* OSPF LSA Type definition. */ #define OSPF_UNKNOWN_LSA 0 @@ -211,9 +207,7 @@ struct as_external_lsa } e[1]; }; -#ifdef HAVE_OPAQUE_LSA #include "ospfd/ospf_opaque.h" -#endif /* HAVE_OPAQUE_LSA */ /* Macros. */ #define GET_METRIC(x) get_metric(x) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 1e4184ff0..f373650c2 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -308,9 +308,7 @@ main (int argc, char **argv) #ifdef HAVE_SNMP ospf_snmp_init (); #endif /* HAVE_SNMP */ -#ifdef HAVE_OPAQUE_LSA ospf_opaque_init (); -#endif /* HAVE_OPAQUE_LSA */ /* Get configuration file. */ vty_read_config (config_file, config_default); diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 23a641736..862de5e85 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -272,7 +272,6 @@ ospf_nbr_count (struct ospf_interface *oi, int state) return count; } -#ifdef HAVE_OPAQUE_LSA int ospf_nbr_count_opaque_capable (struct ospf_interface *oi) { @@ -289,7 +288,6 @@ ospf_nbr_count_opaque_capable (struct ospf_interface *oi) return count; } -#endif /* HAVE_OPAQUE_LSA */ /* lookup nbr by address - use this only if you know you must * otherwise use the ospf_nbr_lookup() wrapper, which deals diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 822c2024c..38f8cb5cb 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -102,9 +102,7 @@ extern int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); extern void ospf_nbr_self_reset (struct ospf_interface *); extern void ospf_nbr_add_self (struct ospf_interface *); extern int ospf_nbr_count (struct ospf_interface *, int); -#ifdef HAVE_OPAQUE_LSA extern int ospf_nbr_count_opaque_capable (struct ospf_interface *); -#endif /* HAVE_OPAQUE_LSA */ extern struct ospf_neighbor *ospf_nbr_get (struct ospf_interface *, struct ospf_header *, struct ip *, struct prefix *); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 4fecb599b..b43d88550 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -208,7 +208,6 @@ ospf_db_summary_isempty (struct ospf_neighbor *nbr) static int ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { -#ifdef HAVE_OPAQUE_LSA switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: @@ -226,7 +225,6 @@ ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) default: break; } -#endif /* HAVE_OPAQUE_LSA */ /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) @@ -282,7 +280,6 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); -#ifdef HAVE_OPAQUE_LSA /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { @@ -291,7 +288,6 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); } -#endif /* HAVE_OPAQUE_LSA */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP)) { @@ -304,13 +300,11 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT)) LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); -#endif /* HAVE_OPAQUE_LSA */ return 0; } @@ -360,10 +354,8 @@ nsm_clear_adj (struct ospf_neighbor *nbr) if (!ospf_ls_retransmit_isempty (nbr)) ospf_ls_retransmit_clear (nbr); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) UNSET_FLAG (nbr->options, OSPF_OPTION_O); -#endif /* HAVE_OPAQUE_LSA */ } static int @@ -735,9 +727,7 @@ nsm_change_state (struct ospf_neighbor *nbr, int state) } } -#ifdef HAVE_OPAQUE_LSA ospf_opaque_nsm_change (nbr, old_state); -#endif /* HAVE_OPAQUE_LSA */ /* State changes from > ExStart to <= ExStart should clear any Exchange * or Full/LSA Update related lists and state. diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 64284803d..215676e61 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -27,7 +27,6 @@ #define MTYPE_OPAQUE_INFO_PER_ID 0 #include -#ifdef HAVE_OPAQUE_LSA #include "linklist.h" #include "prefix.h" @@ -2179,4 +2178,3 @@ oi_to_top (struct ospf_interface *oi) return top; } -#endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 117401c0b..25f70bba8 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -894,7 +894,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) && CHECK_FLAG (hello->options, OSPF_OPTION_O)) { @@ -910,7 +909,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ #endif /* STRICT_OBIT_USAGE_CHECK */ } -#endif /* HAVE_OPAQUE_LSA */ /* new for NSSA is to ensure that NP is on and E is off */ @@ -1062,7 +1060,6 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, return; } -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsah->type) && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { @@ -1070,14 +1067,11 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } -#endif /* HAVE_OPAQUE_LSA */ switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ /* Check for stub area. Reject if AS-External from stub but allow if from NSSA. */ if (oi->area->external_routing == OSPF_AREA_STUB) @@ -1248,7 +1242,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (dd->options, OSPF_OPTION_O) && !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { @@ -1258,7 +1251,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, */ UNSET_FLAG (dd->options, OSPF_OPTION_O); } -#endif /* HAVE_OPAQUE_LSA */ /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); @@ -1323,7 +1315,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, /* This is where the real Options are saved */ nbr->options = dd->options; -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) @@ -1341,7 +1332,6 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, /* This situation is undesirable, but not a real error. */ } } -#endif /* HAVE_OPAQUE_LSA */ OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); @@ -1619,7 +1609,6 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) lsah->ls_age = htons (OSPF_LSA_MAXAGE); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { #ifdef STRICT_OBIT_USAGE_CHECK @@ -1651,7 +1640,6 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); continue; } -#endif /* HAVE_OPAQUE_LSA */ /* Create OSPF LSA instance. */ lsa = ospf_lsa_new (); @@ -1661,16 +1649,12 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ lsa->area = NULL; break; -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ /* Fallthrough */ -#endif /* HAVE_OPAQUE_LSA */ default: lsa->area = oi->area; break; @@ -1857,7 +1841,6 @@ ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, DISCARD_LSA (lsa, 3); } -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) { @@ -1905,7 +1888,6 @@ ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, continue; } } -#endif /* HAVE_OPAQUE_LSA */ /* It might be happen that received LSA is self-originated network LSA, but * router ID is changed. So, we should check if LSA is a network-LSA whose @@ -2481,7 +2463,6 @@ ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */ -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: @@ -2489,7 +2470,6 @@ ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char * data) padded to 32-bit alignment." This is considered equivalent * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt * file for the detailed analysis of this passage. */ -#endif ret = lsalen % 4 ? MSG_NG : MSG_OK; break; default: @@ -3120,10 +3100,8 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, /* Set Options. */ options = OPTIONS (oi); -#ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) SET_FLAG (options, OSPF_OPTION_O); -#endif /* HAVE_OPAQUE_LSA */ stream_putc (s, options); /* DD flags */ @@ -3148,7 +3126,6 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, for (rn = route_top (table); rn; rn = route_next (rn)) if ((lsa = rn->info) != NULL) { -#ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && (! CHECK_FLAG (options, OSPF_OPTION_O))) { @@ -3157,7 +3134,6 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, ospf_lsdb_delete (lsdb, lsa); continue; } -#endif /* HAVE_OPAQUE_LSA */ if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) { diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index bcb89630a..fe142353a 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -27,9 +27,6 @@ #include #ifdef HAVE_OSPF_TE -#ifndef HAVE_OPAQUE_LSA -#error "Wrong configure option" -#endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 45a19c096..fb17dff39 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2786,14 +2786,12 @@ show_ip_ospf_area (struct vty *vty, struct ospf_area *area) vty_out (vty, " Number of NSSA LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_AS_NSSA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_AS_NSSA_LSA), VTY_NEWLINE); -#ifdef HAVE_OPAQUE_LSA vty_out (vty, " Number of opaque link LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_LINK_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_LINK_LSA), VTY_NEWLINE); vty_out (vty, " Number of opaque area LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_AREA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_AREA_LSA), VTY_NEWLINE); -#endif /* HAVE_OPAQUE_LSA */ vty_out (vty, "%s", VTY_NEWLINE); } @@ -2834,12 +2832,10 @@ DEFUN (show_ip_ospf, vty_out (vty, " RFC1583Compatibility flag is %s%s", CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE) ? "enabled" : "disabled", VTY_NEWLINE); -#ifdef HAVE_OPAQUE_LSA vty_out (vty, " OpaqueCapability flag is %s%s", CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? "enabled" : "disabled", VTY_NEWLINE); -#endif /* HAVE_OPAQUE_LSA */ /* Show stub-router configuration */ if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED @@ -2899,11 +2895,9 @@ DEFUN (show_ip_ospf, vty_out (vty, " Number of external LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), VTY_NEWLINE); -#ifdef HAVE_OPAQUE_LSA vty_out (vty, " Number of opaque AS LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (ospf->lsdb, OSPF_OPAQUE_AS_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_OPAQUE_AS_LSA), VTY_NEWLINE); -#endif /* HAVE_OPAQUE_LSA */ /* Show number of areas attached. */ vty_out (vty, " Number of areas attached to this router: %d%s", listcount (ospf->areas), VTY_NEWLINE); @@ -3606,11 +3600,9 @@ show_lsa_summary (struct vty *vty, struct ospf_lsa *lsa, int self) break; case OSPF_NETWORK_LSA: case OSPF_ASBR_SUMMARY_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ default: break; } @@ -3630,12 +3622,10 @@ static const char *show_database_desc[] = "AS External Link States", "Group Membership LSA", "NSSA-external Link States", -#ifdef HAVE_OPAQUE_LSA "Type-8 LSA", "Link-Local Opaque-LSA", "Area-Local Opaque-LSA", "AS-external Opaque-LSA", -#endif /* HAVE_OPAQUE_LSA */ }; static const char *show_database_header[] = @@ -3648,12 +3638,10 @@ static const char *show_database_header[] = "Link ID ADV Router Age Seq# CkSum Route", " --- header for Group Member ----", "Link ID ADV Router Age Seq# CkSum Route", -#ifdef HAVE_OPAQUE_LSA " --- type-8 ---", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", -#endif /* HAVE_OPAQUE_LSA */ }; static void @@ -3925,7 +3913,6 @@ show_func_dummy (struct vty *vty, struct ospf_lsa *lsa) return 0; } -#ifdef HAVE_OPAQUE_LSA static int show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { @@ -3938,7 +3925,6 @@ show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) } return 0; } -#endif /* HAVE_OPAQUE_LSA */ int (*show_function[])(struct vty *, struct ospf_lsa *) = { @@ -3950,12 +3936,10 @@ int (*show_function[])(struct vty *, struct ospf_lsa *) = show_as_external_lsa_detail, show_func_dummy, show_as_nssa_lsa_detail, /* almost same as external */ -#ifdef HAVE_OPAQUE_LSA NULL, /* type-8 */ show_opaque_lsa_detail, show_opaque_lsa_detail, show_opaque_lsa_detail, -#endif /* HAVE_OPAQUE_LSA */ }; static void @@ -4014,9 +3998,7 @@ show_lsa_detail (struct vty *vty, struct ospf *ospf, int type, switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); @@ -4063,9 +4045,7 @@ show_lsa_detail_adv_router (struct vty *vty, struct ospf *ospf, int type, switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); @@ -4101,9 +4081,7 @@ show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ continue; default: break; @@ -4130,9 +4108,7 @@ show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) switch (type) { case OSPF_AS_EXTERNAL_LSA: -#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: -#endif /* HAVE_OPAQUE_LSA */ break; default: continue; @@ -4184,17 +4160,10 @@ show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) #define OSPF_LSA_TYPE_NSSA_DESC "NSSA external link state\n" #define OSPF_LSA_TYPE_NSSA_CMD_STR "|nssa-external" -#ifdef HAVE_OPAQUE_LSA #define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AS_DESC "Link AS Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_CMD_STR "|opaque-link|opaque-area|opaque-as" -#else /* HAVE_OPAQUE_LSA */ -#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "" -#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "" -#define OSPF_LSA_TYPE_OPAQUE_AS_DESC "" -#define OSPF_LSA_TYPE_OPAQUE_CMD_STR "" -#endif /* HAVE_OPAQUE_LSA */ #define OSPF_LSA_TYPES_CMD_STR \ "asbr-summary|external|network|router|summary" \ @@ -4264,14 +4233,12 @@ DEFUN (show_ip_ospf_database, show_ip_ospf_database_maxage (vty, ospf); return CMD_SUCCESS; } -#ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; -#endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; @@ -4391,14 +4358,12 @@ DEFUN (show_ip_ospf_database_type_adv_router, type = OSPF_ASBR_SUMMARY_LSA; else if (strncmp (argv[0], "e", 1) == 0) type = OSPF_AS_EXTERNAL_LSA; -#ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; -#endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; @@ -7084,9 +7049,7 @@ config_write_interface (struct vty *vty) } } while (rn); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_if (vty, ifp); -#endif /* HAVE_OPAQUE_LSA */ } return write; @@ -7555,9 +7518,7 @@ ospf_config_write (struct vty *vty) /* Distance configuration. */ config_write_ospf_distance (vty, ospf); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_router (vty, ospf); -#endif /* HAVE_OPAQUE_LSA */ } return write; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index c317ed87c..c9fcdc393 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -294,9 +294,7 @@ ospf_get () if (ospf->router_id_static.s_addr == 0) ospf_router_id_update (ospf); -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_init (ospf); -#endif /* HAVE_OPAQUE_LSA */ } return ospf; @@ -429,9 +427,7 @@ ospf_finish_final (struct ospf *ospf) struct listnode *node, *nnode; int i; -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_term (ospf); -#endif /* HAVE_OPAQUE_LSA */ /* be nice if this worked, but it doesn't */ /*ospf_flush_self_originated_lsas_now (ospf);*/ @@ -507,17 +503,13 @@ ospf_finish_final (struct ospf *ospf) OSPF_TIMER_OFF (ospf->t_lsa_refresher); OSPF_TIMER_OFF (ospf->t_read); OSPF_TIMER_OFF (ospf->t_write); -#ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (ospf->t_opaque_lsa_self); -#endif close (ospf->fd); stream_free(ospf->ibuf); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); -#endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); @@ -609,9 +601,7 @@ ospf_area_new (struct ospf *ospf, struct in_addr area_id) /* Self-originated LSAs initialize. */ new->router_lsa_self = NULL; -#ifdef HAVE_OPAQUE_LSA ospf_opaque_type10_lsa_init (new); -#endif /* HAVE_OPAQUE_LSA */ new->oiflist = list_new (); new->ranges = route_table_init (); @@ -640,12 +630,10 @@ ospf_area_free (struct ospf_area *area) LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); -#ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); -#endif /* HAVE_OPAQUE_LSA */ ospf_lsdb_delete_all (area->lsdb); ospf_lsdb_free (area->lsdb); @@ -663,9 +651,7 @@ ospf_area_free (struct ospf_area *area) /* Cancel timer. */ OSPF_TIMER_OFF (area->t_stub_router); -#ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (area->t_opaque_lsa_self); -#endif /* HAVE_OPAQUE_LSA */ if (OSPF_IS_AREA_BACKBONE (area)) area->ospf->backbone = NULL; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 595c04f61..098fc5f41 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -131,11 +131,9 @@ struct ospf #define OSPF_LOG_ADJACENCY_CHANGES (1 << 3) #define OSPF_LOG_ADJACENCY_DETAIL (1 << 4) -#ifdef HAVE_OPAQUE_LSA /* Opaque-LSA administrative flags. */ u_char opaque; #define OPAQUE_OPERATION_READY_BIT (1 << 0) -#endif /* HAVE_OPAQUE_LSA */ /* RFC3137 stub router. Configured time to stay stub / max-metric */ unsigned int stub_router_startup_time; /* seconds */ @@ -178,9 +176,7 @@ struct ospf int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ -#ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ /* Routing tables. */ struct route_table *old_table; /* Old routing table. */ @@ -209,9 +205,7 @@ struct ospf struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ -#ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ -#endif /* HAVE_OPAQUE_LSA */ unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ @@ -344,9 +338,7 @@ struct ospf_area /* Self-originated LSAs. */ struct ospf_lsa *router_lsa_self; -#ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-10 Opaque-LSAs */ -#endif /* HAVE_OPAQUE_LSA */ /* Area announce list. */ struct @@ -388,9 +380,7 @@ struct ospf_area /* Threads. */ struct thread *t_stub_router; /* Stub-router timer */ -#ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ -#endif /* HAVE_OPAQUE_LSA */ /* Statistics field. */ u_int32_t spf_calculation; /* SPF Calculation Count. */ From 693da6096a28eef5eadeea699771265987b3ec0c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 16 Dec 2015 14:22:11 -0500 Subject: [PATCH 0965/1342] ospfd: Remove HAVE_OSPF_TE Remove from ospf the HAVE_OSPF_TE define and just always have ospf traffic engineering. Signed-off-by: Donald Sharp Tested-by: NetDEF CI System --- configure.ac | 6 ------ ospfd/ospf_opaque.c | 6 ------ ospfd/ospf_te.c | 4 ---- 3 files changed, 16 deletions(-) diff --git a/configure.ac b/configure.ac index 5808db30a..b4d934b63 100755 --- a/configure.ac +++ b/configure.ac @@ -259,8 +259,6 @@ AC_ARG_ENABLE(ospfapi, AC_ARG_ENABLE(ospfclient, AS_HELP_STRING([--disable-ospfclient], [do not build OSPFAPI client for OSPFAPI, (this is the default if --disable-ospfapi is set)])) -AC_ARG_ENABLE(ospf-te, - AS_HELP_STRING([--disable-ospf-te],[disable Traffic Engineering Extension to OSPF])) AC_ARG_ENABLE(multipath, AS_HELP_STRING([--enable-multipath=ARG], [enable multipath function, ARG must be digit])) AC_ARG_ENABLE(user, @@ -323,10 +321,6 @@ if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi -if test "${enable_ospf_te}" != "no"; then - AC_DEFINE(HAVE_OSPF_TE,,OSPF TE) -fi - if test "${enable_linux24_tcp_md5}" = "yes"; then AC_DEFINE(HAVE_TCP_MD5_LINUX24,,Old Linux 2.4 TCP MD5 Signature Patch) fi diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 215676e61..61e98f400 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -61,9 +61,7 @@ * Followings are initialize/terminate functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ -#ifdef HAVE_OSPF_TE #include "ospfd/ospf_te.h" -#endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API int ospf_apiserver_init (void); @@ -86,10 +84,8 @@ ospf_opaque_init (void) ospf_opaque_register_vty (); ospf_opaque_funclist_init (); -#ifdef HAVE_OSPF_TE if (ospf_mpls_te_init () != 0) exit (1); -#endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) @@ -102,9 +98,7 @@ ospf_opaque_init (void) void ospf_opaque_term (void) { -#ifdef HAVE_OSPF_TE ospf_mpls_te_term (); -#endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API ospf_apiserver_term (); diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index fe142353a..cd52866be 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -26,8 +26,6 @@ #include -#ifdef HAVE_OSPF_TE - #include "linklist.h" #include "prefix.h" #include "if.h" @@ -1904,5 +1902,3 @@ ospf_mpls_te_register_vty (void) return; } - -#endif /* HAVE_OSPF_TE */ From d18396369ff85517cd4b0b7abe96f6f706710dc7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 9 Dec 2015 08:24:44 -0500 Subject: [PATCH 0966/1342] build: Rework how MULTIPATH_NUM is delivered to build Changes made here: 1) MULTIPATH_NUM will never be 0. If user specifies --enable-multipath=0 then this translates to MULTIPATH_NUM being set to 64 inside of the build system. 2) Move MULTIPATH_NUM from a Makefile construct to a config.h construct. 3) Allowed MULTIPATH_NUM to be a number > 99 but < 1000 Signed-off-by: Donald Sharp --- bgpd/Makefile.am | 2 +- configure.ac | 11 +++++++---- zebra/Makefile.am | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 7da4dd873..d2775f39d 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) diff --git a/configure.ac b/configure.ac index b4d934b63..7aaacb96d 100755 --- a/configure.ac +++ b/configure.ac @@ -379,11 +379,14 @@ AC_DEFINE_UNQUOTED(CONFIGFILE_MASK, ${enable_configfile_mask}, Mask for config f enable_logfile_mask=${enable_logfile_mask:-0600} AC_DEFINE_UNQUOTED(LOGFILE_MASK, ${enable_logfile_mask}, Mask for log files) -MULTIPATH_NUM=1 +MPATH_NUM=1 case "${enable_multipath}" in - [[0-9]|[1-9][0-9]]) - MULTIPATH_NUM="${enable_multipath}" + 0) + MPATH_NUM=64 + ;; + [[1-9]|[1-9][0-9]|[1-9][0-9][0-9]]) + MPATH_NUM="${enable_multipath}" ;; "") ;; @@ -392,7 +395,7 @@ case "${enable_multipath}" in ;; esac -AC_SUBST(MULTIPATH_NUM) +AC_DEFINE_UNQUOTED(MULTIPATH_NUM, $MPATH_NUM, Maximum number of paths for a route) dnl ----------------------------------- dnl Add extra version string to package diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 96dc6f035..90ce7b97d 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 LIBCAP = @LIBCAP@ From 91ce87aacfd8718b5a52fb0f4453e9f72d8bdb53 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 9 Dec 2015 08:24:45 -0500 Subject: [PATCH 0967/1342] zebra, bgpd: Fixup MULTIPATH_NUM usage to not consider 0 The code has spots where MULTIPATH_NUM set to 0 is equal to 64. Now that MULTIPATH_NUM is set from the makefile to never be 0, remove the code that depends on this. Signed-off-by: Donald Sharp --- bgpd/bgp_vty.c | 4 ++-- zebra/rt_netlink.c | 2 +- zebra/zebra_fpm_netlink.c | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 987ff298c..18a22264b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -737,7 +737,7 @@ DEFUN (bgp_maxpaths, return CMD_WARNING; } - if ((MULTIPATH_NUM != 0) && (maxpaths > MULTIPATH_NUM)) + if (maxpaths > MULTIPATH_NUM) vty_out (vty, "%% Warning: maximum-paths set to %d is greater than %d that zebra is compiled to support%s", maxpaths, MULTIPATH_NUM, VTY_NEWLINE); @@ -770,7 +770,7 @@ DEFUN (bgp_maxpaths_ibgp, return CMD_WARNING; } - if ((MULTIPATH_NUM != 0) && (maxpaths > MULTIPATH_NUM)) + if (maxpaths > MULTIPATH_NUM) vty_out (vty, "%% Warning: maximum-paths set to %d is greater than %d that zebra is compiled to support%s", maxpaths, MULTIPATH_NUM, VTY_NEWLINE); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2539d614a..e4505de33 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1809,7 +1809,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { - if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM) + if (nexthop_num >= MULTIPATH_NUM) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index c4a650d6e..01730007f 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -136,10 +136,9 @@ typedef struct netlink_route_info_t_ int num_nhs; /* - * Nexthop structures. We keep things simple for now by enforcing a - * maximum of 64 in case MULTIPATH_NUM is 0; + * Nexthop structures */ - netlink_nh_info_t nhs[MAX (MULTIPATH_NUM, 64)]; + netlink_nh_info_t nhs[MULTIPATH_NUM]; union g_addr *pref_src; } netlink_route_info_t; @@ -287,7 +286,7 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd, for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { - if (MULTIPATH_NUM != 0 && ri->num_nhs >= MULTIPATH_NUM) + if (ri->num_nhs >= MULTIPATH_NUM) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) From b2a2fd788f34a4f5d1bbd92a283e47704f05ae8f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 9 Dec 2015 08:24:46 -0500 Subject: [PATCH 0968/1342] lib: Add CMD_RANGE_STR macro to command.h Allow the auto-generation of a "" string for cli handline. Where X or Y can be a #define. CMD_RANGE_STR(LOW, HIGH) translates to: "<4-99>" Signed-off-by: Donald Sharp --- lib/command.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/command.h b/lib/command.h index fd55f2d54..6a20e2324 100644 --- a/lib/command.h +++ b/lib/command.h @@ -459,6 +459,17 @@ struct cmd_token #endif /* VTYSH_EXTRACT_PL */ +/* + * Sometimes #defines create maximum values that + * need to have strings created from them that + * allow the parser to match against them. + * These macros allow that. + */ +#define CMD_CREATE_STR(s) CMD_CREATE_STR_HELPER(s) +#define CMD_CREATE_STR_HELPER(s) #s +#define CMD_RANGE_STR(a,s) "<" CMD_CREATE_STR(a) "-" CMD_CREATE_STR(s) ">" + + /* Common descriptions. */ #define SHOW_STR "Show running system information\n" #define IP_STR "IP information\n" From ecc1a136e10e0717761b6f436d299938a05a1309 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 9 Dec 2015 08:24:47 -0500 Subject: [PATCH 0969/1342] bgpd: Modify maxpaths cli's to use MULTIPATH_NUM for range Modify the various maxpath commands to use MULTIPATH_NUM as the upper limit of allowed max paths in BGP. There is no point in allowing a number of maximum paths greater than what Quagga is compiled for. Signed-off-by: Donald Sharp Tested-by: NetDEF CI System --- bgpd/bgp_vty.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 18a22264b..6db3dcb1c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -715,7 +715,7 @@ DEFUN (no_bgp_confederation_peers, /* Maximum-paths configuration */ DEFUN (bgp_maxpaths, bgp_maxpaths_cmd, - "maximum-paths <1-255>", + "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), "Forward packets over multiple paths\n" "Number of paths\n") { @@ -737,17 +737,12 @@ DEFUN (bgp_maxpaths, return CMD_WARNING; } - if (maxpaths > MULTIPATH_NUM) - vty_out (vty, - "%% Warning: maximum-paths set to %d is greater than %d that zebra is compiled to support%s", - maxpaths, MULTIPATH_NUM, VTY_NEWLINE); - return CMD_SUCCESS; } DEFUN (bgp_maxpaths_ibgp, bgp_maxpaths_ibgp_cmd, - "maximum-paths ibgp <1-255>", + "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM), "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") @@ -770,11 +765,6 @@ DEFUN (bgp_maxpaths_ibgp, return CMD_WARNING; } - if (maxpaths > MULTIPATH_NUM) - vty_out (vty, - "%% Warning: maximum-paths set to %d is greater than %d that zebra is compiled to support%s", - maxpaths, MULTIPATH_NUM, VTY_NEWLINE); - return CMD_SUCCESS; } @@ -805,7 +795,7 @@ DEFUN (no_bgp_maxpaths, ALIAS (no_bgp_maxpaths, no_bgp_maxpaths_arg_cmd, - "no maximum-paths <1-255>", + "no maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), NO_STR "Forward packets over multiple paths\n" "Number of paths\n") @@ -838,7 +828,7 @@ DEFUN (no_bgp_maxpaths_ibgp, ALIAS (no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_arg_cmd, - "no maximum-paths ibgp <1-255>", + "no maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM), NO_STR "Forward packets over multiple paths\n" "iBGP-multipath\n" From e98dce60cea213a4155a0db60b463e40c67aa77f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 20 Jan 2016 07:53:51 -0500 Subject: [PATCH 0970/1342] bgpd: Fix Null pointer dereference in bgp_info_mpath_update bgp_info_mpath_update is called with new_best == NULL, this causes the dereference of new_best in order to get at the mpath_cfg. Signed-off-by: Donald Sharp --- bgpd/bgp_mpath.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 73b93cebb..8e78aafe0 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -428,6 +428,7 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN]; + struct bgp_maxpaths_cfg *mpath_cfg = NULL; mpath_changed = 0; maxpaths = BGP_DEFAULT_MAXPATHS; @@ -436,16 +437,15 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, old_mpath_count = 0; prev_mpath = new_best; mp_node = listhead (mp_list); - struct bgp_maxpaths_cfg *mpath_cfg; - debug = BGP_DEBUG (events, EVENTS); - mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi]; + debug = BGP_DEBUG (events, EVENTS); if (debug) prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf)); if (new_best) { + mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi]; mpath_count++; if (new_best != old_best) bgp_info_mpath_dequeue (new_best); From c49a2747f6a6199dba27c0c413f4de6112fa649e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 5 Feb 2016 14:57:17 +0000 Subject: [PATCH 0971/1342] bgpd: make bgp_nlri_parse_encap conform with other nlri_parse funcs * bgp_encap.{c,h} (bgp_nlri_parse_encap) afi is already in the NLRI argument. update or withdraw is signalled by attr being non-NULL or NULL. * bgp_packet.c: (update_receive) fixup to match, and also make the attr argument conform with NLRI_ATTR_ARG for correct error handling on optional, transitive, partial, attributes. --- bgpd/bgp_encap.c | 7 +++---- bgpd/bgp_encap.h | 7 +------ bgpd/bgp_packet.c | 8 ++++---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index d0beb1ba6..1a09ba601 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -126,14 +126,13 @@ ecom2prd(struct ecommunity *ecom, struct prefix_rd *prd) int bgp_nlri_parse_encap( - afi_t afi, struct peer *peer, struct attr *attr, /* Need even for withdraw */ - struct bgp_nlri *packet, - int withdraw) /* 0=update, !0 = withdraw */ + struct bgp_nlri *packet) { u_char *pnt; u_char *lim; + afi_t afi = packet->afi; struct prefix p; int psize = 0; int prefixlen; @@ -227,7 +226,7 @@ bgp_nlri_parse_encap( inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); - if (!withdraw) { + if (attr) { bgp_update (peer, &p, attr, afi, SAFI_ENCAP, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } else { diff --git a/bgpd/bgp_encap.h b/bgpd/bgp_encap.h index 6f43b7b3b..7442c73c4 100644 --- a/bgpd/bgp_encap.h +++ b/bgpd/bgp_encap.h @@ -23,12 +23,7 @@ #define _QUAGGA_BGP_ENCAP_H extern void bgp_encap_init (void); -extern int bgp_nlri_parse_encap ( - afi_t, - struct peer *, - struct attr *, - struct bgp_nlri *, - int withdraw); +extern int bgp_nlri_parse_encap (struct peer *, struct attr *, struct bgp_nlri *); #include "bgp_encap_types.h" #endif /* _QUAGGA_BGP_ENCAP_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 26e4d8ffc..b8a38fa56 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1943,12 +1943,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (mp_update.afi, peer, &attr, &mp_update, 0); + bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (mp_withdraw.afi, peer, &attr, &mp_withdraw, 1); + bgp_nlri_parse_encap (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP @@ -1967,12 +1967,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (mp_update.afi, peer, &attr, &mp_update, 0); + bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (mp_withdraw.afi, peer, &attr, &mp_withdraw, 1); + bgp_nlri_parse_encap (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP6 From 18ab08b71e6b29e67b36df5e2261569d381b1708 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 27 Jan 2016 16:37:33 +0000 Subject: [PATCH 0972/1342] bgpd: Regularise BGP NLRI sanity checks a bit * bgp_route.h: (bgp_nlri_sanity_check) The bulk of the args are equivalent to a (struct bgp_nlri), consolidate. * bgp_route.c: (bgp_nlri_sanity_check) Make this a frontend for all afi/safis. Including SAFI_MPLS_LABELED_VPN. (bgp_nlri_sanity_check_ip) Regular IP NLRI sanity check based on the existing code, and adjusted for (struct bgp_nlri *) arg. * bgp_attr.c: (bgp_mp_reach_parse) Adjust for passing (struct bgp_nlri *) to bgp_nlri_sanity_check. Get rid of special-casing to not sanity check VPN. (bgp_mp_unreach_parse) Ditto. * bgp_mplsvpn.c: Use the same VPN parsing code for both the sanity check and the actual parse. (bgp_nlri_parse_vpn) renamed to bgp_nlri_parse_vpn_body and made internal. (bgp_nlri_parse_vpn_body) Added (bool) argument to control whether it is sanity checking or whether it should update routing state for each NLRI. Send a NOTIFY and reset the session, if there's a parsing error, as bgp_nlri_sanity_check_ip does, and as is required by the RFC. (bgp_nlri_parse_vpn) now a wrapper to call _body with update. (bgp_nlri_sanity_check_vpn) wrapper to call parser without updating. * bgp_mplsvpn.h: (bgp_nlri_sanity_check_vpn) export for bgp_nlri_sanity_check. * bgp_packet.c: (bgp_update_receive) Adjust for bgp_nlri_sanity_check argument changes. * test/bgp_mp_attr_test.c: Extend to also test the NLRI parsing functions, if the initial MP-attr parsing has succeeded. Fix the NLRI in the VPN cases. Add further VPN tests. * tests/bgpd.tests/testbgpmpattr.exp: Add the new test cases. This commit a joint effort of: Lou Berger Donald Sharp Paul Jakma / --- bgpd/bgp_attr.c | 32 ++- bgpd/bgp_mplsvpn.c | 80 ++++++-- bgpd/bgp_mplsvpn.h | 1 + bgpd/bgp_packet.c | 23 ++- bgpd/bgp_route.c | 26 ++- bgpd/bgp_route.h | 2 +- tests/bgp_mp_attr_test.c | 316 +++++++++++++++++++++++++---- tests/bgpd.tests/testbgpmpattr.exp | 11 +- 8 files changed, 390 insertions(+), 101 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 888f11a19..98571dab5 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1725,23 +1725,20 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } - - if (safi != SAFI_MPLS_LABELED_VPN) - { - ret = bgp_nlri_sanity_check (peer, afi, safi, stream_pnt (s), nlri_len); - if (ret < 0) - { - zlog_info ("%s: (%s) NLRI doesn't pass sanity check", - __func__, peer->host); - return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; - } - } - + mp_update->afi = afi; mp_update->safi = safi; mp_update->nlri = stream_pnt (s); mp_update->length = nlri_len; + ret = bgp_nlri_sanity_check (peer, mp_update); + if (ret < 0) + { + zlog_info ("%s: (%s) NLRI doesn't pass sanity check", + __func__, peer->host); + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; + } + stream_forward_getp (s, nlri_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI); @@ -1759,7 +1756,6 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, afi_t afi; safi_t safi; u_int16_t withdraw_len; - int ret; struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; @@ -1775,18 +1771,14 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; - if (safi != SAFI_MPLS_LABELED_VPN) - { - ret = bgp_nlri_sanity_check (peer, afi, safi, stream_pnt (s), withdraw_len); - if (ret < 0) - return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; - } - mp_withdraw->afi = afi; mp_withdraw->safi = safi; mp_withdraw->nlri = stream_pnt (s); mp_withdraw->length = withdraw_len; + if (bgp_nlri_sanity_check (peer, mp_withdraw) < 0) + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; + stream_forward_getp (s, withdraw_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index f8b43df88..900bc4875 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -32,6 +32,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_packet.h" static u_int16_t decode_rd_type (u_char *pnt) @@ -91,9 +92,9 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) rd_ip->val |= (u_int16_t) *pnt; } -int -bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, - struct bgp_nlri *packet) +static int +bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, bool update) { u_char *pnt; u_char *lim; @@ -129,30 +130,53 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, psize = PSIZE (prefixlen); /* sanity check against packet data */ - if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8 || (pnt + psize) > lim) + if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8) + { + plog_err (peer->log, + "%s [Error] Update packet error / VPNv4" + " (prefix length %d less than VPNv4 min length)", + peer->host, prefixlen); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + return -1; + } + if ((pnt + psize) > lim) { - zlog_err ("prefix length (%d) is less than 88" - " or larger than received (%u)", + plog_err (peer->log, + "%s [Error] Update packet error / VPNv4" + " (psize %u exceeds packet size (%u)", + peer->host, prefixlen, (uint)(lim-pnt)); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } /* sanity check against storage for the IP address portion */ if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u)) { - zlog_err ("prefix length (%d) exceeds prefix storage (%zu)", + plog_err (peer->log, + "%s [Error] Update packet error / VPNv4" + " (psize %u exceeds storage size (%zu)", + peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u)); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } /* Sanity check against max bitlen of the address family */ if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p)) { - zlog_err ("prefix length (%d) exceeds family (%u) max byte length (%u)", + plog_err (peer->log, + "%s [Error] Update packet error / VPNv4" + " (psize %u exceeds family (%u) max byte len %u)", + peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, p.family, prefix_blen (&p)); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; - } /* Copyr label to prefix. */ @@ -187,21 +211,45 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, psize - VPN_PREFIXLEN_MIN_BYTES); - if (attr) - bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); - else - bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + if (update) + { + if (attr) + bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); + else + bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + } } /* Packet length consistency check. */ if (pnt != lim) - return -1; + { + plog_err (peer->log, + "%s [Error] Update packet error / VPNv4" + " (%zu data remaining after parsing)", + peer->host, lim - pnt); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + return -1; + } return 0; #undef VPN_PREFIXLEN_MIN_BYTES } +int +bgp_nlri_sanity_check_vpn (struct peer *peer, struct bgp_nlri *nlri) +{ + return bgp_nlri_parse_vpn_body (peer, NULL, nlri, false); +} + +int +bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) +{ + return bgp_nlri_parse_vpn_body (peer, attr, packet, true); +} + int str2prefix_rd (const char *str, struct prefix_rd *prd) { diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 3299b9cb9..b89b6d8ac 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -43,6 +43,7 @@ struct rd_ip extern void bgp_mplsvpn_init (void); extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *); +extern int bgp_nlri_sanity_check_vpn (struct peer *, struct bgp_nlri *); extern u_int32_t decode_label (u_char *); extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index b8a38fa56..d40c24c2c 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1660,17 +1660,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { - ret = bgp_nlri_sanity_check (peer, AFI_IP, SAFI_UNICAST, stream_pnt (s), withdraw_len); + withdraw.afi = AFI_IP; + withdraw.safi = SAFI_UNICAST; + withdraw.nlri = stream_pnt (s); + withdraw.length = withdraw_len; + ret = bgp_nlri_sanity_check (peer, &withdraw); if (ret < 0) return -1; if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); - withdraw.afi = AFI_IP; - withdraw.safi = SAFI_UNICAST; - withdraw.nlri = stream_pnt (s); - withdraw.length = withdraw_len; stream_forward_getp (s, withdraw_len); } @@ -1751,8 +1751,14 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (update_len) { + /* Set NLRI portion to structure. */ + update.afi = AFI_IP; + update.safi = SAFI_UNICAST; + update.nlri = stream_pnt (s); + update.length = update_len; + /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, AFI_IP, SAFI_UNICAST, stream_pnt (s), update_len); + ret = bgp_nlri_sanity_check (peer, &update); if (ret < 0) { bgp_attr_unintern_sub (&attr); @@ -1760,11 +1766,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) return -1; } - /* Set NLRI portion to structure. */ - update.afi = AFI_IP; - update.safi = SAFI_UNICAST; - update.nlri = stream_pnt (s); - update.length = update_len; stream_forward_getp (s, update_len); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0dcae61ea..c1e5e59b1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3322,16 +3322,16 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) return 0; } -/* NLRI encode syntax check routine. */ -int -bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi, - u_char *pnt, bgp_size_t length) +static int +bgp_nlri_sanity_check_ip (struct peer *peer, struct bgp_nlri *nlri) { u_char *end; u_char prefixlen; int psize; - - end = pnt + length; + u_char *pnt = nlri->nlri; + afi_t afi = nlri->afi; + safi_t safi = nlri->safi; + end = pnt + nlri->length; /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for syntactic validity. If the field is syntactically incorrect, @@ -3395,6 +3395,20 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi, return 0; } +int +bgp_nlri_sanity_check (struct peer *peer, struct bgp_nlri *nlri) +{ + switch (nlri->safi) + { + case SAFI_MPLS_LABELED_VPN: + return bgp_nlri_sanity_check_vpn (peer, nlri); + case SAFI_UNICAST: + case SAFI_MULTICAST: + return bgp_nlri_sanity_check_ip (peer, nlri); + default: return -1; + } +} + static struct bgp_static * bgp_static_new (void) { diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 8e9bcbd1c..c16eca7bb 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -196,7 +196,7 @@ extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *); extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); -extern int bgp_nlri_sanity_check (struct peer *, int, safi_t, u_char *, bgp_size_t); +extern int bgp_nlri_sanity_check (struct peer *, struct bgp_nlri *); extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 6dc6757cd..39f3b0da1 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -31,6 +31,9 @@ #include "bgpd/bgp_attr.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_nexthop.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" @@ -308,8 +311,34 @@ static struct test_segment { SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, - { "IPv4-MLVPN", - "IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs", + { "IPv4-VPNv4", + "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 16, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), + SHOULD_PARSE, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + { "IPv4-VPNv4-bogus-plen", + "IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, NLRI / bogus p'len", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, @@ -321,10 +350,169 @@ static struct test_segment { 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, - (4 + 12 + 1 + 3 + 4 + 1), + (3 + 1 + 3*4 + 1 + 3 + 4 + 1), + SHOULD_ERR, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + { "IPv4-VPNv4-plen1-short", + "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen short", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 1, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), + SHOULD_ERR, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + { "IPv4-VPNv4-plen1-long", + "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen long", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 32, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), + SHOULD_ERR, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + { "IPv4-VPNv4-plenn-long", + "IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRIs, last plen long", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 16, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + 88 + 1, /* bogus */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3) + 1), + SHOULD_ERR, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + { "IPv4-VPNv4-plenn-short", + "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, last plen short", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 16, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 2, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), + SHOULD_ERR, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + { "IPv4-VPNv4-bogus-rd-type", + "IPv4/VPNv4 MP Reach, RD, NH, 2 NLRI, unknown RD in 1st (log, but parse)", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 16, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0xff, 0, /* Bogus RD */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), SHOULD_PARSE, - AFI_IP, SAFI_UNICAST, VALID_AFI, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, + { "IPv4-VPNv4-0-nlri", + "IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRI, 3rd 0 bogus", + { + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, + /* nexthop bytes */ 12, + /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ + 0, 0, 0, 0, + /* Nexthop */ 192, 168, 0, 1, + /* SNPA (defunct, MBZ) */ 0x0, + /* NLRI tuples */ 88 + 16, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ + 0 /* 0/0, bogus for vpnv4 ?? */ + }, + (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3) + 1), + SHOULD_ERR, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, + }, + /* From bug #385 */ { "IPv6-bug", "IPv6, global nexthop, 1 default NLRI", @@ -431,33 +619,79 @@ static struct test_segment mp_unreach_segments [] = SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, - { "IPv4-unreach-MLVPN", + { "IPv4-unreach-VPNv4", "IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, - /* nexthop bytes */ 12, - /* RD */ 0, 0, 1, 2, - 0, 0xff, 3, 4, - /* Nexthop */ 192, 168, 0, 1, - /* SNPA (defunct, MBZ) */ 0x0, - /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ - 17, 10, 2, 3, /* 10.2.3/17 */ - 0, /* 0/0 */ + /* NLRI tuples */ 88 + 16, + 0, 1, 2, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_AS */ + 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ + 10, 1, /* 10.1/16 */ + 88 + 17, + 0xff, 0, 0, /* tag */ + /* rd, 8 octets */ + 0, 0, /* RD_TYPE_IP */ + 192, 168, 0, 1, /* IPv4 */ + 10, 2, 3, /* 10.2.3/17 */ }, - (3 + 3 + 4 + 1), + (3 + (1+3+8+2) + (1+3+8+3)), SHOULD_PARSE, - AFI_IP, SAFI_UNICAST, VALID_AFI, + AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; +/* nlri_parse indicates 0 on successful parse, and -1 otherwise. + * attr_parse indicates BGP_ATTR_PARSE_PROCEED/0 on success, + * and BGP_ATTR_PARSE_ERROR/-1 or lower negative ret on err. + */ +static void +handle_result (struct peer *peer, struct test_segment *t, + int parse_ret, int nlri_ret) +{ + int oldfailed = failed; + + if (!parse_ret) + { + safi_t safi = t->safi; + + if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) + failed++; + + printf ("MP: %u/%u (%u): recv %u, nego %u\n", + t->afi, t->safi, safi, + peer->afc_recv[t->afi][safi], + peer->afc_nego[t->afi][safi]); + } + + printf ("mp attr parsed?: %s\n", parse_ret ? "no" : "yes"); + if (!parse_ret) + printf ("nrli parsed?: %s\n", nlri_ret ? "no" : "yes"); + printf ("should parse?: %s\n", t->parses ? "no" : "yes"); + + if ((parse_ret != 0 || nlri_ret != 0) != (t->parses != 0)) + failed++; + + + if (tty) + printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET + : VT100_GREEN "OK" VT100_RESET); + else + printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); + + if (failed) + printf (" (%u)", failed); + + printf ("\n\n"); +} /* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { - int ret; - int oldfailed = failed; + int parse_ret = 0, nlri_ret = 0; struct attr attr = { }; struct bgp_nlri nlri = { }; struct bgp_attr_parser_args attr_args = { @@ -465,7 +699,7 @@ parse_test (struct peer *peer, struct test_segment *t, int type) .length = t->len, .total = 1, .attr = &attr, - .type = BGP_ATTR_MP_REACH_NLRI, + .type = type, .flags = BGP_ATTR_FLAG_OPTIONAL, .startp = BGP_INPUT_PNT (peer), }; @@ -479,40 +713,29 @@ parse_test (struct peer *peer, struct test_segment *t, int type) printf ("%s: %s\n", t->name, t->desc); - if (type == BGP_ATTR_MP_REACH_NLRI) - ret = bgp_mp_reach_parse (&attr_args, &nlri); + parse_ret = bgp_mp_reach_parse (&attr_args, &nlri); else - ret = bgp_mp_unreach_parse (&attr_args, &nlri); - - if (!ret) + parse_ret = bgp_mp_unreach_parse (&attr_args, &nlri); + + if (parse_ret == 0 && t->afi_valid == VALID_AFI) + assert (nlri.afi == t->afi && nlri.safi == t->safi); + + if (!parse_ret) { - safi_t safi = t->safi; + int (*f) (struct peer *, struct attr *, struct bgp_nlri *) + = bgp_nlri_parse; - if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) - failed++; + if (t->safi == SAFI_MPLS_LABELED_VPN) + f = bgp_nlri_parse_vpn; - printf ("MP: %u/%u (%u): recv %u, nego %u\n", - t->afi, t->safi, safi, - peer->afc_recv[t->afi][safi], - peer->afc_nego[t->afi][safi]); + if (type == BGP_ATTR_MP_REACH_NLRI) + nlri_ret = f (peer, &attr, &nlri); + else + nlri_ret = f (peer, NULL, &nlri); } - printf ("parsed?: %s\n", ret ? "no" : "yes"); - - if ((ret == 0) != (t->parses == 0)) - failed++; - - if (tty) - printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET - : VT100_GREEN "OK" VT100_RESET); - else - printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); - - if (failed) - printf (" (%u)", failed); - - printf ("\n\n"); + handle_result (peer, t, parse_ret, nlri_ret); } static struct bgp *bgp; @@ -538,6 +761,8 @@ main (void) master = thread_master_create (); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); + bgp_attr_init (); + bgp_address_init (); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); @@ -547,6 +772,7 @@ main (void) peer = peer_create_accept (bgp); peer->host = (char *)"foo"; + peer->status = Established; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) diff --git a/tests/bgpd.tests/testbgpmpattr.exp b/tests/bgpd.tests/testbgpmpattr.exp index 646bbe506..e6d7305a6 100644 --- a/tests/bgpd.tests/testbgpmpattr.exp +++ b/tests/bgpd.tests/testbgpmpattr.exp @@ -19,7 +19,14 @@ simpletest "IPv6-nlri: IPV6 MP Reach, NLRI bitlen overflow" simpletest "IPv4: IPv4 MP Reach, 2 NLRIs + default" simpletest "IPv4-nhlen: IPv4 MP Reach, nexthop lenth overflow" simpletest "IPv4-nlrilen: IPv4 MP Reach, nlri lenth overflow" -simpletest "IPv4-MLVPN: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs" +simpletest "IPv4-VPNv4: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs" +simpletest "IPv4-VPNv4-bogus-plen: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, NLRI / bogus p'len" +simpletest "IPv4-VPNv4-plen1-short: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen short" +simpletest "IPv4-VPNv4-plen1-long: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen long" +simpletest "IPv4-VPNv4-plenn-long: IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRIs, last plen long" +simpletest "IPv4-VPNv4-plenn-short: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, last plen short" +simpletest "IPv4-VPNv4-bogus-rd-type: IPv4/VPNv4 MP Reach, RD, NH, 2 NLRI, unknown RD in 1st (log, but parse)" +simpletest "IPv4-VPNv4-0-nlri: IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRI, 3rd 0 bogus" simpletest "IPv6-bug: IPv6, global nexthop, 1 default NLRI" simpletest "IPv6-unreach: IPV6 MP Unreach, 1 NLRI" simpletest "IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs" @@ -27,5 +34,5 @@ simpletest "IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default" simpletest "IPv6-unreach-nlri: IPV6 MP Unreach, NLRI bitlen overflow" simpletest "IPv4-unreach: IPv4 MP Unreach, 2 NLRIs + default" simpletest "IPv4-unreach-nlrilen: IPv4 MP Unreach, nlri length overflow" -simpletest "IPv4-unreach-MLVPN: IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs" +simpletest "IPv4-unreach-VPNv4: IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs" From 518a4b7eadcba567f01061e6659d8179380efcdf Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 4 Feb 2016 13:27:04 +0000 Subject: [PATCH 0973/1342] bgpd: Regularise bgp_update_receive, add missing notifies and checks * bgp_packet.c: (bgp_update_receive) Lots of repeated code, doing same thing for each AFI/SAFI. Except when it doesn't, e.g. the IPv4/VPN case was missing the EoR bgp_clear_stale_route call - the only action really needed for EoR. Make this function a lot more regular, using common, AFI/SAFI independent blocks so far as possible. Replace the 4 separate bgp_nlris with an array, indexed by an enum. The distinct blocks that handle calling bgp_nlri_parse for each different AFI/SAFI can now be replaced with a loop. Transmogrify the nlri SAFI from the SAFI_MPLS_LABELED_VPN code-point used on the wire, to the SAFI_MPLS_VPN safi_t enum we use internally as early as possible. The existing code was not necessarily sending a NOTIFY for NLRI parsing errors, if they arose via bgp_nlri_sanity_check. Send the correct NOTIFY - INVAL_NETWORK for the classic NLRIs and OPT_ATTR_ERR for the MP ones. EoR can now be handled in one block. The existing code seemed broken for EoR recognition in a number of ways: 1. A v4/unicast EoR should be an empty UPDATE. However, it seemed to be treating an UPDATE with attributes, inc. MP REACH/UNREACH, but no classic NLRIs, as a v4/uni EoR. 2. For other AFI/SAFIs, it was treating UPDATEs with no classic withraw and with a zero-length MP withdraw as EoRs. However, that would mean an UPDATE packet _with_ update NLRIs and a 0-len MP withdraw could be classed as an EoR. This seems to be loose coding leading to ambiguous protocol situations and likely incorrect behaviour, rather than simply being liberal. Be more strict about checking that an UPDATE really is an EoR and definitely is not trying to update any NLRIs. This same loose EoR parsing was noted by Chris Hall previously on list. (bgp_nlri_parse) Front end NLRI parse function, to fan-out to the correct parser for the AFI/SAFI. * bgp_route.c: (bgp_nlri_sanity_check) We try convert NLRI safi to internal code-point ASAP, adjust switch for that. Leave the wire code point in for defensive coding. (bgp_nlri_parse) rename to bgp_nlri_parse_ip. * tests/bgp_mp_attr_test.c: Can just use bgp_nlri_parse frontend. --- bgpd/bgp_mplsvpn.c | 1 + bgpd/bgp_packet.c | 386 +++++++++++++++------------------------ bgpd/bgp_packet.h | 2 + bgpd/bgp_route.c | 4 +- bgpd/bgp_route.h | 2 +- tests/bgp_mp_attr_test.c | 11 +- 6 files changed, 162 insertions(+), 244 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 900bc4875..83bb6ca9d 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_packet.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_packet.h" diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d40c24c2c..628c333ab 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1591,11 +1591,29 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) return 0; } +/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */ +int +bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +{ + switch (packet->safi) + { + case SAFI_UNICAST: + case SAFI_MULTICAST: + return bgp_nlri_parse_ip (peer, attr, packet); + case SAFI_MPLS_VPN: + case SAFI_MPLS_LABELED_VPN: + return bgp_nlri_parse_vpn (peer, attr, packet); + case SAFI_ENCAP: + return bgp_nlri_parse_encap (peer, attr, packet); + } + return -1; +} + /* Parse BGP Update packet and make attribute object. */ static int bgp_update_receive (struct peer *peer, bgp_size_t size) { - int ret; + int ret, nlri_ret; u_char *end; struct stream *s; struct attr attr; @@ -1603,10 +1621,16 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; - struct bgp_nlri update; - struct bgp_nlri withdraw; - struct bgp_nlri mp_update; - struct bgp_nlri mp_withdraw; + int i; + + enum NLRI_TYPES { + NLRI_UPDATE, + NLRI_WITHDRAW, + NLRI_MP_UPDATE, + NLRI_MP_WITHDRAW, + NLRI_TYPE_MAX, + }; + struct bgp_nlri nlris[NLRI_TYPE_MAX]; /* Status must be Established. */ if (peer->status != Established) @@ -1620,10 +1644,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Set initial values. */ memset (&attr, 0, sizeof (struct attr)); memset (&extra, 0, sizeof (struct attr_extra)); - memset (&update, 0, sizeof (struct bgp_nlri)); - memset (&withdraw, 0, sizeof (struct bgp_nlri)); - memset (&mp_update, 0, sizeof (struct bgp_nlri)); - memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); + memset (&nlris, 0, sizeof nlris); attr.extra = &extra; s = peer->ibuf; @@ -1660,14 +1681,18 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { - withdraw.afi = AFI_IP; - withdraw.safi = SAFI_UNICAST; - withdraw.nlri = stream_pnt (s); - withdraw.length = withdraw_len; - ret = bgp_nlri_sanity_check (peer, &withdraw); - if (ret < 0) - return -1; - + nlris[NLRI_WITHDRAW].afi = AFI_IP; + nlris[NLRI_WITHDRAW].safi = SAFI_UNICAST; + nlris[NLRI_WITHDRAW].nlri = stream_pnt (s); + nlris[NLRI_WITHDRAW].length = withdraw_len; + + if (bgp_nlri_sanity_check (peer, &nlris[NLRI_WITHDRAW]) < 0) + { + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); @@ -1716,7 +1741,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (attribute_len) { attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, - &mp_update, &mp_withdraw); + &nlris[NLRI_MP_UPDATE], &nlris[NLRI_MP_WITHDRAW]); if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) { bgp_attr_unintern_sub (&attr); @@ -1752,15 +1777,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (update_len) { /* Set NLRI portion to structure. */ - update.afi = AFI_IP; - update.safi = SAFI_UNICAST; - update.nlri = stream_pnt (s); - update.length = update_len; + nlris[NLRI_UPDATE].afi = AFI_IP; + nlris[NLRI_UPDATE].safi = SAFI_UNICAST; + nlris[NLRI_UPDATE].nlri = stream_pnt (s); + nlris[NLRI_UPDATE].length = update_len; /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, &update); + ret = bgp_nlri_sanity_check (peer, &nlris[NLRI_UPDATE]); if (ret < 0) { + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); bgp_attr_unintern_sub (&attr); bgp_attr_flush (&attr); return -1; @@ -1768,226 +1795,117 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) stream_forward_getp (s, update_len); } - - /* NLRI is processed only when the peer is configured specific - Address Family and Subsequent Address Family. */ - if (peer->afc[AFI_IP][SAFI_UNICAST]) - { - if (withdraw.length) - bgp_nlri_parse (peer, NULL, &withdraw); - - if (update.length) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); - - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! attribute_len && ! withdraw_len) - { - /* End-of-RIB received */ - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], - PEER_STATUS_EOR_RECEIVED); - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP][SAFI_UNICAST]) - bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST); - - if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s", - peer->host); - } + + /* Parse any given NLRIs */ + for (i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) + { + /* We use afi and safi as indices into tables and what not. It would + * be impossible, at this time, to support unknown afi/safis. And + * anyway, the peer needs to be configured to enable the afi/safi + * explicitly which requires UI support. + * + * Ignore unknown afi/safi NLRIs. + * + * Note: this means nlri[x].afi/safi still can not be trusted for + * indexing later in this function! + * + * Note2: This will also remap the wire code-point for VPN safi to the + * internal safi_t point, as needs be. + */ + if (!bgp_afi_safi_valid_indices (nlris[i].afi, &nlris[i].safi)) + { + plog_info (peer->log, + "%s [Info] UPDATE with unsupported AFI/SAFI %u/%u", + peer->host, nlris[i].afi, nlris[i].safi); + continue; + } + + /* NLRI is processed only when the peer is configured specific + Address Family and Subsequent Address Family. */ + if (!peer->afc[nlris[i].afi][nlris[i].safi]) + { + plog_info (peer->log, + "%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u", + peer->host, nlris[i].afi, nlris[i].safi); + continue; + } + + /* EoR handled later */ + if (nlris[i].length == 0) + continue; + + switch (i) + { + case NLRI_UPDATE: + case NLRI_MP_UPDATE: + nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]); + break; + case NLRI_WITHDRAW: + case NLRI_MP_WITHDRAW: + nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]); + } + + if (nlri_ret < 0) + { + plog_err (peer->log, + "%s [Error] Error parsing NLRI", peer->host); + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + i <= NLRI_WITHDRAW + ? BGP_NOTIFY_UPDATE_INVAL_NETWORK + : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + bgp_attr_unintern_sub (&attr); + return -1; + } } - if (peer->afc[AFI_IP][SAFI_MULTICAST]) + + /* EoR checks. + * + * Non-MP IPv4/Unicast EoR is a completely empty UPDATE + * and MP EoR should have only an empty MP_UNREACH + */ + if (!update_len && !withdraw_len + && nlris[NLRI_MP_UPDATE].length == 0) { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MULTICAST - && mp_withdraw.length == 0) - { + afi_t afi = 0; + safi_t safi; + + /* Non-MP IPv4/Unicast is a completely empty UPDATE - already + * checked update and withdraw NLRI lengths are 0. + */ + if (!attribute_len) + { + afi = AFI_IP; + safi = SAFI_UNICAST; + } + /* otherwise MP AFI/SAFI is an empty update, other than an empty + * MP_UNREACH_NLRI attr (with an AFI/SAFI we recognise). + */ + else if (attr.flag == BGP_ATTR_MP_UNREACH_NLRI + && nlris[NLRI_MP_WITHDRAW].length == 0 + && bgp_afi_safi_valid_indices (nlris[NLRI_MP_WITHDRAW].afi, + &nlris[NLRI_MP_WITHDRAW].safi)) + { + afi = nlris[NLRI_MP_WITHDRAW].afi; + safi = nlris[NLRI_MP_WITHDRAW].safi; + } + + if (afi && peer->afc[afi][safi]) + { /* End-of-RIB received */ - SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ - if (peer->nsf[AFI_IP][SAFI_MULTICAST]) - bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); + if (peer->nsf[afi][safi]) + bgp_clear_stale_route (peer, afi, safi); if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP6][SAFI_UNICAST]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_UNICAST - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP6][SAFI_UNICAST]) - bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST); - - if (BGP_DEBUG (normal, NORMAL)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP6][SAFI_MULTICAST]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MULTICAST - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - - /* NSF delete stale route */ - if (peer->nsf[AFI_IP6][SAFI_MULTICAST]) - bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST); - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) - { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP6][SAFI_MPLS_VPN]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) - bgp_nlri_parse_vpn (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP][SAFI_ENCAP]) - { - if (mp_update.length - && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s", - peer->host); - } - } - if (peer->afc[AFI_IP6][SAFI_ENCAP]) - { - if (mp_update.length - && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NLRI_ATTR_ARG, &mp_update); - - if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_ENCAP) - bgp_nlri_parse_encap (peer, NULL, &mp_withdraw); - - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN - && mp_withdraw.length == 0) - { - /* End-of-RIB received */ - - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s", - peer->host); - } + zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for %s from %s", + peer->host, afi_safi_print (afi, safi)); + } } - + /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&attr); diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 8f0ebe318..6b0b7f4d4 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -54,4 +54,6 @@ extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); extern int bgp_capability_receive (struct peer *, bgp_size_t); +extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); + #endif /* _QUAGGA_BGP_PACKET_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c1e5e59b1..b581fd990 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3226,7 +3226,8 @@ bgp_reset (void) /* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr value. */ int -bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) { u_char *pnt; u_char *lim; @@ -3401,6 +3402,7 @@ bgp_nlri_sanity_check (struct peer *peer, struct bgp_nlri *nlri) switch (nlri->safi) { case SAFI_MPLS_LABELED_VPN: + case SAFI_MPLS_VPN: return bgp_nlri_sanity_check_vpn (peer, nlri); case SAFI_UNICAST: case SAFI_MULTICAST: diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index c16eca7bb..8064598c4 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -197,7 +197,7 @@ extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern int bgp_nlri_sanity_check (struct peer *, struct bgp_nlri *); -extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); +extern int bgp_nlri_parse_ip (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 39f3b0da1..5400dd179 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -32,6 +32,7 @@ #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_packet.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_nexthop.h" @@ -723,16 +724,10 @@ parse_test (struct peer *peer, struct test_segment *t, int type) if (!parse_ret) { - int (*f) (struct peer *, struct attr *, struct bgp_nlri *) - = bgp_nlri_parse; - - if (t->safi == SAFI_MPLS_LABELED_VPN) - f = bgp_nlri_parse_vpn; - if (type == BGP_ATTR_MP_REACH_NLRI) - nlri_ret = f (peer, &attr, &nlri); + nlri_ret = bgp_nlri_parse (peer, &attr, &nlri); else - nlri_ret = f (peer, NULL, &nlri); + nlri_ret = bgp_nlri_parse (peer, NULL, &nlri); } handle_result (peer, t, parse_ret, nlri_ret); From 405e9e19eb6ce62fa4f3f39a1f73990db9e146b7 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 4 Feb 2016 17:00:18 +0000 Subject: [PATCH 0974/1342] bgpd: Remove the double-pass parsing of NLRIs * bgpd parses NLRIs twice, a first pass "sanity check" and then a second pass that changes actual state. For most AFI/SAFIs this is done by bgp_nlri_sanity_check and bgp_nlri_parse, which are almost identical. As the required action on a syntactic error in an NLRI is to NOTIFY and shut down the session, it should be acceptable to just do a one pass parse. There is no need to atomically handle the NLRIs. * bgp_route.h: (bgp_nlri_sanity_check) Delete * bgp_route.c: (bgp_nlri_parse) Make the prefixlen size check more general and don't hard-code AFI/SAFI details, e.g. use prefix_blen library function. Add error logs consistent with bgp_nlri_sanity_check as much as possible. Add a "defense in depth" type check of the prefixlen against the sizeof the (struct prefix) storage - ala bgp_nlri_parse_vpn. Update standards text from draft RFC4271 to the actual RFC4271 text. Extend the semantic consistency test of IPv6. E.g. it should skip mcast NLRIs for unicast safi as v4 does. * bgp_mplsvpn.{c,h}: Delete bgp_nlri_sanity_check_vpn and make bgp_nlri_parse_vpn_body the bgp_nlri_parse_vpn function again. (bgp_nlri_parse_vpn) Remove the notifies. The sanity checks were responsible for this, but bgp_update_receive handles sending NOTIFY generically for bgp_nlri_parse. * bgp_attr.c: (bgp_mp_reach_parse,bgp_mp_unreach_parse) Delete sanity check. NLRI parsing done after attr parsing by bgp_update_receive. Arising out of discussions on the need for two-pass NLRI parse with: Lou Berger Donald Sharp --- bgpd/bgp_attr.c | 12 ---- bgpd/bgp_mplsvpn.c | 44 +++---------- bgpd/bgp_mplsvpn.h | 1 - bgpd/bgp_packet.c | 18 ----- bgpd/bgp_route.c | 161 ++++++++++++++++----------------------------- bgpd/bgp_route.h | 1 - 6 files changed, 65 insertions(+), 172 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 98571dab5..d74e0efc7 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1602,7 +1602,6 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, safi_t safi; bgp_size_t nlri_len; size_t start; - int ret; struct stream *s; struct peer *const peer = args->peer; struct attr *const attr = args->attr; @@ -1731,14 +1730,6 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args, mp_update->nlri = stream_pnt (s); mp_update->length = nlri_len; - ret = bgp_nlri_sanity_check (peer, mp_update); - if (ret < 0) - { - zlog_info ("%s: (%s) NLRI doesn't pass sanity check", - __func__, peer->host); - return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; - } - stream_forward_getp (s, nlri_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI); @@ -1776,9 +1767,6 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, mp_withdraw->nlri = stream_pnt (s); mp_withdraw->length = withdraw_len; - if (bgp_nlri_sanity_check (peer, mp_withdraw) < 0) - return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; - stream_forward_getp (s, withdraw_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 83bb6ca9d..08a4272d6 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -93,9 +93,9 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) rd_ip->val |= (u_int16_t) *pnt; } -static int -bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, bool update) +int +bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) { u_char *pnt; u_char *lim; @@ -137,8 +137,6 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, "%s [Error] Update packet error / VPNv4" " (prefix length %d less than VPNv4 min length)", peer->host, prefixlen); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } if ((pnt + psize) > lim) @@ -148,8 +146,6 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, " (psize %u exceeds packet size (%u)", peer->host, prefixlen, (uint)(lim-pnt)); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } @@ -161,8 +157,6 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, " (psize %u exceeds storage size (%zu)", peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u)); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } @@ -175,8 +169,6 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, p.family, prefix_blen (&p)); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } @@ -212,15 +204,12 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, psize - VPN_PREFIXLEN_MIN_BYTES); - if (update) - { - if (attr) - bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); - else - bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); - } + if (attr) + bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); + else + bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } /* Packet length consistency check. */ if (pnt != lim) @@ -229,8 +218,6 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, "%s [Error] Update packet error / VPNv4" " (%zu data remaining after parsing)", peer->host, lim - pnt); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); return -1; } @@ -238,19 +225,6 @@ bgp_nlri_parse_vpn_body (struct peer *peer, struct attr *attr, #undef VPN_PREFIXLEN_MIN_BYTES } -int -bgp_nlri_sanity_check_vpn (struct peer *peer, struct bgp_nlri *nlri) -{ - return bgp_nlri_parse_vpn_body (peer, NULL, nlri, false); -} - -int -bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, - struct bgp_nlri *packet) -{ - return bgp_nlri_parse_vpn_body (peer, attr, packet, true); -} - int str2prefix_rd (const char *str, struct prefix_rd *prd) { diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index b89b6d8ac..3299b9cb9 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -43,7 +43,6 @@ struct rd_ip extern void bgp_mplsvpn_init (void); extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *); -extern int bgp_nlri_sanity_check_vpn (struct peer *, struct bgp_nlri *); extern u_int32_t decode_label (u_char *); extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 628c333ab..740b0f1ce 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1686,13 +1686,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) nlris[NLRI_WITHDRAW].nlri = stream_pnt (s); nlris[NLRI_WITHDRAW].length = withdraw_len; - if (bgp_nlri_sanity_check (peer, &nlris[NLRI_WITHDRAW]) < 0) - { - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); - return -1; - } - if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); @@ -1782,17 +1775,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) nlris[NLRI_UPDATE].nlri = stream_pnt (s); nlris[NLRI_UPDATE].length = update_len; - /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, &nlris[NLRI_UPDATE]); - if (ret < 0) - { - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); - bgp_attr_unintern_sub (&attr); - bgp_attr_flush (&attr); - return -1; - } - stream_forward_getp (s, update_len); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b581fd990..2728b1031 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3242,6 +3242,9 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, pnt = packet->nlri; lim = pnt + packet->length; + /* RFC4771 6.3 The NLRI field in the UPDATE message is checked for + syntactic validity. If the field is syntactically incorrect, + then the Error Subcode is set to Invalid Network Field. */ for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ @@ -3249,20 +3252,41 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, /* Fetch prefix length. */ p.prefixlen = *pnt++; + /* afi/safi validity already verified by caller, bgp_update_receive */ p.family = afi2family (packet->afi); - /* Already checked in nlri_sanity_check(). We do double check - here. */ - if ((packet->afi == AFI_IP && p.prefixlen > 32) - || (packet->afi == AFI_IP6 && p.prefixlen > 128)) - return -1; - + /* Prefix length check. */ + if (p.prefixlen > prefix_blen (&p) * 8) + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (wrong prefix length %u for afi %u)", + peer->host, p.prefixlen, packet->afi); + return -1; + } + /* Packet size overflow check. */ psize = PSIZE (p.prefixlen); /* When packet overflow occur return immediately. */ if (pnt + psize > lim) - return -1; + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (prefix length %u overflows packet)", + peer->host, p.prefixlen); + return -1; + } + + /* Defensive coding, double-check the psize fits in a struct prefix */ + if (psize > (ssize_t) sizeof(p.u)) + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (prefix length %u too large for prefix storage %zu!?!!", + peer->host, p.prefixlen, sizeof(p.u)); + return -1; + } /* Fetch prefix from NLRI packet. */ memcpy (&p.u.prefix, pnt, psize); @@ -3273,17 +3297,16 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) { /* - * From draft-ietf-idr-bgp4-22, Section 6.3: - * If a BGP router receives an UPDATE message with a - * semantically incorrect NLRI field, in which a prefix is - * semantically incorrect (eg. an unexpected multicast IP - * address), it should ignore the prefix. + * From RFC4271 Section 6.3: + * + * If a prefix in the NLRI field is semantically incorrect + * (e.g., an unexpected multicast IP address), an error SHOULD + * be logged locally, and the prefix SHOULD be ignored. */ zlog (peer->log, LOG_ERR, - "IPv4 unicast NLRI is multicast address %s", - inet_ntoa (p.u.prefix4)); - - return -1; + "%s: IPv4 unicast NLRI is multicast address %s, ignoring", + peer->host, inet_ntoa (p.u.prefix4)); + continue; } } @@ -3294,13 +3317,23 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, { char buf[BUFSIZ]; - zlog (peer->log, LOG_WARNING, - "IPv6 link-local NLRI received %s ignore this NLRI", + zlog (peer->log, LOG_ERR, + "%s: IPv6 unicast NLRI is link-local address %s, ignoring", + peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); + continue; + } + if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6)) + { + char buf[BUFSIZ]; + zlog (peer->log, LOG_ERR, + "%s: IPv6 unicast NLRI is multicast address %s, ignoring", + peer->host, + inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); continue; } - } + } /* Normal process. */ if (attr) @@ -3318,99 +3351,17 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, /* Packet length consistency check. */ if (pnt != lim) - return -1; - - return 0; -} - -static int -bgp_nlri_sanity_check_ip (struct peer *peer, struct bgp_nlri *nlri) -{ - u_char *end; - u_char prefixlen; - int psize; - u_char *pnt = nlri->nlri; - afi_t afi = nlri->afi; - safi_t safi = nlri->safi; - end = pnt + nlri->length; - - /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for - syntactic validity. If the field is syntactically incorrect, - then the Error Subcode is set to Invalid Network Field. */ - - while (pnt < end) - { - int badlength; - prefixlen = *pnt++; - - /* Prefix length check. */ - badlength = 0; - if (safi == SAFI_ENCAP) { - if (prefixlen > 128) - badlength = 1; - } else { - if ((afi == AFI_IP && prefixlen > 32) || - (afi == AFI_IP6 && prefixlen > 128)) { - - badlength = 1; - } - } - if (badlength) - { - plog_err (peer->log, - "%s [Error] Update packet error (wrong prefix length %d)", - peer->host, prefixlen); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); - return -1; - } - - /* Packet size overflow check. */ - psize = PSIZE (prefixlen); - - if (pnt + psize > end) - { - plog_err (peer->log, - "%s [Error] Update packet error" - " (prefix data overflow prefix size is %d)", - peer->host, psize); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); - return -1; - } - - pnt += psize; - } - - /* Packet length consistency check. */ - if (pnt != end) { plog_err (peer->log, - "%s [Error] Update packet error" - " (prefix length mismatch with total length)", - peer->host); - bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); + "%s [Error] Update packet error" + " (prefix length mismatch with total length)", + peer->host); return -1; } + return 0; } -int -bgp_nlri_sanity_check (struct peer *peer, struct bgp_nlri *nlri) -{ - switch (nlri->safi) - { - case SAFI_MPLS_LABELED_VPN: - case SAFI_MPLS_VPN: - return bgp_nlri_sanity_check_vpn (peer, nlri); - case SAFI_UNICAST: - case SAFI_MULTICAST: - return bgp_nlri_sanity_check_ip (peer, nlri); - default: return -1; - } -} - static struct bgp_static * bgp_static_new (void) { diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 8064598c4..c80375925 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -196,7 +196,6 @@ extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *); extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); -extern int bgp_nlri_sanity_check (struct peer *, struct bgp_nlri *); extern int bgp_nlri_parse_ip (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); From 2db962760426ddb9e266f9a4bc0b274584c819cc Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 8 Feb 2016 14:46:28 +0000 Subject: [PATCH 0975/1342] lib: zclient can overflow (struct interface) hw_addr if zebra is evil * lib/zclient.c: (zebra_interface_if_set_value) The hw_addr_len field is used as trusted input to read off the hw_addr and write to the INTERFACE_HWADDR_MAX sized hw_addr field. The read from the stream is bounds-checked by the stream abstraction, however the write out to the heap can not be. Tighten the supplied length to stream_get used to do the write. Impact: a malicious zebra can overflow the heap of clients using the ZServ IPC. Note that zebra is already fairly trusted within Quagga. Reported-by: Kostya Kortchinsky --- lib/zclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index 9188c0183..610008b4d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -794,7 +794,7 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->ll_type = stream_getl (s); ifp->hw_addr_len = stream_getl (s); if (ifp->hw_addr_len) - stream_get (ifp->hw_addr, s, ifp->hw_addr_len); + stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); } static int From bf83fa25f1bddec6f09ad879cba5e975a3ae5495 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 9 Feb 2016 15:23:03 +0000 Subject: [PATCH 0976/1342] lib: Check prefix length from zebra is sensible * zclient.c: prefix length on router-id and interface address add messages not sanity checked. fix. * */*_zebra.c: Prefix length on zebra route read was not checked, and clients use it to write to storage. An evil zebra could overflow client structures by sending overly long prefixlen. Prompted by discussions with: Donald Sharp --- bgpd/bgp_zebra.c | 4 ++-- isisd/isis_zebra.c | 2 +- lib/zclient.c | 45 +++++++++++++++++++++++++++----------------- ospf6d/ospf6_zebra.c | 2 +- ospfd/ospf_zebra.c | 2 +- ripd/rip_zebra.c | 2 +- ripngd/ripng_zebra.c | 2 +- 7 files changed, 35 insertions(+), 24 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4ec15d0dc..bee1a9470 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -250,7 +250,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; - p.prefixlen = stream_getc (s); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s)); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ @@ -326,7 +326,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; - p.prefixlen = stream_getc (s); + p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s)); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 6c398cf54..a1a5bea7c 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -541,7 +541,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, api.message = stream_getc (stream); p.family = AF_INET; - p.prefixlen = stream_getc (stream); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (stream)); stream_get (&p.prefix, stream, PSIZE (p.prefixlen)); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) diff --git a/lib/zclient.c b/lib/zclient.c index 610008b4d..d25c8d443 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -651,18 +651,30 @@ zebra_redistribute_send (int command, struct zclient *zclient, int type, return zclient_send_message(zclient); } +/* Get prefix in ZServ format; family should be filled in on prefix */ +static void +zclient_stream_get_prefix (struct stream *s, struct prefix *p) +{ + size_t plen = prefix_blen (p); + u_char c; + p->prefixlen = 0; + + if (plen == 0) + return; + + stream_get (&p->u.prefix, s, plen); + c = stream_getc(s); + p->prefixlen = MIN(plen * 8, c); +} + /* Router-id update from zebra daemon. */ void zebra_router_id_update_read (struct stream *s, struct prefix *rid) { - int plen; - /* Fetch interface address. */ rid->family = stream_getc (s); - - plen = prefix_blen (rid); - stream_get (&rid->u.prefix, s, plen); - rid->prefixlen = stream_getc (s); + + zclient_stream_get_prefix (s, rid); } /* Interface addition from zebra daemon. */ @@ -814,8 +826,7 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) ifindex_t ifindex; struct interface *ifp; struct connected *ifc; - struct prefix p, d; - int family; + struct prefix p, d, *dp; int plen; u_char ifc_flags; @@ -840,21 +851,21 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) ifc_flags = stream_getc (s); /* Fetch interface address. */ - family = p.family = stream_getc (s); - - plen = prefix_blen (&p); - stream_get (&p.u.prefix, s, plen); - p.prefixlen = stream_getc (s); + d.family = p.family = stream_getc (s); + plen = prefix_blen (&d); + + zclient_stream_get_prefix (s, &p); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); - d.family = family; - + + /* N.B. NULL destination pointers are encoded as all zeroes */ + dp = memconstant(&d.u.prefix,0,plen) ? NULL : &d; + if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* N.B. NULL destination pointers are encoded as all zeroes */ - ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ? - NULL : &d)); + ifc = connected_add_by_prefix(ifp, &p, dp); if (ifc != NULL) { ifc->flags = ifc_flags; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 30b6fc6ff..0caf0014b 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -227,7 +227,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; - p.prefixlen = stream_getc (s); + p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s)); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index cf2ea81f5..4531f13d4 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -845,7 +845,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; - p.prefixlen = stream_getc (s); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s)); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); if (IPV4_NET127(ntohl(p.prefix.s_addr))) diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 0b6c22a86..1411cd71b 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -148,7 +148,7 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; - p.prefixlen = stream_getc (s); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s)); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index a48539e5f..e02b09896 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -147,7 +147,7 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient, /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; - p.prefixlen = stream_getc (s); + p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s)); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ From 370b7e59170acf853ca3357c71dd5ab0d85e763c Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Thu, 4 Feb 2016 21:29:49 -0500 Subject: [PATCH 0977/1342] bgpd: Fix crash reported by NetDEF CI This patch is part of the previously submitted patch set on VPN and Encap SAFIs. It fixes an issue identified by NetDEF CI. Ensure temp stack structures are initialized Add protection against double frees / post free access to bgp_attr_flush Signed-off-by: Lou Berger --- bgpd/bgp_attr.c | 20 ++++++++++++++++---- bgpd/bgp_route.c | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d74e0efc7..f34e64933 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -833,9 +833,15 @@ void bgp_attr_flush (struct attr *attr) { if (attr->aspath && ! attr->aspath->refcnt) - aspath_free (attr->aspath); + { + aspath_free (attr->aspath); + attr->aspath = NULL; + } if (attr->community && ! attr->community->refcnt) - community_free (attr->community); + { + community_free (attr->community); + attr->community = NULL; + } if (attr->extra) { struct attr_extra *attre = attr->extra; @@ -843,9 +849,15 @@ bgp_attr_flush (struct attr *attr) if (attre->ecommunity && ! attre->ecommunity->refcnt) ecommunity_free (&attre->ecommunity); if (attre->cluster && ! attre->cluster->refcnt) - cluster_free (attre->cluster); + { + cluster_free (attre->cluster); + attre->cluster = NULL; + } if (attre->transit && ! attre->transit->refcnt) - transit_free (attre->transit); + { + transit_free (attre->transit); + attre->transit = NULL; + } encap_free(attre->encap_subtlvs); attre->encap_subtlvs = NULL; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2728b1031..c364372f8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2121,6 +2121,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, const char *reason; char buf[SU_ADDRSTRLEN]; + memset (&new_attr, 0, sizeof(struct attr)); + memset (&new_extra, 0, sizeof(struct attr_extra)); + bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); From a3ee120fcf2b2b205e3e15f544eb4090653e7bff Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Dec 2015 19:38:23 +0100 Subject: [PATCH 0978/1342] lib: fix vrf_bitmap leak in zclient_free() zclient_stop(), which is used as antagonist to zclient_init(), needs to undo the vrf_bitmap allocation. Otherwise zclient_init() will leak the allocated memory, for example when zclient_reset() is used. Reported-by: Lou Berger Signed-off-by: David Lamparter --- lib/zclient.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index d25c8d443..9d50ebc04 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -112,6 +112,8 @@ zclient_init (struct zclient *zclient, int redist_default) void zclient_stop (struct zclient *zclient) { + int i; + if (zclient_debug) zlog_debug ("zclient stopped"); @@ -134,6 +136,14 @@ zclient_stop (struct zclient *zclient) zclient->sock = -1; } zclient->fail = 0; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + vrf_bitmap_free(zclient->redist[i]); + zclient->redist[i] = VRF_BITMAP_NULL; + } + vrf_bitmap_free(zclient->default_information); + zclient->default_information = VRF_BITMAP_NULL; } void From e07068c838142a127da8821afd660f075f7c35f8 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 4 Sep 2015 14:25:13 +0100 Subject: [PATCH 0979/1342] distro: fix redhat/quagga.spec.in * quagga.spec.in: Add default for with_pimd macro. Remove ancient condtional on quagga_buildreqs. More recent rpmbuild complains about too many levels of recursion in quagga_buildreqs, so use %{expand:..}. Actually use quagga_buildreqs in BuildRequires! groff is needed for build. texi2html --number argument has disappeared, split into 2. Acked-by: Donald Sharp --- redhat/quagga.spec.in | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 43feea411..5e36b9d36 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -20,6 +20,7 @@ %{!?with_irdp: %define with_irdp 1 } %{!?with_rtadv: %define with_rtadv 1 } %{!?with_isisd: %define with_isisd 1 } +%{!?with_pimd: %define with_pimd 1 } %{!?with_shared: %define with_shared 1 } %{!?with_multipath: %define with_multipath 64 } %{!?quagga_user: %define quagga_user quagga } @@ -44,23 +45,24 @@ %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. -%define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel -%define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel +%define quagga_buildreqs texi2html texinfo autoconf pam-devel +%define quagga_buildreqs %{expand:%{quagga_buildreqs}} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. -%if "%dist" != "fc2" || "%dist" != "fc3" -%define quagga_buildreqs %{quagga_buildreqs} texi2html -%endif +%define quagga_buildreqs %{expand:%{quagga_buildreqs}} texi2html -# pam_stack is deprecated in FC5 +# pam_stack was deprecated in FC5 # default to pam_stack, default should be changed later. %if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack %else %define quagga_pam_source quagga.pam %endif -############################################################################ +# man page probably needs groff for groff_ms macros +%define quagga_buildreqs %{expand:%{quagga_buildreqs}} groff + +############################################################################ # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } @@ -103,7 +105,7 @@ Requires(pre): net-snmp BuildRequires: readline readline-devel ncurses ncurses-devel Requires(pre): ncurses %endif -BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex +BuildRequires: %{quagga_buildreqs} # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 Requires(pre): ncurses pam @@ -223,7 +225,7 @@ developing OSPF-API and quagga applications. make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc -texi2html -number quagga.texi +texi2html --number-footnotes --number-sections quagga.texi popd %install @@ -449,6 +451,10 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Fri Sep 4 2015 Paul Jakma - %{version} +- buildreq updates +- add a default define for with_pimd + * Thu Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable From fca2c24ff21a9d837229bc40e462c6615e368123 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 12 Aug 2015 17:31:07 -0700 Subject: [PATCH 0980/1342] Adding redhat init/service files to start pimd Added missing pimd.init (for RedHat/CentOS <= 6) and pimd.service (for RedHat/CentOS >= 7) Signed-off-by: Martin Winter --- redhat/Makefile.am | 2 +- redhat/pimd.init | 72 +++++++++++++++++++++++++++++++++++++++++++++ redhat/pimd.service | 14 +++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 redhat/pimd.init create mode 100644 redhat/pimd.service diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 9612e9148..94c8db03a 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -3,4 +3,4 @@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ - watchquagga.init zebra.init zebra.service + watchquagga.init pimd.init pimd.service zebra.init zebra.service diff --git a/redhat/pimd.init b/redhat/pimd.init new file mode 100644 index 000000000..49f90755d --- /dev/null +++ b/redhat/pimd.init @@ -0,0 +1,72 @@ +#!/bin/bash +# chkconfig: - 16 84 +# config: /etc/quagga/pimd.conf + +### BEGIN INIT INFO +# Provides: pimd +# Short-Description: PIM multicast routing engine +# Description: PIM routing engine for use with Zebra +### END INIT INFO + +# source function library +. /etc/rc.d/init.d/functions + +# Get network config +. /etc/sysconfig/network + +# quagga command line options +. /etc/sysconfig/quagga + +RETVAL=0 +PROG="pimd" +cmd=pimd +LOCK_FILE=/var/lock/subsys/pimd +CONF_FILE=/etc/quagga/pimd.conf + +case "$1" in + start) + # Check that networking is up. + [ "${NETWORKING}" = "no" ] && exit 1 + + # The process must be configured first. + [ -f $CONF_FILE ] || exit 6 + if [ `id -u` -ne 0 ]; then + echo $"Insufficient privilege" 1>&2 + exit 4 + fi + + echo -n $"Starting $PROG: " + daemon $cmd -d $PIMD_OPTS -f $CONF_FILE + RETVAL=$? + [ $RETVAL -eq 0 ] && touch $LOCK_FILE + echo + ;; + stop) + echo -n $"Shutting down $PROG: " + killproc $cmd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE + echo + ;; + restart|reload|force-reload) + $0 stop + $0 start + RETVAL=$? + ;; + condrestart|try-restart) + if [ -f $LOCK_FILE ]; then + $0 stop + $0 start + fi + RETVAL=$? + ;; + status) + status $cmd + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" + exit 2 +esac + +exit $RETVAL diff --git a/redhat/pimd.service b/redhat/pimd.service new file mode 100644 index 000000000..d62fe6488 --- /dev/null +++ b/redhat/pimd.service @@ -0,0 +1,14 @@ +[Unit] +Description=PIM multicast routing engine +BindTo=zebra.service +After=syslog.target network.target zebra.service +ConditionPathExists=/etc/quagga/pimd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/pimd -d $PIMD_OPTS -f /etc/quagga/pimd.conf +Restart=on-abort + +[Install] +WantedBy=network.target From 283d5d7f2fa12c3d33dc17962154665a9993b2c5 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 11 Feb 2016 13:54:23 +0000 Subject: [PATCH 0981/1342] distro/redhat/rpm: remove with_ipv6, package pimd binary, remove pam stack * redhat/quagga.spec.in: remove with_ipv6, it should just be the norm now. The actual pimd binary wasn't being packaged, fix. Remove deprecated pam.stack support. * redhat/quagga.pam.stack: ancient, nuke. * Makefile.am: ditto --- redhat/Makefile.am | 2 +- redhat/quagga.pam.stack | 26 -------------------------- redhat/quagga.spec.in | 36 +++++++++++++----------------------- 3 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 redhat/quagga.pam.stack diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 94c8db03a..4e9985518 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -1,6 +1,6 @@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ - quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ + quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init pimd.init pimd.service zebra.init zebra.service diff --git a/redhat/quagga.pam.stack b/redhat/quagga.pam.stack deleted file mode 100644 index 8ddc2bbe3..000000000 --- a/redhat/quagga.pam.stack +++ /dev/null @@ -1,26 +0,0 @@ -#%PAM-1.0 -# - -##### if running quagga as root: -# Only allow root (and possibly wheel) to use this because enable access -# is unrestricted. -auth sufficient /lib/security/$ISA/pam_rootok.so - -# Uncomment the following line to implicitly trust users in the "wheel" group. -#auth sufficient /lib/security/$ISA/pam_wheel.so trust use_uid -# Uncomment the following line to require a user to be in the "wheel" group. -#auth required /lib/security/$ISA/pam_wheel.so use_uid -########################################################### - -# If using quagga privileges and with a seperate group for vty access, then -# access can be controlled via the vty access group, and pam can simply -# check for valid user/password, eg: -# -# only allow local users. -#auth required /lib/security/$ISA/pam_securetty.so -#auth required /lib/security/$ISA/pam_stack.so service=system-auth -#auth required /lib/security/$ISA/pam_nologin.so -#account required /lib/security/$ISA/pam_stack.so service=system-auth -#password required /lib/security/$ISA/pam_stack.so service=system-auth -#session required /lib/security/$ISA/pam_stack.so service=system-auth -#session optional /lib/security/$ISA/pam_console.so diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 5e36b9d36..b156475e3 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -3,6 +3,9 @@ # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # +# E.g. rpmbuild --define 'release_rev 02' may be useful if building +# rpms again and again on the same day, so the newer rpms can be installed. +# bumping the number each time. ####################### Quagga configure options ######################### # with-feature options @@ -14,7 +17,6 @@ %{!?with_tcp_zebra: %define with_tcp_zebra 0 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_pam: %define with_pam 1 } -%{!?with_ipv6: %define with_ipv6 1 } %{!?with_ospfclient: %define with_ospfclient 1 } %{!?with_ospfapi: %define with_ospfapi 1 } %{!?with_irdp: %define with_irdp 1 } @@ -51,14 +53,6 @@ # FC4 and 5 split texi2html out of tetex package. %define quagga_buildreqs %{expand:%{quagga_buildreqs}} texi2html -# pam_stack was deprecated in FC5 -# default to pam_stack, default should be changed later. -%if "%dist" == "fc4" || "%dist" == "fc3" -%define quagga_pam_source quagga.pam.stack -%else -%define quagga_pam_source quagga.pam -%endif - # man page probably needs groff for groff_ms macros %define quagga_buildreqs %{expand:%{quagga_buildreqs}} groff @@ -69,11 +63,7 @@ %{!?quagga_gid: %define quagga_gid 92 } %define daemon_list zebra ripd ospfd bgpd -%if %{with_ipv6} %define daemonv6_list ripngd ospf6d -%else -%define daemonv6_list "" -%endif %if %{with_isisd} %define daemon_other isisd @@ -161,9 +151,6 @@ developing OSPF-API and quagga applications. %if !%{with_shared} --disable-shared \ %endif -%if %{with_ipv6} - --enable-ipv6 \ -%endif %if %{with_snmp} --enable-snmp \ %endif @@ -247,7 +234,7 @@ for daemon in %{all_daemons} ; do $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} fi done -install -m644 %{zeb_rh_src}/%{quagga_pam_source} \ +install -m644 %{zeb_rh_src}/quagga.pam \ $RPM_BUILD_ROOT/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ $RPM_BUILD_ROOT/etc/logrotate.d/quagga @@ -291,14 +278,10 @@ zebra_spec_add_service () zebra_spec_add_service zebrasrv 2600/tcp "zebra service" zebra_spec_add_service zebra 2601/tcp "zebra vty" zebra_spec_add_service ripd 2602/tcp "RIPd vty" -%if %{with_ipv6} zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" -%endif zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" zebra_spec_add_service bgpd 2605/tcp "BGPd vty" -%if %{with_ipv6} zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" -%endif %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif @@ -408,9 +391,10 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/watchquagga -%if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d +%if %{with_pimd} +%{_sbindir}/pimd %endif %if %{with_isisd} %{_sbindir}/isisd @@ -451,6 +435,12 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Fri Sep 4 2015 Paul Jakma - %{version} +- package the pimd binary +- remove with_ipv6 conditionals, always build v6 +- Fix UTF-8 char in spec changelog +- remove quagga.pam.stack, long deprecated. + * Fri Sep 4 2015 Paul Jakma - %{version} - buildreq updates - add a default define for with_pimd @@ -587,7 +577,7 @@ rm -rf $RPM_BUILD_ROOT * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 -* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 +* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) From 988e22f8429ce678ba503bddaaf4ec9f9965eb73 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 11 Feb 2016 15:25:52 +0000 Subject: [PATCH 0982/1342] configure.ac: remove -dev in version * configure.ac: Remove the -dev suffix from the version, some package systems at least do not like non-numeric strings in package versions (e.g., rpm, which I often use in testing Quagga). TODO: Work out some sensible scheme for semi-autogenerating the version perhaps via git describe. The --with-pkg-git-version doesn't affect the tarball name. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7aaacb96d..c6844147a 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.25-dev, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.25, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From a5efdb60905049e1224a020b78dd9699bdd15b29 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 29 Oct 2015 22:15:42 -0700 Subject: [PATCH 0983/1342] distro/redhat: Update to support CentOS/RHEL/Fedora, upstart/init/systemd * redhat/quagga.spec.in: Update to support CentOS, RHEL and Fedora, and support the various init systems across different versions of these distros, e.g. upstart/init/systemd. Clean up various warnings from rpmlint. Remove configure options that are gone. A few edits and commit message by: Paul Jakma / --- redhat/Makefile.am | 4 +- redhat/README.rpm_build.md | 128 +++++++++++ redhat/quagga.spec.in | 437 +++++++++++++++++++++++++------------ 3 files changed, 424 insertions(+), 145 deletions(-) create mode 100644 redhat/README.rpm_build.md diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 4e9985518..fadfe64c7 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -3,4 +3,6 @@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ - watchquagga.init pimd.init pimd.service zebra.init zebra.service + watchquagga.init pimd.init pimd.service zebra.init zebra.service \ + README.rpm_build.md + diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md new file mode 100644 index 000000000..3e8fa0530 --- /dev/null +++ b/redhat/README.rpm_build.md @@ -0,0 +1,128 @@ +Building your own Quagga RPM +============================ +(Tested on CentOS 6, CentOS 7 and Fedora 22.) + +1. Install the following packages to build the RPMs: + + yum install git autoconf automake libtool make gawk readline-devel \ + texinfo dejagnu net-snmp-devel groff rpm-build net-snmp-devel \ + libcap-devel texi2html + + (use `dnf install` on new Fedora instead of `yum install `) + +2. Checkout Quagga under a **unpriviledged** user account + + git clone git://git.savannah.nongnu.org/quagga.git quagga + +3. Run Bootstrap and make distribution tar.gz + + cd quagga + ./bootstrap.sh + ./configure --with-pkg-extra-version=-MyRPMVersion + make dist + + Note: configure parameters are not important for the RPM building - except the + `with-pkg-extra-version` if you want to give the RPM a specific name to + mark your own unoffical build + +4. Create RPM directory structure and populate with sources + + mkdir rpmbuild + mkdir rpmbuild/SOURCES + mkdir rpmbuild/SPECS + cp redhat/*.spec rpmbuild/SPECS/ + cp quagga*.tar.gz rpmbuild/SOURCES/ + +5. Edit rpm/SPECS/quagga.spec with configuration as needed + Look at the beginning of the file and adjust the following parameters to enable + or disable features as required: + + ################# Quagga configure options #################### + # with-feature options + %{!?with_snmp: %global with_snmp 1 } + %{!?with_vtysh: %global with_vtysh 1 } + %{!?with_ospf_te: %global with_ospf_te 1 } + %{!?with_opaque_lsa: %global with_opaque_lsa 1 } + %{!?with_tcp_zebra: %global with_tcp_zebra 0 } + %{!?with_vtysh: %global with_vtysh 1 } + %{!?with_pam: %global with_pam 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_irdp: %global with_irdp 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_isisd: %global with_isisd 1 } + %{!?with_pimd: %global with_pimd 1 } + %{!?with_shared: %global with_shared 1 } + %{!?with_multipath: %global with_multipath 64 } + %{!?quagga_user: %global quagga_user quagga } + %{!?vty_group: %global vty_group quaggavt } + %{!?with_fpm: %global with_fpm 0 } + %{!?with_watchquagga: %global with_watchquagga 1 } + +6. Build the RPM + + rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/quagga.spec + +DONE. + +If all works correctly, then you should end up with the RPMs under `rpmbuild/RPMS` +and the Source RPM under `rpmbuild/SRPMS` + + +Enabling daemons after installation of the package: +--------------------------------------------------- + +### init.d based systems (ie CentOS 6): + +1. Enable the daemons as needed to run after boot (Zebra is mandatory) + + chkconfig zebra on + chkconfig ospfd on + chkconfig ospf6d on + chkconfig bgpd on + ... etc + +2. If you want to run `watchquagga`, then configure `/etc/sysconfig/quagga` + and uncomment the line with the daemons for `watchquagga` to monitor, + then enable watchquagga + + chkconfig watchquagga on + +3. Check your firewall / IPtables to make sure the routing protocols are +allowed. + +4. Start the daemons (or reboot) + + service zebra start + service bgpd start + service ospfd start + ... etc + +Configuration is stored in `/etc/quagga/*.conf` files. + + +### systemd based systems (ie CentOS 7, Fedora 22) + +1. Enable the daemons as needed to run after boot (Zebra is mandatory) + + systemctl enable zebra + systemctl enable ospfd + systemctl enable ospf6d + systemctl enable bgpd + ... etc + + Note: There is no watchquagga on systemd based systems. Systemd contains + the functionality of monitoring and restarting daemons. + +2. Check your firewall / IPtables to make sure the routing protocols are +allowed. + +3. Start the daemons (or reboot) + + systemctl start zebra + systemctl start bgpd + systemctl start ospfd + ... etc + +Configuration is stored in `/etc/quagga/*.conf` files. + diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index b156475e3..a1263d12a 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -2,6 +2,7 @@ # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' +# (use any value, ie 1 for flag "with_XXXX" definitions) # # E.g. rpmbuild --define 'release_rev 02' may be useful if building # rpms again and again on the same day, so the newer rpms can be installed. @@ -9,107 +10,141 @@ ####################### Quagga configure options ######################### # with-feature options -%{!?with_snmp: %define with_snmp 1 } -%{!?with_vtysh: %define with_vtysh 1 } -%{!?with_ospf_te: %define with_ospf_te 1 } -%{!?with_nssa: %define with_nssa 1 } -%{!?with_opaque_lsa: %define with_opaque_lsa 1 } -%{!?with_tcp_zebra: %define with_tcp_zebra 0 } -%{!?with_vtysh: %define with_vtysh 1 } -%{!?with_pam: %define with_pam 1 } -%{!?with_ospfclient: %define with_ospfclient 1 } -%{!?with_ospfapi: %define with_ospfapi 1 } -%{!?with_irdp: %define with_irdp 1 } -%{!?with_rtadv: %define with_rtadv 1 } -%{!?with_isisd: %define with_isisd 1 } -%{!?with_pimd: %define with_pimd 1 } -%{!?with_shared: %define with_shared 1 } -%{!?with_multipath: %define with_multipath 64 } -%{!?quagga_user: %define quagga_user quagga } -%{!?vty_group: %define vty_group quaggavty } +%{!?with_snmp: %global with_snmp 1 } +%{!?with_vtysh: %global with_vtysh 1 } +%{!?with_tcp_zebra: %global with_tcp_zebra 0 } +%{!?with_vtysh: %global with_vtysh 1 } +%{!?with_pam: %global with_pam 1 } +%{!?with_ospfclient: %global with_ospfclient 1 } +%{!?with_ospfapi: %global with_ospfapi 1 } +%{!?with_irdp: %global with_irdp 1 } +%{!?with_rtadv: %global with_rtadv 1 } +%{!?with_isisd: %global with_isisd 1 } +%{!?with_pimd: %global with_pimd 1 } +%{!?with_shared: %global with_shared 1 } +%{!?with_multipath: %global with_multipath 64 } +%{!?quagga_user: %global quagga_user quagga } +%{!?vty_group: %global vty_group quaggavt } +%{!?with_fpm: %global with_fpm 0 } +%{!?with_watchquagga: %global with_watchquagga 1 } # path defines %define _sysconfdir /etc/quagga -%define zeb_src %{_builddir}/%{name}-%{version} +%define zeb_src %{_builddir}/%{name}-%{quaggaversion} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure -%define _libexecdir %{_exec_prefix}/libexec/quagga -%define _libdir %{_exec_prefix}/%{_lib}/quagga -%define _includedir %{_prefix}/include %define _localstatedir /var/run/quagga ############################################################################ -####################### distro specific tweaks ############################# -# default distro. Override with rpmbuild -D "dist XXX" -%{expand: %%define default_dist %(rpm -q --qf 'fc%%{VERSION}' fedora-release | grep -v 'not installed')} -%{!?dist: %define dist %{default_dist}} +#### Version String tweak +# Remove invalid characters form version string and replace with _ +%{expand: %%define rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} +%define quaggaversion @VERSION@ -# as distros change packages we depend on, our Requires have to change, sadly. -%define quagga_buildreqs texi2html texinfo autoconf pam-devel -%define quagga_buildreqs %{expand:%{quagga_buildreqs}} patch libcap-devel +#### Check version of texi2html +# Old versions don't support "--number-footnotes" option. +%{expand: %%global texi2htmlversion %(rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1 )} -# FC4 and 5 split texi2html out of tetex package. -%define quagga_buildreqs %{expand:%{quagga_buildreqs}} texi2html - -# man page probably needs groff for groff_ms macros -%define quagga_buildreqs %{expand:%{quagga_buildreqs}} groff +#### Check for systemd or init.d (upstart) +# Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) +%{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)} +# +# If init system is systemd, then always disable watchquagga +# +%if "%{initsystem}" == "systemd" + # Note: For systems with systemd, watchquagga will NOT be built. Systemd + # takes over the role of restarting crashed processes. Value will + # be overwritten with 0 below for systemd independent on the setting here + %global with_watchquagga 0 +%endif -############################################################################ +# if FPM is enabled, then enable tcp_zebra as well +# +%if %{with_fpm} + %global with_tcp_zebra 1 +%endif # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } %{!?quagga_gid: %define quagga_gid 92 } +%{!?vty_gid: %define vty_gid 85 } + %define daemon_list zebra ripd ospfd bgpd %define daemonv6_list ripngd ospf6d %if %{with_isisd} -%define daemon_other isisd +%define daemon_isisd isisd %else -%define daemon_other "" +%define daemon_isisd "" %endif -%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_other} watchquagga +%if %{with_pimd} +%define daemon_pimd pimd +%else +%define daemon_pimd "" +%endif + +%if %{with_watchquagga} +%define daemon_watchquagga watchquagga +%else +%define daemon_watchquagga "" +%endif + +%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_watchquagga} # allow build dir to be kept -%{!?keep_build: %define keep_build 0 } +%{!?keep_build: %global keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %define release_rev 01 } Summary: Routing daemon -Name: quagga -Version: @VERSION@ -Release: @CONFDATE@%{release_rev} -License: GPL -Group: System Environment/Daemons -Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz -URL: http://www.quagga.net +Name: quagga +Version: %{rpmversion} +Release: @CONFDATE@%{release_rev}%{?dist} +License: GPLv2+ +Group: System Environment/Daemons +Source0: http://download.savannah.gnu.org/releases/quagga/%{name}-%{quaggaversion}.tar.gz +URL: http://www.quagga.net +Requires: ncurses +Requires(pre): /sbin/install-info +Requires(preun): /sbin/install-info +Requires(post): /sbin/install-info +BuildRequires: texi2html texinfo autoconf patch libcap-devel groff %if %{with_snmp} BuildRequires: net-snmp-devel -Requires(pre): net-snmp +Requires: net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel -Requires(pre): ncurses +Requires: ncurses %endif -BuildRequires: %{quagga_buildreqs} +%if %{with_pam} +BuildRequires: pam-devel +Requires: pam +%endif +%if "%{initsystem}" == "systemd" +BuildRequires: systemd +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +%else # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 -Requires(pre): ncurses pam -Requires(pre): /sbin/install-info -Provides: routingdaemon -BuildRoot: %{_tmppath}/%{name}-%{version}-root -Obsoletes: bird gated mrt zebra +%endif +Provides: routingdaemon = %{version}-%{release} +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Obsoletes: bird gated mrt zebra quagga-sysvinit %description Quagga is a free software that manages TCP/IP based routing protocol. It takes multi-server and multi-thread approach to resolve the current complexity of the Internet. -Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. +Quagga supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng and PIM. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. @@ -127,13 +162,14 @@ Contributed/3rd party tools which may be of use with quagga. %package devel Summary: Header and object files for quagga development Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep -%setup -q +%setup -q -n quagga-%{quaggaversion} %build @@ -148,6 +184,11 @@ developing OSPF-API and quagga applications. #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ + --sysconfdir=%{_sysconfdir} \ + --libdir=%{_libdir} \ + --libexecdir=%{_libexecdir} \ + --localstatedir=%{_localstatedir} \ + --disable-werror \ %if !%{with_shared} --disable-shared \ %endif @@ -160,15 +201,6 @@ developing OSPF-API and quagga applications. %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif -%if %{with_nssa} - --enable-nssa \ -%endif -%if %{with_opaque_lsa} - --enable-opaque-lsa \ -%endif -%if %{with_ospf_te} - --enable-ospf-te \ -%endif %if %{with_vtysh} --enable-vtysh \ %endif @@ -200,57 +232,79 @@ developing OSPF-API and quagga applications. %if %{with_pam} --with-libpam \ %endif -%if %quagga_user +%if 0%{?quagga_user:1} --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif -%if %vty_group +%if 0%{?vty_group:1} --enable-vty-group=%vty_group \ %endif ---enable-netlink --enable-gcc-rdynamic +%if %{with_fpm} + --enable-fpm \ +%else + --disable-fpm \ +%endif +%if %{with_watchquagga} + --enable-watchquagga \ +%else + --disable-watchquagga \ +%endif + --enable-gcc-rdynamic make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc +%if %{texi2htmlversion} < 5 +texi2html --number-sections quagga.texi +%else texi2html --number-footnotes --number-sections quagga.texi +%endif popd %install -rm -rf $RPM_BUILD_ROOT - -install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ - $RPM_BUILD_ROOT/var/log/quagga $RPM_BUILD_ROOT%{_infodir} - -make install \ - DESTDIR=$RPM_BUILD_ROOT +mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ + %{buildroot}/var/log/quagga %{buildroot}%{_infodir} +make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install # Remove this file, as it is uninstalled and causes errors when building on RH9 -rm -rf $RPM_BUILD_ROOT/usr/share/info/dir +rm -rf %{buildroot}/usr/share/info/dir -# install etc sources +# install /etc sources +%if "%{initsystem}" == "systemd" +mkdir -p %{buildroot}%{_unitdir} +for daemon in %{all_daemons} ; do + if [ x"${daemon}" != x"" ] ; then + install %{zeb_rh_src}/${daemon}.service \ + %{buildroot}%{_unitdir}/${daemon}.service + fi +done +%else +mkdir -p %{buildroot}/etc/rc.d/init.d for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ - $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} + %{buildroot}/etc/rc.d/init.d/${daemon} fi done +%endif + install -m644 %{zeb_rh_src}/quagga.pam \ - $RPM_BUILD_ROOT/etc/pam.d/quagga + %{buildroot}/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ - $RPM_BUILD_ROOT/etc/logrotate.d/quagga + %{buildroot}/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ - $RPM_BUILD_ROOT/etc/sysconfig/quagga -install -d -m750 $RPM_BUILD_ROOT/var/run/quagga + %{buildroot}/etc/sysconfig/quagga +install -d -m750 %{buildroot}/var/run/quagga %pre # add vty_group -%if %vty_group +%if 0%{?vty_group:1} if getent group %vty_group > /dev/null ; then : ; else \ - /usr/sbin/groupadd -r %vty_group > /dev/null || : ; fi + /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi %endif # add quagga user and group -%if %quagga_user +%if 0%{?quagga_user:1} # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ @@ -292,77 +346,145 @@ zebra_spec_add_service isisd 2608/tcp "ISISd vty" zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif -for daemon in %daemon_list ; do +%if "%{initsystem}" == "systemd" +for daemon in %all_daemons ; do + %systemd_post ${daemon}.service +done +%else +for daemon in %all_daemons ; do /sbin/chkconfig --add ${daemon} done +%endif /sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf -%if %{quagga_user} - chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf +%if 0%{?quagga_user:1} + chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf* %endif chmod 640 %{_sysconfdir}/zebra.conf fi +for daemon in %{all_daemons} ; do + if [ ! -e %{_sysconfdir}/${daemon}.conf ]; then + touch %{_sysconfdir}/${daemon}.conf + %if 0%{?quagga_user:1} + chown %quagga_user:%quagga_user %{_sysconfdir}/${daemon}.conf* + %endif + fi +done +%if %{with_watchquagga} + # No config for watchquagga - this is part of /etc/sysconfig/quagga + rm -f %{_sysconfdir}/watchquagga.* +%endif + if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf +%if 0%{?vty_group:1} + chown quagga:%{vty_group} %{_sysconfdir}/vtysh.conf* +%endif fi %postun if [ "$1" -ge 1 ]; then # Find out which daemons need to be restarted. for daemon in %all_daemons ; do - if [ -f /var/lock/subsys/$daemon ]; then - eval restart_$daemon=yes + if [ -f /var/lock/subsys/${daemon} ]; then + eval restart_${daemon}=yes else - eval restart_$daemon=no + eval restart_${daemon}=no fi done # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no - running_watchquagga="$restart_watchquagga" - restart_watchquagga=no - # Stop watchquagga first. - [ "$running_watchquagga" = yes ] && \ - /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 - # Stop all daemons other than zebra and watchquagga. - for daemon in %all_daemons ; do - eval restart=\$restart_${daemon} - [ "$restart" = yes ] && \ - /etc/rc.d/init.d/$daemon stop >/dev/null 2>&1 - done - # Restart zebra. - [ "$running_zebra" = yes ] && \ - /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 - # Start all daemons other than zebra and watchquagga. - for daemon in %all_daemons ; do - eval restart=\$restart_${daemon} - [ "$restart" = yes ] && \ - /etc/rc.d/init.d/$daemon start >/dev/null 2>&1 - done - # Start watchquagga last. - # Avoid postun scriptlet error if watchquagga is not running. - [ "$running_watchquagga" = yes ] && \ - /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : + %if %{with_watchquagga} + running_watchquagga="$restart_watchquagga" + restart_watchquagga=no + %endif + + %if "%{initsystem}" == "systemd" + ## + ## Systemd Version + ## + # No watchquagga for systemd version + # + # Stop all daemons other than zebra. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + %systemd_postun ${daemon}.service + done + # Restart zebra. + [ "$running_zebra" = yes ] && \ + %systemd_postun_with_restart $daemon.service + # Start all daemons other than zebra. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + %systemd_post ${daemon}.service + done + %else + ## + ## init.d Version + ## + %if %{with_watchquagga} + # Stop watchquagga first. + [ "$running_watchquagga" = yes ] && \ + /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 + %endif + # Stop all daemons other than zebra and watchquagga. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 + done + # Restart zebra. + [ "$running_zebra" = yes ] && \ + /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 + # Start all daemons other than zebra and watchquagga. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + /etc/rc.d/init.d/${daemon} start >/dev/null 2>&1 + done + %if %{with_watchquagga} + # Start watchquagga last. + # Avoid postun scriptlet error if watchquagga is not running. + [ "$running_watchquagga" = yes ] && \ + /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : + %endif + %endif fi -/sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %preun -if [ "$1" = "0" ]; then - for daemon in %all_daemons ; do - /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 - /sbin/chkconfig --del ${daemon} - done - /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir -fi +%if "%{initsystem}" == "systemd" + ## + ## Systemd Version + ## + if [ "$1" = "0" ]; then + for daemon in %all_daemons ; do + %systemd_preun ${daemon}.service + done + fi +%else + ## + ## init.d Version + ## + if [ "$1" = "0" ]; then + for daemon in %all_daemons ; do + /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 + /sbin/chkconfig --del ${daemon} + done + fi +%endif +/sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %clean -%if !%{keep_build} -rm -rf $RPM_BUILD_ROOT +%if !0%{?keep_build:1} +rm -rf %{buildroot} %endif %files @@ -371,26 +493,27 @@ rm -rf $RPM_BUILD_ROOT %doc doc/quagga.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO -%if %{quagga_user} +%if 0%{?quagga_user:1} %dir %attr(751,%quagga_user,%quagga_user) %{_sysconfdir} %dir %attr(750,%quagga_user,%quagga_user) /var/log/quagga %dir %attr(751,%quagga_user,%quagga_user) /var/run/quagga %else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/quagga -%dir %attr(755,root,root) /usr/share/info %dir %attr(750,root,root) /var/run/quagga %endif -%if %{vty_group} +%if 0%{?vty_group:1} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif -%{_infodir}/*info* +%{_infodir}/quagga.info.gz %{_mandir}/man*/* %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd -%{_sbindir}/watchquagga +%if %{with_watchquagga} + %{_sbindir}/watchquagga +%endif %{_sbindir}/ripngd %{_sbindir}/ospf6d %if %{with_pimd} @@ -399,17 +522,33 @@ rm -rf $RPM_BUILD_ROOT %if %{with_isisd} %{_sbindir}/isisd %endif -%dir %attr(755,root,root) %{_libdir} %if %{with_shared} -%dir %{_libdir} -%{_libdir}/lib*.so -%{_libdir}/lib*.so.* +%attr(755,root,root) %{_libdir}/lib*.so +%attr(755,root,root) %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* -%config /etc/rc.d/init.d/* +%if "%{initsystem}" == "systemd" + %config %{_unitdir}/*.service +%else + %config /etc/rc.d/init.d/zebra + %if %{with_watchquagga} + %config /etc/rc.d/init.d/watchquagga + %endif + %config /etc/rc.d/init.d/ripd + %config /etc/rc.d/init.d/ospfd + %config /etc/rc.d/init.d/bgpd + %config /etc/rc.d/init.d/ripngd + %config /etc/rc.d/init.d/ospf6d + %if %{with_isisd} + %config /etc/rc.d/init.d/isisd + %endif + %if %{with_pimd} + %config /etc/rc.d/init.d/pimd + %endif +%endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* @@ -435,17 +574,27 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog -* Fri Sep 4 2015 Paul Jakma - %{version} -- package the pimd binary +* Thu Feb 11 2016 Paul Jakma - %{version} - remove with_ipv6 conditionals, always build v6 - Fix UTF-8 char in spec changelog - remove quagga.pam.stack, long deprecated. -* Fri Sep 4 2015 Paul Jakma - %{version} +* Thu Oct 22 2015 Martin Winter +- Cleanup configure: remove --enable-ipv6 (default now), --enable-nssa, + --enable-netlink +- Remove support for old fedora 4/5 +- Fix for package nameing +- Fix Weekdays of previous changelogs (bogus dates) +- Add conditional logic to only build tex footnotes with supported texi2html +- Added pimd to files section and fix double listing of /var/lib*/quagga +- Numerous fixes to unify upstart/systemd startup into same spec file +- Only allow use of watchquagga for non-systemd systems. no need with systemd + +* Fri Sep 4 2015 Paul Jakma - buildreq updates - add a default define for with_pimd -* Thu Sep 12 2005 Paul Jakma +* Mon Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding @@ -498,7 +647,7 @@ rm -rf $RPM_BUILD_ROOT - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) -- delete info file on %preun, not %postun to avoid deletion on upgrade. (RH) +- delete info file on preun, not postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon @@ -510,10 +659,10 @@ rm -rf $RPM_BUILD_ROOT - Renamed to Quagga - Sync to Quagga release 0.96 -* Tue Mar 20 2003 Paul Jakma +* Thu Mar 20 2003 Paul Jakma - zebra privileges support -* Mon Mar 18 2003 Paul Jakma +* Tue Mar 18 2003 Paul Jakma - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp @@ -537,7 +686,7 @@ rm -rf $RPM_BUILD_ROOT - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp -- Added conditional to %files for %_bindir depending on vtysh +- Added conditional to files for _bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma - update to latest CVS @@ -577,7 +726,7 @@ rm -rf $RPM_BUILD_ROOT * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 -* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 +* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) From e84e4d3d2d6127bfd467d9fc18e09450245f7c41 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 15 Feb 2016 14:11:06 +0000 Subject: [PATCH 0984/1342] doc: Distribute a modern version of texinfo.tex with the docs * doc/texinfo.tex: Ship a more recent texinfo.tex, from texinfo 6.1, so we don't have to worry about that. E.g., this should allow UTF-8 unicode chars to be used directly in the text. * doc/Makefile.am: Add previous to EXTRA_DIST --- doc/.gitignore | 1 - doc/Makefile.am | 3 +- doc/texinfo.tex | 11198 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 11200 insertions(+), 2 deletions(-) create mode 100644 doc/texinfo.tex diff --git a/doc/.gitignore b/doc/.gitignore index 5071f9870..ed527fcb2 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -6,7 +6,6 @@ quagga.info-* zebra.html defines.texi version.texi -texinfo.tex quagga.html quagga.info *.pdf diff --git a/doc/Makefile.am b/doc/Makefile.am index 943f06b3a..00d404a74 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -112,7 +112,8 @@ EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ - $(figures_sources) $(figures_png) $(figures_txt) + $(figures_sources) $(figures_png) $(figures_txt) \ + texinfo.tex draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ diff --git a/doc/texinfo.tex b/doc/texinfo.tex new file mode 100644 index 000000000..ddda670ef --- /dev/null +++ b/doc/texinfo.tex @@ -0,0 +1,11198 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{2016-02-05.07} +% +% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, +% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, +% 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 +% Free Software Foundation, Inc. +% +% This texinfo.tex file 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 3 of the +% License, or (at your option) any later version. +% +% This texinfo.tex file is distributed in the hope that it will be +% useful, but WITHOUT ANY WARRANTY; without even the implied warranty +% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . +% +% As a special exception, when this file is read by TeX when processing +% a Texinfo source document, you may use the result without +% restriction. This Exception is an additional permission under section 7 +% of the GNU General Public License, version 3 ("GPLv3"). +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or +% http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or +% http://www.gnu.org/software/texinfo/ (the Texinfo home page) +% The texinfo.tex in any given distribution could well be out +% of date, so if that's what you're using, please check. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever; this makes foo.ps. +% The extra TeX runs get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages, to some +% extent. You can get the existing language-specific files from the +% full Texinfo distribution. +% +% The GNU Texinfo home page is http://www.gnu.org/software/texinfo. + + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +\chardef\other=12 + +% We never want plain's \outer definition of \+ in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +% Save some plain tex macros whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexfootnote=\footnote +\let\ptexgtr=> +\let\ptexhat=^ +\let\ptexi=\i +\let\ptexindent=\indent +\let\ptexinsert=\insert +\let\ptexlbrace=\{ +\let\ptexless=< +\let\ptexnewwrite\newwrite +\let\ptexnoindent=\noindent +\let\ptexplus=+ +\let\ptexraggedright=\raggedright +\let\ptexrbrace=\} +\let\ptexslash=\/ +\let\ptexsp=\sp +\let\ptexstar=\* +\let\ptexsup=\sup +\let\ptext=\t +\let\ptextop=\top +{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Pre-3.0. +\else + \def\linenumber{l.\the\inputlineno:\space} +\fi + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putworderror\undefined \gdef\putworderror{error}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi + +% Give the space character the catcode for a space. +\def\spaceisspace{\catcode`\ =10\relax} + +\chardef\dashChar = `\- +\chardef\slashChar = `\/ +\chardef\underChar = `\_ + +% Ignore a token. +% +\def\gobble#1{} + +% The following is used inside several \edef's. +\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} + +% Hyphenation fixes. +\hyphenation{ + Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script + ap-pen-dix bit-map bit-maps + data-base data-bases eshell fall-ing half-way long-est man-u-script + man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm + par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces + spell-ing spell-ings + stand-alone strong-est time-stamp time-stamps which-ever white-space + wide-spread wrap-around +} + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. We also make +% some effort to order the tracing commands to reduce output in the log +% file; cf. trace.sty in LaTeX. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{% + \tracingstats2 + \tracingpages1 + \tracinglostchars2 % 2 gives us more in etex + \tracingparagraphs1 + \tracingoutput1 + \tracingmacros2 + \tracingrestores1 + \showboxbreadth\maxdimen \showboxdepth\maxdimen + \ifx\eTeXversion\thisisundefined\else % etex gives us more logging + \tracingscantokens1 + \tracingifs1 + \tracinggroups1 + \tracingnesting2 + \tracingassigns1 + \fi + \tracingcommands3 % 3 gives us more in etex + \errorcontextlines16 +}% + +% @errormsg{MSG}. Do the index-like expansions on MSG, but if things +% aren't perfect, it's not the end of the world, being an error message, +% after all. +% +\def\errormsg{\begingroup \indexnofonts \doerrormsg} +\def\doerrormsg#1{\errmessage{#1}} + +% add check for \lastpenalty to plain's definitions. If the last thing +% we did was a \nobreak, we don't want to insert more space. +% +\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount + \removelastskip\penalty-50\smallskip\fi\fi} +\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount + \removelastskip\penalty-100\medskip\fi\fi} +\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount + \removelastskip\penalty-200\bigskip\fi\fi} + +% Output routine +% + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt } + +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Output a mark which sets \thischapter, \thissection and \thiscolor. +% We dump everything together because we only have one kind of mark. +% This works because we only use \botmark / \topmark, not \firstmark. +% +% A mark contains a subexpression of the \ifcase ... \fi construct. +% \get*marks macros below extract the needed part using \ifcase. +% +% Another complication is to let the user choose whether \thischapter +% (\thissection) refers to the chapter (section) in effect at the top +% of a page, or that at the bottom of a page. + +% \domark is called twice inside \chapmacro, to add one +% mark before the section break, and one after. +% In the second call \prevchapterdefs is the same as \lastchapterdefs, +% and \prevsectiondefs is the same as \lastsectiondefs. +% Then if the page is not broken at the mark, some of the previous +% section appears on the page, and we can get the name of this section +% from \firstmark for @everyheadingmarks top. +% @everyheadingmarks bottom uses \botmark. +% +% See page 260 of The TeXbook. +\def\domark{% + \toks0=\expandafter{\lastchapterdefs}% + \toks2=\expandafter{\lastsectiondefs}% + \toks4=\expandafter{\prevchapterdefs}% + \toks6=\expandafter{\prevsectiondefs}% + \toks8=\expandafter{\lastcolordefs}% + \mark{% + \the\toks0 \the\toks2 % 0: marks for @everyheadingmarks top + \noexpand\or \the\toks4 \the\toks6 % 1: for @everyheadingmarks bottom + \noexpand\else \the\toks8 % 2: color marks + }% +} + +% \gettopheadingmarks, \getbottomheadingmarks, +% \getcolormarks - extract needed part of mark. +% +% \topmark doesn't work for the very first chapter (after the title +% page or the contents), so we use \firstmark there -- this gets us +% the mark with the chapter defs, unless the user sneaks in, e.g., +% @setcolor (or @url, or @link, etc.) between @contents and the very +% first @chapter. +\def\gettopheadingmarks{% + \ifcase0\topmark\fi + \ifx\thischapter\empty \ifcase0\firstmark\fi \fi +} +\def\getbottomheadingmarks{\ifcase1\botmark\fi} +\def\getcolormarks{\ifcase2\topmark\fi} + +% Avoid "undefined control sequence" errors. +\def\lastchapterdefs{} +\def\lastsectiondefs{} +\def\lastsection{} +\def\prevchapterdefs{} +\def\prevsectiondefs{} +\def\lastcolordefs{} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen\bindingoffset +\newdimen\normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Main output routine. +% +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. +% \shipout a vbox for a single page, adding an optional header, footer, +% cropmarks, and footnote. This also causes index entries for this page +% to be written to the auxiliary files. +% +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Common context changes for both heading and footing. + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \def\commmonheadfootline{\let\hsize=\pagewidth \texinfochars} + % + % Retrieve the information for the headings from the marks in the page, + % and call Plain TeX's \makeheadline and \makefootline, which use the + % values in \headline and \footline. + % + % This is used to check if we are on the first page of a chapter. + \ifcase1\topmark\fi + \let\prevchaptername\thischaptername + \ifcase0\firstmark\fi + \let\curchaptername\thischaptername + % + \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi + \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi + % + \ifx\curchaptername\prevchaptername + \let\thischapterheading\thischapter + \else + % \thischapterheading is the same as \thischapter except it is blank + % for the first page of a chapter. This is to prevent the chapter name + % being shown twice. + \def\thischapterheading{}% + \fi + % + \global\setbox\headlinebox = \vbox{\commmonheadfootline \makeheadline}% + \global\setbox\footlinebox = \vbox{\commmonheadfootline \makefootline}% + % + {% + % Set context for writing to auxiliary files like index files. + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + % We don't want .vr (or whatever) entries like this: + % \entry{{\indexbackslash }acronym}{32}{\code {\acronym}} + % "\acronym" won't work when it's read back in; + % it needs to be + % {\code {{\backslashcurfont }acronym} + \shipout\vbox{% + % Do this early so pdf references go to the beginning of the page. + \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi + % + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingyyy.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 24pt + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \indexdummies + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +% Main part of page, including any footnotes +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1\relax \unvbox#1\relax +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + + +% Argument parsing + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% For example, \def\foo{\parsearg\fooxxx}. +% +\def\parsearg{\parseargusing{}} +\def\parseargusing#1#2{% + \def\argtorun{#2}% + \begingroup + \obeylines + \spaceisspace + #1% + \parseargline\empty% Insert the \empty token, see \finishparsearg below. +} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + \argremovecomment #1\comment\ArgTerm% + }% +} + +% First remove any @comment, then any @c comment. Also remove a @texinfoc +% comment (see \scanmacro for details). Pass the result on to \argcheckspaces. +\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} +\def\argremovec#1\c#2\ArgTerm{\argremovetexinfoc #1\texinfoc\ArgTerm} +\def\argremovetexinfoc#1\texinfoc#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} + +% Each occurrence of `\^^M' or `\^^M' is replaced by a single space. +% +% \argremovec might leave us with trailing space, e.g., +% @end itemize @c foo +% This space token undergoes the same procedure and is eventually removed +% by \finishparsearg. +% +\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} +\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} +\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% + \def\temp{#3}% + \ifx\temp\empty + % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: + \let\temp\finishparsearg + \else + \let\temp\argcheckspaces + \fi + % Put the space token in: + \temp#1 #3\ArgTerm +} + +% If a _delimited_ argument is enclosed in braces, they get stripped; so +% to get _exactly_ the rest of the line, we had to prevent such situation. +% We prepended an \empty token at the very beginning and we expand it now, +% just before passing the control to \argtorun. +% (Similarly, we have to think about #3 of \argcheckspacesY above: it is +% either the null string, or it ends with \^^M---thus there is no danger +% that a pair of braces would be stripped. +% +% But first, we have to remove the trailing space token. +% +\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} + + +% \parseargdef - define a command taking an argument on the line +% +% \parseargdef\foo{...} +% is roughly equivalent to +% \def\foo{\parsearg\Xfoo} +% \def\Xfoo#1{...} +\def\parseargdef#1{% + \expandafter \doparseargdef \csname\string#1\endcsname #1% +} +\def\doparseargdef#1#2{% + \def#2{\parsearg#1}% + \def#1##1% +} + +% Several utility definitions with active space: +{ + \obeyspaces + \gdef\obeyedspace{ } + + % Make each space character in the input produce a normal interword + % space in the output. Don't allow a line break at this space, as this + % is used only in environments like @example, where each line of input + % should produce a line of output anyway. + % + \gdef\sepspaces{\obeyspaces\let =\tie} + + % If an index command is used in an @example environment, any spaces + % therein should become regular spaces in the raw index file, not the + % expansion of \tie (\leavevmode \penalty \@M \ ). + \gdef\unsepspaces{\let =\space} +} + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +% Define the framework for environments in texinfo.tex. It's used like this: +% +% \envdef\foo{...} +% \def\Efoo{...} +% +% It's the responsibility of \envdef to insert \begingroup before the +% actual body; @end closes the group after calling \Efoo. \envdef also +% defines \thisenv, so the current environment is known; @end checks +% whether the environment name matches. The \checkenv macro can also be +% used to check whether the current environment is the one expected. +% +% Non-false conditionals (@iftex, @ifset) don't fit into this, so they +% are not treated as environments; they don't open a group. (The +% implementation of @end takes care not to call \endgroup in this +% special case.) + + +% At run-time, environments start with this: +\def\startenvironment#1{\begingroup\def\thisenv{#1}} +% initialize +\let\thisenv\empty + +% ... but they get defined via ``\envdef\foo{...}'': +\long\def\envdef#1#2{\def#1{\startenvironment#1#2}} +\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} + +% Check whether we're in the right environment: +\def\checkenv#1{% + \def\temp{#1}% + \ifx\thisenv\temp + \else + \badenverr + \fi +} + +% Environment mismatch, #1 expected: +\def\badenverr{% + \errhelp = \EMsimple + \errmessage{This command can appear only \inenvironment\temp, + not \inenvironment\thisenv}% +} +\def\inenvironment#1{% + \ifx#1\empty + outside of any environment% + \else + in environment \expandafter\string#1% + \fi +} + +% @end foo executes the definition of \Efoo. +% But first, it executes a specialized version of \checkenv +% +\parseargdef\end{% + \if 1\csname iscond.#1\endcsname + \else + % The general wording of \badenverr may not be ideal. + \expandafter\checkenv\csname#1\endcsname + \csname E#1\endcsname + \endgroup + \fi +} + +\newhelp\EMsimple{Press RETURN to continue.} + + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\unskip\hfil\break\hbox{}\ignorespaces} + +% @/ allows a line break. +\let\/=\allowbreak + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=\endofsentencespacefactor\space} + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=\endofsentencespacefactor\space} + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=\endofsentencespacefactor\space} + +% @frenchspacing on|off says whether to put extra space after punctuation. +% +\def\onword{on} +\def\offword{off} +% +\parseargdef\frenchspacing{% + \def\temp{#1}% + \ifx\temp\onword \plainfrenchspacing + \else\ifx\temp\offword \plainnonfrenchspacing + \else + \errhelp = \EMsimple + \errmessage{Unknown @frenchspacing option `\temp', must be on|off}% + \fi\fi +} + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +% Another complication is that the group might be very large. This can +% cause the glue on the previous page to be unduly stretched, because it +% does not have much material. In this case, it's better to add an +% explicit \vfill so that the extra space is at the bottom. The +% threshold for doing this is if the group is more than \vfilllimit +% percent of a page (\vfilllimit can be changed inside of @tex). +% +\newbox\groupbox +\def\vfilllimit{0.7} +% +\envdef\group{% + \ifnum\catcode`\^^M=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + \startsavinginserts + % + \setbox\groupbox = \vtop\bgroup + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% The \vtop produces a box with normal height and large depth; thus, TeX puts +% \baselineskip glue before it, and (when the next line of text is done) +% \lineskip glue after it. Thus, space below is not quite equal to space +% above. But it's pretty close. +\def\Egroup{% + % To get correct interline space between the last line of the group + % and the first line afterwards, we have to propagate \prevdepth. + \endgraf % Not \par, as it may have been set to \lisppar. + \global\dimen1 = \prevdepth + \egroup % End the \vtop. + \addgroupbox + \prevdepth = \dimen1 + \checkinserts +} + +\def\addgroupbox{ + % \dimen0 is the vertical size of the group's box. + \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox + % \dimen2 is how much space is left on the page (more or less). + \dimen2 = \pageheight \advance\dimen2 by -\pagetotal + % if the group doesn't fit on the current page, and it's a big big + % group, force a page break. + \ifdim \dimen0 > \dimen2 + \ifdim \pagetotal < \vfilllimit\pageheight + \page + \fi + \fi + \box\groupbox +} + +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\parseargdef\need{% + % Ensure vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % If the @need value is less than one line space, it's useless. + \dimen0 = #1\mil + \dimen2 = \ht\strutbox + \advance\dimen2 by \dp\strutbox + \ifdim\dimen0 > \dimen2 + % + % Do a \strut just to make the height of this box be normal, so the + % normal leading is inserted relative to the preceding line. + % And a page break here is fine. + \vtop to #1\mil{\strut\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + \fi +} + +% @br forces paragraph break (and is undocumented). + +\let\br = \par + +% @page forces the start of a new page. +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} + +% This defn is used inside nofill environments such as @example. +\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount + \leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current +% paragraph. For more general purposes, use the \margin insertion +% class. WHICH is `l' or `r'. Not documented, written for gawk manual. +% +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} +% +\def\doinmargin#1#2{\strut\vadjust{% + \nobreak + \kern-\strutdepth + \vtop to \strutdepth{% + \baselineskip=\strutdepth + \vss + % if you have multiple lines of stuff to put here, you'll need to + % make the vbox yourself of the appropriate size. + \ifx#1l% + \llap{\ignorespaces #2\hskip\inmarginspacing}% + \else + \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% + \fi + \null + }% +}} +\def\inleftmargin{\doinmargin l} +\def\inrightmargin{\doinmargin r} +% +% @inmargin{TEXT [, RIGHT-TEXT]} +% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; +% else use TEXT for both). +% +\def\inmargin#1{\parseinmargin #1,,\finish} +\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \def\lefttext{#1}% have both texts + \def\righttext{#2}% + \else + \def\lefttext{#1}% have only one text + \def\righttext{#1}% + \fi + % + \ifodd\pageno + \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin + \else + \def\temp{\inleftmargin\lefttext}% + \fi + \temp +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). This command +% is not documented, not supported, and doesn't work. +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% @include FILE -- \input text of FILE. +% +\def\include{\parseargusing\filenamecatcodes\includezzz} +\def\includezzz#1{% + \pushthisfilestack + \def\thisfile{#1}% + {% + \makevalueexpandable % we want to expand any @value in FILE. + \turnoffactive % and allow special characters in the expansion + \indexnofonts % Allow `@@' and other weird things in file names. + \wlog{texinfo.tex: doing @include of #1^^J}% + \edef\temp{\noexpand\input #1 }% + % + % This trickery is to read FILE outside of a group, in case it makes + % definitions, etc. + \expandafter + }\temp + \popthisfilestack +} +\def\filenamecatcodes{% + \catcode`\\=\other + \catcode`~=\other + \catcode`^=\other + \catcode`_=\other + \catcode`|=\other + \catcode`<=\other + \catcode`>=\other + \catcode`+=\other + \catcode`-=\other + \catcode`\`=\other + \catcode`\'=\other +} + +\def\pushthisfilestack{% + \expandafter\pushthisfilestackX\popthisfilestack\StackTerm +} +\def\pushthisfilestackX{% + \expandafter\pushthisfilestackY\thisfile\StackTerm +} +\def\pushthisfilestackY #1\StackTerm #2\StackTerm {% + \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% +} + +\def\popthisfilestack{\errthisfilestackempty} +\def\errthisfilestackempty{\errmessage{Internal error: + the stack of filenames is empty.}} +% +\def\thisfile{} + +% @center line +% outputs that line, centered. +% +\parseargdef\center{% + \ifhmode + \let\centersub\centerH + \else + \let\centersub\centerV + \fi + \centersub{\hfil \ignorespaces#1\unskip \hfil}% + \let\centersub\relax % don't let the definition persist, just in case +} +\def\centerH#1{{% + \hfil\break + \advance\hsize by -\leftskip + \advance\hsize by -\rightskip + \line{#1}% + \break +}} +% +\newcount\centerpenalty +\def\centerV#1{% + % The idea here is the same as in \startdefun, \cartouche, etc.: if + % @center is the first thing after a section heading, we need to wipe + % out the negative parskip inserted by \sectionheading, but still + % prevent a page break here. + \centerpenalty = \lastpenalty + \ifnum\centerpenalty>10000 \vskip\parskip \fi + \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi + \line{\kern\leftskip #1\kern\rightskip}% +} + +% @sp n outputs n lines of vertical space +% +\parseargdef\sp{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment +% +\def\comment{\begingroup \catcode`\^^M=\active% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other\commentxxx}% + +{\catcode`\^^M=\active% +\gdef\commentxxx#1^^M{\endgroup% +\futurelet\nexttoken\commentxxxx}% +\gdef\commentxxxx{\ifx\nexttoken\aftermacro\expandafter\comment\fi}% +} + +\def\c{\begingroup \catcode`\^^M=\active% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\cxxx} +{\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}} +% See comment in \scanmacro about why the definitions of @c and @comment differ + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% NCHARS can also be the word `asis' or `none'. +% We cannot feasibly implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\parseargdef\paragraphindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\parseargdef\exampleindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @firstparagraphindent WORD +% If WORD is `none', then suppress indentation of the first paragraph +% after a section heading. If WORD is `insert', then do indent at such +% paragraphs. +% +% The paragraph indentation is suppressed or not by calling +% \suppressfirstparagraphindent, which the sectioning commands do. +% We switch the definition of this back and forth according to WORD. +% By default, we suppress indentation. +% +\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} +\def\insertword{insert} +% +\parseargdef\firstparagraphindent{% + \def\temp{#1}% + \ifx\temp\noneword + \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent + \else\ifx\temp\insertword + \let\suppressfirstparagraphindent = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @firstparagraphindent option `\temp'}% + \fi\fi +} + +% Here is how we actually suppress indentation. Redefine \everypar to +% \kern backwards by \parindent, and then reset itself to empty. +% +% We also make \indent itself not actually do anything until the next +% paragraph. +% +\gdef\dosuppressfirstparagraphindent{% + \gdef\indent {\restorefirstparagraphindent \indent}% + \gdef\noindent{\restorefirstparagraphindent \noindent}% + \global\everypar = {\kern -\parindent \restorefirstparagraphindent}% +} +% +\gdef\restorefirstparagraphindent{% + \global\let\indent = \ptexindent + \global\let\noindent = \ptexnoindent + \global\everypar = {}% +} + + +% @refill is a no-op. +\let\refill=\relax + +% @setfilename INFO-FILENAME - ignored +\let\setfilename=\comment + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newbox\boxB +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 +% can be set). So we test for \relax and 0 as well as being undefined. +\ifx\pdfoutput\thisisundefined +\else + \ifx\pdfoutput\relax + \else + \ifcase\pdfoutput + \else + \pdftrue + \fi + \fi +\fi + +% PDF uses PostScript string constants for the names of xref targets, +% for display in the outlines, and in other places. Thus, we have to +% double any backslashes. Otherwise, a name like "\node" will be +% interpreted as a newline (\n), followed by o, d, e. Not good. +% +% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and +% related messages. The final outcome is that it is up to the TeX user +% to double the backslashes and otherwise make the string valid, so +% that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to +% do this reliably, so we use it. + +% #1 is a control sequence in which to do the replacements, +% which we \xdef. +\def\txiescapepdf#1{% + \ifx\pdfescapestring\thisisundefined + % No primitive available; should we give a warning or log? + % Many times it won't matter. + \else + % The expandable \pdfescapestring primitive escapes parentheses, + % backslashes, and other special chars. + \xdef#1{\pdfescapestring{#1}}% + \fi +} + +\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images +with PDF output, and none of those formats could be found. (.eps cannot +be supported due to the design of the PDF format; use regular TeX (DVI +output) for that.)} + +\ifpdf + % + % Color manipulation macros using ideas from pdfcolor.tex, + % except using rgb instead of cmyk; the latter is said to render as a + % very dark gray on-screen and a very dark halftone in print, instead + % of actual black. The dark red here is dark enough to print on paper as + % nearly black, but still distinguishable for online viewing. We use + % black by default, though. + \def\rgbDarkRed{0.50 0.09 0.12} + \def\rgbBlack{0 0 0} + % + % rg sets the color for filling (usual text, etc.); + % RG sets the color for stroking (thin rules, e.g., normal _'s). + \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}} + % + % Set color, and create a mark which defines \thiscolor accordingly, + % so that \makeheadline knows which color to restore. + \def\setcolor#1{% + \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% + \domark + \pdfsetcolor{#1}% + } + % + \def\maincolor{\rgbBlack} + \pdfsetcolor{\maincolor} + \edef\thiscolor{\maincolor} + \def\lastcolordefs{} + % + \def\makefootline{% + \baselineskip24pt + \line{\pdfsetcolor{\maincolor}\the\footline}% + } + % + \def\makeheadline{% + \vbox to 0pt{% + \vskip-22.5pt + \line{% + \vbox to8.5pt{}% + % Extract \thiscolor definition from the marks. + \getcolormarks + % Typeset the headline with \maincolor, then restore the color. + \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% + }% + \vss + }% + \nointerlineskip + } + % + % + \pdfcatalog{/PageMode /UseOutlines} + % + % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). + \def\dopdfimage#1#2#3{% + \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% + \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% + % + % pdftex (and the PDF format) support .pdf, .png, .jpg (among + % others). Let's try in that order, PDF first since if + % someone has a scalable image, presumably better to use that than a + % bitmap. + \let\pdfimgext=\empty + \begingroup + \openin 1 #1.pdf \ifeof 1 + \openin 1 #1.PDF \ifeof 1 + \openin 1 #1.png \ifeof 1 + \openin 1 #1.jpg \ifeof 1 + \openin 1 #1.jpeg \ifeof 1 + \openin 1 #1.JPG \ifeof 1 + \errhelp = \nopdfimagehelp + \errmessage{Could not find image file #1 for pdf}% + \else \gdef\pdfimgext{JPG}% + \fi + \else \gdef\pdfimgext{jpeg}% + \fi + \else \gdef\pdfimgext{jpg}% + \fi + \else \gdef\pdfimgext{png}% + \fi + \else \gdef\pdfimgext{PDF}% + \fi + \else \gdef\pdfimgext{pdf}% + \fi + \closein 1 + \endgroup + % + % without \immediate, ancient pdftex seg faults when the same image is + % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) + \ifnum\pdftexversion < 14 + \immediate\pdfimage + \else + \immediate\pdfximage + \fi + \ifdim \wd0 >0pt width \pdfimagewidth \fi + \ifdim \wd2 >0pt height \pdfimageheight \fi + \ifnum\pdftexversion<13 + #1.\pdfimgext + \else + {#1.\pdfimgext}% + \fi + \ifnum\pdftexversion < 14 \else + \pdfrefximage \pdflastximage + \fi} + % + \def\pdfmkdest#1{{% + % We have to set dummies so commands such as @code, and characters + % such as \, aren't expanded when present in a section title. + \indexnofonts + \turnoffactive + \makevalueexpandable + \def\pdfdestname{#1}% + \txiescapepdf\pdfdestname + \safewhatsit{\pdfdest name{\pdfdestname} xyz}% + }} + % + % used to mark target names; must be expandable. + \def\pdfmkpgn#1{#1} + % + % by default, use black for everything. + \def\urlcolor{\rgbBlack} + \def\linkcolor{\rgbBlack} + \def\endlink{\setcolor{\maincolor}\pdfendlink} + % + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by 1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + % + % #1 is the section text, which is what will be displayed in the + % outline by the pdf viewer. #2 is the pdf expression for the number + % of subentries (or empty, for subsubsections). #3 is the node text, + % which might be empty if this toc entry had no corresponding node. + % #4 is the page number + % + \def\dopdfoutline#1#2#3#4{% + % Generate a link to the node text if that exists; else, use the + % page number. We could generate a destination for the section + % text in the case where a section has no node, but it doesn't + % seem worth the trouble, since most documents are normally structured. + \edef\pdfoutlinedest{#3}% + \ifx\pdfoutlinedest\empty + \def\pdfoutlinedest{#4}% + \else + \txiescapepdf\pdfoutlinedest + \fi + % + % Also escape PDF chars in the display string. + \edef\pdfoutlinetext{#1}% + \txiescapepdf\pdfoutlinetext + % + \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% + } + % + \def\pdfmakeoutlines{% + \begingroup + % Read toc silently, to get counts of subentries for \pdfoutline. + \def\partentry##1##2##3##4{}% ignore parts in the outlines + \def\numchapentry##1##2##3##4{% + \def\thischapnum{##2}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + }% + \def\numsecentry##1##2##3##4{% + \advancenumber{chap\thischapnum}% + \def\thissecnum{##2}% + \def\thissubsecnum{0}% + }% + \def\numsubsecentry##1##2##3##4{% + \advancenumber{sec\thissecnum}% + \def\thissubsecnum{##2}% + }% + \def\numsubsubsecentry##1##2##3##4{% + \advancenumber{subsec\thissubsecnum}% + }% + \def\thischapnum{0}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + % + % use \def rather than \let here because we redefine \chapentry et + % al. a second time, below. + \def\appentry{\numchapentry}% + \def\appsecentry{\numsecentry}% + \def\appsubsecentry{\numsubsecentry}% + \def\appsubsubsecentry{\numsubsubsecentry}% + \def\unnchapentry{\numchapentry}% + \def\unnsecentry{\numsecentry}% + \def\unnsubsecentry{\numsubsecentry}% + \def\unnsubsubsecentry{\numsubsubsecentry}% + \readdatafile{toc}% + % + % Read toc second time, this time actually producing the outlines. + % The `-' means take the \expnumber as the absolute number of + % subentries, which we calculated on our first read of the .toc above. + % + % We use the node names as the destinations. + \def\numchapentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% + \def\numsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% + \def\numsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% + \def\numsubsubsecentry##1##2##3##4{% count is always zero + \dopdfoutline{##1}{}{##3}{##4}}% + % + % PDF outlines are displayed using system fonts, instead of + % document fonts. Therefore we cannot use special characters, + % since the encoding is unknown. For example, the eogonek from + % Latin 2 (0xea) gets translated to a | character. Info from + % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. + % + % TODO this right, we have to translate 8-bit characters to + % their "best" equivalent, based on the @documentencoding. Too + % much work for too little return. Just use the ASCII equivalents + % we use for the index sort strings. + % + \indexnofonts + \setupdatafile + % We can have normal brace characters in the PDF outlines, unlike + % Texinfo index files. So set that up. + \def\{{\lbracecharliteral}% + \def\}{\rbracecharliteral}% + \catcode`\\=\active \otherbackslash + \input \tocreadfilename + \endgroup + } + {\catcode`[=1 \catcode`]=2 + \catcode`{=\other \catcode`}=\other + \gdef\lbracecharliteral[{]% + \gdef\rbracecharliteral[}]% + ] + % + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \nextsp} + \def\getfilename#1{% + \filenamelength=0 + % If we don't expand the argument now, \skipspaces will get + % snagged on things like "@value{foo}". + \edef\temp{#1}% + \expandafter\skipspaces\temp|\relax + } + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + % make a live url in pdf output. + \def\pdfurl#1{% + \begingroup + % it seems we really need yet another set of dummies; have not + % tried to figure out what each command should do in the context + % of @url. for now, just make @/ a no-op, that's the only one + % people have actually reported a problem with. + % + \normalturnoffactive + \def\@{@}% + \let\/=\empty + \makevalueexpandable + % do we want to go so far as to use \indexnofonts instead of just + % special-casing \var here? + \def\var##1{##1}% + % + \leavevmode\setcolor{\urlcolor}% + \startlink attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS|\relax + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} + \setcolor{\linkcolor}#1\endlink} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\else + % non-pdf mode + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\setcolor = \gobble + \let\pdfsetcolor = \gobble + \let\pdfmakeoutlines = \relax +\fi % \ifx\pdfoutput + +% +% @image support for XeTeX +% +\newif\ifxeteximgpdf +\ifx\XeTeXrevision\thisisundefined +\else + % + % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). + \def\doxeteximage#1#2#3{% + \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% + \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% + % + % XeTeX (and the PDF format) support .pdf, .png, .jpg (among + % others). Let's try in that order, PDF first since if + % someone has a scalable image, presumably better to use that than a + % bitmap. + \let\xeteximgext=\empty + \xeteximgpdffalse + \begingroup + \openin 1 #1.pdf \ifeof 1 + \openin 1 #1.PDF \ifeof 1 + \openin 1 #1.png \ifeof 1 + \openin 1 #1.jpg \ifeof 1 + \openin 1 #1.jpeg \ifeof 1 + \openin 1 #1.JPG \ifeof 1 + \errmessage{Could not find image file #1 for XeTeX}% + \else \gdef\xeteximgext{JPG}% + \fi + \else \gdef\xeteximgext{jpeg}% + \fi + \else \gdef\xeteximgext{jpg}% + \fi + \else \gdef\xeteximgext{png}% + \fi + \else \gdef\xeteximgext{PDF} \global\xeteximgpdftrue% + \fi + \else \gdef\xeteximgext{pdf} \global\xeteximgpdftrue% + \fi + \closein 1 + \endgroup + % + \ifxeteximgpdf + \XeTeXpdffile "#1".\xeteximgext "" + \else + \XeTeXpicfile "#1".\xeteximgext "" + \fi + \ifdim \wd0 >0pt width \xeteximagewidth \fi + \ifdim \wd2 >0pt height \xeteximageheight \fi \relax + } +\fi + +\message{fonts,} + +% Change the current font style to #1, remembering it in \curfontstyle. +% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in +% italics, not bold italics. +% +\def\setfontstyle#1{% + \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. + \csname ten#1\endcsname % change the current font +} + +% Select #1 fonts with the current style. +% +\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} + +\def\rm{\fam=0 \setfontstyle{rm}} +\def\it{\fam=\itfam \setfontstyle{it}} +\def\sl{\fam=\slfam \setfontstyle{sl}} +\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} +\def\tt{\fam=\ttfam \setfontstyle{tt}} + +% Unfortunately, we have to override this for titles and the like, since +% in those cases "rm" is bold. Sigh. +\def\rmisbold{\rm\def\curfontstyle{bf}} + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf. +\newfam\sffam +\def\sf{\fam=\sffam \setfontstyle{sf}} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this font style. +\def\ttsl{\setfontstyle{ttsl}} + + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +% can get a sort of poor man's double spacing by redefining this. +\def\baselinefactor{1} +% +\newdimen\textleading +\def\setleading#1{% + \dimen0 = #1\relax + \normalbaselineskip = \baselinefactor\dimen0 + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% PDF CMaps. See also LaTeX's t1.cmap. +% +% do nothing with this by default. +\expandafter\let\csname cmapOT1\endcsname\gobble +\expandafter\let\csname cmapOT1IT\endcsname\gobble +\expandafter\let\csname cmapOT1TT\endcsname\gobble + +% if we are producing pdf, and we have \pdffontattr, then define cmaps. +% (\pdffontattr was introduced many years ago, but people still run +% older pdftex's; it's easy to conditionalize, so we do.) +\ifpdf \ifx\pdffontattr\thisisundefined \else + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1-0) +%%Title: (TeX-OT1-0 TeX OT1 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1) +/Supplement 0 +>> def +/CMapName /TeX-OT1-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<23> <26> <0023> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +40 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1IT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1IT-0) +%%Title: (TeX-OT1IT-0 TeX OT1IT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1IT) +/Supplement 0 +>> def +/CMapName /TeX-OT1IT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<25> <26> <0025> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +42 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<23> <0023> +<24> <00A3> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1IT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1TT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1TT-0) +%%Title: (TeX-OT1TT-0 TeX OT1TT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1TT) +/Supplement 0 +>> def +/CMapName /TeX-OT1TT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +5 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<21> <26> <0021> +<28> <5F> <0028> +<61> <7E> <0061> +endbfrange +32 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <2191> +<0C> <2193> +<0D> <0027> +<0E> <00A1> +<0F> <00BF> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<20> <2423> +<27> <2019> +<60> <2018> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1TT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +\fi\fi + + +% Set the font macro #1 to the font named \fontprefix#2. +% #3 is the font's design size, #4 is a scale factor, #5 is the CMap +% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit). +% Example: +% #1 = \textrm +% #2 = \rmshape +% #3 = 10 +% #4 = \mainmagstep +% #5 = OT1 +% +\def\setfont#1#2#3#4#5{% + \font#1=\fontprefix#2#3 scaled #4 + \csname cmap#5\endcsname#1% +} +% This is what gets called when #5 of \setfont is empty. +\let\cmap\gobble +% +% (end of cmaps) + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\thisisundefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} % where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +% Definitions for a main text size of 11pt. (The default in Texinfo.) +% +\def\definetextfontsizexi{% +% Text fonts (11.2pt, magstep1). +\def\textnominalsize{11pt} +\edef\mainmagstep{\magstephalf} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep +\def\textecsize{1095} + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstep1}{OT1} +\setfont\deftt\ttshape{10}{\magstep1}{OT1TT} +\setfont\defsl\slshape{10}{\magstep1}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf +\let\tenttsl=\defttsl \let\tensl=\defsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 +\def\smallecsize{0900} + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 +\def\smallerecsize{0800} + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\titleecsize{2074} + +% Chapter (and unnumbered) fonts (17.28pt). +\def\chapnominalsize{17pt} +\setfont\chaprm\rmbshape{12}{\magstep2}{OT1} +\setfont\chapit\itbshape{10}{\magstep3}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep3}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} +\setfont\chapsf\sfbshape{17}{1000}{OT1} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3}{OT1} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 +\def\chapecsize{1728} + +% Section fonts (14.4pt). +\def\secnominalsize{14pt} +\setfont\secrm\rmbshape{12}{\magstep1}{OT1} +\setfont\secrmnotbold\rmshape{12}{\magstep1}{OT1} +\setfont\secit\itbshape{10}{\magstep2}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep2}{OT1} +\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\secsf\sfbshape{12}{\magstep1}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2}{OT1} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 +\def\sececsize{1440} + +% Subsection fonts (13.15pt). +\def\ssecnominalsize{13pt} +\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} +\setfont\ssecit\itbshape{10}{1315}{OT1IT} +\setfont\ssecsl\slbshape{10}{1315}{OT1} +\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} +\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1315}{OT1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +\def\ssececsize{1200} + +% Reduced fonts for @acro in text (10pt). +\def\reducednominalsize{10pt} +\setfont\reducedrm\rmshape{10}{1000}{OT1} +\setfont\reducedtt\ttshape{10}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{1000}{OT1} +\setfont\reducedit\itshape{10}{1000}{OT1IT} +\setfont\reducedsl\slshape{10}{1000}{OT1} +\setfont\reducedsf\sfshape{10}{1000}{OT1} +\setfont\reducedsc\scshape{10}{1000}{OT1} +\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} +\font\reducedi=cmmi10 +\font\reducedsy=cmsy10 +\def\reducedecsize{1000} + +\textleading = 13.2pt % line spacing for 11pt CM +\textfonts % reset the current fonts +\rm +} % end of 11pt text font size definitions, \definetextfontsizexi + + +% Definitions to make the main text be 10pt Computer Modern, with +% section, chapter, etc., sizes following suit. This is for the GNU +% Press printing of the Emacs 22 manual. Maybe other manuals in the +% future. Used with @smallbook, which sets the leading to 12pt. +% +\def\definetextfontsizex{% +% Text fonts (10pt). +\def\textnominalsize{10pt} +\edef\mainmagstep{1000} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep +\def\textecsize{1000} + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstephalf}{OT1} +\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} +\setfont\defsl\slshape{10}{\magstephalf}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf +\let\tensl=\defsl \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 +\def\smallecsize{0900} + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 +\def\smallerecsize{0800} + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\titleecsize{2074} + +% Chapter fonts (14.4pt). +\def\chapnominalsize{14pt} +\setfont\chaprm\rmbshape{12}{\magstep1}{OT1} +\setfont\chapit\itbshape{10}{\magstep2}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep2}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\chapsf\sfbshape{12}{\magstep1}{OT1} +\let\chapbf\chaprm +\setfont\chapsc\scbshape{10}{\magstep2}{OT1} +\font\chapi=cmmi12 scaled \magstep1 +\font\chapsy=cmsy10 scaled \magstep2 +\def\chapecsize{1440} + +% Section fonts (12pt). +\def\secnominalsize{12pt} +\setfont\secrm\rmbshape{12}{1000}{OT1} +\setfont\secit\itbshape{10}{\magstep1}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep1}{OT1} +\setfont\sectt\ttbshape{12}{1000}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} +\setfont\secsf\sfbshape{12}{1000}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep1}{OT1} +\font\seci=cmmi12 +\font\secsy=cmsy10 scaled \magstep1 +\def\sececsize{1200} + +% Subsection fonts (10pt). +\def\ssecnominalsize{10pt} +\setfont\ssecrm\rmbshape{10}{1000}{OT1} +\setfont\ssecit\itbshape{10}{1000}{OT1IT} +\setfont\ssecsl\slbshape{10}{1000}{OT1} +\setfont\ssectt\ttbshape{10}{1000}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} +\setfont\ssecsf\sfbshape{10}{1000}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1000}{OT1} +\font\sseci=cmmi10 +\font\ssecsy=cmsy10 +\def\ssececsize{1000} + +% Reduced fonts for @acro in text (9pt). +\def\reducednominalsize{9pt} +\setfont\reducedrm\rmshape{9}{1000}{OT1} +\setfont\reducedtt\ttshape{9}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{900}{OT1} +\setfont\reducedit\itshape{9}{1000}{OT1IT} +\setfont\reducedsl\slshape{9}{1000}{OT1} +\setfont\reducedsf\sfshape{9}{1000}{OT1} +\setfont\reducedsc\scshape{10}{900}{OT1} +\setfont\reducedttsl\ttslshape{10}{900}{OT1TT} +\font\reducedi=cmmi9 +\font\reducedsy=cmsy9 +\def\reducedecsize{0900} + +\divide\parskip by 2 % reduce space between paragraphs +\textleading = 12pt % line spacing for 10pt CM +\textfonts % reset the current fonts +\rm +} % end of 10pt text font size definitions, \definetextfontsizex + + +% We provide the user-level command +% @fonttextsize 10 +% (or 11) to redefine the text font size. pt is assumed. +% +\def\xiword{11} +\def\xword{10} +\def\xwordpt{10pt} +% +\parseargdef\fonttextsize{% + \def\textsizearg{#1}% + %\wlog{doing @fonttextsize \textsizearg}% + % + % Set \globaldefs so that documents can use this inside @tex, since + % makeinfo 4.8 does not support it, but we need it nonetheless. + % + \begingroup \globaldefs=1 + \ifx\textsizearg\xword \definetextfontsizex + \else \ifx\textsizearg\xiword \definetextfontsizexi + \else + \errhelp=\EMsimple + \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} + \fi\fi + \endgroup +} + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. We don't +% bother to reset \scriptfont and \scriptscriptfont; awaiting user need. +% +\def\resetmathfonts{% + \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy + \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf + \textfont\ttfam=\tentt \textfont\sffam=\tensf +} + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this because \STYLE needs to also set the +% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire +% \tenSTYLE to set the current font. +% +% Each font-changing command also sets the names \lsize (one size lower) +% and \lllsize (three sizes lower). These relative commands are used +% in, e.g., the LaTeX logo and acronyms. +% +% This all needs generalizing, badly. +% +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy + \let\tenttsl=\textttsl + \def\curfontsize{text}% + \def\lsize{reduced}\def\lllsize{smaller}% + \resetmathfonts \setleading{\textleading}} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \def\curfontsize{title}% + \def\lsize{chap}\def\lllsize{subsec}% + \resetmathfonts \setleading{27pt}} +\def\titlefont#1{{\titlefonts\rmisbold #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \let\tenttsl=\chapttsl + \def\curfontsize{chap}% + \def\lsize{sec}\def\lllsize{text}% + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \let\tenttsl=\secttsl + \def\curfontsize{sec}% + \def\lsize{subsec}\def\lllsize{reduced}% + \resetmathfonts \setleading{17pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \let\tenttsl=\ssecttsl + \def\curfontsize{ssec}% + \def\lsize{text}\def\lllsize{small}% + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts +\def\reducedfonts{% + \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl + \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc + \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy + \let\tenttsl=\reducedttsl + \def\curfontsize{reduced}% + \def\lsize{small}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallfonts{% + \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl + \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc + \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy + \let\tenttsl=\smallttsl + \def\curfontsize{small}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallerfonts{% + \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl + \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc + \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy + \let\tenttsl=\smallerttsl + \def\curfontsize{smaller}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{9.5pt}} + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000}{OT1} +\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 +\setfont\shortcontsl\slshape{12}{1000}{OT1} +\setfont\shortconttt\ttshape{12}{1000}{OT1TT} + +% Define these just so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Set the fonts to use with the @small... environments. +\let\smallexamplefonts = \smallfonts + +% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample +% can fit this many characters: +% 8.5x11=86 smallbook=72 a4=90 a5=69 +% If we use \scriptfonts (8pt), then we can fit this many characters: +% 8.5x11=90+ smallbook=80 a4=90+ a5=77 +% For me, subjectively, the few extra characters that fit aren't worth +% the additional smallness of 8pt. So I'm making the default 9pt. +% +% By the way, for comparison, here's what fits with @example (10pt): +% 8.5x11=71 smallbook=60 a4=75 a5=58 +% --karl, 24jan03. + +% Set up the default fonts, so we can use them for creating boxes. +% +\definetextfontsizexi + + +\message{markup,} + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Markup style infrastructure. \defmarkupstylesetup\INITMACRO will +% define and register \INITMACRO to be called on markup style changes. +% \INITMACRO can check \currentmarkupstyle for the innermost +% style and the set of \ifmarkupSTYLE switches for all styles +% currently in effect. +\newif\ifmarkupvar +\newif\ifmarkupsamp +\newif\ifmarkupkey +%\newif\ifmarkupfile % @file == @samp. +%\newif\ifmarkupoption % @option == @samp. +\newif\ifmarkupcode +\newif\ifmarkupkbd +%\newif\ifmarkupenv % @env == @code. +%\newif\ifmarkupcommand % @command == @code. +\newif\ifmarkuptex % @tex (and part of @math, for now). +\newif\ifmarkupexample +\newif\ifmarkupverb +\newif\ifmarkupverbatim + +\let\currentmarkupstyle\empty + +\def\setupmarkupstyle#1{% + \csname markup#1true\endcsname + \def\currentmarkupstyle{#1}% + \markupstylesetup +} + +\let\markupstylesetup\empty + +\def\defmarkupstylesetup#1{% + \expandafter\def\expandafter\markupstylesetup + \expandafter{\markupstylesetup #1}% + \def#1% +} + +% Markup style setup for left and right quotes. +\defmarkupstylesetup\markupsetuplq{% + \expandafter\let\expandafter \temp + \csname markupsetuplq\currentmarkupstyle\endcsname + \ifx\temp\relax \markupsetuplqdefault \else \temp \fi +} + +\defmarkupstylesetup\markupsetuprq{% + \expandafter\let\expandafter \temp + \csname markupsetuprq\currentmarkupstyle\endcsname + \ifx\temp\relax \markupsetuprqdefault \else \temp \fi +} + +{ +\catcode`\'=\active +\catcode`\`=\active + +\gdef\markupsetuplqdefault{\let`\lq} +\gdef\markupsetuprqdefault{\let'\rq} + +\gdef\markupsetcodequoteleft{\let`\codequoteleft} +\gdef\markupsetcodequoteright{\let'\codequoteright} +} + +\let\markupsetuplqcode \markupsetcodequoteleft +\let\markupsetuprqcode \markupsetcodequoteright +% +\let\markupsetuplqexample \markupsetcodequoteleft +\let\markupsetuprqexample \markupsetcodequoteright +% +\let\markupsetuplqkbd \markupsetcodequoteleft +\let\markupsetuprqkbd \markupsetcodequoteright +% +\let\markupsetuplqsamp \markupsetcodequoteleft +\let\markupsetuprqsamp \markupsetcodequoteright +% +\let\markupsetuplqverb \markupsetcodequoteleft +\let\markupsetuprqverb \markupsetcodequoteright +% +\let\markupsetuplqverbatim \markupsetcodequoteleft +\let\markupsetuprqverbatim \markupsetcodequoteright + +% Allow an option to not use regular directed right quote/apostrophe +% (char 0x27), but instead the undirected quote from cmtt (char 0x0d). +% The undirected quote is ugly, so don't make it the default, but it +% works for pasting with more pdf viewers (at least evince), the +% lilypond developers report. xpdf does work with the regular 0x27. +% +\def\codequoteright{% + \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax + \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax + '% + \else \char'15 \fi + \else \char'15 \fi +} +% +% and a similar option for the left quote char vs. a grave accent. +% Modern fonts display ASCII 0x60 as a grave accent, so some people like +% the code environments to do likewise. +% +\def\codequoteleft{% + \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax + \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax + % [Knuth] pp. 380,381,391 + % \relax disables Spanish ligatures ?` and !` of \tt font. + \relax`% + \else \char'22 \fi + \else \char'22 \fi +} + +% Commands to set the quote options. +% +\parseargdef\codequoteundirected{% + \def\temp{#1}% + \ifx\temp\onword + \expandafter\let\csname SETtxicodequoteundirected\endcsname + = t% + \else\ifx\temp\offword + \expandafter\let\csname SETtxicodequoteundirected\endcsname + = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}% + \fi\fi +} +% +\parseargdef\codequotebacktick{% + \def\temp{#1}% + \ifx\temp\onword + \expandafter\let\csname SETtxicodequotebacktick\endcsname + = t% + \else\ifx\temp\offword + \expandafter\let\csname SETtxicodequotebacktick\endcsname + = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}% + \fi\fi +} + +% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. +\def\noligaturesquoteleft{\relax\lq} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Font commands. + +% #1 is the font command (\sl or \it), #2 is the text to slant. +% If we are in a monospaced environment, however, 1) always use \ttsl, +% and 2) do not add an italic correction. +\def\dosmartslant#1#2{% + \ifusingtt + {{\ttsl #2}\let\next=\relax}% + {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}% + \next +} +\def\smartslanted{\dosmartslant\sl} +\def\smartitalic{\dosmartslant\it} + +% Output an italic correction unless \next (presumed to be the following +% character) is such as not to need one. +\def\smartitaliccorrection{% + \ifx\next,% + \else\ifx\next-% + \else\ifx\next.% + \else\ifx\next\.% + \else\ifx\next\comma% + \else\ptexslash + \fi\fi\fi\fi\fi + \aftersmartic +} + +% Unconditional use \ttsl, and no ic. @var is set to this for defuns. +\def\ttslanted#1{{\ttsl #1}} + +% @cite is like \smartslanted except unconditionally use \sl. We never want +% ttsl for book titles, do we? +\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection} + +\def\aftersmartic{} +\def\var#1{% + \let\saveaftersmartic = \aftersmartic + \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}% + \smartslanted{#1}% +} + +\let\i=\smartitalic +\let\slanted=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @b, explicit bold. Also @strong. +\def\b#1{{\bf #1}} +\let\strong=\b + +% @sansserif, explicit sans. +\def\sansserif#1{{\sf #1}} + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +% Set sfcode to normal for the chars that usually have another value. +% Can't use plain's \frenchspacing because it uses the `\x notation, and +% sometimes \x has an active definition that messes things up. +% +\catcode`@=11 + \def\plainfrenchspacing{% + \sfcode`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m + \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@m + \def\endofsentencespacefactor{1000}% for @. and friends + } + \def\plainnonfrenchspacing{% + \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 + \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 + \def\endofsentencespacefactor{3000}% for @. and friends + } +\catcode`@=\other +\def\endofsentencespacefactor{3000}% default + +% @t, explicit typewriter. +\def\t#1{% + {\tt \rawbackslash \plainfrenchspacing #1}% + \null +} + +% @samp. +\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} + +% @indicateurl is \samp, that is, with quotes. +\let\indicateurl=\samp + +% @code (and similar) prints in typewriter, but with spaces the same +% size as normal in the surrounding text, without hyphenation, etc. +% This is a subroutine for that. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \plainfrenchspacing + #1% + }% + \null % reset spacefactor to 1000 +} + +% We *must* turn on hyphenation at `-' and `_' in @code. +% (But see \codedashfinish below.) +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. +% +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. -- rms. +{ + \catcode`\-=\active \catcode`\_=\active + \catcode`\'=\active \catcode`\`=\active + \global\let'=\rq \global\let`=\lq % default definitions + % + \global\def\code{\begingroup + \setupmarkupstyle{code}% + % The following should really be moved into \setupmarkupstyle handlers. + \catcode\dashChar=\active \catcode\underChar=\active + \ifallowcodebreaks + \let-\codedash + \let_\codeunder + \else + \let-\normaldash + \let_\realunder + \fi + % Given -foo (with a single dash), we do not want to allow a break + % after the hyphen. + \global\let\codedashprev=\codedash + % + \codex + } + % + \gdef\codedash{\futurelet\next\codedashfinish} + \gdef\codedashfinish{% + \normaldash % always output the dash character itself. + % + % Now, output a discretionary to allow a line break, unless + % (a) the next character is a -, or + % (b) the preceding character is a -. + % E.g., given --posix, we do not want to allow a break after either -. + % Given --foo-bar, we do want to allow a break between the - and the b. + \ifx\next\codedash \else + \ifx\codedashprev\codedash + \else \discretionary{}{}{}\fi + \fi + % we need the space after the = for the case when \next itself is a + % space token; it would get swallowed otherwise. As in @code{- a}. + \global\let\codedashprev= \next + } +} +\def\normaldash{-} +% +\def\codex #1{\tclose{#1}\endgroup} + +\def\codeunder{% + % this is all so @math{@code{var_name}+1} can work. In math mode, _ + % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) + % will therefore expand the active definition of _, which is us + % (inside @code that is), therefore an endless loop. + \ifusingtt{\ifmmode + \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. + \else\normalunderscore \fi + \discretionary{}{}{}}% + {\_}% +} + +% An additional complication: the above will allow breaks after, e.g., +% each of the four underscores in __typeof__. This is bad. +% @allowcodebreaks provides a document-level way to turn breaking at - +% and _ on and off. +% +\newif\ifallowcodebreaks \allowcodebreakstrue + +\def\keywordtrue{true} +\def\keywordfalse{false} + +\parseargdef\allowcodebreaks{% + \def\txiarg{#1}% + \ifx\txiarg\keywordtrue + \allowcodebreakstrue + \else\ifx\txiarg\keywordfalse + \allowcodebreaksfalse + \else + \errhelp = \EMsimple + \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}% + \fi\fi +} + +% For @command, @env, @file, @option quotes seem unnecessary, +% so use \code rather than \samp. +\let\command=\code +\let\env=\code +\let\file=\code +\let\option=\code + +% @uref (abbreviation for `urlref') aka @url takes an optional +% (comma-separated) second argument specifying the text to display and +% an optional third arg as text to display instead of (rather than in +% addition to) the url itself. First (mandatory) arg is the url. + +% TeX-only option to allow changing PDF output to show only the second +% arg (if given), and not the url (which is then just the link target). +\newif\ifurefurlonlylink + +% The main macro is \urefbreak, which allows breaking at expected +% places within the url. (There used to be another version, which +% didn't support automatic breaking.) +\def\urefbreak{\begingroup \urefcatcodes \dourefbreak} +\let\uref=\urefbreak +% +\def\dourefbreak#1{\urefbreakfinish #1,,,\finish} +\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example + \unsepspaces + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% look for second arg + \ifdim\wd0 > 0pt + \ifpdf + \ifurefurlonlylink + % PDF plus option to not display url, show just arg + \unhbox0 + \else + % PDF, normally display both arg and url for consistency, + % visibility, if the pdf is eventually used to print, etc. + \unhbox0\ (\urefcode{#1})% + \fi + \else + \unhbox0\ (\urefcode{#1})% DVI, always show arg and url + \fi + \else + \urefcode{#1}% only url given, so show it + \fi + \fi + \endlink +\endgroup} + +% Allow line breaks around only a few characters (only). +\def\urefcatcodes{% + \catcode`\&=\active \catcode`\.=\active + \catcode`\#=\active \catcode`\?=\active + \catcode`\/=\active +} +{ + \urefcatcodes + % + \global\def\urefcode{\begingroup + \setupmarkupstyle{code}% + \urefcatcodes + \let&\urefcodeamp + \let.\urefcodedot + \let#\urefcodehash + \let?\urefcodequest + \let/\urefcodeslash + \codex + } + % + % By default, they are just regular characters. + \global\def&{\normalamp} + \global\def.{\normaldot} + \global\def#{\normalhash} + \global\def?{\normalquest} + \global\def/{\normalslash} +} + +% we put a little stretch before and after the breakable chars, to help +% line breaking of long url's. The unequal skips make look better in +% cmtt at least, especially for dots. +\def\urefprestretchamount{.13em} +\def\urefpoststretchamount{.1em} +\def\urefprestretch{\urefprebreak \hskip0pt plus\urefprestretchamount\relax} +\def\urefpoststretch{\urefpostbreak \hskip0pt plus\urefprestretchamount\relax} +% +\def\urefcodeamp{\urefprestretch \&\urefpoststretch} +\def\urefcodedot{\urefprestretch .\urefpoststretch} +\def\urefcodehash{\urefprestretch \#\urefpoststretch} +\def\urefcodequest{\urefprestretch ?\urefpoststretch} +\def\urefcodeslash{\futurelet\next\urefcodeslashfinish} +{ + \catcode`\/=\active + \global\def\urefcodeslashfinish{% + \urefprestretch \slashChar + % Allow line break only after the final / in a sequence of + % slashes, to avoid line break between the slashes in http://. + \ifx\next/\else \urefpoststretch \fi + } +} + +% One more complication: by default we'll break after the special +% characters, but some people like to break before the special chars, so +% allow that. Also allow no breaking at all, for manual control. +% +\parseargdef\urefbreakstyle{% + \def\txiarg{#1}% + \ifx\txiarg\wordnone + \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak} + \else\ifx\txiarg\wordbefore + \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak} + \else\ifx\txiarg\wordafter + \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak} + \else + \errhelp = \EMsimple + \errmessage{Unknown @urefbreakstyle setting `\txiarg'}% + \fi\fi\fi +} +\def\wordafter{after} +\def\wordbefore{before} +\def\wordnone{none} + +\urefbreakstyle after + +% @url synonym for @uref, since that's how everyone uses it. +% +\let\url=\uref + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} +\else + \let\email=\uref +\fi + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\parseargdef\kbdinputstyle{% + \def\txiarg{#1}% + \ifx\txiarg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\txiarg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\txiarg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \else + \errhelp = \EMsimple + \errmessage{Unknown @kbdinputstyle setting `\txiarg'}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is `distinct'. +\kbdinputstyle distinct + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. +\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}} + +\def\xkey{\key} +\def\kbdsub#1#2#3\par{% + \def\one{#1}\def\three{#3}\def\threex{??}% + \ifx\one\xkey\ifx\threex\three \key{#2}% + \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi + \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi +} + +% definition of @key that produces a lozenge. Doesn't adjust to text size. +%\setfont\keyrm\rmshape{8}{1000}{OT1} +%\font\keysy=cmsy9 +%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% +% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% +% \vbox{\hrule\kern-0.4pt +% \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% +% \kern-0.4pt\hrule}% +% \kern-.06em\raise0.4pt\hbox{\angleright}}}} + +% definition of @key with no lozenge. If the current font is already +% monospace, don't change it; that way, we respect @kbdinputstyle. But +% if it isn't monospace, then use \tt. +% +\def\key#1{{\setupmarkupstyle{key}% + \nohyphenation + \ifmonospace\else\tt\fi + #1}\null} + +% @clicksequence{File @click{} Open ...} +\def\clicksequence#1{\begingroup #1\endgroup} + +% @clickstyle @arrow (by default) +\parseargdef\clickstyle{\def\click{#1}} +\def\click{\arrow} + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +% @acronym for "FBI", "NATO", and the like. +% We print this one point size smaller, since it's intended for +% all-uppercase. +% +\def\acronym#1{\doacronym #1,,\finish} +\def\doacronym#1,#2,#3\finish{% + {\selectfonts\lsize #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi + \null % reset \spacefactor=1000 +} + +% @abbr for "Comput. J." and the like. +% No font change, but don't do end-of-sentence spacing. +% +\def\abbr#1{\doabbr #1,,\finish} +\def\doabbr#1,#2,#3\finish{% + {\plainfrenchspacing #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi + \null % reset \spacefactor=1000 +} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math outputs its argument in math mode. +% +% One complication: _ usually means subscripts, but it could also mean +% an actual _ character, as in @math{@var{some_variable} + 1}. So make +% _ active, and distinguish by seeing if the current family is \slfam, +% which is what @var uses. +{ + \catcode`\_ = \active + \gdef\mathunderscore{% + \catcode`\_=\active + \def_{\ifnum\fam=\slfam \_\else\sb\fi}% + } +} +% Another complication: we want \\ (and @\) to output a math (or tt) \. +% FYI, plain.tex uses \\ as a temporary control sequence (for no +% particular reason), but this is not advertised and we don't care. +% +% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. +\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} +% +\def\math{% + \ifmmode\else % only go into math if not in math mode already + \tex + \mathunderscore + \let\\ = \mathbackslash + \mathactive + % make the texinfo accent commands work in math mode + \let\"=\ddot + \let\'=\acute + \let\==\bar + \let\^=\hat + \let\`=\grave + \let\u=\breve + \let\v=\check + \let\~=\tilde + \let\dotaccent=\dot + % have to provide another name for sup operator + \let\mathopsup=\sup + $\expandafter\finishmath\fi +} +\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. + +% Some active characters (such as <) are spaced differently in math. +% We have to reset their definitions in case the @math was an argument +% to a command which sets the catcodes (such as @item or @section). +% +{ + \catcode`^ = \active + \catcode`< = \active + \catcode`> = \active + \catcode`+ = \active + \catcode`' = \active + \gdef\mathactive{% + \let^ = \ptexhat + \let< = \ptexless + \let> = \ptexgtr + \let+ = \ptexplus + \let' = \ptexquoteright + } +} + +% for @sub and @sup, if in math mode, just do a normal sub/superscript. +% If in text, use math to place as sub/superscript, but switch +% into text mode, with smaller fonts. This is a different font than the +% one used for real math sub/superscripts (8pt vs. 7pt), but let's not +% fix it (significant additions to font machinery) until someone notices. +% +\def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi} +\def\finishsub#1{$\sb{\hbox{\selectfonts\lllsize #1}}$}% +% +\def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi} +\def\finishsup#1{$\ptexsp{\hbox{\selectfonts\lllsize #1}}$}% + +% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}. +% Ignore unless FMTNAME == tex; then it is like @iftex and @tex, +% except specified as a normal braced arg, so no newlines to worry about. +% +\def\outfmtnametex{tex} +% +\long\def\inlinefmt#1{\doinlinefmt #1,\finish} +\long\def\doinlinefmt#1,#2,\finish{% + \def\inlinefmtname{#1}% + \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi +} +% +% @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if +% FMTNAME is tex, else ELSE-TEXT. +\long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish} +\long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{% + \def\inlinefmtname{#1}% + \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi +} +% +% For raw, must switch into @tex before parsing the argument, to avoid +% setting catcodes prematurely. Doing it this way means that, for +% example, @inlineraw{html, foo{bar} gets a parse error instead of being +% ignored. But this isn't important because if people want a literal +% *right* brace they would have to use a command anyway, so they may as +% well use a command to get a left brace too. We could re-use the +% delimiter character idea from \verb, but it seems like overkill. +% +\long\def\inlineraw{\tex \doinlineraw} +\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish} +\def\doinlinerawtwo#1,#2,\finish{% + \def\inlinerawname{#1}% + \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi + \endgroup % close group opened by \tex. +} + +% @inlineifset{VAR, TEXT} expands TEXT if VAR is @set. +% +\long\def\inlineifset#1{\doinlineifset #1,\finish} +\long\def\doinlineifset#1,#2,\finish{% + \def\inlinevarname{#1}% + \expandafter\ifx\csname SET\inlinevarname\endcsname\relax + \else\ignorespaces#2\fi +} + +% @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set. +% +\long\def\inlineifclear#1{\doinlineifclear #1,\finish} +\long\def\doinlineifclear#1,#2,\finish{% + \def\inlinevarname{#1}% + \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi +} + + +\message{glyphs,} +% and logos. + +% @@ prints an @, as does @atchar{}. +\def\@{\char64 } +\let\atchar=\@ + +% @{ @} @lbracechar{} @rbracechar{} all generate brace characters. +% Unless we're in typewriter, use \ecfont because the CM text fonts do +% not have braces, and we don't want to switch into math. +\def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}} +\def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}} +\let\{=\mylbrace \let\lbracechar=\{ +\let\}=\myrbrace \let\rbracechar=\} +\begingroup + % Definitions to produce \{ and \} commands for indices, + % and @{ and @} for the aux/toc files. + \catcode`\{ = \other \catcode`\} = \other + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\! = 0 \catcode`\\ = \other + !gdef!lbracecmd[\{]% + !gdef!rbracecmd[\}]% + !gdef!lbraceatcmd[@{]% + !gdef!rbraceatcmd[@}]% +!endgroup + +% @comma{} to avoid , parsing problems. +\let\comma = , + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. +\let\, = \ptexc +\let\dotaccent = \ptexdot +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \ptext +\let\ubaraccent = \ptexb +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown @ordf @ordm +% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} +\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} +\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi + \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% The \TeX{} logo, as in plain, but resetting the spacing so that a +% period following counts as ending a sentence. (Idea found in latex.) +% +\edef\TeX{\TeX \spacefactor=1000 } + +% @LaTeX{} logo. Not quite the same results as the definition in +% latex.ltx, since we use a different font for the raised A; it's most +% convenient for us to use an explicitly smaller font, rather than using +% the \scriptstyle font (since we don't reset \scriptstyle and +% \scriptscriptstyle). +% +\def\LaTeX{% + L\kern-.36em + {\setbox0=\hbox{T}% + \vbox to \ht0{\hbox{% + \ifx\textnominalsize\xwordpt + % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX. + % Revert to plain's \scriptsize, which is 7pt. + \count255=\the\fam $\fam\count255 \scriptstyle A$% + \else + % For 11pt, we can use our lllsize. + \selectfonts\lllsize A% + \fi + }% + \vss + }}% + \kern-.15em + \TeX +} + +% Some math mode symbols. Define \ensuremath to switch into math mode +% unless we are already there. Expansion tricks may not be needed here, +% but safer, and can't hurt. +\def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi} +\def\ensuredmath#1{$\relax#1$} +% +\def\bullet{\ensuremath\ptexbullet} +\def\geq{\ensuremath\ge} +\def\leq{\ensuremath\le} +\def\minus{\ensuremath-} + +% @dots{} outputs an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in the cm +% typewriter fonts as three actual period characters; on the other hand, +% in other typewriter fonts three periods are wider than 1.5em. So do +% whichever is larger. +% +\def\dots{% + \leavevmode + \setbox0=\hbox{...}% get width of three periods + \ifdim\wd0 > 1.5em + \dimen0 = \wd0 + \else + \dimen0 = 1.5em + \fi + \hbox to \dimen0{% + \hskip 0pt plus.25fil + .\hskip 0pt plus1fil + .\hskip 0pt plus1fil + .\hskip 0pt plus.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \dots + \spacefactor=\endofsentencespacefactor +} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +% +% Since these characters are used in examples, they should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% +\def\point{$\star$} +\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} +\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% The @error{} command. +% Adapted from the TeXbook's \boxit. +% +\newbox\errorbox +% +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt} +% +\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{% + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} +% +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @pounds{} is a sterling sign, which Knuth put in the CM italic font. +% +\def\pounds{{\it\$}} + +% @euro{} comes from a separate font, depending on the current style. +% We use the free feym* fonts from the eurosym package by Henrik +% Theiling, which support regular, slanted, bold and bold slanted (and +% "outlined" (blackboard board, sort of) versions, which we don't need). +% It is available from http://www.ctan.org/tex-archive/fonts/eurosym. +% +% Although only regular is the truly official Euro symbol, we ignore +% that. The Euro is designed to be slightly taller than the regular +% font height. +% +% feymr - regular +% feymo - slanted +% feybr - bold +% feybo - bold slanted +% +% There is no good (free) typewriter version, to my knowledge. +% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. +% Hmm. +% +% Also doesn't work in math. Do we need to do math with euro symbols? +% Hope not. +% +% +\def\euro{{\eurofont e}} +\def\eurofont{% + % We set the font at each command, rather than predefining it in + % \textfonts and the other font-switching commands, so that + % installations which never need the symbol don't have to have the + % font installed. + % + % There is only one designed size (nominal 10pt), so we always scale + % that to the current nominal size. + % + % By the way, simply using "at 1em" works for cmr10 and the like, but + % does not work for cmbx10 and other extended/shrunken fonts. + % + \def\eurosize{\csname\curfontsize nominalsize\endcsname}% + % + \ifx\curfontstyle\bfstylename + % bold: + \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize + \else + % regular: + \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize + \fi + \thiseurofont +} + +% Glyphs from the EC fonts. We don't use \let for the aliases, because +% sometimes we redefine the original macro, and the alias should reflect +% the redefinition. +% +% Use LaTeX names for the Icelandic letters. +\def\DH{{\ecfont \char"D0}} % Eth +\def\dh{{\ecfont \char"F0}} % eth +\def\TH{{\ecfont \char"DE}} % Thorn +\def\th{{\ecfont \char"FE}} % thorn +% +\def\guillemetleft{{\ecfont \char"13}} +\def\guillemotleft{\guillemetleft} +\def\guillemetright{{\ecfont \char"14}} +\def\guillemotright{\guillemetright} +\def\guilsinglleft{{\ecfont \char"0E}} +\def\guilsinglright{{\ecfont \char"0F}} +\def\quotedblbase{{\ecfont \char"12}} +\def\quotesinglbase{{\ecfont \char"0D}} +% +% This positioning is not perfect (see the ogonek LaTeX package), but +% we have the precomposed glyphs for the most common cases. We put the +% tests to use those glyphs in the single \ogonek macro so we have fewer +% dummy definitions to worry about for index entries, etc. +% +% ogonek is also used with other letters in Lithuanian (IOU), but using +% the precomposed glyphs for those is not so easy since they aren't in +% the same EC font. +\def\ogonek#1{{% + \def\temp{#1}% + \ifx\temp\macrocharA\Aogonek + \else\ifx\temp\macrochara\aogonek + \else\ifx\temp\macrocharE\Eogonek + \else\ifx\temp\macrochare\eogonek + \else + \ecfont \setbox0=\hbox{#1}% + \ifdim\ht0=1ex\accent"0C #1% + \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% + \fi + \fi\fi\fi\fi + }% +} +\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} +\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} +\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} +\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} +% +% Use the European Computer Modern fonts (cm-super in outline format) +% for non-CM glyphs. That is ec* for regular text and tc* for the text +% companion symbols (LaTeX TS1 encoding). Both are part of the ec +% package and follow the same conventions. +% +\def\ecfont{\etcfont{e}} +\def\tcfont{\etcfont{t}} +% +\def\etcfont#1{% + % We can't distinguish serif/sans and italic/slanted, but this + % is used for crude hacks anyway (like adding French and German + % quotes to documents typeset with CM, where we lose kerning), so + % hopefully nobody will notice/care. + \edef\ecsize{\csname\curfontsize ecsize\endcsname}% + \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% + \ifmonospace + % typewriter: + \font\thisecfont = #1ctt\ecsize \space at \nominalsize + \else + \ifx\curfontstyle\bfstylename + % bold: + \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize + \else + % regular: + \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize + \fi + \fi + \thisecfont +} + +% @registeredsymbol - R in a circle. The font for the R should really +% be smaller yet, but lllsize is the best we can do for now. +% Adapted from the plain.tex definition of \copyright. +% +\def\registeredsymbol{% + $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% + \hfil\crcr\Orb}}% + }$% +} + +% @textdegree - the normal degrees sign. +% +\def\textdegree{$^\circ$} + +% Laurent Siebenmann reports \Orb undefined with: +% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 +% so we'll define it if necessary. +% +\ifx\Orb\thisisundefined +\def\Orb{\mathhexbox20D} +\fi + +% Quotes. +\chardef\quotedblleft="5C +\chardef\quotedblright=`\" +\chardef\quoteleft=`\` +\chardef\quoteright=`\' + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\parseargdef\shorttitlepage{% + \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\envdef\titlepage{% + % Open one extra group, as we want to close it in the middle of \Etitlepage. + \begingroup + \parindent=0pt \textfonts + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \let\page = \oldpage + \page + \null + }% +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % Need this before the \...aftertitlepage checks so that if they are + % in effect the toc pages will come out with page numbers. + \HEADINGSon + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +% Settings used for typesetting titles: no hyphenation, no indentation, +% don't worry much about spacing, ragged right. This should be used +% inside a \vbox, and fonts need to be set appropriately first. Because +% it is always used for titles, nothing else, we call \rmisbold. \par +% should be specified before the end of the \vbox, since a vbox is a group. +% +\def\raggedtitlesettings{% + \rmisbold + \hyphenpenalty=10000 + \parindent=0pt + \tolerance=5000 + \ptexraggedright +} + +% Macros to be used within @titlepage: + +\let\subtitlerm=\tenrm +\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} + +\parseargdef\title{% + \checkenv\titlepage + \vbox{\titlefonts \raggedtitlesettings #1\par}% + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt +} + +\parseargdef\subtitle{% + \checkenv\titlepage + {\subtitlefont \rightline{#1}}% +} + +% @author should come last, but may come many times. +% It can also be used inside @quotation. +% +\parseargdef\author{% + \def\temp{\quotation}% + \ifx\thisenv\temp + \def\quotationauthor{#1}% printed in \Equotation. + \else + \checkenv\titlepage + \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi + {\secfonts\rmisbold \leftline{#1}}% + \fi +} + + +% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make \makeheadline and \makefootline in Plain TeX use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + + +\def\evenheading{\parsearg\evenheadingxxx} +\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} +\def\evenheadingyyy #1\|#2\|#3\|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddheading{\parsearg\oddheadingxxx} +\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} +\def\oddheadingyyy #1\|#2\|#3\|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} +\def\evenfootingyyy #1\|#2\|#3\|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddfooting{\parsearg\oddfootingxxx} +\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} +\def\oddfootingyyy #1\|#2\|#3\|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -12pt + \global\advance\vsize by -12pt +} + +\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} + +% @evenheadingmarks top \thischapter <- chapter at the top of a page +% @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page +% +% The same set of arguments for: +% +% @oddheadingmarks +% @evenfootingmarks +% @oddfootingmarks +% @everyheadingmarks +% @everyfootingmarks + +% These define \getoddheadingmarks, \getevenheadingmarks, +% \getoddfootingmarks, and \getevenfootingmarks, each to one of +% \gettopheadingmarks, \getbottomheadingmarks. +% +\def\evenheadingmarks{\headingmarks{even}{heading}} +\def\oddheadingmarks{\headingmarks{odd}{heading}} +\def\evenfootingmarks{\headingmarks{even}{footing}} +\def\oddfootingmarks{\headingmarks{odd}{footing}} +\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} + \headingmarks{odd}{heading}{#1} } +\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} + \headingmarks{odd}{footing}{#1} } +% #1 = even/odd, #2 = heading/footing, #3 = top/bottom. +\def\headingmarks#1#2#3 {% + \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname + \global\expandafter\let\csname get#1#2marks\endcsname \temp +} + +\everyheadingmarks bottom +\everyfootingmarks bottom + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\headingsoff{% non-global headings elimination + \evenheadline={\hfil}\evenfootline={\hfil}% + \oddheadline={\hfil}\oddfootline={\hfil}% +} + +\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting +\HEADINGSoff % it's the default + +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapterheading\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapterheading\hfil\folio}} +\global\oddheadline={\line{\thischapterheading\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapterheading\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapterheading\hfil\folio}} +\global\oddheadline={\line{\thischapterheading\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% This produces Day Month Year style of output. +% Only define if not already defined, in case a txi-??.tex file has set +% up a different format (e.g., txi-cs.tex does this). +\ifx\today\thisisundefined +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} +\fi + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg{\gdef\thistitle}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @ftable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemindicate{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil\relax + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. However, if + % what follows is an environment such as @example, there will be no + % \parskip glue; then the negative vskip we just inserted would + % cause the example and the item to crash together. So we use this + % bizarre value of 10001 as a signal to \aboveenvbreak to insert + % \parskip glue after all. Section titles are handled this way also. + % + \penalty 10001 + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a list environment}} +\def\itemx{\errmessage{@itemx while not in a list environment}} + +% @table, @ftable, @vtable. +\envdef\table{% + \let\itemindex\gobble + \tablecheck{table}% +} +\envdef\ftable{% + \def\itemindex ##1{\doind {fn}{\code{##1}}}% + \tablecheck{ftable}% +} +\envdef\vtable{% + \def\itemindex ##1{\doind {vr}{\code{##1}}}% + \tablecheck{vtable}% +} +\def\tablecheck#1{% + \ifnum \the\catcode`\^^M=\active + \endgroup + \errmessage{This command won't work in this context; perhaps the problem is + that we are \inenvironment\thisenv}% + \def\next{\doignore{#1}}% + \else + \let\next\tablex + \fi + \next +} +\def\tablex#1{% + \def\itemindicate{#1}% + \parsearg\tabley +} +\def\tabley#1{% + {% + \makevalueexpandable + \edef\temp{\noexpand\tablez #1\space\space\space}% + \expandafter + }\temp \endtablez +} +\def\tablez #1 #2 #3 #4\endtablez{% + \aboveenvbreak + \ifnum 0#1>0 \advance \leftskip by #1\mil \fi + \ifnum 0#2>0 \tableindent=#2\mil \fi + \ifnum 0#3>0 \advance \rightskip by #3\mil \fi + \itemmax=\tableindent + \advance \itemmax by -\itemmargin + \advance \leftskip by \tableindent + \exdentamount=\tableindent + \parindent = 0pt + \parskip = \smallskipamount + \ifdim \parskip=0pt \parskip=2pt \fi + \let\item = \internalBitem + \let\itemx = \internalBitemx +} +\def\Etable{\endgraf\afterenvbreak} +\let\Eftable\Etable +\let\Evtable\Etable +\let\Eitemize\Etable +\let\Eenumerate\Etable + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\envdef\itemize{\parsearg\doitemize} + +\def\doitemize#1{% + \aboveenvbreak + \itemmax=\itemindent + \advance\itemmax by -\itemmargin + \advance\leftskip by \itemindent + \exdentamount=\itemindent + \parindent=0pt + \parskip=\smallskipamount + \ifdim\parskip=0pt \parskip=2pt \fi + % + % Try typesetting the item mark so that if the document erroneously says + % something like @itemize @samp (intending @table), there's an error + % right away at the @itemize. It's not the best error message in the + % world, but it's better than leaving it to the @item. This means if + % the user wants an empty mark, they have to say @w{} not just @w. + \def\itemcontents{#1}% + \setbox0 = \hbox{\itemcontents}% + % + % @itemize with no arg is equivalent to @itemize @bullet. + \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi + % + \let\item=\itemizeitem +} + +% Definition of @item while inside @itemize and @enumerate. +% +\def\itemizeitem{% + \advance\itemno by 1 % for enumerations + {\let\par=\endgraf \smallbreak}% reasonable place to break + {% + % If the document has an @itemize directly after a section title, a + % \nobreak will be last on the list, and \sectionheading will have + % done a \vskip-\parskip. In that case, we don't want to zero + % parskip, or the item text will crash with the heading. On the + % other hand, when there is normal text preceding the item (as there + % usually is), we do want to zero parskip, or there would be too much + % space. In that case, we won't have a \nobreak before. At least + % that's the theory. + \ifnum\lastpenalty<10000 \parskip=0in \fi + \noindent + \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% + % + \ifinner\else + \vadjust{\penalty 1200}% not good to break after first line of item. + \fi + % We can be in inner vertical mode in a footnote, although an + % @itemize looks awful there. + }% + \flushcr +} + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\envparseargdef\enumerate{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call \doitemize, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \doitemize{#1.}\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab do not need to be on their own lines, but it will not hurt +% if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the @columnfraction, usually a decimal number like .5, but might +% be just 1. We just use it, whatever it is. +% +\def\pickupwholefraction#1 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a + % separator; typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable-only commands. +% +% @headitem starts a heading row, which we typeset in bold. Assignments +% have to be global since we are inside the implicit group of an +% alignment entry. \everycr below resets \everytab so we don't have to +% undo it ourselves. +\def\headitemfont{\b}% for people to use in the template row; not changeable +\def\headitem{% + \checkenv\multitable + \crcr + \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings + \global\everytab={\bf}% can't use \headitemfont since the parsing differs + \the\everytab % for the first item +}% +% +% default for tables with no headings. +\let\headitemcrhook=\relax +% +% A \tab used to include \hskip1sp. But then the space in a template +% line is not enough. That is bad. So let's go back to just `&' until +% we again encounter the problem the 1sp was intended to solve. +% --karl, nathan@acm.org, 20apr99. +\def\tab{\checkenv\multitable &\the\everytab}% + +% @multitable ... @end multitable definitions: +% +\newtoks\everytab % insert after every tab. +% +\envdef\multitable{% + \vskip\parskip + \startsavinginserts + % + % @item within a multitable starts a normal row. + % We use \def instead of \let so that if one of the multitable entries + % contains an @itemize, we don't choke on the \item (seen as \crcr aka + % \endtemplate) expanding \doitemize. + \def\item{\crcr}% + % + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + % + \everycr = {% + \noalign{% + \global\everytab={}% Reset from possible headitem. + \global\colcount=0 % Reset the column counter. + % + % Check for saved footnotes, etc.: + \checkinserts + % + % Perhaps a \nobreak, then reset: + \headitemcrhook + \global\let\headitemcrhook=\relax + }% + }% + % + \parsearg\domultitable +} +\def\domultitable#1{% + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup &% + \global\advance\colcount by 1 + \multistrut + \vtop{% + % Use the current \colcount to find the correct column width: + \hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively + % marking characters. + \noindent\ignorespaces##\unskip\multistrut + }\cr +} +\def\Emultitable{% + \crcr + \egroup % end the \halign + \global\setpercentfalse +} + +\def\setmultitablespacing{% + \def\multistrut{\strut}% just use the standard line spacing + % + % Compute \multitablelinespace (if not defined by user) for use in + % \multitableparskip calculation. We used define \multistrut based on + % this, but (ironically) that caused the spacing to be off. + % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. +\ifdim\multitablelinespace=0pt +\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip +\global\advance\multitablelinespace by-\ht0 +\fi +% Test to see if parskip is larger than space between lines of +% table. If not, do nothing. +% If so, set to same dimension as multitablelinespace. +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller + % than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller + % than skip between lines in the table. +\fi} + + +\message{conditionals,} + +% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, +% @ifnotxml always succeed. They currently do nothing; we don't +% attempt to check whether the conditionals are properly nested. But we +% have to remember that they are conditionals, so that @end doesn't +% attempt to close an environment group. +% +\def\makecond#1{% + \expandafter\let\csname #1\endcsname = \relax + \expandafter\let\csname iscond.#1\endcsname = 1 +} +\makecond{iftex} +\makecond{ifnotdocbook} +\makecond{ifnothtml} +\makecond{ifnotinfo} +\makecond{ifnotplaintext} +\makecond{ifnotxml} + +% Ignore @ignore, @ifhtml, @ifinfo, and the like. +% +\def\direntry{\doignore{direntry}} +\def\documentdescription{\doignore{documentdescription}} +\def\docbook{\doignore{docbook}} +\def\html{\doignore{html}} +\def\ifdocbook{\doignore{ifdocbook}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifinfo{\doignore{ifinfo}} +\def\ifnottex{\doignore{ifnottex}} +\def\ifplaintext{\doignore{ifplaintext}} +\def\ifxml{\doignore{ifxml}} +\def\ignore{\doignore{ignore}} +\def\menu{\doignore{menu}} +\def\xml{\doignore{xml}} + +% Ignore text until a line `@end #1', keeping track of nested conditionals. +% +% A count to remember the depth of nesting. +\newcount\doignorecount + +\def\doignore#1{\begingroup + % Scan in ``verbatim'' mode: + \obeylines + \catcode`\@ = \other + \catcode`\{ = \other + \catcode`\} = \other + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \spaceisspace + % + % Count number of #1's that we've seen. + \doignorecount = 0 + % + % Swallow text until we reach the matching `@end #1'. + \dodoignore{#1}% +} + +{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. + \obeylines % + % + \gdef\dodoignore#1{% + % #1 contains the command name as a string, e.g., `ifinfo'. + % + % Define a command to find the next `@end #1'. + \long\def\doignoretext##1^^M@end #1{% + \doignoretextyyy##1^^M@#1\_STOP_}% + % + % And this command to find another #1 command, at the beginning of a + % line. (Otherwise, we would consider a line `@c @ifset', for + % example, to count as an @ifset for nesting.) + \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% + % + % And now expand that command. + \doignoretext ^^M% + }% +} + +\def\doignoreyyy#1{% + \def\temp{#1}% + \ifx\temp\empty % Nothing found. + \let\next\doignoretextzzz + \else % Found a nested condition, ... + \advance\doignorecount by 1 + \let\next\doignoretextyyy % ..., look for another. + % If we're here, #1 ends with ^^M\ifinfo (for example). + \fi + \next #1% the token \_STOP_ is present just after this macro. +} + +% We have to swallow the remaining "\_STOP_". +% +\def\doignoretextzzz#1{% + \ifnum\doignorecount = 0 % We have just found the outermost @end. + \let\next\enddoignore + \else % Still inside a nested condition. + \advance\doignorecount by -1 + \let\next\doignoretext % Look for the next @end. + \fi + \next +} + +% Finish off ignored text. +{ \obeylines% + % Ignore anything after the last `@end #1'; this matters in verbatim + % environments, where otherwise the newline after an ignored conditional + % would result in a blank line in the output. + \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% +} + + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% We rely on the fact that \parsearg sets \catcode`\ =10. +% +\parseargdef\set{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + {% + \makevalueexpandable + \def\temp{#2}% + \edef\next{\gdef\makecsname{SET#1}}% + \ifx\temp\empty + \next{}% + \else + \setzzz#2\endsetzzz + \fi + }% +} +% Remove the trailing space \setxxx inserted. +\def\setzzz#1 \endsetzzz{\next{#1}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\parseargdef\clear{% + {% + \makevalueexpandable + \global\expandafter\let\csname SET#1\endcsname=\relax + }% +} + +% @value{foo} gets the text saved in variable foo. +\def\value{\begingroup\makevalueexpandable\valuexxx} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} +{ + \catcode`\-=\active \catcode`\_=\active + % + \gdef\makevalueexpandable{% + \let\value = \expandablevalue + % We don't want these characters active, ... + \catcode`\-=\other \catcode`\_=\other + % ..., but we might end up with active ones in the argument if + % we're called from @code, as @code{@value{foo-bar_}}, though. + % So \let them to their normal equivalents. + \let-\normaldash \let_\normalunderscore + } +} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we call \makevalueexpandable in \indexdummies). +% The command has to be fully expandable (if the variable is set), since +% the result winds up in the index file. This means that if the +% variable's value contains other Texinfo commands, it's almost certain +% it will fail (although perhaps we could fix that with sufficient work +% to do a one-level expansion on the result, instead of complete). +% +% Unfortunately, this has the consequence that when _ is in the *value* +% of an @set, it does not print properly in the roman fonts (get the cmr +% dot accent at position 126 instead). No fix comes to mind, and it's +% been this way since 2003 or earlier, so just ignore it. +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \message{Variable `#1', used in @value, is not set.}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +% To get the special treatment we need for `@end ifset,' we call +% \makecond and then redefine. +% +\makecond{ifset} +\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} +\def\doifset#1#2{% + {% + \makevalueexpandable + \let\next=\empty + \expandafter\ifx\csname SET#2\endcsname\relax + #1% If not set, redefine \next. + \fi + \expandafter + }\next +} +\def\ifsetfail{\doignore{ifset}} + +% @ifclear VAR ... @end executes the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +% The `\else' inside the `\doifset' parameter is a trick to reuse the +% above code: if the variable is not set, do nothing, if it is set, +% then redefine \next to \ifclearfail. +% +\makecond{ifclear} +\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} +\def\ifclearfail{\doignore{ifclear}} + +% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written +% without the @) is in fact defined. We can only feasibly check at the +% TeX level, so something like `mathcode' is going to considered +% defined even though it is not a Texinfo command. +% +\makecond{ifcommanddefined} +\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}} +% +\def\doifcmddefined#1#2{{% + \makevalueexpandable + \let\next=\empty + \expandafter\ifx\csname #2\endcsname\relax + #1% If not defined, \let\next as above. + \fi + \expandafter + }\next +} +\def\ifcmddefinedfail{\doignore{ifcommanddefined}} + +% @ifcommandnotdefined CMD ... handled similar to @ifclear above. +\makecond{ifcommandnotdefined} +\def\ifcommandnotdefined{% + \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}} +\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}} + +% Set the `txicommandconditionals' variable, so documents have a way to +% test if the @ifcommand...defined conditionals are available. +\set txicommandconditionals + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory=\comment + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within macros and \if's. +\edef\newwrite{\makecsname{ptexnewwrite}} + +% \newindex {foo} defines an index named IX. +% It automatically defines \IXindex such that +% \IXindex ...rest of line... puts an entry in the index IX. +% It also defines \IXindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is IX. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \expandafter\chardef\csname#1indfile\endcsname=0 + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} +% +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. +% +\def\defcodeindex{\parsearg\newcodeindex} +% +\def\newcodeindex#1{% + \expandafter\chardef\csname#1indfile\endcsname=0 + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}}% +} + +% The default indices: +\newindex{cp}% concepts, +\newcodeindex{fn}% functions, +\newcodeindex{vr}% variables, +\newcodeindex{tp}% types, +\newcodeindex{ky}% keys +\newcodeindex{pg}% and programs. + + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +% +\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} +\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} + +% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), +% #3 the target index (bar). +\def\dosynindex#1#2#3{% + % Only do \closeout if we haven't already done it, else we'll end up + % closing the target index. + \expandafter \ifx\csname donesynindex#2\endcsname \relax + % The \closeout helps reduce unnecessary open files; the limit on the + % Acorn RISC OS is a mere 16 files. + \expandafter\closeout\csname#2indfile\endcsname + \expandafter\let\csname donesynindex#2\endcsname = 1 + \fi + % redefine \fooindfile: + \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname + \expandafter\let\csname#2indfile\endcsname=\temp + % redefine \fooindex: + \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% +} + +% Define \doindex, the driver for all index macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it the two-letter name of the index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx} +\def\doindexxxx #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx} +\def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}} + +% Used when writing an index entry out to an index file, to prevent +% expansion of Texinfo commands that can appear in an index entry. +% +\def\indexdummies{% + \escapechar = `\\ % use backslash in output files. + \def\@{@}% change to @@ when we switch to @ as escape char in index files. + \def\ {\realbackslash\space }% + % + % Need these unexpandable (because we define \tt as a dummy) + % definitions when @{ or @} appear in index entry text. Also, more + % complicated, when \tex is in effect and \{ is a \delimiter again. + % We can't use \lbracecmd and \rbracecmd because texindex assumes + % braces and backslashes are used only as delimiters. Perhaps we + % should use @lbracechar and @rbracechar? + \def\{{{\tt\char123}}% + \def\}{{\tt\char125}}% + % + % Do the redefinitions. + \commondummies +} + +% For the aux and toc files, @ is the escape character. So we want to +% redefine everything using @ as the escape character (instead of +% \realbackslash, still used for index files). When everything uses @, +% this will be simpler. +% +\def\atdummies{% + \def\@{@@}% + \def\ {@ }% + \let\{ = \lbraceatcmd + \let\} = \rbraceatcmd + % + % Do the redefinitions. + \commondummies + \otherbackslash +} + +% Called from \indexdummies and \atdummies. +% +\def\commondummies{% + % \definedummyword defines \#1 as \string\#1\space, thus effectively + % preventing its expansion. This is used only for control words, + % not control letters, because the \space would be incorrect for + % control characters, but is needed to separate the control word + % from whatever follows. + % + % For control letters, we have \definedummyletter, which omits the + % space. + % + % These can be used both for control words that take an argument and + % those that do not. If it is followed by {arg} in the input, then + % that will dutifully get written to the index (or wherever). + % + \def\definedummyword ##1{\def##1{\string##1\space}}% + \def\definedummyletter##1{\def##1{\string##1}}% + \let\definedummyaccent\definedummyletter + % + \commondummiesnofonts + % + \definedummyletter\_% + \definedummyletter\-% + % + % Non-English letters. + \definedummyword\AA + \definedummyword\AE + \definedummyword\DH + \definedummyword\L + \definedummyword\O + \definedummyword\OE + \definedummyword\TH + \definedummyword\aa + \definedummyword\ae + \definedummyword\dh + \definedummyword\exclamdown + \definedummyword\l + \definedummyword\o + \definedummyword\oe + \definedummyword\ordf + \definedummyword\ordm + \definedummyword\questiondown + \definedummyword\ss + \definedummyword\th + % + % Although these internal commands shouldn't show up, sometimes they do. + \definedummyword\bf + \definedummyword\gtr + \definedummyword\hat + \definedummyword\less + \definedummyword\sf + \definedummyword\sl + \definedummyword\tclose + \definedummyword\tt + % + \definedummyword\LaTeX + \definedummyword\TeX + % + % Assorted special characters. + \definedummyword\arrow + \definedummyword\bullet + \definedummyword\comma + \definedummyword\copyright + \definedummyword\registeredsymbol + \definedummyword\dots + \definedummyword\enddots + \definedummyword\entrybreak + \definedummyword\equiv + \definedummyword\error + \definedummyword\euro + \definedummyword\expansion + \definedummyword\geq + \definedummyword\guillemetleft + \definedummyword\guillemetright + \definedummyword\guilsinglleft + \definedummyword\guilsinglright + \definedummyword\lbracechar + \definedummyword\leq + \definedummyword\mathopsup + \definedummyword\minus + \definedummyword\ogonek + \definedummyword\pounds + \definedummyword\point + \definedummyword\print + \definedummyword\quotedblbase + \definedummyword\quotedblleft + \definedummyword\quotedblright + \definedummyword\quoteleft + \definedummyword\quoteright + \definedummyword\quotesinglbase + \definedummyword\rbracechar + \definedummyword\result + \definedummyword\sub + \definedummyword\sup + \definedummyword\textdegree + % + % We want to disable all macros so that they are not expanded by \write. + \macrolist + % + \normalturnoffactive + % + % Handle some cases of @value -- where it does not contain any + % (non-fully-expandable) commands. + \makevalueexpandable +} + +% \commondummiesnofonts: common to \commondummies and \indexnofonts. +% Define \definedumyletter, \definedummyaccent and \definedummyword before +% using. +% +\def\commondummiesnofonts{% + % Control letters and accents. + \definedummyletter\!% + \definedummyaccent\"% + \definedummyaccent\'% + \definedummyletter\*% + \definedummyaccent\,% + \definedummyletter\.% + \definedummyletter\/% + \definedummyletter\:% + \definedummyaccent\=% + \definedummyletter\?% + \definedummyaccent\^% + \definedummyaccent\`% + \definedummyaccent\~% + \definedummyword\u + \definedummyword\v + \definedummyword\H + \definedummyword\dotaccent + \definedummyword\ogonek + \definedummyword\ringaccent + \definedummyword\tieaccent + \definedummyword\ubaraccent + \definedummyword\udotaccent + \definedummyword\dotless + % + % Texinfo font commands. + \definedummyword\b + \definedummyword\i + \definedummyword\r + \definedummyword\sansserif + \definedummyword\sc + \definedummyword\slanted + \definedummyword\t + % + % Commands that take arguments. + \definedummyword\abbr + \definedummyword\acronym + \definedummyword\anchor + \definedummyword\cite + \definedummyword\code + \definedummyword\command + \definedummyword\dfn + \definedummyword\dmn + \definedummyword\email + \definedummyword\emph + \definedummyword\env + \definedummyword\file + \definedummyword\image + \definedummyword\indicateurl + \definedummyword\inforef + \definedummyword\kbd + \definedummyword\key + \definedummyword\math + \definedummyword\option + \definedummyword\pxref + \definedummyword\ref + \definedummyword\samp + \definedummyword\strong + \definedummyword\tie + \definedummyword\U + \definedummyword\uref + \definedummyword\url + \definedummyword\var + \definedummyword\verb + \definedummyword\w + \definedummyword\xref +} + +% For testing: output @{ and @} in index sort strings as \{ and \}. +\newif\ifusebracesinindexes + +\let\indexlbrace\relax +\let\indexrbrace\relax + +{\catcode`\@=0 +\catcode`\\=13 + @gdef@backslashdisappear{@def\{}} +} + +{ +\catcode`\<=13 +\catcode`\-=13 +\catcode`\`=13 + \gdef\indexnonalnumdisappear{% + \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else + % @set txiindexlquoteignore makes us ignore left quotes in the sort term. + % (Introduced for FSFS 2nd ed.) + \let`=\empty + \fi + % + \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else + \backslashdisappear + \fi + % + \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else + \def-{}% + \fi + \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else + \def<{}% + \fi + \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else + \def\@{}% + \fi + } + + \gdef\indexnonalnumreappear{% + \useindexbackslash + \let-\normaldash + \let<\normalless + \def\@{@}% + } +} + + +% \indexnofonts is used when outputting the strings to sort the index +% by, and when constructing control sequence names. It eliminates all +% control sequences and just writes whatever the best ASCII sort string +% would be for a given command (usually its argument). +% +\def\indexnofonts{% + % Accent commands should become @asis. + \def\definedummyaccent##1{\let##1\asis}% + % We can just ignore other control letters. + \def\definedummyletter##1{\let##1\empty}% + % All control words become @asis by default; overrides below. + \let\definedummyword\definedummyaccent + \commondummiesnofonts + % + % Don't no-op \tt, since it isn't a user-level command + % and is used in the definitions of the active chars like <, >, |, etc. + % Likewise with the other plain tex font commands. + %\let\tt=\asis + % + \def\ { }% + \def\@{@}% + \def\_{\normalunderscore}% + \def\-{}% @- shouldn't affect sorting + % + \uccode`\1=`\{ \uppercase{\def\{{1}}% + \uccode`\1=`\} \uppercase{\def\}{1}}% + \let\lbracechar\{% + \let\rbracechar\}% + % + % Non-English letters. + \def\AA{AA}% + \def\AE{AE}% + \def\DH{DZZ}% + \def\L{L}% + \def\OE{OE}% + \def\O{O}% + \def\TH{TH}% + \def\aa{aa}% + \def\ae{ae}% + \def\dh{dzz}% + \def\exclamdown{!}% + \def\l{l}% + \def\oe{oe}% + \def\ordf{a}% + \def\ordm{o}% + \def\o{o}% + \def\questiondown{?}% + \def\ss{ss}% + \def\th{th}% + % + \def\LaTeX{LaTeX}% + \def\TeX{TeX}% + % + % Assorted special characters. + % (The following {} will end up in the sort string, but that's ok.) + \def\arrow{->}% + \def\bullet{bullet}% + \def\comma{,}% + \def\copyright{copyright}% + \def\dots{...}% + \def\enddots{...}% + \def\equiv{==}% + \def\error{error}% + \def\euro{euro}% + \def\expansion{==>}% + \def\geq{>=}% + \def\guillemetleft{<<}% + \def\guillemetright{>>}% + \def\guilsinglleft{<}% + \def\guilsinglright{>}% + \def\leq{<=}% + \def\minus{-}% + \def\point{.}% + \def\pounds{pounds}% + \def\print{-|}% + \def\quotedblbase{"}% + \def\quotedblleft{"}% + \def\quotedblright{"}% + \def\quoteleft{`}% + \def\quoteright{'}% + \def\quotesinglbase{,}% + \def\registeredsymbol{R}% + \def\result{=>}% + \def\textdegree{o}% + % + % We need to get rid of all macros, leaving only the arguments (if present). + % Of course this is not nearly correct, but it is the best we can do for now. + % makeinfo does not expand macros in the argument to @deffn, which ends up + % writing an index entry, and texindex isn't prepared for an index sort entry + % that starts with \. + % + % Since macro invocations are followed by braces, we can just redefine them + % to take a single TeX argument. The case of a macro invocation that + % goes to end-of-line is not handled. + % + \macrolist +} + + +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% Most index entries go through here, but \dosubind is the general case. +% #1 is the index name, #2 is the entry text. +\def\doind#1#2{\dosubind{#1}{#2}{}} + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. +% TODO: Two-level index? Operation index? + +% Workhorse for all indexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% empty if called from \doind, as we usually are (the main exception +% is with most defuns, which call us directly). +% +\def\dosubind#1#2#3{% + \iflinks + {% + \requireopenindexfile{#1}% + % Store the main index entry text (including the third arg). + \toks0 = {#2}% + % If third arg is present, precede it with a space. + \def\thirdarg{#3}% + \ifx\thirdarg\empty \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + \edef\writeto{\csname#1indfile\endcsname}% + % + \safewhatsit\dosubindwrite + }% + \fi +} + +% Check if an index file has been opened, and if not, open it. +\def\requireopenindexfile#1{% +\ifnum\csname #1indfile\endcsname=0 + \expandafter\newwrite \csname#1indfile\endcsname + \edef\suffix{#1}% + % A .fls suffix would conflict with the file extension for the output + % of -recorder, so use .f1s instead. + \ifx\suffix\indexisfl\def\suffix{f1}\fi + % Open the file + \immediate\openout\csname#1indfile\endcsname \jobname.\suffix + % Using \immediate here prevents an object entering into the current box, + % which could confound checks such as those in \safewhatsit for preceding + % skips. +\fi} +\def\indexisfl{fl} + +% Output \ as {\indexbackslash}, because \ is an escape character in +% the index files. +\let\indexbackslash=\relax +{\catcode`\@=0 \catcode`\\=\active + @gdef@useindexbackslash{@def\{{@indexbackslash}}} +} + +% Definition for writing index entry text. +\def\sortas#1{\ignorespaces}% + +% Definition for writing index entry sort key. Should occur at the at +% the beginning of the index entry, like +% @cindex @sortas{september} \september +% The \ignorespaces takes care of following space, but there's no way +% to remove space before it. +{ +\catcode`\-=13 +\gdef\indexwritesortas{% + \begingroup + \indexnonalnumreappear + \indexwritesortasxxx} +\gdef\indexwritesortasxxx#1{% + \xdef\indexsortkey{#1}\endgroup} +} + + +% Write the entry in \toks0 to the index file. +% +\def\dosubindwrite{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% + \fi + % + % Remember, we are within a group. + \indexdummies % Must do this here, since \bf, etc expand at this stage + \useindexbackslash % \indexbackslash isn't defined now so it will be output + % as is; and it will print as backslash. + % The braces around \indexbrace are recognized by texindex. + % + % Get the string to sort by, by processing the index entry with all + % font commands turned off. + {\indexnofonts + \def\lbracechar{{\indexlbrace}}% + \def\rbracechar{{\indexrbrace}}% + \let\{=\lbracechar + \let\}=\rbracechar + \indexnonalnumdisappear + \xdef\indexsortkey{}% + \let\sortas=\indexwritesortas + \edef\temp{\the\toks0}% + \setbox\dummybox = \hbox{\temp}% Make sure to execute any \sortas + \ifx\indexsortkey\empty + \xdef\indexsortkey{\temp}% + \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi + \fi + }% + % + % Set up the complete index entry, with both the sort key and + % the original text, including any font commands. We write + % three arguments to \entry to the .?? file (four in the + % subentry case), texindex reduces to two when writing the .??s + % sorted result. + \edef\temp{% + \write\writeto{% + \string\entry{\indexsortkey}{\noexpand\folio}{\the\toks0}}% + }% + \temp +} +\newbox\dummybox % used above + +% Take care of unwanted page breaks/skips around a whatsit: +% +% If a skip is the last thing on the list now, preserve it +% by backing up by \lastskip, doing the \write, then inserting +% the skip again. Otherwise, the whatsit generated by the +% \write or \pdfdest will make \lastskip zero. The result is that +% sequences like this: +% @end defun +% @tindex whatever +% @defun ... +% will have extra space inserted, because the \medbreak in the +% start of the @defun won't see the skip inserted by the @end of +% the previous defun. +% +% But don't do any of this if we're not in vertical mode. We +% don't want to do a \vskip and prematurely end a paragraph. +% +% Avoid page breaks due to these extra skips, too. +% +% But wait, there is a catch there: +% We'll have to check whether \lastskip is zero skip. \ifdim is not +% sufficient for this purpose, as it ignores stretch and shrink parts +% of the skip. The only way seems to be to check the textual +% representation of the skip. +% +% The following is almost like \def\zeroskipmacro{0.0pt} except that +% the ``p'' and ``t'' characters have catcode \other, not 11 (letter). +% +\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} +% +\newskip\whatsitskip +\newcount\whatsitpenalty +% +% ..., ready, GO: +% +\def\safewhatsit#1{\ifhmode + #1% + \else + % \lastskip and \lastpenalty cannot both be nonzero simultaneously. + \whatsitskip = \lastskip + \edef\lastskipmacro{\the\lastskip}% + \whatsitpenalty = \lastpenalty + % + % If \lastskip is nonzero, that means the last item was a + % skip. And since a skip is discardable, that means this + % -\whatsitskip glue we're inserting is preceded by a + % non-discardable item, therefore it is not a potential + % breakpoint, therefore no \nobreak needed. + \ifx\lastskipmacro\zeroskipmacro + \else + \vskip-\whatsitskip + \fi + % + #1% + % + \ifx\lastskipmacro\zeroskipmacro + % If \lastskip was zero, perhaps the last item was a penalty, and + % perhaps it was >=10000, e.g., a \nobreak. In that case, we want + % to re-insert the same penalty (values >10000 are used for various + % signals); since we just inserted a non-discardable item, any + % following glue (such as a \parskip) would be a breakpoint. For example: + % @deffn deffn-whatever + % @vindex index-whatever + % Description. + % would allow a break between the index-whatever whatsit + % and the "Description." paragraph. + \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi + \else + % On the other hand, if we had a nonzero \lastskip, + % this make-up glue would be preceded by a non-discardable item + % (the whatsit from the \write), so we must insert a \nobreak. + \nobreak\vskip\whatsitskip + \fi +\fi} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\parseargdef\printindex{\begingroup + \dobreak \chapheadingskip{10000}% + % + \smallfonts \rm + \tolerance = 9500 + \plainfrenchspacing + \everypar = {}% don't want the \kern\-parindent from indentation suppression. + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + % See comment in \requireopenindexfile. + \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi + \openin 1 \jobname.\indexname s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + \catcode`\\ = 0 + \escapechar = `\\ + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \thisline + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\ttbackslash}% + \let\indexlbrace\{ % Likewise, set these sequences for braces + \let\indexrbrace\} % used in the sort key. + \begindoublecolumns + \let\entryorphanpenalty=\indexorphanpenalty + % + % Read input from the index file line by line. + \loopdo + \ifeof1 + \let\firsttoken\relax + \else + \read 1 to \nextline + \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}% + \act + \fi + \thisline + % + \ifeof1\else + \let\thisline\nextline + \repeat + %% + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +\def\getfirsttoken#1{\expandafter\getfirsttokenx#1\endfirsttoken} +\long\def\getfirsttokenx#1#2\endfirsttoken{\noexpand#1} + +\def\loopdo#1\repeat{\def\body{#1}\loopdoxxx} +\def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +{\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13 +\catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13 +\catcode`\$=3 +\gdef\initialglyphs{% + % Some changes for non-alphabetic characters. Using the glyphs from the + % math fonts looks more consistent than the typewriter font used elsewhere + % for these characters. + \def\indexbackslash{\math{\backslash}}% + \let\\=\indexbackslash + % + % Can't get bold backslash so don't use bold forward slash + \catcode`\/=13 + \def/{{\secrmnotbold \normalslash}}% + \def-{{\normaldash\normaldash}}% en dash `--' + \def^{{\chapbf \normalcaret}}% + \def~{{\chapbf \normaltilde}}% + \def\_{% + \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }% + \def|{$\vert$}% + \def<{$\less$}% + \def>{$\gtr$}% + \def+{$\normalplus$}% +}} + +\def\initial{% + \bgroup + \initialglyphs + \initialx +} + +\def\initialx#1{% + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + % The glue before the bonus allows a little bit of space at the + % bottom of a column to reduce an increase in inter-line spacing. + \nobreak + \vskip 0pt plus 5\baselineskip + \penalty -300 + \vskip 0pt plus -5\baselineskip + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus 1\baselineskip + \leftline{\secfonts \kern-0.05em \secbf #1}% + % \secfonts is inside the argument of \leftline so that the change of + % \baselineskip will not affect any glue inserted before the vbox that + % \leftline creates. + % Do our best not to break after the initial. + \nobreak + \vskip .33\baselineskip plus .1\baselineskip + \egroup % \initialglyphs +} + +\newdimen\entryrightmargin +\entryrightmargin=0pt + +% \entry typesets a paragraph consisting of the text (#1), dot leaders, and +% then page number (#2) flushed to the right margin. It is used for index +% and table of contents entries. The paragraph is indented by \leftskip. +% +\def\entry{% + \begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % No extra space above this paragraph. + \parskip = 0in + % + % When reading the text of entry, convert explicit line breaks + % from @* into spaces. The user might give these in long section + % titles, for instance. + \def\*{\unskip\space\ignorespaces}% + \def\entrybreak{\hfil\break}% An undocumented command + % + % A bit of stretch before each entry for the benefit of balancing + % columns. + \vskip 0pt plus0.5pt + % + % Swallow the left brace of the text (first parameter): + \afterassignment\doentry + \let\temp = +} +\def\entrybreak{\unskip\space\ignorespaces}% +\def\doentry{% + % Save the text of the entry + \global\setbox\boxA=\hbox\bgroup + \bgroup % Instead of the swallowed brace. + \noindent + \aftergroup\finishentry + % And now comes the text of the entry. + % Not absorbing as a macro argument reduces the chance of problems + % with catcodes occurring. +} +{\catcode`\@=11 +\gdef\finishentry#1{% + \egroup % end box A + \dimen@ = \wd\boxA % Length of text of entry + \global\setbox\boxA=\hbox\bgroup\unhbox\boxA + % #1 is the page number. + % + % Get the width of the page numbers, and only use + % leaders if they are present. + \global\setbox\boxB = \hbox{#1}% + \ifdim\wd\boxB = 0pt + \null\nobreak\hfill\ % + \else + % + \null\nobreak\indexdotfill % Have leaders before the page number. + % + \ifpdf + \pdfgettoks#1.% + \bgroup\let\domark\relax + \hskip\skip\thinshrinkable\the\toksA + \egroup + % The redefinion of \domark stops marks being added in \pdflink to + % preserve coloured links across page boundaries. Otherwise the marks + % would get in the way of \lastbox in \insertindexentrybox. + \else + \hskip\skip\thinshrinkable #1% + \fi + \fi + \egroup % end \boxA + \ifdim\wd\boxB = 0pt + \global\setbox\entryindexbox=\vbox{\unhbox\boxA}% + \else + \global\setbox\entryindexbox=\vbox\bgroup + \prevdepth=\entrylinedepth + \noindent + % We want the text of the entries to be aligned to the left, and the + % page numbers to be aligned to the right. + % + \advance\leftskip by 0pt plus 1fil + \advance\leftskip by 0pt plus -1fill + \rightskip = 0pt plus -1fil + \advance\rightskip by 0pt plus 1fill + % Cause last line, which could consist of page numbers on their own + % if the list of page numbers is long, to be aligned to the right. + \parfillskip=0pt plus -1fill + % + \hangindent=1em + % + \advance\rightskip by \entryrightmargin + % Determine how far we can stretch into the margin. + % This allows, e.g., "Appendix H GNU Free Documentation License" to + % fit on one line in @letterpaper format. + \ifdim\entryrightmargin>2.1em + \dimen@i=2.1em + \else + \dimen@i=0em + \fi + \advance \parfillskip by 0pt minus 1\dimen@i + % + \dimen@ii = \hsize + \advance\dimen@ii by -1\leftskip + \advance\dimen@ii by -1\entryrightmargin + \advance\dimen@ii by 1\dimen@i + \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line + \ifdim\dimen@ > 0.8\dimen@ii % due to long index text + \dimen@ = 0.7\dimen@ % Try to split the text roughly evenly + \dimen@ii = \hsize + \advance \dimen@ii by -1em + \ifnum\dimen@>\dimen@ii + % If the entry is too long, use the whole line + \dimen@ = \dimen@ii + \fi + \advance\leftskip by 0pt plus 1fill % ragged right + \advance \dimen@ by 1\rightskip + \parshape = 2 0pt \dimen@ 1em \dimen@ii + % Ideally we'd add a finite glue at the end of the first line only, but + % TeX doesn't seem to provide a way to do such a thing. + \fi\fi + \unhbox\boxA + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % Word spacing - no stretch + \spaceskip=\fontdimen2\font minus \fontdimen4\font + % + \linepenalty=1000 % Discourage line breaks. + \hyphenpenalty=5000 % Discourage hyphenation. + % + \par % format the paragraph + \egroup % The \vbox + \fi + \endgroup + % delay text of entry until after penalty + \bgroup\aftergroup\insertindexentrybox + \entryorphanpenalty +}} + +\newskip\thinshrinkable +\skip\thinshrinkable=.15em minus .15em + +\newbox\entryindexbox +\def\insertindexentrybox{% + \copy\entryindexbox + % The following gets the depth of the last box. This is for even + % line spacing when entries span several lines. + \setbox\dummybox\vbox{% + \unvbox\entryindexbox + \nointerlineskip + \lastbox + \global\entrylinedepth=\prevdepth + }% + % Note that we couldn't simply \unvbox\entryindexbox followed by + % \nointerlineskip\lastbox to remove the last box and then reinstate it, + % because this resets how far the box has been \moveleft'ed to 0. \unvbox + % doesn't affect \prevdepth either. +} +\newdimen\entrylinedepth + +% Default is no penalty +\let\entryorphanpenalty\egroup + +% Used from \printindex. \firsttoken should be the first token +% after the \entry. If it's not another \entry, we are at the last +% line of a group of index entries, so insert a penalty to discourage +% orphaned index entries. +\long\def\indexorphanpenalty{% + \def\isentry{\entry}% + \ifx\firsttoken\isentry + \else + \unskip\penalty 9000 + % The \unskip here stops breaking before the glue. It relies on the + % \vskip above being there, otherwise there is an error + % "You can't use `\unskip' in vertical mode". There has to be glue + % in the current vertical list that hasn't been added to the + % "current page". See Chapter 24 of the TeXbook. This contradicts + % Section 8.3.7 in "TeX by Topic," though. + \fi + \egroup % now comes the box added with \aftergroup +} + +% Like plain.tex's \dotfill, except uses up at least 1 em. +% The filll stretch here overpowers both the fil and fill stretch to push +% the page number to the right. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll} + + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm +\def\secondary#1#2{{% + \parfillskip=0in + \parskip=0in + \hangindent=1in + \hangafter=1 + \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + #2 + \fi + \par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 % private names + +\newbox\partialpage +\newdimen\doublecolumnhsize +\newdimen\doublecolumntopgap +\doublecolumntopgap = 0pt + +% Use inside an output routine to save \topmark and \firstmark +\def\savemarks{% + \global\savedtopmark=\expandafter{\topmark }% + \global\savedfirstmark=\expandafter{\firstmark }% +} +\newtoks\savedtopmark +\newtoks\savedfirstmark + +% Set \topmark and \firstmark for next time \output runs. +% Can't be run from withinside \output (because any material +% added while an output routine is active, including +% penalties, is saved for after it finishes). The page so far +% should be empty, otherwise what's on it will be thrown away. +\def\restoremarks{% + \mark{\the\savedtopmark}% + \bgroup\output = {% + \setbox\dummybox=\box\PAGE + }abc\eject\egroup + % "abc" because output routine doesn't fire for a completely empty page. + \mark{\the\savedfirstmark}% +} + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % If not much space left on page, start a new page. + \ifdim\pagetotal>0.8\vsize\vfill\eject\fi + % + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + \savemarks + }% + \eject % run that output routine to set \partialpage + \restoremarks + % + % We recover the two marks that the last output routine saved in order + % to propagate the information in marks added around a chapter heading, + % which could be otherwise be lost by the time the final page is output. + % + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \global\doublecolumntopgap = \topskip + \global\advance\doublecolumntopgap by -1\baselineskip + \advance\vsize by -1\doublecolumntopgap + \vsize = 2\vsize + \topskip=0pt + \global\entrylinedepth=0pt\relax +} + +% The double-column output routine for all double-column pages except +% the last, which is done by \balancecolumns. +% +\def\doublecolumnout{% + % + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + \advance\dimen@ by -\ht\partialpage + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +% +% Re-output the contents of the output page -- any previous material, +% followed by the two boxes we just split, in box0 and box2. +\def\pagesofar{% + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \vbox{% + \vskip\doublecolumntopgap + \hbox to\pagewidth{\box0\hfil\box2}}% +} + + +% Finished with with double columns. +\def\enddoublecolumns{% + % The following penalty ensures that the page builder is exercised + % _before_ we change the output routine. This is necessary in the + % following situation: + % + % The last section of the index consists only of a single entry. + % Before this section, \pagetotal is less than \pagegoal, so no + % break occurs before the last section starts. However, the last + % section, consisting of \initial and the single \entry, does not + % fit on the page and has to be broken off. Without the following + % penalty the page builder will not be exercised until \eject + % below, and by that time we'll already have changed the output + % routine to the \balancecolumns version, so the next-to-last + % double-column page will be processed with \balancecolumns, which + % is wrong: The two columns will go to the main vertical list, with + % the broken-off section in the recent contributions. As soon as + % the output routine finishes, TeX starts reconsidering the page + % break. The two columns and the broken-off section both fit on the + % page, because the two columns now take up only half of the page + % goal. When TeX sees \eject from below which follows the final + % section, it invokes the new output routine that we've set after + % \balancecolumns below; \onepageout will try to fit the two columns + % and the final section into the vbox of \pageheight (see + % \pagebody), causing an overfull box. + % + % Note that glue won't work here, because glue does not exercise the + % page builder, unlike penalties (see The TeXbook, pp. 280-281). + \penalty0 + % + \output = {% + % Split the last of the double-column material. + \savemarks + \balancecolumns + % + % Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + \restoremarks + % Leave the double-column material on the current page, no automatic + % page break. + \box\balancedcolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +\newbox\balancedcolumns +\setbox\balancedcolumns=\vbox{shouldnt see this}% +% +% Only called for the last of the double column material. \doublecolumnout +% does the others. +\def\balancecolumns{% + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \ifdim\dimen@<14\baselineskip + % Don't split a short final column in two. + \setbox2=\vbox{}% + \else + \divide\dimen@ by 2 % target to split to + \dimen@ii = \dimen@ + \splittopskip = \topskip + % Loop until the second column is no higher than the first + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + % Remove glue from bottom of first column to + % make sure it is higher than the second. + \global\setbox1 = \vbox{\unvbox1\unpenalty\unskip}% + \ifdim\ht3>\ht1 + \global\advance\dimen@ by 1pt + \repeat + }% + \multiply\dimen@ii by 4 + \divide\dimen@ii by 5 + \ifdim\ht3<\dimen@ii + % Column heights are too different, so don't make their bottoms + % flush with each other. The glue at the end of the second column + % allows a second column to stretch, reducing the difference in + % height between the two. + \setbox0=\vbox to\dimen@{\unvbox1\vfill}% + \setbox2=\vbox to\dimen@{\unvbox3\vskip 0pt plus 0.3\ht0}% + \else + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + \fi + \fi + % + \global\setbox\balancedcolumns=\vbox{\pagesofar}% +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +% Let's start with @part. +\outer\parseargdef\part{\partzzz{#1}} +\def\partzzz#1{% + \chapoddpage + \null + \vskip.3\vsize % move it down on the page a bit + \begingroup + \noindent \titlefonts\rmisbold #1\par % the text + \let\lastnode=\empty % no node to associate with + \writetocentry{part}{#1}{}% but put it in the toc + \headingsoff % no headline or footline on the part page + % This outputs a mark at the end of the page that clears \thischapter + % and \thissection, as is done in \startcontents. + \let\pchapsepmacro\relax + \chapmacro{}{Yomitfromtoc}{}% + \chapoddpage + \endgroup +} + +% \unnumberedno is an oxymoron. But we count the unnumbered +% sections so that we can refer to them unambiguously in the pdf +% outlines by their "section number". We avoid collisions with chapter +% numbers by starting them at 10000. (If a document ever has 10000 +% chapters, we're in trouble anyway, I'm sure.) +\newcount\unnumberedno \unnumberedno = 10000 +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +% +% \def\appendixletter{\char\the\appendixno} +% We do the following ugly conditional instead of the above simple +% construct for the sake of pdftex, which needs the actual +% letter in the expansion, not just typeset. +% +\def\appendixletter{% + \ifnum\appendixno=`A A% + \else\ifnum\appendixno=`B B% + \else\ifnum\appendixno=`C C% + \else\ifnum\appendixno=`D D% + \else\ifnum\appendixno=`E E% + \else\ifnum\appendixno=`F F% + \else\ifnum\appendixno=`G G% + \else\ifnum\appendixno=`H H% + \else\ifnum\appendixno=`I I% + \else\ifnum\appendixno=`J J% + \else\ifnum\appendixno=`K K% + \else\ifnum\appendixno=`L L% + \else\ifnum\appendixno=`M M% + \else\ifnum\appendixno=`N N% + \else\ifnum\appendixno=`O O% + \else\ifnum\appendixno=`P P% + \else\ifnum\appendixno=`Q Q% + \else\ifnum\appendixno=`R R% + \else\ifnum\appendixno=`S S% + \else\ifnum\appendixno=`T T% + \else\ifnum\appendixno=`U U% + \else\ifnum\appendixno=`V V% + \else\ifnum\appendixno=`W W% + \else\ifnum\appendixno=`X X% + \else\ifnum\appendixno=`Y Y% + \else\ifnum\appendixno=`Z Z% + % The \the is necessary, despite appearances, because \appendixletter is + % expanded while writing the .toc file. \char\appendixno is not + % expandable, thus it is written literally, thus all appendixes come out + % with the same letter (or @) in the toc without it. + \else\char\the\appendixno + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + +% Each @chapter defines these (using marks) as the number+name, number +% and name of the chapter. Page headings and footings can use +% these. @section does likewise. +\def\thischapter{} +\def\thischapternum{} +\def\thischaptername{} +\def\thissection{} +\def\thissectionnum{} +\def\thissectionname{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% we only have subsub. +\chardef\maxseclevel = 3 +% +% A numbered section within an unnumbered changes to unnumbered too. +% To achieve this, remember the "biggest" unnum. sec. we are currently in: +\chardef\unnlevel = \maxseclevel +% +% Trace whether the current chapter is an appendix or not: +% \chapheadtype is "N" or "A", unnumbered chapters are ignored. +\def\chapheadtype{N} + +% Choose a heading macro +% #1 is heading type +% #2 is heading level +% #3 is text for heading +\def\genhead#1#2#3{% + % Compute the abs. sec. level: + \absseclevel=#2 + \advance\absseclevel by \secbase + % Make sure \absseclevel doesn't fall outside the range: + \ifnum \absseclevel < 0 + \absseclevel = 0 + \else + \ifnum \absseclevel > 3 + \absseclevel = 3 + \fi + \fi + % The heading type: + \def\headtype{#1}% + \if \headtype U% + \ifnum \absseclevel < \unnlevel + \chardef\unnlevel = \absseclevel + \fi + \else + % Check for appendix sections: + \ifnum \absseclevel = 0 + \edef\chapheadtype{\headtype}% + \else + \if \headtype A\if \chapheadtype N% + \errmessage{@appendix... within a non-appendix chapter}% + \fi\fi + \fi + % Check for numbered within unnumbered: + \ifnum \absseclevel > \unnlevel + \def\headtype{U}% + \else + \chardef\unnlevel = 3 + \fi + \fi + % Now print the heading: + \if \headtype U% + \ifcase\absseclevel + \unnumberedzzz{#3}% + \or \unnumberedseczzz{#3}% + \or \unnumberedsubseczzz{#3}% + \or \unnumberedsubsubseczzz{#3}% + \fi + \else + \if \headtype A% + \ifcase\absseclevel + \appendixzzz{#3}% + \or \appendixsectionzzz{#3}% + \or \appendixsubseczzz{#3}% + \or \appendixsubsubseczzz{#3}% + \fi + \else + \ifcase\absseclevel + \chapterzzz{#3}% + \or \seczzz{#3}% + \or \numberedsubseczzz{#3}% + \or \numberedsubsubseczzz{#3}% + \fi + \fi + \fi + \suppressfirstparagraphindent +} + +% an interface: +\def\numhead{\genhead N} +\def\apphead{\genhead A} +\def\unnmhead{\genhead U} + +% @chapter, @appendix, @unnumbered. Increment top-level counter, reset +% all lower-level sectioning counters to zero. +% +% Also set \chaplevelprefix, which we prepend to @float sequence numbers +% (e.g., figures), q.v. By default (before any chapter), that is empty. +\let\chaplevelprefix = \empty +% +\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz#1{% + % section resetting is \global in case the chapter is in a group, such + % as an @include file. + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\chapno by 1 + % + % Used for \float. + \gdef\chaplevelprefix{\the\chapno.}% + \resetallfloatnos + % + % \putwordChapter can contain complex things in translations. + \toks0=\expandafter{\putwordChapter}% + \message{\the\toks0 \space \the\chapno}% + % + % Write the actual heading. + \chapmacro{#1}{Ynumbered}{\the\chapno}% + % + % So @section and the like are numbered underneath this chapter. + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec +} + +\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz +% +\def\appendixzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\appendixno by 1 + \gdef\chaplevelprefix{\appendixletter.}% + \resetallfloatnos + % + % \putwordAppendix can contain complex things in translations. + \toks0=\expandafter{\putwordAppendix}% + \message{\the\toks0 \space \appendixletter}% + % + \chapmacro{#1}{Yappendix}{\appendixletter}% + % + \global\let\section = \appendixsec + \global\let\subsection = \appendixsubsec + \global\let\subsubsection = \appendixsubsubsec +} + +% normally unnmhead0 calls unnumberedzzz: +\outer\parseargdef\unnumbered{\unnmhead0{#1}} +\def\unnumberedzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\unnumberedno by 1 + % + % Since an unnumbered has no number, no prefix for figures. + \global\let\chaplevelprefix = \empty + \resetallfloatnos + % + % This used to be simply \message{#1}, but TeX fully expands the + % argument to \message. Therefore, if #1 contained @-commands, TeX + % expanded them. For example, in `@unnumbered The @cite{Book}', TeX + % expanded @cite (which turns out to cause errors because \cite is meant + % to be executed, not expanded). + % + % Anyway, we don't want the fully-expanded definition of @cite to appear + % as a result of the \message, we just want `@cite' itself. We use + % \the to achieve this: TeX expands \the only once, + % simply yielding the contents of . (We also do this for + % the toc entries.) + \toks0 = {#1}% + \message{(\the\toks0)}% + % + \chapmacro{#1}{Ynothing}{\the\unnumberedno}% + % + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\parseargdef\centerchap{% + \let\centerparametersmaybe = \centerparameters + \unnmhead0{#1}% + \let\centerparametersmaybe = \relax +} + +% @top is like @unnumbered. +\let\top\unnumbered + +% Sections. +% +\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz +\def\seczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% +} + +% normally calls appendixsectionzzz: +\outer\parseargdef\appendixsection{\apphead1{#1}} +\def\appendixsectionzzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% +} +\let\appendixsec\appendixsection + +% normally calls unnumberedseczzz: +\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} +\def\unnumberedseczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% +} + +% Subsections. +% +% normally calls numberedsubseczzz: +\outer\parseargdef\numberedsubsec{\numhead2{#1}} +\def\numberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% +} + +% normally calls appendixsubseczzz: +\outer\parseargdef\appendixsubsec{\apphead2{#1}} +\def\appendixsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno}% +} + +% normally calls unnumberedsubseczzz: +\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} +\def\unnumberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno}% +} + +% Subsubsections. +% +% normally numberedsubsubseczzz: +\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} +\def\numberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynumbered}% + {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% normally appendixsubsubseczzz: +\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} +\def\appendixsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% normally unnumberedsubsubseczzz: +\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} +\def\unnumberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\let\section = \numberedsec +\let\subsection = \numberedsubsec +\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +\def\majorheading{% + {\advance\chapheadingskip by 10pt \chapbreak }% + \parsearg\chapheadingzzz +} + +\def\chapheading{\chapbreak \parsearg\chapheadingzzz} +\def\chapheadingzzz#1{% + \vbox{\chapfonts \raggedtitlesettings #1\par}% + \nobreak\bigskip \nobreak + \suppressfirstparagraphindent +} + +% @heading, @subheading, @subsubheading. +\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +% Parameter controlling skip before chapter headings (if needed) +\newskip\chapheadingskip + +% Define plain chapter starts, and page on/off switching for it. +\def\chapbreak{\dobreak \chapheadingskip {-4000}} + +% Start a new page +\def\chappager{\par\vfill\supereject} + +% \chapoddpage - start on an odd page for a new chapter +% Because \domark is called before \chapoddpage, the filler page will +% get the headings for the next chapter, which is wrong. But we don't +% care -- we just disable all headings on the filler page. +\def\chapoddpage{% + \chappager + \ifodd\pageno \else + \begingroup + \headingsoff + \null + \chappager + \endgroup + \fi +} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{% +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +% \chapmacro - Chapter opening. +% +% #1 is the text, #2 is the section type (Ynumbered, Ynothing, +% Yappendix, Yomitfromtoc), #3 the chapter number. +% Not used for @heading series. +% +% To test against our argument. +\def\Ynothingkeyword{Ynothing} +\def\Yappendixkeyword{Yappendix} +\def\Yomitfromtockeyword{Yomitfromtoc} +% +\def\chapmacro#1#2#3{% + \expandafter\ifx\thisenv\titlepage\else + \checkenv{}% chapters, etc., should not start inside an environment. + \fi + % FIXME: \chapmacro is currently called from inside \titlepage when + % \setcontentsaftertitlepage to print the "Table of Contents" heading, but + % this should probably be done by \sectionheading with an option to print + % in chapter size. + % + % Insert the first mark before the heading break (see notes for \domark). + \let\prevchapterdefs=\lastchapterdefs + \let\prevsectiondefs=\lastsectiondefs + \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% + \gdef\thissection{}}% + % + \def\temptype{#2}% + \ifx\temptype\Ynothingkeyword + \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% + \gdef\thischapter{\thischaptername}}% + \else\ifx\temptype\Yomitfromtockeyword + \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% + \gdef\thischapter{}}% + \else\ifx\temptype\Yappendixkeyword + \toks0={#1}% + \xdef\lastchapterdefs{% + \gdef\noexpand\thischaptername{\the\toks0}% + \gdef\noexpand\thischapternum{\appendixletter}% + % \noexpand\putwordAppendix avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} + \noexpand\thischapternum: + \noexpand\thischaptername}% + }% + \else + \toks0={#1}% + \xdef\lastchapterdefs{% + \gdef\noexpand\thischaptername{\the\toks0}% + \gdef\noexpand\thischapternum{\the\chapno}% + % \noexpand\putwordChapter avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thischapter{\noexpand\putwordChapter{} + \noexpand\thischapternum: + \noexpand\thischaptername}% + }% + \fi\fi\fi + % + % Output the mark. Pass it through \safewhatsit, to take care of + % the preceding space. + \safewhatsit\domark + % + % Insert the chapter heading break. + \pchapsepmacro + % + % Now the second mark, after the heading break. No break points + % between here and the heading. + \let\prevchapterdefs=\lastchapterdefs + \let\prevsectiondefs=\lastsectiondefs + \domark + % + {% + \chapfonts \rmisbold + \let\footnote=\errfootnoteheading % give better error message + % + % Have to define \lastsection before calling \donoderef, because the + % xref code eventually uses it. On the other hand, it has to be called + % after \pchapsepmacro, or the headline will change too soon. + \gdef\lastsection{#1}% + % + % Only insert the separating space if we have a chapter/appendix + % number, and don't print the unnumbered ``number''. + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unnchap}% + \else\ifx\temptype\Yomitfromtockeyword + \setbox0 = \hbox{}% contents like unnumbered, but no toc entry + \def\toctype{omit}% + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% + \def\toctype{app}% + \else + \setbox0 = \hbox{#3\enspace}% + \def\toctype{numchap}% + \fi\fi\fi + % + % Write the toc entry for this chapter. Must come before the + % \donoderef, because we include the current node name in the toc + % entry, and \donoderef resets it to empty. + \writetocentry{\toctype}{#1}{#3}% + % + % For pdftex, we have to write out the node definition (aka, make + % the pdfdest) after any page break, but before the actual text has + % been typeset. If the destination for the pdf outline is after the + % text, then jumping from the outline may wind up with the text not + % being visible, for instance under high magnification. + \donoderef{#2}% + % + % Typeset the actual heading. + \nobreak % Avoid page breaks at the interline glue. + \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerparameters{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt +} + + +% I don't think this chapter style is supported any more, so I'm not +% updating it with the new noderef stuff. We'll see. --karl, 11aug03. +% +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} +% +\def\unnchfopen #1{% + \chapoddpage + \vbox{\chapfonts \raggedtitlesettings #1\par}% + \nobreak\bigskip\nobreak +} +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} +\def\centerchfopen #1{% + \chapoddpage + \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}% + \nobreak\bigskip \nobreak +} +\def\CHAPFopen{% + \global\let\chapmacro=\chfopen + \global\let\centerchapmacro=\centerchfopen} + + +% Section titles. These macros combine the section number parts and +% call the generic \sectionheading to do the printing. +% +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip{-1000}} + +% Subsection titles. +\newskip\subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} + +% Subsubsection titles. +\def\subsubsecheadingskip{\subsecheadingskip} +\def\subsubsecheadingbreak{\subsecheadingbreak} + + +% Print any size, any type, section title. +% +% #1 is the text of the title, +% #2 is the section level (sec/subsec/subsubsec), +% #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc), +% #4 is the section number. +% +\def\seckeyword{sec} +% +\def\sectionheading#1#2#3#4{% + {% + \def\sectionlevel{#2}% + \def\temptype{#3}% + % + % It is ok for the @heading series commands to appear inside an + % environment (it's been historically allowed, though the logic is + % dubious), but not the others. + \ifx\temptype\Yomitfromtockeyword\else + \checkenv{}% non-@*heading should not be in an environment. + \fi + \let\footnote=\errfootnoteheading + % + % Switch to the right set of fonts. + \csname #2fonts\endcsname \rmisbold + % + % Insert first mark before the heading break (see notes for \domark). + \let\prevsectiondefs=\lastsectiondefs + \ifx\temptype\Ynothingkeyword + \ifx\sectionlevel\seckeyword + \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% + \gdef\thissection{\thissectionname}}% + \fi + \else\ifx\temptype\Yomitfromtockeyword + % Don't redefine \thissection. + \else\ifx\temptype\Yappendixkeyword + \ifx\sectionlevel\seckeyword + \toks0={#1}% + \xdef\lastsectiondefs{% + \gdef\noexpand\thissectionname{\the\toks0}% + \gdef\noexpand\thissectionnum{#4}% + % \noexpand\putwordSection avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thissection{\noexpand\putwordSection{} + \noexpand\thissectionnum: + \noexpand\thissectionname}% + }% + \fi + \else + \ifx\sectionlevel\seckeyword + \toks0={#1}% + \xdef\lastsectiondefs{% + \gdef\noexpand\thissectionname{\the\toks0}% + \gdef\noexpand\thissectionnum{#4}% + % \noexpand\putwordSection avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thissection{\noexpand\putwordSection{} + \noexpand\thissectionnum: + \noexpand\thissectionname}% + }% + \fi + \fi\fi\fi + % + % Go into vertical mode. Usually we'll already be there, but we + % don't want the following whatsit to end up in a preceding paragraph + % if the document didn't happen to have a blank line. + \par + % + % Output the mark. Pass it through \safewhatsit, to take care of + % the preceding space. + \safewhatsit\domark + % + % Insert space above the heading. + \csname #2headingbreak\endcsname + % + % Now the second mark, after the heading break. No break points + % between here and the heading. + \global\let\prevsectiondefs=\lastsectiondefs + \domark + % + % Only insert the space after the number if we have a section number. + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unn}% + \gdef\lastsection{#1}% + \else\ifx\temptype\Yomitfromtockeyword + % for @headings -- no section number, don't include in toc, + % and don't redefine \lastsection. + \setbox0 = \hbox{}% + \def\toctype{omit}% + \let\sectionlevel=\empty + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{#4\enspace}% + \def\toctype{app}% + \gdef\lastsection{#1}% + \else + \setbox0 = \hbox{#4\enspace}% + \def\toctype{num}% + \gdef\lastsection{#1}% + \fi\fi\fi + % + % Write the toc entry (before \donoderef). See comments in \chapmacro. + \writetocentry{\toctype\sectionlevel}{#1}{#4}% + % + % Write the node reference (= pdf destination for pdftex). + % Again, see comments in \chapmacro. + \donoderef{#3}% + % + % Interline glue will be inserted when the vbox is completed. + % That glue will be a valid breakpoint for the page, since it'll be + % preceded by a whatsit (usually from the \donoderef, or from the + % \writetocentry if there was no node). We don't want to allow that + % break, since then the whatsits could end up on page n while the + % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. + \nobreak + % + % Output the actual section heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright + \hangindent=\wd0 % zero if no section number + \unhbox0 #1}% + }% + % Add extra space after the heading -- half of whatever came above it. + % Don't allow stretch, though. + \kern .5 \csname #2headingskip\endcsname + % + % Do not let the kern be a potential breakpoint, as it would be if it + % was followed by glue. + \nobreak + % + % We'll almost certainly start a paragraph next, so don't let that + % glue accumulate. (Not a breakpoint because it's preceded by a + % discardable item.) However, when a paragraph is not started next + % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out + % or the negative glue will cause weirdly wrong output, typically + % obscuring the section heading with something else. + \vskip-\parskip + % + % This is so the last item on the main vertical list is a known + % \penalty > 10000, so \startdefun, etc., can recognize the situation + % and do the needful. + \penalty 10001 +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. +% +% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} +% We append the current node name (if any) and page number as additional +% arguments for the \{chap,sec,...}entry macros which will eventually +% read this. The node name is used in the pdf outlines as the +% destination to jump to. +% +% We open the .toc file for writing here instead of at @setfilename (or +% any other fixed time) so that @contents can be anywhere in the document. +% But if #1 is `omit', then we don't do anything. This is used for the +% table of contents chapter openings themselves. +% +\newif\iftocfileopened +\def\omitkeyword{omit}% +% +\def\writetocentry#1#2#3{% + \edef\writetoctype{#1}% + \ifx\writetoctype\omitkeyword \else + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + % + \iflinks + {\atdummies + \edef\temp{% + \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% + \temp + }% + \fi + \fi + % + % Tell \shipout to create a pdf destination on each page, if we're + % writing pdf. These are used in the table of contents. We can't + % just write one on every page because the title pages are numbered + % 1 and 2 (the page numbers aren't printed), and so are the first + % two pages of the document. Thus, we'd have two destinations named + % `1', and two named `2'. + \ifpdf \global\pdfmakepagedesttrue \fi +} + + +% These characters do not print properly in the Computer Modern roman +% fonts, so we must take special care. This is more or less redundant +% with the Texinfo input format setup at the end of this file. +% +\def\activecatcodes{% + \catcode`\"=\active + \catcode`\$=\active + \catcode`\<=\active + \catcode`\>=\active + \catcode`\\=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\|=\active + \catcode`\~=\active +} + + +% Read the toc file, which is essentially Texinfo input. +\def\readtocfile{% + \setupdatafile + \activecatcodes + \input \tocreadfilename +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Prepare to read what we've written to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \chapmacro{#1}{Yomitfromtoc}{}% + % + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \raggedbottom % Worry more about breakpoints than the bottom. + \entryrightmargin=\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi +} + +% redefined for the two-volume lispref. We always output on +% \jobname.toc even if this is redefined. +% +\def\tocreadfilename{\jobname.toc} + +% Normal (long) toc. +% +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \tocreadfilename\space + \ifeof 1 \else + \readtocfile + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \ifeof 1 \else + \pdfmakeoutlines + \fi + \closein 1 + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\partentry = \shortpartentry + \let\numchapentry = \shortchapentry + \let\appentry = \shortchapentry + \let\unnchapentry = \shortunnchapentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf + \let\sl=\shortcontsl \let\tt=\shortconttt + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\numsecentry##1##2##3##4{} + \let\appsecentry = \numsecentry + \let\unnsecentry = \numsecentry + \let\numsubsecentry = \numsecentry + \let\appsubsecentry = \numsecentry + \let\unnsubsecentry = \numsecentry + \let\numsubsubsecentry = \numsecentry + \let\appsubsubsecentry = \numsecentry + \let\unnsubsubsecentry = \numsecentry + \openin 1 \tocreadfilename\space + \ifeof 1 \else + \readtocfile + \fi + \closein 1 + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g., `A' for an appendix, or `3' for a chapter. +% +\def\shortchaplabel#1{% + % This space should be enough, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % But use \hss just in case. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + % + % We'd like to right-justify chapter numbers, but that looks strange + % with appendix letters. And right-justifying numbers and + % left-justifying letters looks strange when there is less than 10 + % chapters. Have to read the whole toc once to know how many chapters + % there are before deciding ... + \hbox to 1em{#1\hss}% +} + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Parts, in the main contents. Replace the part number, which doesn't +% exist, with an empty box. Let's hope all the numbers have the same width. +% Also ignore the page number, which is conventionally not printed. +\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}} +\def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}} +% +% Parts, in the short toc. +\def\shortpartentry#1#2#3#4{% + \penalty-300 + \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip + \shortchapentry{{\bf #1}}{\numeralbox}{}{}% +} + +% Chapters, in the main contents. +\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} + +% Chapters, in the short toc. +% See comments in \dochapentry re vbox and related settings. +\def\shortchapentry#1#2#3#4{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% +} + +% Appendices, in the main contents. +% Need the word Appendix, and a fixed-size box. +% +\def\appendixbox#1{% + % We use M since it's probably the widest letter. + \setbox0 = \hbox{\putwordAppendix{} M}% + \hbox to \wd0{\putwordAppendix{} #1\hss}} +% +\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\hskip.7em#1}{#4}} + +% Unnumbered chapters. +\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} +\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} + +% Sections. +\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} +\let\appsecentry=\numsecentry +\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} + +% Subsections. +\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} +\let\appsubsecentry=\numsubsecentry +\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} + +% And subsubsections. +\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} +\let\appsubsubsecentry=\numsubsubsecentry +\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} + +% This parameter controls the indentation of the various levels. +% Same as \defaultparindent. +\newdimen\tocindent \tocindent = 15pt + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + % Move the page numbers slightly to the right + \advance\entryrightmargin by -0.05em + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% We use the same \entry macro as for the index entries. +\let\tocentry = \entry + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\def\subsecentryfonts{\textfonts} +\def\subsubsecentryfonts{\textfonts} + + +\message{environments,} +% @foo ... @end foo. + +% @tex ... @end tex escapes into raw TeX temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain @ character. + +\envdef\tex{% + \setupmarkupstyle{tex}% + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie + \catcode `\%=14 + \catcode `\+=\other + \catcode `\"=\other + \catcode `\|=\other + \catcode `\<=\other + \catcode `\>=\other + \catcode `\`=\other + \catcode `\'=\other + \escapechar=`\\ + % + % ' is active in math mode (mathcode"8000). So reset it, and all our + % other math active characters (just in case), to plain's definitions. + \mathactive + % + % Inverse of the list at the beginning of the file. + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\/=\ptexslash + \let\sp=\ptexsp + \let\*=\ptexstar + %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode + \let\t=\ptext + \expandafter \let\csname top\endcsname=\ptextop % we've made it outer + \let\frenchspacing=\plainfrenchspacing + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +} +% There is no need to define \Etex. + +% Define @lisp ... @end lisp. +% @lisp environment forms a group so it can rebind things, +% including the definition of @end lisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip. +% +\def\aboveenvbreak{{% + % =10000 instead of <10000 because of a special case in \itemzzz and + % \sectionheading, q.v. + \ifnum \lastpenalty=10000 \else + \advance\envskipamount by \parskip + \endgraf + \ifdim\lastskip<\envskipamount + \removelastskip + \ifnum\lastpenalty<10000 + % Penalize breaking before the environment, because preceding text + % often leads into it. + \penalty100 + \fi + \vskip\envskipamount + \fi + \fi +}} + +\def\afterenvbreak{{% + % =10000 instead of <10000 because of a special case in \itemzzz and + % \sectionheading, q.v. + \ifnum \lastpenalty=10000 \else + \advance\envskipamount by \parskip + \endgraf + \ifdim\lastskip<\envskipamount + \removelastskip + % it's not a good place to break if the last penalty was \nobreak + % or better ... + \ifnum\lastpenalty<10000 \penalty-50 \fi + \vskip\envskipamount + \fi + \fi +}} + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will +% also clear it, so that its embedded environments do the narrowing again. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\envdef\cartouche{% + \ifhmode\par\fi % can't be in the midst of a paragraph. + \startsavinginserts + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt % we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either + % side, and for 6pt waste from + % each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % + % If this cartouche directly follows a sectioning command, we need the + % \parskip glue (backspaced over by default) or the cartouche can + % collide with the section heading. + \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi + % + \setbox\groupbox=\vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \kern3pt + \hsize=\cartinner + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip + \comment % For explanation, see the end of def\group. +} +\def\Ecartouche{% + \ifhmode\par\fi + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup + \addgroupbox + \checkinserts +} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\newdimen\nonfillparindent +\def\nonfillstart{% + \aboveenvbreak + \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + % Turn off paragraph indentation but redefine \indent to emulate + % the normal \indent. + \nonfillparindent=\parindent + \parindent = 0pt + \let\indent\nonfillindent + % + \emergencystretch = 0pt % don't try to avoid overfull boxes + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \let\exdent=\nofillexdent +} + +\begingroup +\obeyspaces +% We want to swallow spaces (but not other tokens) after the fake +% @indent in our nonfill-environments, where spaces are normally +% active and set to @tie, resulting in them not being ignored after +% @indent. +\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% +\gdef\nonfillindentcheck{% +\ifx\temp % +\expandafter\nonfillindentgobble% +\else% +\leavevmode\nonfillindentbox% +\fi% +}% +\endgroup +\def\nonfillindentgobble#1{\nonfillindent} +\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} + +% If you want all examples etc. small: @set dispenvsize small. +% If you want even small examples the full size: @set dispenvsize nosmall. +% This affects the following displayed environments: +% @example, @display, @format, @lisp +% +\def\smallword{small} +\def\nosmallword{nosmall} +\let\SETdispenvsize\relax +\def\setnormaldispenv{% + \ifx\SETdispenvsize\smallword + % end paragraph for sake of leading, in case document has no blank + % line. This is redundant with what happens in \aboveenvbreak, but + % we need to do it before changing the fonts, and it's inconvenient + % to change the fonts afterward. + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} +\def\setsmalldispenv{% + \ifx\SETdispenvsize\nosmallword + \else + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} + +% We often define two environments, @foo and @smallfoo. +% Let's do it in one command. #1 is the env name, #2 the definition. +\def\makedispenvdef#1#2{% + \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}% + \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}% + \expandafter\let\csname E#1\endcsname \afterenvbreak + \expandafter\let\csname Esmall#1\endcsname \afterenvbreak +} + +% Define two environment synonyms (#1 and #2) for an environment. +\def\maketwodispenvdef#1#2#3{% + \makedispenvdef{#1}{#3}% + \makedispenvdef{#2}{#3}% +} +% +% @lisp: indented, narrowed, typewriter font; +% @example: same as @lisp. +% +% @smallexample and @smalllisp: use smaller fonts. +% Originally contributed by Pavel@xerox. +% +\maketwodispenvdef{lisp}{example}{% + \nonfillstart + \tt\setupmarkupstyle{example}% + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} +% @display/@smalldisplay: same as @lisp except keep current font. +% +\makedispenvdef{display}{% + \nonfillstart + \gobble +} + +% @format/@smallformat: same as @display except don't narrow margins. +% +\makedispenvdef{format}{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} + +% @flushleft: same as @format, but doesn't obey \SETdispenvsize. +\envdef\flushleft{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} +\let\Eflushleft = \afterenvbreak + +% @flushright. +% +\envdef\flushright{% + \let\nonarrowing = t% + \nonfillstart + \advance\leftskip by 0pt plus 1fill\relax + \gobble +} +\let\Eflushright = \afterenvbreak + + +% @raggedright does more-or-less normal line breaking but no right +% justification. From plain.tex. Don't stretch around special +% characters in urls in this environment, since the stretch at the right +% should be enough. +\envdef\raggedright{% + \rightskip0pt plus2.4em \spaceskip.3333em \xspaceskip.5em\relax + \def\urefprestretchamount{0pt}% + \def\urefpoststretchamount{0pt}% +} +\let\Eraggedright\par + +\envdef\raggedleft{% + \parindent=0pt \leftskip0pt plus2em + \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt + \hbadness=10000 % Last line will usually be underfull, so turn off + % badness reporting. +} +\let\Eraggedleft\par + +\envdef\raggedcenter{% + \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em + \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt + \hbadness=10000 % Last line will usually be underfull, so turn off + % badness reporting. +} +\let\Eraggedcenter\par + + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. We keep \parskip nonzero in general, since +% we're doing normal filling. So, when using \aboveenvbreak and +% \afterenvbreak, temporarily make \parskip 0. +% +\makedispenvdef{quotation}{\quotationstart} +% +\def\quotationstart{% + \indentedblockstart % same as \indentedblock, but increase right margin too. + \ifx\nonarrowing\relax + \advance\rightskip by \lispnarrowing + \fi + \parsearg\quotationlabel +} + +% We have retained a nonzero parskip for the environment, since we're +% doing normal filling. +% +\def\Equotation{% + \par + \ifx\quotationauthor\thisisundefined\else + % indent a bit. + \leftline{\kern 2\leftskip \sl ---\quotationauthor}% + \fi + {\parskip=0pt \afterenvbreak}% +} +\def\Esmallquotation{\Equotation} + +% If we're given an argument, typeset it in bold with a colon after. +\def\quotationlabel#1{% + \def\temp{#1}% + \ifx\temp\empty \else + {\bf #1: }% + \fi +} + +% @indentedblock is like @quotation, but indents only on the left and +% has no optional argument. +% +\makedispenvdef{indentedblock}{\indentedblockstart} +% +\def\indentedblockstart{% + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \parindent=0pt + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \exdentamount = \lispnarrowing + \else + \let\nonarrowing = \relax + \fi +} + +% Keep a nonzero parskip for the environment, since we're doing normal filling. +% +\def\Eindentedblock{% + \par + {\parskip=0pt \afterenvbreak}% +} +\def\Esmallindentedblock{\Eindentedblock} + + +% LaTeX-like @verbatim...@end verbatim and @verb{...} +% If we want to allow any as delimiter, +% we need the curly braces so that makeinfo sees the @verb command, eg: +% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org +% +% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. +% +% [Knuth] p.344; only we need to do the other characters Texinfo sets +% active too. Otherwise, they get lost as the first character on a +% verbatim line. +\def\dospecials{% + \do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% + \do\<\do\>\do\|\do\@\do+\do\"% + % Don't do the quotes -- if we do, @set txicodequoteundirected and + % @set txicodequotebacktick will not have effect on @verb and + % @verbatim, and ?` and !` ligatures won't get disabled. + %\do\`\do\'% +} +% +% [Knuth] p. 380 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1=\other}\dospecials} +% +% Setup for the @verb command. +% +% Eight spaces for a tab +\begingroup + \catcode`\^^I=\active + \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} +\endgroup +% +\def\setupverb{% + \tt % easiest (and conventionally used) font for verbatim + \def\par{\leavevmode\endgraf}% + \setupmarkupstyle{verb}% + \tabeightspaces + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces +} + +% Setup for the @verbatim environment +% +% Real tab expansion. +\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount +% +% We typeset each line of the verbatim in an \hbox, so we can handle +% tabs. The \global is in case the verbatim line starts with an accent, +% or some other command that starts with a begin-group. Otherwise, the +% entire \verbbox would disappear at the corresponding end-group, before +% it is typeset. Meanwhile, we can't have nested verbatim commands +% (can we?), so the \global won't be overwriting itself. +\newbox\verbbox +\def\starttabbox{\global\setbox\verbbox=\hbox\bgroup} +% +\begingroup + \catcode`\^^I=\active + \gdef\tabexpand{% + \catcode`\^^I=\active + \def^^I{\leavevmode\egroup + \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab + \divide\dimen\verbbox by\tabw + \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw + \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw + \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox + }% + } +\endgroup + +% start the verbatim environment. +\def\setupverbatim{% + \let\nonarrowing = t% + \nonfillstart + \tt % easiest (and conventionally used) font for verbatim + % The \leavevmode here is for blank lines. Otherwise, we would + % never \starttabox and the \egroup would end verbatim mode. + \def\par{\leavevmode\egroup\box\verbbox\endgraf}% + \tabexpand + \setupmarkupstyle{verbatim}% + % Respect line breaks, + % print special symbols as themselves, and + % make each space count. + % Must do in this order: + \obeylines \uncatcodespecials \sepspaces + \everypar{\starttabbox}% +} + +% Do the @verb magic: verbatim text is quoted by unique +% delimiter characters. Before first delimiter expect a +% right brace, after last delimiter expect closing brace: +% +% \def\doverb'{'#1'}'{#1} +% +% [Knuth] p. 382; only eat outer {} +\begingroup + \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other + \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] +\endgroup +% +\def\verb{\begingroup\setupverb\doverb} +% +% +% Do the @verbatim magic: define the macro \doverbatim so that +% the (first) argument ends when '@end verbatim' is reached, ie: +% +% \def\doverbatim#1@end verbatim{#1} +% +% For Texinfo it's a lot easier than for LaTeX, +% because texinfo's \verbatim doesn't stop at '\end{verbatim}': +% we need not redefine '\', '{' and '}'. +% +% Inspired by LaTeX's verbatim command set [latex.ltx] +% +\begingroup + \catcode`\ =\active + \obeylines % + % ignore everything up to the first ^^M, that's the newline at the end + % of the @verbatim input line itself. Otherwise we get an extra blank + % line in the output. + \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% + % We really want {...\end verbatim} in the body of the macro, but + % without the active space; thus we have to use \xdef and \gobble. +\endgroup +% +\envdef\verbatim{% + \setupverbatim\doverbatim +} +\let\Everbatim = \afterenvbreak + + +% @verbatiminclude FILE - insert text of file in verbatim environment. +% +\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} +% +\def\doverbatiminclude#1{% + {% + \makevalueexpandable + \setupverbatim + \indexnofonts % Allow `@@' and other weird things in file names. + \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}% + \input #1 + \afterenvbreak + }% +} + +% @copying ... @end copying. +% Save the text away for @insertcopying later. +% +% We save the uninterpreted tokens, rather than creating a box. +% Saving the text in a box would be much easier, but then all the +% typesetting commands (@smallbook, font changes, etc.) have to be done +% beforehand -- and a) we want @copying to be done first in the source +% file; b) letting users define the frontmatter in as flexible order as +% possible is desirable. +% +\def\copying{\checkenv{}\begingroup\scanargctxt\docopying} +\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} +% +\def\insertcopying{% + \begingroup + \parindent = 0pt % paragraph indentation looks wrong on title page + \scanexp\copyingtext + \endgroup +} + + +\message{defuns,} +% @defun etc. + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deflastargmargin \deflastargmargin=18pt +\newcount\defunpenalty + +% Start the processing of @deffn: +\def\startdefun{% + \ifnum\lastpenalty<10000 + \medbreak + \defunpenalty=10003 % Will keep this @deffn together with the + % following @def command, see below. + \else + % If there are two @def commands in a row, we'll have a \nobreak, + % which is there to keep the function description together with its + % header. But if there's nothing but headers, we need to allow a + % break somewhere. Check specifically for penalty 10002, inserted + % by \printdefunline, instead of 10000, since the sectioning + % commands also insert a nobreak penalty, and we don't want to allow + % a break between a section heading and a defun. + % + % As a further refinement, we avoid "club" headers by signalling + % with penalty of 10003 after the very first @deffn in the + % sequence (see above), and penalty of 10002 after any following + % @def command. + \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi + % + % Similarly, after a section heading, do not allow a break. + % But do insert the glue. + \medskip % preceded by discardable penalty, so not a breakpoint + \fi + % + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent +} + +\def\dodefunx#1{% + % First, check whether we are in the right environment: + \checkenv#1% + % + % As above, allow line break if we have multiple x headers in a row. + % It's not a great place, though. + \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi + % + % And now, it's time to reuse the body of the original defun: + \expandafter\gobbledefun#1% +} +\def\gobbledefun#1\startdefun{} + +% \printdefunline \deffnheader{text} +% +\def\printdefunline#1#2{% + \begingroup + % call \deffnheader: + #1#2 \endheader + % common ending: + \interlinepenalty = 10000 + \advance\rightskip by 0pt plus 1fil\relax + \endgraf + \nobreak\vskip -\parskip + \penalty\defunpenalty % signal to \startdefun and \dodefunx + % Some of the @defun-type tags do not enable magic parentheses, + % rendering the following check redundant. But we don't optimize. + \checkparencounts + \endgroup +} + +\def\Edefun{\endgraf\medbreak} + +% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; +% the only thing remaining is to define \deffnheader. +% +\def\makedefun#1{% + \expandafter\let\csname E#1\endcsname = \Edefun + \edef\temp{\noexpand\domakedefun + \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% + \temp +} + +% \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) } +% +% Define \deffn and \deffnx, without parameters. +% \deffnheader has to be defined explicitly. +% +\def\domakedefun#1#2#3{% + \envdef#1{% + \startdefun + \doingtypefnfalse % distinguish typed functions from all else + \parseargusing\activeparens{\printdefunline#3}% + }% + \def#2{\dodefunx#1}% + \def#3% +} + +\newif\ifdoingtypefn % doing typed function? +\newif\ifrettypeownline % typeset return type on its own line? + +% @deftypefnnewline on|off says whether the return type of typed functions +% are printed on their own line. This affects @deftypefn, @deftypefun, +% @deftypeop, and @deftypemethod. +% +\parseargdef\deftypefnnewline{% + \def\temp{#1}% + \ifx\temp\onword + \expandafter\let\csname SETtxideftypefnnl\endcsname + = \empty + \else\ifx\temp\offword + \expandafter\let\csname SETtxideftypefnnl\endcsname + = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @txideftypefnnl value `\temp', + must be on|off}% + \fi\fi +} + +% Untyped functions: + +% @deffn category name args +\makedefun{deffn}{\deffngeneral{}} + +% @deffn category class name args +\makedefun{defop}#1 {\defopon{#1\ \putwordon}} + +% \defopon {category on}class name args +\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deffngeneral {subind}category name args +% +\def\deffngeneral#1#2 #3 #4\endheader{% + % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. + \dosubind{fn}{\code{#3}}{#1}% + \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% +} + +% Typed functions: + +% @deftypefn category type name args +\makedefun{deftypefn}{\deftypefngeneral{}} + +% @deftypeop category class type name args +\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} + +% \deftypeopon {category on}class type name args +\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deftypefngeneral {subind}category type name args +% +\def\deftypefngeneral#1#2 #3 #4 #5\endheader{% + \dosubind{fn}{\code{#4}}{#1}% + \doingtypefntrue + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +% Typed variables: + +% @deftypevr category type var args +\makedefun{deftypevr}{\deftypecvgeneral{}} + +% @deftypecv category class type var args +\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} + +% \deftypecvof {category of}class type var args +\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } + +% \deftypecvgeneral {subind}category type var args +% +\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% + \dosubind{vr}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +% Untyped variables: + +% @defvr category var args +\makedefun{defvr}#1 {\deftypevrheader{#1} {} } + +% @defcv category class var args +\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} + +% \defcvof {category of}class var args +\def\defcvof#1#2 {\deftypecvof{#1}#2 {} } + +% Types: + +% @deftp category name args +\makedefun{deftp}#1 #2 #3\endheader{% + \doind{tp}{\code{#2}}% + \defname{#1}{}{#2}\defunargs{#3\unskip}% +} + +% Remaining @defun-like shortcuts: +\makedefun{defun}{\deffnheader{\putwordDeffunc} } +\makedefun{defmac}{\deffnheader{\putwordDefmac} } +\makedefun{defspec}{\deffnheader{\putwordDefspec} } +\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } +\makedefun{defvar}{\defvrheader{\putwordDefvar} } +\makedefun{defopt}{\defvrheader{\putwordDefopt} } +\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } +\makedefun{defmethod}{\defopon\putwordMethodon} +\makedefun{deftypemethod}{\deftypeopon\putwordMethodon} +\makedefun{defivar}{\defcvof\putwordInstanceVariableof} +\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} + +% \defname, which formats the name of the @def (not the args). +% #1 is the category, such as "Function". +% #2 is the return type, if any. +% #3 is the function name. +% +% We are followed by (but not passed) the arguments, if any. +% +\def\defname#1#2#3{% + \par + % Get the values of \leftskip and \rightskip as they were outside the @def... + \advance\leftskip by -\defbodyindent + % + % Determine if we are typesetting the return type of a typed function + % on a line by itself. + \rettypeownlinefalse + \ifdoingtypefn % doing a typed function specifically? + % then check user option for putting return type on its own line: + \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else + \rettypeownlinetrue + \fi + \fi + % + % How we'll format the category name. Putting it in brackets helps + % distinguish it from the body text that may end up on the next line + % just below it. + \def\temp{#1}% + \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} + % + % Figure out line sizes for the paragraph shape. We'll always have at + % least two. + \tempnum = 2 + % + % The first line needs space for \box0; but if \rightskip is nonzero, + % we need only space for the part of \box0 which exceeds it: + \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip + % + % If doing a return type on its own line, we'll have another line. + \ifrettypeownline + \advance\tempnum by 1 + \def\maybeshapeline{0in \hsize}% + \else + \def\maybeshapeline{}% + \fi + % + % The continuations: + \dimen2=\hsize \advance\dimen2 by -\defargsindent + % + % The final paragraph shape: + \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2 + % + % Put the category name at the right margin. + \noindent + \hbox to 0pt{% + \hfil\box0 \kern-\hsize + % \hsize has to be shortened this way: + \kern\leftskip + % Intentionally do not respect \rightskip, since we need the space. + }% + % + % Allow all lines to be underfull without complaint: + \tolerance=10000 \hbadness=10000 + \exdentamount=\defbodyindent + {% + % defun fonts. We use typewriter by default (used to be bold) because: + % . we're printing identifiers, they should be in tt in principle. + % . in languages with many accents, such as Czech or French, it's + % common to leave accents off identifiers. The result looks ok in + % tt, but exceedingly strange in rm. + % . we don't want -- and --- to be treated as ligatures. + % . this still does not fix the ?` and !` ligatures, but so far no + % one has made identifiers using them :). + \df \tt + \def\temp{#2}% text of the return type + \ifx\temp\empty\else + \tclose{\temp}% typeset the return type + \ifrettypeownline + % put return type on its own line; prohibit line break following: + \hfil\vadjust{\nobreak}\break + \else + \space % type on same line, so just followed by a space + \fi + \fi % no return type + #3% output function name + }% + {\rm\enskip}% hskip 0.5 em of \tenrm + % + \boldbrax + % arguments will be output next, if any. +} + +% Print arguments in slanted roman (not ttsl), inconsistently with using +% tt for the name. This is because literal text is sometimes needed in +% the argument list (groff manual), and ttsl and tt are not very +% distinguishable. Prevent hyphenation at `-' chars. +% +\def\defunargs#1{% + % use sl by default (not ttsl), + % tt for the names. + \df \sl \hyphenchar\font=0 + % + % On the other hand, if an argument has two dashes (for instance), we + % want a way to get ttsl. We used to recommend @var for that, so + % leave the code in, but it's strange for @var to lead to typewriter. + % Nowadays we recommend @code, since the difference between a ttsl hyphen + % and a tt hyphen is pretty tiny. @code also disables ?` !`. + \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% + #1% + \sl\hyphenchar\font=45 +} + +% We want ()&[] to print specially on the defun line. +% +\def\activeparens{% + \catcode`\(=\active \catcode`\)=\active + \catcode`\[=\active \catcode`\]=\active + \catcode`\&=\active +} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +{ + \activeparens + \global\let(=\lparen \global\let)=\rparen + \global\let[=\lbrack \global\let]=\rbrack + \global\let& = \& + + \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + \gdef\magicamp{\let&=\amprm} +} + +\newcount\parencount + +% If we encounter &foo, then turn on ()-hacking afterwards +\newif\ifampseen +\def\amprm#1 {\ampseentrue{\bf\ }} + +\def\parenfont{% + \ifampseen + % At the first level, print parens in roman, + % otherwise use the default font. + \ifnum \parencount=1 \rm \fi + \else + % The \sf parens (in \boldbrax) actually are a little bolder than + % the contained text. This is especially needed for [ and ] . + \sf + \fi +} +\def\infirstlevel#1{% + \ifampseen + \ifnum\parencount=1 + #1% + \fi + \fi +} +\def\bfafterword#1 {#1 \bf} + +\def\opnr{% + \global\advance\parencount by 1 + {\parenfont(}% + \infirstlevel \bfafterword +} +\def\clnr{% + {\parenfont)}% + \infirstlevel \sl + \global\advance\parencount by -1 +} + +\newcount\brackcount +\def\lbrb{% + \global\advance\brackcount by 1 + {\bf[}% +} +\def\rbrb{% + {\bf]}% + \global\advance\brackcount by -1 +} + +\def\checkparencounts{% + \ifnum\parencount=0 \else \badparencount \fi + \ifnum\brackcount=0 \else \badbrackcount \fi +} +% these should not use \errmessage; the glibc manual, at least, actually +% has such constructs (when documenting function pointers). +\def\badparencount{% + \message{Warning: unbalanced parentheses in @def...}% + \global\parencount=0 +} +\def\badbrackcount{% + \message{Warning: unbalanced square brackets in @def...}% + \global\brackcount=0 +} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\thisisundefined + \newwrite\macscribble + \def\scantokens#1{% + \toks0={#1}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \input \jobname.tmp + } +\fi + +\let\aftermacroxxx\relax +\def\aftermacro{\aftermacroxxx} + +% alias because \c means cedilla in @tex or @math +\let\texinfoc=\c + +% Used at the time of macro expansion. +% Argument is macro body with arguments substituted +\def\scanmacro#1{% + \newlinechar`\^^M + \def\xprocessmacroarg{\eatspaces}% + % + % Process the macro body under the current catcode regime. + \scantokens{#1\texinfoc}\aftermacro% + % + % The \c is to remove the \newlinechar added by \scantokens, and + % can be noticed by \parsearg. + % The \aftermacro allows a \comment at the end of the macro definition + % to duplicate itself past the final \newlinechar added by \scantokens: + % this is used in the definition of \group to comment out a newline. We + % don't do the same for \c to support Texinfo files with macros that ended + % with a @c, which should no longer be necessary. + % We avoid surrounding the call to \scantokens with \bgroup and \egroup + % to allow macros to open or close groups themselves. +} + +% Used for copying and captions +\def\scanexp#1{% + \bgroup + % Undo catcode changes of \startcontents and \printindex + % When called from @insertcopying or (short)caption, we need active + % backslash to get it printed correctly. + % FIXME: This may not be needed. + %\catcode`\@=0 \catcode`\\=\active \escapechar=`\@ + \edef\temp{\noexpand\scanmacro{#1}}% + \temp + \egroup +} + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? + +% List of all defined macros in the form +% \definedummyword\macro1\definedummyword\macro2... +% Currently is also contains all @aliases; the list can be split +% if there is a need. +\def\macrolist{} + +% Add the macro to \macrolist +\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} +\def\addtomacrolistxxx#1{% + \toks0 = \expandafter{\macrolist\definedummyword#1}% + \xdef\macrolist{\the\toks0}% +} + +% Utility routines. +% This does \let #1 = #2, with \csnames; that is, +% \let \csname#1\endcsname = \csname#2\endcsname +% (except of course we have to play expansion games). +% +\def\cslet#1#2{% + \expandafter\let + \csname#1\expandafter\endcsname + \csname#2\endcsname +} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=\other \catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \ +% to recognize macro arguments; this is the job of \mbodybackslash. +% +% Non-ASCII encodings make 8-bit characters active, so un-activate +% them to avoid their expansion. Must do this non-globally, to +% confine the change to the current group. +% +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. +% +\def\scanctxt{% used as subroutine + \catcode`\"=\other + \catcode`\+=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\^=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\~=\other + \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi +} + +\def\scanargctxt{% used for copying and captions, not macros. + \scanctxt + \catcode`\@=\other + \catcode`\\=\other + \catcode`\^^M=\other +} + +\def\macrobodyctxt{% used for @macro definitions + \scanctxt + \catcode`\ =\other + \catcode`\@=\other + \catcode`\{=\other + \catcode`\}=\other + \catcode`\^^M=\other + \usembodybackslash +} + +% Used when scanning braced macro arguments. Note, however, that catcode +% changes here are ineffectual if the macro invocation was nested inside +% an argument to another Texinfo command. +\def\macroargctxt{% + \scanctxt + \catcode`\ =\active + \catcode`\^^M=\other + \catcode`\\=\active +} + +\def\macrolineargctxt{% used for whole-line arguments without braces + \scanctxt + \catcode`\{=\other + \catcode`\}=\other +} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. +% +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\margbackslash#1{\char`\#1 } + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0\relax + \else + \expandafter\parsemargdef \argl;% + \if\paramno>256\relax + \ifx\eTeXversion\thisisundefined + \errhelp = \EMsimple + \errmessage{You need eTeX to compile a file with macros with more than 256 arguments} + \fi + \fi + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{Macro name \the\macname\space already defined}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + \addtomacrolist{\the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\parseargdef\unmacro{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist: + \begingroup + \expandafter\let\csname#1\endcsname \relax + \let\definedummyword\unmacrodo + \xdef\macrolist{\macrolist}% + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% Called by \do from \dounmacro on each macro. The idea is to omit any +% macro definitions that have been changed to \relax. +% +\def\unmacrodo#1{% + \ifx #1\relax + % remove this + \else + \noexpand\definedummyword \noexpand#1% + \fi +} + +% \getargs -- Parse the arguments to a @macro line. Set \macname to +% the name of the macro, and \argl to the braced argument list. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname#1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} +% This made use of the feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. + +% Parse the optional {params} list to @macro or @rmacro. +% Set \paramno to the number of arguments, +% and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a +% three-param macro.) Define \macarg.BLAH for each BLAH in the params +% list to some hook where the argument is to be expanded. If there are +% less than 10 arguments that hook is to be replaced by ##N where N +% is the position in that list, that is to say the macro arguments are to be +% defined `a la TeX in the macro body. +% +% That gets used by \mbodybackslash (above). +% +% If there are 10 or more arguments, a different technique is used: see +% \parsemmanyargdef. +% +\def\parsemargdef#1;{% + \paramno=0\def\paramlist{}% + \let\hash\relax + % \hash is redefined to `#' later to get it into definitions + \let\processmacroarg\relax + \parsemargdefxxx#1,;,% + \ifnum\paramno<10\relax\else + \paramno0\relax + \parsemmanyargdef@@#1,;,% 10 or more arguments + \fi +} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1 + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\processmacroarg{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% \parsemacbody, \parsermacbody +% +% Read recursive and nonrecursive macro bodies. (They're different since +% rec and nonrec macros end differently.) +% +% We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro +% body to be transformed. +% Set \macrobody to the body of the macro, and call \defmacro. +% +{\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{% +\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}% +{\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{% +\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}% + +% Make @ a letter, so that we can make private-to-Texinfo macro names. +\edef\texiatcatcode{\the\catcode`\@} +\catcode `@=11\relax + +%%%%%%%%%%%%%% Code for > 10 arguments only %%%%%%%%%%%%%%%%%% + +% If there are 10 or more arguments, a different technique is used, where the +% hook remains in the body, and when macro is to be expanded the body is +% processed again to replace the arguments. +% +% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the +% argument N value and then \edef the body (nothing else will expand because of +% the catcode regime under which the body was input). +% +% If you compile with TeX (not eTeX), and you have macros with 10 or more +% arguments, no macro can have more than 256 arguments (else error). +% +% In case that there are 10 or more arguments we parse again the arguments +% list to set new definitions for the \macarg.BLAH macros corresponding to +% each BLAH argument. It was anyhow needed to parse already once this list +% in order to count the arguments, and as macros with at most 9 arguments +% are by far more frequent than macro with 10 or more arguments, defining +% twice the \macarg.BLAH macros does not cost too much processing power. +\def\parsemmanyargdef@@#1,{% + \if#1;\let\next=\relax + \else + \let\next=\parsemmanyargdef@@ + \edef\tempb{\eatspaces{#1}}% + \expandafter\def\expandafter\tempa + \expandafter{\csname macarg.\tempb\endcsname}% + % Note that we need some extra \noexpand\noexpand, this is because we + % don't want \the to be expanded in the \parsermacbody as it uses an + % \xdef . + \expandafter\edef\tempa + {\noexpand\noexpand\noexpand\the\toks\the\paramno}% + \advance\paramno by 1\relax + \fi\next} + + +\let\endargs@\relax +\let\nil@\relax +\def\nilm@{\nil@}% +\long\def\nillm@{\nil@}% + +% This macro is expanded during the Texinfo macro expansion, not during its +% definition. It gets all the arguments' values and assigns them to macros +% macarg.ARGNAME +% +% #1 is the macro name +% #2 is the list of argument names +% #3 is the list of argument values +\def\getargvals@#1#2#3{% + \def\macargdeflist@{}% + \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion. + \def\paramlist{#2,\nil@}% + \def\macroname{#1}% + \begingroup + \macroargctxt + \def\argvaluelist{#3,\nil@}% + \def\@tempa{#3}% + \ifx\@tempa\empty + \setemptyargvalues@ + \else + \getargvals@@ + \fi +} +\def\getargvals@@{% + \ifx\paramlist\nilm@ + % Some sanity check needed here that \argvaluelist is also empty. + \ifx\argvaluelist\nillm@ + \else + \errhelp = \EMsimple + \errmessage{Too many arguments in macro `\macroname'!}% + \fi + \let\next\macargexpandinbody@ + \else + \ifx\argvaluelist\nillm@ + % No more arguments values passed to macro. Set remaining named-arg + % macros to empty. + \let\next\setemptyargvalues@ + \else + % pop current arg name into \@tempb + \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}% + \expandafter\@tempa\expandafter{\paramlist}% + % pop current argument value into \@tempc + \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}% + \expandafter\@tempa\expandafter{\argvaluelist}% + % Here \@tempb is the current arg name and \@tempc is the current arg value. + % First place the new argument macro definition into \@tempd + \expandafter\macname\expandafter{\@tempc}% + \expandafter\let\csname macarg.\@tempb\endcsname\relax + \expandafter\def\expandafter\@tempe\expandafter{% + \csname macarg.\@tempb\endcsname}% + \edef\@tempd{\long\def\@tempe{\the\macname}}% + \push@\@tempd\macargdeflist@ + \let\next\getargvals@@ + \fi + \fi + \next +} + +\def\push@#1#2{% + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter#2% + \expandafter\expandafter\expandafter{% + \expandafter#1#2}% +} + +% Replace arguments by their values in the macro body, and place the result +% in macro \@tempa. +% +\def\macvalstoargs@{% + % To do this we use the property that token registers that are \the'ed + % within an \edef expand only once. So we are going to place all argument + % values into respective token registers. + % + % First we save the token context, and initialize argument numbering. + \begingroup + \paramno0\relax + % Then, for each argument number #N, we place the corresponding argument + % value into a new token list register \toks#N + \expandafter\putargsintokens@\saveparamlist@,;,% + % Then, we expand the body so that argument are replaced by their + % values. The trick for values not to be expanded themselves is that they + % are within tokens and that tokens expand only once in an \edef . + \edef\@tempc{\csname mac.\macroname .body\endcsname}% + % Now we restore the token stack pointer to free the token list registers + % which we have used, but we make sure that expanded body is saved after + % group. + \expandafter + \endgroup + \expandafter\def\expandafter\@tempa\expandafter{\@tempc}% + } + +% Define the named-macro outside of this group and then close this group. +% +\def\macargexpandinbody@{% + \expandafter + \endgroup + \macargdeflist@ + % First the replace in body the macro arguments by their values, the result + % is in \@tempa . + \macvalstoargs@ + % Then we point at the \norecurse or \gobble (for recursive) macro value + % with \@tempb . + \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname + % Depending on whether it is recursive or not, we need some tailing + % \egroup . + \ifx\@tempb\gobble + \let\@tempc\relax + \else + \let\@tempc\egroup + \fi + % And now we do the real job: + \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}% + \@tempd +} + +\def\putargsintokens@#1,{% + \if#1;\let\next\relax + \else + \let\next\putargsintokens@ + % First we allocate the new token list register, and give it a temporary + % alias \@tempb . + \toksdef\@tempb\the\paramno + % Then we place the argument value into that token list register. + \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname + \expandafter\@tempb\expandafter{\@tempa}% + \advance\paramno by 1\relax + \fi + \next +} + +% Trailing missing arguments are set to empty. +% +\def\setemptyargvalues@{% + \ifx\paramlist\nilm@ + \let\next\macargexpandinbody@ + \else + \expandafter\setemptyargvaluesparser@\paramlist\endargs@ + \let\next\setemptyargvalues@ + \fi + \next +} + +\def\setemptyargvaluesparser@#1,#2\endargs@{% + \expandafter\def\expandafter\@tempa\expandafter{% + \expandafter\def\csname macarg.#1\endcsname{}}% + \push@\@tempa\macargdeflist@ + \def\paramlist{#2}% +} + +% #1 is the element target macro +% #2 is the list macro +% #3,#4\endargs@ is the list value +\def\pop@#1#2#3,#4\endargs@{% + \def#1{#3}% + \def#2{#4}% +} +\long\def\longpop@#1#2#3,#4\endargs@{% + \long\def#1{#3}% + \long\def#2{#4}% +} + + +%%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%% + + + +% Remove following spaces at the expansion stage. +% This works because spaces are discarded before each argument when TeX is +% getting the arguments for a macro. +% This must not be immediately followed by a }. +\long\def\gobblespaces#1{#1} + +% This defines a Texinfo @macro or @rmacro, called by \parsemacbody. +% \macrobody has the body of the macro in it, with placeholders for +% its parameters, looking like "\processmacroarg{\hash 1}". +% \paramno is the number of parameters +% \paramlist is a TeX parameter text, e.g. "#1,#2,#3," +% There are eight cases: recursive and nonrecursive macros of zero, one, +% up to nine, and many arguments. +% \xdef is used so that macro definitions will survive the file +% they're defined in: @include reads the file inside a group. +% +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifnum\paramno=1 + \def\processmacroarg{\gobblespaces}% + % This removes the pair of braces around the argument. We don't + % use \eatspaces, because this can cause ends of lines to be lost + % when the argument to \eatspaces is read, leading to line-based + % commands like "@itemize" not being read correctly. + \else + \def\processmacroarg{\xprocessmacroarg}% + \let\xprocessmacroarg\relax + \fi + \ifrecursive %%%%%%%%%%%%%% Recursive %%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\macrobody}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname @@@\endcsname}% + \expandafter\xdef\csname\the\macname @@@\endcsname##1{% + \expandafter\noexpand\csname\the\macname @@@@\endcsname{% + \noexpand\gobblespaces##1\empty}% + % The \empty is for \gobblespaces in case #1 is empty + }% + \expandafter\xdef\csname\the\macname @@@@\endcsname##1{% + \egroup\noexpand\scanmacro{\macrobody}}% + \else + \ifnum\paramno<10\relax % at most 9 + % See non-recursive section below for comments + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup + \noexpand\expandafter + \noexpand\macroargctxt + \noexpand\expandafter + \expandafter\noexpand\csname\the\macname @@\endcsname}% + \expandafter\xdef\csname\the\macname @@\endcsname##1{% + \noexpand\passargtomacro + \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% + \expandafter\xdef\csname\the\macname @@@\endcsname##1{% + \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname @@@@\endcsname\paramlist{% + \egroup\noexpand\scanmacro{\macrobody}}% + \else % 10 or more + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\getargvals@{\the\macname}{\argl}% + }% + \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody + \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble + \fi + \fi + \else %%%%%%%%%%%%%%%%%%%%%% Non-recursive %%%%%%%%%%%%%%%%%%%%%%%%%% + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\macrobody}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname @@@\endcsname}% + \expandafter\xdef\csname\the\macname @@@\endcsname##1{% + \expandafter\noexpand\csname\the\macname @@@@\endcsname{% + \noexpand\gobblespaces##1\empty}% + % The \empty is for \gobblespaces in case #1 is empty + }% + \expandafter\xdef\csname\the\macname @@@@\endcsname##1{% + \egroup + \noexpand\scanmacro{\macrobody}% + }% + \else % at most 9 + \ifnum\paramno<10\relax + % @MACNAME sets the context for reading the macro argument + % @MACNAME@@ gets the argument, processes backslashes and appends a + % comma. + % @MACNAME@@@ removes braces surrounding the argument list. + % @MACNAME@@@@ scans the macro body with arguments substituted. + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup + \noexpand\expandafter % This \expandafter skip any spaces after the + \noexpand\macroargctxt % macro before we change the catcode of space. + \noexpand\expandafter + \expandafter\noexpand\csname\the\macname @@\endcsname}% + \expandafter\xdef\csname\the\macname @@\endcsname##1{% + \noexpand\passargtomacro + \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% + \expandafter\xdef\csname\the\macname @@@\endcsname##1{% + \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname @@@@\endcsname\paramlist{% + \egroup\noexpand\scanmacro{\macrobody}}% + \else % 10 or more: + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\getargvals@{\the\macname}{\argl}% + }% + \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody + \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse + \fi + \fi + \fi} + +\catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +{\catcode`\@=0 \catcode`\\=13 % We need to manipulate \ so use @ as escape +@catcode`@_=11 % private names +@catcode`@!=11 % used as argument separator + +% \passargtomacro#1#2 - +% Call #1 with a list of tokens #2, with any doubled backslashes in #2 +% compressed to one. +% +% This implementation works by expansion, and not execution (so we cannot use +% \def or similar). This reduces the risk of this failing in contexts where +% complete expansion is done with no execution (for example, in writing out to +% an auxiliary file for an index entry). +% +% State is kept in the input stream: the argument passed to +% @look_ahead, @gobble_and_check_finish and @add_segment is +% +% THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN (... rest of input) +% +% where: +% THE_MACRO - name of the macro we want to call +% ARG_RESULT - argument list we build to pass to that macro +% PENDING_BS - either a backslash or nothing +% NEXT_TOKEN - used to look ahead in the input stream to see what's coming next + +@gdef@passargtomacro#1#2{% + @add_segment #1!{}@relax#2\@_finish\% +} +@gdef@_finish{@_finishx} @global@let@_finishx@relax + +% #1 - THE_MACRO ARG_RESULT +% #2 - PENDING_BS +% #3 - NEXT_TOKEN +% #4 used to look ahead +% +% If the next token is not a backslash, process the rest of the argument; +% otherwise, remove the next token. +@gdef@look_ahead#1!#2#3#4{% + @ifx#4\% + @expandafter@gobble_and_check_finish + @else + @expandafter@add_segment + @fi#1!{#2}#4#4% +} + +% #1 - THE_MACRO ARG_RESULT +% #2 - PENDING_BS +% #3 - NEXT_TOKEN +% #4 should be a backslash, which is gobbled. +% #5 looks ahead +% +% Double backslash found. Add a single backslash, and look ahead. +@gdef@gobble_and_check_finish#1!#2#3#4#5{% + @add_segment#1\!{}#5#5% +} + +@gdef@is_fi{@fi} + +% #1 - THE_MACRO ARG_RESULT +% #2 - PENDING_BS +% #3 - NEXT_TOKEN +% #4 is input stream until next backslash +% +% Input stream is either at the start of the argument, or just after a +% backslash sequence, either a lone backslash, or a doubled backslash. +% NEXT_TOKEN contains the first token in the input stream: if it is \finish, +% finish; otherwise, append to ARG_RESULT the segment of the argument up until +% the next backslash. PENDING_BACKSLASH contains a backslash to represent +% a backslash just before the start of the input stream that has not been +% added to ARG_RESULT. +@gdef@add_segment#1!#2#3#4\{% +@ifx#3@_finish + @call_the_macro#1!% +@else + % append the pending backslash to the result, followed by the next segment + @expandafter@is_fi@look_ahead#1#2#4!{\}@fi + % this @fi is discarded by @look_ahead. + % we can't get rid of it with \expandafter because we don't know how + % long #4 is. +} + +% #1 - THE_MACRO +% #2 - ARG_RESULT +% #3 discards the res of the conditional in @add_segment, and @is_fi ends the +% conditional. +@gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}} + +} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% \braceorline MAC is used for a one-argument macro MAC. It checks +% whether the next non-whitespace character is a {. It sets the context +% for reading the argument (slightly different in the two cases). Then, +% to read the argument, in the whole-line case, it then calls the regular +% \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC. +% +\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup + \macroargctxt + \expandafter\passargtomacro + \else + \macrolineargctxt\expandafter\parsearg + \fi \macnamexxx} + + +% @alias. +% We need some trickery to remove the optional spaces around the equal +% sign. Make them active and then expand them all to nothing. +% +\def\alias{\parseargusing\obeyspaces\aliasxxx} +\def\aliasxxx #1{\aliasyyy#1\relax} +\def\aliasyyy #1=#2\relax{% + {% + \expandafter\let\obeyedspace=\empty + \addtomacrolist{#1}% + \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% + }% + \next +} + + +\message{cross references,} + +\newwrite\auxfile +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{% + \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's only job in TeX is to define \lastnode, which is used in +% cross-references. The @node line might or might not have commas, and +% might or might not have spaces before the first comma, like: +% @node foo , bar , ... +% We don't want such trailing spaces in the node name. +% +\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} +% +% also remove a trailing comma, in case of something like this: +% @node Help-Cross, , , Cross-refs +\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} +\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} + +\let\nwnode=\node +\let\lastnode=\empty + +% Write a cross-reference definition for the current node. #1 is the +% type (Ynumbered, Yappendix, Ynothing). +% +\def\donoderef#1{% + \ifx\lastnode\empty\else + \setref{\lastnode}{#1}% + \global\let\lastnode=\empty + \fi +} + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\newcount\savesfregister +% +\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} +\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} +\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} + +% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an +% anchor), which consists of three parts: +% 1) NAME-title - the current sectioning name taken from \lastsection, +% or the anchor name. +% 2) NAME-snt - section number and type, passed as the SNT arg, or +% empty for anchors. +% 3) NAME-pg - the page number. +% +% This is called from \donoderef, \anchor, and \dofloat. In the case of +% floats, there is an additional part, which is not written here: +% 4) NAME-lof - the text as it should appear in a @listoffloats. +% +\def\setref#1#2{% + \pdfmkdest{#1}% + \iflinks + {% + \requireauxfile + \atdummies % preserve commands, but don't expand them + \edef\writexrdef##1##2{% + \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef + ##1}{##2}}% these are parameters of \writexrdef + }% + \toks0 = \expandafter{\lastsection}% + \immediate \writexrdef{title}{\the\toks0 }% + \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. + \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout + }% + \fi +} + +% @xrefautosectiontitle on|off says whether @section(ing) names are used +% automatically in xrefs, if the third arg is not explicitly specified. +% This was provided as a "secret" @set xref-automatic-section-title +% variable, now it's official. +% +\parseargdef\xrefautomaticsectiontitle{% + \def\temp{#1}% + \ifx\temp\onword + \expandafter\let\csname SETxref-automatic-section-title\endcsname + = \empty + \else\ifx\temp\offword + \expandafter\let\csname SETxref-automatic-section-title\endcsname + = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @xrefautomaticsectiontitle value `\temp', + must be on|off}% + \fi\fi +} + +% +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref{\putwordsee{} \xrefXX} +\def\xref{\putwordSee{} \xrefXX} +\def\ref{\xrefXX} + +\def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX} +\def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]} +% +\newbox\toprefbox +\newbox\printedrefnamebox +\newbox\infofilenamebox +\newbox\printedmanualbox +% +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \unsepspaces + % + % Get args without leading/trailing spaces. + \def\printedrefname{\ignorespaces #3}% + \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}% + % + \def\infofilename{\ignorespaces #4}% + \setbox\infofilenamebox = \hbox{\infofilename\unskip}% + % + \def\printedmanual{\ignorespaces #5}% + \setbox\printedmanualbox = \hbox{\printedmanual\unskip}% + % + % If the printed reference name (arg #3) was not explicitly given in + % the @xref, figure out what we want to use. + \ifdim \wd\printedrefnamebox = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax + % Not auto section-title: use node name inside the square brackets. + \def\printedrefname{\ignorespaces #1}% + \else + % Auto section-title: use chapter/section title inside + % the square brackets if we have it. + \ifdim \wd\printedmanualbox > 0pt + % It is in another manual, so we don't have it; use node name. + \def\printedrefname{\ignorespaces #1}% + \else + \ifhavexrefs + % We (should) know the real title if we have the xref values. + \def\printedrefname{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printedrefname{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % Make link in pdf output. + \ifpdf + {\indexnofonts + \turnoffactive + \makevalueexpandable + % This expands tokens, so do it after making catcode changes, so _ + % etc. don't get their TeX definitions. This ignores all spaces in + % #4, including (wrongly) those in the middle of the filename. + \getfilename{#4}% + % + % This (wrongly) does not take account of leading or trailing + % spaces in #1, which should be ignored. + \edef\pdfxrefdest{#1}% + \ifx\pdfxrefdest\empty + \def\pdfxrefdest{Top}% no empty targets + \else + \txiescapepdf\pdfxrefdest % escape PDF special chars + \fi + % + \leavevmode + \startlink attr{/Border [0 0 0]}% + \ifnum\filenamelength>0 + goto file{\the\filename.pdf} name{\pdfxrefdest}% + \else + goto name{\pdfmkpgn{\pdfxrefdest}}% + \fi + }% + \setcolor{\linkcolor}% + \fi + {% + % Have to otherify everything special to allow the \csname to + % include an _ in the xref name, etc. + \indexnofonts + \turnoffactive + \expandafter\global\expandafter\let\expandafter\Xthisreftitle + \csname XR#1-title\endcsname + }% + % + % Float references are printed completely differently: "Figure 1.2" + % instead of "[somenode], p.3". \iffloat distinguishes them by + % \Xthisreftitle being set to a magic string. + \iffloat\Xthisreftitle + % If the user specified the print name (third arg) to the ref, + % print it instead of our usual "Figure 1.2". + \ifdim\wd\printedrefnamebox = 0pt + \refx{#1-snt}{}% + \else + \printedrefname + \fi + % + % If the user also gave the printed manual name (fifth arg), append + % "in MANUALNAME". + \ifdim \wd\printedmanualbox > 0pt + \space \putwordin{} \cite{\printedmanual}% + \fi + \else + % node/anchor (non-float) references. + % + % If we use \unhbox to print the node names, TeX does not insert + % empty discretionaries after hyphens, which means that it will not + % find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, + % this is a loss. Therefore, we give the text of the node name + % again, so it is as if TeX is seeing it for the first time. + % + \ifdim \wd\printedmanualbox > 0pt + % Cross-manual reference with a printed manual name. + % + \crossmanualxref{\cite{\printedmanual\unskip}}% + % + \else\ifdim \wd\infofilenamebox > 0pt + % Cross-manual reference with only an info filename (arg 4), no + % printed manual name (arg 5). This is essentially the same as + % the case above; we output the filename, since we have nothing else. + % + \crossmanualxref{\code{\infofilename\unskip}}% + % + \else + % Reference within this manual. + % + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % output the `[mynode]' via the macro below so it can be overridden. + \xrefprintnodename\printedrefname + % + % But we always want a comma and a space: + ,\space + % + % output the `page 3'. + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + % Add a , if xref followed by a space + \if\space\noexpand\tokenafterxref ,% + \else\ifx\ \tokenafterxref ,% @TAB + \else\ifx\*\tokenafterxref ,% @* + \else\ifx\ \tokenafterxref ,% @SPACE + \else\ifx\ + \tokenafterxref ,% @NL + \else\ifx\tie\tokenafterxref ,% @tie + \fi\fi\fi\fi\fi\fi + \fi\fi + \fi + \endlink +\endgroup} + +% Output a cross-manual xref to #1. Used just above (twice). +% +% Only include the text "Section ``foo'' in" if the foo is neither +% missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply +% "see The Foo Manual", the idea being to refer to the whole manual. +% +% But, this being TeX, we can't easily compare our node name against the +% string "Top" while ignoring the possible spaces before and after in +% the input. By adding the arbitrary 7sp below, we make it much less +% likely that a real node name would have the same width as "Top" (e.g., +% in a monospaced font). Hopefully it will never happen in practice. +% +% For the same basic reason, we retypeset the "Top" at every +% reference, since the current font is indeterminate. +% +\def\crossmanualxref#1{% + \setbox\toprefbox = \hbox{Top\kern7sp}% + \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}% + \ifdim \wd2 > 7sp % nonempty? + \ifdim \wd2 = \wd\toprefbox \else % same as Top? + \putwordSection{} ``\printedrefname'' \putwordin{}\space + \fi + \fi + #1% +} + +% This macro is called from \xrefX for the `[nodename]' part of xref +% output. It's a separate macro only so it can be changed more easily, +% since square brackets don't work well in some documents. Particularly +% one that Bob is working on :). +% +\def\xrefprintnodename#1{[#1]} + +% Things referred to by \setref. +% +\def\Ynothing{} +\def\Yomitfromtoc{} +\def\Ynumbered{% + \ifnum\secno=0 + \putwordChapter@tie \the\chapno + \else \ifnum\subsecno=0 + \putwordSection@tie \the\chapno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno + \else + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} +\def\Yappendix{% + \ifnum\secno=0 + \putwordAppendix@tie @char\the\appendixno{}% + \else \ifnum\subsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno + \else + \putwordSection@tie + @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. +% +\def\refx#1#2{% + \requireauxfile + {% + \indexnofonts + \otherbackslash + \expandafter\global\expandafter\let\expandafter\thisrefX + \csname XR#1\endcsname + }% + \ifx\thisrefX\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + {\toks0 = {#1}% avoid expansion of possibly-complex value + \message{\linenumber Undefined cross reference `\the\toks0'.}}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \thisrefX + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. Usually it's +% just a \def (we prepend XR to the control sequence name to avoid +% collisions). But if this is a float type, we have more work to do. +% +\def\xrdef#1#2{% + {% The node name might contain 8-bit characters, which in our current + % implementation are changed to commands like @'e. Don't let these + % mess up the control sequence name. + \indexnofonts + \turnoffactive + \xdef\safexrefname{#1}% + }% + % + \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref + % + % Was that xref control sequence that we just defined for a float? + \expandafter\iffloat\csname XR\safexrefname\endcsname + % it was a float, and we have the (safe) float type in \iffloattype. + \expandafter\let\expandafter\floatlist + \csname floatlist\iffloattype\endcsname + % + % Is this the first time we've seen this float type? + \expandafter\ifx\floatlist\relax + \toks0 = {\do}% yes, so just \do + \else + % had it before, so preserve previous elements in list. + \toks0 = \expandafter{\floatlist\do}% + \fi + % + % Remember this xref in the control sequence \floatlistFLOATTYPE, + % for later use in \listoffloats. + \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 + {\safexrefname}}% + \fi +} + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate at the beginning of the file. +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% Used when writing to the aux file, or when using data from it. +\def\requireauxfile{% + \iflinks + \tryauxfile + % Open the new aux file. TeX will close it automatically at exit. + \immediate\openout\auxfile=\jobname.aux + \fi + \global\let\requireauxfile=\relax % Only do this once. +} + +% Read the last existing aux file, if any. No error if none exists. +% +\def\tryauxfile{% + \openin 1 \jobname.aux + \ifeof 1 \else + \readdatafile{aux}% + \global\havexrefstrue + \fi + \closein 1 +} + +\def\setupdatafile{% + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\^=\other + % + % Special characters. Should be turned off anyway, but... + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`\%=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % + % This is to support \ in node names and titles, since the \ + % characters end up in a \csname. It's easier than + % leaving it active and making its active definition an actual \ + % character. What I don't understand is why it works in the *value* + % of the xrdef. Seems like it should be a catcode12 \, and that + % should not typeset properly. But it works, so I'm moving on for + % now. --karl, 15jan04. + \catcode`\\=\other + % + % Make the characters 128-255 be printing characters. + {\setnonasciicharscatcodenonglobal\other}% + % + % @ is our escape character in .aux files, and we need braces. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\@=0 +} + +\def\readdatafile#1{% +\begingroup + \setupdatafile + \input\jobname.#1 +\endgroup} + + +\message{insertions,} +% including footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for Info output only. +\let\footnotestyle=\comment + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \dofootnote +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset (and anything else that uses +% \parseargline) fails inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\gdef\dofootnote{% + \insert\footins\bgroup + % + % Nested footnotes are not supported in TeX, that would take a lot + % more work. (\startsavinginserts does not suffice.) + \let\footnote=\errfootnotenest + % + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \hsize=\pagewidth + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + \smallfonts \rm + % + % Because we use hanging indentation in footnotes, a @noindent appears + % to exdent this text, so make it be a no-op. makeinfo does not use + % hanging indentation so @noindent can still be needed within footnote + % text after an @example or the like (not that this is good style). + \let\noindent = \relax + % + % Hang the footnote text off the number. Use \everypar in case the + % footnote extends for more than one paragraph. + \everypar = {\hang}% + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + % + % Invoke rest of plain TeX footnote routine. + \futurelet\next\fo@t +} +}%end \catcode `\@=11 + +\def\errfootnotenest{% + \errhelp=\EMsimple + \errmessage{Nested footnotes not supported in texinfo.tex, + even though they work in makeinfo; sorry} +} + +\def\errfootnoteheading{% + \errhelp=\EMsimple + \errmessage{Footnotes in chapters, sections, etc., are not supported} +} + +% In case a @footnote appears in a vbox, save the footnote text and create +% the real \insert just after the vbox finished. Otherwise, the insertion +% would be lost. +% Similarly, if a @footnote appears inside an alignment, save the footnote +% text to a box and make the \insert when a row of the table is finished. +% And the same can be done for other insert classes. --kasal, 16nov03. +% +% Replace the \insert primitive by a cheating macro. +% Deeper inside, just make sure that the saved insertions are not spilled +% out prematurely. +% +\def\startsavinginserts{% + \ifx \insert\ptexinsert + \let\insert\saveinsert + \else + \let\checkinserts\relax + \fi +} + +% This \insert replacement works for both \insert\footins{foo} and +% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. +% +\def\saveinsert#1{% + \edef\next{\noexpand\savetobox \makeSAVEname#1}% + \afterassignment\next + % swallow the left brace + \let\temp = +} +\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} +\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} + +\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} + +\def\placesaveins#1{% + \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname + {\box#1}% +} + +% eat @SAVE -- beware, all of them have catcode \other: +{ + \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) + \gdef\gobblesave @SAVE{} +} + +% initialization: +\def\newsaveins #1{% + \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% + \next +} +\def\newsaveinsX #1{% + \csname newbox\endcsname #1% + \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts + \checksaveins #1}% +} + +% initialize: +\let\checkinserts\empty +\newsaveins\footins +\newsaveins\margin + + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + % Do not bother showing banner with epsf.tex v2.7k (available in + % doc/epsf.tex and on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +\closein 1 +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\thisisundefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is (ignored optional) html alt text. +% #5 is (ignored optional) extension. +% #6 is just the usual extra ignored arg for parsing stuff. +\newif\ifimagevmode +\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup + \catcode`\^^M = 5 % in case we're inside an example + \normalturnoffactive % allow _ et al. in names + \def\xprocessmacroarg{\eatspaces}% in case we are being used via a macro + % If the image is by itself, center it. + \ifvmode + \imagevmodetrue + \else \ifx\centersub\centerV + % for @center @image, we need a vbox so we can have our vertical space + \imagevmodetrue + \vbox\bgroup % vbox has better behavior than vtop herev + \fi\fi + % + \ifimagevmode + \nobreak\medskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \fi + % + % Leave vertical mode so that indentation from an enclosing + % environment such as @quotation is respected. + % However, if we're at the top level, we don't want the + % normal paragraph indentation. + % On the other hand, if we are in the case of @center @image, we don't + % want to start a paragraph, which will create a hsize-width box and + % eradicate the centering. + \ifx\centersub\centerV\else \noindent \fi + % + % Output the image. + \ifpdf + % For pdfTeX and LuaTeX <= 0.80 + \dopdfimage{#1}{#2}{#3}% + \else + \ifx\XeTeXrevision\thisisundefined + % For epsf.tex + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% + \else + % For XeTeX + \doxeteximage{#1}{#2}{#3}% + \fi + \fi + % + \ifimagevmode + \medskip % space after a standalone image + \fi + \ifx\centersub\centerV \egroup \fi +\endgroup} + + +% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, +% etc. We don't actually implement floating yet, we always include the +% float "here". But it seemed the best name for the future. +% +\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} + +% There may be a space before second and/or third parameter; delete it. +\def\eatcommaspace#1, {#1,} + +% #1 is the optional FLOATTYPE, the text label for this float, typically +% "Figure", "Table", "Example", etc. Can't contain commas. If omitted, +% this float will not be numbered and cannot be referred to. +% +% #2 is the optional xref label. Also must be present for the float to +% be referable. +% +% #3 is the optional positioning argument; for now, it is ignored. It +% will somehow specify the positions allowed to float to (here, top, bottom). +% +% We keep a separate counter for each FLOATTYPE, which we reset at each +% chapter-level command. +\let\resetallfloatnos=\empty +% +\def\dofloat#1,#2,#3,#4\finish{% + \let\thiscaption=\empty + \let\thisshortcaption=\empty + % + % don't lose footnotes inside @float. + % + % BEWARE: when the floats start float, we have to issue warning whenever an + % insert appears inside a float which could possibly float. --kasal, 26may04 + % + \startsavinginserts + % + % We can't be used inside a paragraph. + \par + % + \vtop\bgroup + \def\floattype{#1}% + \def\floatlabel{#2}% + \def\floatloc{#3}% we do nothing with this yet. + % + \ifx\floattype\empty + \let\safefloattype=\empty + \else + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + \fi + % + % If label is given but no type, we handle that as the empty type. + \ifx\floatlabel\empty \else + % We want each FLOATTYPE to be numbered separately (Figure 1, + % Table 1, Figure 2, ...). (And if no label, no number.) + % + \expandafter\getfloatno\csname\safefloattype floatno\endcsname + \global\advance\floatno by 1 + % + {% + % This magic value for \lastsection is output by \setref as the + % XREFLABEL-title value. \xrefX uses it to distinguish float + % labels (which have a completely different output format) from + % node and anchor labels. And \xrdef uses it to construct the + % lists of floats. + % + \edef\lastsection{\floatmagic=\safefloattype}% + \setref{\floatlabel}{Yfloat}% + }% + \fi + % + % start with \parskip glue, I guess. + \vskip\parskip + % + % Don't suppress indentation if a float happens to start a section. + \restorefirstparagraphindent +} + +% we have these possibilities: +% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap +% @float Foo,lbl & no caption: Foo 1.1 +% @float Foo & @caption{Cap}: Foo: Cap +% @float Foo & no caption: Foo +% @float ,lbl & Caption{Cap}: 1.1: Cap +% @float ,lbl & no caption: 1.1 +% @float & @caption{Cap}: Cap +% @float & no caption: +% +\def\Efloat{% + \let\floatident = \empty + % + % In all cases, if we have a float type, it comes first. + \ifx\floattype\empty \else \def\floatident{\floattype}\fi + % + % If we have an xref label, the number comes next. + \ifx\floatlabel\empty \else + \ifx\floattype\empty \else % if also had float type, need tie first. + \appendtomacro\floatident{\tie}% + \fi + % the number. + \appendtomacro\floatident{\chaplevelprefix\the\floatno}% + \fi + % + % Start the printed caption with what we've constructed in + % \floatident, but keep it separate; we need \floatident again. + \let\captionline = \floatident + % + \ifx\thiscaption\empty \else + \ifx\floatident\empty \else + \appendtomacro\captionline{: }% had ident, so need a colon between + \fi + % + % caption text. + \appendtomacro\captionline{\scanexp\thiscaption}% + \fi + % + % If we have anything to print, print it, with space before. + % Eventually this needs to become an \insert. + \ifx\captionline\empty \else + \vskip.5\parskip + \captionline + % + % Space below caption. + \vskip\parskip + \fi + % + % If have an xref label, write the list of floats info. Do this + % after the caption, to avoid chance of it being a breakpoint. + \ifx\floatlabel\empty \else + % Write the text that goes in the lof to the aux file as + % \floatlabel-lof. Besides \floatident, we include the short + % caption if specified, else the full caption if specified, else nothing. + {% + \requireauxfile + \atdummies + % + % since we read the caption text in the macro world, where ^^M + % is turned into a normal character, we have to scan it back, so + % we don't write the literal three characters "^^M" into the aux file. + \scanexp{% + \xdef\noexpand\gtemp{% + \ifx\thisshortcaption\empty + \thiscaption + \else + \thisshortcaption + \fi + }% + }% + \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident + \ifx\gtemp\empty \else : \gtemp \fi}}% + }% + \fi + \egroup % end of \vtop + % + % place the captured inserts + % + % BEWARE: when the floats start floating, we have to issue warning + % whenever an insert appears inside a float which could possibly + % float. --kasal, 26may04 + % + \checkinserts +} + +% Append the tokens #2 to the definition of macro #1, not expanding either. +% +\def\appendtomacro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +} + +% @caption, @shortcaption +% +\def\caption{\docaption\thiscaption} +\def\shortcaption{\docaption\thisshortcaption} +\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} +\def\defcaption#1#2{\egroup \def#1{#2}} + +% The parameter is the control sequence identifying the counter we are +% going to use. Create it if it doesn't exist and assign it to \floatno. +\def\getfloatno#1{% + \ifx#1\relax + % Haven't seen this figure type before. + \csname newcount\endcsname #1% + % + % Remember to reset this floatno at the next chap. + \expandafter\gdef\expandafter\resetallfloatnos + \expandafter{\resetallfloatnos #1=0 }% + \fi + \let\floatno#1% +} + +% \setref calls this to get the XREFLABEL-snt value. We want an @xref +% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we +% first read the @float command. +% +\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% + +% Magic string used for the XREFLABEL-title value, so \xrefX can +% distinguish floats from other xref types. +\def\floatmagic{!!float!!} + +% #1 is the control sequence we are passed; we expand into a conditional +% which is true if #1 represents a float ref. That is, the magic +% \lastsection value which we \setref above. +% +\def\iffloat#1{\expandafter\doiffloat#1==\finish} +% +% #1 is (maybe) the \floatmagic string. If so, #2 will be the +% (safe) float type for this float. We set \iffloattype to #2. +% +\def\doiffloat#1=#2=#3\finish{% + \def\temp{#1}% + \def\iffloattype{#2}% + \ifx\temp\floatmagic +} + +% @listoffloats FLOATTYPE - print a list of floats like a table of contents. +% +\parseargdef\listoffloats{% + \def\floattype{#1}% floattype + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + % + % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. + \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax + \ifhavexrefs + % if the user said @listoffloats foo but never @float foo. + \message{\linenumber No `\safefloattype' floats to list.}% + \fi + \else + \begingroup + \leftskip=\tocindent % indent these entries like a toc + \let\do=\listoffloatsdo + \csname floatlist\safefloattype\endcsname + \endgroup + \fi +} + +% This is called on each entry in a list of floats. We're passed the +% xref label, in the form LABEL-title, which is how we save it in the +% aux file. We strip off the -title and look up \XRLABEL-lof, which +% has the text we're supposed to typeset here. +% +% Figures without xref labels will not be included in the list (since +% they won't appear in the aux file). +% +\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} +\def\listoffloatsdoentry#1-title\finish{{% + % Can't fully expand XR#1-lof because it can contain anything. Just + % pass the control sequence. On the other hand, XR#1-pg is just the + % page number, and we want to fully expand that so we can get a link + % in pdf output. + \toksA = \expandafter{\csname XR#1-lof\endcsname}% + % + % use the same \entry macro we use to generate the TOC and index. + \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% + \writeentry +}} + + +\message{localization,} + +% For single-language documents, @documentlanguage is usually given very +% early, just after @documentencoding. Single argument is the language +% (de) or locale (de_DE) abbreviation. +% +{ + \catcode`\_ = \active + \globaldefs=1 +\parseargdef\documentlanguage{% + \tex % read txi-??.tex file in plain TeX. + % Read the file by the name they passed if it exists. + \let_ = \normalunderscore % normal _ character for filename test + \openin 1 txi-#1.tex + \ifeof 1 + \documentlanguagetrywithoutunderscore #1_\finish + \else + \globaldefs = 1 % everything in the txi-LL files needs to persist + \input txi-#1.tex + \fi + \closein 1 + \endgroup % end raw TeX +} +% +% If they passed de_DE, and txi-de_DE.tex doesn't exist, +% try txi-de.tex. +% +\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% + \openin 1 txi-#1.tex + \ifeof 1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \else + \globaldefs = 1 % everything in the txi-LL files needs to persist + \input txi-#1.tex + \fi + \closein 1 +} +}% end of special _ catcode +% +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? Putting it in the current +directory should work if nowhere else does.} + +% This macro is called from txi-??.tex files; the first argument is the +% \language name to set (without the "\lang@" prefix), the second and +% third args are \{left,right}hyphenmin. +% +% The language names to pass are determined when the format is built. +% See the etex.log file created at that time, e.g., +% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. +% +% With TeX Live 2008, etex now includes hyphenation patterns for all +% available languages. This means we can support hyphenation in +% Texinfo, at least to some extent. (This still doesn't solve the +% accented characters problem.) +% +\catcode`@=11 +\def\txisetlanguage#1#2#3{% + % do not set the language if the name is undefined in the current TeX. + \expandafter\ifx\csname lang@#1\endcsname \relax + \message{no patterns for #1}% + \else + \global\language = \csname lang@#1\endcsname + \fi + % but there is no harm in adjusting the hyphenmin values regardless. + \global\lefthyphenmin = #2\relax + \global\righthyphenmin = #3\relax +} + +% Get input by bytes instead of by UTF-8 codepoints for XeTeX and LuaTeX, +% otherwise the encoding support is completely broken. +\ifx\XeTeXrevision\thisisundefined +\else +\XeTeXdefaultencoding "bytes" % For subsequent files to be read +\XeTeXinputencoding "bytes" % Effective in texinfo.tex only +% Unfortunately, there seems to be no corresponding XeTeX command for +% output encoding. This is a problem for auxiliary index and TOC files. +% The only solution would be perhaps to write out @U{...} sequences in +% place of UTF-8 characters. +\fi + +\ifx\luatexversion\thisisundefined +\else +\directlua{ +local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub +local function convert_char (char) + return utf8_char(byte(char)) +end + +local function convert_line (line) + return gsub(line, ".", convert_char) +end + +callback.register("process_input_buffer", convert_line) + +local function convert_line_out (line) + local line_out = "" + for c in string.utfvalues(line) do + line_out = line_out .. string.char(c) + end + return line_out +end + +callback.register("process_output_buffer", convert_line_out) +} +\fi + + +% Helpers for encodings. +% Set the catcode of characters 128 through 255 to the specified number. +% +\def\setnonasciicharscatcode#1{% + \count255=128 + \loop\ifnum\count255<256 + \global\catcode\count255=#1\relax + \advance\count255 by 1 + \repeat +} + +\def\setnonasciicharscatcodenonglobal#1{% + \count255=128 + \loop\ifnum\count255<256 + \catcode\count255=#1\relax + \advance\count255 by 1 + \repeat +} + +% @documentencoding sets the definition of non-ASCII characters +% according to the specified encoding. +% +\def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz} +\def\documentencodingzzz#1{% + % Get input by bytes instead of by UTF-8 codepoints for XeTeX, + % otherwise the encoding support is completely broken. + % This settings is for the document root file. + \ifx\XeTeXrevision\thisisundefined + \else + \XeTeXinputencoding "bytes" + \fi + % + % Encoding being declared for the document. + \def\declaredencoding{\csname #1.enc\endcsname}% + % + % Supported encodings: names converted to tokens in order to be able + % to compare them with \ifx. + \def\ascii{\csname US-ASCII.enc\endcsname}% + \def\latnine{\csname ISO-8859-15.enc\endcsname}% + \def\latone{\csname ISO-8859-1.enc\endcsname}% + \def\lattwo{\csname ISO-8859-2.enc\endcsname}% + \def\utfeight{\csname UTF-8.enc\endcsname}% + % + \ifx \declaredencoding \ascii + \asciichardefs + % + \else \ifx \declaredencoding \lattwo + \setnonasciicharscatcode\active + \lattwochardefs + % + \else \ifx \declaredencoding \latone + \setnonasciicharscatcode\active + \latonechardefs + % + \else \ifx \declaredencoding \latnine + \setnonasciicharscatcode\active + \latninechardefs + % + \else \ifx \declaredencoding \utfeight + \setnonasciicharscatcode\active + % since we already invoked \utfeightchardefs at the top level + % (below), do not re-invoke it, then our check for duplicated + % definitions triggers. Making non-ascii chars active is enough. + % + \else + \message{Ignoring unknown document encoding: #1.}% + % + \fi % utfeight + \fi % latnine + \fi % latone + \fi % lattwo + \fi % ascii +} + +% emacs-page +% A message to be logged when using a character that isn't available +% the default font encoding (OT1). +% +\def\missingcharmsg#1{\message{Character missing, sorry: #1.}} + +% Take account of \c (plain) vs. \, (Texinfo) difference. +\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} + +% First, make active non-ASCII characters in order for them to be +% correctly categorized when TeX reads the replacement text of +% macros containing the character definitions. +\setnonasciicharscatcode\active +% +% Latin1 (ISO-8859-1) character definitions. +\def\latonechardefs{% + \gdef^^a0{\tie} + \gdef^^a1{\exclamdown} + \gdef^^a2{{\tcfont \char162}} % cent + \gdef^^a3{\pounds} + \gdef^^a4{{\tcfont \char164}} % currency + \gdef^^a5{{\tcfont \char165}} % yen + \gdef^^a6{{\tcfont \char166}} % broken bar + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\copyright} + \gdef^^aa{\ordf} + \gdef^^ab{\guillemetleft} + \gdef^^ac{\ensuremath\lnot} + \gdef^^ad{\-} + \gdef^^ae{\registeredsymbol} + \gdef^^af{\={}} + % + \gdef^^b0{\textdegree} + \gdef^^b1{$\pm$} + \gdef^^b2{$^2$} + \gdef^^b3{$^3$} + \gdef^^b4{\'{}} + \gdef^^b5{$\mu$} + \gdef^^b6{\P} + \gdef^^b7{\ensuremath\cdot} + \gdef^^b8{\cedilla\ } + \gdef^^b9{$^1$} + \gdef^^ba{\ordm} + \gdef^^bb{\guillemetright} + \gdef^^bc{$1\over4$} + \gdef^^bd{$1\over2$} + \gdef^^be{$3\over4$} + \gdef^^bf{\questiondown} + % + \gdef^^c0{\`A} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\~A} + \gdef^^c4{\"A} + \gdef^^c5{\ringaccent A} + \gdef^^c6{\AE} + \gdef^^c7{\cedilla C} + \gdef^^c8{\`E} + \gdef^^c9{\'E} + \gdef^^ca{\^E} + \gdef^^cb{\"E} + \gdef^^cc{\`I} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\"I} + % + \gdef^^d0{\DH} + \gdef^^d1{\~N} + \gdef^^d2{\`O} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\~O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\O} + \gdef^^d9{\`U} + \gdef^^da{\'U} + \gdef^^db{\^U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\TH} + \gdef^^df{\ss} + % + \gdef^^e0{\`a} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\~a} + \gdef^^e4{\"a} + \gdef^^e5{\ringaccent a} + \gdef^^e6{\ae} + \gdef^^e7{\cedilla c} + \gdef^^e8{\`e} + \gdef^^e9{\'e} + \gdef^^ea{\^e} + \gdef^^eb{\"e} + \gdef^^ec{\`{\dotless i}} + \gdef^^ed{\'{\dotless i}} + \gdef^^ee{\^{\dotless i}} + \gdef^^ef{\"{\dotless i}} + % + \gdef^^f0{\dh} + \gdef^^f1{\~n} + \gdef^^f2{\`o} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\~o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\o} + \gdef^^f9{\`u} + \gdef^^fa{\'u} + \gdef^^fb{\^u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\th} + \gdef^^ff{\"y} +} + +% Latin9 (ISO-8859-15) encoding character definitions. +\def\latninechardefs{% + % Encoding is almost identical to Latin1. + \latonechardefs + % + \gdef^^a4{\euro} + \gdef^^a6{\v S} + \gdef^^a8{\v s} + \gdef^^b4{\v Z} + \gdef^^b8{\v z} + \gdef^^bc{\OE} + \gdef^^bd{\oe} + \gdef^^be{\"Y} +} + +% Latin2 (ISO-8859-2) character definitions. +\def\lattwochardefs{% + \gdef^^a0{\tie} + \gdef^^a1{\ogonek{A}} + \gdef^^a2{\u{}} + \gdef^^a3{\L} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\v L} + \gdef^^a6{\'S} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\v S} + \gdef^^aa{\cedilla S} + \gdef^^ab{\v T} + \gdef^^ac{\'Z} + \gdef^^ad{\-} + \gdef^^ae{\v Z} + \gdef^^af{\dotaccent Z} + % + \gdef^^b0{\textdegree} + \gdef^^b1{\ogonek{a}} + \gdef^^b2{\ogonek{ }} + \gdef^^b3{\l} + \gdef^^b4{\'{}} + \gdef^^b5{\v l} + \gdef^^b6{\'s} + \gdef^^b7{\v{}} + \gdef^^b8{\cedilla\ } + \gdef^^b9{\v s} + \gdef^^ba{\cedilla s} + \gdef^^bb{\v t} + \gdef^^bc{\'z} + \gdef^^bd{\H{}} + \gdef^^be{\v z} + \gdef^^bf{\dotaccent z} + % + \gdef^^c0{\'R} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\u A} + \gdef^^c4{\"A} + \gdef^^c5{\'L} + \gdef^^c6{\'C} + \gdef^^c7{\cedilla C} + \gdef^^c8{\v C} + \gdef^^c9{\'E} + \gdef^^ca{\ogonek{E}} + \gdef^^cb{\"E} + \gdef^^cc{\v E} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\v D} + % + \gdef^^d0{\DH} + \gdef^^d1{\'N} + \gdef^^d2{\v N} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\H O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\v R} + \gdef^^d9{\ringaccent U} + \gdef^^da{\'U} + \gdef^^db{\H U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\cedilla T} + \gdef^^df{\ss} + % + \gdef^^e0{\'r} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\u a} + \gdef^^e4{\"a} + \gdef^^e5{\'l} + \gdef^^e6{\'c} + \gdef^^e7{\cedilla c} + \gdef^^e8{\v c} + \gdef^^e9{\'e} + \gdef^^ea{\ogonek{e}} + \gdef^^eb{\"e} + \gdef^^ec{\v e} + \gdef^^ed{\'{\dotless{i}}} + \gdef^^ee{\^{\dotless{i}}} + \gdef^^ef{\v d} + % + \gdef^^f0{\dh} + \gdef^^f1{\'n} + \gdef^^f2{\v n} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\H o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\v r} + \gdef^^f9{\ringaccent u} + \gdef^^fa{\'u} + \gdef^^fb{\H u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\cedilla t} + \gdef^^ff{\dotaccent{}} +} + +% UTF-8 character definitions. +% +% This code to support UTF-8 is based on LaTeX's utf8.def, with some +% changes for Texinfo conventions. It is included here under the GPL by +% permission from Frank Mittelbach and the LaTeX team. +% +\newcount\countUTFx +\newcount\countUTFy +\newcount\countUTFz + +\gdef\UTFviiiTwoOctets#1#2{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\endcsname} +% +\gdef\UTFviiiThreeOctets#1#2#3{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} +% +\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} + +\gdef\UTFviiiDefined#1{% + \ifx #1\relax + \message{\linenumber Unicode char \string #1 not defined for Texinfo}% + \else + \expandafter #1% + \fi +} + +\begingroup + \catcode`\~13 + \catcode`\"12 + + \def\UTFviiiLoop{% + \global\catcode\countUTFx\active + \uccode`\~\countUTFx + \uppercase\expandafter{\UTFviiiTmp}% + \advance\countUTFx by 1 + \ifnum\countUTFx < \countUTFy + \expandafter\UTFviiiLoop + \fi} + + \countUTFx = "C2 + \countUTFy = "E0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiTwoOctets\string~}} + \UTFviiiLoop + + \countUTFx = "E0 + \countUTFy = "F0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiThreeOctets\string~}} + \UTFviiiLoop + + \countUTFx = "F0 + \countUTFy = "F4 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiFourOctets\string~}} + \UTFviiiLoop +\endgroup + +\def\globallet{\global\let} % save some \expandafter's below + +% @U{xxxx} to produce U+xxxx, if we support it. +\def\U#1{% + \expandafter\ifx\csname uni:#1\endcsname \relax + \errhelp = \EMsimple + \errmessage{Unicode character U+#1 not supported, sorry}% + \else + \csname uni:#1\endcsname + \fi +} + +\begingroup + \catcode`\"=12 + \catcode`\<=12 + \catcode`\.=12 + \catcode`\,=12 + \catcode`\;=12 + \catcode`\!=12 + \catcode`\~=13 + \gdef\DeclareUnicodeCharacter#1#2{% + \countUTFz = "#1\relax + %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% + \begingroup + \parseXMLCharref + \def\UTFviiiTwoOctets##1##2{% + \csname u8:##1\string ##2\endcsname}% + \def\UTFviiiThreeOctets##1##2##3{% + \csname u8:##1\string ##2\string ##3\endcsname}% + \def\UTFviiiFourOctets##1##2##3##4{% + \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \gdef\UTFviiiTmp{#2}% + % + \expandafter\ifx\csname uni:#1\endcsname \relax \else + \message{Internal error, already defined: #1}% + \fi + % + % define an additional control sequence for this code point. + \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp + \endgroup} + + \gdef\parseXMLCharref{% + \ifnum\countUTFz < "A0\relax + \errhelp = \EMsimple + \errmessage{Cannot define Unicode char value < 00A0}% + \else\ifnum\countUTFz < "800\relax + \parseUTFviiiA,% + \parseUTFviiiB C\UTFviiiTwoOctets.,% + \else\ifnum\countUTFz < "10000\relax + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% + \else + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiA!% + \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% + \fi\fi\fi + } + + \gdef\parseUTFviiiA#1{% + \countUTFx = \countUTFz + \divide\countUTFz by 64 + \countUTFy = \countUTFz + \multiply\countUTFz by 64 + \advance\countUTFx by -\countUTFz + \advance\countUTFx by 128 + \uccode `#1\countUTFx + \countUTFz = \countUTFy} + + \gdef\parseUTFviiiB#1#2#3#4{% + \advance\countUTFz by "#10\relax + \uccode `#3\countUTFz + \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} +\endgroup + +% https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M +% U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block) +% U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block) +% U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A +% U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B +% +% Many of our renditions are less than wonderful, and all the missing +% characters are available somewhere. Loading the necessary fonts +% awaits user request. We can't truly support Unicode without +% reimplementing everything that's been done in LaTeX for many years, +% plus probably using luatex or xetex, and who knows what else. +% We won't be doing that here in this simple file. But we can try to at +% least make most of the characters not bomb out. +% +\def\utfeightchardefs{% + \DeclareUnicodeCharacter{00A0}{\tie} + \DeclareUnicodeCharacter{00A1}{\exclamdown} + \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent + \DeclareUnicodeCharacter{00A3}{\pounds} + \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency + \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen + \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar + \DeclareUnicodeCharacter{00A7}{\S} + \DeclareUnicodeCharacter{00A8}{\"{ }} + \DeclareUnicodeCharacter{00A9}{\copyright} + \DeclareUnicodeCharacter{00AA}{\ordf} + \DeclareUnicodeCharacter{00AB}{\guillemetleft} + \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot} + \DeclareUnicodeCharacter{00AD}{\-} + \DeclareUnicodeCharacter{00AE}{\registeredsymbol} + \DeclareUnicodeCharacter{00AF}{\={ }} + % + \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} + \DeclareUnicodeCharacter{00B1}{\ensuremath\pm} + \DeclareUnicodeCharacter{00B2}{$^2$} + \DeclareUnicodeCharacter{00B3}{$^3$} + \DeclareUnicodeCharacter{00B4}{\'{ }} + \DeclareUnicodeCharacter{00B5}{$\mu$} + \DeclareUnicodeCharacter{00B6}{\P} + \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot} + \DeclareUnicodeCharacter{00B8}{\cedilla{ }} + \DeclareUnicodeCharacter{00B9}{$^1$} + \DeclareUnicodeCharacter{00BA}{\ordm} + \DeclareUnicodeCharacter{00BB}{\guillemetright} + \DeclareUnicodeCharacter{00BC}{$1\over4$} + \DeclareUnicodeCharacter{00BD}{$1\over2$} + \DeclareUnicodeCharacter{00BE}{$3\over4$} + \DeclareUnicodeCharacter{00BF}{\questiondown} + % + \DeclareUnicodeCharacter{00C0}{\`A} + \DeclareUnicodeCharacter{00C1}{\'A} + \DeclareUnicodeCharacter{00C2}{\^A} + \DeclareUnicodeCharacter{00C3}{\~A} + \DeclareUnicodeCharacter{00C4}{\"A} + \DeclareUnicodeCharacter{00C5}{\AA} + \DeclareUnicodeCharacter{00C6}{\AE} + \DeclareUnicodeCharacter{00C7}{\cedilla{C}} + \DeclareUnicodeCharacter{00C8}{\`E} + \DeclareUnicodeCharacter{00C9}{\'E} + \DeclareUnicodeCharacter{00CA}{\^E} + \DeclareUnicodeCharacter{00CB}{\"E} + \DeclareUnicodeCharacter{00CC}{\`I} + \DeclareUnicodeCharacter{00CD}{\'I} + \DeclareUnicodeCharacter{00CE}{\^I} + \DeclareUnicodeCharacter{00CF}{\"I} + % + \DeclareUnicodeCharacter{00D0}{\DH} + \DeclareUnicodeCharacter{00D1}{\~N} + \DeclareUnicodeCharacter{00D2}{\`O} + \DeclareUnicodeCharacter{00D3}{\'O} + \DeclareUnicodeCharacter{00D4}{\^O} + \DeclareUnicodeCharacter{00D5}{\~O} + \DeclareUnicodeCharacter{00D6}{\"O} + \DeclareUnicodeCharacter{00D7}{\ensuremath\times} + \DeclareUnicodeCharacter{00D8}{\O} + \DeclareUnicodeCharacter{00D9}{\`U} + \DeclareUnicodeCharacter{00DA}{\'U} + \DeclareUnicodeCharacter{00DB}{\^U} + \DeclareUnicodeCharacter{00DC}{\"U} + \DeclareUnicodeCharacter{00DD}{\'Y} + \DeclareUnicodeCharacter{00DE}{\TH} + \DeclareUnicodeCharacter{00DF}{\ss} + % + \DeclareUnicodeCharacter{00E0}{\`a} + \DeclareUnicodeCharacter{00E1}{\'a} + \DeclareUnicodeCharacter{00E2}{\^a} + \DeclareUnicodeCharacter{00E3}{\~a} + \DeclareUnicodeCharacter{00E4}{\"a} + \DeclareUnicodeCharacter{00E5}{\aa} + \DeclareUnicodeCharacter{00E6}{\ae} + \DeclareUnicodeCharacter{00E7}{\cedilla{c}} + \DeclareUnicodeCharacter{00E8}{\`e} + \DeclareUnicodeCharacter{00E9}{\'e} + \DeclareUnicodeCharacter{00EA}{\^e} + \DeclareUnicodeCharacter{00EB}{\"e} + \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} + \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} + \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} + \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} + % + \DeclareUnicodeCharacter{00F0}{\dh} + \DeclareUnicodeCharacter{00F1}{\~n} + \DeclareUnicodeCharacter{00F2}{\`o} + \DeclareUnicodeCharacter{00F3}{\'o} + \DeclareUnicodeCharacter{00F4}{\^o} + \DeclareUnicodeCharacter{00F5}{\~o} + \DeclareUnicodeCharacter{00F6}{\"o} + \DeclareUnicodeCharacter{00F7}{\ensuremath\div} + \DeclareUnicodeCharacter{00F8}{\o} + \DeclareUnicodeCharacter{00F9}{\`u} + \DeclareUnicodeCharacter{00FA}{\'u} + \DeclareUnicodeCharacter{00FB}{\^u} + \DeclareUnicodeCharacter{00FC}{\"u} + \DeclareUnicodeCharacter{00FD}{\'y} + \DeclareUnicodeCharacter{00FE}{\th} + \DeclareUnicodeCharacter{00FF}{\"y} + % + \DeclareUnicodeCharacter{0100}{\=A} + \DeclareUnicodeCharacter{0101}{\=a} + \DeclareUnicodeCharacter{0102}{\u{A}} + \DeclareUnicodeCharacter{0103}{\u{a}} + \DeclareUnicodeCharacter{0104}{\ogonek{A}} + \DeclareUnicodeCharacter{0105}{\ogonek{a}} + \DeclareUnicodeCharacter{0106}{\'C} + \DeclareUnicodeCharacter{0107}{\'c} + \DeclareUnicodeCharacter{0108}{\^C} + \DeclareUnicodeCharacter{0109}{\^c} + \DeclareUnicodeCharacter{010A}{\dotaccent{C}} + \DeclareUnicodeCharacter{010B}{\dotaccent{c}} + \DeclareUnicodeCharacter{010C}{\v{C}} + \DeclareUnicodeCharacter{010D}{\v{c}} + \DeclareUnicodeCharacter{010E}{\v{D}} + \DeclareUnicodeCharacter{010F}{d'} + % + \DeclareUnicodeCharacter{0110}{\DH} + \DeclareUnicodeCharacter{0111}{\dh} + \DeclareUnicodeCharacter{0112}{\=E} + \DeclareUnicodeCharacter{0113}{\=e} + \DeclareUnicodeCharacter{0114}{\u{E}} + \DeclareUnicodeCharacter{0115}{\u{e}} + \DeclareUnicodeCharacter{0116}{\dotaccent{E}} + \DeclareUnicodeCharacter{0117}{\dotaccent{e}} + \DeclareUnicodeCharacter{0118}{\ogonek{E}} + \DeclareUnicodeCharacter{0119}{\ogonek{e}} + \DeclareUnicodeCharacter{011A}{\v{E}} + \DeclareUnicodeCharacter{011B}{\v{e}} + \DeclareUnicodeCharacter{011C}{\^G} + \DeclareUnicodeCharacter{011D}{\^g} + \DeclareUnicodeCharacter{011E}{\u{G}} + \DeclareUnicodeCharacter{011F}{\u{g}} + % + \DeclareUnicodeCharacter{0120}{\dotaccent{G}} + \DeclareUnicodeCharacter{0121}{\dotaccent{g}} + \DeclareUnicodeCharacter{0122}{\cedilla{G}} + \DeclareUnicodeCharacter{0123}{\cedilla{g}} + \DeclareUnicodeCharacter{0124}{\^H} + \DeclareUnicodeCharacter{0125}{\^h} + \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}} + \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}} + \DeclareUnicodeCharacter{0128}{\~I} + \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} + \DeclareUnicodeCharacter{012A}{\=I} + \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} + \DeclareUnicodeCharacter{012C}{\u{I}} + \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} + \DeclareUnicodeCharacter{012E}{\ogonek{I}} + \DeclareUnicodeCharacter{012F}{\ogonek{i}} + % + \DeclareUnicodeCharacter{0130}{\dotaccent{I}} + \DeclareUnicodeCharacter{0131}{\dotless{i}} + \DeclareUnicodeCharacter{0132}{IJ} + \DeclareUnicodeCharacter{0133}{ij} + \DeclareUnicodeCharacter{0134}{\^J} + \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} + \DeclareUnicodeCharacter{0136}{\cedilla{K}} + \DeclareUnicodeCharacter{0137}{\cedilla{k}} + \DeclareUnicodeCharacter{0138}{\ensuremath\kappa} + \DeclareUnicodeCharacter{0139}{\'L} + \DeclareUnicodeCharacter{013A}{\'l} + \DeclareUnicodeCharacter{013B}{\cedilla{L}} + \DeclareUnicodeCharacter{013C}{\cedilla{l}} + \DeclareUnicodeCharacter{013D}{L'}% should kern + \DeclareUnicodeCharacter{013E}{l'}% should kern + \DeclareUnicodeCharacter{013F}{L\U{00B7}} + % + \DeclareUnicodeCharacter{0140}{l\U{00B7}} + \DeclareUnicodeCharacter{0141}{\L} + \DeclareUnicodeCharacter{0142}{\l} + \DeclareUnicodeCharacter{0143}{\'N} + \DeclareUnicodeCharacter{0144}{\'n} + \DeclareUnicodeCharacter{0145}{\cedilla{N}} + \DeclareUnicodeCharacter{0146}{\cedilla{n}} + \DeclareUnicodeCharacter{0147}{\v{N}} + \DeclareUnicodeCharacter{0148}{\v{n}} + \DeclareUnicodeCharacter{0149}{'n} + \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}} + \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}} + \DeclareUnicodeCharacter{014C}{\=O} + \DeclareUnicodeCharacter{014D}{\=o} + \DeclareUnicodeCharacter{014E}{\u{O}} + \DeclareUnicodeCharacter{014F}{\u{o}} + % + \DeclareUnicodeCharacter{0150}{\H{O}} + \DeclareUnicodeCharacter{0151}{\H{o}} + \DeclareUnicodeCharacter{0152}{\OE} + \DeclareUnicodeCharacter{0153}{\oe} + \DeclareUnicodeCharacter{0154}{\'R} + \DeclareUnicodeCharacter{0155}{\'r} + \DeclareUnicodeCharacter{0156}{\cedilla{R}} + \DeclareUnicodeCharacter{0157}{\cedilla{r}} + \DeclareUnicodeCharacter{0158}{\v{R}} + \DeclareUnicodeCharacter{0159}{\v{r}} + \DeclareUnicodeCharacter{015A}{\'S} + \DeclareUnicodeCharacter{015B}{\'s} + \DeclareUnicodeCharacter{015C}{\^S} + \DeclareUnicodeCharacter{015D}{\^s} + \DeclareUnicodeCharacter{015E}{\cedilla{S}} + \DeclareUnicodeCharacter{015F}{\cedilla{s}} + % + \DeclareUnicodeCharacter{0160}{\v{S}} + \DeclareUnicodeCharacter{0161}{\v{s}} + \DeclareUnicodeCharacter{0162}{\cedilla{T}} + \DeclareUnicodeCharacter{0163}{\cedilla{t}} + \DeclareUnicodeCharacter{0164}{\v{T}} + \DeclareUnicodeCharacter{0165}{\v{t}} + \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}} + \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}} + \DeclareUnicodeCharacter{0168}{\~U} + \DeclareUnicodeCharacter{0169}{\~u} + \DeclareUnicodeCharacter{016A}{\=U} + \DeclareUnicodeCharacter{016B}{\=u} + \DeclareUnicodeCharacter{016C}{\u{U}} + \DeclareUnicodeCharacter{016D}{\u{u}} + \DeclareUnicodeCharacter{016E}{\ringaccent{U}} + \DeclareUnicodeCharacter{016F}{\ringaccent{u}} + % + \DeclareUnicodeCharacter{0170}{\H{U}} + \DeclareUnicodeCharacter{0171}{\H{u}} + \DeclareUnicodeCharacter{0172}{\ogonek{U}} + \DeclareUnicodeCharacter{0173}{\ogonek{u}} + \DeclareUnicodeCharacter{0174}{\^W} + \DeclareUnicodeCharacter{0175}{\^w} + \DeclareUnicodeCharacter{0176}{\^Y} + \DeclareUnicodeCharacter{0177}{\^y} + \DeclareUnicodeCharacter{0178}{\"Y} + \DeclareUnicodeCharacter{0179}{\'Z} + \DeclareUnicodeCharacter{017A}{\'z} + \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} + \DeclareUnicodeCharacter{017C}{\dotaccent{z}} + \DeclareUnicodeCharacter{017D}{\v{Z}} + \DeclareUnicodeCharacter{017E}{\v{z}} + \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}} + % + \DeclareUnicodeCharacter{01C4}{D\v{Z}} + \DeclareUnicodeCharacter{01C5}{D\v{z}} + \DeclareUnicodeCharacter{01C6}{d\v{z}} + \DeclareUnicodeCharacter{01C7}{LJ} + \DeclareUnicodeCharacter{01C8}{Lj} + \DeclareUnicodeCharacter{01C9}{lj} + \DeclareUnicodeCharacter{01CA}{NJ} + \DeclareUnicodeCharacter{01CB}{Nj} + \DeclareUnicodeCharacter{01CC}{nj} + \DeclareUnicodeCharacter{01CD}{\v{A}} + \DeclareUnicodeCharacter{01CE}{\v{a}} + \DeclareUnicodeCharacter{01CF}{\v{I}} + % + \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} + \DeclareUnicodeCharacter{01D1}{\v{O}} + \DeclareUnicodeCharacter{01D2}{\v{o}} + \DeclareUnicodeCharacter{01D3}{\v{U}} + \DeclareUnicodeCharacter{01D4}{\v{u}} + % + \DeclareUnicodeCharacter{01E2}{\={\AE}} + \DeclareUnicodeCharacter{01E3}{\={\ae}} + \DeclareUnicodeCharacter{01E6}{\v{G}} + \DeclareUnicodeCharacter{01E7}{\v{g}} + \DeclareUnicodeCharacter{01E8}{\v{K}} + \DeclareUnicodeCharacter{01E9}{\v{k}} + % + \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} + \DeclareUnicodeCharacter{01F1}{DZ} + \DeclareUnicodeCharacter{01F2}{Dz} + \DeclareUnicodeCharacter{01F3}{dz} + \DeclareUnicodeCharacter{01F4}{\'G} + \DeclareUnicodeCharacter{01F5}{\'g} + \DeclareUnicodeCharacter{01F8}{\`N} + \DeclareUnicodeCharacter{01F9}{\`n} + \DeclareUnicodeCharacter{01FC}{\'{\AE}} + \DeclareUnicodeCharacter{01FD}{\'{\ae}} + \DeclareUnicodeCharacter{01FE}{\'{\O}} + \DeclareUnicodeCharacter{01FF}{\'{\o}} + % + \DeclareUnicodeCharacter{021E}{\v{H}} + \DeclareUnicodeCharacter{021F}{\v{h}} + % + \DeclareUnicodeCharacter{0226}{\dotaccent{A}} + \DeclareUnicodeCharacter{0227}{\dotaccent{a}} + \DeclareUnicodeCharacter{0228}{\cedilla{E}} + \DeclareUnicodeCharacter{0229}{\cedilla{e}} + \DeclareUnicodeCharacter{022E}{\dotaccent{O}} + \DeclareUnicodeCharacter{022F}{\dotaccent{o}} + % + \DeclareUnicodeCharacter{0232}{\=Y} + \DeclareUnicodeCharacter{0233}{\=y} + \DeclareUnicodeCharacter{0237}{\dotless{j}} + % + \DeclareUnicodeCharacter{02DB}{\ogonek{ }} + % + % Greek letters upper case + \DeclareUnicodeCharacter{0391}{{\it A}} + \DeclareUnicodeCharacter{0392}{{\it B}} + \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}} + \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}} + \DeclareUnicodeCharacter{0395}{{\it E}} + \DeclareUnicodeCharacter{0396}{{\it Z}} + \DeclareUnicodeCharacter{0397}{{\it H}} + \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}} + \DeclareUnicodeCharacter{0399}{{\it I}} + \DeclareUnicodeCharacter{039A}{{\it K}} + \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}} + \DeclareUnicodeCharacter{039C}{{\it M}} + \DeclareUnicodeCharacter{039D}{{\it N}} + \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}} + \DeclareUnicodeCharacter{039F}{{\it O}} + \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}} + \DeclareUnicodeCharacter{03A1}{{\it P}} + %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma + \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}} + \DeclareUnicodeCharacter{03A4}{{\it T}} + \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}} + \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}} + \DeclareUnicodeCharacter{03A7}{{\it X}} + \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}} + \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}} + % + % Vowels with accents + \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}} + \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}} + \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}} + \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}} + \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}} + \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}} + % + % Standalone accent + \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}} + % + % Greek letters lower case + \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha} + \DeclareUnicodeCharacter{03B2}{\ensuremath\beta} + \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma} + \DeclareUnicodeCharacter{03B4}{\ensuremath\delta} + \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon} + \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta} + \DeclareUnicodeCharacter{03B7}{\ensuremath\eta} + \DeclareUnicodeCharacter{03B8}{\ensuremath\theta} + \DeclareUnicodeCharacter{03B9}{\ensuremath\iota} + \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa} + \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda} + \DeclareUnicodeCharacter{03BC}{\ensuremath\mu} + \DeclareUnicodeCharacter{03BD}{\ensuremath\nu} + \DeclareUnicodeCharacter{03BE}{\ensuremath\xi} + \DeclareUnicodeCharacter{03BF}{{\it o}} % omicron + \DeclareUnicodeCharacter{03C0}{\ensuremath\pi} + \DeclareUnicodeCharacter{03C1}{\ensuremath\rho} + \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma} + \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma} + \DeclareUnicodeCharacter{03C4}{\ensuremath\tau} + \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon} + \DeclareUnicodeCharacter{03C6}{\ensuremath\phi} + \DeclareUnicodeCharacter{03C7}{\ensuremath\chi} + \DeclareUnicodeCharacter{03C8}{\ensuremath\psi} + \DeclareUnicodeCharacter{03C9}{\ensuremath\omega} + % + % More Greek vowels with accents + \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}} + \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}} + \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}} + \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}} + \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}} + % + % Variant Greek letters + \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta} + \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi} + \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho} + % + \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} + \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} + \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} + \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} + \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} + \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} + \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} + \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} + \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} + \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} + \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} + \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} + % + \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} + \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} + % + \DeclareUnicodeCharacter{1E20}{\=G} + \DeclareUnicodeCharacter{1E21}{\=g} + \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} + \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} + \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} + \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} + \DeclareUnicodeCharacter{1E26}{\"H} + \DeclareUnicodeCharacter{1E27}{\"h} + % + \DeclareUnicodeCharacter{1E30}{\'K} + \DeclareUnicodeCharacter{1E31}{\'k} + \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} + \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} + \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} + \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} + \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} + \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} + \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} + \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} + \DeclareUnicodeCharacter{1E3E}{\'M} + \DeclareUnicodeCharacter{1E3F}{\'m} + % + \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} + \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} + \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} + \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} + \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} + \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} + \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} + \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} + \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} + \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} + % + \DeclareUnicodeCharacter{1E54}{\'P} + \DeclareUnicodeCharacter{1E55}{\'p} + \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} + \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} + \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} + \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} + \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} + \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} + \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} + \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} + % + \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} + \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} + \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} + \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} + \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} + \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} + \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} + \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} + \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} + \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} + % + \DeclareUnicodeCharacter{1E7C}{\~V} + \DeclareUnicodeCharacter{1E7D}{\~v} + \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} + \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} + % + \DeclareUnicodeCharacter{1E80}{\`W} + \DeclareUnicodeCharacter{1E81}{\`w} + \DeclareUnicodeCharacter{1E82}{\'W} + \DeclareUnicodeCharacter{1E83}{\'w} + \DeclareUnicodeCharacter{1E84}{\"W} + \DeclareUnicodeCharacter{1E85}{\"w} + \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} + \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} + \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} + \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} + \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} + \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} + \DeclareUnicodeCharacter{1E8C}{\"X} + \DeclareUnicodeCharacter{1E8D}{\"x} + \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} + \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} + % + \DeclareUnicodeCharacter{1E90}{\^Z} + \DeclareUnicodeCharacter{1E91}{\^z} + \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} + \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} + \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} + \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} + \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} + \DeclareUnicodeCharacter{1E97}{\"t} + \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} + \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} + % + \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} + \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} + % + \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} + \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} + \DeclareUnicodeCharacter{1EBC}{\~E} + \DeclareUnicodeCharacter{1EBD}{\~e} + % + \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} + \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} + \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} + \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} + % + \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} + \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} + % + \DeclareUnicodeCharacter{1EF2}{\`Y} + \DeclareUnicodeCharacter{1EF3}{\`y} + \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} + % + \DeclareUnicodeCharacter{1EF8}{\~Y} + \DeclareUnicodeCharacter{1EF9}{\~y} + % + % Punctuation + \DeclareUnicodeCharacter{2013}{--} + \DeclareUnicodeCharacter{2014}{---} + \DeclareUnicodeCharacter{2018}{\quoteleft} + \DeclareUnicodeCharacter{2019}{\quoteright} + \DeclareUnicodeCharacter{201A}{\quotesinglbase} + \DeclareUnicodeCharacter{201C}{\quotedblleft} + \DeclareUnicodeCharacter{201D}{\quotedblright} + \DeclareUnicodeCharacter{201E}{\quotedblbase} + \DeclareUnicodeCharacter{2020}{\ensuremath\dagger} + \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger} + \DeclareUnicodeCharacter{2022}{\bullet} + \DeclareUnicodeCharacter{202F}{\thinspace} + \DeclareUnicodeCharacter{2026}{\dots} + \DeclareUnicodeCharacter{2039}{\guilsinglleft} + \DeclareUnicodeCharacter{203A}{\guilsinglright} + % + \DeclareUnicodeCharacter{20AC}{\euro} + % + \DeclareUnicodeCharacter{2192}{\expansion} + \DeclareUnicodeCharacter{21D2}{\result} + % + % Mathematical symbols + \DeclareUnicodeCharacter{2200}{\ensuremath\forall} + \DeclareUnicodeCharacter{2203}{\ensuremath\exists} + \DeclareUnicodeCharacter{2208}{\ensuremath\in} + \DeclareUnicodeCharacter{2212}{\minus} + \DeclareUnicodeCharacter{2217}{\ast} + \DeclareUnicodeCharacter{221E}{\ensuremath\infty} + \DeclareUnicodeCharacter{2225}{\ensuremath\parallel} + \DeclareUnicodeCharacter{2227}{\ensuremath\wedge} + \DeclareUnicodeCharacter{2229}{\ensuremath\cap} + \DeclareUnicodeCharacter{2261}{\equiv} + \DeclareUnicodeCharacter{2264}{\ensuremath\leq} + \DeclareUnicodeCharacter{2265}{\ensuremath\geq} + \DeclareUnicodeCharacter{2282}{\ensuremath\subset} + \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq} + % + \DeclareUnicodeCharacter{2016}{\ensuremath\Vert} + \DeclareUnicodeCharacter{2032}{\ensuremath\prime} + \DeclareUnicodeCharacter{210F}{\ensuremath\hbar} + \DeclareUnicodeCharacter{2111}{\ensuremath\Im} + \DeclareUnicodeCharacter{2113}{\ensuremath\ell} + \DeclareUnicodeCharacter{2118}{\ensuremath\wp} + \DeclareUnicodeCharacter{211C}{\ensuremath\Re} + \DeclareUnicodeCharacter{2127}{\ensuremath\mho} + \DeclareUnicodeCharacter{2135}{\ensuremath\aleph} + \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow} + \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow} + \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow} + \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow} + \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow} + \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow} + \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow} + \DeclareUnicodeCharacter{2198}{\ensuremath\searrow} + \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow} + \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto} + \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow} + \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow} + \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup} + \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown} + \DeclareUnicodeCharacter{21BE}{\ensuremath\upharpoonright} + \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup} + \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown} + \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons} + \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow} + \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow} + \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow} + \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow} + \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow} + \DeclareUnicodeCharacter{21DD}{\ensuremath\leadsto} + \DeclareUnicodeCharacter{2201}{\ensuremath\complement} + \DeclareUnicodeCharacter{2202}{\ensuremath\partial} + \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset} + \DeclareUnicodeCharacter{2207}{\ensuremath\nabla} + \DeclareUnicodeCharacter{2209}{\ensuremath\notin} + \DeclareUnicodeCharacter{220B}{\ensuremath\owns} + \DeclareUnicodeCharacter{220F}{\ensuremath\prod} + \DeclareUnicodeCharacter{2210}{\ensuremath\coprod} + \DeclareUnicodeCharacter{2211}{\ensuremath\sum} + \DeclareUnicodeCharacter{2213}{\ensuremath\mp} + \DeclareUnicodeCharacter{2218}{\ensuremath\circ} + \DeclareUnicodeCharacter{221A}{\ensuremath\surd} + \DeclareUnicodeCharacter{221D}{\ensuremath\propto} + \DeclareUnicodeCharacter{2220}{\ensuremath\angle} + \DeclareUnicodeCharacter{2223}{\ensuremath\mid} + \DeclareUnicodeCharacter{2228}{\ensuremath\vee} + \DeclareUnicodeCharacter{222A}{\ensuremath\cup} + \DeclareUnicodeCharacter{222B}{\ensuremath\smallint} + \DeclareUnicodeCharacter{222E}{\ensuremath\oint} + \DeclareUnicodeCharacter{223C}{\ensuremath\sim} + \DeclareUnicodeCharacter{2240}{\ensuremath\wr} + \DeclareUnicodeCharacter{2243}{\ensuremath\simeq} + \DeclareUnicodeCharacter{2245}{\ensuremath\cong} + \DeclareUnicodeCharacter{2248}{\ensuremath\approx} + \DeclareUnicodeCharacter{224D}{\ensuremath\asymp} + \DeclareUnicodeCharacter{2250}{\ensuremath\doteq} + \DeclareUnicodeCharacter{2260}{\ensuremath\neq} + \DeclareUnicodeCharacter{226A}{\ensuremath\ll} + \DeclareUnicodeCharacter{226B}{\ensuremath\gg} + \DeclareUnicodeCharacter{227A}{\ensuremath\prec} + \DeclareUnicodeCharacter{227B}{\ensuremath\succ} + \DeclareUnicodeCharacter{2283}{\ensuremath\supset} + \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq} + \DeclareUnicodeCharacter{228E}{\ensuremath\uplus} + \DeclareUnicodeCharacter{228F}{\ensuremath\sqsubset} + \DeclareUnicodeCharacter{2290}{\ensuremath\sqsupset} + \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq} + \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq} + \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap} + \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup} + \DeclareUnicodeCharacter{2295}{\ensuremath\oplus} + \DeclareUnicodeCharacter{2296}{\ensuremath\ominus} + \DeclareUnicodeCharacter{2297}{\ensuremath\otimes} + \DeclareUnicodeCharacter{2298}{\ensuremath\oslash} + \DeclareUnicodeCharacter{2299}{\ensuremath\odot} + \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash} + \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv} + \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop} + \DeclareUnicodeCharacter{22A5}{\ensuremath\bot} + \DeclareUnicodeCharacter{22A8}{\ensuremath\models} + \DeclareUnicodeCharacter{22B4}{\ensuremath\unlhd} + \DeclareUnicodeCharacter{22B5}{\ensuremath\unrhd} + \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge} + \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee} + \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap} + \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup} + \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond} + \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot} + \DeclareUnicodeCharacter{22C6}{\ensuremath\star} + \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie} + \DeclareUnicodeCharacter{2308}{\ensuremath\lceil} + \DeclareUnicodeCharacter{2309}{\ensuremath\rceil} + \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor} + \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor} + \DeclareUnicodeCharacter{2322}{\ensuremath\frown} + \DeclareUnicodeCharacter{2323}{\ensuremath\smile} + % + \DeclareUnicodeCharacter{25A1}{\ensuremath\Box} + \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle} + \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright} + \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown} + \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft} + \DeclareUnicodeCharacter{25C7}{\ensuremath\Diamond} + \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit} + \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit} + \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit} + \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit} + \DeclareUnicodeCharacter{266D}{\ensuremath\flat} + \DeclareUnicodeCharacter{266E}{\ensuremath\natural} + \DeclareUnicodeCharacter{266F}{\ensuremath\sharp} + \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc} + \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle} + \DeclareUnicodeCharacter{27C2}{\ensuremath\perp} + \DeclareUnicodeCharacter{27E8}{\ensuremath\langle} + \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow} + \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow} + \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow} + \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto} + \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus} + \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot} + \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus} + \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes} + \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus} + \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup} + \DeclareUnicodeCharacter{2A1D}{\ensuremath\Join} + \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg} + \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq} + \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq} + % + \global\mathchardef\checkmark="1370 % actually the square root sign + \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark} +}% end of \utfeightchardefs + +% US-ASCII character definitions. +\def\asciichardefs{% nothing need be done + \relax +} + +% Latin1 (ISO-8859-1) character definitions. +\def\nonasciistringdefs{% + \setnonasciicharscatcode\active + \def\defstringchar##1{\def##1{\string##1}}% + % + \defstringchar^^80\defstringchar^^81\defstringchar^^82\defstringchar^^83% + \defstringchar^^84\defstringchar^^85\defstringchar^^86\defstringchar^^87% + \defstringchar^^88\defstringchar^^89\defstringchar^^8a\defstringchar^^8b% + \defstringchar^^8c\defstringchar^^8d\defstringchar^^8e\defstringchar^^8f% + % + \defstringchar^^90\defstringchar^^91\defstringchar^^92\defstringchar^^93% + \defstringchar^^94\defstringchar^^95\defstringchar^^96\defstringchar^^97% + \defstringchar^^98\defstringchar^^99\defstringchar^^9a\defstringchar^^9b% + \defstringchar^^9c\defstringchar^^9d\defstringchar^^9e\defstringchar^^9f% + % + \defstringchar^^a0\defstringchar^^a1\defstringchar^^a2\defstringchar^^a3% + \defstringchar^^a4\defstringchar^^a5\defstringchar^^a6\defstringchar^^a7% + \defstringchar^^a8\defstringchar^^a9\defstringchar^^aa\defstringchar^^ab% + \defstringchar^^ac\defstringchar^^ad\defstringchar^^ae\defstringchar^^af% + % + \defstringchar^^b0\defstringchar^^b1\defstringchar^^b2\defstringchar^^b3% + \defstringchar^^b4\defstringchar^^b5\defstringchar^^b6\defstringchar^^b7% + \defstringchar^^b8\defstringchar^^b9\defstringchar^^ba\defstringchar^^bb% + \defstringchar^^bc\defstringchar^^bd\defstringchar^^be\defstringchar^^bf% + % + \defstringchar^^c0\defstringchar^^c1\defstringchar^^c2\defstringchar^^c3% + \defstringchar^^c4\defstringchar^^c5\defstringchar^^c6\defstringchar^^c7% + \defstringchar^^c8\defstringchar^^c9\defstringchar^^ca\defstringchar^^cb% + \defstringchar^^cc\defstringchar^^cd\defstringchar^^ce\defstringchar^^cf% + % + \defstringchar^^d0\defstringchar^^d1\defstringchar^^d2\defstringchar^^d3% + \defstringchar^^d4\defstringchar^^d5\defstringchar^^d6\defstringchar^^d7% + \defstringchar^^d8\defstringchar^^d9\defstringchar^^da\defstringchar^^db% + \defstringchar^^dc\defstringchar^^dd\defstringchar^^de\defstringchar^^df% + % + \defstringchar^^e0\defstringchar^^e1\defstringchar^^e2\defstringchar^^e3% + \defstringchar^^e4\defstringchar^^e5\defstringchar^^e6\defstringchar^^e7% + \defstringchar^^e8\defstringchar^^e9\defstringchar^^ea\defstringchar^^eb% + \defstringchar^^ec\defstringchar^^ed\defstringchar^^ee\defstringchar^^ef% + % + \defstringchar^^f0\defstringchar^^f1\defstringchar^^f2\defstringchar^^f3% + \defstringchar^^f4\defstringchar^^f5\defstringchar^^f6\defstringchar^^f7% + \defstringchar^^f8\defstringchar^^f9\defstringchar^^fa\defstringchar^^fb% + \defstringchar^^fc\defstringchar^^fd\defstringchar^^fe\defstringchar^^ff% +} + + +% define all the unicode characters we know about, for the sake of @U. +\utfeightchardefs + + +% Make non-ASCII characters printable again for compatibility with +% existing Texinfo documents that may use them, even without declaring a +% document encoding. +% +\setnonasciicharscatcode \other + + +\message{formatting,} + +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be very finicky about underfull hboxes, either. +\hbadness = 6666 + +% Following George Bush, get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; +% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; +% 7) physical page height; 8) physical page width. +% +% We also call \setleading{\textleading}, so the caller should define +% \textleading. The caller should also set \parskip. +% +\def\internalpagesizes#1#2#3#4#5#6#7#8{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \ifpdf + \pdfpageheight #7\relax + \pdfpagewidth #8\relax + % if we don't reset these, they will remain at "1 true in" of + % whatever layout pdftex was dumped with. + \pdfhorigin = 1 true in + \pdfvorigin = 1 true in + \fi + % + \setleading{\textleading} + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % If page is nothing but text, make it come out even. + \internalpagesizes{607.2pt}{6in}% that's 46 lines + {\voffset}{.25in}% + {\bindingoffset}{36pt}% + {11in}{8.5in}% +}} + +% Use @smallbook to reset parameters for 7x9.25 trim size. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.5in}{5in}% + {-.2in}{0in}% + {\bindingoffset}{16pt}% + {9.25in}{7in}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .5cm +}} + +% Use @smallerbook to reset parameters for 6x9 trim size. +% (Just testing, parameters still in flux.) +\def\smallerbook{{\globaldefs = 1 + \parskip = 1.5pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.4in}{4.8in}% + {-.2in}{-.4in}% + {0pt}{14pt}% + {9in}{6in}% + % + \lispnarrowing = 0.25in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .4cm +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % Double-side printing via postscript on Laserjet 4050 + % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. + % To change the settings for a different printer or situation, adjust + % \normaloffset until the front-side and back-side texts align. Then + % do the same for \bindingoffset. You can set these for testing in + % your texinfo source file like this: + % @tex + % \global\normaloffset = -6mm + % \global\bindingoffset = 10mm + % @end tex + \internalpagesizes{673.2pt}{160mm}% that's 51 lines + {\voffset}{\hoffset}% + {\bindingoffset}{44pt}% + {297mm}{210mm}% + % + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = 5mm +}} + +% Use @afivepaper to print on European A5 paper. +% From romildo@urano.iceb.ufop.br, 2 July 2000. +% He also recommends making @example and @lisp be small. +\def\afivepaper{{\globaldefs = 1 + \parskip = 2pt plus 1pt minus 0.1pt + \textleading = 12.5pt + % + \internalpagesizes{160mm}{120mm}% + {\voffset}{\hoffset}% + {\bindingoffset}{8pt}% + {210mm}{148mm}% + % + \lispnarrowing = 0.2in + \tolerance = 800 + \hfuzz = 1.2pt + \contentsrightmargin = 0pt + \defbodyindent = 2mm + \tableindent = 12mm +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. +\def\afourlatex{{\globaldefs = 1 + \afourpaper + \internalpagesizes{237mm}{150mm}% + {\voffset}{4.6mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + % + % Must explicitly reset to 0 because we call \afourpaper. + \globaldefs = 0 +}} + +% Use @afourwide to print on A4 paper in landscape format. +\def\afourwide{{\globaldefs = 1 + \afourpaper + \internalpagesizes{241mm}{165mm}% + {\voffset}{-2.95mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + \globaldefs = 0 +}} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\parseargdef\pagesizes{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{\textleading}% + % + \dimen0 = #1\relax + \advance\dimen0 by \voffset + % + \dimen2 = \hsize + \advance\dimen2 by \normaloffset + % + \internalpagesizes{#1}{\hsize}% + {\voffset}{\normaloffset}% + {\bindingoffset}{44pt}% + {\dimen0}{\dimen2}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +\def^^L{\par} % remove \outer, so ^L can appear in an @comment + +% DEL is a comment character, in case @c does not suffice. +\catcode`\^^? = 14 + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other \def\normaldoublequote{"} +\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix +\catcode`\+=\other \def\normalplus{+} +\catcode`\<=\other \def\normalless{<} +\catcode`\>=\other \def\normalgreater{>} +\catcode`\^=\other \def\normalcaret{^} +\catcode`\_=\other \def\normalunderscore{_} +\catcode`\|=\other \def\normalverticalbar{|} +\catcode`\~=\other \def\normaltilde{~} + +% This macro is used to make a character print one way in \tt +% (where it can probably be output as-is), and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Set catcodes for Texinfo file + +% Active characters for printing the wanted glyph. +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. +% +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active \def\activetilde{{\tt\char126}} \let~ = \activetilde +\chardef\hatchar=`\^ +\catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } +\let\realunder=_ + +\catcode`\|=\active \def|{{\tt\char124}} + +\chardef \less=`\< +\catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless +\chardef \gtr=`\> +\catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr +\catcode`\+=\active \def+{{\tt \char 43}} +\catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix +\catcode`\-=\active \let-=\normaldash + + +% used for headline/footline in the output routine, in case the page +% breaks in the middle of an @tex block. +\def\texinfochars{% + \let< = \activeless + \let> = \activegtr + \let~ = \activetilde + \let^ = \activehat + \markupsetuplqdefault \markupsetuprqdefault + \let\b = \strong + \let\i = \smartitalic + % in principle, all other definitions in \tex have to be undone too. +} + +% Used sometimes to turn off (effectively) the active characters even after +% parsing them. +\def\turnoffactive{% + \normalturnoffactive + \otherbackslash +} + +\catcode`\@=0 + +% \backslashcurfont outputs one backslash character in current font, +% as in \char`\\. +\global\chardef\backslashcurfont=`\\ +\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work + +% \realbackslash is an actual character `\' with catcode other, and +% \doublebackslash is two of them (for the pdf outlines). +{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} + +% In Texinfo, backslash is an active character; it prints the backslash +% in fixed width font. +\catcode`\\=\active % @ for escape char from now on. + +% Print a typewriter backslash. For math mode, we can't simply use +% \backslashcurfont: the story here is that in math mode, the \char +% of \backslashcurfont ends up printing the roman \ from the math symbol +% font (because \char in math mode uses the \mathcode, and plain.tex +% sets \mathcode`\\="026E). Hence we use an explicit \mathchar, +% which is the decimal equivalent of "715c (class 7, e.g., use \fam; +% ignored family value; char position "5C). We can't use " for the +% usual hex value because it has already been made active. + +@def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} +@let@backslashchar = @ttbackslash % @backslashchar{} is for user documents. + +% \rawbackslash defines an active \ to do \backslashcurfont. +% \otherbackslash defines an active \ to be a literal `\' character with +% catcode other. We switch back and forth between these. +@gdef@rawbackslash{@let\=@backslashcurfont} +@gdef@otherbackslash{@let\=@realbackslash} + +% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of +% the literal character `\'. +% +{@catcode`- = @active + @gdef@normalturnoffactive{% + @nonasciistringdefs + @let-=@normaldash + @let"=@normaldoublequote + @let$=@normaldollar %$ font-lock fix + @let+=@normalplus + @let<=@normalless + @let>=@normalgreater + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let~=@normaltilde + @let\=@ttbackslash + @markupsetuplqdefault + @markupsetuprqdefault + @unsepspaces + } +} + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have @fixbackslash turn them back on. +@catcode`+=@other @catcode`@_=@other + +% \enablebackslashhack - allow file to begin `\input texinfo' +% +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% If the file did not have a `\input texinfo', then it is turned off after +% the first line; otherwise the first `\' in the file would cause an error. +% This is used on the very last line of this file, texinfo.tex. +% We also use @c to call @fixbackslash, in case ends of lines are hidden. +{ +@catcode`@^=7 +@catcode`@^^M=13@gdef@enablebackslashhack{% + @global@let\ = @eatinput% + @catcode`@^^M=13% + @def@c{@fixbackslash@c}% + @def ^^M{@let^^M@secondlinenl}% + @gdef @secondlinenl{@let^^M@thirdlinenl}% + @gdef @thirdlinenl{@fixbackslash}% +}} + +{@catcode`@^=7 @catcode`@^^M=13% +@gdef@eatinput input texinfo#1^^M{@fixbackslash}} + +% Emergency active definition of newline, in case an active newline token +% appears by mistake. +{@catcode`@^=7 @catcode13=13% +@gdef@enableemergencynewline{% + @gdef^^M{% + @par% + %@par% +}}} + + +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @ttbackslash @fi + @catcode13=5 % regular end of line + @enableemergencynewline + @let@c=@texinfoc + % Also turn back on active characters that might appear in the input + % file name, in case not using a pre-dumped format. + @catcode`+=@active + @catcode`@_=@active + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. This macro, @fixbackslash, gets + % called at the beginning of every Texinfo file. Not opening texinfo.cnf + % directly in this file, texinfo.tex, makes it possible to make a format + % file for Texinfo. + % + @openin 1 texinfo.cnf + @ifeof 1 @else @input texinfo.cnf @fi + @closein 1 +} + + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These (along with & and #) are made active for url-breaking, so need +% active definitions as the normal characters. +@def@normaldot{.} +@def@normalquest{?} +@def@normalslash{/} + +% These look ok in all fonts, so just make them not special. +% @hashchar{} gets its own user-level command, because of #line. +@catcode`@& = @other @def@normalamp{&} +@catcode`@# = @other @def@normalhash{#} +@catcode`@% = @other @def@normalpercent{%} + +@let @hashchar = @normalhash + +@c Finally, make ` and ' active, so that txicodequoteundirected and +@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we +@c don't make ` and ' active, @code will not get them as active chars. +@c Do this last of all since we use ` in the previous @catcode assignments. +@catcode`@'=@active +@catcode`@`=@active +@markupsetuplqdefault +@markupsetuprqdefault + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message\\|emacs-page" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: + +@c vim:sw=2: + +@ignore + arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 +@end ignore +@enablebackslashhack From f8113a2b10a97ba0d5e915b318cebea283d03169 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 16 Feb 2016 11:28:35 +0000 Subject: [PATCH 0985/1342] doc: older versions of texinfo seem to be sensitive to location of unmacro * bgpd.texi: The unmacro of mprec seems to be disliked by older texinfos. Moving it to after the section fixes it. Even easier, just don't undef the macro. --- doc/bgpd.texi | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index c02e9f5a5..5735111d0 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -302,9 +302,6 @@ which case the set has a partial order. Otherwise, if there is an order, all the objects have a distinct place in the order and the set has a total order.}) and that A would be preferred to C. -@c No longer need the precedes character definition -@unmacro mprec - However, when MED is involved this need not be the case. With MED it is possible that C is actually preferred over A. So A is preferred to B, B is preferred to C, but C is preferred to A. This can be true even where BGP From f9f4731245eb9f83d0795acac24183c6cf709288 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 16 Feb 2016 11:30:33 +0000 Subject: [PATCH 0986/1342] configure: Fix warnings on CentOS and bump the minimum autoconf version * configure.ac: Bump the minimum version to 2.60 as needed by AC_USE_SYSTEM_EXTENSIONS. AC 2.60 is nearly 10 years old, note. Add AC_PROG_RANLIB, for when --disable-shared is used. There are other warnings on, e.g., CentOS 6.7 with 2.63, but they don't go away if the suggestion to add AC_SYSTEM_EXTENSIONS is followed. This warning doesn't occur on Fedora with AC 2.69. Note: autoconf (and other auto*) should only be needed on developer machines building direct from git. Other systems should be using the 'make dist' tarballs, with a ready-made build system, that does not need auto* intalled. --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c6844147a..0fc9c099f 100755 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ ## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro ## Portions Copyright (c) 2003 Paul Jakma ## -AC_PREREQ(2.53) +AC_PREREQ(2.60) AC_INIT(Quagga, 0.99.25, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" @@ -70,6 +70,7 @@ AC_LANG([C]) AC_PROG_CC AC_PROG_CPP AM_PROG_CC_C_O +AC_PROG_RANLIB AC_PROG_EGREP dnl autoconf 2.59 appears not to support AC_PROG_SED From d849e23b1c6b7278aef2f460723ac17cdc63e1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 18 Feb 2016 18:19:54 -0800 Subject: [PATCH 0987/1342] zebra: Fix route deletion on *BSD Fix for not handling RTM_CHANGE correctly. This patch change it to delete/add instead. Using RTM_CHANGE on kernels where it works is better, but is left as an exercise for developer who has access and will to fix it on *BSD. [ed note: collaboration with Martin Winter] --- zebra/rt_socket.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 78ec9e579..9dd45823f 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -68,7 +68,7 @@ sin_masklen (struct in_addr mask) /* Interface between zebra message and rtm message. */ static int -kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) +kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib) { struct sockaddr_in *mask = NULL; @@ -245,7 +245,7 @@ sin6_masklen (struct in6_addr mask) /* Interface between zebra message and rtm message. */ static int -kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib, int family) +kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; @@ -363,33 +363,32 @@ kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib, int family) #endif +static int +kernel_rtm (int cmd, struct prefix *p, struct rib *rib) +{ + switch (PREFIX_FAMILY(p)) + { + case AF_INET: + return kernel_rtm_ipv4 (cmd, p, rib); + case AF_INET6: + return kernel_rtm_ipv6 (cmd, p, rib); + } + return 0; +} + int kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { - struct rib *rib; - int route = 0, cmd; - - if (!old && new) - cmd = RTM_ADD; - else if (old && !new) - cmd = RTM_DELETE; - else - cmd = RTM_CHANGE; - - rib = new ? new : old; + int route = 0; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); - switch (PREFIX_FAMILY(p)) - { - case AF_INET: - route = kernel_rtm_ipv4 (cmd, p, rib, AF_INET); - break; - case AF_INET6: - route = kernel_rtm_ipv6 (cmd, p, rib, AF_INET6); - break; - } + if (old) + route |= kernel_rtm (RTM_DELETE, p, old); + + if (new) + route |= kernel_rtm (RTM_ADD, p, new); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); From c0cb90c608f7dcb0807e05c70050d2e238d6c4e9 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 8 Mar 2016 18:14:50 +0000 Subject: [PATCH 0988/1342] Revert "bgpd: Lower BGP's default keepalive/holdtime to 3s/9s" This reverts commit f89b09be92bed03b1e5add55dc14ef92e94c52e1. Martin Winter has reported reliability issues in testing on some platforms. We need a more comprehensive way to deal with defaults and updating them, e.g. profiles of some kind. Defer this change till after next release. --- bgpd/bgpd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 5be5a19c7..7665d9d00 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -743,8 +743,8 @@ struct bgp_nlri /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 -#define BGP_DEFAULT_HOLDTIME 9 -#define BGP_DEFAULT_KEEPALIVE 3 +#define BGP_DEFAULT_HOLDTIME 180 +#define BGP_DEFAULT_KEEPALIVE 60 #define BGP_DEFAULT_EBGP_ROUTEADV 30 #define BGP_DEFAULT_IBGP_ROUTEADV 5 #define BGP_CLEAR_CONNECT_RETRY 20 From e3f623be8b6556db9d70c2fc5d3c2b152f36dc1d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 9 Mar 2016 08:41:59 -0500 Subject: [PATCH 0989/1342] release: 1.0.20160309 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0fc9c099f..7c7116d77 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 0.99.25, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.0.20160309, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From 5e57b5fc621300427d3818f0723b8cd8d5e5ca6a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 11 Mar 2016 16:28:34 -0500 Subject: [PATCH 0990/1342] quagga: Remove double read of stream The addition of a MIN(X,Y) with a stream_getc in the Y causes a double read of the stream due to the way that MIN is defined. This fix removes a crash in all protocols. Signed-off-by: Donald Sharp --- bgpd/bgp_zebra.c | 8 ++++++-- isisd/isis_zebra.c | 4 +++- ospf6d/ospf6_zebra.c | 4 +++- ospfd/ospf_zebra.c | 4 +++- ripd/rip_zebra.c | 6 ++++-- ripngd/ripng_zebra.c | 4 +++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index bee1a9470..d0b9216a8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -238,6 +238,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, struct zapi_ipv4 api; struct in_addr nexthop; struct prefix_ipv4 p; + unsigned char plength = 0; s = zclient->ibuf; nexthop.s_addr = 0; @@ -250,7 +251,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; - p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s)); + plength = stream_getc (s); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ @@ -314,6 +316,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, struct zapi_ipv6 api; struct in6_addr nexthop; struct prefix_ipv6 p; + unsigned char plength = 0; s = zclient->ibuf; memset (&nexthop, 0, sizeof (struct in6_addr)); @@ -326,7 +329,8 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; - p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s)); + plength = stream_getc (s); + p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index a1a5bea7c..4acaf8e88 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -529,6 +529,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, struct prefix *p_generic = (struct prefix*)&p; unsigned long ifindex __attribute__ ((unused)); struct in_addr nexthop __attribute__ ((unused)); + unsigned char plength = 0; stream = zclient->ibuf; memset(&api, 0, sizeof(api)); @@ -541,7 +542,8 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient, api.message = stream_getc (stream); p.family = AF_INET; - p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (stream)); + plength = stream_getc (stream); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); stream_get (&p.prefix, stream, PSIZE (p.prefixlen)); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 0caf0014b..c8f20d864 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -213,6 +213,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, unsigned long ifindex; struct prefix_ipv6 p; struct in6_addr *nexthop; + unsigned char plength = 0; s = zclient->ibuf; ifindex = 0; @@ -227,7 +228,8 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; - p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s)); + plength = stream_getc (s); + p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 4531f13d4..89404552b 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -832,6 +832,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, struct prefix_ipv4 p; struct external_info *ei; struct ospf *ospf; + unsigned char plength = 0; s = zclient->ibuf; ifindex = 0; @@ -845,7 +846,8 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; - p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s)); + plength = stream_getc (s); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); if (IPV4_NET127(ntohl(p.prefix.s_addr))) diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 1411cd71b..2670ff7ee 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -135,7 +135,8 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; - + unsigned char plength = 0; + s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; @@ -148,7 +149,8 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; - p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s)); + plength = stream_getc (s); + p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index e02b09896..72216164a 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -134,6 +134,7 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient, unsigned long ifindex; struct in6_addr nexthop; struct prefix_ipv6 p; + unsigned char plength = 0; s = zclient->ibuf; ifindex = 0; @@ -147,7 +148,8 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient, /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; - p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s)); + plength = stream_getc (s); + p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ From 86c5d2ee68f7b9c00ae4aeb5c8b3c5d82c5ebffc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 15 Mar 2016 19:17:17 -0400 Subject: [PATCH 0991/1342] release: 1.0.20160315 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7c7116d77..620651085 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 1.0.20160309, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.0.20160315, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From 106e38e4d42ecd94c083907872d514e8c67036f6 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sun, 3 Apr 2016 12:46:25 -0300 Subject: [PATCH 0992/1342] isisd: work around route table asserts for deleting node with info The route table code in lib/table.c triggers an assertion when a route node with rn->info != NULL reaches refcount 0, probably to avoid memleaks. In this particular case, this is not an issue, since the info will be freed by the destructor. However, since removing this assertion probably requires more discussion, just make sure that rn->info gets freed and unset before its refcount is decremented to zero. Signed-off-by: Christian Franke --- isisd/isis_redist.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index abb9ecd40..690ae4720 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -176,6 +176,7 @@ isis_redist_uninstall(struct isis_area *area, int level, struct prefix *p) if (!er_node->info) return; + XFREE(MTYPE_ISIS, er_node->info); route_unlock_node(er_node); lsp_regenerate_schedule(area, level, 0); } @@ -358,6 +359,7 @@ isis_redist_delete(int type, struct prefix *p) isis_redist_uninstall(area, level, p); } + XFREE(MTYPE_ISIS, ei_node->info); route_unlock_node(ei_node); } @@ -502,6 +504,7 @@ isis_redist_unset(struct isis_area *area, int level, continue; } + XFREE(MTYPE_ISIS, rn->info); route_unlock_node(rn); } From 8ed8d0b5d1596ec9a6cce5ca45eb1cb1dff94978 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sun, 3 Apr 2016 12:46:26 -0300 Subject: [PATCH 0993/1342] isisd: fix a crash due to an lsp-mtu issue isisd crashed on startup if it was enabled for an interface with a too small MTU. To fix this, we treat this case as an invalid configuration and disable isis on that interface if that case happens, since it is a configuration error. Signed-off-by: Christian Franke --- isisd/isis_circuit.c | 2 +- isisd/isis_csm.c | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index a48afd2b8..01a9d1e43 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -640,7 +640,7 @@ isis_circuit_up (struct isis_circuit *circuit) zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!", isis_circuit_pdu_size(circuit), circuit->interface->name, circuit->area->lsp_mtu); - isis_circuit_down(circuit); + isis_circuit_update_all_srmflags(circuit, 0); return ISIS_ERROR; } diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index a58ba4907..0f642a777 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -147,10 +147,27 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) case IF_UP_FROM_Z: isis_circuit_if_add (circuit, (struct interface *) arg); if (isis_circuit_up (circuit) != ISIS_OK) - { - isis_circuit_if_del (circuit, (struct interface *) arg); + { + zlog_err("Could not bring up %s because of invalid config.", + circuit->interface->name); + zlog_err("Clearing config for %s. Please re-examine it.", + circuit->interface->name); + if (circuit->ip_router) + { + circuit->ip_router = 0; + circuit->area->ip_circuits--; + } + if (circuit->ipv6_router) + { + circuit->ipv6_router = 0; + circuit->area->ipv6_circuits--; + } + circuit_update_nlpids(circuit); + isis_circuit_deconfigure(circuit, circuit->area); + listnode_add (isis->init_circ_list, circuit); + circuit->state = C_STATE_INIT; break; - } + } circuit->state = C_STATE_UP; isis_event_circuit_state_change (circuit, circuit->area, 1); break; From 84a4da039fa620942b6c3a9ff21b7502803f53be Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sun, 3 Apr 2016 12:46:27 -0300 Subject: [PATCH 0994/1342] isisd: make sure that all interface addresses are advertised If the following configuration commands are run interactively in succession, the ipv6 addresses of this interface won't be advertised in the router's LSP immediately: # interface eth0 # ip router isis test # ipv6 router isis test This is because the ipv6 router command won't trigger a state change for the interface and therefore, it won't trigger a regeneration of the LSPs. The same thing happens if IPv4 is enabled after IPv6, or for the cases where IPv4 is disabled and IPv6 stays enabled or vice-versa. Fix this by explicitly calling lsp_regenerate_schedule for the cases where it won't be called implicitly. Signed-off-by: Christian Franke --- isisd/isis_circuit.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 01a9d1e43..b49360932 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1298,6 +1298,8 @@ DEFUN (ip_router_isis, vty->node = INTERFACE_NODE; vty->index = ifp; + if (circuit->ipv6_router) + lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); return rv; } @@ -1339,10 +1341,10 @@ DEFUN (no_ip_router_isis, circuit->ip_router = 0; area->ip_circuits--; -#ifdef HAVE_IPV6 if (circuit->ipv6_router == 0) -#endif isis_csm_state_change (ISIS_DISABLE, circuit, area); + else + lsp_regenerate_schedule(area, circuit->is_type, 0); return CMD_SUCCESS; } @@ -1406,6 +1408,8 @@ DEFUN (ipv6_router_isis, vty->node = INTERFACE_NODE; vty->index = ifp; + if (circuit->ip_router) + lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); return rv; } @@ -1449,6 +1453,8 @@ DEFUN (no_ipv6_router_isis, area->ipv6_circuits--; if (circuit->ip_router == 0) isis_csm_state_change (ISIS_DISABLE, circuit, area); + else + lsp_regenerate_schedule(area, circuit->is_type, 0); return CMD_SUCCESS; } From e7207098c0fa88af6899c1b1483e3ddb19f5336a Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sun, 3 Apr 2016 12:46:28 -0300 Subject: [PATCH 0995/1342] isisd: ignore unknown interfaces when adjusting IS-IS mtu For example during startup of isisd, the MTU of interfaces is not known, since this information will only be available once the interfaces have been learned from zebra. It makes no sense to include the MTU 0 that is stored for interfaces in this state in the consideration whether a new lsp-mtu for an area is valid, so skip interfaces which are in this state. Signed-off-by: Christian Franke --- isisd/isisd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/isisd/isisd.c b/isisd/isisd.c index c446e7fcd..26b71257d 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1619,6 +1619,8 @@ int area_set_lsp_mtu(struct vty *vty, struct isis_area *area, unsigned int lsp_m for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { + if(circuit->state != C_STATE_INIT && circuit->state != C_STATE_UP) + continue; if(lsp_mtu > isis_circuit_pdu_size(circuit)) { vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", From 7e7a101dde5969f62074801d84bb4cc75e50f548 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Apr 2016 22:03:22 -0400 Subject: [PATCH 0996/1342] ripd: Fix Null pointer dereference The rip_output_process function dereferenced a NULL pointer. Core file examination showed that tmp_rinfo was NULL on line 2435. Looking at the last diff associated with this commit, it was obvious that a formating mistake had been made in the loop over the route nodes list of possible paths. Signed-off-by: Donald Sharp Reported-by: Sebastian Kricner Tested-by: NetDEF CI System --- ripd/ripd.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index 82b1adaeb..0beb0e628 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2429,12 +2429,14 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, struct rip_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) - if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && - tmp_rinfo->ifindex == ifc->ifp->ifindex) - rinfo->metric_out = RIP_METRIC_INFINITY; - if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && - prefix_match((struct prefix *)p, ifc->address)) - rinfo->metric_out = RIP_METRIC_INFINITY; + { + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && + tmp_rinfo->ifindex == ifc->ifp->ifindex) + rinfo->metric_out = RIP_METRIC_INFINITY; + if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && + prefix_match((struct prefix *)p, ifc->address)) + rinfo->metric_out = RIP_METRIC_INFINITY; + } } /* Prepare preamble, auth headers, if needs be */ From 7e73eb740f3c52a5b7c0ae9c2cd33b486d885552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 9 Apr 2016 17:22:32 +0300 Subject: [PATCH 0997/1342] zebra: handle multihop nexthop changes properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rib entries are normally added and deleted when they are changed. However, they are modified in placae when the nexthop reachability changes. This fixes to: - properly detect nexthop changes from nexthop_active_update() calls from rib_process() - rib_update_kernel() to not reset FIB flags when a RIB entry is being modifed (old and new RIB are same) - improves the "show ip route " output to display both ACTIVE and FIB flags for each nexthop Fixes: 325823a5 "zebra: support FIB override routes" Signed-off-by: Timo Teräs Reported-By: Igor Ryzhov Tested-by: NetDEF CI System --- zebra/zebra_rib.c | 16 ++++++++++------ zebra/zebra_vty.c | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1650dabf0..18eece81b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1078,7 +1078,6 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) ifindex_t prev_index; rib->nexthop_active_num = 0; - UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { @@ -1124,12 +1123,15 @@ rib_update_kernel (struct route_node *rn, struct rib *old, struct rib *new) /* This condition is never met, if we are using rt_socket.c */ if (ret < 0 && new) + { for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - if (old) - for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + else if (old && old != new) + { + for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } return ret; } @@ -1275,6 +1277,8 @@ rib_process (struct route_node *rn) RNODE_FOREACH_RIB (rn, rib) { + UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); + /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { @@ -1323,7 +1327,7 @@ rib_process (struct route_node *rn) if (new_fib) nexthop_active_update (rn, new_fib, 1); if (new_selected && new_selected != new_fib) - nexthop_active_update (rn, new_selected, 1); + nexthop_active_update (rn, new_selected, 1); /* Update kernel if FIB entry has changed */ if (old_fib != new_fib diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 21b92ea9e..028b744a2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1341,7 +1341,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { - vty_out (vty, " %c%s", + vty_out (vty, " %c%c%s", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? '>' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', recursing ? " " : ""); From 80f61a9979079ed16b9eff50ba65ad8bf1b15fb6 Mon Sep 17 00:00:00 2001 From: Jonathan Hart Date: Tue, 19 Apr 2016 22:13:49 -0700 Subject: [PATCH 0998/1342] pimd: Fix hang when doing nexthop lookup from zebra I was running in to a bug when pimd would hang in some cases when it had to do a nexthop lookup from zebra, such as when a PIM JOIN was received. This issue could be easily reproduced by running 'show ip rib ' from the pimd vty which forces a nexthop lookup. The issue is in zclient_read_nexthop, the zclient_read_header function reads the message content into the stream, but then after that the zclient_read_nexthop function tries to read the message content again from the socket, but there are no bytes so it hangs waiting for input. The solution is to not try to read the message content the second time. Acked-by: Jafar Al-Gharaibeh Tested-by: NetDEF CI System --- pimd/pim_zlookup.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index b5b219ea3..770fbf742 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -155,7 +155,6 @@ static int zclient_read_nexthop(struct zclient *zlookup, u_char version; uint16_t vrf_id; uint16_t command; - int nbytes; struct in_addr raddr; uint8_t distance; uint32_t metric; @@ -189,14 +188,6 @@ static int zclient_read_nexthop(struct zclient *zlookup, return -2; } - nbytes = stream_read(s, zlookup->sock, length); - if (nbytes < length) { - zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d", - __FILE__, __PRETTY_FUNCTION__, nbytes, length); - zclient_lookup_failed(zlookup); - return -3; - } - if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); From 190591f0fe3388c746ea48f69a439f4bd0b49834 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Thu, 21 Apr 2016 17:40:12 -0500 Subject: [PATCH 0999/1342] zserv: [pimd] fix - avoid dereferencing a NULL pointer Signed-off-by: Jafar Al-Gharaibeh Tested-by: NetDEF CI System --- zebra/zserv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index e624ef2f6..6412f8d6d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -626,7 +626,8 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, rib->vrf_id); + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, + rib ? rib->vrf_id : VRF_DEFAULT); stream_put_in_addr (s, &addr); if (rib) From e6ec2d6d18dadb119b93284ef2f5f5b5440d6f66 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Apr 2016 19:30:51 -0400 Subject: [PATCH 1000/1342] lib: Fix priviledge modification for vty group specified When attempting to switch runtime permissions over to the correct group specified for the vty group, if the user specified to run as does not have that vty group then do warn about the issue and stop running Signed-off-by: Donald Sharp Reported-by: Thomas Martin Tested-by: NetDEF CI System --- lib/privs.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/privs.c b/lib/privs.c index 0ca8783dc..e6d76b600 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -664,6 +664,7 @@ zprivs_init(struct zebra_privs_t *zprivs) struct group *grentry = NULL; gid_t groups[NGROUPS_MAX]; int i, ngroups = 0; + int found = 0; if (!zprivs) { @@ -729,8 +730,17 @@ zprivs_init(struct zebra_privs_t *zprivs) for ( i = 0; i < ngroups; i++ ) if ( groups[i] == zprivs_state.vtygrp ) - break; + { + found++; + break; + } + if (!found) + { + fprintf (stderr, "privs_init: user(%s) is not part of vty group specified(%s)\n", + zprivs->user, zprivs->vty_group); + exit (1); + } if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) ) { groups[i] = zprivs_state.vtygrp; From bb01bdd740339b0c07d8ed0786811801b2a79192 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Thu, 21 Apr 2016 16:22:33 -0500 Subject: [PATCH 1001/1342] ospfd: fix - correct neighbor index on changing/p2p/virtual links ospfd keeps a list of neighbor routers for each configured interface. This list is indexed using the neighbor router id in case of point-to-point and virtual link types, otherwise the list is indexed using the neighbor's source IP (RFC 2328, page 96). The router adds itself as a "pseudo" neighbor on each link, and also keeps a pointer called (nbr_self) to the neighbor structure. This takes place when the interface is first configured. Currently ospfd adds this pseudo neighbor before the link parameters are fully configure, including whether the link type is point-to-point or virtual link. This causes the pseudo neighbor to be always indexed using the source IP address regardless of th link type. For point-to-point and virtual links, this causes the lookup for the pseudo neighbor to always fail because the lookup is done using the router id whereas the neighbor was added using its source IP address. This becomes really problematic if there is a state change that requires a rebuild of nbr_self, changing the router id for example. When resetting nbr_self, the router first tries to remove the pseudo neighbor form its neighbor list on each link by looking it up and resetting any references to it before freeing the neighbor structure. since the lookup fails to retrieve any references in the case of point-to-point and virtual links the neighbor structure is freed leaving dangling references to it. Any access to the neighbor list after that is bound to stumble over this dangling pointer causing ospfd to crash. Signed-off-by: Jafar Al-Gharaibeh Tested-by: NetDEF CI System --- ospfd/ospf_interface.c | 8 +++++--- ospfd/ospf_neighbor.c | 33 ++++++++++++++++++++++++++++++++- ospfd/ospfd.c | 6 +++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index f4242b0b3..d54bc473e 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -232,8 +232,8 @@ ospf_if_new (struct ospf *ospf, struct interface *ifp, struct prefix *p) /* Set default values. */ ospf_if_reset_variables (oi); - /* Add pseudo neighbor. */ - oi->nbr_self = ospf_nbr_new (oi); + /* Set pseudo neighbor to Null */ + oi->nbr_self = NULL; oi->ls_upd_queue = route_table_init (); oi->t_ls_upd_event = NULL; @@ -902,7 +902,9 @@ ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data) if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): set associated area to the backbone"); - ospf_nbr_add_self (voi); + /* Add pseudo neighbor. */ + ospf_nbr_self_reset (voi); + ospf_area_add_if (voi->area, voi); ospf_if_stream_set (voi); diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 862de5e85..06e63dd28 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -181,6 +181,35 @@ ospf_nbr_delete (struct ospf_neighbor *nbr) route_unlock_node (rn); } + else + { + /* + * This neighbor was not found, but before we move on and + * free the neighbor structre, make sure that it was not + * indexed incorrectly and ended up in the "worng" place + */ + + /* Reverse the lookup rules */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK || + oi->type == OSPF_IFTYPE_POINTOPOINT) + p.u.prefix4 = nbr->src; + else + p.u.prefix4 = nbr->router_id; + + rn = route_node_lookup (oi->nbrs, &p); + if (rn){ + /* We found the neighbor! + * Now make sure it is not the exact same neighbor + * structure that we are about to free + */ + if (nbr == rn->info){ + /* Same neighbor, drop the reference to it */ + rn->info = NULL; + route_unlock_node (rn); + } + route_unlock_node (rn); + } + } /* Free ospf_neighbor structure. */ ospf_nbr_free (nbr); @@ -207,7 +236,9 @@ ospf_nbr_bidirectional (struct in_addr *router_id, void ospf_nbr_self_reset (struct ospf_interface *oi) { - ospf_nbr_delete (oi->nbr_self); + if (oi->nbr_self) + ospf_nbr_delete (oi->nbr_self); + oi->nbr_self = ospf_nbr_new (oi); ospf_nbr_add_self (oi); } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index c9fcdc393..cc76e9e17 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -754,9 +754,6 @@ add_ospf_interface (struct connected *co, struct ospf_area *area) oi->params = ospf_lookup_if_params (co->ifp, oi->address->u.prefix4); oi->output_cost = ospf_if_get_output_cost (oi); - /* Add pseudo neighbor. */ - ospf_nbr_add_self (oi); - /* Relate ospf interface to ospf instance. */ oi->ospf = area->ospf; @@ -765,6 +762,9 @@ add_ospf_interface (struct connected *co, struct ospf_area *area) skip network type setting. */ oi->type = IF_DEF_PARAMS (co->ifp)->type; + /* Add pseudo neighbor. */ + ospf_nbr_self_reset (oi); + ospf_area_add_if (oi->area, oi); /* if router_id is not configured, dont bring up From aef4650851cf0f74d944466d50e26bb8f8635c3d Mon Sep 17 00:00:00 2001 From: Stas Nichiporovich Date: Tue, 26 Apr 2016 08:14:36 +0000 Subject: [PATCH 1002/1342] zebra: fix crash caused by using route-map with "set src" Signed-off-by: Stas Nichiporovich Tested-by: NetDEF CI System --- zebra/zebra_routemap.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index da9cb1308..49feccd06 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -424,11 +424,13 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix, { struct access_list *alist; struct nexthop *nexthop; + struct nexthop_vrfid *nh_vrf; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { - nexthop = object; + nh_vrf = object; + nexthop = nh_vrf->nexthop; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: @@ -486,11 +488,13 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, { struct prefix_list *plist; struct nexthop *nexthop; + struct nexthop_vrfid *nh_vrf; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { - nexthop = object; + nh_vrf = object; + nexthop = nh_vrf->nexthop; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: @@ -632,10 +636,10 @@ route_set_src (void *rule, struct prefix *prefix, { if (type == RMAP_ZEBRA) { - struct nexthop *nexthop; + struct nexthop_vrfid *nh_vrf; - nexthop = object; - nexthop->src = *(union g_addr *)rule; + nh_vrf = object; + nh_vrf->nexthop->src = *(union g_addr *)rule; } return RMAP_OKAY; } From 5f678889843fb9bc3f07d05eebc2f8fb35584a91 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Fri, 22 Apr 2016 17:38:24 +0300 Subject: [PATCH 1003/1342] zebra: add missing vty commands Signed-off-by: Igor Ryzhov Tested-by: NetDEF CI System --- zebra/zebra_vty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 028b744a2..3973e4382 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3876,6 +3876,7 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ip_route_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd); @@ -3929,6 +3930,7 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ip_route_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_vrf_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_vrf_cmd); From ac6ff4643645315db648604771926218aa4ead2d Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 17 May 2016 07:10:37 -0400 Subject: [PATCH 1004/1342] bgpd: Add flag to not change e{u,g}id on startup and run as unprivileged user * bgp_main.c: add -S / --skip_runas flag to not change effective user/group on start up. Enables bgpd to be run by unprivileged user. --- bgpd/bgp_main.c | 13 +++++++++++-- doc/bgpd.8 | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 11c73ceae..562afc20e 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -67,6 +67,7 @@ static const struct option longopts[] = { "no_kernel", no_argument, NULL, 'n'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, + { "skip_runas", no_argument, NULL, 'S'}, { "version", no_argument, NULL, 'v'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, @@ -161,6 +162,7 @@ redistribution between different routing protocols.\n\n\ -n, --no_kernel Do not install route to kernel.\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ +-S, --skip_runas Skip user and group run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ @@ -200,7 +202,8 @@ sigint (void) if (! retain_mode) { bgp_terminate (); - zprivs_terminate (&bgpd_privs); + if (bgpd_privs.user) /* NULL if skip_runas flag set */ + zprivs_terminate (&bgpd_privs); } bgp_exit (0); @@ -346,6 +349,7 @@ main (int argc, char **argv) char *progname; struct thread thread; int tmp_port; + int skip_runas = 0; /* Set umask before anything for security */ umask (0027); @@ -362,7 +366,7 @@ main (int argc, char **argv) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vCS", longopts, 0); if (opt == EOF) break; @@ -420,6 +424,9 @@ main (int argc, char **argv) case 'g': bgpd_privs.group = optarg; break; + case 'S': /* skip run as = override bgpd_privs */ + skip_runas = 1; + break; case 'v': print_version (progname); exit (0); @@ -439,6 +446,8 @@ main (int argc, char **argv) /* Initializations. */ srandom (time (NULL)); signal_init (bm->master, array_size(bgp_signals), bgp_signals); + if (skip_runas) + memset (&bgpd_privs, 0, sizeof (bgpd_privs)); zprivs_init (&bgpd_privs); cmd_init (1); vty_init (bm->master); diff --git a/doc/bgpd.8 b/doc/bgpd.8 index 8daaefa27..1a873b426 100644 --- a/doc/bgpd.8 +++ b/doc/bgpd.8 @@ -6,7 +6,7 @@ software .SH SYNOPSIS .B bgpd [ -.B \-dhrv +.B \-dhrSv ] [ .B \-f .I config-file @@ -74,6 +74,9 @@ Specify the user to run as. Default is \fIquagga\fR. \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBbgpd\fR. .TP +\fB\-S\fR, \fB\-\-skip_runas\fR +Skip setting the process effective user and group. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES From f53585d59b62b12d68282154af346796b75c7f2f Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 17 May 2016 07:10:36 -0400 Subject: [PATCH 1005/1342] bgp: add "debug bgp allow-martians" next hops and related code/commands --- bgpd/bgp_attr.c | 3 ++- bgpd/bgp_debug.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_debug.h | 3 +++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f34e64933..42da7ff43 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1249,7 +1249,8 @@ bgp_attr_nexthop (struct bgp_attr_parser_args *args) gets ignored in any of these cases. */ nexthop_n = stream_get_ipv4 (peer->ibuf); nexthop_h = ntohl (nexthop_n); - if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) + if ((IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) + && !BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) /* loopbacks may be used in testing */ { char buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 60e2777ec..90a378ba2 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -46,6 +46,7 @@ unsigned long conf_bgp_debug_keepalive; unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_normal; unsigned long conf_bgp_debug_zebra; +unsigned long conf_bgp_debug_allow_martians; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_fsm; @@ -56,6 +57,7 @@ unsigned long term_bgp_debug_keepalive; unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_normal; unsigned long term_bgp_debug_zebra; +unsigned long term_bgp_debug_allow_martians; /* messages for BGP-4 status */ const struct message bgp_status_msg[] = @@ -725,6 +727,48 @@ ALIAS (no_debug_bgp_zebra, BGP_STR "BGP Zebra messages\n") +DEFUN (debug_bgp_allow_martians, + debug_bgp_allow_martians_cmd, + "debug bgp allow-martians", + DEBUG_STR + BGP_STR + "BGP allow martian next hops\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (allow_martians, ALLOW_MARTIANS); + else + { + TERM_DEBUG_ON (allow_martians, ALLOW_MARTIANS); + vty_out (vty, "BGP allow_martian next hop debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_allow_martians, + no_debug_bgp_allow_martians_cmd, + "no debug bgp allow-martians", + NO_STR + DEBUG_STR + BGP_STR + "BGP allow martian next hops\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (allow_martians, ALLOW_MARTIANS); + else + { + TERM_DEBUG_OFF (allow_martians, ALLOW_MARTIANS); + vty_out (vty, "BGP allow martian next hop debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_allow_martians, + undebug_bgp_allow_martians_cmd, + "undebug bgp allow-martians", + UNDEBUG_STR + BGP_STR + "BGP allow martian next hops\n") + DEFUN (no_debug_bgp_all, no_debug_bgp_all_cmd, "no debug all bgp", @@ -743,6 +787,7 @@ DEFUN (no_debug_bgp_all, TERM_DEBUG_OFF (fsm, FSM); TERM_DEBUG_OFF (filter, FILTER); TERM_DEBUG_OFF (zebra, ZEBRA); + TERM_DEBUG_OFF (allow_martians, ALLOW_MARTIANS); vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -786,6 +831,8 @@ DEFUN (show_debugging_bgp, vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (as4, AS4_SEGMENT)) vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) + vty_out (vty, " BGP allow martian next hop debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -859,6 +906,12 @@ bgp_config_write_debug (struct vty *vty) write++; } + if (CONF_BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) + { + vty_out (vty, "debug bgp allow-martians%s", VTY_NEWLINE); + write++; + } + return write; } @@ -897,6 +950,8 @@ bgp_debug_init (void) install_element (CONFIG_NODE, &debug_bgp_normal_cmd); install_element (ENABLE_NODE, &debug_bgp_zebra_cmd); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); + install_element (ENABLE_NODE, &debug_bgp_allow_martians_cmd); + install_element (CONFIG_NODE, &debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd); install_element (ENABLE_NODE, &undebug_bgp_as4_cmd); @@ -926,6 +981,9 @@ bgp_debug_init (void) install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd); install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_allow_martians_cmd); + install_element (ENABLE_NODE, &undebug_bgp_allow_martians_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); install_element (ENABLE_NODE, &undebug_bgp_all_cmd); } diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index ce8547b04..42cbd7e79 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -67,6 +67,7 @@ extern unsigned long conf_bgp_debug_keepalive; extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_normal; extern unsigned long conf_bgp_debug_zebra; +extern unsigned long conf_bgp_debug_allow_martians; extern unsigned long term_bgp_debug_as4; extern unsigned long term_bgp_debug_fsm; @@ -77,6 +78,7 @@ extern unsigned long term_bgp_debug_keepalive; extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_normal; extern unsigned long term_bgp_debug_zebra; +extern unsigned long term_bgp_debug_allow_martians; #define BGP_DEBUG_AS4 0x01 #define BGP_DEBUG_AS4_SEGMENT 0x02 @@ -90,6 +92,7 @@ extern unsigned long term_bgp_debug_zebra; #define BGP_DEBUG_UPDATE_OUT 0x02 #define BGP_DEBUG_NORMAL 0x01 #define BGP_DEBUG_ZEBRA 0x01 +#define BGP_DEBUG_ALLOW_MARTIANS 0x01 #define BGP_DEBUG_PACKET_SEND 0x01 #define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 From 86b2a0a12ace817e64e8e4a719b1ba9a8e6af253 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 17 May 2016 12:19:51 -0400 Subject: [PATCH 1006/1342] lib: change command logging to be off by default * lib/vty.c: add 'log_command' to enable logging of vty commands executed. Default command logging to off. --- doc/basic.texi | 7 +++++++ lib/vty.c | 23 ++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/basic.texi b/doc/basic.texi index 0f7bec9c2..4485665af 100644 --- a/doc/basic.texi +++ b/doc/basic.texi @@ -185,6 +185,13 @@ In this example, the precision is set to provide timestamps with millisecond accuracy. @end deffn +@deffn Command {log commands} {} +This command enables the logging of all commands typed by a user to +all enabled log destinations. The note that logging includes full +command lines, including passwords. Once set, command logging can only +be turned off by restarting the daemon. +@end deffn + @deffn Command {service password-encryption} {} Encrypt password. @end deffn diff --git a/lib/vty.c b/lib/vty.c index e4510f850..ff013cf61 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -90,6 +90,7 @@ static u_char restricted_mode = 0; /* Integrated configuration file path */ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; +static int do_log_commands = 0; /* VTY standard output function. */ int @@ -401,12 +402,13 @@ vty_command (struct vty *vty, char *buf) int ret; vector vline; const char *protocolname; - char *cp; + char *cp = NULL; /* * Log non empty command lines */ - cp = buf; + if (do_log_commands) + cp = buf; if (cp != NULL) { /* Skip white spaces. */ @@ -434,7 +436,7 @@ vty_command (struct vty *vty, char *buf) snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str); /* now log the command */ - zlog(NULL, LOG_NOTICE, "%s%s", prompt_str, buf); + zlog(NULL, LOG_ERR, "%s%s", prompt_str, buf); } /* Split readline string up into the vector */ vline = cmd_make_strvec (buf); @@ -2938,6 +2940,17 @@ DEFUN (show_history, return CMD_SUCCESS; } +/* vty login. */ +DEFUN (log_commands, + log_commands_cmd, + "log commands", + "Logging control\n" + "Log all commands (can't be unset without restart)\n") +{ + do_log_commands = 1; + return CMD_SUCCESS; +} + /* Display current configuration. */ static int vty_config_write (struct vty *vty) @@ -2970,6 +2983,9 @@ vty_config_write (struct vty *vty) vty_out (vty, " anonymous restricted%s", VTY_NEWLINE); } + if (do_log_commands) + vty_out (vty, "log commands%s", VTY_NEWLINE); + vty_out (vty, "!%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -3091,6 +3107,7 @@ vty_init (struct thread_master *master_thread) install_element (CONFIG_NODE, &service_advanced_vty_cmd); install_element (CONFIG_NODE, &no_service_advanced_vty_cmd); install_element (CONFIG_NODE, &show_history_cmd); + install_element (CONFIG_NODE, &log_commands_cmd); install_element (ENABLE_NODE, &terminal_monitor_cmd); install_element (ENABLE_NODE, &terminal_no_monitor_cmd); install_element (ENABLE_NODE, &no_terminal_monitor_cmd); From d319a3abbf6e6c310b6b6a6891ebe1957592f9a9 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 25 May 2016 14:47:00 +0100 Subject: [PATCH 1007/1342] ripd: split-horizon default differed between rip_interface_new and _reset * rip_interface.c: Default for split_horizon_default differed between rip_interface_new and rip_interface_reset, causing at least some issues after interface events. See patchwork #604. Fix, and consolidate code. (rip_interface_{reset,clean}) rename these to 'interface', as that's more appropriate. Spin the ri specific bodies of these functions out to rip_interface_{reset,clean} helpers. Factor out the overlaps, so rip_interface_reset uses rip_interface_clean. (rip_interface_new) just use rip_interface_reset. * ripd.h: Update for (rip_interface_{reset,clean}) Reported by xufeng zhang, with a suggested fix on which this commit expands. See patchwork #604. This commit addresses only the split-horizon discrepency, issue #2. The other issue they reported, #1, is not addressed, though suggested fix seems inappropriate. Cc: xufeng.zhang@windriver.com --- ripd/rip_interface.c | 129 ++++++++++++++++++++----------------------- ripd/ripd.c | 4 +- ripd/ripd.h | 4 +- 3 files changed, 65 insertions(+), 72 deletions(-) diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 7bdcf46a1..240c9688b 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -110,6 +110,8 @@ ipv4_multicast_leave (int sock, return ret; } +static void rip_interface_reset (struct rip_interface *); + /* Allocate new RIP's interface configuration. */ static struct rip_interface * rip_interface_new (void) @@ -117,19 +119,9 @@ rip_interface_new (void) struct rip_interface *ri; ri = XCALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); - - /* Default authentication type is simple password for Cisco - compatibility. */ - ri->auth_type = RIP_NO_AUTH; - ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; - - /* Set default split-horizon behavior. If the interface is Frame - Relay or SMDS is enabled, the default value for split-horizon is - off. But currently Zebra does detect Frame Relay or SMDS - interface. So all interface is set to split horizon. */ - ri->split_horizon_default = RIP_SPLIT_HORIZON; - ri->split_horizon = ri->split_horizon_default; - + + rip_interface_reset (ri); + return ri; } @@ -497,81 +489,82 @@ rip_interface_delete (int command, struct zclient *zclient, return 0; } -void -rip_interface_clean (void) +static void +rip_interface_clean (struct rip_interface *ri) { - struct listnode *node; - struct interface *ifp; - struct rip_interface *ri; + ri->enable_network = 0; + ri->enable_interface = 0; + ri->running = 0; - for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + if (ri->t_wakeup) { - ri = ifp->info; - - ri->enable_network = 0; - ri->enable_interface = 0; - ri->running = 0; - - if (ri->t_wakeup) - { - thread_cancel (ri->t_wakeup); - ri->t_wakeup = NULL; - } + thread_cancel (ri->t_wakeup); + ri->t_wakeup = NULL; } } void -rip_interface_reset (void) +rip_interfaces_clean (void) { struct listnode *node; struct interface *ifp; - struct rip_interface *ri; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) - { - ri = ifp->info; - - ri->enable_network = 0; - ri->enable_interface = 0; - ri->running = 0; + rip_interface_clean (ifp->info); +} - ri->ri_send = RI_RIP_UNSPEC; - ri->ri_receive = RI_RIP_UNSPEC; +static void +rip_interface_reset (struct rip_interface *ri) +{ + /* Default authentication type is simple password for Cisco + compatibility. */ + ri->auth_type = RIP_NO_AUTH; + ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; - ri->auth_type = RIP_NO_AUTH; + /* Set default split-horizon behavior. If the interface is Frame + Relay or SMDS is enabled, the default value for split-horizon is + off. But currently Zebra does detect Frame Relay or SMDS + interface. So all interface is set to split horizon. */ + ri->split_horizon_default = RIP_SPLIT_HORIZON; + ri->split_horizon = ri->split_horizon_default; - if (ri->auth_str) - { - free (ri->auth_str); - ri->auth_str = NULL; - } - if (ri->key_chain) - { - free (ri->key_chain); - ri->key_chain = NULL; - } + ri->ri_send = RI_RIP_UNSPEC; + ri->ri_receive = RI_RIP_UNSPEC; + + if (ri->auth_str) + { + free (ri->auth_str); + ri->auth_str = NULL; + } + if (ri->key_chain) + { + free (ri->key_chain); + ri->key_chain = NULL; + } - ri->split_horizon = RIP_NO_SPLIT_HORIZON; - ri->split_horizon_default = RIP_NO_SPLIT_HORIZON; + ri->list[RIP_FILTER_IN] = NULL; + ri->list[RIP_FILTER_OUT] = NULL; - ri->list[RIP_FILTER_IN] = NULL; - ri->list[RIP_FILTER_OUT] = NULL; + ri->prefix[RIP_FILTER_IN] = NULL; + ri->prefix[RIP_FILTER_OUT] = NULL; + + ri->recv_badpackets = 0; + ri->recv_badroutes = 0; + ri->sent_updates = 0; - ri->prefix[RIP_FILTER_IN] = NULL; - ri->prefix[RIP_FILTER_OUT] = NULL; - - if (ri->t_wakeup) - { - thread_cancel (ri->t_wakeup); - ri->t_wakeup = NULL; - } + ri->passive = 0; + + rip_interface_clean (ri); +} - ri->recv_badpackets = 0; - ri->recv_badroutes = 0; - ri->sent_updates = 0; +void +rip_interfaces_reset (void) +{ + struct listnode *node; + struct interface *ifp; - ri->passive = 0; - } + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + rip_interface_reset (ifp->info); } int diff --git a/ripd/ripd.c b/ripd/ripd.c index 0beb0e628..1d3eb4c50 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -4025,7 +4025,7 @@ rip_clean (void) rip_clean_network (); rip_passive_nondefault_clean (); rip_offset_clean (); - rip_interface_clean (); + rip_interfaces_clean (); rip_distance_reset (); rip_redistribute_clean (); } @@ -4049,7 +4049,7 @@ rip_reset (void) distribute_list_reset (); - rip_interface_reset (); + rip_interfaces_reset (); rip_distance_reset (); rip_zclient_reset (); diff --git a/ripd/ripd.h b/ripd/ripd.h index dbed342db..5e87fcd57 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -381,8 +381,8 @@ extern void rip_init (void); extern void rip_reset (void); extern void rip_clean (void); extern void rip_clean_network (void); -extern void rip_interface_clean (void); -extern void rip_interface_reset (void); +extern void rip_interfaces_clean (void); +extern void rip_interfaces_reset (void); extern void rip_passive_nondefault_clean (void); extern void rip_if_init (void); extern void rip_if_down_all (void); From a343cf8d74920752ba0e35142e23a3ca56620755 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 14 Jan 2013 23:41:57 +0100 Subject: [PATCH 1008/1342] lib: update Solaris multicast API (BZ#725) On OpenIndiana/Solaris the build fails with "unsupported multicast API". It's only in the IPv4 part where setsockopt IP_MULTICAST_IF needs a local address and not the index (IPv6 wants the index). The following code walks the list of interfaces until it finds the matching index and uses the interface's local address for the setsockopt call. I don't know if it works on Solaris < 10 (I guess yes, but I don't have any machine to verify it). [NB: this breaks unnumbered setups that use the same IPv4 address on multiple interfaces. -- equinox@opensourcerouting.org] Reported-by: Brian Utterback Signed-off-by: Christian Franke Patchwork #762 --- lib/sockopt.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/sockopt.c b/lib/sockopt.c index 301423711..3e6ee730a 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -20,6 +20,11 @@ */ #include + +#ifdef SUNOS_5 +#include +#endif + #include "log.h" #include "sockopt.h" #include "sockunion.h" @@ -338,6 +343,35 @@ setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex) m.s_addr = htonl(ifindex); return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m)); +#elif defined(SUNOS_5) + char ifname[IF_NAMESIZE]; + struct ifaddrs *ifa, *ifap; + struct in_addr ifaddr; + + if (if_indextoname(ifindex, ifname) == NULL) + return -1; + + if (getifaddrs(&ifa) != 0) + return -1; + + for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) + { + struct sockaddr_in *sa; + + if (strcmp(ifap->ifa_name, ifname) != 0) + continue; + if (ifap->ifa_addr->sa_family != AF_INET) + continue; + sa = (struct sockaddr_in*)ifap->ifa_addr; + memcpy(&ifaddr, &sa->sin_addr, sizeof(ifaddr)); + break; + } + + freeifaddrs(ifa); + if (!ifap) /* This means we did not find an IP */ + return -1; + + return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&ifaddr, sizeof(ifaddr)); #else #error "Unsupported multicast API" #endif From a0a661f982c4a9726573faf28817d77d3e7cdad5 Mon Sep 17 00:00:00 2001 From: boris yakubov Date: Fri, 26 Apr 2013 14:38:34 -0400 Subject: [PATCH 1009/1342] isisd: Segmentation fault on isis daemon fixes I have a fix for 2 segmentation fault scenarios on the isis daemon: 1. When running a command "isis passive" on an interface in the following context: "end" "configure terminal " "interface dummy0" "isis passive" The trace back collected: isis_adjacency.c:521 family=2, root_sysid=0x20aee6d0 "", parent=0x20af4d68) at isis_spf.c:999 sysid=0x20aee6d0 "") at isis_spf.c:1217 isis_spf.c:1372 isis_lsp.c:416 isis_lsp.c:1660 isis_main.c:368 The fix location: file name: isisd/isis_adjacency.c routine name: isis_adj_build_up_list 2. When deleting the existing isis router instance: "end" "configure terminal " "no router isis DEAD" The fix location: isisd/isis_events.c, routine circuit_resign_level isisd/isis_lsp.c, routine lsp_destroy isisd/isis_route.c, isis_route_validate The trace back collection: "DEAD") at isisd.c:252 argc=1, argv=0xbfc39054) at isisd.c:1520 vty=0x20d6f528, cmd=0x0) at command.c:2121 cmd=0x0, vtysh=0) at command.c:2155 isis DEAD") at vty.c:433 isis_main.c:368 and "DEAD") at isisd.c:260 argc=1, argv=0xbfd6cf54) at isisd.c:1520 vty=0x208cb528, cmd=0x0) at command.c:2121 cmd=0x0, vtysh=0) at command.c:2155 isis DEAD") at vty.c:433 isis_main.c:368 The patch is included. patchwork #833: http://patchwork.quagga.net/patch/833/ --- isisd/isis_adjacency.c | 5 +++++ isisd/isis_events.c | 6 ++++-- isisd/isis_lsp.c | 18 ++++++++++-------- isisd/isis_route.c | 3 +++ 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index c7ab83ba0..8afabede4 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -507,6 +507,11 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list) struct isis_adjacency *adj; struct listnode *node; + if (adjdb == NULL) { + zlog_warn ("isis_adj_build_up_list(): adjacency DB is empty"); + return; + } + if (!list) { zlog_warn ("isis_adj_build_up_list(): NULL list"); diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 0dee9e6f5..26f02100a 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -250,8 +250,10 @@ circuit_resign_level (struct isis_circuit *circuit, int level) THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]); circuit->lsp_regenerate_pending[idx] = 0; circuit->u.bc.run_dr_elect[idx] = 0; - list_delete (circuit->u.bc.lan_neighs[idx]); - circuit->u.bc.lan_neighs[idx] = NULL; + if (circuit->u.bc.lan_neighs[idx] != NULL) { + list_delete (circuit->u.bc.lan_neighs[idx]); + circuit->u.bc.lan_neighs[idx] = NULL; + } } return; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 730924861..4665490be 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -137,14 +137,16 @@ lsp_destroy (struct isis_lsp *lsp) if (!lsp) return; - for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit)) - { - if (circuit->lsp_queue == NULL) - continue; - for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list)) - if (lsp_in_list == lsp) - list_delete_node(circuit->lsp_queue, lnode); - } + if (lsp->area->circuit_list) { + for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit)) + { + if (circuit->lsp_queue == NULL) + continue; + for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list)) + if (lsp_in_list == lsp) + list_delete_node(circuit->lsp_queue, lnode); + } + } ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 9cca80920..c0ec01e84 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -643,6 +643,9 @@ isis_route_validate (struct isis_area *area) isis_route_validate_merge (area, AF_INET6); #endif + if (!area->circuit_list) { + return; + } /* walk all circuits and reset any spf specific flags */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); From d8f7f86a64842fcc6200c2fa4f560b9aa7a279bb Mon Sep 17 00:00:00 2001 From: Roman Hoog Antink Date: Wed, 5 Mar 2014 09:13:43 +0100 Subject: [PATCH 1010/1342] ospf6d: implement admin distance Until today the admin distance cannot be configured for any IPv6 routing protocol. This patch implements it for ospf6. Signed-off-by: Maitane Zotes --- lib/memtypes.c | 1 + ospf6d/ospf6_top.c | 496 +++++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_top.h | 10 +- ospf6d/ospf6_zebra.c | 143 +++++++++++++ ospf6d/ospf6_zebra.h | 20 ++ 5 files changed, 668 insertions(+), 2 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index 6df144803..3b9345d33 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -234,6 +234,7 @@ struct memory_list memory_list_ospf6[] = { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop" }, { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info" }, { MTYPE_OSPF6_OTHER, "OSPF6 other" }, + { MTYPE_OSPF6_DISTANCE, "OSPF6 distance" }, { -1, NULL }, }; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 7fffba83d..1288bc74e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -150,6 +150,8 @@ ospf6_create (void) o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; + o->distance_table = route_table_init (); + return o; } @@ -176,6 +178,9 @@ ospf6_delete (struct ospf6 *o) ospf6_route_table_delete (o->external_table); route_table_finish (o->external_id_table); + ospf6_distance_reset (o); + route_table_finish (o->distance_table); + XFREE (MTYPE_OSPF6_TOP, o); } @@ -401,6 +406,435 @@ DEFUN (no_ospf6_log_adjacency_changes_detail, return CMD_SUCCESS; } +DEFUN (ospf6_distance, + ospf6_distance_cmd, + "distance <1-255>", + NO_STR + "Define an administrative distance\n" + "OSPF6 Administrative distance\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_all = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance, + no_ospf6_distance_cmd, + "no distance <1-255>", + NO_STR + "Define an administrative distance\n" + "OSPF6 Administrative distance\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_all = 0; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance_ospf6, + no_ospf6_distance_ospf6_cmd, + "no distance ospf6", + NO_STR + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "OSPF6 Distance\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_intra = 0; + o->distance_inter = 0; + o->distance_external = 0; + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_intra, + ospf6_distance_ospf6_intra_cmd, + "distance ospf6 intra-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_intra = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_intra_inter, + ospf6_distance_ospf6_intra_inter_cmd, + "distance ospf6 intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_intra = atoi (argv[0]); + o->distance_inter = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_intra_external, + ospf6_distance_ospf6_intra_external_cmd, + "distance ospf6 intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_intra = atoi (argv[0]); + o->distance_external = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_intra_inter_external, + ospf6_distance_ospf6_intra_inter_external_cmd, + "distance ospf6 intra-area <1-255> inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_intra = atoi (argv[0]); + o->distance_inter = atoi (argv[1]); + o->distance_external = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_intra_external_inter, + ospf6_distance_ospf6_intra_external_inter_cmd, + "distance ospf6 intra-area <1-255> external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_intra = atoi (argv[0]); + o->distance_external = atoi (argv[1]); + o->distance_inter = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_inter, + ospf6_distance_ospf6_inter_cmd, + "distance ospf6 inter-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_inter = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_inter_intra, + ospf6_distance_ospf6_inter_intra_cmd, + "distance ospf6 inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_inter = atoi (argv[0]); + o->distance_intra = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_inter_external, + ospf6_distance_ospf6_inter_external_cmd, + "distance ospf6 inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_inter = atoi (argv[0]); + o->distance_external = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_inter_intra_external, + ospf6_distance_ospf6_inter_intra_external_cmd, + "distance ospf6 inter-area <1-255> intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_inter = atoi (argv[0]); + o->distance_intra = atoi (argv[1]); + o->distance_external = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_inter_external_intra, + ospf6_distance_ospf6_inter_external_intra_cmd, + "distance ospf6 inter-area <1-255> external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_inter = atoi (argv[0]); + o->distance_external = atoi (argv[1]); + o->distance_intra = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_external, + ospf6_distance_ospf6_external_cmd, + "distance ospf6 external <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_external = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_external_intra, + ospf6_distance_ospf6_external_intra_cmd, + "distance ospf6 external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_external = atoi (argv[0]); + o->distance_intra = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_external_inter, + ospf6_distance_ospf6_external_inter_cmd, + "distance ospf6 external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_external = atoi (argv[0]); + o->distance_inter = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_external_intra_inter, + ospf6_distance_ospf6_external_intra_inter_cmd, + "distance ospf6 external <1-255> intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_external = atoi (argv[0]); + o->distance_intra = atoi (argv[1]); + o->distance_inter = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6_external_inter_intra, + ospf6_distance_ospf6_external_inter_intra_cmd, + "distance ospf6 external <1-255> inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF6 Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + o->distance_external = atoi (argv[0]); + o->distance_inter = atoi (argv[1]); + o->distance_intra = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_source, + ospf6_distance_source_cmd, + "distance <1-255> X:X::X:X/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + ospf6_distance_set (vty, o, argv[0], argv[1], NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance_source, + no_ospf6_distance_source_cmd, + "no distance <1-255> X:X::X:X/M", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + /* XXX: distance arg seems to be irrelevant */ + ospf6_distance_unset (vty, o, argv[1], NULL); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_source_access_list, + ospf6_distance_source_access_list_cmd, + "distance <1-255> X:X::X:X/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + ospf6_distance_set (vty, o, argv[0], argv[1], argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance_source_access_list, + no_ospf6_distance_source_access_list_cmd, + "no distance <1-255> X:X::X:X/M WORD", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + ospf6_distance_unset (vty, o, argv[1], argv[2]); + + return CMD_SUCCESS; +} + DEFUN (ospf6_interface_area, ospf6_interface_area_cmd, "interface IFNAME area A.B.C.D", @@ -864,6 +1298,43 @@ ospf6_stub_router_config_write (struct vty *vty) return; } +static int +ospf6_distance_config_write (struct vty *vty) +{ + struct route_node *rn; + struct ospf6_distance *odistance; + + if (ospf6->distance_all) + vty_out (vty, " distance %d%s", ospf6->distance_all, VTY_NEWLINE); + + if (ospf6->distance_intra + || ospf6->distance_inter + || ospf6->distance_external) + { + vty_out (vty, " distance ospf6"); + + if (ospf6->distance_intra) + vty_out (vty, " intra-area %d", ospf6->distance_intra); + if (ospf6->distance_inter) + vty_out (vty, " inter-area %d", ospf6->distance_inter); + if (ospf6->distance_external) + vty_out (vty, " external %d", ospf6->distance_external); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + for (rn = route_top (ospf6->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + char pstr[128]; + vty_out (vty, " distance %d %s %s%s", odistance->distance, + prefix2str (&rn->p, pstr, sizeof(pstr)), + odistance->access_list ? odistance->access_list : "", + VTY_NEWLINE); + } + return 0; +} + /* OSPF configuration write function. */ static int config_write_ospf6 (struct vty *vty) @@ -899,6 +1370,7 @@ config_write_ospf6 (struct vty *vty) ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); ospf6_spf_config_write (vty); + ospf6_distance_config_write (vty); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, j, oa)) { @@ -963,6 +1435,30 @@ ospf6_top_init (void) install_element (OSPF6_NODE, &ospf6_stub_router_shutdown_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_shutdown_cmd); */ + + install_element (OSPF6_NODE, &ospf6_distance_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_ospf6_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_external_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_inter_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_external_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_intra_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_inter_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_intra_cmd); + + install_element (OSPF6_NODE, &ospf6_distance_source_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_source_cmd); + install_element (OSPF6_NODE, &ospf6_distance_source_access_list_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_source_access_list_cmd); } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index d6f4bf0f3..97fac0d66 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -82,6 +82,14 @@ struct ospf6 struct thread *maxage_remover; u_int32_t ref_bandwidth; + + /* Distance parameters */ + u_char distance_all; + u_char distance_intra; + u_char distance_inter; + u_char distance_external; + + struct route_table *distance_table; }; #define OSPF6_DISABLED 0x01 @@ -97,5 +105,3 @@ extern void ospf6_delete (struct ospf6 *o); extern void ospf6_maxage_remove (struct ospf6 *o); #endif /* OSPF6_TOP_H */ - - diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index c8f20d864..1f0daa161 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -477,6 +477,8 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = (request->path.metric_type == 2 ? request->path.cost_e2 : request->path.cost); + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = ospf6_distance_apply (request, ospf6); dest = (struct prefix_ipv6 *) &request->prefix; if (type == REM) @@ -579,6 +581,147 @@ ospf6_zebra_connected (struct zclient *zclient) zclient_send_requests (zclient, VRF_DEFAULT); } +static struct ospf6_distance * +ospf6_distance_new (void) +{ + return XCALLOC (MTYPE_OSPF6_DISTANCE, sizeof (struct ospf6_distance)); +} + +static void +ospf6_distance_free (struct ospf6_distance *odistance) +{ + XFREE (MTYPE_OSPF6_DISTANCE, odistance); +} + +int +ospf6_distance_set (struct vty *vty, struct ospf6 *o, + const char *distance_str, + const char *ip_str, + const char *access_list_str) +{ + int ret; + struct prefix_ipv6 p; + u_char distance; + struct route_node *rn; + struct ospf6_distance *odistance; + + ret = str2prefix_ipv6 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get OSPF6 distance node. */ + rn = route_node_get (o->distance_table, (struct prefix *) &p); + if (rn->info) + { + odistance = rn->info; + route_unlock_node (rn); + } + else + { + odistance = ospf6_distance_new (); + rn->info = odistance; + } + + /* Set distance value. */ + odistance->distance = distance; + + /*Reset access-list configuration. */ + if (odistance->access_list) + { + free (odistance->access_list); + odistance->access_list = NULL; + } + if (access_list_str) + odistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +ospf6_distance_unset (struct vty *vty, struct ospf6 *o, + const char *ip_str, + const char *access_list_str) +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rn; + struct ospf6_distance *odistance; + + ret = str2prefix_ipv6 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_lookup (o->distance_table, (struct prefix *) &p); + if (!rn) + { + vty_out (vty, "Cant't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + odistance = rn->info; + + if (odistance->access_list) + free (odistance->access_list); + ospf6_distance_free (odistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +ospf6_distance_reset (struct ospf6 *o) +{ + struct route_node *rn; + struct ospf6_distance *odistance; + + for (rn = route_top (o->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + if (odistance->access_list) + free (odistance->access_list); + ospf6_distance_free (odistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +u_char +ospf6_distance_apply (struct ospf6_route *or, struct ospf6 *o) +{ + + if (o == NULL) + return 0; + + if (o->distance_intra) + if (or->path.type == OSPF6_PATH_TYPE_INTRA) + return o->distance_intra; + + if (o->distance_inter) + if (or->path.type == OSPF6_PATH_TYPE_INTER) + return o->distance_inter; + + if (o->distance_external) + if(or->path.type == OSPF6_PATH_TYPE_EXTERNAL1 + || or->path.type == OSPF6_PATH_TYPE_EXTERNAL2) + return o->distance_external; + + if (o->distance_all) + return o->distance_all; + + return 0; +} + void ospf6_zebra_init (struct thread_master *master) { diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index 05694d390..51eb9d7d5 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -23,6 +23,7 @@ #define OSPF6_ZEBRA_H #include "zclient.h" +#include "ospf6_top.h" /* Debug option */ extern unsigned char conf_debug_ospf6_zebra; @@ -35,6 +36,16 @@ extern unsigned char conf_debug_ospf6_zebra; #define IS_OSPF6_DEBUG_ZEBRA(e) \ (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e) +/* OSPF6 distance */ +struct ospf6_distance +{ + /* Distance value for the IP source prefix */ + u_char distance; + + /* Name of the access-list to be matched */ + char *access_list; +}; + extern struct zclient *zclient; extern void ospf6_zebra_route_update_add (struct ospf6_route *request); @@ -44,6 +55,15 @@ extern void ospf6_zebra_redistribute (int); extern void ospf6_zebra_no_redistribute (int); #define ospf6_zebra_is_redistribute(type) \ vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) + +extern void ospf6_distance_reset (struct ospf6 *); +extern u_char ospf6_distance_apply (struct ospf6_route *, + struct ospf6 *); +extern int ospf6_distance_set (struct vty *, struct ospf6 *, const char *, + const char *, const char *); +extern int ospf6_distance_unset (struct vty *, struct ospf6 *, const char *, + const char *); + extern void ospf6_zebra_init(struct thread_master *); extern int config_write_ospf6_debug_zebra (struct vty *vty); From 6184c39e27d4b6f3721b8c4dc3df1b968e09606a Mon Sep 17 00:00:00 2001 From: Roman Hoog Antink Date: Mon, 17 Mar 2014 14:01:42 +0100 Subject: [PATCH 1011/1342] bgpd: implement admin distance Until today the admin distance cannot be configured for any IPv6 routing protocol. This patch implements it for bgp. Signed-off-by: Maitane Zotes patchwork #993: http://patchwork.quagga.net/patch/993/ --- bgpd/bgp_route.c | 257 ++++++++++++++++++++++++++++++++++++++++++----- bgpd/bgp_route.h | 3 +- bgpd/bgp_zebra.c | 8 ++ bgpd/bgpd.c | 4 +- bgpd/bgpd.h | 5 + 5 files changed, 251 insertions(+), 26 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c364372f8..494375f77 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -14844,12 +14844,12 @@ bgp_distance_set (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; - struct prefix_ipv4 p; + struct prefix p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; - ret = str2prefix_ipv4 (ip_str, &p); + ret = str2prefix (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); @@ -14891,12 +14891,12 @@ bgp_distance_unset (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; - struct prefix_ipv4 p; + struct prefix p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; - ret = str2prefix_ipv4 (ip_str, &p); + ret = str2prefix (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); @@ -15005,6 +15005,81 @@ bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) } } +#ifdef HAVE_IPV6 +/* Apply BGP information to ipv6 distance method. */ +u_char +ipv6_bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) +{ + struct bgp_node *rn; + struct prefix_ipv6 q; + struct peer *peer; + struct bgp_distance *bdistance; + struct access_list *alist; + struct bgp_static *bgp_static; + + if (! bgp) + return 0; + + if (p->family != AF_INET6) + return 0; + + peer = rinfo->peer; + + if (peer->su.sa.sa_family != AF_INET6) + return 0; + + memset (&q, 0, sizeof (struct prefix_ipv6)); + q.family = AF_INET; + q.prefix = peer->su.sin6.sin6_addr; + q.prefixlen = IPV6_MAX_BITLEN; + + /* Check source address. */ + rn = bgp_node_match (bgp_distance_table, (struct prefix *) &q); + if (rn) + { + bdistance = rn->info; + bgp_unlock_node (rn); + + if (bdistance->access_list) + { + alist = access_list_lookup (AFI_IP6, bdistance->access_list); + if (alist && access_list_apply (alist, p) == FILTER_PERMIT) + return bdistance->distance; + } + else + return bdistance->distance; + } + /* Backdoor check. */ + rn = bgp_node_lookup (bgp->route[AFI_IP6][SAFI_UNICAST], p); + if (rn) + { + bgp_static = rn->info; + bgp_unlock_node (rn); + + if (bgp_static->backdoor) + { + if (bgp->ipv6_distance_local) + return bgp->ipv6_distance_local; + else + return ZEBRA_IBGP_DISTANCE_DEFAULT; + } + } + + if (peer_sort (peer) == BGP_PEER_EBGP) + { + if (bgp->ipv6_distance_ebgp) + return bgp->ipv6_distance_ebgp; + return ZEBRA_EBGP_DISTANCE_DEFAULT; + } + else + { + if (bgp->ipv6_distance_ibgp) + return bgp->ipv6_distance_ibgp; + return ZEBRA_IBGP_DISTANCE_DEFAULT; + } +} +#endif /* HAVE_IPV6 */ + DEFUN (bgp_distance, bgp_distance_cmd, "distance bgp <1-255> <1-255> <1-255>", @@ -15099,6 +15174,102 @@ DEFUN (no_bgp_distance_source_access_list, return CMD_SUCCESS; } +#ifdef HAVE_IPV6 +DEFUN (ipv6_bgp_distance, + ipv6_bgp_distance_cmd, + "distance bgp <1-255> <1-255> <1-255>", + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + bgp->ipv6_distance_ebgp = atoi (argv[0]); + bgp->ipv6_distance_ibgp = atoi (argv[1]); + bgp->ipv6_distance_local = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_bgp_distance, + no_ipv6_bgp_distance_cmd, + "no distance bgp <1-255> <1-255> <1-255>", + NO_STR + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + bgp->ipv6_distance_ebgp= 0; + bgp->ipv6_distance_ibgp = 0; + bgp->ipv6_distance_local = 0; + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_bgp_distance, + no_ipv6_bgp_distance2_cmd, + "no distance bgp", + NO_STR + "Define an administrative distance\n" + "BGP distance\n") + +DEFUN (ipv6_bgp_distance_source, + ipv6_bgp_distance_source_cmd, + "distance <1-255> X:X::X:X/M", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") +{ + bgp_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_bgp_distance_source, + no_ipv6_bgp_distance_source_cmd, + "no distance <1-255> X:X::X:X/M", + NO_STR + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") +{ + bgp_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (ipv6_bgp_distance_source_access_list, + ipv6_bgp_distance_source_access_list_cmd, + "distance <1-255> X:X::X:X/M WORD", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") +{ + bgp_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_bgp_distance_source_access_list, + no_ipv6_bgp_distance_source_access_list_cmd, + "no distance <1-255> X:X::X:X/M WORD", + NO_STR + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") +{ + bgp_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} +#endif + DEFUN (bgp_damp_set, bgp_damp_set_cmd, "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", @@ -15661,30 +15832,59 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp, } int -bgp_config_write_distance (struct vty *vty, struct bgp *bgp) +bgp_config_write_distance (struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi, int *write) { struct bgp_node *rn; struct bgp_distance *bdistance; - /* Distance configuration. */ - if (bgp->distance_ebgp - && bgp->distance_ibgp - && bgp->distance_local - && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT - || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT - || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) - vty_out (vty, " distance bgp %d %d %d%s", - bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, - VTY_NEWLINE); - - for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) - if ((bdistance = rn->info) != NULL) - { - vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, - inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, - bdistance->access_list ? bdistance->access_list : "", - VTY_NEWLINE); - } + if (afi == AFI_IP && safi == SAFI_UNICAST) + { + /* Distance configuration. */ + if (bgp->distance_ebgp + && bgp->distance_ibgp + && bgp->distance_local + && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT + || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT + || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) + vty_out (vty, " distance bgp %d %d %d%s", + bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, + VTY_NEWLINE); + + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + bdistance->access_list ? bdistance->access_list : "", + VTY_NEWLINE); + } + } + +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6 && safi == SAFI_UNICAST) + { + bgp_config_write_family_header (vty, afi, safi, write); + if (bgp->ipv6_distance_ebgp + && bgp->ipv6_distance_ibgp + && bgp->ipv6_distance_local + && (bgp->ipv6_distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT + || bgp->ipv6_distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT + || bgp->ipv6_distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) + vty_out (vty, " distance bgp %d %d %d%s", + bgp->ipv6_distance_ebgp, bgp->ipv6_distance_ibgp, bgp->ipv6_distance_local, + VTY_NEWLINE); + + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, + inet6_ntoa (rn->p.u.prefix6), rn->p.prefixlen, + bdistance->access_list ? bdistance->access_list : "", + VTY_NEWLINE); + } + } +#endif /* HAVE_IPV6 */ return 0; } @@ -16253,6 +16453,15 @@ bgp_route_init (void) install_element (BGP_NODE, &no_bgp_distance_source_cmd); install_element (BGP_NODE, &bgp_distance_source_access_list_cmd); install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd); +#ifdef HAVE_IPV6 + install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance2_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_source_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_source_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_source_access_list_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_source_access_list_cmd); +#endif /* HAVE_IPV6 */ install_element (BGP_NODE, &bgp_damp_set_cmd); install_element (BGP_NODE, &bgp_damp_set2_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index c80375925..8483f3dac 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -227,7 +227,7 @@ extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *, /* for bgp_nexthop and bgp_damp */ extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); extern int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *); -extern int bgp_config_write_distance (struct vty *, struct bgp *); +extern int bgp_config_write_distance (struct vty *, struct bgp *, afi_t, safi_t, int *); extern void bgp_aggregate_increment (struct bgp *, struct prefix *, struct bgp_info *, afi_t, safi_t); @@ -235,6 +235,7 @@ extern void bgp_aggregate_decrement (struct bgp *, struct prefix *, struct bgp_i afi_t, safi_t); extern u_char bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); +extern u_char ipv6_bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); extern afi_t bgp_node_afi (struct vty *); extern safi_t bgp_node_safi (struct vty *); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d0b9216a8..4066a9a18 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -814,6 +814,14 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + distance = ipv6_bgp_distance_apply (p, info, bgp); + + if (distance) + { + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = distance; + } + if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 249d20f32..351701177 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5367,6 +5367,8 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi, bgp_config_write_maxpaths (vty, bgp, afi, safi, &write); + bgp_config_write_distance (vty, bgp, afi, safi, &write); + if (write) vty_out (vty, " exit-address-family%s", VTY_NEWLINE); @@ -5547,7 +5549,7 @@ bgp_config_write (struct vty *vty) bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* Distance configuration. */ - bgp_config_write_distance (vty, bgp); + bgp_config_write_distance (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* No auto-summary */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7665d9d00..d8e687bcc 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -156,6 +156,11 @@ struct bgp u_char distance_ebgp; u_char distance_ibgp; u_char distance_local; + + /* BGP ipv6 distance configuration. */ + u_char ipv6_distance_ebgp; + u_char ipv6_distance_ibgp; + u_char ipv6_distance_local; /* BGP default local-preference. */ u_int32_t default_local_pref; From a3936d04942795bb92f04fefd25957c327e31c20 Mon Sep 17 00:00:00 2001 From: Boian Bonev Date: Wed, 25 Jun 2014 20:26:44 +0300 Subject: [PATCH 1012/1342] bgpd: add aspath_aggregate_mpath that preserves path length Issue - when two aspaths are aggregated the result will be with different length if the two paths do not share common prefix. E.g.: aggregation of 100 101 400 500 and 200 201 400 500 currently will result in {100,101,200,201,400,500} which is of much shorter length and is not ok to be readvertised becase may create shortest path on the internet and cause infinite flapping. aspath_aggregate_mpath will construct the followin path for the above example: {100,200} {101,201} 400 500 Signed-off-by: Boian Bonev patchwork #994: http://patchwork.quagga.net/patch/994/ --- bgpd/bgp_aspath.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_aspath.h | 1 + bgpd/bgp_mpath.c | 2 +- 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 6ab293765..49b65b628 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1099,6 +1099,128 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) return aspath; } +/* Modify as1 using as2 for aggregation for multipath, keeping the + * AS-Path length the same, and so minimising change to the preference + * of the mpath aggregrate route. + */ +struct aspath * +aspath_aggregate_mpath (struct aspath *as1, struct aspath *as2) +{ + int i; + int minlen; + int match; + int from1,from2; + struct assegment *seg1 = as1->segments; + struct assegment *seg2 = as2->segments; + struct aspath *aspath = NULL; + struct assegment *asset; + struct assegment *prevseg = NULL; + + match = 0; + minlen = 0; + aspath = NULL; + asset = NULL; + + /* First of all check common leading sequence. */ + while (seg1 && seg2) + { + /* Check segment type. */ + if (seg1->type != seg2->type) + break; + + /* Minimum segment length. */ + minlen = min (seg1->length, seg2->length); + + for (match = 0; match < minlen; match++) + if (seg1->as[match] != seg2->as[match]) + break; + + if (match) + { + struct assegment *seg = assegment_new (seg1->type, 0); + + seg = assegment_append_asns (seg, seg1->as, match); + + if (! aspath) + { + aspath = aspath_new (); + aspath->segments = seg; + } + else + prevseg->next = seg; + + prevseg = seg; + } + + if (match != minlen || match != seg1->length + || seg1->length != seg2->length) + break; + + seg1 = seg1->next; + seg2 = seg2->next; + } + + if (! aspath) + aspath = aspath_new(); + + /* Make as-set using rest of all information. */ + from1 = from2 = match; + while (seg1 || seg2) + { + if (seg1) + { + if (seg1->type == AS_SEQUENCE) + { + asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[from1]); + from1++; + if (from1 >= seg1->length) + { + from1 = 0; + seg1 = seg1->next; + } + } + else + { + for (i = from1; i < seg1->length; i++) + asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]); + + from1 = 0; + seg1 = seg1->next; + } + } + + if (seg2) + { + if (seg2->type == AS_SEQUENCE) + { + asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[from2]); + from2++; + if (from2 >= seg2->length) + { + from2 = 0; + seg2 = seg2->next; + } + } + else + { + for (i = from2; i < seg2->length; i++) + asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]); + + from2 = 0; + seg2 = seg2->next; + } + } + + if (asset->length == 1) + asset->type = AS_SEQUENCE; + asset = NULL; + } + + assegment_normalise (aspath->segments); + aspath_str_update (aspath); + return aspath; +} + /* When a BGP router receives an UPDATE with an MP_REACH_NLRI attribute, check the leftmost AS number in the AS_PATH attribute is or not the peer's AS number. */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 1311f8a5a..2f0a5195c 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -69,6 +69,7 @@ extern void aspath_finish (void); extern struct aspath *aspath_parse (struct stream *, size_t, int); extern struct aspath *aspath_dup (struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); +extern struct aspath *aspath_aggregate_mpath (struct aspath *, struct aspath *); extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); extern struct aspath *aspath_add_seq_n (struct aspath *, as_t, unsigned); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 8e78aafe0..48694c633 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -695,7 +695,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { - asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath); + asmerge = aspath_aggregate_mpath (aspath, mpinfo->attr->aspath); aspath_free (aspath); aspath = asmerge; From 2074d6752d1dafcd6511677e2bdc9bbe0b73c388 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 10 Sep 2014 16:50:42 +0200 Subject: [PATCH 1013/1342] lib: simplify distribute.c's code. Use loops and variables instead of doing each cases by hand. Use static functions instead of rewriting code. --- lib/distribute.c | 296 ++++++++++++++++++++--------------------------- 1 file changed, 124 insertions(+), 172 deletions(-) diff --git a/lib/distribute.c b/lib/distribute.c index ba8043cf9..4603e13ef 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -45,22 +45,33 @@ distribute_new (void) static void distribute_free (struct distribute *dist) { + int i = 0; if (dist->ifname) XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname); - if (dist->list[DISTRIBUTE_IN]) - free (dist->list[DISTRIBUTE_IN]); - if (dist->list[DISTRIBUTE_OUT]) - free (dist->list[DISTRIBUTE_OUT]); + for (i=0; i < DISTRIBUTE_MAX; i++) + if (dist->list[i]) + free(dist->list[i]); - if (dist->prefix[DISTRIBUTE_IN]) - free (dist->prefix[DISTRIBUTE_IN]); - if (dist->prefix[DISTRIBUTE_OUT]) - free (dist->prefix[DISTRIBUTE_OUT]); + for (i=0; i < DISTRIBUTE_MAX; i++) + if (dist->prefix[i]) + free(dist->prefix[i]); XFREE (MTYPE_DISTRIBUTE, dist); } +static void +distribute_free_if_empty(struct distribute *dist) +{ + int i; + for (i=0; i < DISTRIBUTE_MAX; i++) + if (dist->list[i] != NULL || dist->prefix[i] != NULL) + return; + + hash_release (disthash, dist); + distribute_free (dist); +} + /* Lookup interface's distribute list. */ struct distribute * distribute_lookup (const char *ifname) @@ -136,36 +147,27 @@ distribute_cmp (const struct distribute *dist1, const struct distribute *dist2) /* Set access-list name to the distribute list. */ static struct distribute * -distribute_list_set (const char *ifname, enum distribute_type type, +distribute_list_set (const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; dist = distribute_get (ifname); - if (type == DISTRIBUTE_IN) - { - if (dist->list[DISTRIBUTE_IN]) - free (dist->list[DISTRIBUTE_IN]); - dist->list[DISTRIBUTE_IN] = strdup (alist_name); - } - if (type == DISTRIBUTE_OUT) - { - if (dist->list[DISTRIBUTE_OUT]) - free (dist->list[DISTRIBUTE_OUT]); - dist->list[DISTRIBUTE_OUT] = strdup (alist_name); - } + if (dist->list[type]) + free (dist->list[type]); + dist->list[type] = strdup (alist_name); /* Apply this distribute-list to the interface. */ (*distribute_add_hook) (dist); - + return dist; } /* Unset distribute-list. If matched distribute-list exist then return 1. */ static int -distribute_list_unset (const char *ifname, enum distribute_type type, +distribute_list_unset (const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; @@ -174,41 +176,19 @@ distribute_list_unset (const char *ifname, enum distribute_type type, if (!dist) return 0; - if (type == DISTRIBUTE_IN) - { - if (!dist->list[DISTRIBUTE_IN]) - return 0; - if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0) - return 0; - - free (dist->list[DISTRIBUTE_IN]); - dist->list[DISTRIBUTE_IN] = NULL; - } - - if (type == DISTRIBUTE_OUT) - { - if (!dist->list[DISTRIBUTE_OUT]) - return 0; - if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0) - return 0; + if (!dist->list[type]) + return 0; + if (strcmp (dist->list[type], alist_name) != 0) + return 0; - free (dist->list[DISTRIBUTE_OUT]); - dist->list[DISTRIBUTE_OUT] = NULL; - } + free (dist->list[type]); + dist->list[type] = NULL; /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); - /* If both out and in is NULL then free distribute list. */ - if (dist->list[DISTRIBUTE_IN] == NULL && - dist->list[DISTRIBUTE_OUT] == NULL && - dist->prefix[DISTRIBUTE_IN] == NULL && - dist->prefix[DISTRIBUTE_OUT] == NULL) - { - hash_release (disthash, dist); - distribute_free (dist); - } - + /* If all dist are NULL, then free distribute list. */ + distribute_free_if_empty(dist); return 1; } @@ -221,18 +201,9 @@ distribute_list_prefix_set (const char *ifname, enum distribute_type type, dist = distribute_get (ifname); - if (type == DISTRIBUTE_IN) - { - if (dist->prefix[DISTRIBUTE_IN]) - free (dist->prefix[DISTRIBUTE_IN]); - dist->prefix[DISTRIBUTE_IN] = strdup (plist_name); - } - if (type == DISTRIBUTE_OUT) - { - if (dist->prefix[DISTRIBUTE_OUT]) - free (dist->prefix[DISTRIBUTE_OUT]); - dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name); - } + if (dist->prefix[type]) + free (dist->prefix[type]); + dist->prefix[type] = strdup (plist_name); /* Apply this distribute-list to the interface. */ (*distribute_add_hook) (dist); @@ -252,41 +223,19 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type, if (!dist) return 0; - if (type == DISTRIBUTE_IN) - { - if (!dist->prefix[DISTRIBUTE_IN]) - return 0; - if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0) - return 0; - - free (dist->prefix[DISTRIBUTE_IN]); - dist->prefix[DISTRIBUTE_IN] = NULL; - } - - if (type == DISTRIBUTE_OUT) - { - if (!dist->prefix[DISTRIBUTE_OUT]) - return 0; - if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0) - return 0; + if (!dist->prefix[type]) + return 0; + if (strcmp (dist->prefix[type], plist_name) != 0) + return 0; - free (dist->prefix[DISTRIBUTE_OUT]); - dist->prefix[DISTRIBUTE_OUT] = NULL; - } + free (dist->prefix[type]); + dist->prefix[type] = NULL; /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); - /* If both out and in is NULL then free distribute list. */ - if (dist->list[DISTRIBUTE_IN] == NULL && - dist->list[DISTRIBUTE_OUT] == NULL && - dist->prefix[DISTRIBUTE_IN] == NULL && - dist->prefix[DISTRIBUTE_OUT] == NULL) - { - hash_release (disthash, dist); - distribute_free (dist); - } - + /* If all dist are NULL, then free distribute list. */ + distribute_free_if_empty(dist); return 1; } @@ -394,7 +343,7 @@ DEFUN (distribute_list, distribute_list_set (argv[2], type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (distribute_list, ipv6_distribute_list_cmd, @@ -435,7 +384,7 @@ DEFUN (no_distribute_list, no_distribute_list_cmd, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_distribute_list, no_ipv6_distribute_list_cmd, "no distribute-list WORD (in|out) WORD", @@ -473,7 +422,7 @@ DEFUN (distribute_list_prefix_all, distribute_list_prefix_set (NULL, type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (distribute_list_prefix_all, ipv6_distribute_list_prefix_all_cmd, @@ -516,7 +465,7 @@ DEFUN (no_distribute_list_prefix_all, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_distribute_list_prefix_all, no_ipv6_distribute_list_prefix_all_cmd, @@ -555,7 +504,7 @@ DEFUN (distribute_list_prefix, distribute_list_prefix_cmd, distribute_list_prefix_set (argv[2], type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (distribute_list_prefix, ipv6_distribute_list_prefix_cmd, "distribute-list prefix WORD (in|out) WORD", @@ -598,7 +547,7 @@ DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd, "no distribute-list prefix WORD (in|out) WORD", @@ -610,80 +559,96 @@ ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd, "Filter outgoing routing updates\n" "Interface name\n") +static int +distribute_print (struct vty *vty, char *tab[], int is_prefix, + enum distribute_type type, int has_print) +{ + if (tab[type]) { + vty_out (vty, "%s %s%s", + has_print ? "," : "", + is_prefix ? "(prefix-list) " : "", + tab[type]); + return 1; + } + return has_print; +} + int config_show_distribute (struct vty *vty) { unsigned int i; + int has_print = 0; struct hash_backet *mp; struct distribute *dist; /* Output filter configuration. */ dist = distribute_lookup (NULL); - if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])) + vty_out(vty, " Outgoing update filter list for all interface is"); + has_print = 0; + if (dist) { - vty_out (vty, " Outgoing update filter list for all interface is"); - if (dist->list[DISTRIBUTE_OUT]) - vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); - if (dist->prefix[DISTRIBUTE_OUT]) - vty_out (vty, "%s (prefix-list) %s", - dist->list[DISTRIBUTE_OUT] ? "," : "", - dist->prefix[DISTRIBUTE_OUT]); - vty_out (vty, "%s", VTY_NEWLINE); + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_OUT, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_OUT, has_print); } + if (has_print) + vty_out (vty, "%s", VTY_NEWLINE); else - vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE); + vty_out (vty, " not set%s", VTY_NEWLINE); for (i = 0; i < disthash->size; i++) for (mp = disthash->index[i]; mp; mp = mp->next) { dist = mp->data; if (dist->ifname) - if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]) - { - vty_out (vty, " %s filtered by", dist->ifname); - if (dist->list[DISTRIBUTE_OUT]) - vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); - if (dist->prefix[DISTRIBUTE_OUT]) - vty_out (vty, "%s (prefix-list) %s", - dist->list[DISTRIBUTE_OUT] ? "," : "", - dist->prefix[DISTRIBUTE_OUT]); - vty_out (vty, "%s", VTY_NEWLINE); - } + { + vty_out (vty, " %s filtered by", dist->ifname); + has_print = 0; + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_OUT, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_OUT, has_print); + if (has_print) + vty_out (vty, "%s", VTY_NEWLINE); + else + vty_out(vty, " nothing%s", VTY_NEWLINE); + } } /* Input filter configuration. */ dist = distribute_lookup (NULL); - if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])) + vty_out(vty, " Incoming update filter list for all interface is"); + has_print = 0; + if (dist) { - vty_out (vty, " Incoming update filter list for all interface is"); - if (dist->list[DISTRIBUTE_IN]) - vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); - if (dist->prefix[DISTRIBUTE_IN]) - vty_out (vty, "%s (prefix-list) %s", - dist->list[DISTRIBUTE_IN] ? "," : "", - dist->prefix[DISTRIBUTE_IN]); - vty_out (vty, "%s", VTY_NEWLINE); - } + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_IN, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_IN, has_print); } + if (has_print) + vty_out (vty, "%s", VTY_NEWLINE); else - vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE); + vty_out (vty, " not set%s", VTY_NEWLINE); for (i = 0; i < disthash->size; i++) for (mp = disthash->index[i]; mp; mp = mp->next) { dist = mp->data; - if (dist->ifname) - if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]) - { - vty_out (vty, " %s filtered by", dist->ifname); - if (dist->list[DISTRIBUTE_IN]) - vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); - if (dist->prefix[DISTRIBUTE_IN]) - vty_out (vty, "%s (prefix-list) %s", - dist->list[DISTRIBUTE_IN] ? "," : "", - dist->prefix[DISTRIBUTE_IN]); - vty_out (vty, "%s", VTY_NEWLINE); - } + if (dist->ifname) + { + vty_out (vty, " %s filtered by", dist->ifname); + has_print = 0; + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_IN, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_IN, has_print); + if (has_print) + vty_out (vty, "%s", VTY_NEWLINE); + else + vty_out(vty, " nothing%s", VTY_NEWLINE); + } } return 0; } @@ -693,6 +658,8 @@ int config_write_distribute (struct vty *vty) { unsigned int i; + int j; + int output; struct hash_backet *mp; int write = 0; @@ -703,38 +670,23 @@ config_write_distribute (struct vty *vty) dist = mp->data; - if (dist->list[DISTRIBUTE_IN]) - { - vty_out (vty, " distribute-list %s in %s%s", - dist->list[DISTRIBUTE_IN], - dist->ifname ? dist->ifname : "", - VTY_NEWLINE); - write++; - } - - if (dist->list[DISTRIBUTE_OUT]) - { - vty_out (vty, " distribute-list %s out %s%s", - - dist->list[DISTRIBUTE_OUT], - dist->ifname ? dist->ifname : "", - VTY_NEWLINE); - write++; - } - - if (dist->prefix[DISTRIBUTE_IN]) - { - vty_out (vty, " distribute-list prefix %s in %s%s", - dist->prefix[DISTRIBUTE_IN], + for (j=0; j < DISTRIBUTE_MAX; j++) + if (dist->list[j]) { + output = j == DISTRIBUTE_OUT; + vty_out (vty, " distribute-list %s %s %s%s", + dist->list[j], + output ? "out" : "in", dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; } - if (dist->prefix[DISTRIBUTE_OUT]) - { - vty_out (vty, " distribute-list prefix %s out %s%s", - dist->prefix[DISTRIBUTE_OUT], + for (j=0; j < DISTRIBUTE_MAX; j++) + if (dist->prefix[j]) { + output = j == DISTRIBUTE_OUT; + vty_out (vty, " distribute-list prefix %s %s %s%s", + dist->prefix[j], + output ? "out" : "in", dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; From fafa899b4e84c7b9fd07b076517744d9351aaa6b Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 10 Sep 2014 16:50:43 +0200 Subject: [PATCH 1014/1342] ripd: code simplification for redistribution. Use loops and variables instead of doing each cases by hand. Use boolean instead of having 2 almost identical functions. --- ripd/ripd.c | 116 +++++++++++----------------------------------------- 1 file changed, 24 insertions(+), 92 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index 1d3eb4c50..990db60a7 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -315,32 +315,35 @@ rip_timeout_update (struct rip_info *rinfo) } static int -rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri) +rip_filter (int rip_distribute, struct prefix_ipv4 *p, struct rip_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; + int distribute = rip_distribute == RIP_FILTER_OUT ? + DISTRIBUTE_OUT : DISTRIBUTE_IN; + const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ - if (ri->list[RIP_FILTER_IN]) + if (ri->list[rip_distribute]) { - if (access_list_apply (ri->list[RIP_FILTER_IN], + if (access_list_apply (ri->list[rip_distribute], (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute in", - inet_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by distribute %s", + inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } - if (ri->prefix[RIP_FILTER_IN]) + if (ri->prefix[rip_distribute]) { - if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], + if (prefix_list_apply (ri->prefix[rip_distribute], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list in", - inet_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by prefix-list %s", + inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } @@ -349,104 +352,33 @@ rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri) dist = distribute_lookup (NULL); if (dist) { - if (dist->list[DISTRIBUTE_IN]) + if (dist->list[distribute]) { - alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); - - if (alist) - { - if (access_list_apply (alist, - (struct prefix *) p) == FILTER_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute in", - inet_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - } - if (dist->prefix[DISTRIBUTE_IN]) - { - plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); - - if (plist) - { - if (prefix_list_apply (plist, - (struct prefix *) p) == PREFIX_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list in", - inet_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - } - } - return 0; -} + alist = access_list_lookup (AFI_IP, dist->list[distribute]); -static int -rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri) -{ - struct distribute *dist; - struct access_list *alist; - struct prefix_list *plist; - - if (ri->list[RIP_FILTER_OUT]) - { - if (access_list_apply (ri->list[RIP_FILTER_OUT], - (struct prefix *) p) == FILTER_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d is filtered by distribute out", - inet_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - if (ri->prefix[RIP_FILTER_OUT]) - { - if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT], - (struct prefix *) p) == PREFIX_DENY) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d is filtered by prefix-list out", - inet_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - - /* All interface filter check. */ - dist = distribute_lookup (NULL); - if (dist) - { - if (dist->list[DISTRIBUTE_OUT]) - { - alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); - if (alist) { - if (access_list_apply (alist, - (struct prefix *) p) == FILTER_DENY) + if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute out", - inet_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by distribute %s", + inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } } - if (dist->prefix[DISTRIBUTE_OUT]) + if (dist->prefix[distribute]) { - plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); - + plist = prefix_list_lookup (AFI_IP, dist->prefix[distribute]); + if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list out", - inet_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by prefix-list %s", + inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } @@ -509,7 +441,7 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from, /* Apply input filters. */ ri = ifp->info; - ret = rip_incoming_filter (&p, ri); + ret = rip_filter (RIP_FILTER_IN, &p, ri); if (ret < 0) return; @@ -2294,7 +2226,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, p = (struct prefix_ipv4 *) &rp->p; /* Apply output filters. */ - ret = rip_outgoing_filter (p, ri); + ret = rip_filter (RIP_FILTER_OUT, p, ri); if (ret < 0) continue; From 543e791be9257e60d4d02abd0cdac7337a31636a Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 10 Sep 2014 16:50:44 +0200 Subject: [PATCH 1015/1342] ripngd: code simplification for redistribution. Use loops and variables instead of doing each cases by hand. Use boolean instead of having 2 almost identical functions. --- ripngd/ripngd.c | 116 +++++++++++------------------------------------- 1 file changed, 25 insertions(+), 91 deletions(-) diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index d27d45b22..dd5444060 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -608,32 +608,36 @@ ripng_timeout_update (struct ripng_info *rinfo) } static int -ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) +ripng_filter (int ripng_distribute, struct prefix_ipv6 *p, + struct ripng_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; + int distribute = ripng_distribute == RIPNG_FILTER_OUT ? + DISTRIBUTE_OUT : DISTRIBUTE_IN; + const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ - if (ri->list[RIPNG_FILTER_IN]) + if (ri->list[ripng_distribute]) { - if (access_list_apply (ri->list[RIPNG_FILTER_IN], + if (access_list_apply (ri->list[ripng_distribute], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute in", - inet6_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by distribute %s", + inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } - if (ri->prefix[RIPNG_FILTER_IN]) + if (ri->prefix[ripng_distribute]) { - if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], + if (prefix_list_apply (ri->prefix[ripng_distribute], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list in", - inet6_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by prefix-list %s", + inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } @@ -642,104 +646,34 @@ ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) dist = distribute_lookup (NULL); if (dist) { - if (dist->list[DISTRIBUTE_IN]) + if (dist->list[distribute]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); - - if (alist) - { - if (access_list_apply (alist, - (struct prefix *) p) == FILTER_DENY) - { - if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute in", - inet6_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - } - if (dist->prefix[DISTRIBUTE_IN]) - { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); - - if (plist) - { - if (prefix_list_apply (plist, - (struct prefix *) p) == PREFIX_DENY) - { - if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list in", - inet6_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - } - } - return 0; -} + alist = access_list_lookup (AFI_IP6, dist->list[distribute]); -static int -ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) -{ - struct distribute *dist; - struct access_list *alist; - struct prefix_list *plist; - - if (ri->list[RIPNG_FILTER_OUT]) - { - if (access_list_apply (ri->list[RIPNG_FILTER_OUT], - (struct prefix *) p) == FILTER_DENY) - { - if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d is filtered by distribute out", - inet6_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - if (ri->prefix[RIPNG_FILTER_OUT]) - { - if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], - (struct prefix *) p) == PREFIX_DENY) - { - if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d is filtered by prefix-list out", - inet6_ntoa (p->prefix), p->prefixlen); - return -1; - } - } - - /* All interface filter check. */ - dist = distribute_lookup (NULL); - if (dist) - { - if (dist->list[DISTRIBUTE_OUT]) - { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); - if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by distribute out", - inet6_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by distribute %s", + inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } } - if (dist->prefix[DISTRIBUTE_OUT]) + if (dist->prefix[distribute]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); - + plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); + if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) - zlog_debug ("%s/%d filtered by prefix-list out", - inet6_ntoa (p->prefix), p->prefixlen); + zlog_debug ("%s/%d filtered by prefix-list %s", + inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } @@ -779,7 +713,7 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, /* Apply input filters. */ ri = ifp->info; - ret = ripng_incoming_filter (&p, ri); + ret = ripng_filter (RIPNG_FILTER_IN, &p, ri); if (ret < 0) return; @@ -1674,7 +1608,7 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, rinfo->nexthop_out = rinfo->nexthop; /* Apply output filters. */ - ret = ripng_outgoing_filter (p, ri); + ret = ripng_filter (RIPNG_FILTER_OUT, p, ri); if (ret < 0) continue; @@ -1803,7 +1737,7 @@ ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out)); /* Apply output filters.*/ - ret = ripng_outgoing_filter (p, ri); + ret = ripng_filter (RIPNG_FILTER_OUT, p, ri); if (ret < 0) continue; From df2ef24fb73c83a6e733be9eb8cac3e0df8467f8 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 10 Sep 2014 16:50:45 +0200 Subject: [PATCH 1016/1342] lib: Make distribute.c accepts both v4 and v6. distribute.c doesn't allow to manage both v4 and v6 distribute lists. This patch fix this problem by having 4 DISTRIBUTE* values in the enumeration instead of two. The code in all daemons using distribute.c is adapted. --- lib/distribute.c | 380 +++++++++++++++++++++++++++++++++++++++++------ lib/distribute.h | 6 +- ripd/ripd.c | 18 +-- ripngd/ripngd.c | 18 +-- 4 files changed, 355 insertions(+), 67 deletions(-) diff --git a/lib/distribute.c b/lib/distribute.c index 4603e13ef..583befb36 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -251,9 +251,9 @@ DEFUN (distribute_list_all, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", @@ -267,8 +267,36 @@ DEFUN (distribute_list_all, return CMD_SUCCESS; } -ALIAS (distribute_list_all, +DEFUN (ipv6_distribute_list_all, ipv6_distribute_list_all_cmd, + "ipv6 distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + distribute_list_set (NULL, type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (ipv6_distribute_list_all, + ipv6_as_v4_distribute_list_all_cmd, "distribute-list WORD (in|out)", "Filter networks in routing updates\n" "Access-list name\n" @@ -289,9 +317,9 @@ DEFUN (no_distribute_list_all, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", @@ -308,8 +336,41 @@ DEFUN (no_distribute_list_all, return CMD_SUCCESS; } -ALIAS (no_distribute_list_all, +DEFUN (no_ipv6_distribute_list_all, no_ipv6_distribute_list_all_cmd, + "no ipv6 distribute-list WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_unset (NULL, type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_distribute_list_all, + no_ipv6_as_v4_distribute_list_all_cmd, "no distribute-list WORD (in|out)", NO_STR "Filter networks in routing updates\n" @@ -330,9 +391,9 @@ DEFUN (distribute_list, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); @@ -345,8 +406,36 @@ DEFUN (distribute_list, return CMD_SUCCESS; } -ALIAS (distribute_list, +DEFUN (ipv6_distribute_list, ipv6_distribute_list_cmd, + "ipv6 distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + distribute_list_set (argv[2], type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (ipv6_distribute_list, + ipv6_as_v4_distribute_list_cmd, "distribute-list WORD (in|out) WORD", "Filter networks in routing updates\n" "Access-list name\n" @@ -368,9 +457,9 @@ DEFUN (no_distribute_list, no_distribute_list_cmd, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); @@ -386,7 +475,41 @@ DEFUN (no_distribute_list, no_distribute_list_cmd, return CMD_SUCCESS; } -ALIAS (no_distribute_list, no_ipv6_distribute_list_cmd, +DEFUN (no_ipv6_distribute_list, + no_ipv6_distribute_list_cmd, + "no ipv6 distribute-list WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_unset (argv[2], type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_distribute_list, + no_ipv6_as_v4_distribute_list_cmd, "no distribute-list WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" @@ -408,12 +531,12 @@ DEFUN (distribute_list_prefix_all, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -424,8 +547,37 @@ DEFUN (distribute_list_prefix_all, return CMD_SUCCESS; } -ALIAS (distribute_list_prefix_all, +DEFUN (ipv6_distribute_list_prefix_all, ipv6_distribute_list_prefix_all_cmd, + "ipv6 distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + distribute_list_prefix_set (NULL, type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (ipv6_distribute_list_prefix_all, + ipv6_as_v4_distribute_list_prefix_all_cmd, "distribute-list prefix WORD (in|out)", "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" @@ -448,12 +600,12 @@ DEFUN (no_distribute_list_prefix_all, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -467,8 +619,42 @@ DEFUN (no_distribute_list_prefix_all, return CMD_SUCCESS; } -ALIAS (no_distribute_list_prefix_all, +DEFUN (no_ipv6_distribute_list_prefix_all, no_ipv6_distribute_list_prefix_all_cmd, + "no ipv6 distribute-list prefix WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_prefix_unset (NULL, type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_distribute_list_prefix_all, + no_ipv6_as_v4_distribute_list_prefix_all_cmd, "no distribute-list prefix WORD (in|out)", NO_STR "Filter networks in routing updates\n" @@ -490,12 +676,12 @@ DEFUN (distribute_list_prefix, distribute_list_prefix_cmd, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -506,7 +692,38 @@ DEFUN (distribute_list_prefix, distribute_list_prefix_cmd, return CMD_SUCCESS; } -ALIAS (distribute_list_prefix, ipv6_distribute_list_prefix_cmd, +DEFUN (ipv6_distribute_list_prefix, + ipv6_distribute_list_prefix_cmd, + "ipv6 distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + distribute_list_prefix_set (argv[2], type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (ipv6_distribute_list_prefix, + ipv6_as_v4_distribute_list_prefix_cmd, "distribute-list prefix WORD (in|out) WORD", "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" @@ -530,12 +747,12 @@ DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd, /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) - type = DISTRIBUTE_IN; + type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) - type = DISTRIBUTE_OUT; + type = DISTRIBUTE_V4_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -549,7 +766,43 @@ DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd, return CMD_SUCCESS; } -ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd, +DEFUN (no_ipv6_distribute_list_prefix, + no_ipv6_distribute_list_prefix_cmd, + "no ipv6 distribute-list prefix WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_V6_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_V6_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_prefix_unset (argv[2], type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_distribute_list_prefix, + no_ipv6_as_v4_distribute_list_prefix_cmd, "no distribute-list prefix WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" @@ -588,9 +841,13 @@ config_show_distribute (struct vty *vty) if (dist) { has_print = distribute_print(vty, dist->list, 0, - DISTRIBUTE_OUT, has_print); + DISTRIBUTE_V4_OUT, has_print); has_print = distribute_print(vty, dist->prefix, 1, - DISTRIBUTE_OUT, has_print); + DISTRIBUTE_V4_OUT, has_print); + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_V6_OUT, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_V6_OUT, has_print); } if (has_print) vty_out (vty, "%s", VTY_NEWLINE); @@ -606,9 +863,13 @@ config_show_distribute (struct vty *vty) vty_out (vty, " %s filtered by", dist->ifname); has_print = 0; has_print = distribute_print(vty, dist->list, 0, - DISTRIBUTE_OUT, has_print); + DISTRIBUTE_V4_OUT, has_print); has_print = distribute_print(vty, dist->prefix, 1, - DISTRIBUTE_OUT, has_print); + DISTRIBUTE_V4_OUT, has_print); + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_V6_OUT, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_V6_OUT, has_print); if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else @@ -624,9 +885,14 @@ config_show_distribute (struct vty *vty) if (dist) { has_print = distribute_print(vty, dist->list, 0, - DISTRIBUTE_IN, has_print); + DISTRIBUTE_V4_IN, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_V4_IN, has_print); + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_V6_IN, has_print); has_print = distribute_print(vty, dist->prefix, 1, - DISTRIBUTE_IN, has_print); } + DISTRIBUTE_V6_IN, has_print); + } if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else @@ -641,9 +907,13 @@ config_show_distribute (struct vty *vty) vty_out (vty, " %s filtered by", dist->ifname); has_print = 0; has_print = distribute_print(vty, dist->list, 0, - DISTRIBUTE_IN, has_print); + DISTRIBUTE_V4_IN, has_print); + has_print = distribute_print(vty, dist->prefix, 1, + DISTRIBUTE_V4_IN, has_print); + has_print = distribute_print(vty, dist->list, 0, + DISTRIBUTE_V6_IN, has_print); has_print = distribute_print(vty, dist->prefix, 1, - DISTRIBUTE_IN, has_print); + DISTRIBUTE_V6_IN, has_print); if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else @@ -659,7 +929,7 @@ config_write_distribute (struct vty *vty) { unsigned int i; int j; - int output; + int output, v6; struct hash_backet *mp; int write = 0; @@ -672,8 +942,10 @@ config_write_distribute (struct vty *vty) for (j=0; j < DISTRIBUTE_MAX; j++) if (dist->list[j]) { - output = j == DISTRIBUTE_OUT; - vty_out (vty, " distribute-list %s %s %s%s", + output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT; + v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT; + vty_out (vty, " %sdistribute-list %s %s %s%s", + v6 ? "ipv6 " : "", dist->list[j], output ? "out" : "in", dist->ifname ? dist->ifname : "", @@ -683,8 +955,10 @@ config_write_distribute (struct vty *vty) for (j=0; j < DISTRIBUTE_MAX; j++) if (dist->prefix[j]) { - output = j == DISTRIBUTE_OUT; - vty_out (vty, " distribute-list prefix %s %s %s%s", + output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT; + v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT; + vty_out (vty, " %sdistribute-list prefix %s %s %s%s", + v6 ? "ipv6 " : "", dist->prefix[j], output ? "out" : "in", dist->ifname ? dist->ifname : "", @@ -708,8 +982,8 @@ distribute_list_init (int node) { disthash = hash_create (distribute_hash_make, (int (*) (const void *, const void *)) distribute_cmp); - - if(node==RIP_NODE) { + /* install v4 */ + if (node == RIP_NODE || node == BABEL_NODE) { install_element (node, &distribute_list_all_cmd); install_element (node, &no_distribute_list_all_cmd); install_element (node, &distribute_list_cmd); @@ -718,10 +992,10 @@ distribute_list_init (int node) install_element (node, &no_distribute_list_prefix_all_cmd); install_element (node, &distribute_list_prefix_cmd); install_element (node, &no_distribute_list_prefix_cmd); - } else if (node == RIPNG_NODE || node == BABEL_NODE) { - /* WARNING: two identical commands installed do a crash, so be worry with - aliases. For this reason, and because all these commands are aliases, Babel - is not set with RIP. */ + } + + /* install v6 */ + if (node == RIPNG_NODE || node == BABEL_NODE) { install_element (node, &ipv6_distribute_list_all_cmd); install_element (node, &no_ipv6_distribute_list_all_cmd); install_element (node, &ipv6_distribute_list_cmd); @@ -731,4 +1005,16 @@ distribute_list_init (int node) install_element (node, &ipv6_distribute_list_prefix_cmd); install_element (node, &no_ipv6_distribute_list_prefix_cmd); } + + /* install v4 syntax command for v6 only protocols. */ + if (node == RIPNG_NODE) { + install_element (node, &ipv6_as_v4_distribute_list_all_cmd); + install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd); + install_element (node, &ipv6_as_v4_distribute_list_cmd); + install_element (node, &no_ipv6_as_v4_distribute_list_cmd); + install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd); + install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd); + install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd); + install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd); + } } diff --git a/lib/distribute.h b/lib/distribute.h index a2ffffd5f..e9625a354 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -29,8 +29,10 @@ /* Disctirubte list types. */ enum distribute_type { - DISTRIBUTE_IN, - DISTRIBUTE_OUT, + DISTRIBUTE_V4_IN, + DISTRIBUTE_V6_IN, + DISTRIBUTE_V4_OUT, + DISTRIBUTE_V6_OUT, DISTRIBUTE_MAX }; diff --git a/ripd/ripd.c b/ripd/ripd.c index 990db60a7..385dab997 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -321,7 +321,7 @@ rip_filter (int rip_distribute, struct prefix_ipv4 *p, struct rip_interface *ri) struct access_list *alist; struct prefix_list *plist; int distribute = rip_distribute == RIP_FILTER_OUT ? - DISTRIBUTE_OUT : DISTRIBUTE_IN; + DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN; const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ @@ -3799,9 +3799,9 @@ rip_distribute_update (struct distribute *dist) ri = ifp->info; - if (dist->list[DISTRIBUTE_IN]) + if (dist->list[DISTRIBUTE_V4_IN]) { - alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]); if (alist) ri->list[RIP_FILTER_IN] = alist; else @@ -3810,9 +3810,9 @@ rip_distribute_update (struct distribute *dist) else ri->list[RIP_FILTER_IN] = NULL; - if (dist->list[DISTRIBUTE_OUT]) + if (dist->list[DISTRIBUTE_V4_OUT]) { - alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]); if (alist) ri->list[RIP_FILTER_OUT] = alist; else @@ -3821,9 +3821,9 @@ rip_distribute_update (struct distribute *dist) else ri->list[RIP_FILTER_OUT] = NULL; - if (dist->prefix[DISTRIBUTE_IN]) + if (dist->prefix[DISTRIBUTE_V4_IN]) { - plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]); if (plist) ri->prefix[RIP_FILTER_IN] = plist; else @@ -3832,9 +3832,9 @@ rip_distribute_update (struct distribute *dist) else ri->prefix[RIP_FILTER_IN] = NULL; - if (dist->prefix[DISTRIBUTE_OUT]) + if (dist->prefix[DISTRIBUTE_V4_OUT]) { - plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]); if (plist) ri->prefix[RIP_FILTER_OUT] = plist; else diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index dd5444060..910583121 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -615,7 +615,7 @@ ripng_filter (int ripng_distribute, struct prefix_ipv6 *p, struct access_list *alist; struct prefix_list *plist; int distribute = ripng_distribute == RIPNG_FILTER_OUT ? - DISTRIBUTE_OUT : DISTRIBUTE_IN; + DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN; const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ @@ -2757,9 +2757,9 @@ ripng_distribute_update (struct distribute *dist) ri = ifp->info; - if (dist->list[DISTRIBUTE_IN]) + if (dist->list[DISTRIBUTE_V6_IN]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_IN]); if (alist) ri->list[RIPNG_FILTER_IN] = alist; else @@ -2768,9 +2768,9 @@ ripng_distribute_update (struct distribute *dist) else ri->list[RIPNG_FILTER_IN] = NULL; - if (dist->list[DISTRIBUTE_OUT]) + if (dist->list[DISTRIBUTE_V6_OUT]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_OUT]); if (alist) ri->list[RIPNG_FILTER_OUT] = alist; else @@ -2779,9 +2779,9 @@ ripng_distribute_update (struct distribute *dist) else ri->list[RIPNG_FILTER_OUT] = NULL; - if (dist->prefix[DISTRIBUTE_IN]) + if (dist->prefix[DISTRIBUTE_V6_IN]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_IN]); if (plist) ri->prefix[RIPNG_FILTER_IN] = plist; else @@ -2790,9 +2790,9 @@ ripng_distribute_update (struct distribute *dist) else ri->prefix[RIPNG_FILTER_IN] = NULL; - if (dist->prefix[DISTRIBUTE_OUT]) + if (dist->prefix[DISTRIBUTE_V6_OUT]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_OUT]); if (plist) ri->prefix[RIPNG_FILTER_OUT] = plist; else From 9c52caeaf40e32701ff79a721f0fee52cfcbd77c Mon Sep 17 00:00:00 2001 From: Balaji Date: Wed, 20 Jan 2016 22:59:26 +0530 Subject: [PATCH 1017/1342] bgpd: Addition of dampening show commands under v4 unicast/multicast tree Patch contains addition of show ip bgp ipv4 (unicast| multicast) dampening tree. Signed-off-by: Balaji Gurudoss --- bgpd/bgp_route.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 494375f77..9d4314b34 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8603,6 +8603,66 @@ DEFUN (show_bgp_ipv6_filter_list, bgp_show_type_filter_list); } + +DEFUN (show_ip_bgp_ipv4_dampening_parameters, + show_ip_bgp_ipv4_dampening_parameters_cmd, + "show ip bgp ipv4 (unicast|multicast) dampening parameters", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display detail of configured dampening parameters\n") +{ + if (strncmp(argv[0], "m", 1) == 0) + return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_MULTICAST); + + return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); +} + + +DEFUN (show_ip_bgp_ipv4_dampening_flap_stats, + show_ip_bgp_ipv4_dampening_flap_stats_cmd, + "show ip bgp ipv4 (unicast|multicast) dampening flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n") +{ + if (strncmp(argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_flap_statistics, NULL); + + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_flap_statistics, NULL); +} + +DEFUN (show_ip_bgp_ipv4_dampening_dampd_paths, + show_ip_bgp_ipv4_dampening_dampd_paths_cmd, + "show ip bgp ipv4 (unicast|multicast) dampening dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display detailed information about dampening\n" + "Display paths suppressed due to dampening\n") +{ + if (strncmp(argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_dampend_paths, NULL); + + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_dampend_paths, NULL); +} + static int bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -16577,7 +16637,10 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd); @@ -16691,6 +16754,9 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd); install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd); From 9145f0e4cf776bd3156620da6c8a772fee4d4383 Mon Sep 17 00:00:00 2001 From: Balaji Date: Wed, 20 Jan 2016 22:59:27 +0530 Subject: [PATCH 1018/1342] bgpd: Addition of bgp dampening configuration commands under IPv4/multicast Signed-off-by: Balaji Gurudoss Tested-by: NetDEF CI System --- bgpd/bgp_route.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9d4314b34..4ad912bde 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -16533,6 +16533,14 @@ bgp_route_init (void) install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); + + /* IPv4 Multicast Mode */ + install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_set2_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_set3_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd); + install_element (BGP_IPV4M_NODE, &bgp_damp_unset2_cmd); + /* Deprecated AS-Pathlimit commands */ install_element (BGP_NODE, &bgp_network_ttl_cmd); From 687bea20fa61d8fc7cf48c0b227f16d0b324778c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 25 Jan 2016 14:56:26 -0500 Subject: [PATCH 1019/1342] lib: Allow zclient do-over of connect on initial attempt When a protocol is attempting to connect to the zebra daemon through it's socket. If the inital attempt fails, give it a few more attempts before giving up and leaving the daemon in a bizarre state. This problem was found by Ashley Penney, and Ashley was of immense help in debugging and testing the fix for this issue. Signed-off-by: Donald Sharp Tested-by: Ashley Penney Tested-by: NetDEF CI System --- lib/zclient.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index 9d50ebc04..208ea5cb5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -181,6 +181,7 @@ zclient_socket(void) ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); if (ret < 0) { + zlog_warn ("%s connect failure: %d", __PRETTY_FUNCTION__, errno); close (sock); return -1; } @@ -216,6 +217,7 @@ zclient_socket_un (const char *path) ret = connect (sock, (struct sockaddr *) &addr, len); if (ret < 0) { + zlog_warn ("%s connect failure: %d", __PRETTY_FUNCTION__, errno); close (sock); return -1; } @@ -429,11 +431,23 @@ zclient_start (struct zclient *zclient) if (zclient->t_connect) return 0; - if (zclient_socket_connect(zclient) < 0) + /* + * If we fail to connect to the socket on initialization, + * Let's wait a second and see if we can reconnect. + * Cause if we don't connect, we never attempt to + * reconnect. On startup if zebra is slow we + * can get into this situation. + */ + while (zclient_socket_connect(zclient) < 0 && zclient->fail < 5) { if (zclient_debug) zlog_debug ("zclient connection fail"); zclient->fail++; + sleep (1); + } + + if (zclient->sock < 0) + { zclient_event (ZCLIENT_CONNECT, zclient); return -1; } From 3c964045459f66921f8a3dc33fe4c028e6b0b141 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 25 Jan 2016 23:38:53 -0500 Subject: [PATCH 1020/1342] bgpd: Fix 'show bgp ipv4 vpnv4 statistics' cli. When attempting to use the 'show bgp ipv4 vpnv4 statistics' cli, the safi choosen is BGP_MPLS_LABELED_VPN which is #defined to 128. The afi/safi combination is fed to bgp->rib, which limits the size of the safi to BGP_SAFI_MAX which is #defined to 5. The correct value to use is BGP_MPLS_VPN The bgp code differentiates between the actual safi value for BGP_MPLS_LABELED_VPN used defined by RFC 4364, to a internal SAFI value used to limit array size. Signed-off-by: Donald Sharp Tested-by: NetDEF CI System --- bgpd/bgp_route.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4ad912bde..f99045a84 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -11794,7 +11794,8 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) if (!bgp->rib[afi][safi]) { - vty_out (vty, "%% No RIB exists for the AFI/SAFI%s", VTY_NEWLINE); + vty_out (vty, "%% No RIB exists for the specified AFI(%d)/SAFI(%d) %s", + afi, safi, VTY_NEWLINE); return CMD_WARNING; } @@ -11908,7 +11909,7 @@ bgp_table_stats_vty (struct vty *vty, const char *name, safi = SAFI_UNICAST; break; case 'v': - safi = SAFI_MPLS_LABELED_VPN; + safi = SAFI_MPLS_VPN; break; case 'e': safi = SAFI_ENCAP; From 9514fee4b37a9043738aa16ca8684993a1b572ad Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 26 Jan 2016 11:44:14 -0500 Subject: [PATCH 1021/1342] bgpd, ripngd, zebra: Remove duplicate PSIZE define The PSIZE macro is defined the same in multiple places. Remove the duplicates. Signed-off-by: Donald Sharp Tested-by: NetDEF CI System --- bgpd/bgpd.h | 3 --- ripngd/ripngd.h | 3 --- zebra/zserv.h | 3 --- 3 files changed, 9 deletions(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d8e687bcc..d8afbf386 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -795,9 +795,6 @@ enum bgp_clear_type #define BGP_IS_VALID_STATE_FOR_NOTIF(S)\ (((S) == OpenSent) || ((S) == OpenConfirm) || ((S) == Established)) -/* Count prefix size from mask length */ -#define PSIZE(a) (((a) + 7) / (8)) - /* BGP error codes. */ #define BGP_SUCCESS 0 #define BGP_ERR_INVALID_VALUE -1 diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 75b542e97..93f6ff14a 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -337,9 +337,6 @@ do { \ } \ } while (0) -/* Count prefix size from mask length */ -#define PSIZE(a) (((a) + 7) / (8)) - /* Extern variables. */ extern struct ripng *ripng; diff --git a/zebra/zserv.h b/zebra/zserv.h index fc01f961a..413cd6ab2 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -84,9 +84,6 @@ struct zebra_t struct meta_queue *mq; }; -/* Count prefix size from mask length */ -#define PSIZE(a) (((a) + 7) / (8)) - /* Prototypes. */ extern void zebra_init (void); extern void zebra_if_init (void); From 071cfcd2e315499f0a4fa8c23779468eacc20033 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 2 Feb 2016 21:02:42 -0500 Subject: [PATCH 1022/1342] bgpd: Removed unused variable from 'struct attr_extra' The mp_nexthop_local_in variable is never used. Remove it from the code base. Signed-off-by: Donald Sharp Tested-by: NetDEF CI System --- bgpd/bgp_attr.h | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index fe6c2a1a1..000ceaaf7 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -74,7 +74,6 @@ struct attr_extra struct transit *transit; struct in_addr mp_nexthop_global_in; - struct in_addr mp_nexthop_local_in; /* Aggregator Router ID attribute */ struct in_addr aggregator_addr; From 9da9a61e2f8afb61aa31c17fb810169290bf96ee Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 2 Feb 2016 21:11:40 -0500 Subject: [PATCH 1023/1342] config: Remove unused library check configure.ac is looking for the setproctitle library, which while it might be useful, we never call setproctitle or any other function that the library might expose. Signed-off-by: Donald Sharp Tested-by: NetDEF CI System --- configure.ac | 8 -------- 1 file changed, 8 deletions(-) diff --git a/configure.ac b/configure.ac index 620651085..35e402369 100755 --- a/configure.ac +++ b/configure.ac @@ -785,14 +785,6 @@ AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \ if_nametoindex if_indextoname getifaddrs \ uname fcntl getgrouplist]) -AC_CHECK_FUNCS(setproctitle, , - [AC_CHECK_LIB(util, setproctitle, - [LIBS="$LIBS -lutil" - AC_DEFINE(HAVE_SETPROCTITLE,, Have setproctitle) - ] - ) - ] -) AC_CHECK_HEADER([asm-generic/unistd.h], [AC_CHECK_DECL(__NR_setns, From d869dbd03b4d75d512552d07ed8fbe0807272a9c Mon Sep 17 00:00:00 2001 From: Udaya Shankara KS Date: Thu, 11 Feb 2016 21:42:29 +0530 Subject: [PATCH 1024/1342] zebra: Enable fpm module to connect to remote fpm server FPM aims to provide cross platform mechanism to support the scenario where the router has forwarding path distinct fromt the kernel.Commonly Hardware based fast path.Hence it is non-configurable paramter.This limits us to use funcationality to update FIB information to remote hosts, like SDN controller. This implementation provides the CLI to configure remote hosts and port information of remote fpm controller.Otherwise default fpm server will be localhost and default fpm port will be well know port 2620. * zebra_fpm.c: added fpm_server paramter to zfpm_global_t handler. Implemented CLI for configuring the fpm server and no fpm command to revert back to default configuration. * zserv.c: Install zebra node to write fpm configuration info on console/config file. Further documentation supplied: ------------------------------- ZEBRA : CLI CONFIGURATION FOR FPM MODULE ======================================================== 1. INTRODUCTION ================================ 1.1 scope This memo discusses the configuration option for zebra to update FIB information to local and remote modules. This will also helps to address the issue associated with CORD project. https://jira.onosproject.org/browse/CORD-411 2. REFERENCE ================================ Quagga version 99.24+ ( main branch committed on 29-sep-2015) 3. PROBLEM DESCRIPTION ================================ Once FPM is enabled, Quagga periodically tries to initiate fpm connection to localhost:2620. These values are non configurable in existing implementation. There is no CLI available to configure "host:port". hence limits us to use it for hardware based fast path modules only. 4. PROPOSED CHANGES ================================ Following changes are done to the quagga code a) Added new CLI to configure "host address : port". The CLI format $ fpm connection ip port and no fpm command to revert back to default $ no fpm connection ip port b) Allowed values are ipv4 address and tcp port range <1-65535> c) FPM initialization code has been enhanced to pick the "host address : port" values from zebra.conf. if not found then default values as localhost:2620 will be used. and updated the information on to config file on write config command 5. FILES MODIFIED ================================ 1) fpm/fpm.h : a) Added MACRO to represent network order loopback ip 2) zebra/zebra_fpm.h : a) introduced fpm_server variable in zfpm_glob_t handler to hold the remote fpm server address b) Hooked 'fpm_remote_ip_cmd' and 'no_fpm_remote_ip_cmd' at CONFIG node to configure remote fpm detail and to revert back to default respectively 3) zebra/zserv.c : a) Hooked 'config_write_fpm' callback function, at ZEBRA_NODE to display the fpm connection details on console on entering command $ show running_config and to write to configuration file on entering command $ write config 6. TESTING DETAILS ================================ 6.1. default behavior In default configuration FPM will attempt to connect to localhost:2620 6.2. update fpm info a) Using CLI command user can configure fpm host:port details and can be able to write to config file(zebra.conf) using write config command. this parameters has no dependency/impact on other parameters of config file b) show running-config/write config will display the fpm information if configured. and will not display any information related to fpm for default configuration c) these configured information will be stored to config file. only on write config command. 6.3 loading from config file a) zebra attempts to connect to fpm server if fpm parameter found in config file.else connects to default parameters. b) if fpm connection drops, fpm will periodically attempts to connect to remote server. c) if fpm connections already established. then newly configured fpm parameters will not disconnect the existing connection. new connection to the different fpm server will happen only after existing connection closes by either of the end. --- fpm/fpm.h | 14 ++++++++ zebra/zebra_fpm.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++- zebra/zserv.c | 21 ++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/fpm/fpm.h b/fpm/fpm.h index 96f05f486..9a1dbf2b0 100644 --- a/fpm/fpm.h +++ b/fpm/fpm.h @@ -87,6 +87,14 @@ * table(s) when it reconnects. */ +/* + * Local host as a default server for fpm connection + */ +#define FPM_DEFAULT_IP (htonl (INADDR_LOOPBACK)) + +/* + * default port for fpm connections + */ #define FPM_DEFAULT_PORT 2620 /* @@ -270,4 +278,10 @@ fpm_msg_ok (const fpm_msg_hdr_t *hdr, size_t len) return 1; } +// tcp maximum range +#define TCP_MAX_PORT 65535 + +// tcp minimum range +#define TCP_MIN_PORT 1 + #endif /* _FPM_H */ diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index cb04f21ae..9cbbf689d 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -153,6 +153,7 @@ typedef struct zfpm_glob_t_ zfpm_state_t state; + in_addr_t fpm_server; /* * Port on which the FPM is running. */ @@ -1126,7 +1127,10 @@ zfpm_connect_cb (struct thread *t) #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (!zfpm_g->fpm_server) + serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + else + serv.sin_addr.s_addr = (zfpm_g->fpm_server); /* * Connect to the FPM. @@ -1517,6 +1521,76 @@ DEFUN (clear_zebra_fpm_stats, return CMD_SUCCESS; } +/* + * update fpm connection information + */ +DEFUN ( fpm_remote_ip, + fpm_remote_ip_cmd, + "fpm connection ip A.B.C.D port <1-65535>", + "fpm connection remote ip and port\n" + "Remote fpm server ip A.B.C.D\n" + "Enter ip ") +{ + + in_addr_t fpm_server; + uint32_t port_no; + + fpm_server = inet_addr (argv[0]); + if (fpm_server == INADDR_NONE) + return CMD_ERR_INCOMPLETE; + + port_no = atoi (argv[1]); + if (port_no < TCP_MIN_PORT || port_no > TCP_MAX_PORT) + return CMD_ERR_INCOMPLETE; + + zfpm_g->fpm_server = fpm_server; + zfpm_g->fpm_port = port_no; + + + return CMD_SUCCESS; +} + +DEFUN ( no_fpm_remote_ip, + no_fpm_remote_ip_cmd, + "no fpm connection ip A.B.C.D port <1-65535>", + "fpm connection remote ip and port\n" + "Connection\n" + "Remote fpm server ip A.B.C.D\n" + "Enter ip ") +{ + if (zfpm_g->fpm_server != inet_addr (argv[0]) || + zfpm_g->fpm_port != atoi (argv[1])) + return CMD_ERR_NO_MATCH; + + zfpm_g->fpm_server = FPM_DEFAULT_IP; + zfpm_g->fpm_port = FPM_DEFAULT_PORT; + + return CMD_SUCCESS; +} + + +/** + * fpm_remote_srv_write + * + * Module to write remote fpm connection + * + * Returns ZERO on success. + */ + +int fpm_remote_srv_write (struct vty *vty ) +{ + struct in_addr in; + + in.s_addr = zfpm_g->fpm_server; + + if (zfpm_g->fpm_server != FPM_DEFAULT_IP || + zfpm_g->fpm_port != FPM_DEFAULT_PORT) + vty_out (vty,"fpm connection ip %s port %d%s", inet_ntoa (in),zfpm_g->fpm_port,VTY_NEWLINE); + + return 0; +} + + /** * zfpm_init * @@ -1560,11 +1634,16 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port) install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd); + install_element (CONFIG_NODE, &fpm_remote_ip_cmd); + install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd); if (!enable) { return 1; } + if (!zfpm_g->fpm_server) + zfpm_g->fpm_server = FPM_DEFAULT_IP; + if (!port) port = FPM_DEFAULT_PORT; diff --git a/zebra/zserv.c b/zebra/zserv.c index 6412f8d6d..e0e32ab07 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1922,6 +1922,24 @@ static struct cmd_node forwarding_node = 1 }; +#ifdef HAVE_FPM +/* function to write the fpm config info */ +static int +config_write_fpm (struct vty *vty) +{ + return + fpm_remote_srv_write (vty); +} + +/* Zebra node */ +static struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "", + 1 +}; +#endif + /* Initialisation of zebra and installation of commands. */ void @@ -1933,6 +1951,9 @@ zebra_init (void) /* Install configuration write function. */ install_node (&table_node, config_write_table); install_node (&forwarding_node, config_write_forwarding); +#ifdef HAVE_FPM + install_node (&zebra_node, config_write_fpm); +#endif install_element (VIEW_NODE, &show_ip_forwarding_cmd); install_element (ENABLE_NODE, &show_ip_forwarding_cmd); From 8b3ab1f1c8172ff7c77b382b6636c8e8314d7ebc Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 16 Feb 2016 19:50:15 +0100 Subject: [PATCH 1025/1342] isisd: fix assert warning icc (the Intel C Compiler) "knows" that assert() can be disabled by setting specific optimisation flags, and therefore emits a warning about missing a return value after an "always-error" assert. Workaround by returning a value - this probably needs discussion and a better fix (for all places where the code needs to abort due to internal errors). Signed-off-by: David Lamparter --- isisd/isis_redist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 690ae4720..ad0a31b74 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -52,6 +52,7 @@ redist_protocol(int family) return 1; assert(!"Unsupported address family!"); + return 0; } static int From 47dd9af50d7fcf3ea25ebb8c8c4e9c4726a072f6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 16 Feb 2016 19:50:16 +0100 Subject: [PATCH 1026/1342] build/pimd: remove special shell scripts Signed-off-by: David Lamparter Tested-by: NetDEF CI System --- pimd/git-clone-github.sh | 27 --------------------------- pimd/git-clone-savannah.sh | 27 --------------------------- pimd/quagga-bootstrap.sh | 23 ----------------------- pimd/quagga-build-no-vtysh.sh | 10 ---------- pimd/quagga-build.sh | 10 ---------- pimd/quagga-configure-no-vtysh.sh | 10 ---------- pimd/quagga-configure.sh | 10 ---------- pimd/quagga-git-add.sh | 12 ------------ pimd/quagga-memtypes.sh | 22 ---------------------- 9 files changed, 151 deletions(-) delete mode 100755 pimd/git-clone-github.sh delete mode 100755 pimd/git-clone-savannah.sh delete mode 100755 pimd/quagga-bootstrap.sh delete mode 100755 pimd/quagga-build-no-vtysh.sh delete mode 100755 pimd/quagga-build.sh delete mode 100755 pimd/quagga-configure-no-vtysh.sh delete mode 100755 pimd/quagga-configure.sh delete mode 100755 pimd/quagga-git-add.sh delete mode 100755 pimd/quagga-memtypes.sh diff --git a/pimd/git-clone-github.sh b/pimd/git-clone-github.sh deleted file mode 100755 index ae2362a73..000000000 --- a/pimd/git-clone-github.sh +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash -# -# Github Developer Git Checkout -# -# Delete remote branch qpimd: git push origin :qpimd -# (git push origin :refs/heads/branch_to_delete) -# Delete remote tag v0.139: git push origin :v0.139 -# (git push origin :refs/tags/tag_to_delete) -# Create remote-tracking branch: git checkout -b pim0.142 origin/pim0.142 -# Rename branch qpimd to pim: git branch -m qpimd pim -# Commit changes: git commit -a -# Send changes: git push --all -# -# Recipe to re-sync with Quagga repository: -# git clone https://github.com/udhos/qpimd quagga -# cd quagga -# git checkout master -# git pull http://git.sv.gnu.org/r/quagga.git master -# git checkout -b pim origin/pim -# git rebase master pim -# # Test, then push back into Github repository: -# git push origin :pim ;# delete remote branch pim -# git push --all -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -git clone https://github.com/udhos/qpimd diff --git a/pimd/git-clone-savannah.sh b/pimd/git-clone-savannah.sh deleted file mode 100755 index 1aad51bb2..000000000 --- a/pimd/git-clone-savannah.sh +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash -# -# Savannah Developer Git Checkout -# -# Delete remote branch qpimd: git push origin :qpimd -# (git push origin :refs/heads/branch_to_delete) -# Delete remote tag v0.139: git push origin :v0.139 -# (git push origin :refs/tags/tag_to_delete) -# Create remote-tracking branch: git checkout -b pim0.142 origin/pim0.142 -# Rename branch qpimd to pim: git branch -m qpimd pim -# Commit changes: git commit -a -# Send changes: git push --all -# -# Recipe to re-sync with Quagga repository: -# git clone ssh://evertonm@git.sv.gnu.org/srv/git/qpimd.git quagga -# cd quagga -# git checkout master -# git pull git://code.quagga.net/quagga.git master -# git checkout -b pim origin/pim -# git rebase master pim -# # Test, then push back into Savannah repository: -# git push origin :pim ;# delete remote branch pim -# git push --all -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -git clone ssh://evertonm@git.sv.gnu.org/srv/git/qpimd.git quagga diff --git a/pimd/quagga-bootstrap.sh b/pimd/quagga-bootstrap.sh deleted file mode 100755 index 4ec443d93..000000000 --- a/pimd/quagga-bootstrap.sh +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash -# -# Bootstrap Quagga autotools for pimd. -# -# Run from quagga's top dir as: -# ./pimd/quagga-bootstrap.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -me=`basename $0` -msg () { - echo >&2 $me: $* -} - -if [ -f ./bootstrap.sh ]; then - msg found ./bootstrap.sh from quagga - ./bootstrap.sh -else - msg missing ./bootstrap.sh from quagga - #autoreconf -i --force - #bootstrap from tarball prefers autoreconf -i - autoreconf -i -fi diff --git a/pimd/quagga-build-no-vtysh.sh b/pimd/quagga-build-no-vtysh.sh deleted file mode 100755 index 7136f6705..000000000 --- a/pimd/quagga-build-no-vtysh.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash -# -# Build minimum Quagga needed for pimd. -# -# Run from quagga's top dir as: -# ./pimd/quagga-build-no-vtysh.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -./pimd/quagga-memtypes.sh && ./pimd/quagga-bootstrap.sh && ./pimd/quagga-configure-no-vtysh.sh && make diff --git a/pimd/quagga-build.sh b/pimd/quagga-build.sh deleted file mode 100755 index 2ad476d00..000000000 --- a/pimd/quagga-build.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash -# -# Build minimum Quagga needed for pimd. -# -# Run from quagga's top dir as: -# ./pimd/quagga-build.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -./pimd/quagga-memtypes.sh && ./pimd/quagga-bootstrap.sh && ./pimd/quagga-configure.sh && make diff --git a/pimd/quagga-configure-no-vtysh.sh b/pimd/quagga-configure-no-vtysh.sh deleted file mode 100755 index 672007ba7..000000000 --- a/pimd/quagga-configure-no-vtysh.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash -# -# Configure for minimum Quagga build needed for pimd. -# -# Run from quagga's top dir as: -# ./pimd/quagga-configure-no-vtysh.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -./configure --disable-bgpd --disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d --disable-watchquagga --disable-bgp-announce --disable-ospfapi --disable-ospfclient --disable-rtadv --disable-irdp --enable-pimd --enable-tcp-zebra --enable-ipv6 diff --git a/pimd/quagga-configure.sh b/pimd/quagga-configure.sh deleted file mode 100755 index 72329eb90..000000000 --- a/pimd/quagga-configure.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash -# -# Configure for minimum Quagga build needed for pimd. -# -# Run from quagga's top dir as: -# . pimd/quagga-configure.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -tail -1 ./pimd/quagga-configure-no-vtysh.sh --enable-vtysh diff --git a/pimd/quagga-git-add.sh b/pimd/quagga-git-add.sh deleted file mode 100755 index 3824e984e..000000000 --- a/pimd/quagga-git-add.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash -# -# Add to git new files created by qpimd patch -# -# Run from quagga's top dir as: -# ./pimd/quagga-git-add.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -chmod a+rx pimd/*.sh -git add doc/pimd.8 -git add pimd diff --git a/pimd/quagga-memtypes.sh b/pimd/quagga-memtypes.sh deleted file mode 100755 index e86f414b8..000000000 --- a/pimd/quagga-memtypes.sh +++ /dev/null @@ -1,22 +0,0 @@ -#! /bin/bash -# -# Check lib/memtypes.h from Quagga -# -# Run from quagga's top dir as: -# ./pimd/quagga-memtypes.sh -# -# $QuaggaId: $Format:%an, %ai, %h$ $ - -me=`basename $0` -msg () { - echo >&2 $me: $* -} - -memtypes_h=lib/memtypes.h -if [ -e $memtypes_h ]; then - memtypes_h_size=`ls -s $memtypes_h | cut -d' ' -f1` - if [ "$memtypes_h_size" -lt 1 ]; then - msg WARNING: removing empty file: $memtypes_h -- awk failed? - rm $memtypes_h - fi -fi From 7bd31774cf2c1cfaf74bca87f57f698e20a07e65 Mon Sep 17 00:00:00 2001 From: kitty Date: Thu, 18 Feb 2016 21:33:40 -0800 Subject: [PATCH 1027/1342] ospfd: fix non-zero metric when describing loopback addresses Fixes Quagga Bugzilla #842 Change-Id: Iff33d70089d1393bf3e9c757d9e9faf134699121 Signed-off-by: kitty Tested-by: NetDEF CI System Acked-by: Donald Sharp --- ospfd/ospf_lsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 634bc4351..c1b1e0e61 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -624,7 +624,7 @@ lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi) mask.s_addr = 0xffffffff; id.s_addr = oi->address->u.prefix4.s_addr; - return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); } /* Describe Virtual Link. */ From 23757db11c5378521b7948847e17691f4fc35e0a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 24 Feb 2016 06:26:02 +0100 Subject: [PATCH 1028/1342] *: get rid of "MTYPE 0" A few places are using 0 in place of the MTYPE_* argument. The following rewrite of the alloc tracking won't deal with that, so let's use MTYPE_TMP instead. Signed-off-by: David Lamparter Acked-by: Donald Sharp --- lib/prefix.c | 2 +- ospfclient/ospf_apiclient.h | 2 +- ospfd/ospf_opaque.c | 6 +++--- ospfd/ospf_snmp.c | 4 ++-- ospfd/ospf_te.c | 2 +- vtysh/vtysh_main.c | 2 +- vtysh/vtysh_user.c | 2 +- zebra/zebra_rib.c | 10 +++++----- zebra/zserv.c | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 3e4ca1679..aeb627bd0 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -566,7 +566,7 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p) { int plen; - cp = XMALLOC (0, (pnt - str) + 1); + cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); strncpy (cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton (AF_INET6, cp, &p->prefix); diff --git a/ospfclient/ospf_apiclient.h b/ospfclient/ospf_apiclient.h index 0e74787ae..809861995 100644 --- a/ospfclient/ospf_apiclient.h +++ b/ospfclient/ospf_apiclient.h @@ -23,7 +23,7 @@ #ifndef _OSPF_APICLIENT_H #define _OSPF_APICLIENT_H -#define MTYPE_OSPF_APICLIENT 0 +#define MTYPE_OSPF_APICLIENT MTYPE_TMP /* Structure for the OSPF API client */ struct ospf_apiclient diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 61e98f400..697655d53 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -22,9 +22,9 @@ */ /***** MTYPE definitions are not reflected to "memory.h" yet. *****/ -#define MTYPE_OSPF_OPAQUE_FUNCTAB 0 -#define MTYPE_OPAQUE_INFO_PER_TYPE 0 -#define MTYPE_OPAQUE_INFO_PER_ID 0 +#define MTYPE_OSPF_OPAQUE_FUNCTAB MTYPE_TMP +#define MTYPE_OPAQUE_INFO_PER_TYPE MTYPE_TMP +#define MTYPE_OPAQUE_INFO_PER_ID MTYPE_TMP #include diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index ebeffa8ea..1f9b85187 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1420,13 +1420,13 @@ struct ospf_snmp_if static struct ospf_snmp_if * ospf_snmp_if_new (void) { - return XCALLOC (0, sizeof (struct ospf_snmp_if)); + return XCALLOC (MTYPE_TMP, sizeof (struct ospf_snmp_if)); } static void ospf_snmp_if_free (struct ospf_snmp_if *osif) { - XFREE (0, osif); + XFREE (MTYPE_TMP, osif); } void diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index cd52866be..03109bc82 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -22,7 +22,7 @@ */ /***** MTYPE definition is not reflected to "memory.h" yet. *****/ -#define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 +#define MTYPE_OSPF_MPLS_TE_LINKPARAMS MTYPE_TMP #include diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 02a19b7c2..e82771b34 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -251,7 +251,7 @@ main (int argc, char **argv, char **env) case 'c': { struct cmd_rec *cr; - cr = XMALLOC(0, sizeof(*cr)); + cr = XMALLOC(MTYPE_TMP, sizeof(*cr)); cr->line = optarg; cr->next = NULL; if (tail) diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 239a633f4..248b18120 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -102,7 +102,7 @@ struct list *userlist; static struct vtysh_user * user_new () { - return XCALLOC (0, sizeof (struct vtysh_user)); + return XCALLOC (MTYPE_TMP, sizeof (struct vtysh_user)); } #if 0 diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 18eece81b..2e15f99a1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -218,7 +218,7 @@ nexthop_ifname_add (struct rib *rib, char *ifname) nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IFNAME; - nexthop->ifname = XSTRDUP (0, ifname); + nexthop->ifname = XSTRDUP (MTYPE_TMP, ifname); nexthop_add (rib, nexthop); @@ -282,7 +282,7 @@ nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; nexthop->gate.ipv6 = *ipv6; - nexthop->ifname = XSTRDUP (0, ifname); + nexthop->ifname = XSTRDUP (MTYPE_TMP, ifname); nexthop_add (rib, nexthop); @@ -2464,7 +2464,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, if (gate) si->addr.ipv4 = *gate; if (ifname) - si->ifname = XSTRDUP (0, ifname); + si->ifname = XSTRDUP (MTYPE_TMP, ifname); /* Add new static route information to the tree with sort by distance value and gateway address. */ @@ -2861,11 +2861,11 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->addr.ipv6 = *gate; break; case STATIC_IPV6_IFNAME: - si->ifname = XSTRDUP (0, ifname); + si->ifname = XSTRDUP (MTYPE_TMP, ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: si->addr.ipv6 = *gate; - si->ifname = XSTRDUP (0, ifname); + si->ifname = XSTRDUP (MTYPE_TMP, ifname); break; } diff --git a/zebra/zserv.c b/zebra/zserv.c index e0e32ab07..c0f9a9094 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1313,7 +1313,7 @@ zebra_client_create (int sock) struct zserv *client; int i; - client = XCALLOC (0, sizeof (struct zserv)); + client = XCALLOC (MTYPE_TMP, sizeof (struct zserv)); /* Make client input/output buffer. */ client->sock = sock; From 0744040564ece3f4b9fe39fcf857e466a5f68a72 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 25 Feb 2016 07:39:45 -0500 Subject: [PATCH 1029/1342] vtysh: Add ability to only look at one processes work queue When examining performance information it is nice to not have to look at daemons who you are not interested in. Signed-off-by: Donald Sharp Reviewed-by: Don Slice Tested-by: NetDEF CI System --- vtysh/vtysh.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 63b596a58..69e98883d 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -85,6 +85,19 @@ vclient_close (struct vtysh_client *vclient) } } +/* Return true if str begins with prefix, else return false */ +static int +begins_with(const char *str, const char *prefix) +{ + if (!str || !prefix) + return 0; + size_t lenstr = strlen(str); + size_t lenprefix = strlen(prefix); + if (lenprefix > lenstr) + return 0; + return strncmp(str, prefix, lenprefix) == 0; +} + /* Following filled with debug code to trace a problematic condition * under load - it SHOULD handle it. */ #define ERR_WHERE_STRING "vtysh(): vtysh_client_execute(): " @@ -1404,6 +1417,33 @@ DEFUN (vtysh_show_work_queues, return ret; } +DEFUN (vtysh_show_work_queues_daemon, + vtysh_show_work_queues_daemon_cmd, + "show work-queues (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd)", + SHOW_STR + "Work Queue information\n" + "For the zebra daemon\n" + "For the rip daemon\n" + "For the ripng daemon\n" + "For the ospf daemon\n" + "For the ospfv6 daemon\n" + "For the bgp daemon\n" + "For the isis daemon\n") +{ + unsigned int i; + int ret = CMD_SUCCESS; + + for (i = 0; i < array_size(vtysh_client); i++) + { + if (begins_with(vtysh_client[i].name, argv[0])) + break; + } + + ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n", stdout); + + return ret; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2528,7 +2568,7 @@ vtysh_init_vty (void) /* "write terminal" command. */ install_element (ENABLE_NODE, &vtysh_write_terminal_cmd); install_element (ENABLE_NODE, &vtysh_write_terminal_daemon_cmd); - + install_element (CONFIG_NODE, &vtysh_integrated_config_cmd); install_element (CONFIG_NODE, &no_vtysh_integrated_config_cmd); @@ -2573,6 +2613,8 @@ vtysh_init_vty (void) install_element (VIEW_NODE, &vtysh_show_work_queues_cmd); install_element (ENABLE_NODE, &vtysh_show_work_queues_cmd); + install_element (ENABLE_NODE, &vtysh_show_work_queues_daemon_cmd); + install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); install_element (VIEW_NODE, &vtysh_show_thread_cmd); install_element (ENABLE_NODE, &vtysh_show_thread_cmd); From 4ab273bb60606ed681bee1be6fb2c8bb31dc26a7 Mon Sep 17 00:00:00 2001 From: Denil Vira Date: Fri, 4 Mar 2016 15:28:54 -0500 Subject: [PATCH 1030/1342] lib: Replace lists with arrays to store read and write threads With arrays, a thread corresponding to given fd is looked up in constant time versus the linear time taken for list traversals. Signed-off-by: Denil Vira Signed-off-by: Donald Sharp --- lib/thread.c | 102 ++++++++++++++++++++++++++++++++++++++++----------- lib/thread.h | 5 ++- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 5e40261e6..6c2b0b0ba 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -22,6 +22,7 @@ /* #define DEBUG */ #include +#include #include "thread.h" #include "memory.h" @@ -525,6 +526,9 @@ struct thread_master * thread_master_create () { struct thread_master *rv; + struct rlimit limit; + + getrlimit(RLIMIT_NOFILE, &limit); if (cpu_record == NULL) cpu_record @@ -532,6 +536,26 @@ thread_master_create () (int (*) (const void *, const void *))cpu_record_hash_cmp); rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); + if (rv == NULL) + { + return NULL; + } + + rv->fd_limit = (int)limit.rlim_cur; + rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); + if (rv->read == NULL) + { + XFREE (MTYPE_THREAD_MASTER, rv); + return NULL; + } + + rv->write = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); + if (rv->write == NULL) + { + XFREE (MTYPE_THREAD, rv->read); + XFREE (MTYPE_THREAD_MASTER, rv); + return NULL; + } /* Initialize the timer queues */ rv->timer = pqueue_create(); @@ -573,6 +597,18 @@ thread_list_delete (struct thread_list *list, struct thread *thread) return thread; } +static void +thread_delete_fd (struct thread **thread_array, struct thread *thread) +{ + thread_array[thread->u.fd] = NULL; +} + +static void +thread_add_fd (struct thread **thread_array, struct thread *thread) +{ + thread_array[thread->u.fd] = thread; +} + /* Move thread to unuse list. */ static void thread_add_unuse (struct thread_master *m, struct thread *thread) @@ -600,6 +636,25 @@ thread_list_free (struct thread_master *m, struct thread_list *list) } } +static void +thread_array_free (struct thread_master *m, struct thread **thread_array) +{ + struct thread *t; + int index; + + for (index = 0; index < m->fd_limit; ++index) + { + t = thread_array[index]; + if (t) + { + thread_array[index] = NULL; + XFREE (MTYPE_THREAD, t); + m->alloc--; + } + } + XFREE (MTYPE_THREAD, thread_array); +} + static void thread_queue_free (struct thread_master *m, struct pqueue *queue) { @@ -616,8 +671,8 @@ thread_queue_free (struct thread_master *m, struct pqueue *queue) void thread_master_free (struct thread_master *m) { - thread_list_free (m, &m->read); - thread_list_free (m, &m->write); + thread_array_free (m, m->read); + thread_array_free (m, m->write); thread_queue_free (m, m->timer); thread_list_free (m, &m->event); thread_list_free (m, &m->ready); @@ -718,7 +773,7 @@ funcname_thread_add_read (struct thread_master *m, thread = thread_get (m, THREAD_READ, func, arg, debugargpass); FD_SET (fd, &m->readfd); thread->u.fd = fd; - thread_list_add (&m->read, thread); + thread_add_fd (m->read, thread); return thread; } @@ -742,7 +797,7 @@ funcname_thread_add_write (struct thread_master *m, thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass); FD_SET (fd, &m->writefd); thread->u.fd = fd; - thread_list_add (&m->write, thread); + thread_add_fd (m->write, thread); return thread; } @@ -863,18 +918,19 @@ thread_cancel (struct thread *thread) { struct thread_list *list = NULL; struct pqueue *queue = NULL; + struct thread **thread_array = NULL; switch (thread->type) { case THREAD_READ: assert (FD_ISSET (thread->u.fd, &thread->master->readfd)); FD_CLR (thread->u.fd, &thread->master->readfd); - list = &thread->master->read; + thread_array = thread->master->read; break; case THREAD_WRITE: assert (FD_ISSET (thread->u.fd, &thread->master->writefd)); FD_CLR (thread->u.fd, &thread->master->writefd); - list = &thread->master->write; + thread_array = thread->master->write; break; case THREAD_TIMER: queue = thread->master->timer; @@ -903,9 +959,13 @@ thread_cancel (struct thread *thread) { thread_list_delete (list, thread); } + else if (thread_array) + { + thread_delete_fd (thread_array, thread); + } else { - assert(!"Thread should be either in queue or list!"); + assert(!"Thread should be either in queue or list or array!"); } thread->type = THREAD_UNUSED; @@ -979,29 +1039,27 @@ thread_run (struct thread_master *m, struct thread *thread, } static int -thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset) +thread_process_fd (struct thread **thread_array, fd_set *fdset, fd_set *mfdset, int num, int fd_limit) { struct thread *thread; - struct thread *next; - int ready = 0; - - assert (list); + int ready = 0, index; + + assert (thread_array); - for (thread = list->head; thread; thread = next) + for (index = 0; index < fd_limit && ready < num; ++index) { - next = thread->next; - - if (FD_ISSET (THREAD_FD (thread), fdset)) + thread = thread_array[index]; + if (thread && FD_ISSET (THREAD_FD (thread), fdset)) { assert (FD_ISSET (THREAD_FD (thread), mfdset)); FD_CLR(THREAD_FD (thread), mfdset); - thread_list_delete (list, thread); + thread_delete_fd (thread_array, thread); thread_list_add (&thread->master->ready, thread); thread->type = THREAD_READY; ready++; } } - return ready; + return num - ready; } /* Add all timers that have popped to the ready list. */ @@ -1154,10 +1212,10 @@ thread_fetch (struct thread_master *m, struct thread *fetch) /* Got IO, process it */ if (num > 0) { - /* Normal priority read thead. */ - thread_process_fd (&m->read, &readfd, &m->readfd); - /* Write thead. */ - thread_process_fd (&m->write, &writefd, &m->writefd); + /* Normal priority read thread. */ + num = thread_process_fd (m->read, &readfd, &m->readfd, num, m->fd_limit); + /* Write thread. */ + num = thread_process_fd (m->write, &writefd, &m->writefd, num, m->fd_limit); } #if 0 diff --git a/lib/thread.h b/lib/thread.h index 5bc756c7a..5a3bf7d57 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -48,13 +48,14 @@ struct pqueue; /* Master of the theads. */ struct thread_master { - struct thread_list read; - struct thread_list write; + struct thread **read; + struct thread **write; struct pqueue *timer; struct thread_list event; struct thread_list ready; struct thread_list unuse; struct pqueue *background; + int fd_limit; fd_set readfd; fd_set writefd; fd_set exceptfd; From b9ac2f320922542e0320ceeced4aa7264564e98a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 11 Mar 2016 14:27:12 -0500 Subject: [PATCH 1031/1342] lib: Consolidate VIEW_NODE to be ENABLE_NODE as well If you are in VIEW_NODE, the command should exist in ENABLE_NODE as well. This is being done to reduce chances of code being added to one but not the other NODE. Signed-off-by: Donald Sharp --- lib/command.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/command.c b/lib/command.c index 80893602d..308859350 100644 --- a/lib/command.c +++ b/lib/command.c @@ -622,6 +622,9 @@ install_element (enum node_type ntype, struct cmd_element *cmd) vector_set (cnode->cmd_vector, cmd); if (cmd->tokens == NULL) cmd->tokens = cmd_parse_format(cmd->string, cmd->doc); + + if (ntype == VIEW_NODE) + install_element (ENABLE_NODE, cmd); } static const unsigned char itoa64[] = From 68b45cc592d5d61e748e8d99ec9f84e63aa73213 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 11 Mar 2016 14:27:13 -0500 Subject: [PATCH 1032/1342] *: Consolidate all double VIEW_NODE and ENABLE_NODE's If a command is put into the VIEW_NODE, it is going into the ENABLE_NODE as well. This is especially true for show commands. As such if a command is in both consolidate it down to VIEW_NODE. Signed-off-by: Donald Sharp --- bgpd/bgp_encap.c | 19 -- bgpd/bgp_route.c | 370 ++------------------------------------- bgpd/bgp_vty.c | 71 ++------ isisd/isisd.c | 21 --- lib/command.c | 2 - lib/memory.c | 2 - lib/plist.c | 24 --- ospf6d/ospf6_area.c | 4 - ospf6d/ospf6_asbr.c | 1 - ospf6d/ospf6_interface.c | 8 - ospf6d/ospf6_neighbor.c | 2 - ospf6d/ospf6_top.c | 9 - ospf6d/ospf6_zebra.c | 1 - ospf6d/ospf6d.c | 7 - ospfd/ospf_te.c | 2 - ospfd/ospf_vty.c | 18 -- pimd/pim_cmd.c | 33 ---- ripd/ripd.c | 2 - ripngd/ripng_debug.c | 1 - ripngd/ripngd.c | 3 - zebra/interface.c | 9 - zebra/zebra_vty.c | 57 ------ zebra/zserv.c | 3 - 23 files changed, 24 insertions(+), 645 deletions(-) diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 1a09ba601..edd9d7675 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -955,23 +955,4 @@ bgp_encap_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); - - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); - - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); - } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f99045a84..746c54573 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -16226,134 +16226,12 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rd_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rd_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_afi_safi_view_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_cidr_only_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cidr_only_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community4_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_address_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_flap_address_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_address_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_cidr_only_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_cidr_only_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_damp_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_damp_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); - - /* BGP dampening clear commands */ + /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); - /* prefix count */ - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_prefix_counts_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_prefix_counts_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd); - /* New config IPv6 BGP commands. */ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); @@ -16453,56 +16331,6 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv4_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); - /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); @@ -16677,6 +16505,7 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); @@ -16706,97 +16535,10 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_address_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_regexp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_filter_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_route_map_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); + + install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); install_element (VIEW_NODE, &show_bgp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_route_cmd); @@ -16836,6 +16578,7 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); + install_element (RESTRICTED_NODE, &show_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_cmd); @@ -16849,46 +16592,10 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); - install_element (ENABLE_NODE, &show_bgp_route_cmd); - install_element (ENABLE_NODE, &show_bgp_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_regexp_cmd); - install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_bgp_route_map_cmd); - install_element (ENABLE_NODE, &show_bgp_community_all_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); - install_element (ENABLE_NODE, &show_bgp_community_cmd); - install_element (ENABLE_NODE, &show_bgp_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_list_cmd); - install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); - install_element (ENABLE_NODE, &show_bgp_view_cmd); - install_element (ENABLE_NODE, &show_bgp_view_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_flap_cmd); - install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); - install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); @@ -16925,54 +16632,12 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); - install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); - install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); - install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); /* old with name safi collision */ install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); @@ -16990,32 +16655,23 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); - install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); - install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); + + install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); } void diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 6db3dcb1c..a8383cf86 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10961,11 +10961,9 @@ bgp_vty_init (void) /* "show ip bgp summary" commands. */ install_element (VIEW_NODE, &show_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_summary_cmd); install_element (VIEW_NODE, &show_bgp_summary_1w_cmd); install_element (RESTRICTED_NODE, &show_bgp_summary_1w_cmd); - install_element (ENABLE_NODE, &show_bgp_summary_1w_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); @@ -10980,6 +10978,7 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); @@ -10993,52 +10992,34 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv4_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); - - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_encap_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_encap_summary_cmd); - - install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); /* "show ip bgp neighbors" commands. */ install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); - install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); /* "show ip bgp rsclient" commands. */ install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); + + install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); @@ -11047,22 +11028,15 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); /* "show ip bgp paths" commands. */ install_element (VIEW_NODE, &show_bgp_ipv4_paths_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_paths_cmd); /* "show ip bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd); /* "show ip bgp attribute-info" commands. */ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd); /* "redistribute" commands. */ install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd); @@ -11093,12 +11067,13 @@ bgp_vty_init (void) /* "show bgp memory" commands. */ install_element (VIEW_NODE, &show_bgp_memory_cmd); install_element (RESTRICTED_NODE, &show_bgp_memory_cmd); - install_element (ENABLE_NODE, &show_bgp_memory_cmd); /* "show bgp views" commands. */ install_element (VIEW_NODE, &show_bgp_views_cmd); install_element (RESTRICTED_NODE, &show_bgp_views_cmd); - install_element (ENABLE_NODE, &show_bgp_views_cmd); + + /* "show bgp views" commands. */ + install_element (VIEW_NODE, &show_bgp_views_cmd); /* non afi/safi forms of commands */ install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); @@ -11115,13 +11090,6 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); @@ -11137,25 +11105,13 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); - install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd); - install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); @@ -11165,13 +11121,8 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); /* Community-list. */ community_list_vty (); } diff --git a/isisd/isisd.c b/isisd/isisd.c index 26b71257d..202b04061 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -3286,26 +3286,6 @@ isis_init () install_element (VIEW_NODE, &show_database_detail_cmd); install_element (VIEW_NODE, &show_database_detail_arg_cmd); - install_element (ENABLE_NODE, &show_isis_summary_cmd); - - install_element (ENABLE_NODE, &show_isis_interface_cmd); - install_element (ENABLE_NODE, &show_isis_interface_detail_cmd); - install_element (ENABLE_NODE, &show_isis_interface_arg_cmd); - - install_element (ENABLE_NODE, &show_isis_neighbor_cmd); - install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd); - install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd); - install_element (ENABLE_NODE, &clear_isis_neighbor_cmd); - install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd); - - install_element (ENABLE_NODE, &show_hostname_cmd); - install_element (ENABLE_NODE, &show_database_cmd); - install_element (ENABLE_NODE, &show_database_arg_cmd); - install_element (ENABLE_NODE, &show_database_arg_detail_cmd); - install_element (ENABLE_NODE, &show_database_detail_cmd); - install_element (ENABLE_NODE, &show_database_detail_arg_cmd); - install_element (ENABLE_NODE, &show_debugging_cmd); - install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &debug_isis_adj_cmd); @@ -3455,6 +3435,5 @@ isis_init () install_element (ISIS_NODE, &no_topology_baseis_cmd); install_element (ISIS_NODE, &no_topology_baseis_noid_cmd); install_element (VIEW_NODE, &show_isis_generated_topology_cmd); - install_element (ENABLE_NODE, &show_isis_generated_topology_cmd); #endif /* TOPOLOGY_GENERATE */ } diff --git a/lib/command.c b/lib/command.c index 308859350..56220dac4 100644 --- a/lib/command.c +++ b/lib/command.c @@ -4246,12 +4246,10 @@ cmd_init (int terminal) install_element (CONFIG_NODE, &no_service_terminal_length_cmd); install_element (VIEW_NODE, &show_thread_cpu_cmd); - install_element (ENABLE_NODE, &show_thread_cpu_cmd); install_element (RESTRICTED_NODE, &show_thread_cpu_cmd); install_element (ENABLE_NODE, &clear_thread_cpu_cmd); install_element (VIEW_NODE, &show_work_queues_cmd); - install_element (ENABLE_NODE, &show_work_queues_cmd); } install_element (CONFIG_NODE, &show_commandtree_cmd); srandom(time(NULL)); diff --git a/lib/memory.c b/lib/memory.c index 269520d5a..13e1fb7c0 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -425,8 +425,6 @@ memory_init (void) install_element (RESTRICTED_NODE, &show_memory_cmd); install_element (VIEW_NODE, &show_memory_cmd); - - install_element (ENABLE_NODE, &show_memory_cmd); } /* Stats querying from users */ diff --git a/lib/plist.c b/lib/plist.c index 699c9b131..abce63376 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -2686,23 +2686,11 @@ prefix_list_init_ipv4 (void) install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd); install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd); - install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd); - install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd); } -#ifdef HAVE_IPV6 /* Prefix-list node. */ static struct cmd_node prefix_ipv6_node = { @@ -2763,22 +2751,10 @@ prefix_list_init_ipv6 (void) install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd); install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd); - install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd); } -#endif /* HAVE_IPV6 */ void prefix_list_init () diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 9b704221b..096748210 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -793,10 +793,6 @@ ospf6_area_init (void) install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); - install_element (OSPF6_NODE, &area_range_cmd); install_element (OSPF6_NODE, &area_range_advertise_cmd); install_element (OSPF6_NODE, &no_area_range_cmd); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 6eca142de..c3c06edc2 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1303,7 +1303,6 @@ ospf6_asbr_init (void) ospf6_install_lsa_handler (&as_external_handler); install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 26f68ac54..9aa6908fa 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1874,14 +1874,6 @@ ospf6_interface_init (void) install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); install_element (CONFIG_NODE, &interface_cmd); install_default (INTERFACE_NODE); diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 4e637970f..fbad62a6c 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -936,8 +936,6 @@ ospf6_neighbor_init (void) { install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); } DEFUN (debug_ospf6_neighbor, diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 1288bc74e..145a88e5a 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -1398,7 +1398,6 @@ ospf6_top_init (void) install_node (&ospf6_node, config_write_ospf6); install_element (VIEW_NODE, &show_ipv6_ospf6_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd); install_element (CONFIG_NODE, &router_ospf6_cmd); install_element (CONFIG_NODE, &no_router_ospf6_cmd); @@ -1410,14 +1409,6 @@ ospf6_top_init (void) install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_detail_cmd); install_default (OSPF6_NODE); install_element (OSPF6_NODE, &ospf6_router_id_cmd); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 1f0daa161..5d5db0b93 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -749,7 +749,6 @@ ospf6_zebra_init (struct thread_master *master) /* Install command element for zebra node. */ install_element (VIEW_NODE, &show_zebra_cmd); - install_element (ENABLE_NODE, &show_zebra_cmd); install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index c2baa314a..bfcc242a8 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1791,21 +1791,14 @@ ospf6_init (void) install_element_ospf6_debug_flood (); install_element (VIEW_NODE, &show_version_ospf6_cmd); - install_element (ENABLE_NODE, &show_version_ospf6_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_router_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_network_cmd); - install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); #define INSTALL(n,c) \ install_element (n ## _NODE, &show_ipv6_ospf6_ ## c) diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 03109bc82..125a46ffc 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1886,8 +1886,6 @@ ospf_mpls_te_register_vty (void) { install_element (VIEW_NODE, &show_mpls_te_router_cmd); install_element (VIEW_NODE, &show_mpls_te_link_cmd); - install_element (ENABLE_NODE, &show_mpls_te_router_cmd); - install_element (ENABLE_NODE, &show_mpls_te_link_cmd); install_element (OSPF_NODE, &mpls_te_cmd); install_element (OSPF_NODE, &no_mpls_te_cmd); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index fb17dff39..dec70953a 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -7529,7 +7529,6 @@ ospf_vty_show_init (void) { /* "show ip ospf" commands. */ install_element (VIEW_NODE, &show_ip_ospf_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_cmd); /* "show ip ospf database" commands. */ install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd); @@ -7539,17 +7538,9 @@ ospf_vty_show_init (void) install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_database_cmd); /* "show ip ospf interface" commands. */ install_element (VIEW_NODE, &show_ip_ospf_interface_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd); /* "show ip ospf neighbor" commands. */ install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd); @@ -7559,19 +7550,10 @@ ospf_vty_show_init (void) install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd); /* "show ip ospf route" commands. */ install_element (VIEW_NODE, &show_ip_ospf_route_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_route_cmd); install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd); } diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 69c04ec70..749eeab63 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -4861,39 +4861,6 @@ void pim_cmd_init() install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_join_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_parameters_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_groups_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_sources_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_sources_retransmissions_cmd); - install_element (ENABLE_NODE, &show_ip_igmp_querier_cmd); - install_element (ENABLE_NODE, &show_ip_pim_address_cmd); - install_element (ENABLE_NODE, &show_ip_pim_assert_cmd); - install_element (ENABLE_NODE, &show_ip_pim_assert_internal_cmd); - install_element (ENABLE_NODE, &show_ip_pim_assert_metric_cmd); - install_element (ENABLE_NODE, &show_ip_pim_assert_winner_metric_cmd); - install_element (ENABLE_NODE, &show_ip_pim_dr_cmd); - install_element (ENABLE_NODE, &show_ip_pim_hello_cmd); - install_element (ENABLE_NODE, &show_ip_pim_interface_cmd); - install_element (ENABLE_NODE, &show_ip_pim_join_cmd); - install_element (ENABLE_NODE, &show_ip_pim_jp_override_interval_cmd); - install_element (ENABLE_NODE, &show_ip_pim_lan_prune_delay_cmd); - install_element (ENABLE_NODE, &show_ip_pim_local_membership_cmd); - install_element (ENABLE_NODE, &show_ip_pim_neighbor_cmd); - install_element (ENABLE_NODE, &show_ip_pim_rpf_cmd); - install_element (ENABLE_NODE, &show_ip_pim_secondary_cmd); - install_element (ENABLE_NODE, &show_ip_pim_upstream_cmd); - install_element (ENABLE_NODE, &show_ip_pim_upstream_join_desired_cmd); - install_element (ENABLE_NODE, &show_ip_pim_upstream_rpf_cmd); - install_element (ENABLE_NODE, &show_ip_multicast_cmd); - install_element (ENABLE_NODE, &show_ip_mroute_cmd); - install_element (ENABLE_NODE, &show_ip_mroute_count_cmd); - install_element (ENABLE_NODE, &show_ip_rib_cmd); - install_element (ENABLE_NODE, &show_ip_ssmpingd_cmd); - install_element (ENABLE_NODE, &show_debugging_pim_cmd); - install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd); install_element (ENABLE_NODE, &test_pim_receive_dump_cmd); diff --git a/ripd/ripd.c b/ripd/ripd.c index 385dab997..a5bc067a9 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -4075,8 +4075,6 @@ rip_init (void) /* Install rip commands. */ install_element (VIEW_NODE, &show_ip_rip_cmd); install_element (VIEW_NODE, &show_ip_rip_status_cmd); - install_element (ENABLE_NODE, &show_ip_rip_cmd); - install_element (ENABLE_NODE, &show_ip_rip_status_cmd); install_element (CONFIG_NODE, &router_rip_cmd); install_element (CONFIG_NODE, &no_router_rip_cmd); diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c index c1eb39ba2..eb8ff5dc6 100644 --- a/ripngd/ripng_debug.c +++ b/ripngd/ripng_debug.c @@ -266,7 +266,6 @@ ripng_debug_init () install_element (VIEW_NODE, &show_debugging_ripng_cmd); - install_element (ENABLE_NODE, &show_debugging_ripng_cmd); install_element (ENABLE_NODE, &debug_ripng_events_cmd); install_element (ENABLE_NODE, &debug_ripng_packet_cmd); install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 910583121..d94bea380 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -3027,9 +3027,6 @@ ripng_init () install_element (VIEW_NODE, &show_ipv6_ripng_cmd); install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd); - install_element (ENABLE_NODE, &show_ipv6_ripng_cmd); - install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd); - install_element (CONFIG_NODE, &router_ripng_cmd); install_element (CONFIG_NODE, &no_router_ripng_cmd); diff --git a/zebra/interface.c b/zebra/interface.c index 8a9225ac1..b22186dfe 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1796,15 +1796,6 @@ zebra_if_init (void) install_element (VIEW_NODE, &show_interface_name_cmd); install_element (VIEW_NODE, &show_interface_name_vrf_cmd); install_element (VIEW_NODE, &show_interface_name_vrf_all_cmd); - install_element (ENABLE_NODE, &show_interface_cmd); - install_element (ENABLE_NODE, &show_interface_vrf_cmd); - install_element (ENABLE_NODE, &show_interface_vrf_all_cmd); - install_element (ENABLE_NODE, &show_interface_name_cmd); - install_element (ENABLE_NODE, &show_interface_name_vrf_cmd); - install_element (ENABLE_NODE, &show_interface_name_vrf_all_cmd); - install_element (ENABLE_NODE, &show_interface_desc_cmd); - install_element (ENABLE_NODE, &show_interface_desc_vrf_cmd); - install_element (ENABLE_NODE, &show_interface_desc_vrf_all_cmd); install_element (CONFIG_NODE, &zebra_interface_cmd); install_element (CONFIG_NODE, &zebra_interface_vrf_cmd); install_element (CONFIG_NODE, &no_interface_cmd); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 3973e4382..23660d7dc 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3854,7 +3854,6 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &ip_protocol_cmd); install_element (CONFIG_NODE, &no_ip_protocol_cmd); install_element (VIEW_NODE, &show_ip_protocol_cmd); - install_element (ENABLE_NODE, &show_ip_protocol_cmd); install_element (CONFIG_NODE, &ip_route_cmd); install_element (CONFIG_NODE, &ip_route_flags_cmd); install_element (CONFIG_NODE, &ip_route_flags2_cmd); @@ -3888,19 +3887,9 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_route_supernets_cmd); install_element (VIEW_NODE, &show_ip_route_summary_cmd); install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_route_cmd); - install_element (ENABLE_NODE, &show_ip_route_addr_cmd); - install_element (ENABLE_NODE, &show_ip_route_prefix_cmd); - install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ip_route_protocol_cmd); - install_element (ENABLE_NODE, &show_ip_route_supernets_cmd); - install_element (ENABLE_NODE, &show_ip_route_summary_cmd); - install_element (ENABLE_NODE, &show_ip_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ip_rpf_cmd); - install_element (ENABLE_NODE, &show_ip_rpf_cmd); install_element (VIEW_NODE, &show_ip_rpf_addr_cmd); - install_element (ENABLE_NODE, &show_ip_rpf_addr_cmd); /* Commands for VRF */ @@ -3942,14 +3931,6 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_route_supernets_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_summary_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_summary_prefix_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_addr_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_prefix_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_prefix_longer_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_protocol_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_supernets_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_summary_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_route_summary_prefix_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_vrf_all_cmd); install_element (VIEW_NODE, &show_ip_route_addr_vrf_all_cmd); @@ -3959,25 +3940,12 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_route_supernets_vrf_all_cmd); install_element (VIEW_NODE, &show_ip_route_summary_vrf_all_cmd); install_element (VIEW_NODE, &show_ip_route_summary_prefix_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_addr_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_prefix_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_prefix_longer_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_protocol_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_supernets_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_summary_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_route_summary_prefix_vrf_all_cmd); install_element (VIEW_NODE, &show_ip_rpf_vrf_cmd); install_element (VIEW_NODE, &show_ip_rpf_vrf_all_cmd); install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_cmd); install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_rpf_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_rpf_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ip_rpf_addr_vrf_cmd); - install_element (ENABLE_NODE, &show_ip_rpf_addr_vrf_all_cmd); -#ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); install_element (CONFIG_NODE, &ipv6_route_flags_cmd); install_element (CONFIG_NODE, &ipv6_route_ifname_cmd); @@ -4001,16 +3969,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_route_addr_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_summary_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_mroute_cmd); - install_element (ENABLE_NODE, &show_ipv6_mroute_cmd); /* Commands for VRF */ @@ -4038,13 +3998,6 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_route_addr_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_protocol_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_addr_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_prefix_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_summary_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_vrf_all_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_vrf_all_cmd); @@ -4053,18 +4006,8 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_route_addr_vrf_all_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_vrf_all_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_protocol_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_addr_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_prefix_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_summary_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_vrf_all_cmd); install_element (VIEW_NODE, &show_ipv6_mroute_vrf_cmd); - install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd); - install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_all_cmd); -#endif /* HAVE_IPV6 */ } diff --git a/zebra/zserv.c b/zebra/zserv.c index c0f9a9094..054cdb32d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1956,20 +1956,17 @@ zebra_init (void) #endif install_element (VIEW_NODE, &show_ip_forwarding_cmd); - install_element (ENABLE_NODE, &show_ip_forwarding_cmd); install_element (CONFIG_NODE, &ip_forwarding_cmd); install_element (CONFIG_NODE, &no_ip_forwarding_cmd); install_element (ENABLE_NODE, &show_zebra_client_cmd); #ifdef HAVE_NETLINK install_element (VIEW_NODE, &show_table_cmd); - install_element (ENABLE_NODE, &show_table_cmd); install_element (CONFIG_NODE, &config_table_cmd); #endif /* HAVE_NETLINK */ #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_ipv6_forwarding_cmd); - install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd); install_element (CONFIG_NODE, &ipv6_forwarding_cmd); install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd); #endif /* HAVE_IPV6 */ From 41de629c1fe88f9ea95d0400af6896f3c84a0dff Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 3 May 2016 19:59:41 +0200 Subject: [PATCH 1033/1342] lib: add api method to read current config path Signed-off-by: Christian Franke --- lib/command.c | 6 ++++++ lib/command.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/command.c b/lib/command.c index 56220dac4..12e8bb100 100644 --- a/lib/command.c +++ b/lib/command.c @@ -4108,6 +4108,12 @@ host_config_set (char *filename) host.config = XSTRDUP (MTYPE_HOST, filename); } +const char * +host_config_get (void) +{ + return host.config; +} + void install_default (enum node_type node) { diff --git a/lib/command.h b/lib/command.h index 6a20e2324..09bc516d6 100644 --- a/lib/command.h +++ b/lib/command.h @@ -556,7 +556,7 @@ extern struct cmd_element config_exit_cmd; extern struct cmd_element config_quit_cmd; extern struct cmd_element config_help_cmd; extern struct cmd_element config_list_cmd; -extern char *host_config_file (void); +extern const char *host_config_get (void); extern void host_config_set (char *); extern void print_version (const char *); From 921936652359fe72728eb196aa9107310f02a4d4 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 16 Jun 2016 15:53:26 +0100 Subject: [PATCH 1034/1342] lib: keep hash of node's commands to detect duplicate installs * command.h: (struct cmd_node) Add a hash, so duplicate installs of a cmd_element to a command node can be detected. To help catch strays from the VIEW/ENABLE node consolidation particularly (installs to VIEW automatically install to ENABLE too now). * command.c: (cmd_hash_{key,cmp}) helpers for the hash - just directly on the pointer value is sufficient to catch the main problem. (install_node) setup the hash for the command node. (install_element) check for duplicate installs. The assert on the cmd_parse_format seems misplaced. (install_default_basic) separate the basic, VIEW, node default commands to here. (cmd_init) get rid of dupes, given consolidation. (cmd_terminate) clean up the node command hash. Not done: The (struct cmd_node)'s vector could be replaced with the cmd hash, however much of the command parser depends heavily on the vector and it's a lot of work to change. A vector_lookup_value could also work, particularly if vector could be backed by a hash. The duplicate check could be disabled in releases - but useful in development. It's a little extra overhead at startup. The command initialisation overhead is already something that bites in micro-benchmarks - makes it easy for other implementations to show how much faster they are with benchmarks where other load is low enough that startup time is a factor. --- lib/command.c | 73 +++++++++++++++++++++++++++++++++++++-------------- lib/command.h | 6 ++++- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/lib/command.c b/lib/command.c index 12e8bb100..fa2ef1180 100644 --- a/lib/command.c +++ b/lib/command.c @@ -212,6 +212,18 @@ argv_concat (const char **argv, int argc, int shift) return str; } +static unsigned int +cmd_hash_key (void *p) +{ + return (uintptr_t) p; +} + +static int +cmd_hash_cmp (const void *a, const void *b) +{ + return a == b; +} + /* Install top node of command vector. */ void install_node (struct cmd_node *node, @@ -220,6 +232,7 @@ install_node (struct cmd_node *node, vector_set_index (cmdvec, node->node, node); node->func = func; node->cmd_vector = vector_init (VECTOR_MIN_SIZE); + node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp); } /* Breaking up string into each command piece. I assume given @@ -608,7 +621,11 @@ install_element (enum node_type ntype, struct cmd_element *cmd) /* cmd_init hasn't been called */ if (!cmdvec) - return; + { + fprintf (stderr, "%s called before cmd_init, breakage likely\n", + __func__); + return; + } cnode = vector_slot (cmdvec, ntype); @@ -618,7 +635,17 @@ install_element (enum node_type ntype, struct cmd_element *cmd) ntype); exit (1); } - + + if (hash_lookup (cnode->cmd_hash, cmd) != NULL) + { + fprintf (stderr, + "Multiple command installs to node %d of command:\n%s\n", + ntype, cmd->string); + return; + } + + assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern)); + vector_set (cnode->cmd_vector, cmd); if (cmd->tokens == NULL) cmd->tokens = cmd_parse_format(cmd->string, cmd->doc); @@ -4114,15 +4141,30 @@ host_config_get (void) return host.config; } -void -install_default (enum node_type node) +static void +install_default_basic (enum node_type node) { install_element (node, &config_exit_cmd); install_element (node, &config_quit_cmd); - install_element (node, &config_end_cmd); install_element (node, &config_help_cmd); install_element (node, &config_list_cmd); +} +/* Install common/default commands for a privileged node */ +void +install_default (enum node_type node) +{ + /* VIEW_NODE is inited below, via install_default_basic, and + install_element's of commands to VIEW_NODE automatically are + also installed to ENABLE_NODE. + + For all other nodes, we must ensure install_default_basic is + also called/ + */ + if (node != VIEW_NODE && node != ENABLE_NODE) + install_default_basic (node); + + install_element (node, &config_end_cmd); install_element (node, &config_write_terminal_cmd); install_element (node, &config_write_file_cmd); install_element (node, &config_write_memory_cmd); @@ -4142,7 +4184,7 @@ cmd_init (int terminal) /* Allocate initial top vector of commands. */ cmdvec = vector_init (VECTOR_MIN_SIZE); - + /* Default host value settings. */ host.name = NULL; host.password = NULL; @@ -4165,10 +4207,8 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_version_cmd); if (terminal) { - install_element (VIEW_NODE, &config_list_cmd); - install_element (VIEW_NODE, &config_exit_cmd); - install_element (VIEW_NODE, &config_quit_cmd); - install_element (VIEW_NODE, &config_help_cmd); + install_default_basic (VIEW_NODE); + install_element (VIEW_NODE, &config_enable_cmd); install_element (VIEW_NODE, &config_terminal_length_cmd); install_element (VIEW_NODE, &config_terminal_no_length_cmd); @@ -4176,10 +4216,6 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_commandtree_cmd); install_element (VIEW_NODE, &echo_cmd); - install_element (RESTRICTED_NODE, &config_list_cmd); - install_element (RESTRICTED_NODE, &config_exit_cmd); - install_element (RESTRICTED_NODE, &config_quit_cmd); - install_element (RESTRICTED_NODE, &config_help_cmd); install_element (RESTRICTED_NODE, &config_enable_cmd); install_element (RESTRICTED_NODE, &config_terminal_length_cmd); install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd); @@ -4195,15 +4231,9 @@ cmd_init (int terminal) install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); } install_element (ENABLE_NODE, &show_startup_config_cmd); - install_element (ENABLE_NODE, &show_version_cmd); - install_element (ENABLE_NODE, &show_commandtree_cmd); if (terminal) { - install_element (ENABLE_NODE, &config_terminal_length_cmd); - install_element (ENABLE_NODE, &config_terminal_no_length_cmd); - install_element (ENABLE_NODE, &show_logging_cmd); - install_element (ENABLE_NODE, &echo_cmd); install_element (ENABLE_NODE, &config_logmsg_cmd); install_default (CONFIG_NODE); @@ -4329,6 +4359,9 @@ cmd_terminate () cmd_terminate_element(cmd_element); vector_free (cmd_node_v); + hash_clean (cmd_node->cmd_hash, NULL); + hash_free (cmd_node->cmd_hash); + cmd_node->cmd_hash = NULL; } vector_free (cmdvec); diff --git a/lib/command.h b/lib/command.h index 09bc516d6..214b1d51b 100644 --- a/lib/command.h +++ b/lib/command.h @@ -26,6 +26,7 @@ #include "vector.h" #include "vty.h" #include "lib/route_types.h" +#include "hash.h" /* Host configuration variable */ struct host @@ -127,7 +128,10 @@ struct cmd_node int (*func) (struct vty *); /* Vector of this node's command list. */ - vector cmd_vector; + vector cmd_vector; + + /* Hashed index of command node list, for de-dupping primarily */ + struct hash *cmd_hash; }; enum From 6bcee414a487024e7865fb29d4e583870406d914 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 12 Mar 2016 19:58:09 +0100 Subject: [PATCH 1035/1342] lib: fix MIN/MAX macros to not double-eval cf. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html (Works on all compilers on Quagga's compiler support list in doc/overview.texi) Signed-off-by: David Lamparter Tested-by: NetDEF CI System Acked-by: Donald Sharp --- lib/zebra.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/zebra.h b/lib/zebra.h index d9802830d..0ea5ee48d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -373,10 +373,16 @@ struct in_pktinfo /* MAX / MIN are not commonly defined, but useful */ #ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif +#define MAX(a, b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a > _b ? _a : _b; }) +#endif #ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MIN(a, b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a < _b ? _a : _b; }) #endif #define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0])) From 19be18a929c3afa343ac5435dba25f522e294d9b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 4 Mar 2016 15:28:55 -0500 Subject: [PATCH 1036/1342] lib: Abstract fd set operations Abstract FD set operations so that we can eventually choose what type of select/poll operation that we want to use. Signed-off-by: Donald Sharp --- lib/thread.c | 69 +++++++++++++++++++++++++++++++++++++--------------- lib/thread.h | 12 ++++++--- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 6c2b0b0ba..9b201de90 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -754,6 +754,41 @@ thread_get (struct thread_master *m, u_char type, return thread; } +#define fd_copy_fd_set(X) (X) + +static int +fd_select (int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *t) +{ + return(select(size, read, write, except, t)); +} + +static int +fd_is_set (int fd, thread_fd_set *fdset) +{ + return FD_ISSET (fd, fdset); +} + +static int +fd_set_read_write (int fd, thread_fd_set *fdset) +{ + if (FD_ISSET (fd, fdset)) + return 0; + + FD_SET (fd, fdset); + + return 1; +} + +static int +fd_clear_read_write (int fd, thread_fd_set *fdset) +{ + if (!FD_ISSET (fd, fdset)) + return 0; + + FD_CLR (fd, fdset); + return 1; +} + /* Add new read thread. */ struct thread * funcname_thread_add_read (struct thread_master *m, @@ -764,14 +799,13 @@ funcname_thread_add_read (struct thread_master *m, assert (m != NULL); - if (FD_ISSET (fd, &m->readfd)) + if (!fd_set_read_write (fd, &m->readfd)) { zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd); return NULL; } thread = thread_get (m, THREAD_READ, func, arg, debugargpass); - FD_SET (fd, &m->readfd); thread->u.fd = fd; thread_add_fd (m->read, thread); @@ -788,14 +822,13 @@ funcname_thread_add_write (struct thread_master *m, assert (m != NULL); - if (FD_ISSET (fd, &m->writefd)) + if (!fd_set_read_write (fd, &m->writefd)) { zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd); return NULL; } thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass); - FD_SET (fd, &m->writefd); thread->u.fd = fd; thread_add_fd (m->write, thread); @@ -923,13 +956,11 @@ thread_cancel (struct thread *thread) switch (thread->type) { case THREAD_READ: - assert (FD_ISSET (thread->u.fd, &thread->master->readfd)); - FD_CLR (thread->u.fd, &thread->master->readfd); + assert (fd_clear_read_write (thread->u.fd, &thread->master->readfd)); thread_array = thread->master->read; break; case THREAD_WRITE: - assert (FD_ISSET (thread->u.fd, &thread->master->writefd)); - FD_CLR (thread->u.fd, &thread->master->writefd); + assert (fd_clear_read_write (thread->u.fd, &thread->master->writefd)); thread_array = thread->master->write; break; case THREAD_TIMER: @@ -1039,7 +1070,8 @@ thread_run (struct thread_master *m, struct thread *thread, } static int -thread_process_fd (struct thread **thread_array, fd_set *fdset, fd_set *mfdset, int num, int fd_limit) +thread_process_fd (struct thread **thread_array, thread_fd_set *fdset, + thread_fd_set *mfdset, int num, int fd_limit) { struct thread *thread; int ready = 0, index; @@ -1049,10 +1081,9 @@ thread_process_fd (struct thread **thread_array, fd_set *fdset, fd_set *mfdset, for (index = 0; index < fd_limit && ready < num; ++index) { thread = thread_array[index]; - if (thread && FD_ISSET (THREAD_FD (thread), fdset)) + if (thread && fd_is_set (THREAD_FD (thread), fdset)) { - assert (FD_ISSET (THREAD_FD (thread), mfdset)); - FD_CLR(THREAD_FD (thread), mfdset); + assert (fd_clear_read_write (THREAD_FD (thread), mfdset)); thread_delete_fd (thread_array, thread); thread_list_add (&thread->master->ready, thread); thread->type = THREAD_READY; @@ -1107,9 +1138,9 @@ struct thread * thread_fetch (struct thread_master *m, struct thread *fetch) { struct thread *thread; - fd_set readfd; - fd_set writefd; - fd_set exceptfd; + thread_fd_set readfd; + thread_fd_set writefd; + thread_fd_set exceptfd; struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 }; struct timeval timer_val_bg; struct timeval *timer_wait = &timer_val; @@ -1142,9 +1173,9 @@ thread_fetch (struct thread_master *m, struct thread *fetch) thread_process (&m->event); /* Structure copy. */ - readfd = m->readfd; - writefd = m->writefd; - exceptfd = m->exceptfd; + readfd = fd_copy_fd_set(m->readfd); + writefd = fd_copy_fd_set(m->writefd); + exceptfd = fd_copy_fd_set(m->exceptfd); /* Calculate select wait timer if nothing else to do */ if (m->ready.count == 0) @@ -1178,7 +1209,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) timer_wait = &snmp_timer_wait; } #endif - num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); + num = fd_select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); /* Signals should get quick treatment */ if (num < 0) diff --git a/lib/thread.h b/lib/thread.h index 5a3bf7d57..dafd438a8 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -45,6 +45,12 @@ struct thread_list struct pqueue; +/* + * Abstract it so we can use different methodologies to + * select on data. + */ +typedef fd_set thread_fd_set; + /* Master of the theads. */ struct thread_master { @@ -56,9 +62,9 @@ struct thread_master struct thread_list unuse; struct pqueue *background; int fd_limit; - fd_set readfd; - fd_set writefd; - fd_set exceptfd; + thread_fd_set readfd; + thread_fd_set writefd; + thread_fd_set exceptfd; unsigned long alloc; }; From e0b8324deb490c52834775d2b805cbb57e003ce0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 4 Mar 2016 15:28:56 -0500 Subject: [PATCH 1037/1342] lib: Refactor read/write functionality Both the read and write functions used the same code slightly modified for reading and writing. Combine this code together. Signed-off-by: Donald Sharp Edited-by: Paul Jakma to retain the external library symbols, for ease of merging. --- lib/thread.c | 66 ++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 9b201de90..6608bb101 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -46,7 +46,6 @@ extern int agentx_enabled; #include #endif - /* Recent absolute time of day */ struct timeval recent_time; static struct timeval last_recent_time; @@ -768,17 +767,6 @@ fd_is_set (int fd, thread_fd_set *fdset) return FD_ISSET (fd, fdset); } -static int -fd_set_read_write (int fd, thread_fd_set *fdset) -{ - if (FD_ISSET (fd, fdset)) - return 0; - - FD_SET (fd, fdset); - - return 1; -} - static int fd_clear_read_write (int fd, thread_fd_set *fdset) { @@ -789,50 +777,56 @@ fd_clear_read_write (int fd, thread_fd_set *fdset) return 1; } -/* Add new read thread. */ -struct thread * -funcname_thread_add_read (struct thread_master *m, +static struct thread * +funcname_thread_add_read_write (int dir, struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, debugargdef) { - struct thread *thread; + struct thread *thread = NULL; + thread_fd_set *fdset = NULL; - assert (m != NULL); + if (dir == THREAD_READ) + fdset = &m->readfd; + else + fdset = &m->writefd; - if (!fd_set_read_write (fd, &m->readfd)) + if (FD_ISSET (fd, &m->readfd)) { - zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd); + zlog (NULL, LOG_WARNING, "There is already %s fd [%d]", + (dir = THREAD_READ) ? "read" : "write", fd); return NULL; } - thread = thread_get (m, THREAD_READ, func, arg, debugargpass); + FD_SET (fd, fdset); + + thread = thread_get (m, dir, func, arg, debugargpass); thread->u.fd = fd; - thread_add_fd (m->read, thread); + if (dir == THREAD_READ) + thread_add_fd (m->read, thread); + else + thread_add_fd (m->write, thread); return thread; } +/* Add new read thread. */ +struct thread * +funcname_thread_add_read (struct thread_master *m, + int (*func) (struct thread *), void *arg, int fd, + debugargdef) +{ + return funcname_thread_add_read_write (THREAD_READ, m, func, + arg, fd, debugargpass); +} + /* Add new write thread. */ struct thread * funcname_thread_add_write (struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, debugargdef) { - struct thread *thread; - - assert (m != NULL); - - if (!fd_set_read_write (fd, &m->writefd)) - { - zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd); - return NULL; - } - - thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass); - thread->u.fd = fd; - thread_add_fd (m->write, thread); - - return thread; + return funcname_thread_add_read_write (THREAD_WRITE, m, func, + arg, fd, debugargpass); } static struct thread * From 1ad00b07a10eb8b3f5c94348488735fb08f28717 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 13 Jul 2016 11:02:38 -0400 Subject: [PATCH 1038/1342] lib: Fix regression in thread.c * Fix regression introduced with merging of 'lib: Refactor read/write functionality' --- lib/thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/thread.c b/lib/thread.c index 6608bb101..41c362b02 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -790,7 +790,7 @@ funcname_thread_add_read_write (int dir, struct thread_master *m, else fdset = &m->writefd; - if (FD_ISSET (fd, &m->readfd)) + if (FD_ISSET (fd, fdset)) { zlog (NULL, LOG_WARNING, "There is already %s fd [%d]", (dir = THREAD_READ) ? "read" : "write", fd); From 54406ac4c6883725f8a337bdc4f15fb015926b0f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 4 Mar 2016 15:28:57 -0500 Subject: [PATCH 1039/1342] lib: Refactor thread_process_fd thread_process_fd is looping over the read and write fd's separately. There is no need to do this individually. loop over both the read and write fdset's at the same time. This will improve select processing performance, especially for large data sets. Signed-off-by: Donald Sharp --- lib/thread.c | 59 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 41c362b02..6fcddd789 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1064,25 +1064,45 @@ thread_run (struct thread_master *m, struct thread *thread, } static int -thread_process_fd (struct thread **thread_array, thread_fd_set *fdset, - thread_fd_set *mfdset, int num, int fd_limit) +thread_process_fds_helper (struct thread_master *m, struct thread *thread, thread_fd_set *fdset) +{ + thread_fd_set *mfdset = NULL; + struct thread **thread_array; + + if (!thread) + return 0; + + if (thread->type == THREAD_READ) + { + mfdset = &m->readfd; + thread_array = m->read; + } + else + { + mfdset = &m->writefd; + thread_array = m->write; + } + + if (fd_is_set (THREAD_FD (thread), fdset)) + { + fd_clear_read_write (THREAD_FD (thread), mfdset); + thread_delete_fd (thread_array, thread); + thread_list_add (&m->ready, thread); + thread->type = THREAD_READY; + return 1; + } + return 0; +} + +static int +thread_process_fds (struct thread_master *m, thread_fd_set *rset, thread_fd_set *wset, int num) { - struct thread *thread; int ready = 0, index; - assert (thread_array); - - for (index = 0; index < fd_limit && ready < num; ++index) + for (index = 0; index < m->fd_limit && ready < num; ++index) { - thread = thread_array[index]; - if (thread && fd_is_set (THREAD_FD (thread), fdset)) - { - assert (fd_clear_read_write (THREAD_FD (thread), mfdset)); - thread_delete_fd (thread_array, thread); - thread_list_add (&thread->master->ready, thread); - thread->type = THREAD_READY; - ready++; - } + ready += thread_process_fds_helper (m, m->read[index], rset); + ready += thread_process_fds_helper (m, m->write[index], wset); } return num - ready; } @@ -1211,7 +1231,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) if (errno == EINTR) continue; /* signal received - process it */ zlog_warn ("select() error: %s", safe_strerror (errno)); - return NULL; + return NULL; } #if defined HAVE_SNMP && defined SNMP_AGENTX @@ -1236,12 +1256,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) /* Got IO, process it */ if (num > 0) - { - /* Normal priority read thread. */ - num = thread_process_fd (m->read, &readfd, &m->readfd, num, m->fd_limit); - /* Write thread. */ - num = thread_process_fd (m->write, &writefd, &m->writefd, num, m->fd_limit); - } + thread_process_fds (m, &readfd, &writefd, num); #if 0 /* If any threads were made ready above (I/O or foreground timer), From 985c3556921fa669f86fe5e62130fbeb93d94ca9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 10 Mar 2016 20:16:47 -0500 Subject: [PATCH 1040/1342] bgpd: Fix code path that leads to uninitialized variables subtype and sublength are not initialized and if on Line 1877 BGP_ATTR_ENCAP != type we will not set subtype and sublength, but these variables are used immediately below that if statement. This issue was discovered via the freebsd compiler. Signed-off-by: Donald Sharp --- bgpd/bgp_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 42da7ff43..54ff54446 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1871,8 +1871,8 @@ bgp_attr_encap( } while (length >= 4) { - uint16_t subtype; - uint16_t sublength; + uint16_t subtype = 0; + uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; if (BGP_ATTR_ENCAP == type) { From 811577eaede8b6a7ea6ba3731c82eed1c4d07500 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 10 Mar 2016 20:16:48 -0500 Subject: [PATCH 1041/1342] lib: Remove unnecessary parentheses The freebsd compiler complains that there is an extra set of ()'s around the if statement. Signed-off-by: Donald Sharp --- lib/vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vty.c b/lib/vty.c index ff013cf61..38916617b 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -425,7 +425,7 @@ vty_command (struct vty *vty, char *buf) snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address); if (vty) for (i = 0; i < vector_active (vtyvec); i++) - if ((vty == vector_slot (vtyvec, i))) + if (vty == vector_slot (vtyvec, i)) { snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", i, vty->address); From 2ab67a7591d7693bb726dd82795017c8c3f52d99 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Fri, 1 Apr 2016 12:54:38 +0200 Subject: [PATCH 1042/1342] build: detect and create AM_SILENT_RULES macro if needed Older libs have problem with that: configure.ac:17: warning: macro `AM_SILENT_RULES' not found in library ... configure.ac:24: error: possibly undefined macro: AM_SILENT_RULES Tested-by: NetDEF CI System --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 35e402369..ec0351dbd 100755 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,8 @@ AC_CANONICAL_HOST() AC_CANONICAL_TARGET() AM_INIT_AUTOMAKE(1.6) + +m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS(config.h) From 880e31ca2d8a8a8fcbc28bfeac9bd13fc76dd2c1 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 3 May 2016 19:59:40 +0200 Subject: [PATCH 1043/1342] lib: use constant to replace magic value for length of quagga_timestamp Signed-off-by: Christian Franke --- lib/log.h | 3 ++- lib/vty.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/log.h b/lib/log.h index 514884cc9..7aa0896b7 100644 --- a/lib/log.h +++ b/lib/log.h @@ -186,6 +186,7 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter); It caches the most recent localtime result and can therefore avoid multiple calls within the same second. If buflen is too small, *buf will be set to '\0', and 0 will be returned. */ +#define QUAGGA_TIMESTAMP_LEN 40 extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, char *buf, size_t buflen); @@ -196,7 +197,7 @@ struct timestamp_control { size_t len; /* length of rendered timestamp */ int precision; /* configuration parameter */ int already_rendered; /* should be initialized to 0 */ - char buf[40]; /* will contain the rendered timestamp */ + char buf[QUAGGA_TIMESTAMP_LEN]; /* will contain the rendered timestamp */ }; /* Defines for use in command construction: */ diff --git a/lib/vty.c b/lib/vty.c index 38916617b..bf259fc4b 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -210,7 +210,7 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str, void vty_time_print (struct vty *vty, int cr) { - char buf [25]; + char buf[QUAGGA_TIMESTAMP_LEN]; if (quagga_timestamp(0, buf, sizeof(buf)) == 0) { From 00667cea1fbd088900f7909f2044da2a7e26270d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 3 May 2016 19:59:42 +0200 Subject: [PATCH 1044/1342] lib: add event_counter Signed-off-by: Christian Franke --- lib/Makefile.am | 4 +-- lib/event_counter.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ lib/event_counter.h | 56 ++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 lib/event_counter.c create mode 100644 lib/event_counter.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 57e859d6d..32998a870 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -13,7 +13,7 @@ libzebra_la_SOURCES = \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c + sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c event_counter.c BUILT_SOURCES = memtypes.h route_types.h gitversion.h @@ -28,7 +28,7 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h libospf.h vrf.h fifo.h + workqueue.h route_types.h libospf.h vrf.h fifo.h event_counter.h noinst_HEADERS = \ plist_int.h diff --git a/lib/event_counter.c b/lib/event_counter.c new file mode 100644 index 000000000..e94aa4c0f --- /dev/null +++ b/lib/event_counter.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 Christian Franke + * + * This file is part of Quagga. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, you can use, redistribute and/or modify it under the + * following terms: + * + * 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 + +#include "event_counter.h" + +void +event_counter_inc (struct event_counter *counter) +{ + counter->count++; + counter->last = time (NULL); +} + +const char * +event_counter_format (const struct event_counter *counter) +{ + struct tm last_change_store; + struct tm *last_change; + char timebuf[sizeof ("Thu, 01 Jan 1970 00:00:00 +0000")]; + static char rv[20 + sizeof (" last: ") + sizeof (timebuf)]; + + last_change = localtime_r (&counter->last, &last_change_store); + if (!last_change || strftime (timebuf, sizeof (timebuf), + "%a, %d %b %Y %T %z", last_change) == 0) + { + strncpy (timebuf, "???", sizeof (timebuf)); + } + + snprintf (rv, sizeof (rv), "%5llu last: %s", counter->count, + counter->last ? timebuf : "(never)"); + return rv; +} diff --git a/lib/event_counter.h b/lib/event_counter.h new file mode 100644 index 000000000..f40c6cde6 --- /dev/null +++ b/lib/event_counter.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Christian Franke + * + * This file is part of Quagga. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, you can use, redistribute and/or modify it under the + * following terms: + * + * 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 _ZEBRA_EVENT_COUNTER_H +#define _ZEBRA_EVENT_COUNTER_H + +struct event_counter +{ + unsigned long long count; + time_t last; +}; + +void event_counter_inc (struct event_counter *counter); +const char *event_counter_format (const struct event_counter *counter); + +#endif From 581ecbfe91d23791c116a8e3790208a17c1a5983 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 3 May 2016 19:59:43 +0200 Subject: [PATCH 1045/1342] zebra: count iface up/down events and keep last time of their occurrence It is quite useful to be able to assert whether specific interfaces have flapped or also to verify that specific interfaces have not flapped. By having counters for those events and storing the last time of their occurrence, this is made possible. Signed-off-by: Christian Franke Tested-by: NetDEF CI System --- zebra/interface.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ zebra/interface.h | 6 ++++++ zebra/main.c | 5 ++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/zebra/interface.c b/zebra/interface.c index b22186dfe..14dc5898f 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -33,6 +33,7 @@ #include "log.h" #include "zclient.h" #include "vrf.h" +#include "command.h" #include "zebra/interface.h" #include "zebra/rtadv.h" @@ -361,6 +362,35 @@ if_addr_wakeup (struct interface *ifp) } } +static void if_count_up(struct zebra_if *zif) +{ + event_counter_inc(&zif->up_events); +} + +static void if_count_down(struct zebra_if *zif) +{ + event_counter_inc(&zif->down_events); +} + +void +if_startup_count_up (void) +{ + vrf_iter_t iter; + struct interface *ifp; + struct zebra_if *zif; + struct listnode *node; + + for (iter = vrf_first(); iter != VRF_ITER_INVALID; iter = vrf_next(iter)) + { + for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist(iter), node, ifp)) + { + zif = ifp->info; + if (!zif->up_events.count && if_is_operative(ifp)) + if_count_up(zif); + } + } +} + /* Handle interface addition */ void if_add_update (struct interface *ifp) @@ -402,6 +432,17 @@ if_add_update (struct interface *ifp) zlog_debug ("interface %s vrf %u index %d is added.", ifp->name, ifp->vrf_id, ifp->ifindex); } + + if (host_config_get()) + { + /* If configuration and therefore link-detect have already been + * loaded, count an initial up event when new interfaces are added + * in up state. + * If configuration has not been loaded yet, this is handled by + * if_startup_count_up which is called after reading the config. */ + if (!if_data->up_events.count && if_is_operative(ifp)) + if_count_up(if_data); + } } /* Handle an interface delete event */ @@ -537,6 +578,8 @@ if_up (struct interface *ifp) struct connected *ifc; struct prefix *p; + if_count_up(ifp->info); + /* Notify the protocol daemons. */ zebra_interface_up_update (ifp); @@ -569,6 +612,11 @@ if_down (struct interface *ifp) struct listnode *next; struct connected *ifc; struct prefix *p; + struct zebra_if *zif; + + zif = ifp->info; + if (zif->up_events.count) + if_count_down(zif); /* Notify to the protocol daemons. */ zebra_interface_down_update (ifp); @@ -728,6 +776,11 @@ if_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, "down%s", VTY_NEWLINE); } + vty_out (vty, " Link ups: %s%s", + event_counter_format(&zebra_if->up_events), VTY_NEWLINE); + vty_out (vty, " Link downs: %s%s", + event_counter_format(&zebra_if->down_events), VTY_NEWLINE); + vty_out (vty, " vrf: %u%s", ifp->vrf_id, VTY_NEWLINE); if (ifp->desc) diff --git a/zebra/interface.h b/zebra/interface.h index dbb33c559..8baf186ab 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -23,6 +23,7 @@ #define _ZEBRA_INTERFACE_H #include "redistribute.h" +#include "event_counter.h" #ifdef HAVE_IRDP #include "zebra/irdp.h" @@ -188,6 +189,10 @@ struct zebra_if /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; + /* Information about up/down changes */ + struct event_counter up_events; + struct event_counter down_events; + #if defined(HAVE_RTADV) struct rtadvconf rtadv; #endif /* RTADV */ @@ -222,6 +227,7 @@ extern void if_up (struct interface *); extern void if_down (struct interface *); extern void if_refresh (struct interface *); extern void if_flags_update (struct interface *, uint64_t); +extern void if_startup_count_up (void); extern int if_subnet_add (struct interface *, struct connected *); extern int if_subnet_delete (struct interface *, struct connected *); diff --git a/zebra/main.c b/zebra/main.c index f3c08f192..8370732d7 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -440,7 +440,10 @@ main (int argc, char **argv) /* Don't start execution if we are in dry-run mode */ if (dryrun) return(0); - + + /* Count up events for interfaces */ + if_startup_count_up (); + /* Clean up rib. */ rib_weed_tables (); From d41e7b975b901f109608471b77c46718c1fb5b45 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 19 May 2015 15:38:43 +0100 Subject: [PATCH 1046/1342] lib/stream: add float/double <-> IEEE-754 single/double mux/demuxers * stream.{c,h}: Add stream_get{f,d} and stream_put{f,d}) demux and muxers to safely convert between big-endian IEEE-754 single and double binary format, as used in IETF RFCs, and C99. Implementation depends on host using __STDC_IEC_559__, which should be everything we care about. Should correctly error out otherwise. Thanks to Aidan Delaney and Olivier Dugeon for pointing out the __STDC_IEC_559__ macro. Update: GCC does not per se set __STDC_IEC_559__, so also test for __GCC_IEC_559 >= 1. --- lib/stream.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/stream.h | 6 +++++ 2 files changed, 72 insertions(+) diff --git a/lib/stream.c b/lib/stream.c index ca1a40f16..4d4f867dd 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -22,6 +22,8 @@ #include #include +/* primarily for __STDC_IEC_559__ with clang */ +#include #include "stream.h" #include "memory.h" @@ -493,6 +495,38 @@ stream_get_ipv4 (struct stream *s) return l; } +float +stream_getf (struct stream *s) +{ +#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 +/* we can safely assume 'float' is in the single precision + IEC 60559 binary format in host order */ + union { + float r; + uint32_t d; + } u; + u.d = stream_getl (s); + return u.r; +#else +#error "Please supply stream_getf implementation for this platform" +#endif +} + +double +stream_getd (struct stream *s) +{ +#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 + union { + double r; + uint64_t d; + } u; + u.d = stream_getq (s); + return u.r; +#else +#error "Please supply stream_getd implementation for this platform" +#endif +} + /* Copy to source to stream. * * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap @@ -601,6 +635,38 @@ stream_putq (struct stream *s, uint64_t q) return 8; } +int +stream_putf (struct stream *s, float f) +{ +#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 +/* we can safely assume 'float' is in the single precision + IEC 60559 binary format in host order */ + union { + float i; + uint32_t o; + } u; + u.i = f; + return stream_putl (s, u.o); +#else +#error "Please supply stream_putf implementation for this platform" +#endif +} + +int +stream_putd (struct stream *s, double d) +{ +#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 + union { + double i; + uint64_t o; + } u; + u.i = d; + return stream_putq (s, u.o); +#else +#error "Please supply stream_putd implementation for this platform" +#endif +} + int stream_putc_at (struct stream *s, size_t putp, u_char c) { diff --git a/lib/stream.h b/lib/stream.h index 1fc382d68..06b0ee12c 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -186,6 +186,12 @@ extern uint64_t stream_getq (struct stream *); extern uint64_t stream_getq_from (struct stream *, size_t); extern u_int32_t stream_get_ipv4 (struct stream *); +/* IEEE-754 floats */ +extern float stream_getf (struct stream *); +extern double stream_getd (struct stream *); +extern int stream_putf (struct stream *, float); +extern int stream_putd (struct stream *, double); + #undef stream_read #undef stream_write From 4359501e1a427159c9b49f3041889837aaaf2eb3 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 19 May 2015 18:50:49 +0100 Subject: [PATCH 1047/1342] lib: consolidate ntohf/htonf from ospfd/isisd TE to lib/network * lib/network.{c,h}: Consolidate the ntohf/htonf functions used in ospfd TE to here, using the value-passing variant that fits with existing ntoh/hton functions. * ospfd/ospf_opaque.c: Remove its variants. * ospfd/ospf_te.c: Update to use the consolidated, by-value variant. --- lib/network.c | 22 ++++++++++++++++++++++ lib/network.h | 3 +++ ospfd/ospf_opaque.c | 22 ---------------------- ospfd/ospf_opaque.h | 2 -- ospfd/ospf_te.c | 43 ++++++++++++++++++++++--------------------- 5 files changed, 47 insertions(+), 45 deletions(-) diff --git a/lib/network.c b/lib/network.c index 3373983b3..b81d5f8f3 100644 --- a/lib/network.c +++ b/lib/network.c @@ -93,3 +93,25 @@ set_nonblocking(int fd) } return 0; } + +float +htonf (float host) +{ +#ifdef __STDC_IEC_559__ + u_int32_t lu1, lu2; + float convert; + + memcpy (&lu1, &host, sizeof (u_int32_t)); + lu2 = htonl (lu1); + memcpy (&convert, &lu2, sizeof (u_int32_t)); + return convert; +#else +#error "Please supply htonf implementation for this platform" +#endif +} + +float +ntohf (float net) +{ + return htonf (net); +} diff --git a/lib/network.h b/lib/network.h index 4d9c2284b..0fcb575d1 100644 --- a/lib/network.h +++ b/lib/network.h @@ -37,4 +37,7 @@ extern int set_nonblocking(int fd); #define ERRNO_IO_RETRY(EN) \ (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) +extern float htonf (float); +extern float ntohf (float); + #endif /* _ZEBRA_NETWORK_H */ diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 697655d53..988a2e557 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -2138,28 +2138,6 @@ ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, * Followings are util functions; probably be used by Opaque-LSAs only... *------------------------------------------------------------------------*/ -void -htonf (float *src, float *dst) -{ - u_int32_t lu1, lu2; - - memcpy (&lu1, src, sizeof (u_int32_t)); - lu2 = htonl (lu1); - memcpy (dst, &lu2, sizeof (u_int32_t)); - return; -} - -void -ntohf (float *src, float *dst) -{ - u_int32_t lu1, lu2; - - memcpy (&lu1, src, sizeof (u_int32_t)); - lu2 = ntohl (lu1); - memcpy (dst, &lu2, sizeof (u_int32_t)); - return; -} - struct ospf * oi_to_top (struct ospf_interface *oi) { diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index b9490a0ff..2affa91b2 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -137,8 +137,6 @@ extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); -extern void htonf (float *src, float *dst); -extern void ntohf (float *src, float *dst); extern struct ospf *oi_to_top (struct ospf_interface *oi); #endif /* _ZEBRA_OSPF_OPAQUE_H */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 125a46ffc..e750933d0 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -38,6 +38,7 @@ #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ +#include "network.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -451,30 +452,30 @@ set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) } static void -set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) +set_linkparams_max_bw (struct mpls_te_link *lp, float fp) { lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); - htonf (fp, &lp->max_bw.value); + lp->max_bw.value = htonf (fp); return; } static void -set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) +set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float fp) { lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); - htonf (fp, &lp->max_rsv_bw.value); + lp->max_rsv_bw.value = htonf (fp); return; } static void -set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) +set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float fp) { /* Note that TLV-length field is the size of array. */ lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); - htonf (fp, &lp->unrsv_bw.value [priority]); + lp->unrsv_bw.value [priority] = htonf (fp); return; } @@ -511,11 +512,11 @@ initialize_linkparams (struct mpls_te_link *lp) fval = (float)((ifp->bandwidth ? ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); - set_linkparams_max_bw (lp, &fval); - set_linkparams_max_rsv_bw (lp, &fval); + set_linkparams_max_bw (lp, fval); + set_linkparams_max_rsv_bw (lp, fval); for (i = 0; i < 8; i++) - set_linkparams_unrsv_bw (lp, i, &fval); + set_linkparams_unrsv_bw (lp, i, fval); return; } @@ -1246,7 +1247,7 @@ show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh) float fval; top = (struct te_link_subtlv_max_bw *) tlvh; - ntohf (&top->value, &fval); + fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); @@ -1263,7 +1264,7 @@ show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) float fval; top = (struct te_link_subtlv_max_rsv_bw *) tlvh; - ntohf (&top->value, &fval); + fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); @@ -1283,7 +1284,7 @@ show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) top = (struct te_link_subtlv_unrsv_bw *) tlvh; for (i = 0; i < 8; i++) { - ntohf (&top->value[i], &fval); + fval = ntohf (top->value[i]); if (vty != NULL) vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); else @@ -1434,17 +1435,17 @@ ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) vty_out (vty, " mpls-te link metric %u%s", (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); - ntohf (&lp->max_bw.value, &fval); + fval = ntohf (lp->max_bw.value); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); - ntohf (&lp->max_rsv_bw.value, &fval); + fval = ntohf (lp->max_rsv_bw.value); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); for (i = 0; i < 8; i++) { - ntohf (&lp->unrsv_bw.value[i], &fval); + fval = ntohf (lp->unrsv_bw.value[i]); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link unrsv-bw %d %g%s", i, fval, VTY_NEWLINE); @@ -1637,7 +1638,7 @@ DEFUN (mpls_te_link_maxbw, return CMD_WARNING; } - ntohf (&lp->max_bw.value, &f1); + f1 = ntohf (lp->max_bw.value); if (sscanf (argv[0], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); @@ -1647,7 +1648,7 @@ DEFUN (mpls_te_link_maxbw, if (ntohs (lp->max_bw.header.type) == 0 || f1 != f2) { - set_linkparams_max_bw (lp, &f2); + set_linkparams_max_bw (lp, f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) @@ -1679,7 +1680,7 @@ DEFUN (mpls_te_link_max_rsv_bw, return CMD_WARNING; } - ntohf (&lp->max_rsv_bw.value, &f1); + f1 = ntohf (lp->max_rsv_bw.value); if (sscanf (argv[0], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); @@ -1689,7 +1690,7 @@ DEFUN (mpls_te_link_max_rsv_bw, if (ntohs (lp->max_rsv_bw.header.type) == 0 || f1 != f2) { - set_linkparams_max_rsv_bw (lp, &f2); + set_linkparams_max_rsv_bw (lp, f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) @@ -1730,7 +1731,7 @@ DEFUN (mpls_te_link_unrsv_bw, return CMD_WARNING; } - ntohf (&lp->unrsv_bw.value [priority], &f1); + f1 = ntohf (lp->unrsv_bw.value [priority]); if (sscanf (argv[1], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); @@ -1740,7 +1741,7 @@ DEFUN (mpls_te_link_unrsv_bw, if (ntohs (lp->unrsv_bw.header.type) == 0 || f1 != f2) { - set_linkparams_unrsv_bw (lp, priority, &f2); + set_linkparams_unrsv_bw (lp, priority, f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) From a3b161bb72d7fdb58e79afd0f706849601f77fe2 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 1 Aug 2016 15:13:58 +0100 Subject: [PATCH 1048/1342] lib: IEC559 tests are fragile, reduce to warning rather than error. * {network,stream}.c: Weaken the compile time tests for IEEE754 / IEC-559 binary floating point format from an error to a warning when not detected. I can't think of any platforms that are not IEEE-754 format, and as the testing for the defines appears to be fragile (often not set) the error just gives false positives. Even the warnings may be too much. Those should probably be moved to some configure test. Will do for now though, to fix compilation on CentOS and some BSDs. --- lib/network.c | 7 +++---- lib/stream.c | 33 +++++++++++++++------------------ 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/lib/network.c b/lib/network.c index b81d5f8f3..b982640e4 100644 --- a/lib/network.c +++ b/lib/network.c @@ -97,7 +97,9 @@ set_nonblocking(int fd) float htonf (float host) { -#ifdef __STDC_IEC_559__ +#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 0 +#warning "Unknown floating-point format on platform, htonf may break" +#endif u_int32_t lu1, lu2; float convert; @@ -105,9 +107,6 @@ htonf (float host) lu2 = htonl (lu1); memcpy (&convert, &lu2, sizeof (u_int32_t)); return convert; -#else -#error "Please supply htonf implementation for this platform" -#endif } float diff --git a/lib/stream.c b/lib/stream.c index 4d4f867dd..43575e1c9 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -498,33 +498,31 @@ stream_get_ipv4 (struct stream *s) float stream_getf (struct stream *s) { -#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 -/* we can safely assume 'float' is in the single precision - IEC 60559 binary format in host order */ +#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 +#warning "Unknown floating-point format, __func__ may be wrong" +#endif +/* we assume 'float' is in the single precision IEC 60559 binary + format, in host byte order */ union { float r; uint32_t d; } u; u.d = stream_getl (s); return u.r; -#else -#error "Please supply stream_getf implementation for this platform" -#endif } double stream_getd (struct stream *s) { -#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 +#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 +#warning "Unknown floating-point format, __func__ may be wrong" +#endif union { double r; uint64_t d; } u; u.d = stream_getq (s); return u.r; -#else -#error "Please supply stream_getd implementation for this platform" -#endif } /* Copy to source to stream. @@ -638,7 +636,10 @@ stream_putq (struct stream *s, uint64_t q) int stream_putf (struct stream *s, float f) { -#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 +#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 +#warning "Unknown floating-point format, __func__ may be wrong" +#endif + /* we can safely assume 'float' is in the single precision IEC 60559 binary format in host order */ union { @@ -647,24 +648,20 @@ stream_putf (struct stream *s, float f) } u; u.i = f; return stream_putl (s, u.o); -#else -#error "Please supply stream_putf implementation for this platform" -#endif } int stream_putd (struct stream *s, double d) { -#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1 +#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 +#warning "Unknown floating-point format, __func__ may be wrong" +#endif union { double i; uint64_t o; } u; u.i = d; return stream_putq (s, u.o); -#else -#error "Please supply stream_putd implementation for this platform" -#endif } int From 7e49a4f99273858887806c6251d958e1e664bedf Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 2 Aug 2016 13:36:03 +0100 Subject: [PATCH 1049/1342] build: Test for features.h and move include to lib/zebra.h * configure.ac: Check for features.h, which is needed to get Clang to define __STDC_IEC_559__. * lib/{stream.c,zebra.h}: move the features.h include to zebra.h, so lib/network.c also gets it. --- configure.ac | 2 +- lib/stream.c | 2 -- lib/zebra.h | 4 ++++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index ec0351dbd..c35a111c5 100755 --- a/configure.ac +++ b/configure.ac @@ -442,7 +442,7 @@ dnl ------------------------- AC_CHECK_HEADERS([stropts.h sys/ksym.h sys/times.h sys/select.h \ sys/types.h linux/version.h netdb.h asm/types.h \ sys/cdefs.h sys/param.h limits.h signal.h \ - sys/socket.h netinet/in.h time.h sys/time.h]) + sys/socket.h netinet/in.h time.h sys/time.h features.h]) dnl Utility macro to avoid retyping includes all the time m4_define([QUAGGA_INCLUDES], diff --git a/lib/stream.c b/lib/stream.c index 43575e1c9..b50992d6a 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -22,8 +22,6 @@ #include #include -/* primarily for __STDC_IEC_559__ with clang */ -#include #include "stream.h" #include "memory.h" diff --git a/lib/zebra.h b/lib/zebra.h index 0ea5ee48d..7c4adf1d7 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -94,6 +94,10 @@ typedef int socklen_t; #ifdef HAVE_STDBOOL_H #include #endif +/* primarily for __STDC_IEC_559__ with clang */ +#ifdef HAVE_FEATURES_H +#include +#endif /* machine dependent includes */ #ifdef SUNOS_5 From ae51c9d510fb7d9cc41ead8803af916c1f4b34ca Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 16:21:46 +0200 Subject: [PATCH 1050/1342] lib: Add new if_link_params structure This new structure is the basis to get new link parameters for Traffic Engineering from Zebra/interface layer to OSPFD and ISISD for the support of Traffic Engineering * lib/if.[c,h]: link parameters struture and get/set functions * lib/command.[c,h]: creation of a new link-node * lib/zclient.[c,h]: modification to the ZBUS message to convey the link parameters structure * lib/zebra.h: New ZBUS message * lib/memtypes.c: Add new memory type for Traffic Engineering support Signed-off-by: Olivier Dugeon --- lib/command.c | 8 +++ lib/command.h | 5 ++ lib/if.c | 42 ++++++++++++ lib/if.h | 64 +++++++++++++++++ lib/memtypes.c | 4 ++ lib/zclient.c | 182 +++++++++++++++++++++++++++++++++++++++++-------- lib/zclient.h | 4 ++ lib/zebra.h | 3 +- 8 files changed, 281 insertions(+), 31 deletions(-) diff --git a/lib/command.c b/lib/command.c index fa2ef1180..ab46fc4a6 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2632,8 +2632,12 @@ node_parent ( enum node_type node ) case KEYCHAIN_KEY_NODE: ret = KEYCHAIN_NODE; break; + case LINK_PARAMS_NODE: + ret = INTERFACE_NODE; + break; default: ret = CONFIG_NODE; + break; } return ret; @@ -3003,6 +3007,9 @@ DEFUN (config_exit, case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; + case LINK_PARAMS_NODE: + vty->node = INTERFACE_NODE; + break; default: break; } @@ -3052,6 +3059,7 @@ DEFUN (config_end, case MASC_NODE: case PIM_NODE: case VTY_NODE: + case LINK_PARAMS_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; break; diff --git a/lib/command.h b/lib/command.h index 214b1d51b..d8029fb39 100644 --- a/lib/command.h +++ b/lib/command.h @@ -109,6 +109,7 @@ enum node_type FORWARDING_NODE, /* IP forwarding node. */ PROTOCOL_NODE, /* protocol filtering node */ VTY_NODE, /* Vty node. */ + LINK_PARAMS_NODE, /* Link-parameters node */ }; /* Node which has some commands and prompt string and configuration @@ -509,6 +510,10 @@ struct cmd_token "(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" #define ISIS_STR "IS-IS information\n" #define AREA_TAG_STR "[area tag]\n" +#define MPLS_TE_STR "MPLS-TE specific commands\n" +#define LINK_PARAMS_STR "Configure interface link parameters\n" +#define OSPF_RI_STR "OSPF Router Information specific commands\n" +#define PCE_STR "PCE Router Information specific commands\n" #define CONF_BACKUP_EXT ".sav" diff --git a/lib/if.c b/lib/if.c index 44b8586e4..45c1accf0 100644 --- a/lib/if.c +++ b/lib/if.c @@ -168,6 +168,8 @@ if_delete (struct interface *ifp) list_free (ifp->connected); + if_link_params_free (ifp); + XFREE (MTYPE_IF, ifp); } @@ -1125,3 +1127,43 @@ if_link_type_str (enum zebra_link_type llt) } return NULL; } + +struct if_link_params * +if_link_params_get (struct interface *ifp) +{ + if (ifp->link_params != NULL) + return ifp->link_params; + + struct if_link_params *iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, + sizeof (struct if_link_params)); + if (iflp == NULL) return NULL; + + /* Set TE metric == standard metric */ + iflp->te_metric = ifp->metric; + + /* Compute default bandwidth based on interface */ + int bw = (float)((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH) + * TE_KILO_BIT / TE_BYTE); + + /* Set Max, Reservable and Unreserved Bandwidth */ + iflp->max_bw = bw; + iflp->max_rsv_bw = bw; + for (int i = 0; i < MAX_CLASS_TYPE; i++) + iflp->unrsv_bw[i] = bw; + + /* Update Link parameters status */ + iflp->lp_status = LP_TE | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW; + + /* Finally attach newly created Link Parameters */ + ifp->link_params = iflp; + + return iflp; +} + +void +if_link_params_free (struct interface *ifp) +{ + if (ifp->link_params == NULL) return; + XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params); + ifp->link_params = NULL; +} diff --git a/lib/if.h b/lib/if.h index b3d14ba4e..9796a4d2e 100644 --- a/lib/if.h +++ b/lib/if.h @@ -131,6 +131,63 @@ struct if_stats }; #endif /* HAVE_PROC_NET_DEV */ +/* Here are "non-official" architectural constants. */ +#define TE_EXT_MASK 0x0FFFFFFF +#define TE_EXT_ANORMAL 0x80000000 +#define LOSS_PRECISION 0.000003 +#define TE_KILO_BIT 1000 +#define TE_BYTE 8 +#define DEFAULT_BANDWIDTH 10000 +#define MAX_CLASS_TYPE 8 +#define MAX_PKT_LOSS 50.331642 + +/* Link Parameters Status: 0: unset, 1: set, */ +#define LP_UNSET 0x0000 +#define LP_TE 0x0001 +#define LP_MAX_BW 0x0002 +#define LP_MAX_RSV_BW 0x0004 +#define LP_UNRSV_BW 0x0008 +#define LP_ADM_GRP 0x0010 +#define LP_RMT_AS 0x0020 +#define LP_DELAY 0x0040 +#define LP_MM_DELAY 0x0080 +#define LP_DELAY_VAR 0x0100 +#define LP_PKT_LOSS 0x0200 +#define LP_RES_BW 0x0400 +#define LP_AVA_BW 0x0800 +#define LP_USE_BW 0x1000 + +#define IS_PARAM_UNSET(lp, st) !(lp->lp_status & st) +#define IS_PARAM_SET(lp, st) (lp->lp_status & st) +#define IS_LINK_PARAMS_SET(lp) (lp->lp_status != LP_UNSET) + +#define SET_PARAM(lp, st) (lp->lp_status) |= (st) +#define UNSET_PARAM(lp, st) (lp->lp_status) &= ~(st) +#define RESET_LINK_PARAM(lp) (lp->lp_status = LP_UNSET) + +/* Link Parameters for Traffic Engineering */ +struct if_link_params { + u_int32_t lp_status; /* Status of Link Parameters: */ + u_int32_t te_metric; /* Traffic Engineering metric */ + float max_bw; /* Maximum Bandwidth */ + float max_rsv_bw; /* Maximum Reservable Bandwidth */ + float unrsv_bw[MAX_CLASS_TYPE]; /* Unreserved Bandwidth per Class Type (8) */ + u_int32_t admin_grp; /* Administrative group */ + u_int32_t rmt_as; /* Remote AS number */ + struct in_addr rmt_ip; /* Remote IP address */ + u_int32_t av_delay; /* Link Average Delay */ + u_int32_t min_delay; /* Link Min Delay */ + u_int32_t max_delay; /* Link Max Delay */ + u_int32_t delay_var; /* Link Delay Variation */ + float pkt_loss; /* Link Packet Loss */ + float res_bw; /* Residual Bandwidth */ + float ava_bw; /* Available Bandwidth */ + float use_bw; /* Utilized Bandwidth */ +}; + +#define INTERFACE_LINK_PARAMS_SIZE sizeof(struct if_link_params) +#define HAS_LINK_PARAMS(ifp) ((ifp)->link_params != NULL) + /* Interface structure */ struct interface { @@ -172,6 +229,9 @@ struct interface /* interface bandwidth, kbits */ unsigned int bandwidth; + /* Link parameters for Traffic Engineering */ + struct if_link_params *link_params; + /* description of the interface. */ char *desc; @@ -389,6 +449,10 @@ extern ifindex_t if_nametoindex (const char *); extern char *if_indextoname (ifindex_t, char *); #endif +/* link parameters */ +struct if_link_params *if_link_params_get (struct interface *); +void if_link_params_free (struct interface *); + /* Exported variables. */ extern struct list *iflist; extern struct cmd_element interface_desc_cmd; diff --git a/lib/memtypes.c b/lib/memtypes.c index 3b9345d33..f464c4b00 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -72,6 +72,7 @@ struct memory_list memory_list_lib[] = { MTYPE_VRF, "VRF" }, { MTYPE_VRF_NAME, "VRF name" }, { MTYPE_VRF_BITMAP, "VRF bit-map" }, + { MTYPE_IF_LINK_PARAMS, "Informational Link Parameters" }, { -1, NULL }, }; @@ -214,6 +215,8 @@ struct memory_list memory_list_ospf[] = { MTYPE_OSPF_IF_INFO, "OSPF if info" }, { MTYPE_OSPF_IF_PARAMS, "OSPF if params" }, { MTYPE_OSPF_MESSAGE, "OSPF message" }, + { MTYPE_OSPF_MPLS_TE, "OSPF MPLS parameters" }, + { MTYPE_OSPF_PCE_PARAMS, "OSPF PCE parameters" }, { -1, NULL }, }; @@ -256,6 +259,7 @@ struct memory_list memory_list_isis[] = { MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6" }, { MTYPE_ISIS_DICT, "ISIS dictionary" }, { MTYPE_ISIS_DICT_NODE, "ISIS dictionary node" }, + { MTYPE_ISIS_MPLS_TE, "ISIS MPLS_TE parameters" }, { -1, NULL }, }; diff --git a/lib/zclient.c b/lib/zclient.c index 208ea5cb5..c2e133310 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -707,8 +707,6 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid) * ZEBRA_INTERFACE_DELETE from zebra to the client is: * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+ - * | type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifname | * | | @@ -716,20 +714,32 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid) * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ifindex | + * | ifindex | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | status | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | if_flags | + * | if_flags | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | metric | + * | metric | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ifmtu | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ifmtu6 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | bandwidth | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Link Layer Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ifmtu | + * | Harware Address Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ifmtu6 | + * | Hardware Address if HW lenght different from 0 | + * | ... max INTERFACE_HWADDR_MAX | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | bandwidth | + * | Link_params? | Whether a link-params follows: 1 or 0. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | sockaddr_dl | + * | Link_params 0 or 1 INTERFACE_LINK_PARAMS_SIZE sized | + * | .... (struct if_link_params). | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ @@ -782,7 +792,135 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) return ifp; } -/* +static void +link_params_set_value(struct stream *s, struct if_link_params *iflp) +{ + + if (iflp == NULL) + return; + + iflp->lp_status = stream_getl (s); + iflp->te_metric = stream_getl (s); + iflp->max_bw = stream_getf (s); + iflp->max_rsv_bw = stream_getf (s); + uint32_t bwclassnum = stream_getl (s); + { + unsigned int i; + for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++) + iflp->unrsv_bw[i] = stream_getf (s); + if (i < bwclassnum) + zlog_err ("%s: received %d > %d (MAX_CLASS_TYPE) bw entries" + " - outdated library?", + __func__, bwclassnum, MAX_CLASS_TYPE); + } + iflp->admin_grp = stream_getl (s); + iflp->rmt_as = stream_getl (s); + iflp->rmt_ip.s_addr = stream_get_ipv4 (s); + + iflp->av_delay = stream_getl (s); + iflp->min_delay = stream_getl (s); + iflp->max_delay = stream_getl (s); + iflp->delay_var = stream_getl (s); + + iflp->pkt_loss = stream_getf (s); + iflp->res_bw = stream_getf (s); + iflp->ava_bw = stream_getf (s); + iflp->use_bw = stream_getf (s); +} + +struct interface * +zebra_interface_link_params_read (struct stream *s) +{ + struct if_link_params *iflp; + uint32_t ifindex = stream_getl (s); + + struct interface *ifp = if_lookup_by_index (ifindex); + + if (ifp == NULL || s == NULL) + { + zlog_err ("%s: unknown ifindex %u, shouldn't happen", + __func__, ifindex); + return NULL; + } + + if ((iflp = if_link_params_get (ifp)) == NULL) + return NULL; + + link_params_set_value(s, iflp); + + return ifp; +} + +void +zebra_interface_if_set_value (struct stream *s, struct interface *ifp) +{ + u_char link_params_status = 0; + + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + ifp->status = stream_getc (s); + + /* Read interface's value. */ + ifp->flags = stream_getq (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->mtu6 = stream_getl (s); + ifp->bandwidth = stream_getl (s); + ifp->ll_type = stream_getl (s); + ifp->hw_addr_len = stream_getl (s); + if (ifp->hw_addr_len) + stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); + + /* Read Traffic Engineering status */ + link_params_status = stream_getc (s); + /* Then, Traffic Engineering parameters if any */ + if (link_params_status) + { + struct if_link_params *iflp = if_link_params_get (ifp); + link_params_set_value(s, iflp); + } +} + +size_t +zebra_interface_link_params_write (struct stream *s, struct interface *ifp) +{ + size_t w; + struct if_link_params *iflp; + + if (s == NULL || ifp == NULL || ifp->link_params == NULL) + return 0; + + iflp = ifp->link_params; + w = 0; + + w += stream_putl (s, iflp->lp_status); + + w += stream_putl (s, iflp->te_metric); + w += stream_putf (s, iflp->max_bw); + w += stream_putf (s, iflp->max_rsv_bw); + + w += stream_putl (s, MAX_CLASS_TYPE); + for (int i = 0; i < MAX_CLASS_TYPE; i++) + w += stream_putf (s, iflp->unrsv_bw[i]); + + w += stream_putl (s, iflp->admin_grp); + w += stream_putl (s, iflp->rmt_as); + w += stream_put_in_addr (s, &iflp->rmt_ip); + + w += stream_putl (s, iflp->av_delay); + w += stream_putl (s, iflp->min_delay); + w += stream_putl (s, iflp->max_delay); + w += stream_putl (s, iflp->delay_var); + + w += stream_putf (s, iflp->pkt_loss); + w += stream_putf (s, iflp->res_bw); + w += stream_putf (s, iflp->ava_bw); + w += stream_putf (s, iflp->use_bw); + + return w; +} + +/* * format of message for address additon is: * 0 * 0 1 2 3 4 5 6 7 @@ -811,28 +949,8 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) * : : * | | * +-+-+-+-+-+-+-+-+ - * */ -void -zebra_interface_if_set_value (struct stream *s, struct interface *ifp) -{ - /* Read interface's index. */ - ifp->ifindex = stream_getl (s); - ifp->status = stream_getc (s); - - /* Read interface's value. */ - ifp->flags = stream_getq (s); - ifp->metric = stream_getl (s); - ifp->mtu = stream_getl (s); - ifp->mtu6 = stream_getl (s); - ifp->bandwidth = stream_getl (s); - ifp->ll_type = stream_getl (s); - ifp->hw_addr_len = stream_getl (s); - if (ifp->hw_addr_len) - stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); -} - static int memconstant(const void *s, int c, size_t n) { @@ -1059,6 +1177,10 @@ zclient_read (struct thread *thread) if (zclient->ipv6_route_delete) (*zclient->ipv6_route_delete) (command, zclient, length, vrf_id); break; + case ZEBRA_INTERFACE_LINK_PARAMS: + if (zclient->interface_link_params) + (*zclient->interface_link_params) (command, zclient, length); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index d069eb22b..151349297 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -85,6 +85,7 @@ struct zclient int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t); + int (*interface_link_params) (int, struct zclient *, uint16_t); int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t); @@ -184,6 +185,9 @@ extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid); extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); +extern struct interface *zebra_interface_link_params_read (struct stream *); +extern size_t zebra_interface_link_params_write (struct stream *, + struct interface *); #ifdef HAVE_IPV6 /* IPv6 prefix add and delete function prototype. */ diff --git a/lib/zebra.h b/lib/zebra.h index 7c4adf1d7..cb83a112b 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -425,7 +425,8 @@ struct in_pktinfo #define ZEBRA_HELLO 23 #define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24 #define ZEBRA_VRF_UNREGISTER 25 -#define ZEBRA_MESSAGE_MAX 26 +#define ZEBRA_INTERFACE_LINK_PARAMS 26 +#define ZEBRA_MESSAGE_MAX 27 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new From 15773a87ce652da5b02ca14dc0088408899ea007 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 18:29:55 +0200 Subject: [PATCH 1051/1342] zebra: Add link parameters support to Zebra * zebra/interface.c: - Add new link-params CLI commands - Add new functions to set/get link parameters for interface * zebra/redistribute.[c,h]: Add new function to propagate link parameters to routing daemon (essentially OSPFD and ISISD) for Traffic Engineering. * zebra/redistribute_null.c: Add new function zebra_interface_parameters_update() * zebra/zserv.[c,h]: Add new functions to send link parameters Signed-off-by: Olivier Dugeon --- zebra/interface.c | 815 +++++++++++++++++++++++++++++++++++++- zebra/redistribute.c | 26 +- zebra/redistribute.h | 2 + zebra/redistribute_null.c | 4 + zebra/zserv.c | 39 ++ zebra/zserv.h | 2 + 6 files changed, 881 insertions(+), 7 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 14dc5898f..6fa097f6f 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -192,7 +192,7 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc) /* If deleted address is primary, mark subsequent one as such and distribute. */ if (! CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) { - ifc = listgetdata (listhead (addr_list)); + ifc = listgetdata ((struct listnode *)listhead (addr_list)); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); /* XXX: Linux kernel removes all the secondary addresses when the primary @@ -831,7 +831,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp) { if (! rn->info) continue; - + for (ALL_LIST_ELEMENTS_RO ((struct list *)rn->info, node, connected)) connected_dump_vty (vty, connected); } @@ -843,6 +843,53 @@ if_dump_vty (struct vty *vty, struct interface *ifp) connected_dump_vty (vty, connected); } + if (HAS_LINK_PARAMS(ifp)) + { + int i; + struct if_link_params *iflp = ifp->link_params; + vty_out(vty, " Traffic Engineering Link Parameters:%s", VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_TE)) + vty_out(vty, " TE metric %u%s",iflp->te_metric, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_BW)) + vty_out(vty, " Maximum Bandwidth %g (Byte/s)%s", iflp->max_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW)) + vty_out(vty, " Maximum Reservable Bandwidth %g (Byte/s)%s", iflp->max_rsv_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { + vty_out(vty, " Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE); + for (i = 0; i < MAX_CLASS_TYPE; i+=2) + vty_out(vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", + i, iflp->unrsv_bw[i], i+1, iflp->unrsv_bw[i+1], VTY_NEWLINE); + } + + if (IS_PARAM_SET(iflp, LP_ADM_GRP)) + vty_out(vty, " Administrative Group:%u%s", iflp->admin_grp, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_DELAY)) + { + vty_out(vty, " Link Delay Average: %u (micro-sec.)", iflp->av_delay); + if (IS_PARAM_SET(iflp, LP_MM_DELAY)) + { + vty_out(vty, " Min: %u (micro-sec.)", iflp->min_delay); + vty_out(vty, " Max: %u (micro-sec.)", iflp->max_delay); + } + vty_out(vty, "%s", VTY_NEWLINE); + } + if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) + vty_out(vty, " Link Delay Variation %u (micro-sec.)%s", iflp->delay_var, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) + vty_out(vty, " Link Packet Loss %g (in %%)%s", iflp->pkt_loss, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_AVA_BW)) + vty_out(vty, " Available Bandwidth %g (Byte/s)%s", iflp->ava_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RES_BW)) + vty_out(vty, " Residual Bandwidth %g (Byte/s)%s", iflp->res_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_USE_BW)) + vty_out(vty, " Utilized Bandwidth %g (Byte/s)%s", iflp->use_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RMT_AS)) + vty_out(vty, " Neighbor ASBR IP: %s AS: %u %s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE); + } + + #ifdef RTADV + nd_dump_vty (vty, ifp); + #endif /* RTADV */ #if defined (HAVE_RTADV) nd_dump_vty (vty, ifp); #endif /* HAVE_RTADV */ @@ -938,13 +985,13 @@ DEFUN_NOSH (zebra_interface, "Interface's name\n") { int ret; - struct interface * ifp; + struct interface *ifp; /* Call lib interface() */ if ((ret = interface_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS) return ret; - ifp = vty->index; + ifp = vty->index; if (ifp->ifindex == IFINDEX_INTERNAL) /* Is this really necessary? Shouldn't status be initialized to 0 @@ -1414,6 +1461,692 @@ ALIAS (no_bandwidth_if, "Set bandwidth informational parameter\n" "Bandwidth in kilobits\n") +struct cmd_node link_params_node = +{ + LINK_PARAMS_NODE, + "%s(config-link-params)# ", + 1, +}; + +static void +link_param_cmd_set_uint32 (struct interface *ifp, uint32_t *field, + uint32_t type, uint32_t value) +{ + /* Update field as needed */ + if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) + { + *field = value; + SET_PARAM(ifp->link_params, type); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + } +} +static void +link_param_cmd_set_float (struct interface *ifp, float *field, + uint32_t type, float value) +{ + + /* Update field as needed */ + if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) + { + *field = value; + SET_PARAM(ifp->link_params, type); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + } +} + +static void +link_param_cmd_unset (struct interface *ifp, uint32_t type) +{ + + /* Unset field */ + UNSET_PARAM(ifp->link_params, type); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); +} + +DEFUN (link_params, + link_params_cmd, + "link-params", + LINK_PARAMS_STR) +{ + vty->node = LINK_PARAMS_NODE; + + return CMD_SUCCESS; +} + +/* Specific Traffic Engineering parameters commands */ +DEFUN (link_params_enable, + link_params_enable_cmd, + "enable", + "Activate link parameters on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* This command could be issue at startup, when activate MPLS TE */ + /* on a new interface or after a ON / OFF / ON toggle */ + /* In all case, TE parameters are reset to their default factory */ + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("Link-params: enable TE link parameters on interface %s", ifp->name); + + if (!if_link_params_get (ifp)) + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("Link-params: failed to init TE link parameters %s", ifp->name); + + return CMD_WARNING; + } + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_enable, + no_link_params_enable_cmd, + "no enable", + NO_STR + "Disable link parameters on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + zlog_debug ("MPLS-TE: disable TE link parameters on interface %s", ifp->name); + + if_link_params_free (ifp); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +/* STANDARD TE metrics */ +DEFUN (link_params_metric, + link_params_metric_cmd, + "metric <0-4294967295>", + "Link metric for MPLS-TE purpose\n" + "Metric value in decimal\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + u_int32_t metric; + + VTY_GET_ULONG("metric", metric, argv[0]); + + /* Update TE metric if needed */ + link_param_cmd_set_uint32 (ifp, &iflp->te_metric, LP_TE, metric); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_metric, + no_link_params_metric_cmd, + "no metric", + NO_STR + "Disbale Link Metric on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset TE Metric */ + link_param_cmd_unset(ifp, LP_TE); + + return CMD_SUCCESS; +} + +DEFUN (link_params_maxbw, + link_params_maxbw_cmd, + "max-bw BANDWIDTH", + "Maximum bandwidth that can be used\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_maxbw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that Maximum bandwidth is not lower than other bandwidth parameters */ + if ((bw <= iflp->max_rsv_bw) + || (bw <= iflp->unrsv_bw[0]) + || (bw <= iflp->unrsv_bw[1]) + || (bw <= iflp->unrsv_bw[2]) + || (bw <= iflp->unrsv_bw[3]) + || (bw <= iflp->unrsv_bw[4]) + || (bw <= iflp->unrsv_bw[5]) + || (bw <= iflp->unrsv_bw[6]) + || (bw <= iflp->unrsv_bw[7]) + || (bw <= iflp->ava_bw) + || (bw <= iflp->res_bw) + || (bw <= iflp->use_bw)) + { + vty_out (vty, + "Maximum Bandwidth could not be lower than others bandwidth%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Maximum Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->max_bw, LP_MAX_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (link_params_max_rsv_bw, + link_params_max_rsv_bw_cmd, + "max-rsv-bw BANDWIDTH", + "Maximum bandwidth that may be reserved\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Maximum Reservable Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (link_params_unrsv_bw, + link_params_unrsv_bw_cmd, + "unrsv-bw <0-7> BANDWIDTH", + "Unreserved bandwidth at each priority level\n" + "Priority\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + int priority; + float bw; + + /* We don't have to consider about range check here. */ + if (sscanf (argv[0], "%d", &priority) != 1) + { + vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (sscanf (argv[1], "%g", &bw) != 1) + { + vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Unreserved Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (link_params_admin_grp, + link_params_admin_grp_cmd, + "admin-grp BITPATTERN", + "Administrative group membership\n" + "32-bit Hexadecimal value (e.g. 0xa1)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + unsigned long value; + + if (sscanf (argv[0], "0x%lx", &value) != 1) + { + vty_out (vty, "link_params_admin_grp: fscanf: %s%s", + safe_strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Administrative Group if needed */ + link_param_cmd_set_uint32 (ifp, &iflp->admin_grp, LP_ADM_GRP, value); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_admin_grp, + no_link_params_admin_grp_cmd, + "no admin-grp", + NO_STR + "Disbale Administrative group membership on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Admin Group */ + link_param_cmd_unset(ifp, LP_ADM_GRP); + + return CMD_SUCCESS; +} + +/* RFC5392 & RFC5316: INTER-AS */ +DEFUN (link_params_inter_as, + link_params_inter_as_cmd, + "neighbor A.B.C.D as <1-4294967295>", + "Configure remote ASBR information (Neighbor IP address and AS number)\n" + "Remote IP address in dot decimal A.B.C.D\n" + "Remote AS number\n" + "AS number in the range <1-4294967295>\n") +{ + + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + struct in_addr addr; + u_int32_t as; + + if (!inet_aton (argv[0], &addr)) + { + vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_GET_ULONG("AS number", as, argv[1]); + + /* Update Remote IP and Remote AS fields if needed */ + if (IS_PARAM_UNSET(iflp, LP_RMT_AS) + || iflp->rmt_as != as + || iflp->rmt_ip.s_addr != addr.s_addr) + { + + iflp->rmt_as = as; + iflp->rmt_ip.s_addr = addr.s_addr; + SET_PARAM(iflp, LP_RMT_AS); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + } + return CMD_SUCCESS; +} + +DEFUN (no_link_params_inter_as, + no_link_params_inter_as_cmd, + "no neighbor", + NO_STR + "Remove Neighbor IP address and AS number for Inter-AS TE\n") +{ + + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + + /* Reset Remote IP and AS neighbor */ + iflp->rmt_as = 0; + iflp->rmt_ip.s_addr = 0; + UNSET_PARAM(iflp, LP_RMT_AS); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +/* RFC7471: OSPF Traffic Engineering (TE) Metric extensions & draft-ietf-isis-metric-extensions-07.txt */ +DEFUN (link_params_delay, + link_params_delay_cmd, + "delay <0-16777215>", + "Unidirectional Average Link Delay\n" + "Average delay in micro-second as decimal (0...16777215)\n") +{ + + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + u_int32_t delay = 0, low = 0, high = 0; + u_int8_t update = 0; + + /* Get and Check new delay values */ + VTY_GET_ULONG("delay", delay, argv[0]); + switch (argc) + { + case 1: + /* Check new delay value against old Min and Max delays if set */ + if (IS_PARAM_SET(iflp, LP_MM_DELAY) + && (delay <= iflp->min_delay || delay >= iflp->max_delay)) + { + vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s", + iflp->min_delay, iflp->max_delay, VTY_NEWLINE); + return CMD_WARNING; + } + /* Update delay if value is not set or change */ + if (IS_PARAM_UNSET(iflp, LP_DELAY)|| iflp->av_delay != delay) + { + iflp->av_delay = delay; + SET_PARAM(iflp, LP_DELAY); + update = 1; + } + /* Unset Min and Max delays if already set */ + if (IS_PARAM_SET(iflp, LP_MM_DELAY)) + { + iflp->min_delay = 0; + iflp->max_delay = 0; + UNSET_PARAM(iflp, LP_MM_DELAY); + update = 1; + } + break; + case 2: + vty_out (vty, "You should specify both Minimum and Maximum delay with Average delay%s", + VTY_NEWLINE); + return CMD_WARNING; + break; + case 3: + VTY_GET_ULONG("minimum delay", low, argv[1]); + VTY_GET_ULONG("maximum delay", high, argv[2]); + /* Check new delays value coherency */ + if (delay <= low || delay >= high) + { + vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s", + low, high, VTY_NEWLINE); + return CMD_WARNING; + } + /* Update Delays if needed */ + if (IS_PARAM_UNSET(iflp, LP_DELAY) + || IS_PARAM_UNSET(iflp, LP_MM_DELAY) + || iflp->av_delay != delay + || iflp->min_delay != low + || iflp->max_delay != high) + { + iflp->av_delay = delay; + SET_PARAM(iflp, LP_DELAY); + iflp->min_delay = low; + iflp->max_delay = high; + SET_PARAM(iflp, LP_MM_DELAY); + update = 1; + } + break; + default: + return CMD_WARNING; + break; + } + + /* force protocols to update LINK STATE due to parameters change */ + if (update == 1 && if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +ALIAS (link_params_delay, + link_params_delay_mm_cmd, + "delay <0-16777215> min <0-16777215> max <0-16777215>", + "Unidirectional Average Link Delay (optionally Minimum and Maximum delays)\n" + "Average delay in micro-second as decimal (0...16777215)\n" + "Minimum delay\n" + "Minimum delay in micro-second as decimal (0...16777215)\n" + "Maximum delay\n" + "Maximum delay in micro-second as decimal (0...16777215)\n") + +DEFUN (no_link_params_delay, + no_link_params_delay_cmd, + "no delay", + NO_STR + "Disbale Unidirectional Average, Min & Max Link Delay on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + + /* Unset Delays */ + iflp->av_delay = 0; + UNSET_PARAM(iflp, LP_DELAY); + iflp->min_delay = 0; + iflp->max_delay = 0; + UNSET_PARAM(iflp, LP_MM_DELAY); + + /* force protocols to update LINK STATE due to parameters change */ + if (if_is_operative (ifp)) + zebra_interface_parameters_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (link_params_delay_var, + link_params_delay_var_cmd, + "delay-variation <0-16777215>", + "Unidirectional Link Delay Variation\n" + "delay variation in micro-second as decimal (0...16777215)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + u_int32_t value; + + VTY_GET_ULONG("delay variation", value, argv[0]); + + /* Update Delay Variation if needed */ + link_param_cmd_set_uint32 (ifp, &iflp->delay_var, LP_DELAY_VAR, value); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_delay_var, + no_link_params_delay_var_cmd, + "no delay-variation", + NO_STR + "Disbale Unidirectional Delay Variation on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Delay Variation */ + link_param_cmd_unset(ifp, LP_DELAY_VAR); + + return CMD_SUCCESS; +} + +DEFUN (link_params_pkt_loss, + link_params_pkt_loss_cmd, + "packet-loss PERCENTAGE", + "Unidirectional Link Packet Loss\n" + "percentage of total traffic by 0.000003% step and less than 50.331642%\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float fval; + + if (sscanf (argv[0], "%g", &fval) != 1) + { + vty_out (vty, "link_params_pkt_loss: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (fval > MAX_PKT_LOSS) + fval = MAX_PKT_LOSS; + + /* Update Packet Loss if needed */ + link_param_cmd_set_float (ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_pkt_loss, + no_link_params_pkt_loss_cmd, + "no packet-loss", + NO_STR + "Disbale Unidirectional Link Packet Loss on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Packet Loss */ + link_param_cmd_unset(ifp, LP_PKT_LOSS); + + return CMD_SUCCESS; +} + +DEFUN (link_params_res_bw, + link_params_res_bw_cmd, + "res-bw BANDWIDTH", + "Unidirectional Residual Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_res_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Residual Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Residual Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->res_bw, LP_RES_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_res_bw, + no_link_params_res_bw_cmd, + "no res-bw", + NO_STR + "Disbale Unidirectional Residual Bandwidth on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Residual Bandwidth */ + link_param_cmd_unset(ifp, LP_RES_BW); + + return CMD_SUCCESS; +} + +DEFUN (link_params_ava_bw, + link_params_ava_bw_cmd, + "ava-bw BANDWIDTH", + "Unidirectional Available Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_ava_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Available Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Residual Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->ava_bw, LP_AVA_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_ava_bw, + no_link_params_ava_bw_cmd, + "no ava-bw", + NO_STR + "Disbale Unidirectional Available Bandwidth on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Available Bandwidth */ + link_param_cmd_unset(ifp, LP_AVA_BW); + + return CMD_SUCCESS; +} + +DEFUN (link_params_use_bw, + link_params_use_bw_cmd, + "use-bw BANDWIDTH", + "Unidirectional Utilised Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct if_link_params *iflp = if_link_params_get (ifp); + float bw; + + if (sscanf (argv[0], "%g", &bw) != 1) + { + vty_out (vty, "link_params_use_bw: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check that bandwidth is not greater than maximum bandwidth parameter */ + if (bw > iflp->max_bw) + { + vty_out (vty, + "Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)%s", + iflp->max_bw, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Update Utilized Bandwidth if needed */ + link_param_cmd_set_float (ifp, &iflp->use_bw, LP_USE_BW, bw); + + return CMD_SUCCESS; +} + +DEFUN (no_link_params_use_bw, + no_link_params_use_bw_cmd, + "no use-bw", + NO_STR + "Disbale Unidirectional Utilised Bandwidth on this interface\n") +{ + struct interface *ifp = (struct interface *) vty->index; + + /* Unset Utilised Bandwidth */ + link_param_cmd_unset(ifp, LP_USE_BW); + + return CMD_SUCCESS; +} + static int ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, @@ -1751,6 +2484,56 @@ DEFUN (no_ipv6_address, } #endif /* HAVE_IPV6 */ +static int +link_params_config_write (struct vty *vty, struct interface *ifp) +{ + if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) + return -1; + + struct if_link_params *iflp = ifp->link_params; + + vty_out (vty, " link-params%s", VTY_NEWLINE); + vty_out(vty, " enable%s", VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_TE)) + vty_out(vty, " metric %u%s",iflp->te_metric, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_BW)) + vty_out(vty, " max-bw %g%s", iflp->max_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW)) + vty_out(vty, " max-rsv-bw %g%s", iflp->max_rsv_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) + { + for (int i = 0; i < 8; i++) + vty_out(vty, " unrsv-bw %d %g%s", + i, iflp->unrsv_bw[i], VTY_NEWLINE); + } + if (IS_PARAM_SET(iflp, LP_ADM_GRP)) + vty_out(vty, " admin-grp %u%s", iflp->admin_grp, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_DELAY)) + { + vty_out(vty, " delay %u", iflp->av_delay); + if (IS_PARAM_SET(iflp, LP_MM_DELAY)) + { + vty_out(vty, " min %u", iflp->min_delay); + vty_out(vty, " max %u", iflp->max_delay); + } + vty_out(vty, "%s", VTY_NEWLINE); + } + if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) + vty_out(vty, " delay-variation %u%s", iflp->delay_var, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) + vty_out(vty, " packet-loss %g%s", iflp->pkt_loss, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_AVA_BW)) + vty_out(vty, " ava-bw %g%s", iflp->ava_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RES_BW)) + vty_out(vty, " res-bw %g%s", iflp->res_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_USE_BW)) + vty_out(vty, " use-bw %g%s", iflp->use_bw, VTY_NEWLINE); + if (IS_PARAM_SET(iflp, LP_RMT_AS)) + vty_out(vty, " neighbor %s as %u%s", inet_ntoa(iflp->rmt_ip), + iflp->rmt_as, VTY_NEWLINE); + return 0; +} + static int if_config_write (struct vty *vty) { @@ -1788,7 +2571,6 @@ if_config_write (struct vty *vty) while processing config script */ if (ifp->bandwidth != 0) vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) vty_out(vty, " link-detect%s", VTY_NEWLINE); else @@ -1827,11 +2609,14 @@ if_config_write (struct vty *vty) irdp_config_write (vty, ifp); #endif /* IRDP */ + link_params_config_write (vty, ifp); + vty_out (vty, "!%s", VTY_NEWLINE); } return 0; } + /* Allocate and initialize interface vector. */ void zebra_if_init (void) @@ -1843,6 +2628,8 @@ zebra_if_init (void) /* Install configuration write function. */ install_node (&interface_node, if_config_write); + install_node (&link_params_node, NULL); + install_element (VIEW_NODE, &show_interface_cmd); install_element (VIEW_NODE, &show_interface_vrf_cmd); install_element (VIEW_NODE, &show_interface_vrf_all_cmd); @@ -1875,4 +2662,22 @@ zebra_if_init (void) install_element (INTERFACE_NODE, &ip_address_label_cmd); install_element (INTERFACE_NODE, &no_ip_address_label_cmd); #endif /* HAVE_NETLINK */ + install_element(INTERFACE_NODE, &link_params_cmd); + install_default(LINK_PARAMS_NODE); + install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); + install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); + install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_mm_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); + install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); + install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 57b515e13..6c5491763 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -281,7 +281,11 @@ zebra_interface_up_update (struct interface *ifp) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + if (client->ifinfo) + { + zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + zsend_interface_link_params (client, ifp); + } } /* Interface down information. */ @@ -310,7 +314,10 @@ zebra_interface_add_update (struct interface *ifp) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) - zsend_interface_add (client, ifp); + { + zsend_interface_add (client, ifp); + zsend_interface_link_params (client, ifp); + } } void @@ -381,3 +388,18 @@ zebra_interface_address_delete_update (struct interface *ifp, if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); } + +/* Interface parameters update */ +void +zebra_interface_parameters_update (struct interface *ifp) +{ + struct listnode *node, *nnode; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s", ifp->name); + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + if (client->ifinfo) + zsend_interface_link_params (client, ifp); +} diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 6a36f4d86..ce8400941 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -48,6 +48,8 @@ extern void zebra_interface_address_add_update (struct interface *, extern void zebra_interface_address_delete_update (struct interface *, struct connected *c); +extern void zebra_interface_parameters_update (struct interface *); + extern int zebra_check_addr (struct prefix *); extern int is_default (struct prefix *); diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index c68cec6ae..5584d12ca 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -78,3 +78,7 @@ void zebra_interface_address_delete_update (struct interface *a, struct connected *b) { return; } #endif + +/* Interface parameters update */ +void zebra_interface_parameters_update (struct interface *ifp) +{ return; }; diff --git a/zebra/zserv.c b/zebra/zserv.c index 054cdb32d..d4c5db906 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -159,6 +159,16 @@ zserv_encode_interface (struct stream *s, struct interface *ifp) if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); + zlog_info("Try to set TE Link Param"); + /* Then, Traffic Engineering parameters if any */ + if (HAS_LINK_PARAMS(ifp) && IS_LINK_PARAMS_SET(ifp->link_params)) + { + stream_putc (s, 1); + zebra_interface_link_params_write (s, ifp); + } + else + stream_putc (s, 0); + /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); } @@ -211,6 +221,35 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) return zebra_server_send_message (client); } +int +zsend_interface_link_params (struct zserv *client, struct interface *ifp) +{ + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return 0; + + if (!ifp->link_params) + return 0; + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); + + /* Add Interface Index */ + stream_putl (s, ifp->ifindex); + + /* Then TE Link Parameters */ + if (zebra_interface_link_params_write (s, ifp) == 0) + return 0; + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return zebra_server_send_message (client); +} + /* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or * ZEBRA_INTERFACE_ADDRESS_DELETE to the client. * diff --git a/zebra/zserv.h b/zebra/zserv.h index 413cd6ab2..9d65998ed 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -108,6 +108,8 @@ extern int zsend_route_multipath (int, struct zserv *, struct prefix *, extern int zsend_router_id_update (struct zserv *, struct prefix *, vrf_id_t); +extern int zsend_interface_link_params (struct zserv *, struct interface *); + extern pid_t pid; #endif /* _ZEBRA_ZEBRA_H */ From ac10d30c03091eace3c0405aa8ccb7d3c09e7bd2 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 18:33:42 +0200 Subject: [PATCH 1052/1342] vtysh: Add support of new link-params CLI In vtysh_config.c/vtysh_config_parse_line(), it is not possible to continue to use the ordered version for adding line i.e. config_add_line_uniq() to print Interface CLI commands as it completely break the new LINK_PARAMS_NODE. Signed-off-by: Olivier Dugeon --- vtysh/extract.pl.in | 1 + vtysh/vtysh.c | 25 +++++++++++++++++++++++++ vtysh/vtysh_config.c | 3 +-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index ca869b643..786493a6a 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -32,6 +32,7 @@ EOF $ignore{'"interface IFNAME"'} = "ignore"; $ignore{'"interface IFNAME " "vrf <0-65535>"'} = "ignore"; +$ignore{'"link-params"'} = "ignore"; $ignore{'"ip vrf NAME"'} = "ignore"; $ignore{'"router rip"'} = "ignore"; $ignore{'"router ripng"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 69e98883d..fe86083e2 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -777,6 +777,12 @@ static struct cmd_node keychain_key_node = "%s(config-keychain-key)# " }; +struct cmd_node link_params_node = +{ + LINK_PARAMS_NODE, + "%s(config-link-params)# ", +}; + /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -1144,6 +1150,9 @@ vtysh_exit (struct vty *vty) case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; + case LINK_PARAMS_NODE: + vty->node = INTERFACE_NODE; + break; default: break; } @@ -1444,6 +1453,17 @@ DEFUN (vtysh_show_work_queues_daemon, return ret; } +DEFUNSH (VTYSH_ZEBRA, + vtysh_link_params, + vtysh_link_params_cmd, + "link-params", + LINK_PARAMS_STR + ) +{ + vty->node = LINK_PARAMS_NODE; + return CMD_SUCCESS; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2394,6 +2414,7 @@ vtysh_init_vty (void) install_node (&bgp_node, NULL); install_node (&rip_node, NULL); install_node (&interface_node, NULL); + install_node (&link_params_node, NULL); install_node (&rmap_node, NULL); install_node (&zebra_node, NULL); install_node (&bgp_vpnv4_node, NULL); @@ -2423,6 +2444,7 @@ vtysh_init_vty (void) vtysh_install_default (BGP_NODE); vtysh_install_default (RIP_NODE); vtysh_install_default (INTERFACE_NODE); + vtysh_install_default (LINK_PARAMS_NODE); vtysh_install_default (RMAP_NODE); vtysh_install_default (ZEBRA_NODE); vtysh_install_default (BGP_VPNV4_NODE); @@ -2517,6 +2539,8 @@ vtysh_init_vty (void) install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &vtysh_end_all_cmd); install_element (INTERFACE_NODE, &vtysh_exit_interface_cmd); + install_element (LINK_PARAMS_NODE, &vtysh_end_all_cmd); + install_element (LINK_PARAMS_NODE, &vtysh_exit_interface_cmd); install_element (INTERFACE_NODE, &vtysh_quit_interface_cmd); install_element (CONFIG_NODE, &router_rip_cmd); #ifdef HAVE_IPV6 @@ -2559,6 +2583,7 @@ vtysh_init_vty (void) install_element (CONFIG_NODE, &vtysh_no_interface_cmd); install_element (CONFIG_NODE, &vtysh_interface_vrf_cmd); install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd); + install_element (INTERFACE_NODE, &vtysh_link_params_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_daemon_cmd); install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index a069164b2..c80c42a4f 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -166,7 +166,7 @@ vtysh_config_parse_line (const char *line) /* Store line to current configuration. */ if (config) { - if (strncmp (line, " address-family vpnv4", + if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0) config = config_get (BGP_VPNV4_NODE, line); else if (strncmp (line, " address-family vpn6", @@ -185,7 +185,6 @@ vtysh_config_parse_line (const char *line) strlen (" address-family ipv6")) == 0) config = config_get (BGP_IPV6_NODE, line); else if (config->index == RMAP_NODE || - config->index == INTERFACE_NODE || config->index == VTY_NODE) config_add_line_uniq (config->line, line); else From 29a1401706a762541b366c7844507efe2bc1345d Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 18:42:40 +0200 Subject: [PATCH 1053/1342] ospfd: Update Traffic Engineering support These patches update original code to RFC3630 (OSPF-TE) and add support of RFC5392 (Inter-AS v2) & RFC7471 (TE metric extensions) and partial support of RFC6827 (ASON - GMPLS). * ospfd/ospf_dump.[c,h]: Add new dump functions for Traffic Engineering * ospfd/ospf_opaque.[c,h]: Add new TLV code points for RFC5392 * ospfd/ospf_packet.c: Update checking of OSPF_OPTION * ospfd/ospf_vty.[c,h]: Update ospf_str2area_id * ospfd/ospf_zebra.c: Add new function ospf_interface_link_params() to get Link Parameters information from the interface to populate Traffic Engineering metrics * ospfd/ospfd.[c,h]: Update OSPF_OPTION flags (T -> MT and new DN) * ospfd/ospf_te.[c,h]: Major modifications to update the code to new link parameters structure and new RFCs Signed-off-by: Olivier Dugeon --- ospfd/ospf_dump.c | 38 +- ospfd/ospf_dump.h | 4 + ospfd/ospf_opaque.c | 18 +- ospfd/ospf_opaque.h | 6 +- ospfd/ospf_packet.c | 4 +- ospfd/ospf_te.c | 1884 ++++++++++++++++++++++++++++++------------- ospfd/ospf_te.h | 319 +++++++- ospfd/ospf_vty.c | 2 +- ospfd/ospf_vty.h | 1 + ospfd/ospf_zebra.c | 21 + ospfd/ospfd.c | 2 +- ospfd/ospfd.h | 3 +- 12 files changed, 1693 insertions(+), 609 deletions(-) diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index fb43210a1..66cc29403 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -133,6 +133,7 @@ unsigned long conf_debug_ospf_nsm = 0; unsigned long conf_debug_ospf_lsa = 0; unsigned long conf_debug_ospf_zebra = 0; unsigned long conf_debug_ospf_nssa = 0; +unsigned long conf_debug_ospf_te = 0; /* Enable debug option variables -- valid only session. */ unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; @@ -142,7 +143,7 @@ unsigned long term_debug_ospf_nsm = 0; unsigned long term_debug_ospf_lsa = 0; unsigned long term_debug_ospf_zebra = 0; unsigned long term_debug_ospf_nssa = 0; - +unsigned long term_debug_ospf_te = 0; const char * @@ -328,13 +329,14 @@ ospf_options_dump (u_char options) { static char buf[OSPF_OPTION_STR_MAXLEN]; - snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*", + snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|%s", (options & OSPF_OPTION_O) ? "O" : "-", (options & OSPF_OPTION_DC) ? "DC" : "-", (options & OSPF_OPTION_EA) ? "EA" : "-", (options & OSPF_OPTION_NP) ? "N/P" : "-", (options & OSPF_OPTION_MC) ? "MC" : "-", - (options & OSPF_OPTION_E) ? "E" : "-"); + (options & OSPF_OPTION_E) ? "E" : "-", + (options & OSPF_OPTION_MT) ? "M/T" : "-"); return buf; } @@ -1426,6 +1428,32 @@ DEFUN (no_debug_ospf_nssa, return CMD_SUCCESS; } +DEFUN (debug_ospf_te, + debug_ospf_te_cmd, + "debug ospf te", + DEBUG_STR + OSPF_STR + "OSPF-TE information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (te, TE); + TERM_DEBUG_ON (te, TE); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_te, + no_debug_ospf_te_cmd, + "no debug ospf te", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF-TE information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (te, TE); + TERM_DEBUG_OFF (te, TE); + return CMD_SUCCESS; +} DEFUN (show_debugging_ospf, show_debugging_ospf_cmd, @@ -1673,6 +1701,7 @@ debug_init () install_element (ENABLE_NODE, &debug_ospf_zebra_cmd); install_element (ENABLE_NODE, &debug_ospf_event_cmd); install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); + install_element (ENABLE_NODE, &debug_ospf_te_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd); @@ -1686,6 +1715,7 @@ debug_init () install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd); install_element (ENABLE_NODE, &no_debug_ospf_event_cmd); install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_te_cmd); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd); @@ -1700,6 +1730,7 @@ debug_init () install_element (CONFIG_NODE, &debug_ospf_zebra_cmd); install_element (CONFIG_NODE, &debug_ospf_event_cmd); install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); + install_element (CONFIG_NODE, &debug_ospf_te_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd); @@ -1713,4 +1744,5 @@ debug_init () install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd); install_element (CONFIG_NODE, &no_debug_ospf_event_cmd); install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_te_cmd); } diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index a2d5e8ba1..f843df03a 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -57,6 +57,7 @@ #define OSPF_DEBUG_EVENT 0x01 #define OSPF_DEBUG_NSSA 0x02 +#define OSPF_DEBUG_TE 0x04 /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) @@ -98,6 +99,8 @@ #define IS_DEBUG_OSPF_NSSA IS_DEBUG_OSPF(nssa,NSSA) +#define IS_DEBUG_OSPF_TE IS_DEBUG_OSPF(te,TE) + #define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) #define IS_CONF_DEBUG_OSPF(a, b) \ @@ -119,6 +122,7 @@ extern unsigned long term_debug_ospf_nsm; extern unsigned long term_debug_ospf_lsa; extern unsigned long term_debug_ospf_zebra; extern unsigned long term_debug_ospf_nssa; +extern unsigned long term_debug_ospf_te; /* Message Strings. */ extern char *ospf_lsa_type_str[]; diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 988a2e557..6b069c808 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -213,6 +213,9 @@ ospf_opaque_type_name (u_char opaque_type) case OPAQUE_TYPE_GRACE_LSA: name = "Grace-LSA"; break; + case OPAQUE_TYPE_INTER_AS_LSA: + name = "Inter-AS TE-v2 LSA"; + break; default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; @@ -1973,6 +1976,7 @@ ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; + struct ospf *top; int delay; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL @@ -2004,7 +2008,10 @@ ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: - ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); + top = ospf_lookup (); + if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL)) + top = lsa0->area->ospf; + ospf_ls_retransmit_delete_nbr_as (top, lsa); break; default: zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); @@ -2049,6 +2056,9 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; + struct ospf *top; + + top = ospf_lookup (); if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) @@ -2072,7 +2082,9 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: - ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); + if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL)) + top = lsa0->area->ospf; + ospf_ls_retransmit_delete_nbr_as (top, lsa); break; default: zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); @@ -2096,7 +2108,7 @@ ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) zlog_debug ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); /* This lsa will be flushed and removed eventually. */ - ospf_lsa_flush (lsa0->area->ospf, lsa); + ospf_lsa_flush (top, lsa); out: return; diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index 2affa91b2..2ac9b41ef 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -60,6 +60,10 @@ #define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 #define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 #define OPAQUE_TYPE_GRACE_LSA 3 +#define OPAQUE_TYPE_L1VPN_LSA 5 +#define OPAQUE_TYPE_ROUTER_INFORMATION_LSA 4 +#define OPAQUE_TYPE_INTER_AS_LSA 6 +#define OPAQUE_TYPE_MAX 6 /* Followings types are proposed in internet-draft documents. */ #define OPAQUE_TYPE_8021_QOSPF 129 @@ -70,7 +74,7 @@ #define OPAQUE_TYPE_WILDCARD 0 #define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ - ( 4 <= (type) && (type) <= 127) + ( OPAQUE_TYPE_MAX <= (type) && (type) <= 127) #define OPAQUE_TYPE_RANGE_RESERVED(type) \ (127 < (type) && (type) <= 255) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 25f70bba8..b997f1bfc 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -882,7 +882,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, /* Compare options. */ #define REJECT_IF_TBIT_ON 1 /* XXX */ #ifdef REJECT_IF_TBIT_ON - if (CHECK_FLAG (hello->options, OSPF_OPTION_T)) + if (CHECK_FLAG (hello->options, OSPF_OPTION_MT)) { /* * This router does not support non-zero TOS. @@ -1231,7 +1231,7 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, } #ifdef REJECT_IF_TBIT_ON - if (CHECK_FLAG (dd->options, OSPF_OPTION_T)) + if (CHECK_FLAG (dd->options, OSPF_OPTION_MT)) { /* * In Hello protocol, optional capability must have checked diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index e750933d0..47771a155 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1,8 +1,11 @@ /* - * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * This is an implementation of RFC3630 * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * + * Copyright (C) 2012 Orange Labs + * http://www.orange.com + * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it @@ -21,10 +24,11 @@ * 02111-1307, USA. */ -/***** MTYPE definition is not reflected to "memory.h" yet. *****/ -#define MTYPE_OSPF_MPLS_TE_LINKPARAMS MTYPE_TMP +/* Add support of RFC7471 */ +/* Add support of RFC5392, RFC6827 */ #include +#include #include "linklist.h" #include "prefix.h" @@ -56,65 +60,19 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" - -/* Following structure are internal use only. */ -struct ospf_mpls_te -{ - enum { disabled, enabled } status; - - /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ - struct list *iflist; - - /* Store Router-TLV in network byte order. */ - struct te_tlv_router_addr router_addr; -}; - -struct mpls_te_link -{ - /* - * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field - * is subdivided into 8-bit "unused" field and 16-bit "instance" field. - * In this implementation, each Link-TLV has its own instance. - */ - u_int32_t instance; - - /* Reference pointer to a Zebra-interface. */ - struct interface *ifp; - - /* Area info in which this MPLS-TE link belongs to. */ - struct ospf_area *area; - - /* Flags to manage this link parameters. */ - u_int32_t flags; -#define LPFLG_LOOKUP_DONE 0x1 -#define LPFLG_LSA_ENGAGED 0x2 -#define LPFLG_LSA_FORCED_REFRESH 0x4 - - /* Store Link-TLV in network byte order. */ - struct te_tlv_link link_header; - struct te_link_subtlv_link_type link_type; - struct te_link_subtlv_link_id link_id; - struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; - struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; - struct te_link_subtlv_te_metric te_metric; - struct te_link_subtlv_max_bw max_bw; - struct te_link_subtlv_max_rsv_bw max_rsv_bw; - struct te_link_subtlv_unrsv_bw unrsv_bw; - struct te_link_subtlv_rsc_clsclr rsc_clsclr; -}; +#include "ospfd/ospf_vty.h" /* * Global variable to manage Opaque-LSA/MPLS-TE on this node. * Note that all parameter values are stored in network byte order. */ -static struct ospf_mpls_te OspfMplsTE; +struct ospf_mpls_te OspfMplsTE; -enum oifstate { - OI_ANY, OI_DOWN, OI_UP -}; +const char *mode2text[] = { "Disable", "AS", "Area", "Emulate" }; -enum sched_opcode { - REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA +enum oifstate +{ + OI_ANY, OI_DOWN, OI_UP }; /*------------------------------------------------------------------------* @@ -123,14 +81,14 @@ enum sched_opcode { static int ospf_mpls_te_new_if (struct interface *ifp); static int ospf_mpls_te_del_if (struct interface *ifp); -static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); +static void ospf_mpls_te_ism_change (struct ospf_interface *oi, + int old_status); static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router (struct vty *vty); -static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); -static int ospf_mpls_te_lsa_originate (void *arg); +static int ospf_mpls_te_lsa_originate_area (void *arg); +static int ospf_mpls_te_lsa_originate_as (void *arg); static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); -static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); static void del_mpls_te_link (void *val); static void ospf_mpls_te_register_vty (void); @@ -148,21 +106,22 @@ ospf_mpls_te_init (void) ospf_mpls_te_ism_change, ospf_mpls_te_nsm_change, ospf_mpls_te_config_write_router, - ospf_mpls_te_config_write_if, + NULL,/*ospf_mpls_te_config_write_if */ NULL,/* ospf_mpls_te_config_write_debug */ ospf_mpls_te_show_info, - ospf_mpls_te_lsa_originate, + ospf_mpls_te_lsa_originate_area, ospf_mpls_te_lsa_refresh, NULL,/* ospf_mpls_te_new_lsa_hook */ NULL /* ospf_mpls_te_del_lsa_hook */); if (rc != 0) { - zlog_warn ("ospf_mpls_te_init: Failed to register functions"); + zlog_warn ("ospf_mpls_te_init: Failed to register Traffic Engineering functions"); goto out; } memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); OspfMplsTE.status = disabled; + OspfMplsTE.inter_as = Disable; OspfMplsTE.iflist = list_new (); OspfMplsTE.iflist->del = del_mpls_te_link; @@ -172,16 +131,75 @@ ospf_mpls_te_init (void) return rc; } +/* Additional register for RFC5392 support */ +static int +ospf_mpls_te_register (enum inter_as_mode mode) +{ + int rc; + u_int8_t scope; + + if (OspfMplsTE.inter_as != Disable) + return 0; + + if (mode == AS) + scope = OSPF_OPAQUE_AS_LSA; + else + scope = OSPF_OPAQUE_AREA_LSA; + + rc = ospf_register_opaque_functab (scope, + OPAQUE_TYPE_INTER_AS_LSA, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ospf_mpls_te_show_info, + ospf_mpls_te_lsa_originate_as, + ospf_mpls_te_lsa_refresh, NULL, NULL); + + if (rc != 0) + { + zlog_warn ("ospf_router_info_init: Failed to register Inter-AS functions"); + return rc; + } + + return 0; +} + +static int +ospf_mpls_te_unregister () +{ + u_int8_t scope; + + if (OspfMplsTE.inter_as == Disable) + return 0; + + if (OspfMplsTE.inter_as == AS) + scope = OSPF_OPAQUE_AS_LSA; + else + scope = OSPF_OPAQUE_AREA_LSA; + + ospf_delete_opaque_functab (scope, OPAQUE_TYPE_INTER_AS_LSA); + + return 0; + +} + void ospf_mpls_te_term (void) { list_delete (OspfMplsTE.iflist); - OspfMplsTE.iflist = NULL; - OspfMplsTE.status = disabled; ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + OspfMplsTE.status = disabled; + + ospf_mpls_te_unregister (); + OspfMplsTE.inter_as = Disable; + return; } @@ -192,11 +210,11 @@ ospf_mpls_te_term (void) static void del_mpls_te_link (void *val) { - XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); + XFREE (MTYPE_OSPF_MPLS_TE, val); return; } -static u_int32_t +u_int32_t get_mpls_te_instance_value (void) { static u_int32_t seqno = 0; @@ -274,9 +292,9 @@ lookup_linkparams_by_instance (struct ospf_lsa *lsa) } static void -ospf_mpls_te_foreach_area ( - void (*func)(struct mpls_te_link *lp, enum sched_opcode), - enum sched_opcode sched_opcode) +ospf_mpls_te_foreach_area (void (*func) + (struct mpls_te_link * lp, opcode_t sched_opcode), + opcode_t sched_opcode) { struct listnode *node, *nnode; struct listnode *node2; @@ -285,10 +303,12 @@ ospf_mpls_te_foreach_area ( for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { - if ((area = lp->area) == NULL) + /* Skip Inter-AS TEv2 Links */ + if (IS_INTER_AS (lp->type)) continue; - if (lp->flags & LPFLG_LOOKUP_DONE) + if ((area = lp->area) == NULL) continue; + if CHECK_FLAG (lp->flags, LPFLG_LOOKUP_DONE) continue; if (func != NULL) (* func)(lp, sched_opcode); @@ -297,12 +317,12 @@ ospf_mpls_te_foreach_area ( if ((lp = listgetdata (node2)) != NULL) if (lp->area != NULL) if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) - lp->flags |= LPFLG_LOOKUP_DONE; + SET_FLAG (lp->flags, LPFLG_LOOKUP_DONE); } for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) if (lp->area != NULL) - lp->flags &= ~LPFLG_LOOKUP_DONE; + UNSET_FLAG (lp->flags, LPFLG_LOOKUP_DONE); return; } @@ -311,7 +331,7 @@ static void set_mpls_te_router_addr (struct in_addr ipv4) { OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); - OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); + OspfMplsTE.router_addr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); OspfMplsTE.router_addr.value = ipv4; return; } @@ -319,7 +339,6 @@ set_mpls_te_router_addr (struct in_addr ipv4) static void set_linkparams_link_header (struct mpls_te_link *lp) { - struct te_tlv_header *tlvh; u_int16_t length = 0; /* TE_LINK_SUBTLV_LINK_TYPE */ @@ -331,14 +350,12 @@ set_linkparams_link_header (struct mpls_te_link *lp) length += TLV_SIZE (&lp->link_id.header); /* TE_LINK_SUBTLV_LCLIF_IPADDR */ - if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL - && ntohs (tlvh->type) != 0) - length += TLV_SIZE (tlvh); + if (lp->lclif_ipaddr.header.type != 0) + length += TLV_SIZE (&lp->lclif_ipaddr.header); /* TE_LINK_SUBTLV_RMTIF_IPADDR */ - if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL - && ntohs (tlvh->type) != 0) - length += TLV_SIZE (tlvh); + if (lp->rmtif_ipaddr.header.type != 0) + length += TLV_SIZE (&lp->rmtif_ipaddr.header); /* TE_LINK_SUBTLV_TE_METRIC */ if (ntohs (lp->te_metric.header.type) != 0) @@ -360,6 +377,50 @@ set_linkparams_link_header (struct mpls_te_link *lp) if (ntohs (lp->rsc_clsclr.header.type) != 0) length += TLV_SIZE (&lp->rsc_clsclr.header); + /* TE_LINK_SUBTLV_LLRI */ + if (ntohs (lp->llri.header.type) != 0) + length += TLV_SIZE (&lp->llri.header); + + /* TE_LINK_SUBTLV_RIP */ + if (ntohs (lp->rip.header.type) != 0) + length += TLV_SIZE (&lp->rip.header); + + /* TE_LINK_SUBTLV_RAS */ + if (ntohs (lp->ras.header.type) != 0) + length += TLV_SIZE (&lp->ras.header); + + /* TE_LINK_SUBTLV_LRRID */ + if (ntohs (lp->lrrid.header.type) != 0) + length += TLV_SIZE (&lp->lrrid.header); + + /* TE_LINK_SUBTLV_AV_DELAY */ + if (ntohs (lp->av_delay.header.type) != 0) + length += TLV_SIZE (&lp->av_delay.header); + + /* TE_LINK_SUBTLV_MM_DELAY */ + if (ntohs (lp->mm_delay.header.type) != 0) + length += TLV_SIZE (&lp->mm_delay.header); + + /* TE_LINK_SUBTLV_DELAY_VAR */ + if (ntohs (lp->delay_var.header.type) != 0) + length += TLV_SIZE (&lp->delay_var.header); + + /* TE_LINK_SUBTLV_PKT_LOSS */ + if (ntohs (lp->pkt_loss.header.type) != 0) + length += TLV_SIZE (&lp->pkt_loss.header); + + /* TE_LINK_SUBTLV_RES_BW */ + if (ntohs (lp->res_bw.header.type) != 0) + length += TLV_SIZE (&lp->res_bw.header); + + /* TE_LINK_SUBTLV_AVA_BW */ + if (ntohs (lp->ava_bw.header.type) != 0) + length += TLV_SIZE (&lp->ava_bw.header); + + /* TE_LINK_SUBTLV_USE_BW */ + if (ntohs (lp->use_bw.header.type) != 0) + length += TLV_SIZE (&lp->use_bw.header); + lp->link_header.header.type = htons (TE_TLV_LINK); lp->link_header.header.length = htons (length); @@ -370,7 +431,7 @@ static void set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) { lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); - lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); + lp->link_type.header.length = htons (TE_LINK_SUBTLV_TYPE_SIZE); switch (oi->type) { @@ -396,7 +457,7 @@ set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) int done = 0; lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); - lp->link_id.header.length = htons (sizeof (lp->link_id.value)); + lp->link_id.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); /* * The Link ID is identical to the contents of the Link ID field @@ -406,8 +467,7 @@ set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) { case OSPF_IFTYPE_POINTOPOINT: /* Take the router ID of the neighbor. */ - if ((nbr = ospf_nbr_lookup_ptop (oi)) - && nbr->state == NSM_Full) + if ((nbr = ospf_nbr_lookup_ptop (oi)) && nbr->state == NSM_Full) { lp->link_id.value = nbr->router_id; done = 1; @@ -442,11 +502,31 @@ set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) return; } +static void +set_linkparams_lclif_ipaddr (struct mpls_te_link *lp, struct in_addr lclif) +{ + + lp->lclif_ipaddr.header.type = htons (TE_LINK_SUBTLV_LCLIF_IPADDR); + lp->lclif_ipaddr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->lclif_ipaddr.value[0] = lclif; + return; +} + +static void +set_linkparams_rmtif_ipaddr (struct mpls_te_link *lp, struct in_addr rmtif) +{ + + lp->rmtif_ipaddr.header.type = htons (TE_LINK_SUBTLV_RMTIF_IPADDR); + lp->rmtif_ipaddr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->rmtif_ipaddr.value[0] = rmtif; + return; +} + static void set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) { lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); - lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); + lp->te_metric.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->te_metric.value = htonl (te_metric); return; } @@ -455,7 +535,7 @@ static void set_linkparams_max_bw (struct mpls_te_link *lp, float fp) { lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); - lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); + lp->max_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->max_bw.value = htonf (fp); return; } @@ -464,7 +544,7 @@ static void set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float fp) { lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); - lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); + lp->max_rsv_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->max_rsv_bw.value = htonf (fp); return; } @@ -474,7 +554,7 @@ set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float fp) { /* Note that TLV-length field is the size of array. */ lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); - lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); + lp->unrsv_bw.header.length = htons (TE_LINK_SUBTLV_UNRSV_SIZE); lp->unrsv_bw.value [priority] = htonf (fp); return; } @@ -483,21 +563,283 @@ static void set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) { lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); - lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); + lp->rsc_clsclr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->rsc_clsclr.value = htonl (classcolor); return; } +static void +set_linkparams_inter_as (struct mpls_te_link *lp, struct in_addr addr, + u_int32_t as) +{ + + /* Set the Remote ASBR IP address and then the associated AS number */ + lp->rip.header.type = htons (TE_LINK_SUBTLV_RIP); + lp->rip.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->rip.value = addr; + + lp->ras.header.type = htons (TE_LINK_SUBTLV_RAS); + lp->ras.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->ras.value = htonl (as); +} + +static void +unset_linkparams_inter_as (struct mpls_te_link *lp) +{ + + /* Reset the Remote ASBR IP address and then the associated AS number */ + lp->rip.header.type = htons (0); + lp->rip.header.length = htons (0); + lp->rip.value.s_addr = htonl (0); + + lp->ras.header.type = htons (0); + lp->ras.header.length = htons (0); + lp->ras.value = htonl (0); +} + +void +set_linkparams_llri (struct mpls_te_link *lp, u_int32_t local, + u_int32_t remote) +{ + + lp->llri.header.type = htons (TE_LINK_SUBTLV_LLRI); + lp->llri.header.length = htons (TE_LINK_SUBTLV_LLRI_SIZE); + lp->llri.local = htonl (local); + lp->llri.remote = htonl (remote); +} + +void +set_linkparams_lrrid (struct mpls_te_link *lp, struct in_addr local, + struct in_addr remote) +{ + + lp->lrrid.header.type = htons (TE_LINK_SUBTLV_LRRID); + lp->lrrid.header.length = htons (TE_LINK_SUBTLV_LRRID_SIZE); + lp->lrrid.local.s_addr = local.s_addr; + lp->lrrid.remote.s_addr = remote.s_addr; +} + +static void +set_linkparams_av_delay (struct mpls_te_link *lp, u_int32_t delay, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + lp->av_delay.header.type = htons (TE_LINK_SUBTLV_AV_DELAY); + lp->av_delay.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + tmp = delay & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + lp->av_delay.value = htonl (tmp); + return; +} + +static void +set_linkparams_mm_delay (struct mpls_te_link *lp, u_int32_t low, u_int32_t high, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + lp->mm_delay.header.type = htons (TE_LINK_SUBTLV_MM_DELAY); + lp->mm_delay.header.length = htons (TE_LINK_SUBTLV_MM_DELAY_SIZE); + tmp = low & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + lp->mm_delay.low = htonl (tmp); + lp->mm_delay.high = htonl (high); + return; +} + +static void +set_linkparams_delay_var (struct mpls_te_link *lp, u_int32_t jitter) +{ + /* Note that TLV-length field is the size of array. */ + lp->delay_var.header.type = htons (TE_LINK_SUBTLV_DELAY_VAR); + lp->delay_var.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->delay_var.value = htonl (jitter & TE_EXT_MASK); + return; +} + +static void +set_linkparams_pkt_loss (struct mpls_te_link *lp, u_int32_t loss, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + lp->pkt_loss.header.type = htons (TE_LINK_SUBTLV_PKT_LOSS); + lp->pkt_loss.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + tmp = loss & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + lp->pkt_loss.value = htonl (tmp); + return; +} + +static void +set_linkparams_res_bw (struct mpls_te_link *lp, float fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->res_bw.header.type = htons (TE_LINK_SUBTLV_RES_BW); + lp->res_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->res_bw.value = htonf (fp); + return; +} + +static void +set_linkparams_ava_bw (struct mpls_te_link *lp, float fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->ava_bw.header.type = htons (TE_LINK_SUBTLV_AVA_BW); + lp->ava_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->ava_bw.value = htonf (fp); + return; +} + +static void +set_linkparams_use_bw (struct mpls_te_link *lp, float fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->use_bw.header.type = htons (TE_LINK_SUBTLV_USE_BW); + lp->use_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); + lp->use_bw.value = htonf (fp); + return; +} + +/* Update TE parameters from Interface */ +static void +update_linkparams(struct mpls_te_link *lp) +{ + int i; + struct interface *ifp; + + /* Get the Interface structure */ + if ((ifp = lp->ifp) == NULL) + { + zlog_warn("OSPF MPLS-TE: Abort update TE parameters: no interface associated to Link Parameters"); + return; + } + if (!HAS_LINK_PARAMS(ifp)) + { + zlog_warn("OSPF MPLS-TE: Abort update TE parameters: no Link Parameters for interface"); + return; + } + + /* RFC3630 metrics */ + if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) + set_linkparams_rsc_clsclr (lp, ifp->link_params->admin_grp); + else + TLV_TYPE(lp->rsc_clsclr) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) + set_linkparams_max_bw (lp, ifp->link_params->max_bw); + else + TLV_TYPE(lp->max_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) + set_linkparams_max_rsv_bw (lp, ifp->link_params->max_rsv_bw); + else + TLV_TYPE(lp->max_rsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) + for (i = 0; i < MAX_CLASS_TYPE; i++) + set_linkparams_unrsv_bw (lp, i, ifp->link_params->unrsv_bw[i]); + else + TLV_TYPE(lp->unrsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_TE)) + set_linkparams_te_metric(lp, ifp->link_params->te_metric); + else + TLV_TYPE(lp->te_metric) = 0; + + /* TE metric Extensions */ + if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) + set_linkparams_av_delay(lp, ifp->link_params->av_delay, 0); + else + TLV_TYPE(lp->av_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) + set_linkparams_mm_delay(lp, ifp->link_params->min_delay, ifp->link_params->max_delay, 0); + else + TLV_TYPE(lp->mm_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) + set_linkparams_delay_var(lp, ifp->link_params->delay_var); + else + TLV_TYPE(lp->delay_var) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) + set_linkparams_pkt_loss(lp, ifp->link_params->pkt_loss, 0); + else + TLV_TYPE(lp->pkt_loss) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) + set_linkparams_res_bw(lp, ifp->link_params->res_bw); + else + TLV_TYPE(lp->res_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) + set_linkparams_ava_bw(lp, ifp->link_params->ava_bw); + else + TLV_TYPE(lp->ava_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) + set_linkparams_use_bw(lp, ifp->link_params->use_bw); + else + TLV_TYPE(lp->use_bw) = 0; + + /* RFC5392 */ + if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) + { + /* Flush LSA if it engaged and was previously a STD_TE one */ + if (IS_STD_TE(lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) + { + if (IS_DEBUG_OSPF_TE) + zlog_debug("OSPF MPLS-TE Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", + ifp->name, lp->flags, lp->type); + + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + /* Then, switch it to INTER-AS */ + if (OspfMplsTE.inter_as == AS) + lp->flags = INTER_AS | FLOOD_AS; + else + { + lp->flags = INTER_AS | FLOOD_AREA; + lp->area = ospf_area_lookup_by_area_id (ospf_lookup(), OspfMplsTE.interas_areaid); + } + } + set_linkparams_inter_as(lp, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); + } + else + { + if (IS_DEBUG_OSPF_TE) + zlog_debug("OSPF MPLS-TE Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", + ifp->name, lp->flags, lp->type); + + /* reset inter-as TE params */ + /* Flush LSA if it engaged and was previously an INTER_AS one */ + if (IS_INTER_AS(lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) + { + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + /* Then, switch it to Standard TE */ + lp->flags = STD_TE | FLOOD_AREA; + } + unset_linkparams_inter_as (lp); + } +} + static void initialize_linkparams (struct mpls_te_link *lp) { struct interface *ifp = lp->ifp; struct ospf_interface *oi; - float fval; - int i; + + if (IS_DEBUG_OSPF_TE) + zlog_debug("MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s", + ifp->name); if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) - return; + { + zlog_warn("MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s", + ifp->name); + return; + } /* * Try to set initial values those can be derived from @@ -505,18 +847,19 @@ initialize_linkparams (struct mpls_te_link *lp) */ set_linkparams_link_type (oi, lp); - /* - * Linux and *BSD kernel holds bandwidth parameter as an "int" type. - * We may have to reconsider, if "ifp->bandwidth" type changes to float. - */ - fval = (float)((ifp->bandwidth ? ifp->bandwidth - : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); + /* Set local IP addr */ + set_linkparams_lclif_ipaddr (lp, oi->address->u.prefix4); - set_linkparams_max_bw (lp, fval); - set_linkparams_max_rsv_bw (lp, fval); + /* Set Remote IP addr if Point to Point Interface */ + if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) + { + struct prefix *pref = CONNECTED_PREFIX(oi->connected); + if (pref != NULL) + set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); + } - for (i = 0; i < 8; i++) - set_linkparams_unrsv_bw (lp, i, fval); + /* Keep Area information in combination with link parameters. */ + lp->area = oi->area; return; } @@ -527,13 +870,22 @@ is_mandated_params_set (struct mpls_te_link *lp) int rc = 0; if (ntohs (OspfMplsTE.router_addr.header.type) == 0) + { + zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Router Address"); goto out; + } if (ntohs (lp->link_type.header.type) == 0) + { + zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Link Type"); goto out; + } - if (ntohs (lp->link_id.header.type) == 0) + if (!IS_INTER_AS (lp->type) && (ntohs (lp->link_id.header.type) == 0)) + { + zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Link ID"); goto out; + } rc = 1; out: @@ -550,6 +902,10 @@ ospf_mpls_te_new_if (struct interface *ifp) struct mpls_te_link *new; int rc = -1; + if (IS_DEBUG_OSPF_TE) + zlog_debug ("MPLS-TE(ospf_mpls_te_new_if) Add new %s interface %s to MPLS-TE list", + ifp->link_params ? "Active" : "Inactive", ifp->name); + if (lookup_linkparams_by_ifp (ifp) != NULL) { zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", (void *)ifp); @@ -557,23 +913,33 @@ ospf_mpls_te_new_if (struct interface *ifp) goto out; } - new = XCALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, - sizeof (struct mpls_te_link)); + new = XCALLOC (MTYPE_OSPF_MPLS_TE, sizeof (struct mpls_te_link)); if (new == NULL) { zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror (errno)); goto out; } - new->area = NULL; - new->flags = 0; new->instance = get_mpls_te_instance_value (); new->ifp = ifp; + /* By default TE-Link is RFC3630 compatible flooding in Area and not active */ + /* This default behavior will be adapted with call to ospf_mpls_te_update_if() */ + new->type = STD_TE | FLOOD_AREA; + new->flags = LPFLG_LSA_INACTIVE; + + /* Initialize Link Parameters from Interface */ + initialize_linkparams(new); - initialize_linkparams (new); + /* Set TE Parameters from Interface */ + update_linkparams(new); + /* Add Link Parameters structure to the list */ listnode_add (OspfMplsTE.iflist, new); + if (IS_DEBUG_OSPF_TE) + zlog_debug("OSPF MPLS-TE New IF: Add new LP context for %s[%d/%d]", + ifp->name, new->flags, new->type); + /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; @@ -598,7 +964,7 @@ ospf_mpls_te_del_if (struct interface *ifp) if (listcount (iflist) == 0) iflist->head = iflist->tail = NULL; - XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp); + XFREE (MTYPE_OSPF_MPLS_TE, lp); } /* Schedule Opaque-LSA refresh. *//* XXX */ @@ -608,6 +974,56 @@ ospf_mpls_te_del_if (struct interface *ifp) return rc; } +/* Main initialization / update function of the MPLS TE Link context */ + +/* Call when interface TE Link parameters are modified */ +void +ospf_mpls_te_update_if (struct interface *ifp) +{ + struct mpls_te_link *lp; + + if (IS_DEBUG_OSPF_TE) + zlog_debug ("OSPF MPLS-TE: Update LSA parameters for interface %s [%s]", + ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); + + /* Get Link context from interface */ + if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) + { + zlog_warn ("OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", ifp->name); + return; + } + + /* Fulfill MPLS-TE Link TLV from Interface TE Link parameters */ + if (HAS_LINK_PARAMS(ifp)) + { + SET_FLAG (lp->flags, LPFLG_LSA_ACTIVE); + + /* Update TE parameters */ + update_linkparams(lp); + + /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is enabled */ + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } + } + else + { + /* If MPLS TE is disable on this interface, flush LSA if it is already engaged */ + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + else + /* Reset Activity flag */ + lp->flags = LPFLG_LSA_INACTIVE; + } + + return; +} + static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) { @@ -620,10 +1036,10 @@ ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); goto out; } + if (oi->area == NULL || oi->area->ospf == NULL) { - zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", -IF_NAME (oi)); + zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", IF_NAME (oi)); goto out; } #ifdef notyet @@ -632,13 +1048,17 @@ IF_NAME (oi)); || (lp->area != NULL && oi->area == NULL)) { /* How should we consider this case? */ - zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); + zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", + IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } #endif - /* Keep Area information in conbination with linkparams. */ + /* Keep Area information in combination with linkparams. */ lp->area = oi->area; + /* Keep interface MPLS-TE status */ + lp->flags = HAS_LINK_PARAMS(oi->ifp); + switch (oi->state) { case ISM_PointToPoint: @@ -648,37 +1068,53 @@ IF_NAME (oi)); old_type = lp->link_type; old_id = lp->link_id; + /* Set Link type, Link ID, Local and Remote IP addr */ set_linkparams_link_type (oi, lp); set_linkparams_link_id (oi, lp); + set_linkparams_lclif_ipaddr (lp, oi->address->u.prefix4); + + if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) + { + struct prefix *pref = CONNECTED_PREFIX(oi->connected); + if (pref != NULL) + set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); + } + /* Update TE parameters */ + update_linkparams(lp); + + /* Try to Schedule LSA */ if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) || old_type.link_type.value != lp->link_type.link_type.value) || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) - || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) + || ntohl (old_id.value.s_addr) != + ntohl (lp->link_id.value.s_addr))) { - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } break; default: lp->link_type.header.type = htons (0); lp->link_id.header.type = htons (0); - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); break; } out: return; + } static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) { - /* So far, nothing to do here. */ + /* Nothing to do here */ return; } @@ -706,22 +1142,10 @@ build_router_tlv (struct stream *s) } static void -build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->link_type.header; - if (ntohs (tlvh->type) != 0) +build_link_subtlv (struct stream *s, struct te_tlv_header *tlvh) { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} -static void -build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->link_id.header; - if (ntohs (tlvh->type) != 0) + if ((tlvh != NULL) && (ntohs (tlvh->type) != 0)) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); @@ -730,104 +1154,32 @@ build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) } static void -build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; - if (tlvh != NULL && ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; - if (tlvh != NULL && ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->te_metric.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->max_bw.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->unrsv_bw.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) -{ - struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; - if (ntohs (tlvh->type) != 0) - { - build_tlv_header (s, tlvh); - stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); - } - return; -} - -static void -build_link_tlv (struct stream *s, struct mpls_te_link *lp) +build_link_tlv (struct stream *s, struct mpls_te_link *lp) { set_linkparams_link_header (lp); build_tlv_header (s, &lp->link_header.header); - build_link_subtlv_link_type (s, lp); - build_link_subtlv_link_id (s, lp); - build_link_subtlv_lclif_ipaddr (s, lp); - build_link_subtlv_rmtif_ipaddr (s, lp); - build_link_subtlv_te_metric (s, lp); - build_link_subtlv_max_bw (s, lp); - build_link_subtlv_max_rsv_bw (s, lp); - build_link_subtlv_unrsv_bw (s, lp); - build_link_subtlv_rsc_clsclr (s, lp); + build_link_subtlv (s, &lp->link_type.header); + build_link_subtlv (s, &lp->link_id.header); + build_link_subtlv (s, &lp->lclif_ipaddr.header); + build_link_subtlv (s, &lp->rmtif_ipaddr.header); + build_link_subtlv (s, &lp->te_metric.header); + build_link_subtlv (s, &lp->max_bw.header); + build_link_subtlv (s, &lp->max_rsv_bw.header); + build_link_subtlv (s, &lp->unrsv_bw.header); + build_link_subtlv (s, &lp->rsc_clsclr.header); + build_link_subtlv (s, &lp->lrrid.header); + build_link_subtlv (s, &lp->llri.header); + build_link_subtlv (s, &lp->rip.header); + build_link_subtlv (s, &lp->ras.header); + build_link_subtlv (s, &lp->av_delay.header); + build_link_subtlv (s, &lp->mm_delay.header); + build_link_subtlv (s, &lp->delay_var.header); + build_link_subtlv (s, &lp->pkt_loss.header); + build_link_subtlv (s, &lp->res_bw.header); + build_link_subtlv (s, &lp->ava_bw.header); + build_link_subtlv (s, &lp->res_bw.header); + return; } @@ -856,7 +1208,7 @@ ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new = NULL; - u_char options, lsa_type; + u_char options, lsa_type = 0; struct in_addr lsa_id; u_int32_t tmp; u_int16_t length; @@ -869,19 +1221,42 @@ ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) } lsah = (struct lsa_header *) STREAM_DATA (s); - options = LSA_OPTIONS_GET (area); - options |= LSA_OPTIONS_NSSA_GET (area); - options |= OSPF_OPTION_O; /* Don't forget this :-) */ + options = OSPF_OPTION_O; /* Don't forget this :-) */ - lsa_type = OSPF_OPAQUE_AREA_LSA; - tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); - lsa_id.s_addr = htonl (tmp); + /* Set opaque-LSA header fields depending of the type of RFC */ + if (IS_INTER_AS (lp->type)) + { + if IS_FLOOD_AS (lp->type) + { + options |= OSPF_OPTION_E; /* Enable AS external as we flood Inter-AS with Opaque Type 11 */ + lsa_type = OSPF_OPAQUE_AS_LSA; + } + else + { + options |= LSA_OPTIONS_GET (area); /* Get area default option */ + options |= LSA_OPTIONS_NSSA_GET (area); + lsa_type = OSPF_OPAQUE_AREA_LSA; + } + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); + lsa_id.s_addr = htonl (tmp); - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); + struct ospf *top = ospf_lookup (); + + lsa_header_set (s, options, lsa_type, lsa_id, top->router_id); + } + else + { + options |= LSA_OPTIONS_GET (area); /* Get area default option */ + options |= LSA_OPTIONS_NSSA_GET (area); + lsa_type = OSPF_OPAQUE_AREA_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsa_id.s_addr = htonl (tmp); + lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); + } - /* Set opaque-LSA header fields. */ - lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", + lsa_type, inet_ntoa (lsa_id)); /* Set opaque-LSA body fields. */ ospf_mpls_te_lsa_body_set (s, lp); @@ -936,9 +1311,8 @@ ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) goto out; } - /* Now this linkparameter entry has associated LSA. */ - lp->flags |= LPFLG_LSA_ENGAGED; - + /* Now this link-parameter entry has associated LSA. */ + SET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); /* Update new LSA origination count. */ area->ospf->lsa_originate_count++; @@ -949,7 +1323,8 @@ ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) { char area_id[INET_ADDRSTRLEN]; strcpy (area_id, inet_ntoa (area->area_id)); - zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); + zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", + new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); ospf_lsa_header_dump (new->data); } @@ -959,7 +1334,7 @@ ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) } static int -ospf_mpls_te_lsa_originate (void *arg) +ospf_mpls_te_lsa_originate_area (void *arg) { struct ospf_area *area = (struct ospf_area *) arg; struct listnode *node, *nnode; @@ -968,34 +1343,44 @@ ospf_mpls_te_lsa_originate (void *arg) if (OspfMplsTE.status == disabled) { - zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now."); + zlog_info ("ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now."); rc = 0; /* This is not an error case. */ goto out; } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { + /* Process only enabled LSA with area scope flooding */ + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE) || IS_FLOOD_AS (lp->type)) + continue; + if (lp->area == NULL) continue; + if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) continue; - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) { - if (lp->flags & LPFLG_LSA_FORCED_REFRESH) + if CHECK_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH) { - lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; + UNSET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); + zlog_warn ("OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } continue; } if (! is_mandated_params_set (lp)) { - zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); + zlog_warn ("ospf_mpls_te_lsa_originate_area: Link(%s) lacks some mandated MPLS-TE parameters.", + lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this area and Link. */ + if (IS_DEBUG_OSPF_TE) + zlog_debug ("MPLS-TE(ospf_mpls_te_lsa_originate_area) Let's finally reoriginate the LSA %d through the Area %s for Link %s", + lp->instance, inet_ntoa (area->area_id), lp->ifp ? lp->ifp->name : "?"); if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) goto out; } @@ -1005,11 +1390,112 @@ ospf_mpls_te_lsa_originate (void *arg) return rc; } +static int +ospf_mpls_te_lsa_originate2 (struct ospf *top, struct mpls_te_link *lp) +{ + struct ospf_lsa *new; + int rc = -1; + + /* Create new Opaque-LSA/Inter-AS instance. */ + if ((new = ospf_mpls_te_lsa_new (NULL, lp)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?"); + goto out; + } + + /* Install this LSA into LSDB. */ + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?"); + ospf_lsa_unlock (&new); + goto out; + } + + /* Now this Router Info parameter entry has associated LSA. */ + SET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); + /* Update new LSA origination count. */ + top->lsa_originate_count++; + + /* Flood new LSA through AS. */ + ospf_flood_through_as (top, NULL /*nbr */ , new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE Inter-AS", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + rc = 0; +out:return rc; +} + +static int +ospf_mpls_te_lsa_originate_as (void *arg) +{ + struct ospf *top; + struct ospf_area *area; + struct listnode *node, *nnode; + struct mpls_te_link *lp; + int rc = -1; + + if ((OspfMplsTE.status == disabled) || (OspfMplsTE.inter_as == Disable)) + { + zlog_info + ("ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now."); + rc = 0; /* This is not an error case. */ + goto out; + } + + for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) + { + /* Process only enabled INTER_AS Links or Pseudo-Links */ + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE) || !IS_INTER_AS (lp->type)) + continue; + + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) + { + if CHECK_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH) + { + UNSET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + } + continue; + } + if (!is_mandated_params_set (lp)) + { + zlog_warn ("ospf_mpls_te_lsa_originate_as: Link(%s) lacks some mandated MPLS-TE parameters.", + lp->ifp ? lp->ifp->name : "?"); + continue; + } + + /* Ok, let's try to originate an LSA for this AS and Link. */ + if (IS_DEBUG_OSPF_TE) + zlog_debug ("MPLS-TE(ospf_mpls_te_lsa_originate_as) Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", + lp->instance, IS_FLOOD_AS (lp->type) ? "AS" : "Area", lp->ifp ? lp->ifp->name : "Unknown"); + + if (IS_FLOOD_AS (lp->type)) + { + top = (struct ospf *) arg; + rc = ospf_mpls_te_lsa_originate2 (top, lp); + } + else + { + area = (struct ospf_area *) arg; + rc = ospf_mpls_te_lsa_originate1 (area, lp); + } + } + + rc = 0; +out:return rc; +} + static struct ospf_lsa * ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) { struct mpls_te_link *lp; struct ospf_area *area = lsa->area; + struct ospf *top; struct ospf_lsa *new = NULL; if (OspfMplsTE.status == disabled) @@ -1029,11 +1515,18 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } + /* Check if lp was not disable in the interval */ + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE)) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: lp was disabled: Flush it!"); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE (lsa)) { if (lp) - lp->flags &= ~LPFLG_LSA_ENGAGED; + UNSET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); ospf_opaque_lsa_flush_schedule (lsa); goto out; } @@ -1048,15 +1541,24 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) /* Install this LSA into LSDB. */ /* Given "lsa" will be freed in the next function. */ - if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) + /* As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use ospf_lookup() to get ospf instance */ + if (area) + top = area->ospf; + else + top = ospf_lookup (); + + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } - /* Flood updated LSA through area. */ - ospf_flood_through_area (area, NULL/*nbr*/, new); + /* Flood updated LSA through AS or Area depending of the RFC of the link */ + if (IS_FLOOD_AS (lp->type)) + ospf_flood_through_as (top, NULL, new); + else + ospf_flood_through_area (area, NULL/*nbr*/, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) @@ -1070,34 +1572,80 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) return new; } -static void -ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, - enum sched_opcode opcode) +void +ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, opcode_t opcode) { struct ospf_lsa lsa; struct lsa_header lsah; + struct ospf *top; u_int32_t tmp; memset (&lsa, 0, sizeof (lsa)); memset (&lsah, 0, sizeof (lsah)); + top = ospf_lookup (); + + /* Check if the pseudo link is ready to flood */ + if (!(CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE)) + || !(IS_FLOOD_AREA (lp->type) || IS_FLOOD_AS (lp->type))) { + return; + } lsa.area = lp->area; lsa.data = &lsah; - lsah.type = OSPF_OPAQUE_AREA_LSA; - tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); - lsah.id.s_addr = htonl (tmp); + if (IS_FLOOD_AS (lp->type)) + { + lsah.type = OSPF_OPAQUE_AS_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); + lsah.id.s_addr = htonl (tmp); + } + else + { + lsah.type = OSPF_OPAQUE_AREA_LSA; + if (IS_INTER_AS (lp->type)) + { + /* Set the area context if not know */ + if (lp->area == NULL) + lp->area = ospf_area_lookup_by_area_id (top, OspfMplsTE.interas_areaid); + /* Unable to set the area context. Abort! */ + if (lp->area == NULL) + { + zlog_warn ("MPLS-TE(ospf_mpls_te_lsa_schedule) Area context is null. Abort !"); + return; + } + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); + } + else + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsah.id.s_addr = htonl (tmp); + } switch (opcode) { - case REORIGINATE_PER_AREA: - ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, - OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + case REORIGINATE_THIS_LSA: + if (IS_FLOOD_AS (lp->type)) + { + ospf_opaque_lsa_reoriginate_schedule ((void *) top, OSPF_OPAQUE_AS_LSA, + OPAQUE_TYPE_INTER_AS_LSA); + break; + } + + if (IS_FLOOD_AREA (lp->type)) + { + if (IS_INTER_AS (lp->type)) + ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_INTER_AS_LSA); + else + ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + break; + } break; case REFRESH_THIS_LSA: ospf_opaque_lsa_refresh_schedule (&lsa); break; case FLUSH_THIS_LSA: - lp->flags &= ~LPFLG_LSA_ENGAGED; + /* Reset Activity flag */ + lp->flags = LPFLG_LSA_INACTIVE; ospf_opaque_lsa_flush_schedule (&lsa); break; default: @@ -1108,6 +1656,7 @@ ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, return; } + /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ @@ -1118,7 +1667,8 @@ show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; if (vty != NULL) - vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); + vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), + VTY_NEWLINE); else zlog_debug (" Router-Address: %s", inet_ntoa (top->value)); @@ -1131,7 +1681,8 @@ show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh) struct te_tlv_link *top = (struct te_tlv_link *) tlvh; if (vty != NULL) - vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE); + vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), + VTY_NEWLINE); else zlog_debug (" Link: %u octets of data", ntohs (top->header.length)); @@ -1158,7 +1709,8 @@ show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh) } if (vty != NULL) - vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE); + vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, + VTY_NEWLINE); else zlog_debug (" Link-Type: %s (%u)", cp, top->link_type.value); @@ -1180,7 +1732,8 @@ show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh) } static u_int16_t -show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, + struct te_tlv_header *tlvh) { struct te_link_subtlv_lclif_ipaddr *top; int i, n; @@ -1196,7 +1749,8 @@ show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) for (i = 0; i < n; i++) { if (vty != NULL) - vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), + VTY_NEWLINE); else zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i])); } @@ -1204,7 +1758,8 @@ show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) } static u_int16_t -show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, + struct te_tlv_header *tlvh) { struct te_link_subtlv_rmtif_ipaddr *top; int i, n; @@ -1219,7 +1774,8 @@ show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) for (i = 0; i < n; i++) { if (vty != NULL) - vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), + VTY_NEWLINE); else zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i])); } @@ -1233,9 +1789,11 @@ show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh) top = (struct te_link_subtlv_te_metric *) tlvh; if (vty != NULL) - vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + vty_out (vty, " Traffic Engineering Metric: %u%s", + (u_int32_t) ntohl (top->value), VTY_NEWLINE); else - zlog_debug (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value)); + zlog_debug (" Traffic Engineering Metric: %u", + (u_int32_t) ntohl (top->value)); return TLV_SIZE (tlvh); } @@ -1267,7 +1825,8 @@ show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) fval = ntohf (top->value); if (vty != NULL) - vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, + VTY_NEWLINE); else zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); @@ -1278,17 +1837,25 @@ static u_int16_t show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_unrsv_bw *top; - float fval; + float fval1, fval2; int i; top = (struct te_link_subtlv_unrsv_bw *) tlvh; - for (i = 0; i < 8; i++) + if (vty != NULL) + vty_out (vty, " Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE); + else + zlog_debug (" Unreserved Bandwidth per Class Type in Byte/s:"); + for (i = 0; i < MAX_CLASS_TYPE; i+=2) { - fval = ntohf (top->value[i]); + fval1 = ntohf (top->value[i]); + fval2 = ntohf (top->value[i+1]); + if (vty != NULL) - vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); + vty_out(vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", + i, fval1, i+1, fval2, VTY_NEWLINE); else - zlog_debug (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); + zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", + i, fval1, i+1, fval2); } return TLV_SIZE (tlvh); @@ -1301,9 +1868,230 @@ show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) top = (struct te_link_subtlv_rsc_clsclr *) tlvh; if (vty != NULL) - vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + vty_out (vty, " Resource class/color: 0x%x%s", + (u_int32_t) ntohl (top->value), VTY_NEWLINE); + else + zlog_debug (" Resource Class/Color: 0x%x", + (u_int32_t) ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_lrrid (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_lrrid *top; + + top = (struct te_link_subtlv_lrrid *) tlvh; + + if (vty != NULL) + { + vty_out (vty, " Local TE Router ID: %s%s", inet_ntoa (top->local), + VTY_NEWLINE); + vty_out (vty, " Remote TE Router ID: %s%s", inet_ntoa (top->remote), + VTY_NEWLINE); + } + else + { + zlog_debug (" Local TE Router ID: %s", inet_ntoa (top->local)); + zlog_debug (" Remote TE Router ID: %s", inet_ntoa (top->remote)); + } + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_llri (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_llri *top; + + top = (struct te_link_subtlv_llri *) tlvh; + + if (vty != NULL) + { + vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (top->local), + VTY_NEWLINE); + vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (top->remote), + VTY_NEWLINE); + } + else + { + zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (top->local)); + zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (top->remote)); + } + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_rip (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_rip *top; + + top = (struct te_link_subtlv_rip *) tlvh; + + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", + inet_ntoa (top->value), VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", + inet_ntoa (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_ras (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_ras *top; + + top = (struct te_link_subtlv_ras *) tlvh; + + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_av_delay (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_av_delay *top; + u_int32_t delay; + u_int32_t anomalous; + + top = (struct te_link_subtlv_av_delay *) tlvh; + delay = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; + anomalous = (u_int32_t) ntohl (top->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", + anomalous ? "Anomalous" : "Normal", delay, VTY_NEWLINE); + else + zlog_debug (" %s Average Link Delay: %d (micro-sec)", + anomalous ? "Anomalous" : "Normal", delay); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_mm_delay (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_mm_delay *top; + u_int32_t low, high; + u_int32_t anomalous; + + top = (struct te_link_subtlv_mm_delay *) tlvh; + low = (u_int32_t) ntohl (top->low) & TE_EXT_MASK; + anomalous = (u_int32_t) ntohl (top->low) & TE_EXT_ANORMAL; + high = (u_int32_t) ntohl (top->high); + + if (vty != NULL) + vty_out (vty, " %s Min/Max Link Delay: %d/%d (micro-sec)%s", + anomalous ? "Anomalous" : "Normal", low, high, VTY_NEWLINE); + else + zlog_debug (" %s Min/Max Link Delay: %d/%d (micro-sec)", + anomalous ? "Anomalous" : "Normal", low, high); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_delay_var (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_delay_var *top; + u_int32_t jitter; + + top = (struct te_link_subtlv_delay_var *) tlvh; + jitter = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; + + if (vty != NULL) + vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE); + else + zlog_debug (" Delay Variation: %d (micro-sec)", jitter); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_pkt_loss (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_pkt_loss *top; + u_int32_t loss; + u_int32_t anomalous; + float fval; + + top = (struct te_link_subtlv_pkt_loss *) tlvh; + loss = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; + fval = (float) (loss * LOSS_PRECISION); + anomalous = (u_int32_t) ntohl (top->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Link Loss: %g (%%)%s", anomalous ? "Anomalous" : "Normal", + fval, VTY_NEWLINE); + else + zlog_debug (" %s Link Loss: %g (%%)", anomalous ? "Anomalous" : "Normal", + fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_res_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_res_bw *top; + float fval; + + top = (struct te_link_subtlv_res_bw *) tlvh; + fval = ntohf (top->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", + fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", + fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_ava_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_ava_bw *top; + float fval; + + top = (struct te_link_subtlv_ava_bw *) tlvh; + fval = ntohf (top->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", + fval, VTY_NEWLINE); else - zlog_debug (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); + zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", + fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_use_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_use_bw *top; + float fval; + + top = (struct te_link_subtlv_use_bw *) tlvh; + fval = ntohf (top->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", + fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", + fval); return TLV_SIZE (tlvh); } @@ -1312,9 +2100,11 @@ static u_int16_t show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) { if (vty != NULL) - vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); + vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", + ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); else - zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); + zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", + ntohs (tlvh->type), ntohs (tlvh->length)); return TLV_SIZE (tlvh); } @@ -1358,6 +2148,39 @@ ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0, case TE_LINK_SUBTLV_RSC_CLSCLR: sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh); break; + case TE_LINK_SUBTLV_LRRID: + sum += show_vty_link_subtlv_lrrid (vty, tlvh); + break; + case TE_LINK_SUBTLV_LLRI: + sum += show_vty_link_subtlv_llri (vty, tlvh); + break; + case TE_LINK_SUBTLV_RIP: + sum += show_vty_link_subtlv_rip (vty, tlvh); + break; + case TE_LINK_SUBTLV_RAS: + sum += show_vty_link_subtlv_ras (vty, tlvh); + break; + case TE_LINK_SUBTLV_AV_DELAY: + sum += show_vty_link_subtlv_av_delay (vty, tlvh); + break; + case TE_LINK_SUBTLV_MM_DELAY: + sum += show_vty_link_subtlv_mm_delay (vty, tlvh); + break; + case TE_LINK_SUBTLV_DELAY_VAR: + sum += show_vty_link_subtlv_delay_var (vty, tlvh); + break; + case TE_LINK_SUBTLV_PKT_LOSS: + sum += show_vty_link_subtlv_pkt_loss (vty, tlvh); + break; + case TE_LINK_SUBTLV_RES_BW: + sum += show_vty_link_subtlv_res_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_AVA_BW: + sum += show_vty_link_subtlv_ava_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_USE_BW: + sum += show_vty_link_subtlv_use_bw (vty, tlvh); + break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; @@ -1411,49 +2234,20 @@ ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) static void ospf_mpls_te_config_write_router (struct vty *vty) { + if (OspfMplsTE.status == enabled) { - vty_out (vty, " mpls-te%s", VTY_NEWLINE); + vty_out (vty, " mpls-te on%s", VTY_NEWLINE); vty_out (vty, " mpls-te router-address %s%s", inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); } - return; -} - -static void -ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) -{ - struct mpls_te_link *lp; - if ((OspfMplsTE.status == enabled) - && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) - && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) - { - float fval; - int i; - - vty_out (vty, " mpls-te link metric %u%s", - (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); - - fval = ntohf (lp->max_bw.value); - if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) - vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); - - fval = ntohf (lp->max_rsv_bw.value); - if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) - vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); + if (OspfMplsTE.inter_as == AS) + vty_out (vty, " mpls-te inter-as as%s", VTY_NEWLINE); + if (OspfMplsTE.inter_as == Area) + vty_out (vty, " mpls-te inter-as area %s %s", + inet_ntoa (OspfMplsTE.interas_areaid), VTY_NEWLINE); - for (i = 0; i < 8; i++) - { - fval = ntohf (lp->unrsv_bw.value[i]); - if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) - vty_out (vty, " mpls-te link unrsv-bw %d %g%s", - i, fval, VTY_NEWLINE); - } - - vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", - (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); - } return; } @@ -1461,13 +2255,13 @@ ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) * Followings are vty command functions. *------------------------------------------------------------------------*/ -DEFUN (mpls_te, - mpls_te_cmd, - "mpls-te", - "Configure MPLS-TE parameters\n" +DEFUN (ospf_mpls_te_on, + ospf_mpls_te_on_cmd, + "mpls-te on", + MPLS_TE_STR "Enable the MPLS-TE functionality\n") { - struct listnode *node, *nnode; + struct listnode *node; struct mpls_te_link *lp; if (OspfMplsTE.status == enabled) @@ -1478,31 +2272,28 @@ DEFUN (mpls_te, OspfMplsTE.status = enabled; - /* - * Following code is intended to handle two cases; - * - * 1) MPLS-TE was disabled at startup time, but now become enabled. - * 2) MPLS-TE was once enabled then disabled, and now enabled again. - */ - for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) - initialize_linkparams (lp); + /* Reoriginate RFC3630 & RFC6827 Links */ + ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); - ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + /* Reoriginate LSA if INTER-AS is always on */ + if (OspfMplsTE.inter_as != Disable) + { + for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) + { + if (IS_INTER_AS (lp->type)) + { + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } + } + } return CMD_SUCCESS; } -ALIAS (mpls_te, - mpls_te_on_cmd, - "mpls-te on", - "Configure MPLS-TE parameters\n" - "Enable the MPLS-TE functionality\n") - -DEFUN (no_mpls_te, - no_mpls_te_cmd, +DEFUN (no_ospf_mpls_te, + no_ospf_mpls_te_cmd, "no mpls-te", NO_STR - "Configure MPLS-TE parameters\n" "Disable the MPLS-TE functionality\n") { struct listnode *node, *nnode; @@ -1517,17 +2308,16 @@ DEFUN (no_mpls_te, OspfMplsTE.status = disabled; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) - if (lp->area != NULL) - if (lp->flags & LPFLG_LSA_ENGAGED) + if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); return CMD_SUCCESS; } -DEFUN (mpls_te_router_addr, - mpls_te_router_addr_cmd, +DEFUN (ospf_mpls_te_router_addr, + ospf_mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", - "MPLS-TE specific commands\n" + MPLS_TE_STR "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") { @@ -1554,10 +2344,10 @@ DEFUN (mpls_te_router_addr, for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { - if (lp->area == NULL) + if ((lp->area == NULL) || IS_FLOOD_AS (lp->type)) continue; - if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) + if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) { need_to_reoriginate = 1; break; @@ -1566,247 +2356,151 @@ DEFUN (mpls_te_router_addr, for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { - if (lp->area == NULL) + if ((lp->area == NULL) || IS_FLOOD_AS (lp->type)) continue; if (need_to_reoriginate) - lp->flags |= LPFLG_LSA_FORCED_REFRESH; + SET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); else ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } if (need_to_reoriginate) - ospf_mpls_te_foreach_area ( - ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); } out: return CMD_SUCCESS; } -DEFUN (mpls_te_link_metric, - mpls_te_link_metric_cmd, - "mpls-te link metric <0-4294967295>", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Link metric for MPLS-TE purpose\n" - "Metric\n") +static int +set_inter_as_mode (struct vty *vty, const char *mode_name, + const char *area_id) { - struct interface *ifp = (struct interface *) vty->index; + enum inter_as_mode mode; + struct listnode *node; struct mpls_te_link *lp; - u_int32_t value; + int format; - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - - value = strtoul (argv[0], NULL, 10); - - if (ntohs (lp->te_metric.header.type) == 0 - || ntohl (lp->te_metric.value) != value) + if (OspfMplsTE.status == enabled) { - set_linkparams_te_metric (lp, value); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } - return CMD_SUCCESS; -} - -DEFUN (mpls_te_link_maxbw, - mpls_te_link_maxbw_cmd, - "mpls-te link max-bw BANDWIDTH", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Maximum bandwidth that can be used\n" - "Bytes/second (IEEE floating point format)\n") -{ - struct interface *ifp = (struct interface *) vty->index; - struct mpls_te_link *lp; - float f1, f2; - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } + /* Read and Check inter_as mode */ + if (strcmp (mode_name, "as") == 0) + mode = AS; + else if (strcmp (mode_name, "area") == 0) + { + mode = Area; + VTY_GET_OSPF_AREA_ID (OspfMplsTE.interas_areaid, format, area_id); + } + else + { + vty_out (vty, "Unknown mode. Please choose between as or area%s", + VTY_NEWLINE); + return CMD_WARNING; + } - f1 = ntohf (lp->max_bw.value); - if (sscanf (argv[0], "%g", &f2) != 1) - { - vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("MPLS-TE: Inter-AS enable with %s flooding support", + mode2text[mode]); - if (ntohs (lp->max_bw.header.type) == 0 - || f1 != f2) - { - set_linkparams_max_bw (lp, f2); + /* Register new callbacks regarding the flooding scope (AS or Area) */ + if (ospf_mpls_te_register (mode) < 0) + { + vty_out (vty, "Internal error: Unable to register Inter-AS functions%s", + VTY_NEWLINE); + return CMD_WARNING; + } - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } + /* Enable mode and re-originate LSA if needed */ + if ((OspfMplsTE.inter_as == Disable) && (mode != OspfMplsTE.inter_as)) + { + OspfMplsTE.inter_as = mode; + /* Re-originate all InterAS-TEv2 LSA */ + for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) + { + if (IS_INTER_AS (lp->type)) + { + if (mode == AS) + lp->type |= FLOOD_AS; + else + lp->type |= FLOOD_AREA; + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); + } + } + } + else + { + vty_out (vty, "Please change Inter-AS support to disable first before going to mode %s%s", + mode2text[mode], VTY_NEWLINE); + return CMD_WARNING; + } } return CMD_SUCCESS; } -DEFUN (mpls_te_link_max_rsv_bw, - mpls_te_link_max_rsv_bw_cmd, - "mpls-te link max-rsv-bw BANDWIDTH", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Maximum bandwidth that may be reserved\n" - "Bytes/second (IEEE floating point format)\n") +DEFUN (ospf_mpls_te_inter_as_as, + ospf_mpls_te_inter_as_cmd, + "mpls-te inter-as as", + MPLS_TE_STR + "Configure MPLS-TE Inter-AS support\n" + "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n") { - struct interface *ifp = (struct interface *) vty->index; - struct mpls_te_link *lp; - float f1, f2; - - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - - f1 = ntohf (lp->max_rsv_bw.value); - if (sscanf (argv[0], "%g", &f2) != 1) - { - vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - if (ntohs (lp->max_rsv_bw.header.type) == 0 - || f1 != f2) - { - set_linkparams_max_rsv_bw (lp, f2); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } - return CMD_SUCCESS; + return set_inter_as_mode (vty, "as", ""); } -DEFUN (mpls_te_link_unrsv_bw, - mpls_te_link_unrsv_bw_cmd, - "mpls-te link unrsv-bw <0-7> BANDWIDTH", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Unreserved bandwidth at each priority level\n" - "Priority\n" - "Bytes/second (IEEE floating point format)\n") +DEFUN (ospf_mpls_te_inter_as_area, + ospf_mpls_te_inter_as_area_cmd, + "mpls-te inter-as area (A.B.C.D|<0-4294967295>)", + MPLS_TE_STR + "Configure MPLS-TE Inter-AS support\n" + "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n" + "OSPF area ID in IP format\n" + "OSPF area ID as decimal value\n") { - struct interface *ifp = (struct interface *) vty->index; - struct mpls_te_link *lp; - int priority; - float f1, f2; - - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } - - /* We don't have to consider about range check here. */ - if (sscanf (argv[0], "%d", &priority) != 1) - { - vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - f1 = ntohf (lp->unrsv_bw.value [priority]); - if (sscanf (argv[1], "%g", &f2) != 1) - { - vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; - } - - if (ntohs (lp->unrsv_bw.header.type) == 0 - || f1 != f2) - { - set_linkparams_unrsv_bw (lp, priority, f2); - - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } - return CMD_SUCCESS; + return set_inter_as_mode (vty, "area", argv[0]); } -DEFUN (mpls_te_link_rsc_clsclr, - mpls_te_link_rsc_clsclr_cmd, - "mpls-te link rsc-clsclr BITPATTERN", - "MPLS-TE specific commands\n" - "Configure MPLS-TE link parameters\n" - "Administrative group membership\n" - "32-bit Hexadecimal value (ex. 0xa1)\n") +DEFUN (no_ospf_mpls_te_inter_as, + no_ospf_mpls_te_inter_as_cmd, + "no mpls-te inter-as", + NO_STR + MPLS_TE_STR + "Disable MPLS-TE Inter-AS support\n") { - struct interface *ifp = (struct interface *) vty->index; + + struct listnode *node, *nnode; struct mpls_te_link *lp; - unsigned long value; - if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) - { - vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); - return CMD_WARNING; - } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("MPLS-TE: Inter-AS support OFF"); - if (sscanf (argv[0], "0x%lx", &value) != 1) + if ((OspfMplsTE.status == enabled) && (OspfMplsTE.inter_as != Disable)) { - vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); - return CMD_WARNING; + OspfMplsTE.inter_as = Disable; + /* Flush all Inter-AS LSA */ + for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) + if (IS_INTER_AS (lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } - if (ntohs (lp->rsc_clsclr.header.type) == 0 - || ntohl (lp->rsc_clsclr.value) != value) - { - set_linkparams_rsc_clsclr (lp, value); + /* Deregister the Callbacks for Inter-AS suport */ + ospf_mpls_te_unregister (); - if (OspfMplsTE.status == enabled) - if (lp->area != NULL) - { - if (lp->flags & LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); - else - ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); - } - } return CMD_SUCCESS; } -DEFUN (show_mpls_te_router, - show_mpls_te_router_cmd, - "show mpls-te router", +DEFUN (show_ip_ospf_mpls_te_router, + show_ip_ospf_mpls_te_router_cmd, + "show ip ospf mpls-te router", SHOW_STR + IP_STR + OSPF_STR "MPLS-TE information\n" - "Router information\n") + "MPLS-TE Router parameters\n") { if (OspfMplsTE.status == enabled) { - vty_out (vty, "--- MPLS-TE router parameters ---%s", - VTY_NEWLINE); + vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); if (ntohs (OspfMplsTE.router_addr.header.type) != 0) show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); @@ -1820,29 +2514,73 @@ static void show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; - struct te_tlv_header *tlvh; - if ((OspfMplsTE.status == enabled) - && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) - && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) + if ((OspfMplsTE.status == enabled) + && HAS_LINK_PARAMS(ifp) + && !if_is_loopback (ifp) + && if_is_up (ifp) + && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { + /* Continue only if interface is not passive or support Inter-AS TEv2 */ + if (!(ospf_oi_count (ifp) > 0)) + { + if (IS_INTER_AS (lp->type)) + { + vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + } + else + { + /* MPLS-TE is not activate on this interface */ + /* or this interface is passive and Inter-AS TEv2 is not activate */ + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + return; + } + } + else + { vty_out (vty, "-- MPLS-TE link parameters for %s --%s", ifp->name, VTY_NEWLINE); + } - show_vty_link_subtlv_link_type (vty, &lp->link_type.header); - show_vty_link_subtlv_link_id (vty, &lp->link_id.header); - - if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) - show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); - if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) - show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); - - show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); - - show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); - show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); - show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); - show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); + if (TLV_TYPE(lp->link_type) != 0) + show_vty_link_subtlv_link_type (vty, &lp->link_type.header); + if (TLV_TYPE(lp->link_id) != 0) + show_vty_link_subtlv_link_id (vty, &lp->link_id.header); + if (TLV_TYPE(lp->lclif_ipaddr) != 0) + show_vty_link_subtlv_lclif_ipaddr (vty, &lp->lclif_ipaddr.header); + if (TLV_TYPE(lp->rmtif_ipaddr) != 0) + show_vty_link_subtlv_rmtif_ipaddr (vty, &lp->rmtif_ipaddr.header); + if (TLV_TYPE(lp->rip) != 0) + show_vty_link_subtlv_rip (vty, &lp->rip.header); + if (TLV_TYPE(lp->ras) != 0) + show_vty_link_subtlv_ras (vty, &lp->ras.header); + if (TLV_TYPE(lp->te_metric) != 0) + show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); + if (TLV_TYPE(lp->max_bw) != 0) + show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); + if (TLV_TYPE(lp->max_rsv_bw) != 0) + show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); + if (TLV_TYPE(lp->unrsv_bw) != 0) + show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); + if (TLV_TYPE(lp->rsc_clsclr) != 0) + show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); + if (TLV_TYPE(lp->av_delay) != 0) + show_vty_link_subtlv_av_delay (vty, &lp->av_delay.header); + if (TLV_TYPE(lp->mm_delay) != 0) + show_vty_link_subtlv_mm_delay (vty, &lp->mm_delay.header); + if (TLV_TYPE(lp->delay_var) != 0) + show_vty_link_subtlv_delay_var (vty, &lp->delay_var.header); + if (TLV_TYPE(lp->pkt_loss) != 0) + show_vty_link_subtlv_pkt_loss (vty, &lp->pkt_loss.header); + if (TLV_TYPE(lp->res_bw) != 0) + show_vty_link_subtlv_res_bw (vty, &lp->res_bw.header); + if (TLV_TYPE(lp->ava_bw) != 0) + show_vty_link_subtlv_ava_bw (vty, &lp->ava_bw.header); + if (TLV_TYPE(lp->use_bw) != 0) + show_vty_link_subtlv_use_bw (vty, &lp->use_bw.header); + vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE); } else { @@ -1853,10 +2591,12 @@ show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) return; } -DEFUN (show_mpls_te_link, - show_mpls_te_link_cmd, - "show mpls-te interface [INTERFACE]", +DEFUN (show_ip_ospf_mpls_te_link, + show_ip_ospf_mpls_te_link_cmd, + "show ip ospf mpls-te interface [INTERFACE]", SHOW_STR + IP_STR + OSPF_STR "MPLS-TE information\n" "Interface information\n" "Interface name\n") @@ -1885,19 +2625,15 @@ DEFUN (show_mpls_te_link, static void ospf_mpls_te_register_vty (void) { - install_element (VIEW_NODE, &show_mpls_te_router_cmd); - install_element (VIEW_NODE, &show_mpls_te_link_cmd); - - install_element (OSPF_NODE, &mpls_te_cmd); - install_element (OSPF_NODE, &no_mpls_te_cmd); - install_element (OSPF_NODE, &mpls_te_on_cmd); - install_element (OSPF_NODE, &mpls_te_router_addr_cmd); + install_element (VIEW_NODE, &show_ip_ospf_mpls_te_router_cmd); + install_element (VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); - install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_on_cmd); + install_element (OSPF_NODE, &no_ospf_mpls_te_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_router_addr_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_inter_as_cmd); + install_element (OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd); + install_element (OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd); return; } diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h index 863d8ba8f..8bb77c40c 100644 --- a/ospfd/ospf_te.h +++ b/ospfd/ospf_te.h @@ -1,8 +1,11 @@ /* - * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * This is an implementation of RFC3630, RFC5392 & RFC6827 * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * + * Copyright (C) 2012 Orange Labs + * http://www.orange.com + * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it @@ -21,6 +24,10 @@ * 02111-1307, USA. */ +/* Add support of RFC7471 */ +/* Add support of RFC5392 */ +/* Add support of RFC6827 (partial) */ + #ifndef _ZEBRA_OSPF_MPLS_TE_H #define _ZEBRA_OSPF_MPLS_TE_H @@ -42,6 +49,7 @@ */ #define MAX_LEGAL_TE_INSTANCE_NUM (0xffff) +#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff) /* * 24 16 8 0 @@ -62,6 +70,31 @@ * +--------+--------+--------+--------+ --- */ +/* Following define the type of TE link regarding the various RFC */ +#define STD_TE 0x01 +#define GMPLS 0x02 +#define INTER_AS 0x04 +#define PSEUDO_TE 0x08 +#define FLOOD_AREA 0x10 +#define FLOOD_AS 0x20 +#define EMULATED 0x80 + +#define IS_STD_TE(x) (x & STD_TE) +#define IS_PSEUDO_TE(x) (x & PSEUDO_TE) +#define IS_INTER_AS(x) (x & INTER_AS) +#define IS_EMULATED(x) (x & EMULATED) +#define IS_FLOOD_AREA(x) (x & FLOOD_AREA) +#define IS_FLOOD_AS(x) (x & FLOOD_AS) +#define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) +#define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) + +/* Flags to manage TE Link LSA */ +#define LPFLG_LSA_INACTIVE 0x0 +#define LPFLG_LSA_ACTIVE 0x1 +#define LPFLG_LSA_ENGAGED 0x2 +#define LPFLG_LOOKUP_DONE 0x4 +#define LPFLG_LSA_FORCED_REFRESH 0x8 + /* * Following section defines TLV (tag, length, value) structures, * used for Traffic Engineering. @@ -87,10 +120,18 @@ struct te_tlv_header #define TLV_HDR_NEXT(tlvh) \ (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) +#define TLV_HDR_SUBTLV(tlvh) \ + (struct te_tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE) + +#define TLV_TYPE(tlvh) tlvh.header.type +#define TLV_LEN(tlvh) tlvh.header.length +#define TLV_HDR(tlvh) tlvh.header + + /* * Following section defines TLV body parts. */ -/* Router Address TLV *//* Mandatory */ +/* Router Address TLV */ /* Mandatory */ #define TE_TLV_ROUTER_ADDR 1 struct te_tlv_router_addr { @@ -106,12 +147,16 @@ struct te_tlv_link /* A set of link-sub-TLVs will follow. */ }; -/* Link Type Sub-TLV *//* Mandatory */ -#define TE_LINK_SUBTLV_LINK_TYPE 1 +#define TE_LINK_SUBTLV_DEF_SIZE 4 + +/* Link Type Sub-TLV */ /* Mandatory */ +#define TE_LINK_SUBTLV_LINK_TYPE 1 +#define TE_LINK_SUBTLV_TYPE_SIZE 1 struct te_link_subtlv_link_type { struct te_tlv_header header; /* Value length is 1 octet. */ - struct { + struct + { #define LINK_TYPE_SUBTLV_VALUE_PTP 1 #define LINK_TYPE_SUBTLV_VALUE_MA 2 u_char value; @@ -119,75 +164,303 @@ struct te_link_subtlv_link_type } link_type; }; -/* Link Sub-TLV: Link ID *//* Mandatory */ -#define TE_LINK_SUBTLV_LINK_ID 2 +/* Link Sub-TLV: Link ID */ /* Mandatory */ +#define TE_LINK_SUBTLV_LINK_ID 2 struct te_link_subtlv_link_id { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Same as router-lsa's link-id. */ }; -/* Link Sub-TLV: Local Interface IP Address *//* Optional */ -#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 +/* Link Sub-TLV: Local Interface IP Address */ /* Optional */ +#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 struct te_link_subtlv_lclif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Local IP address(es). */ }; -/* Link Sub-TLV: Remote Interface IP Address *//* Optional */ -#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 +/* Link Sub-TLV: Remote Interface IP Address */ /* Optional */ +#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 struct te_link_subtlv_rmtif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Neighbor's IP address(es). */ }; -/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ -#define TE_LINK_SUBTLV_TE_METRIC 5 +/* Link Sub-TLV: Traffic Engineering Metric */ /* Optional */ +#define TE_LINK_SUBTLV_TE_METRIC 5 struct te_link_subtlv_te_metric { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Link metric for TE purpose. */ }; -/* Link Sub-TLV: Maximum Bandwidth *//* Optional */ -#define TE_LINK_SUBTLV_MAX_BW 6 +/* Link Sub-TLV: Maximum Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_MAX_BW 6 struct te_link_subtlv_max_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; -/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ -#define TE_LINK_SUBTLV_MAX_RSV_BW 7 +/* Link Sub-TLV: Maximum Reservable Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_MAX_RSV_BW 7 struct te_link_subtlv_max_rsv_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; -/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ -#define TE_LINK_SUBTLV_UNRSV_BW 8 +/* Link Sub-TLV: Unreserved Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_UNRSV_BW 8 +#define TE_LINK_SUBTLV_UNRSV_SIZE 32 struct te_link_subtlv_unrsv_bw { struct te_tlv_header header; /* Value length is 32 octets. */ - float value[8]; /* One for each priority level. */ + float value[MAX_CLASS_TYPE]; /* One for each priority level. */ }; -/* Link Sub-TLV: Resource Class/Color *//* Optional */ -#define TE_LINK_SUBTLV_RSC_CLSCLR 9 +/* Link Sub-TLV: Resource Class/Color */ /* Optional */ +#define TE_LINK_SUBTLV_RSC_CLSCLR 9 struct te_link_subtlv_rsc_clsclr { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Admin. group membership. */ }; -/* Here are "non-official" architechtual constants. */ +/* For RFC6827 */ +/* Local and Remote TE Router ID */ +#define TE_LINK_SUBTLV_LRRID 10 +#define TE_LINK_SUBTLV_LRRID_SIZE 8 +struct te_link_subtlv_lrrid +{ + struct te_tlv_header header; /* Value length is 8 octets. */ + struct in_addr local; /* Local TE Router Identifier */ + struct in_addr remote; /* Remote TE Router Identifier */ +}; + +/* RFC4203: Link Local/Remote Identifiers */ +#define TE_LINK_SUBTLV_LLRI 11 +#define TE_LINK_SUBTLV_LLRI_SIZE 8 +struct te_link_subtlv_llri +{ + struct te_tlv_header header; /* Value length is 8 octets. */ + u_int32_t local; /* Link Local Identifier */ + u_int32_t remote; /* Link Remote Identifier */ +}; + +/* Inter-RA Export Upward sub-TLV (12) and Inter-RA Export Downward sub-TLV (13) (RFC6827bis) are not yet supported */ +/* SUBTLV 14-16 (RFC4203) are not yet supported */ +/* Bandwidth Constraints sub-TLV (17) (RFC4124) is not yet supported */ +/* SUBLV 18-20 are for OSPFv6 TE (RFC5329). see ospf6d */ + +/* For RFC 5392 */ +/* Remote AS Number sub-TLV */ +#define TE_LINK_SUBTLV_RAS 21 +struct te_link_subtlv_ras +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Remote AS number */ +}; + +/* IPv4 Remote ASBR ID Sub-TLV */ +#define TE_LINK_SUBTLV_RIP 22 +struct te_link_subtlv_rip +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Remote ASBR IP address */ +}; + +/* SUBTLV 24 is IPv6 Remote ASBR ID (RFC5392). see ospf6d */ + +/* SUBTLV 23 (RFC5330) and 25 (RFC6001) are not yet supported */ + +/* SUBTLV 26 (RFC7308) is not yet supported */ + +/* RFC7471 */ +/* Link Sub-TLV: Average Link Delay */ /* Optional */ +#define TE_LINK_SUBTLV_AV_DELAY 27 +struct te_link_subtlv_av_delay +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit as Upper most bit */ +}; + +/* Link Sub-TLV: Low/High Link Delay */ +#define TE_LINK_SUBTLV_MM_DELAY 28 +#define TE_LINK_SUBTLV_MM_DELAY_SIZE 8 +struct te_link_subtlv_mm_delay +{ + struct te_tlv_header header; /* Value length is 8 bytes. */ + u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit (A) as Upper most bit */ + u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ +}; + +/* Link Sub-TLV: Link Delay Variation i.e. Jitter */ +#define TE_LINK_SUBTLV_DELAY_VAR 29 +struct te_link_subtlv_delay_var +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ +}; + +/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ +#define TE_LINK_SUBTLV_PKT_LOSS 30 +struct te_link_subtlv_pkt_loss +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2) + with Anomalous Bit as Upper most bit */ +}; + +/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_RES_BW 31 +struct te_link_subtlv_res_bw +{ + struct te_tlv_header header; /* Value length is 4 bytes. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +}; + +/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_AVA_BW 32 +struct te_link_subtlv_ava_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +}; + +/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ +#define TE_LINK_SUBTLV_USE_BW 33 +struct te_link_subtlv_use_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +}; + +#define TE_LINK_SUBTLV_MAX 34 /* Last SUBTLV + 1 */ + +/* Here are "non-official" architectural constants. */ #define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ +/* Following declaration concerns the MPLS-TE and LINk-TE management */ +typedef enum _opcode_t +{ REORIGINATE_THIS_LSA, REFRESH_THIS_LSA, FLUSH_THIS_LSA } opcode_t; + +typedef enum _status_t +{ disabled, enabled } status_t; + +/* Mode for Inter-AS Opaque-LSA */ +enum inter_as_mode { Disable, AS, Area }; + +struct te_link_subtlv +{ + struct te_tlv_header header; + union + { + u_int32_t link_type; + struct in_addr link_id; + struct in_addr lclif; + struct in_addr rmtif; + u_int32_t te_metric; + float max_bw; + float max_rsv_bw; + float unrsv[8]; + u_int32_t rsc_clsclr; + u_int32_t llri[2]; + u_int32_t ras; + struct in_addr rip; + struct in_addr lrrid[2]; + u_int32_t av_delay; + u_int32_t mm_delay; + u_int32_t delay_var; + u_int32_t pkt_loss; + float res_bw; + float ava_bw; + float use_bw; + } value; +}; + +/* Following structure are internal use only. */ +struct ospf_mpls_te +{ + /* Status of MPLS-TE: enable or disbale */ + status_t status; + + /* RFC5392 */ + enum inter_as_mode inter_as; + struct in_addr interas_areaid; + + /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ + struct list *iflist; + + /* Store Router-TLV in network byte order. */ + struct te_tlv_router_addr router_addr; +}; + +struct mpls_te_link +{ + /* + * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field + * is subdivided into 8-bit "unused" field and 16-bit "instance" field. + * In this implementation, each Link-TLV has its own instance. + */ + u_int32_t instance; + + /* Reference pointer to a Zebra-interface. */ + struct interface *ifp; + + /* Area info in which this MPLS-TE link belongs to. */ + struct ospf_area *area; + + /* Flags to manage this link parameters. */ + u_int32_t flags; + + /* Type of MPLS-TE link: RFC3630, RFC5392, RFC5392 emulated, RFC6827 */ + u_int8_t type; + + /* Store Link-TLV in network byte order. */ + /* RFC3630 & RFC6827 / RFC 6827 */ + struct te_tlv_link link_header; + struct te_link_subtlv_link_type link_type; + struct te_link_subtlv_link_id link_id; + struct te_link_subtlv_lclif_ipaddr lclif_ipaddr; + struct te_link_subtlv_rmtif_ipaddr rmtif_ipaddr; + struct te_link_subtlv_te_metric te_metric; + struct te_link_subtlv_max_bw max_bw; + struct te_link_subtlv_max_rsv_bw max_rsv_bw; + struct te_link_subtlv_unrsv_bw unrsv_bw; + struct te_link_subtlv_rsc_clsclr rsc_clsclr; + /* RFC4203 */ + struct te_link_subtlv_llri llri; + /* RFC5392 */ + struct te_link_subtlv_ras ras; + struct te_link_subtlv_rip rip; + /* RFC6827 */ + struct te_link_subtlv_lrrid lrrid; + /* RFC7471 */ + struct te_link_subtlv_av_delay av_delay; + struct te_link_subtlv_mm_delay mm_delay; + struct te_link_subtlv_delay_var delay_var; + struct te_link_subtlv_pkt_loss pkt_loss; + struct te_link_subtlv_res_bw res_bw; + struct te_link_subtlv_ava_bw ava_bw; + struct te_link_subtlv_use_bw use_bw; + + struct in_addr adv_router; + struct in_addr id; +}; + /* Prototypes. */ extern int ospf_mpls_te_init (void); extern void ospf_mpls_te_term (void); +extern struct ospf_mpls_te *get_ospf_mpls_te (void); +extern void ospf_mpls_te_update_if (struct interface *); +extern void ospf_mpls_te_lsa_schedule (struct mpls_te_link *, opcode_t); +extern u_int32_t get_mpls_te_instance_value (void); +extern void set_linkparams_llri (struct mpls_te_link *, u_int32_t, u_int32_t); +extern void set_linkparams_lrrid (struct mpls_te_link *, struct in_addr, struct in_addr); #endif /* _ZEBRA_OSPF_MPLS_TE_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index dec70953a..f0b850530 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -63,7 +63,7 @@ static const char *ospf_network_type_str[] = /* Utility functions. */ -static int +int ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) { char *endptr = NULL; diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h index da0ed1cc1..0602fec4e 100644 --- a/ospfd/ospf_vty.h +++ b/ospfd/ospf_vty.h @@ -53,5 +53,6 @@ /* Prototypes. */ extern void ospf_vty_init (void); extern void ospf_vty_show_init (void); +extern int ospf_str2area_id (const char *, struct in_addr *, int *); #endif /* _QUAGGA_OSPF_VTY_H */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 89404552b..3e359799d 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -48,6 +48,7 @@ #ifdef HAVE_SNMP #include "ospfd/ospf_snmp.h" #endif /* HAVE_SNMP */ +#include "ospfd/ospf_te.h" /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; @@ -326,6 +327,24 @@ ospf_interface_address_delete (int command, struct zclient *zclient, return 0; } +static int +ospf_interface_link_params (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_link_params_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Update TE TLV */ + ospf_mpls_te_update_if (ifp); + + return 0; +} + + void ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) { @@ -1319,6 +1338,8 @@ ospf_zebra_init (struct thread_master *master) zclient->interface_down = ospf_interface_state_down; zclient->interface_address_add = ospf_interface_address_add; zclient->interface_address_delete = ospf_interface_address_delete; + zclient->interface_link_params = ospf_interface_link_params; + zclient->ipv4_route_add = ospf_zebra_read_ipv4; zclient->ipv4_route_delete = ospf_zebra_read_ipv4; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index cc76e9e17..a01af602e 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -255,7 +255,7 @@ ospf_lookup () if (listcount (om->ospf) == 0) return NULL; - return listgetdata (listhead (om->ospf)); + return listgetdata ((struct listnode *)listhead (om->ospf)); } static int diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 098fc5f41..508f623d0 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -59,13 +59,14 @@ #define OSPF_AUTH_CMD_NOTSEEN -2 /* OSPF options. */ -#define OSPF_OPTION_T 0x01 /* TOS. */ +#define OSPF_OPTION_MT 0x01 /* M/T */ #define OSPF_OPTION_E 0x02 #define OSPF_OPTION_MC 0x04 #define OSPF_OPTION_NP 0x08 #define OSPF_OPTION_EA 0x10 #define OSPF_OPTION_DC 0x20 #define OSPF_OPTION_O 0x40 +#define OSPF_OPTION_DN 0x80 /* OSPF Database Description flags. */ #define OSPF_DD_FLAG_MS 0x01 From 4f593574c41deb598cbbefde5c6d938799e81d5a Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 19:03:05 +0200 Subject: [PATCH 1054/1342] isisd: Add support of Traffic Engineering These patches is an implementation of RFC5305 that enable the support of Traffic Engineering in IS-IS * isisd/Makefile.am: Add new files isis_te.c and isis_te.h * isisd/isis_circuit.[c,h]: Add new mpls_te_circuit structure to isis_circuit structure to handle new Traffic Engineering TLVs * isisd/isis_lsp.c: Update LSP handler to mux/demux Traffic Engineering TLVs * isisd/isis_main.c: Add initialisation of ISIS TE * isisd/isis_pdu.c: Update function process_p2p_hello() to retrieve remote IP address to populate Traffic Engineering TLV. * isisd/isis_te.[c,]: Implementation of RFC5305 * isisd/isis_tlv.[c,h]: Update TLV definition and function to handle Traffic Engineering ones * isisd/isis_zebra.c: Add new function isis_zebra_link_params() to retrieve the link parameters of interfaces from ZBus to populate the Traffic Engineering TLVs * isisd/isisd.[c,h]: Add Traffic Engineering support with new debug command Signed-off-by: Olivier Dugeon --- isisd/AUTHORS | 1 + isisd/Makefile.am | 4 +- isisd/isis_circuit.c | 12 +- isisd/isis_circuit.h | 4 +- isisd/isis_lsp.c | 81 +++ isisd/isis_main.c | 3 + isisd/isis_pdu.c | 10 + isisd/isis_te.c | 1372 ++++++++++++++++++++++++++++++++++++++++++ isisd/isis_te.h | 331 ++++++++++ isisd/isis_tlv.c | 36 +- isisd/isis_tlv.h | 20 +- isisd/isis_zebra.c | 26 + isisd/isisd.c | 15 +- isisd/isisd.h | 4 + 14 files changed, 1898 insertions(+), 21 deletions(-) create mode 100644 isisd/isis_te.c create mode 100644 isisd/isis_te.h diff --git a/isisd/AUTHORS b/isisd/AUTHORS index 05fc0a507..80b3a28e1 100644 --- a/isisd/AUTHORS +++ b/isisd/AUTHORS @@ -2,3 +2,4 @@ Sampo Saaristo Ofer Wald Hannes Gredler Subbaiah Venkata +Olivier Dugeon diff --git a/isisd/Makefile.am b/isisd/Makefile.am index 5f866638d..e3ecbc00a 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -16,7 +16,7 @@ libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ - isis_spf.c isis_redist.c isis_route.c isis_routemap.c + isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c noinst_HEADERS = \ @@ -24,7 +24,7 @@ noinst_HEADERS = \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ - isis_route.h isis_routemap.h \ + isis_route.h isis_routemap.h isis_te.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index b49360932..75953ff81 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -36,6 +36,7 @@ #include "linklist.h" #include "command.h" #include "thread.h" +#include "vty.h" #include "hash.h" #include "prefix.h" #include "stream.h" @@ -57,6 +58,7 @@ #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" +#include "isisd/isis_te.h" /* * Prototypes. @@ -98,6 +100,8 @@ isis_circuit_new () circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; } + circuit->mtc = mpls_te_circuit_new(); + return circuit; } @@ -195,8 +199,7 @@ circuit_scan_by_ifp (struct interface *ifp) return circuit_lookup_by_ifp (ifp, isis->init_circ_list); } -static struct isis_circuit * -isis_circuit_lookup (struct vty *vty) +struct isis_circuit * isis_circuit_lookup (struct vty *vty) { struct interface *ifp; struct isis_circuit *circuit; @@ -249,6 +252,10 @@ isis_circuit_add_addr (struct isis_circuit *circuit, ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; listnode_add (circuit->ip_addrs, ipv4); + + /* Update MPLS TE Local IP address parameter */ + set_circuitparams_local_ipaddr (circuit->mtc, ipv4->prefix); + if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); @@ -548,6 +555,7 @@ isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp) assert (ifp->info == circuit); else ifp->info = circuit; + isis_link_params_update (circuit, ifp); } void diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index d88387973..0671d2487 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -108,13 +108,14 @@ struct isis_circuit */ struct isis_passwd passwd; /* Circuit rx/tx password */ int is_type; /* circuit is type == level of circuit - * diffrenciated from circuit type (media) */ + * differentiated from circuit type (media) */ u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */ u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */ u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */ u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */ struct metric metrics[2]; /* l1XxxMetric */ u_int32_t te_metric[2]; + struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */ int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ struct list *ip_addrs; /* our IP addresses */ @@ -143,6 +144,7 @@ void isis_circuit_del (struct isis_circuit *circuit); struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp, struct list *list); struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp); +struct isis_circuit * isis_circuit_lookup (struct vty *vty); void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area); void isis_circuit_deconfigure (struct isis_circuit *circuit, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 4665490be..9032de4f4 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -52,6 +52,7 @@ #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" +#include "isisd/isis_te.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" @@ -983,6 +984,8 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); vty_out (vty, " Metric : %-8d IS-Extended : %s%s", GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE); + if (IS_MPLS_TE(isisMplsTE)) + mpls_te_print_detail(vty, te_is_neigh); } /* TE IPv4 tlv */ @@ -1093,6 +1096,64 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, return; } +/* Process IS_NEIGHBOURS TLV with TE subTLVs */ +static void +lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold) +{ + int count, size = 0; + struct listnode *node, *nextnode; + struct te_is_neigh *elem; + + /* Start computing real size of TLVs */ + for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) + size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN; + + /* can we fit all ? */ + if (!FRAG_NEEDED (lsp->pdu, frag_thold, size)) + { + tlv_add_te_is_neighs (*from, lsp->pdu); + if (listcount (*to) != 0) + { + for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) + { + listnode_add (*to, elem); + list_delete_node (*from, node); + } + } + else + { + list_free (*to); + *to = *from; + *from = NULL; + } + } + else + { + /* fit all we can */ + /* Compute remaining place in LSP PDU */ + count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - + (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); + /* Determine size of TE SubTLVs */ + elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); + count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; + if (count > 0) + { + while (count > 0) + { + listnode_add (*to, listgetdata ((struct listnode *)listhead (*from))); + listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from))); + + elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); + count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; + } + + tlv_add_te_is_neighs (*to, lsp->pdu); + } + } + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); + return; +} + static u_int16_t lsp_rem_lifetime (struct isis_area *area, int level) { @@ -1627,6 +1688,14 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } else { + /* Check if MPLS_TE is activate */ + if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface)) + /* Add SubTLVs & Adjust real size of SubTLVs */ + te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc); + else + /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ + te_is_neigh->sub_tlvs_length = 0; + listnode_add (tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor", area->area_tag, sysid_print(te_is_neigh->neigh_id), @@ -1672,6 +1741,18 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); + /* Check if MPLS_TE is activate */ + if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface)) + /* Update Local and Remote IP address for MPLS TE circuit parameters */ + /* NOTE sure that it is the pertinent place for that updates */ + /* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */ + /* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */ + + /* Add SubTLVs & Adjust real size of SubTLVs */ + te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc); + else + /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ + te_is_neigh->sub_tlvs_length = 0; listnode_add (tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag, sysid_print(te_is_neigh->neigh_id)); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 3a7308795..1dda43bcc 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -50,6 +50,8 @@ #include "isisd/isis_route.h" #include "isisd/isis_routemap.h" #include "isisd/isis_zebra.h" +#include "isisd/isis_tlv.h" +#include "isisd/isis_te.h" /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" @@ -340,6 +342,7 @@ main (int argc, char **argv, char **envp) isis_spf_cmds_init (); isis_redist_init (); isis_route_map_init(); + isis_mpls_te_init(); /* create the global 'isis' instance */ isis_new (1); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 0401e44a9..1dfb4623f 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -53,6 +53,7 @@ #include "isisd/iso_checksum.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" +#include "isisd/isis_te.h" #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ @@ -630,6 +631,15 @@ process_p2p_hello (struct isis_circuit *circuit) if (found & TLVFLAG_IPV4_ADDR) tlvs_to_adj_ipv4_addrs (&tlvs, adj); + /* Update MPLS TE Remote IP address parameter if possible */ + if (IS_MPLS_TE(isisMplsTE) && circuit->mtc && IS_CIRCUIT_TE(circuit->mtc)) + if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) + { + struct in_addr *ip_addr; + ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); + set_circuitparams_rmt_ipaddr (circuit->mtc, *ip_addr); + } + #ifdef HAVE_IPV6 if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); diff --git a/isisd/isis_te.c b/isisd/isis_te.c new file mode 100644 index 000000000..814a8e858 --- /dev/null +++ b/isisd/isis_te.c @@ -0,0 +1,1372 @@ +/* + * IS-IS Rout(e)ing protocol - isis_te.c + * + * This is an implementation of RFC5305 + * + * Copyright (C) 2014 Orange Labs + * http://www.orange.com + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include + +#include "linklist.h" +#include "thread.h" +#include "vty.h" +#include "stream.h" +#include "memory.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "hash.h" +#include "if.h" +#include "checksum.h" +#include "md5.h" +#include "sockunion.h" +#include "network.h" + +#include "isisd/dict.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_flags.h" +#include "isisd/isis_circuit.h" +#include "isisd/isisd.h" +#include "isisd/isis_tlv.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_pdu.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_te.h" + +/* Global varial for MPLS TE management */ +struct isis_mpls_te isisMplsTE; + +const char *mode2text[] = { "Disable", "Area", "AS", "Emulate" }; + +/*------------------------------------------------------------------------* + * Followings are control functions for MPLS-TE parameters management. + *------------------------------------------------------------------------*/ + +/* Search MPLS TE Circuit context from Interface */ +static struct mpls_te_circuit * +lookup_mpls_params_by_ifp (struct interface *ifp) +{ + struct isis_circuit *circuit; + + if ((circuit = circuit_scan_by_ifp (ifp)) == NULL) + return NULL; + + return circuit->mtc; +} + +/* Create new MPLS TE Circuit context */ +struct mpls_te_circuit * +mpls_te_circuit_new() +{ + struct mpls_te_circuit *mtc; + + zlog_debug ("ISIS MPLS-TE: Create new MPLS TE Circuit context"); + + mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof (struct mpls_te_circuit)); + + if (mtc == NULL) + return NULL; + + mtc->status = disable; + mtc->type = STD_TE; + mtc->length = 0; + + return mtc; + +} + +/* Copy SUB TLVs parameters into a buffer - No space verification are performed */ +/* Caller must verify before that there is enough free space in the buffer */ +u_char +add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc) +{ + u_char size, *tlvs = buf; + + zlog_debug ("ISIS MPLS-TE: Add TE Sub TLVs to buffer"); + + if (mtc == NULL) + { + zlog_debug("ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified"); + return 0; + } + + /* Create buffer if not provided */ + if (buf == NULL) + { + zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified"); + return 0; + } + + /* TE_SUBTLV_ADMIN_GRP */ + if (SUBTLV_TYPE(mtc->admin_grp) != 0) + { + size = SUBTLV_SIZE (&(mtc->admin_grp.header)); + memcpy(tlvs, &(mtc->admin_grp), size); + tlvs += size; + } + + /* TE_SUBTLV_LLRI */ + if (SUBTLV_TYPE(mtc->llri) != 0) + { + size = SUBTLV_SIZE (&(mtc->llri.header)); + memcpy(tlvs, &(mtc->llri), size); + tlvs += size; + } + + /* TE_SUBTLV_LCLIF_IPADDR */ + if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) + { + size = SUBTLV_SIZE (&(mtc->local_ipaddr.header)); + memcpy(tlvs, &(mtc->local_ipaddr), size); + tlvs += size; + } + + /* TE_SUBTLV_RMTIF_IPADDR */ + if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) + { + size = SUBTLV_SIZE (&(mtc->rmt_ipaddr.header)); + memcpy(tlvs, &(mtc->rmt_ipaddr), size); + tlvs += size; + } + + /* TE_SUBTLV_MAX_BW */ + if (SUBTLV_TYPE(mtc->max_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->max_bw.header)); + memcpy(tlvs, &(mtc->max_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_MAX_RSV_BW */ + if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->max_rsv_bw.header)); + memcpy(tlvs, &(mtc->max_rsv_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_UNRSV_BW */ + if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->unrsv_bw.header)); + memcpy(tlvs, &(mtc->unrsv_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_TE_METRIC */ + if (SUBTLV_TYPE(mtc->te_metric) != 0) + { + size = SUBTLV_SIZE (&(mtc->te_metric.header)); + memcpy(tlvs, &(mtc->te_metric), size); + tlvs += size; + } + + /* TE_SUBTLV_AV_DELAY */ + if (SUBTLV_TYPE(mtc->av_delay) != 0) + { + size = SUBTLV_SIZE (&(mtc->av_delay.header)); + memcpy(tlvs, &(mtc->av_delay), size); + tlvs += size; + } + + /* TE_SUBTLV_MM_DELAY */ + if (SUBTLV_TYPE(mtc->mm_delay) != 0) + { + size = SUBTLV_SIZE (&(mtc->mm_delay.header)); + memcpy(tlvs, &(mtc->mm_delay), size); + tlvs += size; + } + + /* TE_SUBTLV_DELAY_VAR */ + if (SUBTLV_TYPE(mtc->delay_var) != 0) + { + size = SUBTLV_SIZE (&(mtc->delay_var.header)); + memcpy(tlvs, &(mtc->delay_var), size); + tlvs += size; + } + + /* TE_SUBTLV_PKT_LOSS */ + if (SUBTLV_TYPE(mtc->pkt_loss) != 0) + { + size = SUBTLV_SIZE (&(mtc->pkt_loss.header)); + memcpy(tlvs, &(mtc->pkt_loss), size); + tlvs += size; + } + + /* TE_SUBTLV_RES_BW */ + if (SUBTLV_TYPE(mtc->res_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->res_bw.header)); + memcpy(tlvs, &(mtc->res_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_AVA_BW */ + if (SUBTLV_TYPE(mtc->ava_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->ava_bw.header)); + memcpy(tlvs, &(mtc->ava_bw), size); + tlvs += size; + } + + /* TE_SUBTLV_USE_BW */ + if (SUBTLV_TYPE(mtc->use_bw) != 0) + { + size = SUBTLV_SIZE (&(mtc->use_bw.header)); + memcpy(tlvs, &(mtc->use_bw), size); + tlvs += size; + } + + /* Update SubTLVs length */ + mtc->length = subtlvs_len(mtc); + + zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length); + + return mtc->length; +} + +/* Compute total Sub-TLVs size */ +u_char +subtlvs_len (struct mpls_te_circuit *mtc) +{ + int length = 0; + + /* Sanity Check */ + if (mtc == NULL) + return 0; + + /* TE_SUBTLV_ADMIN_GRP */ + if (SUBTLV_TYPE(mtc->admin_grp) != 0) + length += SUBTLV_SIZE (&(mtc->admin_grp.header)); + + /* TE_SUBTLV_LLRI */ + if (SUBTLV_TYPE(mtc->llri) != 0) + length += SUBTLV_SIZE (&mtc->llri.header); + + /* TE_SUBTLV_LCLIF_IPADDR */ + if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) + length += SUBTLV_SIZE (&mtc->local_ipaddr.header); + + /* TE_SUBTLV_RMTIF_IPADDR */ + if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) + length += SUBTLV_SIZE (&mtc->rmt_ipaddr.header); + + /* TE_SUBTLV_MAX_BW */ + if (SUBTLV_TYPE(mtc->max_bw) != 0) + length += SUBTLV_SIZE (&mtc->max_bw.header); + + /* TE_SUBTLV_MAX_RSV_BW */ + if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) + length += SUBTLV_SIZE (&mtc->max_rsv_bw.header); + + /* TE_SUBTLV_UNRSV_BW */ + if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) + length += SUBTLV_SIZE (&mtc->unrsv_bw.header); + + /* TE_SUBTLV_TE_METRIC */ + if (SUBTLV_TYPE(mtc->te_metric) != 0) + length += SUBTLV_SIZE (&mtc->te_metric.header); + + /* TE_SUBTLV_AV_DELAY */ + if (SUBTLV_TYPE(mtc->av_delay) != 0) + length += SUBTLV_SIZE (&mtc->av_delay.header); + + /* TE_SUBTLV_MM_DELAY */ + if (SUBTLV_TYPE(mtc->mm_delay) != 0) + length += SUBTLV_SIZE (&mtc->mm_delay.header); + + /* TE_SUBTLV_DELAY_VAR */ + if (SUBTLV_TYPE(mtc->delay_var) != 0) + length += SUBTLV_SIZE (&mtc->delay_var.header); + + /* TE_SUBTLV_PKT_LOSS */ + if (SUBTLV_TYPE(mtc->pkt_loss) != 0) + length += SUBTLV_SIZE (&mtc->pkt_loss.header); + + /* TE_SUBTLV_RES_BW */ + if (SUBTLV_TYPE(mtc->res_bw) != 0) + length += SUBTLV_SIZE (&mtc->res_bw.header); + + /* TE_SUBTLV_AVA_BW */ + if (SUBTLV_TYPE(mtc->ava_bw) != 0) + length += SUBTLV_SIZE (&mtc->ava_bw.header); + + /* TE_SUBTLV_USE_BW */ + if (SUBTLV_TYPE(mtc->use_bw) != 0) + length += SUBTLV_SIZE (&mtc->use_bw.header); + + /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */ + if (length > MAX_SUBTLV_SIZE) + { + mtc->length = 0; + return 0; + } + + mtc->length = (u_char)length; + + return mtc->length; +} + +/* Following are various functions to set MPLS TE parameters */ +static void +set_circuitparams_admin_grp (struct mpls_te_circuit *mtc, u_int32_t admingrp) +{ + SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP; + SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE; + mtc->admin_grp.value = htonl(admingrp); + return; +} + +static void __attribute__ ((unused)) +set_circuitparams_llri (struct mpls_te_circuit *mtc, u_int32_t local, u_int32_t remote) +{ + SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI; + SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE; + mtc->llri.local = htonl(local); + mtc->llri.remote = htonl(remote); +} + +void +set_circuitparams_local_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr) +{ + + SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR; + SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE; + mtc->local_ipaddr.value.s_addr = addr.s_addr; + return; +} + +void +set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr) +{ + + SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR; + SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE; + mtc->rmt_ipaddr.value.s_addr = addr.s_addr; + return; +} + +static void +set_circuitparams_max_bw (struct mpls_te_circuit *mtc, float fp) +{ + SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW; + SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE; + mtc->max_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_max_rsv_bw (struct mpls_te_circuit *mtc, float fp) +{ + SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW; + SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE; + mtc->max_rsv_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_unrsv_bw (struct mpls_te_circuit *mtc, int priority, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW; + SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE; + mtc->unrsv_bw.value[priority] = htonf(fp); + return; +} + +static void +set_circuitparams_te_metric (struct mpls_te_circuit *mtc, u_int32_t te_metric) +{ + SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC; + SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE; + mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF; + mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF; + mtc->te_metric.value[2] = te_metric & 0xFF; + return; +} + +static void +set_circuitparams_inter_as (struct mpls_te_circuit *mtc, struct in_addr addr, u_int32_t as) +{ + + /* Set the Remote ASBR IP address and then the associated AS number */ + SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP; + SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE; + mtc->rip.value.s_addr = addr.s_addr; + + SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS; + SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE; + mtc->ras.value = htonl(as); +} + +static void +unset_circuitparams_inter_as (struct mpls_te_circuit *mtc) +{ + + /* Reset the Remote ASBR IP address and then the associated AS number */ + SUBTLV_TYPE(mtc->rip) = 0; + SUBTLV_LEN(mtc->rip) = 0; + mtc->rip.value.s_addr = 0; + + SUBTLV_TYPE(mtc->ras) = 0; + SUBTLV_LEN(mtc->ras) = 0; + mtc->ras.value = 0; +} + +static void +set_circuitparams_av_delay (struct mpls_te_circuit *mtc, u_int32_t delay, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY; + SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE; + tmp = delay & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + mtc->av_delay.value = htonl(tmp); + return; +} + +static void +set_circuitparams_mm_delay (struct mpls_te_circuit *mtc, u_int32_t low, u_int32_t high, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY; + SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE; + tmp = low & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + mtc->mm_delay.low = htonl(tmp); + mtc->mm_delay.high = htonl(high); + return; +} + +static void +set_circuitparams_delay_var (struct mpls_te_circuit *mtc, u_int32_t jitter) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR; + SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE; + mtc->delay_var.value = htonl(jitter & TE_EXT_MASK); + return; +} + +static void +set_circuitparams_pkt_loss (struct mpls_te_circuit *mtc, u_int32_t loss, u_char anormal) +{ + u_int32_t tmp; + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS; + SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE; + tmp = loss & TE_EXT_MASK; + if (anormal) + tmp |= TE_EXT_ANORMAL; + mtc->pkt_loss.value = htonl(tmp); + return; +} + +static void +set_circuitparams_res_bw (struct mpls_te_circuit *mtc, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW; + SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE; + mtc->res_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_ava_bw (struct mpls_te_circuit *mtc, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW; + SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE; + mtc->ava_bw.value = htonf(fp); + return; +} + +static void +set_circuitparams_use_bw (struct mpls_te_circuit *mtc, float fp) +{ + /* Note that TLV-length field is the size of array. */ + SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW; + SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE; + mtc->use_bw.value = htonf(fp); + return; +} + +/* Main initialization / update function of the MPLS TE Circuit context */ +/* Call when interface TE Link parameters are modified */ +void +isis_link_params_update (struct isis_circuit *circuit, struct interface *ifp) +{ + int i; + struct prefix_ipv4 *addr; + struct mpls_te_circuit *mtc; + + /* Sanity Check */ + if ((circuit == NULL) || (ifp == NULL)) + return; + + zlog_info ("MPLS-TE: Initialize circuit parameters for interface %s", ifp->name); + + /* Check if MPLS TE Circuit context has not been already created */ + if (circuit->mtc == NULL) + circuit->mtc = mpls_te_circuit_new(); + + mtc = circuit->mtc; + + /* Fulfil MTC TLV from ifp TE Link parameters */ + if (HAS_LINK_PARAMS(ifp)) + { + mtc->status = enable; + /* STD_TE metrics */ + if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) + set_circuitparams_admin_grp (mtc, ifp->link_params->admin_grp); + else + SUBTLV_TYPE(mtc->admin_grp) = 0; + + /* If not already set, register local IP addr from ip_addr list if it exists */ + if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) + { + if (circuit->ip_addrs != NULL && listcount(circuit->ip_addrs) != 0) + { + addr = (struct prefix_ipv4 *)listgetdata ((struct listnode *)listhead (circuit->ip_addrs)); + set_circuitparams_local_ipaddr (mtc, addr->prefix); + } + } + + /* If not already set, try to determine Remote IP addr if circuit is P2P */ + if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P)) + { + struct isis_adjacency *adj = circuit->u.p2p.neighbor; + if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) + { + struct in_addr *ip_addr; + ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); + set_circuitparams_rmt_ipaddr (mtc, *ip_addr); + } + } + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) + set_circuitparams_max_bw (mtc, ifp->link_params->max_bw); + else + SUBTLV_TYPE(mtc->max_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) + set_circuitparams_max_rsv_bw (mtc, ifp->link_params->max_rsv_bw); + else + SUBTLV_TYPE(mtc->max_rsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) + for (i = 0; i < MAX_CLASS_TYPE; i++) + set_circuitparams_unrsv_bw (mtc, i, ifp->link_params->unrsv_bw[i]); + else + SUBTLV_TYPE(mtc->unrsv_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_TE)) + set_circuitparams_te_metric(mtc, ifp->link_params->te_metric); + else + SUBTLV_TYPE(mtc->te_metric) = 0; + + /* TE metric Extensions */ + if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) + set_circuitparams_av_delay(mtc, ifp->link_params->av_delay, 0); + else + SUBTLV_TYPE(mtc->av_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) + set_circuitparams_mm_delay(mtc, ifp->link_params->min_delay, ifp->link_params->max_delay, 0); + else + SUBTLV_TYPE(mtc->mm_delay) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) + set_circuitparams_delay_var(mtc, ifp->link_params->delay_var); + else + SUBTLV_TYPE(mtc->delay_var) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) + set_circuitparams_pkt_loss(mtc, ifp->link_params->pkt_loss, 0); + else + SUBTLV_TYPE(mtc->pkt_loss) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) + set_circuitparams_res_bw(mtc, ifp->link_params->res_bw); + else + SUBTLV_TYPE(mtc->res_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) + set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw); + else + SUBTLV_TYPE(mtc->ava_bw) = 0; + + if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) + set_circuitparams_use_bw(mtc, ifp->link_params->use_bw); + else + SUBTLV_TYPE(mtc->use_bw) = 0; + + /* INTER_AS */ + if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) + set_circuitparams_inter_as(mtc, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); + else + /* reset inter-as TE params */ + unset_circuitparams_inter_as (mtc); + + /* Compute total length of SUB TLVs */ + mtc->length = subtlvs_len(mtc); + + } + else + mtc->status = disable; + + /* Finally Update LSP */ +#if 0 + if (IS_MPLS_TE(isisMplsTE) && circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); +#endif + return; +} + +void +isis_mpls_te_update (struct interface *ifp) +{ + struct isis_circuit *circuit; + + /* Sanity Check */ + if (ifp == NULL) + return; + + /* Get circuit context from interface */ + if ((circuit = circuit_scan_by_ifp(ifp)) == NULL) + return; + + /* Update TE TLVs ... */ + isis_link_params_update(circuit, ifp); + + /* ... and LSP */ + if (IS_MPLS_TE(isisMplsTE) && circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty session control functions. + *------------------------------------------------------------------------*/ + +static u_char +show_vty_subtlv_admin_grp (struct vty *vty, struct te_subtlv_admin_grp *tlv) +{ + + if (vty != NULL) + vty_out (vty, " Administrative Group: 0x%x%s", + (u_int32_t) ntohl (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Administrative Group: 0x%x", + (u_int32_t) ntohl (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_llri (struct vty *vty, struct te_subtlv_llri *tlv) +{ + if (vty != NULL) + { + vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (tlv->local), + VTY_NEWLINE); + vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (tlv->remote), + VTY_NEWLINE); + } + else + { + zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (tlv->local)); + zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (tlv->remote)); + } + + return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE); +} + +static u_char +show_vty_subtlv_local_ipaddr (struct vty *vty, struct te_subtlv_local_ipaddr *tlv) +{ + if (vty != NULL) + vty_out (vty, " Local Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Local Interface IP Address(es): %s", inet_ntoa (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_rmt_ipaddr (struct vty *vty, struct te_subtlv_rmt_ipaddr *tlv) +{ + if (vty != NULL) + vty_out (vty, " Remote Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Remote Interface IP Address(es): %s", inet_ntoa (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_max_bw (struct vty *vty, struct te_subtlv_max_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Maximum Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_max_rsv_bw (struct vty *vty, struct te_subtlv_max_rsv_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, + VTY_NEWLINE); + else + zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_unrsv_bw (struct vty *vty, struct te_subtlv_unrsv_bw *tlv) +{ + float fval1, fval2; + int i; + + if (vty != NULL) + vty_out (vty, " Unreserved Bandwidth:%s",VTY_NEWLINE); + else + zlog_debug (" Unreserved Bandwidth:"); + + for (i = 0; i < MAX_CLASS_TYPE; i+=2) + { + fval1 = ntohf (tlv->value[i]); + fval2 = ntohf (tlv->value[i+1]); + if (vty != NULL) + vty_out (vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", i, fval1, i+1, fval2, VTY_NEWLINE); + else + zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", i, fval1, i+1, fval2); + } + + return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE); +} + +static u_char +show_vty_subtlv_te_metric (struct vty *vty, struct te_subtlv_te_metric *tlv) +{ + u_int32_t te_metric; + + te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16; + if (vty != NULL) + vty_out (vty, " Traffic Engineering Metric: %u%s", te_metric, VTY_NEWLINE); + else + zlog_debug (" Traffic Engineering Metric: %u", te_metric); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_ras (struct vty *vty, struct te_subtlv_ras *tlv) +{ + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_rip (struct vty *vty, struct te_subtlv_rip *tlv) +{ + if (vty != NULL) + vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); + else + zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", inet_ntoa (tlv->value)); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_av_delay (struct vty *vty, struct te_subtlv_av_delay *tlv) +{ + u_int32_t delay; + u_int32_t A; + + delay = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; + A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", A ? "Anomalous" : "Normal", delay, VTY_NEWLINE); + else + zlog_debug (" %s Average Link Delay: %d (micro-sec)", A ? "Anomalous" : "Normal", delay); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_mm_delay (struct vty *vty, struct te_subtlv_mm_delay *tlv) +{ + u_int32_t low, high; + u_int32_t A; + + low = (u_int32_t) ntohl (tlv->low) & TE_EXT_MASK; + A = (u_int32_t) ntohl (tlv->low) & TE_EXT_ANORMAL; + high = (u_int32_t) ntohl (tlv->high) & TE_EXT_MASK; + + if (vty != NULL) + vty_out (vty, " %s Min/Max Link Delay: %d / %d (micro-sec)%s", A ? "Anomalous" : "Normal", low, high, VTY_NEWLINE); + else + zlog_debug (" %s Min/Max Link Delay: %d / %d (micro-sec)", A ? "Anomalous" : "Normal", low, high); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_delay_var (struct vty *vty, struct te_subtlv_delay_var *tlv) +{ + u_int32_t jitter; + + jitter = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; + + if (vty != NULL) + vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE); + else + zlog_debug (" Delay Variation: %d (micro-sec)", jitter); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_pkt_loss (struct vty *vty, struct te_subtlv_pkt_loss *tlv) +{ + u_int32_t loss; + u_int32_t A; + float fval; + + loss = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; + fval = (float) (loss * LOSS_PRECISION); + A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL; + + if (vty != NULL) + vty_out (vty, " %s Link Packet Loss: %g (%%)%s", A ? "Anomalous" : "Normal", fval, VTY_NEWLINE); + else + zlog_debug (" %s Link Packet Loss: %g (%%)", A ? "Anomalous" : "Normal", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_res_bw (struct vty *vty, struct te_subtlv_res_bw *tlv) +{ + float fval; + + fval = ntohf(tlv->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_ava_bw (struct vty *vty, struct te_subtlv_ava_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_subtlv_use_bw (struct vty *vty, struct te_subtlv_use_bw *tlv) +{ + float fval; + + fval = ntohf (tlv->value); + + if (vty != NULL) + vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", fval); + + return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); +} + +static u_char +show_vty_unknown_tlv (struct vty *vty, struct subtlv_header *tlvh) +{ + int i, rtn = 1; + u_char *v = (u_char *)tlvh; + + if (vty != NULL) + { + if (tlvh->length != 0) + { + vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s", + tlvh->type, tlvh->length, VTY_NEWLINE); + vty_out(vty, " Dump: [00]"); + rtn = 1; /* initialize end of line counter */ + for (i = 0; i < tlvh->length; i++) + { + vty_out (vty, " %#.2x", v[i]); + if (rtn == 8) + { + vty_out (vty, "%s [%.2x]", VTY_NEWLINE, i + 1); + rtn = 1; + } + else + rtn++; + } + vty_out (vty, "%s", VTY_NEWLINE); + } + else + vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s", + tlvh->type, tlvh->length, VTY_NEWLINE); + } + else + { + zlog_debug (" Unknown TLV: [type(%#.2x), length(%#.2x)]", + tlvh->type, tlvh->length); + } + + return SUBTLV_SIZE(tlvh); +} + +/* Main Show function */ +void +mpls_te_print_detail(struct vty *vty, struct te_is_neigh *te) +{ + struct subtlv_header *tlvh, *next; + u_int16_t sum = 0; + + zlog_debug ("ISIS MPLS-TE: Show database TE detail"); + + if (te->sub_tlvs == NULL) + return; + + tlvh = (struct subtlv_header *)te->sub_tlvs; + + for (; sum < te->sub_tlvs_length; tlvh = (next ? next : SUBTLV_HDR_NEXT (tlvh))) + { + next = NULL; + + switch (tlvh->type) + { + case TE_SUBTLV_ADMIN_GRP: + sum += show_vty_subtlv_admin_grp (vty, (struct te_subtlv_admin_grp *)tlvh); + break; + case TE_SUBTLV_LLRI: + sum += show_vty_subtlv_llri (vty, (struct te_subtlv_llri *)tlvh); + break; + case TE_SUBTLV_LOCAL_IPADDR: + sum += show_vty_subtlv_local_ipaddr (vty, (struct te_subtlv_local_ipaddr *)tlvh); + break; + case TE_SUBTLV_RMT_IPADDR: + sum += show_vty_subtlv_rmt_ipaddr (vty, (struct te_subtlv_rmt_ipaddr *)tlvh); + break; + case TE_SUBTLV_MAX_BW: + sum += show_vty_subtlv_max_bw (vty, (struct te_subtlv_max_bw *)tlvh); + break; + case TE_SUBTLV_MAX_RSV_BW: + sum += show_vty_subtlv_max_rsv_bw (vty, (struct te_subtlv_max_rsv_bw *)tlvh); + break; + case TE_SUBTLV_UNRSV_BW: + sum += show_vty_subtlv_unrsv_bw (vty, (struct te_subtlv_unrsv_bw *)tlvh); + break; + case TE_SUBTLV_TE_METRIC: + sum += show_vty_subtlv_te_metric (vty, (struct te_subtlv_te_metric *)tlvh); + break; + case TE_SUBTLV_RAS: + sum += show_vty_subtlv_ras (vty, (struct te_subtlv_ras *)tlvh); + break; + case TE_SUBTLV_RIP: + sum += show_vty_subtlv_rip (vty, (struct te_subtlv_rip *)tlvh); + break; + case TE_SUBTLV_AV_DELAY: + sum += show_vty_subtlv_av_delay (vty, (struct te_subtlv_av_delay *)tlvh); + break; + case TE_SUBTLV_MM_DELAY: + sum += show_vty_subtlv_mm_delay (vty, (struct te_subtlv_mm_delay *)tlvh); + break; + case TE_SUBTLV_DELAY_VAR: + sum += show_vty_subtlv_delay_var (vty, (struct te_subtlv_delay_var *)tlvh); + break; + case TE_SUBTLV_PKT_LOSS: + sum += show_vty_subtlv_pkt_loss (vty, (struct te_subtlv_pkt_loss *)tlvh); + break; + case TE_SUBTLV_RES_BW: + sum += show_vty_subtlv_res_bw (vty, (struct te_subtlv_res_bw *)tlvh); + break; + case TE_SUBTLV_AVA_BW: + sum += show_vty_subtlv_ava_bw (vty, (struct te_subtlv_ava_bw *)tlvh); + break; + case TE_SUBTLV_USE_BW: + sum += show_vty_subtlv_use_bw (vty, (struct te_subtlv_use_bw *)tlvh); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return; +} + +/* Specific MPLS TE router parameters write function */ +void +isis_mpls_te_config_write_router (struct vty *vty) +{ + + zlog_debug ("ISIS MPLS-TE: Write ISIS router configuration"); + + if (IS_MPLS_TE(isisMplsTE)) + { + vty_out (vty, " mpls-te on%s", VTY_NEWLINE); + vty_out (vty, " mpls-te router-address %s%s", + inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE); + } + + return; +} + + +/*------------------------------------------------------------------------* + * Followings are vty command functions. + *------------------------------------------------------------------------*/ + +DEFUN (isis_mpls_te_on, + isis_mpls_te_on_cmd, + "mpls-te on", + MPLS_TE_STR + "Enable MPLS-TE functionality\n") +{ + struct listnode *node; + struct isis_circuit *circuit; + + if (IS_MPLS_TE(isisMplsTE)) + return CMD_SUCCESS; + + if (IS_DEBUG_ISIS(DEBUG_TE)) + zlog_debug ("ISIS MPLS-TE: OFF -> ON"); + + isisMplsTE.status = enable; + + /* + * Following code is intended to handle two cases; + * + * 1) MPLS-TE was disabled at startup time, but now become enabled. + * In this case, we must enable MPLS-TE Circuit regarding interface MPLS_TE flag + * 2) MPLS-TE was once enabled then disabled, and now enabled again. + */ + for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit)) + { + if (circuit->mtc == NULL || IS_FLOOD_AS (circuit->mtc->type)) + continue; + + if ((circuit->mtc->status == disable) + && HAS_LINK_PARAMS(circuit->interface)) + circuit->mtc->status = enable; + else + continue; + + /* Reoriginate STD_TE & GMPLS circuits */ + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_mpls_te_on, + no_isis_mpls_te_on_cmd, + "no mpls-te", + NO_STR + "Disable the MPLS-TE functionality\n") +{ + struct listnode *node; + struct isis_circuit *circuit; + + if (isisMplsTE.status == disable) + return CMD_SUCCESS; + + if (IS_DEBUG_ISIS(DEBUG_TE)) + zlog_debug ("ISIS MPLS-TE: ON -> OFF"); + + isisMplsTE.status = disable; + + /* Flush LSP if circuit engage */ + for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit)) + { + if (circuit->mtc == NULL || (circuit->mtc->status == disable)) + continue; + + /* disable MPLS_TE Circuit */ + circuit->mtc->status = disable; + + /* Re-originate circuit without STD_TE & GMPLS parameters */ + if (circuit->area) + lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (isis_mpls_te_router_addr, + isis_mpls_te_router_addr_cmd, + "mpls-te router-address A.B.C.D", + MPLS_TE_STR + "Stable IP address of the advertising router\n" + "MPLS-TE router address in IPv4 address format\n") +{ + struct in_addr value; + struct listnode *node; + struct isis_area *area; + + if (! inet_aton (argv[0], &value)) + { + vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + isisMplsTE.router_id.s_addr = value.s_addr; + + if (isisMplsTE.status == disable) + return CMD_SUCCESS; + + /* Update main Router ID in isis global structure */ + isis->router_id = value.s_addr; + /* And re-schedule LSP update */ + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) + if (listcount (area->area_addrs) > 0) + lsp_regenerate_schedule (area, area->is_type, 0); + + return CMD_SUCCESS; +} + +DEFUN (isis_mpls_te_inter_as, + isis_mpls_te_inter_as_cmd, + "mpls-te inter-as (level-1|level-1-2|level-2-only)", + MPLS_TE_STR + "Configure MPLS-TE Inter-AS support\n" + "AREA native mode self originate INTER-AS LSP with L1 only flooding scope)\n" + "AREA native mode self originate INTER-AS LSP with L1 and L2 flooding scope)\n" + "AS native mode self originate INTER-AS LSP with L2 only flooding scope\n") +{ + vty_out (vty, "Not yet supported%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (no_isis_mpls_te_inter_as, + no_isis_mpls_te_inter_as_cmd, + "no mpls-te inter-as", + NO_STR + "Disable the MPLS-TE functionality\n" + "Disable MPLS-TE Inter-AS support\n") +{ + + vty_out (vty, "Not yet supported%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (show_isis_mpls_te_router, + show_isis_mpls_te_router_cmd, + "show isis mpls-te router", + SHOW_STR + ISIS_STR + MPLS_TE_STR + "Router information\n") +{ + if (IS_MPLS_TE(isisMplsTE)) + { + vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); + + if (vty != NULL) + { + if (ntohs (isisMplsTE.router_id.s_addr) != 0) + vty_out (vty, " Router-Address: %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE); + else + vty_out (vty, " N/A%s", VTY_NEWLINE); + } + } + else + vty_out (vty, " MPLS-TE is disable on this router%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +static void +show_mpls_te_sub (struct vty *vty, struct interface *ifp) +{ + struct mpls_te_circuit *mtc; + + if ((IS_MPLS_TE(isisMplsTE)) + && ((mtc = lookup_mpls_params_by_ifp (ifp)) != NULL)) + { + /* Continue only if interface is not passive or support Inter-AS TEv2 */ + if (mtc->status != enable) + { + if (IS_INTER_AS(mtc->type)) + { + vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + } + else + { + /* MPLS-TE is not activate on this interface */ + /* or this interface is passive and Inter-AS TEv2 is not activate */ + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + return; + } + } + else + { + vty_out (vty, "-- MPLS-TE link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + } + + show_vty_subtlv_admin_grp (vty, &mtc->admin_grp); + + if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) + show_vty_subtlv_local_ipaddr (vty, &mtc->local_ipaddr); + if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) + show_vty_subtlv_rmt_ipaddr (vty, &mtc->rmt_ipaddr); + + show_vty_subtlv_max_bw (vty, &mtc->max_bw); + show_vty_subtlv_max_rsv_bw (vty, &mtc->max_rsv_bw); + show_vty_subtlv_unrsv_bw (vty, &mtc->unrsv_bw); + show_vty_subtlv_te_metric (vty, &mtc->te_metric); + + if (IS_INTER_AS(mtc->type)) + { + if (SUBTLV_TYPE(mtc->ras) != 0) + show_vty_subtlv_ras (vty, &mtc->ras); + if (SUBTLV_TYPE(mtc->rip) != 0) + show_vty_subtlv_rip (vty, &mtc->rip); + } + + show_vty_subtlv_av_delay (vty, &mtc->av_delay); + show_vty_subtlv_mm_delay (vty, &mtc->mm_delay); + show_vty_subtlv_delay_var (vty, &mtc->delay_var); + show_vty_subtlv_pkt_loss (vty, &mtc->pkt_loss); + show_vty_subtlv_res_bw (vty, &mtc->res_bw); + show_vty_subtlv_ava_bw (vty, &mtc->ava_bw); + show_vty_subtlv_use_bw (vty, &mtc->use_bw); + vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE); + } + else + { + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + } + + return; +} + +DEFUN (show_isis_mpls_te_interface, + show_isis_mpls_te_interface_cmd, + "show isis mpls-te interface [INTERFACE]", + SHOW_STR + ISIS_STR + MPLS_TE_STR + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + struct listnode *node; + + /* Show All Interfaces. */ + if (argc == 0) + { + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + show_mpls_te_sub (vty, ifp); + } + /* Interface name is specified. */ + else + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + show_mpls_te_sub (vty, ifp); + } + + return CMD_SUCCESS; +} + +/* Initialize MPLS_TE */ +void +isis_mpls_te_init (void) +{ + + zlog_debug("ISIS MPLS-TE: Initialize"); + + /* Initialize MPLS_TE structure */ + isisMplsTE.status = disable; + isisMplsTE.level = 0; + isisMplsTE.inter_as = off; + isisMplsTE.interas_areaid.s_addr = 0; + isisMplsTE.cir_list = list_new(); + isisMplsTE.router_id.s_addr = 0; + + /* Register new VTY commands */ + install_element (VIEW_NODE, &show_isis_mpls_te_router_cmd); + install_element (VIEW_NODE, &show_isis_mpls_te_interface_cmd); + install_element (ENABLE_NODE, &show_isis_mpls_te_router_cmd); + install_element (ENABLE_NODE, &show_isis_mpls_te_interface_cmd); + + install_element (ISIS_NODE, &isis_mpls_te_on_cmd); + install_element (ISIS_NODE, &no_isis_mpls_te_on_cmd); + install_element (ISIS_NODE, &isis_mpls_te_router_addr_cmd); + install_element (ISIS_NODE, &isis_mpls_te_inter_as_cmd); + install_element (ISIS_NODE, &no_isis_mpls_te_inter_as_cmd); + + return; +} + diff --git a/isisd/isis_te.h b/isisd/isis_te.h new file mode 100644 index 000000000..4f29fdb9c --- /dev/null +++ b/isisd/isis_te.h @@ -0,0 +1,331 @@ +/* + * IS-IS Rout(e)ing protocol - isis_te.c + * + * This is an implementation of RFC5305, RFC 5307 and draft-ietf-isis-te-metric-extensions-11 + * + * Copyright (C) 2014 Orange Labs + * http://www.orange.com + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_ISIS_MPLS_TE_H +#define _ZEBRA_ISIS_MPLS_TE_H + +/* + * Traffic Engineering information are transport through LSP: + * - Extended IS Reachability TLV = 22 + * - Traffic Engineering Router ID TLV = 134 + * - Extended IP Reachability TLV = 135 + * - Inter-AS Reachability Information TLV = 141 + * + * and support following sub-TLV: + * + * Name Value Status + * _________________________________________________ + * Administartive group (color) 3 RFC5305 + * Link Local/Remote Identifiers 4 RFC5307 + * IPv4 interface address 6 RFC5305 + * IPv4 neighbor address 8 RFC5305 + * Maximum link bandwidth 9 RFC5305 + * Reservable link bandwidth 10 RFC5305 + * Unreserved bandwidth 11 RFC5305 + * TE Default metric 18 RFC5305 + * Link Protection Type 20 RFC5307 + * Interface Switching Capability 21 RFC5307 + * Remote AS number 24 RFC5316 + * IPv4 Remote ASBR identifier 25 RFC5316 + * + */ + +/* NOTE: RFC5316 is not yet supported in this version */ + +/* Following define the type of TE link regarding the various RFC */ +#define STD_TE 0x01 +#define GMPLS 0x02 +#define INTER_AS 0x04 +#define FLOOD_L1 0x10 +#define FLOOD_L2 0x20 +#define FLOOD_AS 0x40 +#define EMULATED 0x80 + +#define IS_STD_TE(x) (x & STD_TE) +#define IS_INTER_AS(x) (x & INTER_AS) +#define IS_EMULATED(x) (x & EMULATED) +#define IS_FLOOD_L1(x) (x & FLOOD_L1) +#define IS_FLOOD_L2(x) (x & FLOOD_L2) +#define IS_FLOOD_AS(x) (x & FLOOD_AS) +#define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) +#define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) + +/* + * Following section defines subTLV (tag, length, value) structures, + * used for Traffic Engineering. + */ +struct subtlv_header +{ + u_char type; /* sub_TLV_XXX type (see above) */ + u_char length; /* Value portion only, in byte */ +}; + +#define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */ + +#define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length) + +#define SUBTLV_HDR_TOP(lsph) (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE) + +#define SUBTLV_HDR_NEXT(stlvh) (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh)) + +#define SUBTLV_TYPE(stlvh) stlvh.header.type +#define SUBTLV_LEN(stlvh) stlvh.header.length +#define SUBTLV_VAL(stlvh) stlvh.value +#define SUBTLV_DATA(stlvh) stlvh + SUBTLV_HDR_SIZE + +#define SUBTLV_DEF_SIZE 4 + +/* Link Sub-TLV: Resource Class/Color - RFC 5305 */ +#define TE_SUBTLV_ADMIN_GRP 3 +struct te_subtlv_admin_grp +{ + struct subtlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Admin. group membership. */ +} __attribute__((__packed__)); + +/* Link Local/Remote Identifiers - RFC 5307 */ +#define TE_SUBTLV_LLRI 4 +#define TE_SUBTLV_LLRI_SIZE 8 +struct te_subtlv_llri +{ + struct subtlv_header header; /* Value length is 8 octets. */ + u_int32_t local; /* Link Local Identifier */ + u_int32_t remote; /* Link Remote Identifier */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */ +#define TE_SUBTLV_LOCAL_IPADDR 6 +struct te_subtlv_local_ipaddr +{ + struct subtlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value; /* Local IP address(es). */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */ +#define TE_SUBTLV_RMT_IPADDR 8 +struct te_subtlv_rmt_ipaddr +{ + struct subtlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value; /* Neighbor's IP address(es). */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */ +#define TE_SUBTLV_MAX_BW 9 +struct te_subtlv_max_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */ +#define TE_SUBTLV_MAX_RSV_BW 10 +struct te_subtlv_max_rsv_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */ +#define TE_SUBTLV_UNRSV_BW 11 +#define TE_SUBTLV_UNRSV_SIZE 32 +struct te_subtlv_unrsv_bw +{ + struct subtlv_header header; /* Value length is 32 octets. */ + float value[8]; /* One for each priority level. */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */ +#define TE_SUBTLV_TE_METRIC 18 +#define TE_SUBTLV_TE_METRIC_SIZE 3 +struct te_subtlv_te_metric +{ + struct subtlv_header header; /* Value length is 4 octets. */ + u_char value[3]; /* Link metric for TE purpose. */ +} __attribute__((__packed__)); + +/* Remote AS Number sub-TLV - RFC5316 */ +#define TE_SUBTLV_RAS 24 +struct te_subtlv_ras +{ + struct subtlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Remote AS number */ +} __attribute__((__packed__)); + +/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ +#define TE_SUBTLV_RIP 25 +struct te_subtlv_rip +{ + struct subtlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Remote ASBR IP address */ +} __attribute__((__packed__)); + + +/* draft-ietf-isis-te-metric-extensions-11.txt */ +/* Link Sub-TLV: Average Link Delay */ +#define TE_SUBTLV_AV_DELAY 33 +struct te_subtlv_av_delay +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* Average delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit (A) as Upper most bit */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Low/High Link Delay */ +#define TE_SUBTLV_MM_DELAY 34 +#define TE_SUBTLV_MM_DELAY_SIZE 8 +struct te_subtlv_mm_delay +{ + struct subtlv_header header; /* Value length is 8 bytes. */ + u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215 + with Anomalous Bit (A) as Upper most bit */ + u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Link Delay Variation i.e. Jitter */ +#define TE_SUBTLV_DELAY_VAR 35 +struct te_subtlv_delay_var +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ +#define TE_SUBTLV_PKT_LOSS 36 +struct te_subtlv_pkt_loss +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2) + with Anomalous Bit (A) as Upper most bit */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ +#define TE_SUBTLV_RES_BW 37 +struct te_subtlv_res_bw +{ + struct subtlv_header header; /* Value length is 4 bytes. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ +#define TE_SUBTLV_AVA_BW 38 +struct te_subtlv_ava_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +} __attribute__((__packed__)); + +/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ +#define TE_SUBTLV_USE_BW 39 +struct te_subtlv_use_bw +{ + struct subtlv_header header; /* Value length is 4 octets. */ + float value; /* bandwidth in IEEE floating point format with units in bytes per second */ +} __attribute__((__packed__)); + +#define TE_SUBTLV_MAX 40 /* Last SUBTLV + 1 */ + +/* Following declaration concerns the MPLS-TE and LINk-TE management */ +typedef enum _status_t { disable, enable, learn } status_t; + +/* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */ +typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t; + +#define IS_MPLS_TE(m) (m.status == enable) +#define IS_CIRCUIT_TE(c) (c->status == enable) + +/* Following structure are internal use only. */ +struct isis_mpls_te +{ + /* Status of MPLS-TE: enable or disable */ + status_t status; + + /* L1, L1-L2, L2-Only */ + u_int8_t level; + + /* RFC5316 */ + interas_mode_t inter_as; + struct in_addr interas_areaid; + + /* Circuit list on which TE are enable */ + struct list *cir_list; + + /* MPLS_TE router ID */ + struct in_addr router_id; +}; + +extern struct isis_mpls_te isisMplsTE; + +struct mpls_te_circuit +{ + + /* Status of MPLS-TE on this interface */ + status_t status; + + /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316), INTER_AS_EMU(RFC5316 emulated) */ + u_int8_t type; + + /* Total size of sub_tlvs */ + u_char length; + + /* Store subTLV in network byte order. */ + /* RFC5305 */ + struct te_subtlv_admin_grp admin_grp; + /* RFC5307 */ + struct te_subtlv_llri llri; + /* RFC5305 */ + struct te_subtlv_local_ipaddr local_ipaddr; + struct te_subtlv_rmt_ipaddr rmt_ipaddr; + struct te_subtlv_max_bw max_bw; + struct te_subtlv_max_rsv_bw max_rsv_bw; + struct te_subtlv_unrsv_bw unrsv_bw; + struct te_subtlv_te_metric te_metric; + /* RFC5316 */ + struct te_subtlv_ras ras; + struct te_subtlv_rip rip; + /* draft-ietf-isis-te-metric-extension */ + struct te_subtlv_av_delay av_delay; + struct te_subtlv_mm_delay mm_delay; + struct te_subtlv_delay_var delay_var; + struct te_subtlv_pkt_loss pkt_loss; + struct te_subtlv_res_bw res_bw; + struct te_subtlv_ava_bw ava_bw; + struct te_subtlv_use_bw use_bw; +}; + +/* Prototypes. */ +void isis_mpls_te_init (void); +struct mpls_te_circuit *mpls_te_circuit_new(void); +void mpls_te_print_detail(struct vty *, struct te_is_neigh *); +void set_circuitparams_local_ipaddr (struct mpls_te_circuit *, struct in_addr); +void set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *, struct in_addr); +u_char subtlvs_len (struct mpls_te_circuit *); +u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *); +u_char build_te_subtlvs(u_char *, struct isis_circuit *); +void isis_link_params_update(struct isis_circuit *, struct interface *); +void isis_mpls_te_update(struct interface *); +void isis_mpls_te_config_write_router (struct vty *); + +#endif /* _ZEBRA_ISIS_MPLS_TE_H */ diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 8d4ea0e35..1d29d7828 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -42,6 +42,7 @@ #include "isisd/isis_misc.h" #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" +#include "isisd/isis_te.h" void free_tlv (void *val) @@ -178,7 +179,6 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, * | Virtual Flag | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ - /* virtual = *pnt; FIXME: what is the use for this? */ pnt++; value_len++; /* +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -230,9 +230,23 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, while (length > value_len) { te_is_nei = (struct te_is_neigh *) pnt; - value_len += 11; - pnt += 11; - /* FIXME - subtlvs are handled here, for now we skip */ + value_len += IS_NEIGHBOURS_LEN; + pnt += IS_NEIGHBOURS_LEN; + /* FIXME - subtlvs are handled here, for now we skip */ + /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */ + /* So, it must be copied in a new te_is_neigh structure */ + /* rather than just initialize pointer to the original LSP PDU */ + /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */ + if (IS_MPLS_TE(isisMplsTE)) + { + struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh)); + memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1); + memcpy(new->te_metric, te_is_nei->te_metric, 3); + new->sub_tlvs_length = te_is_nei->sub_tlvs_length; + memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length); + te_is_nei = new; + } + /* Skip SUB TLVs payload */ value_len += te_is_nei->sub_tlvs_length; pnt += te_is_nei->sub_tlvs_length; @@ -846,8 +860,8 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh)) { - /* FIXME: This will be wrong if we are going to add TE sub TLVs. */ - if (pos - value + IS_NEIGHBOURS_LEN > 255) + /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */ + if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255) { retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) @@ -859,9 +873,15 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) pos += ISIS_SYS_ID_LEN + 1; memcpy (pos, te_is_neigh->te_metric, 3); pos += 3; - /* Sub TLVs length. */ - *pos = 0; + /* Set the total size of Sub TLVs */ + *pos = te_is_neigh->sub_tlvs_length; pos++; + /* Copy Sub TLVs if any */ + if (te_is_neigh->sub_tlvs_length > 0) + { + memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length); + pos += te_is_neigh->sub_tlvs_length; + } } return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index 619003a0e..5a39d564d 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -39,7 +39,7 @@ * LSP Entries 9 n n y ISO10589 * Authentication 10 y y y ISO10589, RFC3567 * Checksum 12 y n y RFC3358 - * TE IS Reachability 22 n y n RFC5305 + * Extended IS Reachability 22 n y n RFC5305 * IS Alias 24 n y n RFC3786 * IP Int. Reachability 128 n y n RFC1195 * Protocols Supported 129 y y n RFC1195 @@ -50,6 +50,7 @@ * Extended IP Reachability 135 n y n RFC5305 * Dynamic Hostname 137 n y n RFC2763 * Shared Risk Link Group 138 n y y RFC5307 + * Inter-AS Reachability 141 n y n RFC5316 * Restart TLV 211 y n n RFC3847 * MT IS Reachability 222 n y n RFC5120 * MT Supported 229 y y n RFC5120 @@ -59,10 +60,10 @@ * MT IPv6 IP Reachability 237 n y n RFC5120 * P2P Adjacency State 240 y n n RFC3373 * IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence - * Router Capability 242 - - - draft-ietf-isis-caps + * Router Capability 242 n y n RFC4971 * * - * IS Reachability sub-TLVs we (should) support. + * IS Reachability sub-TLVs we support (See isis_te.[c,h]) * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ @@ -76,6 +77,8 @@ * TE Default metric 18 RFC5305 * Link Protection Type 20 RFC5307 * Interface Switching Capability 21 RFC5307 + * Remote AS number 24 RFC5316 + * IPv4 Remote ASBR identifier 25 RFC5316 * * * IP Reachability sub-TLVs we (should) support. @@ -109,6 +112,7 @@ #define IPV6_ADDR 232 #define IPV6_REACHABILITY 236 #define WAY3_HELLO 240 +#define ROUTER_INFORMATION 242 #define AUTH_INFO_HDRLEN 3 @@ -121,6 +125,8 @@ #define IPV6_REACH_LEN 22 #define TE_IPV4_REACH_LEN 9 +#define MAX_SUBTLV_SIZE 256 + /* struct for neighbor */ struct is_neigh { @@ -128,12 +134,18 @@ struct is_neigh u_char neigh_id[ISIS_SYS_ID_LEN + 1]; }; -/* struct for te is neighbor */ +/* struct for te metric */ struct te_is_neigh { u_char neigh_id[ISIS_SYS_ID_LEN + 1]; u_char te_metric[3]; u_char sub_tlvs_length; + /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8 bits */ + /* Practically, 118 bytes are necessary to store all supported TE parameters */ + /* FIXME: A pointer will use less memory, but need to be free */ + /* which is hard to fix, especially within free_tlvs() function */ + /* and malloc() / free() as a CPU cost compared to the memory usage */ + u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */ }; /* Decode and encode three-octet metric into host byte order integer */ diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 4acaf8e88..40157b59a 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -48,6 +48,7 @@ #include "isisd/isis_lsp.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" +#include "isisd/isis_te.h" struct zclient *zclient = NULL; @@ -60,6 +61,13 @@ isis_router_id_update_zebra (int command, struct zclient *zclient, struct listnode *node; struct prefix router_id; + /* + * If ISIS TE is enable, TE Router ID is set through specific command. + * See mpls_te_router_addr() command in isis_te.c + */ + if (IS_MPLS_TE(isisMplsTE)) + return 0; + zebra_router_id_update_read (zclient->ibuf, &router_id); if (isis->router_id == router_id.u.prefix4.s_addr) return 0; @@ -227,6 +235,23 @@ isis_zebra_if_address_del (int command, struct zclient *client, return 0; } +static int +isis_zebra_link_params (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_link_params_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Update TE TLV */ + isis_mpls_te_update(ifp); + + return 0; +} + static void isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) @@ -678,6 +703,7 @@ isis_zebra_init (struct thread_master *master) zclient->interface_down = isis_zebra_if_state_down; zclient->interface_address_add = isis_zebra_if_address_add; zclient->interface_address_delete = isis_zebra_if_address_del; + zclient->interface_link_params = isis_zebra_link_params; zclient->ipv4_route_add = isis_zebra_read_ipv4; zclient->ipv4_route_delete = isis_zebra_read_ipv4; #ifdef HAVE_IPV6 diff --git a/isisd/isisd.c b/isisd/isisd.c index 202b04061..d3bddc063 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -54,6 +54,7 @@ #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" +#include "isisd/isis_te.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" @@ -98,6 +99,7 @@ isis_new (unsigned long process_id) * uncomment the next line for full debugs */ /* isis->debugs = 0xFFFF; */ + isisMplsTE.status = disable; /* Only support TE metric */ } struct isis_area * @@ -781,13 +783,15 @@ print_debug (struct vty *vty, int flags, int onoff) } DEFUN (show_debugging, - show_debugging_cmd, - "show debugging", + show_debugging_isis_cmd, + "show debugging isis", SHOW_STR "State of each debugging option\n") { - vty_out (vty, "IS-IS:%s", VTY_NEWLINE); - print_debug (vty, isis->debugs, 1); + if (isis->debugs) { + vty_out (vty, "IS-IS:%s", VTY_NEWLINE); + print_debug (vty, isis->debugs, 1); + } return CMD_SUCCESS; } @@ -3250,6 +3254,7 @@ isis_config_write (struct vty *vty) #endif /* TOPOLOGY_GENERATE */ } + isis_mpls_te_config_write_router(vty); } return write; @@ -3286,6 +3291,8 @@ isis_init () install_element (VIEW_NODE, &show_database_detail_cmd); install_element (VIEW_NODE, &show_database_detail_arg_cmd); + install_element (ENABLE_NODE, &show_debugging_isis_cmd); + install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &debug_isis_adj_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 1a88efdc7..d2efacacb 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -172,4 +172,8 @@ extern struct thread_master *master; } \ while (0) +#define DEBUG_TE (1<<13) + +#define IS_DEBUG_ISIS(x) (isis->debugs & x) + #endif /* ISISD_H */ From ec04b9faf9ec55ccf7d5bb16cf17a85051fc8270 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 19:18:18 +0200 Subject: [PATCH 1055/1342] doc: Update documentation for Traffic Engineering Signed-off-by: Olivier Dugeon --- doc/install.texi | 11 +- doc/isisd.texi | 432 ++++++++++++++++++++++++++++++++++ doc/main.texi | 75 +++++- doc/mpls/ChangeLog.opaque.txt | 13 + doc/mpls/ospfd.conf | 1 + doc/ospfd.texi | 203 ++++++++++++++++ doc/quagga.texi | 2 + 7 files changed, 729 insertions(+), 8 deletions(-) create mode 100644 doc/isisd.texi diff --git a/doc/install.texi b/doc/install.texi index 7349e92cb..811ad9ae8 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -83,8 +83,17 @@ OSPF-API is enabled if --enable-opaque-lsa is set. @item --disable-ospfclient Disable building of the example OSPF-API client. @item --disable-ospf-te -Disable support for OSPF Traffic Engineering Extension (internet-draft) this +Disable support for OSPF Traffic Engineering Extension (RFC3630) this requires support for Opaque LSAs. +@item --disable-ospf-ri +Disable support for OSPF Router Information (RFC4970 & RFC5088) this +requires support for Opaque LSAs and Traffic Engineering. +@item --enable-isisd +Build isisd. +@item --enable-isis-topology +Enable IS-IS topology generator. +@item --enable-isis-te +Enable Traffic Engineering Extension for ISIS (RFC5305) @item --enable-multipath=@var{ARG} Enable support for Equal Cost Multipath. @var{ARG} is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. diff --git a/doc/isisd.texi b/doc/isisd.texi new file mode 100644 index 000000000..bbc289675 --- /dev/null +++ b/doc/isisd.texi @@ -0,0 +1,432 @@ +@cindex ISIS +@node ISIS +@chapter ISIS + +@acronym{ISIS,Intermediate System to Intermediate System} is a routing protocol +which is described in @cite{ISO10589, RFC1195, RFC5308}. ISIS is an +@acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP}, +@acronym{ISIS} can provide scalable network support and faster +convergence times like @acronym{OSPF}. ISIS is widely used in large networks such as +@acronym{ISP,Internet Service Provider} and carrier backbone networks. + +@menu +* Configuring isisd:: +* ISIS router:: +* ISIS Timer:: +* ISIS region:: +* ISIS interface:: +* Showing ISIS information:: +* ISIS Traffic Engineering:: +* Debugging ISIS:: +* ISIS Configuration Examples:: +@end menu + +@node Configuring isisd +@section Configuring isisd + +There are no @command{isisd} specific options. Common options can be +specified (@pxref{Common Invocation Options}) to @command{isisd}. +@command{isisd} needs to acquire interface information from +@command{zebra} in order to function. Therefore @command{zebra} must be +running before invoking @command{isisd}. Also, if @command{zebra} is +restarted then @command{isisd} must be too. + +Like other daemons, @command{isisd} configuration is done in @acronym{ISIS} +specific configuration file @file{isisd.conf}. + +@node ISIS router +@section ISIS router + +To start ISIS process you have to specify the ISIS router. As of this +writing, @command{isisd} does not support multiple ISIS processes. + +@deffn Command {router isis WORD} {} +@deffnx Command {no router isis WORD} {} +@anchor{router isis WORD}Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'. +@command{isisd} does not yet support multiple ISIS processes but you must specify +the name of ISIS process. The ISIS process name 'WORD' is then used for interface +(see command @ref{ip router isis WORD}). +@end deffn + +@deffn {ISIS Command} {net XX.XXXX. ... .XXX.XX} {} +@deffnx {ISIS Command} {no net XX.XXXX. ... .XXX.XX} {} +Set/Unset network entity title (NET) provided in ISO format. +@end deffn + +@deffn {ISIS Command} {hostname dynamic} {} +@deffnx {ISIS Command} {no hostname dynamic} {} +Enable support for dynamic hostname. +@end deffn + +@deffn {ISIS Command} {area-password [clear | md5] } {} +@deffnx {ISIS Command} {domain-password [clear | md5] } {} +@deffnx {ISIS Command} {no area-password} {} +@deffnx {ISIS Command} {no domain-password} {} +Configure the authentication password for an area, respectively a domain, +as clear text or md5 one. +@end deffn + +@deffn {ISIS Command} {log-adjacency-changes} {} +@deffnx {ISIS Command} {no log-adjacency-changes} {} +Log changes in adjacency state. +@end deffn + +@deffn {ISIS Command} {metric-style [narrow | transition | wide]} {} +@deffnx {ISIS Command} {no metric-style} {} +@anchor{metric-style}Set old-style (ISO 10589) or new-style packet formats: + - narrow Use old style of TLVs with narrow metric + - transition Send and accept both styles of TLVs during transition + - wide Use new style of TLVs to carry wider metric +@end deffn + +@deffn {ISIS Command} {set-overload-bit} {} +@deffnx {ISIS Command} {no set-overload-bit} {} +Set overload bit to avoid any transit traffic. +@end deffn + +@node ISIS Timer +@section ISIS Timer + +@deffn {ISIS Command} {lsp-gen-interval <1-120>} {} +@deffnx {ISIS Command} {lsp-gen-interval [level-1 | level-2] <1-120>} {} +@deffnx {ISIS Command} {no lsp-gen-interval} {} +@deffnx {ISIS Command} {no lsp-gen-interval [level-1 | level-2]} {} +Set minimum interval in seconds between regenerating same LSP, +globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {} +@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {} +@deffnx {ISIS Command} {no lsp-refresh-interval} {} +@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {} +Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {} +@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {} +@deffnx {ISIS Command} {no lsp-refresh-interval} {} +@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {} +Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {max-lsp-lifetime <360-65535>} {} +@deffnx {ISIS Command} {max-lsp-lifetime [level-1 | level-2] <360-65535>} {} +@deffnx {ISIS Command} {no max-lsp-lifetime} {} +@deffnx {ISIS Command} {no max-lsp-lifetime [level-1 | level-2]} {} +Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {ISIS Command} {spf-interval <1-120>} {} +@deffnx {ISIS Command} {spf-interval [level-1 | level-2] <1-120>} {} +@deffnx {ISIS Command} {no spf-interval} {} +@deffnx {ISIS Command} {no spf-interval [level-1 | level-2]} {} +Set minimum interval between consecutive SPF calculations in seconds. +@end deffn + +@node ISIS region +@section ISIS region + +@deffn {ISIS Command} {is-type [level-1 | level-1-2 | level-2-only]} {} +@deffnx {ISIS Command} {no is-type} {} +Define the ISIS router behavior: + - level-1 Act as a station router only + - level-1-2 Act as both a station router and an area router + - level-2-only Act as an area router only +@end deffn + +@node ISIS interface +@section ISIS interface + +@deffn {Interface Command} {ip router isis WORD} {} +@deffnx {Interface Command} {no ip router isis WORD} {} +@anchor{ip router isis WORD}Activate ISIS adjacency on this interface. Note that the name +of ISIS instance must be the same as the one used to configure the ISIS process +(see command @ref{router isis WORD}). +@end deffn + +@deffn {Interface Command} {isis circuit-type [level-1 | level-1-2 | level-2]} {} +@deffnx {Interface Command} {no isis circuit-type} {} +Configure circuit type for interface: + - level-1 Level-1 only adjacencies are formed + - level-1-2 Level-1-2 adjacencies are formed + - level-2-only Level-2 only adjacencies are formed +@end deffn + +@deffn {Interface Command} {isis csnp-interval <1-600>} {} +@deffnx {Interface Command} {isis csnp-interval <1-600> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis csnp-interval} {} +@deffnx {Interface Command} {no isis csnp-interval [level-1 | level-2]} {} +Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {Interface Command} {isis hello padding} {} +Add padding to IS-IS hello packets. +@end deffn + +@deffn {Interface Command} {isis hello-interval <1-600>} {} +@deffnx {Interface Command} {isis hello-interval <1-600> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis hello-interval} {} +@deffnx {Interface Command} {no isis hello-interval [level-1 | level-2]} {} +Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {Interface Command} {isis hello-multiplier <2-100>} {} +@deffnx {Interface Command} {isis hello-multiplier <2-100> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis hello-multiplier} {} +@deffnx {Interface Command} {no isis hello-multiplier [level-1 | level-2]} {} +Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2). +@end deffn + +@deffn {Interface Command} {isis metric [<0-255> | <0-16777215>]} {} +@deffnx {Interface Command} {isis metric [<0-255> | <0-16777215>] [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis metric} {} +@deffnx {Interface Command} {no isis metric [level-1 | level-2]} {} +Set default metric value globally, for an area (level-1) or a domain (level-2). +Max value depend if metric support narrow or wide value (see command @ref{metric-style}). +@end deffn + +@deffn {Interface Command} {isis network point-to-point} {} +@deffnx {Interface Command} {no isis network point-to-point} {} +Set network type to 'Point-to-Point' (broadcast by default). +@end deffn + +@deffn {Interface Command} {isis passive} {} +@deffnx {Interface Command} {no isis passive} {} +Configure the passive mode for this interface. +@end deffn + +@deffn {Interface Command} {isis password [clear | md5] } {} +@deffnx {Interface Command} {no isis password} {} +Configure the authentication password (clear or encoded text) for the interface. +@end deffn + +@deffn {Interface Command} {isis priority <0-127>} {} +@deffnx {Interface Command} {isis priority <0-127> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis priority} {} +@deffnx {Interface Command} {no isis priority [level-1 | level-2]} {} +Set priority for Designated Router election, globally, for the area (level-1) +or the domain (level-2). +@end deffn + +@deffn {Interface Command} {isis psnp-interval <1-120>} {} +@deffnx {Interface Command} {isis psnp-interval <1-120> [level-1 | level-2]} {} +@deffnx {Interface Command} {no isis psnp-interval} {} +@deffnx {Interface Command} {no isis psnp-interval [level-1 | level-2]} {} +Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2). +@end deffn + +@node Showing ISIS information +@section Showing ISIS information + +@deffn {Command} {show isis summary} {} +Show summary information about ISIS. +@end deffn + +@deffn {Command} {show isis hostname} {} +Show information about ISIS node. +@end deffn + +@deffn {Command} {show isis interface} {} +@deffnx {Command} {show isis interface detail} {} +@deffnx {Command} {show isis interface } {} +Show state and configuration of ISIS specified interface, or all +interfaces if no interface is given with or without details. +@end deffn + +@deffn {Command} {show isis neighbor} {} +@deffnx {Command} {show isis neighbor } {} +@deffnx {Command} {show isis neighbor detail} {} +Show state and information of ISIS specified neighbor, or all +neighbors if no system id is given with or without details. +@end deffn + +@deffn {Command} {show isis database} {} +@deffnx {Command} {show isis database [detail]} {} +@deffnx {Command} {show isis database [detail]} {} +@deffnx {Command} {show isis database detail } {} +Show the ISIS database globally, for a specific LSP id without or with details. +@end deffn + +@deffn {Command} {show isis topology} {} +@deffnx {Command} {show isis topology [level-1|level-2]} {} +Show topology IS-IS paths to Intermediate Systems, globally, +in area (level-1) or domain (level-2). +@end deffn + +@deffn {Command} {show ip route isis} {} +Show the ISIS routing table, as determined by the most recent SPF calculation. +@end deffn + +@node ISIS Traffic Engineering +@section Traffic Engineering + +@deffn {ISIS Command} {mpls-te on} {} +@deffnx {ISIS Command} {no mpls-te} {} +Enable Traffic Engineering LSP flooding. +@end deffn + +@deffn {ISIS Command} {mpls-te router-address } {} +@deffnx {ISIS Command} {no mpls-te router-address} {} +Configure stable IP address for MPLS-TE. +@end deffn + +@deffn {Command} {show isis mpls-te interface} {} +@deffnx {Command} {show isis mpls-te interface @var{interface}} {} +Show MPLS Traffic Engineering parameters for all or specified interface. +@end deffn + +@deffn {Command} {show isis mpls-te router} {} +Show Traffic Engineering router parameters. +@end deffn + +@node Debugging ISIS +@section Debugging ISIS + +@deffn {Command} {debug isis adj-packets} {} +@deffnx {Command} {no debug isis adj-packets} {} +IS-IS Adjacency related packets. +@end deffn + +@deffn {Command} {debug isis checksum-errors} {} +@deffnx {Command} {no debug isis checksum-errors} {} +IS-IS LSP checksum errors. +@end deffn + +@deffn {Command} {debug isis events} {} +@deffnx {Command} {no debug isis events} {} +IS-IS Events. +@end deffn + +@deffn {Command} {debug isis local-updates} {} +@deffnx {Command} {no debug isis local-updates} {} +IS-IS local update packets. +@end deffn + +@deffn {Command} {debug isis packet-dump} {} +@deffnx {Command} {no debug isis packet-dump} {} +IS-IS packet dump. +@end deffn + +@deffn {Command} {debug isis protocol-errors} {} +@deffnx {Command} {no debug isis protocol-errors} {} +IS-IS LSP protocol errors. +@end deffn + +@deffn {Command} {debug isis route-events} {} +@deffnx {Command} {no debug isis route-events} {} +IS-IS Route related events. +@end deffn + +@deffn {Command} {debug isis snp-packets} {} +@deffnx {Command} {no debug isis snp-packets} {} +IS-IS CSNP/PSNP packets. +@end deffn + +@deffn {Command} {debug isis spf-events} {} +@deffnx {Command} {debug isis spf-statistics} {} +@deffnx {Command} {debug isis spf-triggers} {} +@deffnx {Command} {no debug isis spf-events} {} +@deffnx {Command} {no debug isis spf-statistics} {} +@deffnx {Command} {no debug isis spf-triggers} {} +IS-IS Shortest Path First Events, Timing and Statistic Data +and triggering events. +@end deffn + +@deffn {Command} {debug isis update-packets} {} +@deffnx {Command} {no debug isis update-packets} {} +Update related packets. +@end deffn + +@deffn {Command} {show debugging isis} {} +Print which ISIS debug level is activate. +@end deffn + +@node ISIS Configuration Examples +@section ISIS Configuration Examples +A simple example, with MD5 authentication enabled: + +@example +@group +! +interface eth0 + ip router isis FOO + isis network point-to-point + isis circuit-type level-2-only +! +router isis FOO +net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 + metric-style wide + is-type level-2-only +@end group +@end example + + +A Traffic Engineering configuration, with Inter-ASv2 support. + + - First, the 'zebra.conf' part: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/zebra.log +! +interface eth0 + ip address 10.2.2.2/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab +! +interface eth1 + ip address 10.1.1.1/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab + mpls-te neighbor 10.1.1.2 as 65000 +@end group +@end example + + - Then the 'isisd.conf' itself: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/isisd.log +! +! +interface eth0 + ip router isis FOO +! +interface eth1 + ip router isis FOO +! +! +router isis FOO + isis net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 + mpls-te on + mpls-te router-address 10.1.1.1 +! +line vty +@end group +@end example diff --git a/doc/main.texi b/doc/main.texi index 4c11d2440..209a70392 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -42,6 +42,14 @@ When program terminates, retain routes added by zebra. @node Interface Commands @section Interface Commands +@menu +* Standard Commands:: +* Link Parameters Commands:: +@end menu + +@node Standard Commands +@subsection Standard Commands + @deffn Command {interface @var{ifname}} {} @end deffn @@ -74,18 +82,71 @@ Enable or disables multicast flag for the interface. @deffn {Interface Command} {bandwidth <1-10000000>} {} @deffnx {Interface Command} {no bandwidth <1-10000000>} {} -Set bandwidth value of the interface in kilobits/sec. This is for -calculating OSPF cost. This command does not affect the actual device +Set bandwidth value of the interface in kilobits/sec. This is for +calculating OSPF cost. This command does not affect the actual device configuration. @end deffn @deffn {Interface Command} {link-detect} {} @deffnx {Interface Command} {no link-detect} {} -Enable/disable link-detect on platforms which support this. Currently +Enable/disable link-detect on platforms which support this. Currently only Linux and Solaris, and only where network interface drivers support reporting link-state via the IFF_RUNNING flag. @end deffn +@node Link Parameters Commands +@subsection Link Parameters Commands + +@deffn {Interface Command} {link-params} {} +@deffnx {Interface Command} {no link-param} {} +Enter into the link parameters sub node. At least 'enable' must be set to activate the link parameters, +and consequently Traffic Engineering on this interface. MPLS-TE must be enable at the OSPF (@ref{OSPF Traffic Engineering}) +or ISIS (@ref{ISIS Traffic Engineering}) router level in complement to this. +Disable link parameters for this interface. +@end deffn + +Under link parameter statement, the following commands set the different TE values: + +@deffn link-params {enable} +Enable link parameters for this interface. +@end deffn + +@deffn link-params {metric <0-4294967295>} {} +@deffnx link-params {max-bw @var{bandwidth}} {} +@deffnx link-params {max-rsv-bw @var{bandwidth}} {} +@deffnx link-params {unrsv-bw <0-7> @var{bandwidth}} {} +@deffnx link-params {admin-grp @var{bandwidth}} {} +These commands specifies the Traffic Engineering parameters of the interface in conformity to RFC3630 (OSPF) +or RFC5305 (ISIS). +There are respectively the TE Metric (different from the OSPF or ISIS metric), Maximum Bandwidth (interface speed +by default), Maximum Reservable Bandwidth, Unreserved Bandwidth for each 0-7 priority and Admin Group (ISIS) or +Resource Class/Color (OSPF). + +Note that @var{bandwidth} are specified in IEEE floating point format and express in Bytes/second. +@end deffn + +@deffn link-param {delay <0-16777215> [min <0-16777215> | max <0-16777215>]} {} +@deffnx link-param {delay-variation <0-16777215>} {} +@deffnx link-param {packet-loss @var{percentage}} {} +@deffnx link-param {res-bw @var{bandwidth}} {} +@deffnx link-param {ava-bw @var{bandwidth}} {} +@deffnx link-param {use-bw @var{bandwidth}} {} +These command specifies additionnal Traffic Engineering parameters of the interface in conformity to +draft-ietf-ospf-te-metrics-extension-05.txt and draft-ietf-isis-te-metrics-extension-03.txt. There are +respectively the delay, jitter, loss, available bandwidth, reservable bandwidth and utilized bandwidth. + +Note that @var{bandwidth} are specified in IEEE floating point format and express in Bytes/second. +Delays and delay variation are express in micro-second (µs). Loss is specified in @var{percentage} ranging +from 0 to 50.331642% by step of 0.000003. +@end deffn + +@deffn link-param {neighbor as <0-65535>} {} +@deffnx link-param {no neighbor} {} +Specifies the remote ASBR IP address and Autonomous System (AS) number for InterASv2 link in OSPF (RFC5392). +Note that this option is not yet supported for ISIS (RFC5316). +@end deffn + + @node Static Route Commands @section Static Route Commands @@ -162,7 +223,7 @@ prevent traffic destined for a prefix to match less-specific routes (eg default) should the specified gateways not be reachable. Eg: @example -zebra> show ip route 10.0.0.0/8 +zebra> show ip route 10.0.0.0/8 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 10.0.0.2 inactive @@ -182,7 +243,7 @@ These behave similarly to their ipv4 counterparts. @deffn Command {table @var{tableno}} {} Select the primary kernel routing table to be used. This only works for kernels supporting multiple routing tables (like GNU/Linux 2.2.x -and later). After setting @var{tableno} with this command, +and later). After setting @var{tableno} with this command, static routes defined after this are added to the specified table. @end deffn @@ -365,8 +426,8 @@ Display current routes which zebra holds in its database. @example @group -Router# show ip route -Codes: K - kernel route, C - connected, S - static, R - RIP, +Router# show ip route +Codes: K - kernel route, C - connected, S - static, R - RIP, B - BGP * - FIB route. K* 0.0.0.0/0 203.181.89.241 diff --git a/doc/mpls/ChangeLog.opaque.txt b/doc/mpls/ChangeLog.opaque.txt index 68ddf4c81..afcfaa359 100644 --- a/doc/mpls/ChangeLog.opaque.txt +++ b/doc/mpls/ChangeLog.opaque.txt @@ -1,3 +1,16 @@ +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2013.07.01 + +1. Feature enhancements + + 1.1 Update ospf_te.[c,h] in conformance to RFC3630 and clean the code. + Add new directive to enable MPLS-TE per interface instead of globally + + 1.2 Add support for RFC4970 "Router Information" and RFC5088 "PCE + Capabilities announcement". + + 1.3 Incorporate the mpls documentation into the main stream doc. + ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.12.03 diff --git a/doc/mpls/ospfd.conf b/doc/mpls/ospfd.conf index 6be11f912..2b15fa4d0 100644 --- a/doc/mpls/ospfd.conf +++ b/doc/mpls/ospfd.conf @@ -17,6 +17,7 @@ debug ospf packet all detail interface fxp0 ip ospf hello-interval 60 ip ospf dead-interval 240 + mpls-te on mpls-te link metric 999 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 86cabe409..1cc7973a5 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -1,3 +1,4 @@ + @cindex OSPFv2 @node OSPFv2 @chapter OSPFv2 @@ -18,6 +19,9 @@ networks. * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: +* Opaque LSA:: +* OSPF Traffic Engineering:: +* Router Information:: * Debugging OSPF:: * OSPF Configuration Examples:: @end menu @@ -629,35 +633,137 @@ interfaces if no interface is given. Show the OSPF routing table, as determined by the most recent SPF calculation. @end deffn +@node Opaque LSA +@section Opaque LSA + +@deffn {OSPF Command} {ospf opaque-lsa} {} +@deffnx {OSPF Command} {capability opaque} {} +@deffnx {OSPF Command} {no ospf opaque-lsa} {} +@deffnx {OSPF Command} {no capability opaque} {} +@command{ospfd} support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration file. Alternate command could be "mpls-te on" (@ref{OSPF Traffic Engineering}). +@end deffn + +@deffn {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external)} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id}} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} self-originate} {} +@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate} {} +Show Opaque LSA from the database. +@end deffn + +@node OSPF Traffic Engineering +@section Traffic Engineering + +@deffn {OSPF Command} {mpls-te on} {} +@deffnx {OSPF Command} {no mpls-te} {} +Enable Traffic Engineering LSA flooding. +@end deffn + +@deffn {OSPF Command} {mpls-te router-address } {} +@deffnx {OSPF Command} {no mpls-te} {} +Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE) +option 1 (Router-Address). +@end deffn + +@deffn {OSPF Command} {mpls-te inter-as area |as} {} +@deffnx {OSPF Command} {no mpls-te inter-as} {} +Enable RFC5392 suuport - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link. +2 modes are supported: AREA and AS; LSA are flood in AREA with Opaque Type-10, +respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. +@end deffn + +@deffn {Command} {show ip ospf mpls-te interface} {} +@deffnx {Command} {show ip ospf mpls-te interface @var{interface}} {} +Show MPLS Traffic Engineering parameters for all or specified interface. +@end deffn + +@deffn {Command} {show ip ospf mpls-te router} {} +Show Traffic Engineering router parameters. +@end deffn + +@node Router Information +@section Router Information + +@deffn {OSPF Command} {router-info [as | area ]} {} +@deffnx {OSPF Command} {no router-info} {} +Enable Router Information (RFC4970) LSA advertisement with AS scope (default) or Area scope flooding +when area is specified. +@end deffn + +@deffn {OSPF Command} {pce address } {} +@deffnx {OSPF Command} {no pce address} {} +@deffnx {OSPF Command} {pce domain as <0-65535>} {} +@deffnx {OSPF Command} {no pce domain as <0-65535>} {} +@deffnx {OSPF Command} {pce neighbor as <0-65535>} {} +@deffnx {OSPF Command} {no pce neighbor as <0-65535>} {} +@deffnx {OSPF Command} {pce flag BITPATTERN} {} +@deffnx {OSPF Command} {no pce flag} {} +@deffnx {OSPF Command} {pce scope BITPATTERN} {} +@deffnx {OSPF Command} {no pce scope} {} +The commands are conform to RFC 5088 and allow OSPF router announce Path Compuatation Elemenent (PCE) capabilities +through the Router Information (RI) LSA. Router Information must be enable prior to this. The command set/unset +respectively the PCE IP adress, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope. +For flag and scope, please refer to RFC5088 for the BITPATTERN recognition. Multiple 'pce neighbor' command could +be specified in order to specify all PCE neighbours. +@end deffn + +@deffn {Command} {show ip ospf router-info} {} +Show Router Capabilities flag. +@end deffn +@deffn {Command} {show ip ospf router-info pce} {} +Show Router Capabilities PCE parameters. +@end deffn + @node Debugging OSPF @section Debugging OSPF @deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} @deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} +Dump Packet for debugging @end deffn @deffn {Command} {debug ospf ism} {} @deffnx {Command} {debug ospf ism (status|events|timers)} {} @deffnx {Command} {no debug ospf ism} {} @deffnx {Command} {no debug ospf ism (status|events|timers)} {} +Show debug information of Interface State Machine @end deffn @deffn {Command} {debug ospf nsm} {} @deffnx {Command} {debug ospf nsm (status|events|timers)} {} @deffnx {Command} {no debug ospf nsm} {} @deffnx {Command} {no debug ospf nsm (status|events|timers)} {} +Show debug information of Network State Machine +@end deffn + +@deffn {Command} {debug ospf event} {} +@deffnx {Command} {no debug ospf event} {} +Show debug information of OSPF event +@end deffn + +@deffn {Command} {debug ospf nssa} {} +@deffnx {Command} {no debug ospf nssa} {} +Show debug information about Not So Stub Area @end deffn @deffn {Command} {debug ospf lsa} {} @deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {} @deffnx {Command} {no debug ospf lsa} {} @deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {} +Show debug detail of Link State messages +@end deffn + +@deffn {Command} {debug ospf te} {} +@deffnx {Command} {no debug ospf te} {} +Show debug information about Traffic Engineering LSA @end deffn @deffn {Command} {debug ospf zebra} {} @deffnx {Command} {debug ospf zebra (interface|redistribute)} {} @deffnx {Command} {no debug ospf zebra} {} @deffnx {Command} {no debug ospf zebra (interface|redistribute)} {} +Show debug information of ZEBRA API @end deffn @deffn {Command} {show debugging ospf} {} @@ -715,3 +821,100 @@ router ospf ! @end group @end example + +A Traffic Engineering configuration, with Inter-ASv2 support. + + - First, the 'zebra.conf' part: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/zebra.log +! +interface eth0 + ip address 198.168.1.1/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab +! +interface eth1 + ip address 192.168.2.1/24 + mpls-te on + mpls-te link metric 10 + mpls-te link max-bw 1.25e+06 + mpls-te link max-rsv-bw 1.25e+06 + mpls-te link unrsv-bw 0 1.25e+06 + mpls-te link unrsv-bw 1 1.25e+06 + mpls-te link unrsv-bw 2 1.25e+06 + mpls-te link unrsv-bw 3 1.25e+06 + mpls-te link unrsv-bw 4 1.25e+06 + mpls-te link unrsv-bw 5 1.25e+06 + mpls-te link unrsv-bw 6 1.25e+06 + mpls-te link unrsv-bw 7 1.25e+06 + mpls-te link rsc-clsclr 0xab + mpls-te neighbor 192.168.2.2 as 65000 +@end group +@end example + + - Then the 'ospfd.conf' itself: + +@example +@group +hostname HOSTNAME +password PASSWORD +log file /var/log/ospfd.log +! +! +interface eth0 + ip ospf hello-interval 60 + ip ospf dead-interval 240 +! +interface eth1 + ip ospf hello-interval 60 + ip ospf dead-interval 240 +! +! +router ospf + ospf router-id 192.168.1.1 + network 192.168.0.0/16 area 1 + ospf opaque-lsa + mpls-te + mpls-te router-address 192.168.1.1 + mpls-te inter-as area 1 +! +line vty +@end group +@end example + +A router information example with PCE advsertisement: + +@example +@group +! +router ospf + ospf router-id 192.168.1.1 + network 192.168.0.0/16 area 1 + capability opaque + mpls-te + mpls-te router-address 192.168.1.1 + router-info area 0.0.0.1 + pce address 192.168.1.1 + pce flag 0x80 + pce domain as 65400 + pce neighbor as 65500 + pce neighbor as 65200 + pce scope 0x80 +! +@end group +@end example diff --git a/doc/quagga.texi b/doc/quagga.texi index 65089621a..6831b30cd 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -85,6 +85,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of * RIPng:: * OSPFv2:: * OSPFv3:: +* ISIS:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: @@ -109,6 +110,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of @include ripngd.texi @include ospfd.texi @include ospf6d.texi +@include isisd.texi @include bgpd.texi @include routeserver.texi @include vtysh.texi From 481986950290323e2f5d1e774a666d4b7ed510d6 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 19 Apr 2016 19:21:17 +0200 Subject: [PATCH 1056/1342] ospfd: Add support Router Capabilities support to OSPF This is an implementation of RFC4970 (Router Information) and RFC5088 (PCE Capabilities announcement) * ospfd/Makefile.am: Add new file ospf_ri.c and ospf_ri.h * ospfd/ospf_opaque.c: Add new Router Capabilities code point * ospfd/ospf_ri.[c,h]: Implementation of RFC4970 & RFC5088 Signed-off-by: Olivier Dugeon --- ospfd/Makefile.am | 6 +- ospfd/ospf_opaque.c | 9 + ospfd/ospf_ri.c | 1639 +++++++++++++++++++++++++++++++++++++++++++ ospfd/ospf_ri.h | 191 +++++ 4 files changed, 1842 insertions(+), 3 deletions(-) create mode 100644 ospfd/ospf_ri.c create mode 100644 ospfd/ospf_ri.h diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index f21f50792..f586d7343 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -16,7 +16,7 @@ libospf_la_SOURCES = \ ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ - ospf_opaque.c ospf_te.c ospf_vty.c ospf_api.c ospf_apiserver.c + ospf_opaque.c ospf_te.c ospf_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c ospfdheaderdir = $(pkgincludedir)/ospfd @@ -27,11 +27,11 @@ ospfdheader_HEADERS = \ noinst_HEADERS = \ ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ - ospf_flood.h ospf_snmp.h ospf_te.h ospf_vty.h ospf_apiserver.h + ospf_flood.h ospf_snmp.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c -ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ +ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ @LIBM@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 6b069c808..39465c15a 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -62,6 +62,7 @@ *------------------------------------------------------------------------*/ #include "ospfd/ospf_te.h" +#include "ospfd/ospf_ri.h" #ifdef SUPPORT_OSPF_API int ospf_apiserver_init (void); @@ -87,6 +88,9 @@ ospf_opaque_init (void) if (ospf_mpls_te_init () != 0) exit (1); + if (ospf_router_info_init () != 0) + exit (1); + #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) exit (1); @@ -100,6 +104,8 @@ ospf_opaque_term (void) { ospf_mpls_te_term (); + ospf_router_info_term (); + #ifdef SUPPORT_OSPF_API ospf_apiserver_term (); #endif /* SUPPORT_OSPF_API */ @@ -216,6 +222,9 @@ ospf_opaque_type_name (u_char opaque_type) case OPAQUE_TYPE_INTER_AS_LSA: name = "Inter-AS TE-v2 LSA"; break; + case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: + name = "Router Information LSA"; + break; default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c new file mode 100644 index 000000000..5b1032b0c --- /dev/null +++ b/ospfd/ospf_ri.c @@ -0,0 +1,1639 @@ +/* + * This is an implementation of RFC4970 Router Information + * with support of RFC5088 PCE Capabilites announcement + * + * Module name: Router Information + * Version: 0.99.22 + * Created: 2012-02-01 by Olivier Dugeon + * Copyright (C) 2012 Orange Labs http://www.orange.com/ + * + * This file is part of GNU Quagga. + * + * GNU Zebra 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. + * + * GNU 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 GNU 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 +#include + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_ri.h" +#include "ospfd/ospf_te.h" + +struct ospf_pce_info +{ + + /* Store Router Information PCE TLV and SubTLV in network byte order. */ + struct ri_tlv_pce pce_header; + struct ri_pce_subtlv_address pce_address; + struct ri_pce_subtlv_path_scope pce_scope; + struct list *pce_domain; + struct list *pce_neighbor; + struct ri_pce_subtlv_cap_flag pce_cap_flag; +}; + +/* Following structure are internal use only. */ +struct ospf_router_info +{ + status_t status; + + u_int8_t registered; + u_int8_t scope; + + /* Flags to manage this router information. */ +#define RIFLG_LOOKUP_DONE 0x1 +#define RIFLG_LSA_ENGAGED 0x2 +#define RIFLG_LSA_FORCED_REFRESH 0x4 + u_int32_t flags; + + /* area pointer if flooding is Type 10 Null if flooding is AS scope */ + struct ospf_area *area; + struct in_addr area_id; + + /* Store Router Information Capabilities LSA */ + struct ri_tlv_router_cap router_cap; + + /* Store PCE capability LSA */ + struct ospf_pce_info pce_info; +}; + +/* + * Global variable to manage Opaque-LSA/Router Information on this node. + * Note that all parameter values are stored in network byte order. + */ +static struct ospf_router_info OspfRI; + +/*------------------------------------------------------------------------------* + * Followings are initialize/terminate functions for Router Information handling. + *------------------------------------------------------------------------------*/ + +static void ospf_router_info_ism_change (struct ospf_interface *oi, + int old_status); +static void ospf_router_info_nsm_change (struct ospf_neighbor *nbr, + int old_status); +static void ospf_router_info_config_write_router (struct vty *vty); +static void ospf_router_info_show_info (struct vty *vty, + struct ospf_lsa *lsa); +static int ospf_router_info_lsa_originate (void *arg); +static struct ospf_lsa *ospf_router_info_lsa_refresh (struct ospf_lsa *lsa); +static void ospf_router_info_lsa_schedule (opcode_t opcode); +static void ospf_router_info_register_vty (void); +static void del_pce_info (void *val); + +int +ospf_router_info_init (void) +{ + + memset (&OspfRI, 0, sizeof (struct ospf_router_info)); + OspfRI.status = disabled; + OspfRI.registered = 0; + OspfRI.scope = OSPF_OPAQUE_AS_LSA; + OspfRI.flags = 0; + + /* Initialize pce domain and neighbor list */ + OspfRI.pce_info.pce_domain = list_new (); + OspfRI.pce_info.pce_domain->del = del_pce_info; + OspfRI.pce_info.pce_neighbor = list_new (); + OspfRI.pce_info.pce_neighbor->del = del_pce_info; + + ospf_router_info_register_vty (); + + return 0; +} + +static int +ospf_router_info_register (u_int8_t scope) +{ + int rc = 0; + + if (OspfRI.registered) + return 0; + + zlog_info ("Register Router Information with scope %s(%d)", + scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); + rc = ospf_register_opaque_functab (scope, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA, + NULL, /* new interface */ + NULL, /* del interface */ + ospf_router_info_ism_change, + ospf_router_info_nsm_change, + ospf_router_info_config_write_router, + NULL, /* Config. write interface */ + NULL, /* Config. write debug */ + ospf_router_info_show_info, + ospf_router_info_lsa_originate, + ospf_router_info_lsa_refresh, + NULL, /* new_lsa_hook */ + NULL); /* del_lsa_hook */ + + if (rc != 0) + { + zlog_warn ("ospf_router_info_init: Failed to register functions"); + return rc; + } + + OspfRI.registered = 1; + OspfRI.scope = scope; + return 0; +} + +static int +ospf_router_info_unregister () +{ + + if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA) + && (OspfRI.scope != OSPF_OPAQUE_AREA_LSA)) + { + zlog_warn ("Unable to unregister Router Info functions: Wrong scope!"); + return -1; + } + + ospf_delete_opaque_functab (OspfRI.scope, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA); + + OspfRI.registered = 0; + return 0; + +} + +void +ospf_router_info_term (void) +{ + + list_delete (OspfRI.pce_info.pce_domain); + list_delete (OspfRI.pce_info.pce_neighbor); + + OspfRI.pce_info.pce_domain = NULL; + OspfRI.pce_info.pce_neighbor = NULL; + OspfRI.status = disabled; + + ospf_router_info_unregister (OspfRI.scope); + + return; +} + +static void +del_pce_info (void *val) +{ + XFREE (MTYPE_OSPF_PCE_PARAMS, val); + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions for ROUTER INFORMATION parameters management. + *------------------------------------------------------------------------*/ + +static void +set_router_info_capabilities (struct ri_tlv_router_cap *ric, u_int32_t cap) +{ + ric->header.type = htons (RI_TLV_CAPABILITIES); + ric->header.length = htons (RI_TLV_LENGTH); + ric->value = htonl (cap); + return; +} + +static int +set_pce_header (struct ospf_pce_info *pce) +{ + u_int16_t length = 0; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + + /* PCE Address */ + if (ntohs (pce->pce_address.header.type) != 0) + length += RI_TLV_SIZE (&pce->pce_address.header); + + /* PCE Path Scope */ + if (ntohs (pce->pce_scope.header.type) != 0) + length += RI_TLV_SIZE (&pce->pce_scope.header); + + /* PCE Domain */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (ntohs (domain->header.type) != 0) + length += RI_TLV_SIZE (&domain->header); + } + + /* PCE Neighbor */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (ntohs (neighbor->header.type) != 0) + length += RI_TLV_SIZE (&neighbor->header); + } + + /* PCE Capabilities */ + if (ntohs (pce->pce_cap_flag.header.type) != 0) + length += RI_TLV_SIZE (&pce->pce_cap_flag.header); + + if (length != 0) + { + pce->pce_header.header.type = htons (RI_TLV_PCE); + pce->pce_header.header.length = htons (length); + } + else + { + pce->pce_header.header.type = 0; + pce->pce_header.header.length = 0; + } + + return length; +} + +static void +set_pce_address (struct in_addr ipv4, struct ospf_pce_info *pce) +{ + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + /* Set PCE Address */ + pce->pce_address.header.type = htons (RI_PCE_SUBTLV_ADDRESS); + pce->pce_address.header.length = htons (PCE_ADDRESS_LENGTH_IPV4); + pce->pce_address.address.type = htons (PCE_ADDRESS_TYPE_IPV4); + pce->pce_address.address.value = ipv4; + + return; +} + +static void +set_pce_path_scope (u_int32_t scope, struct ospf_pce_info *pce) +{ + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + /* Set PCE Scope */ + pce->pce_scope.header.type = htons (RI_PCE_SUBTLV_PATH_SCOPE); + pce->pce_scope.header.length = htons (RI_TLV_LENGTH); + pce->pce_scope.value = htonl (scope); + + return; +} + +static void +set_pce_domain (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) +{ + + struct ri_pce_subtlv_domain *new; + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + + /* Create new domain info */ + new = + XCALLOC (MTYPE_OSPF_PCE_PARAMS, + sizeof (struct ri_pce_subtlv_domain)); + + new->header.type = htons (RI_PCE_SUBTLV_DOMAIN); + new->header.length = htons (PCE_ADDRESS_LENGTH_IPV4); + new->type = htons (type); + new->value = htonl (domain); + + /* Add new domain to the list */ + listnode_add (pce->pce_domain, new); + + return; +} + +static void +unset_pce_domain (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) +{ + struct listnode *node; + struct ri_pce_subtlv_domain *old = NULL; + int found = 0; + + /* Search the corresponding node */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, old)) + { + if ((old->type == htons (type)) && (old->value == htonl (domain))) + { + found = 1; + break; + } + } + + /* if found remove it */ + if (found) + { + listnode_delete (pce->pce_domain, old); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (pce->pce_domain) == 0) + pce->pce_domain->head = pce->pce_domain->tail = NULL; + + /* Finally free the old domain */ + XFREE (MTYPE_OSPF_PCE_PARAMS, old); + } +} + +static void +set_pce_neighbor (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) +{ + + struct ri_pce_subtlv_neighbor *new; + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + + /* Create new neighbor info */ + new = + XCALLOC (MTYPE_OSPF_PCE_PARAMS, + sizeof (struct ri_pce_subtlv_neighbor)); + + new->header.type = htons (RI_PCE_SUBTLV_NEIGHBOR); + new->header.length = htons (PCE_ADDRESS_LENGTH_IPV4); + new->type = htons (type); + new->value = htonl (domain); + + /* Add new domain to the list */ + listnode_add (pce->pce_neighbor, new); + + return; +} + +static void +unset_pce_neighbor (u_int16_t type, u_int32_t domain, + struct ospf_pce_info *pce) +{ + struct listnode *node; + struct ri_pce_subtlv_neighbor *old = NULL; + int found = 0; + + /* Search the corresponding node */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, old)) + { + if ((old->type == htons (type)) && (old->value == htonl (domain))) + { + found = 1; + break; + } + } + + /* if found remove it */ + if (found) + { + listnode_delete (pce->pce_neighbor, old); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (pce->pce_neighbor) == 0) + pce->pce_neighbor->head = pce->pce_neighbor->tail = NULL; + + /* Finally free the old domain */ + XFREE (MTYPE_OSPF_PCE_PARAMS, old); + } +} + +static void +set_pce_cap_flag (u_int32_t cap, struct ospf_pce_info *pce) +{ + + /* Enable PCE Info */ + pce->pce_header.header.type = htons (RI_TLV_PCE); + /* Set PCE Capabilities flag */ + pce->pce_cap_flag.header.type = htons (RI_PCE_SUBTLV_CAP_FLAG); + pce->pce_cap_flag.header.length = htons (RI_TLV_LENGTH); + pce->pce_cap_flag.value = htonl (cap); + + return; +} + + +static void +unset_param (struct ri_tlv_header *tlv) +{ + + tlv->type = 0; + /* Fill the Value to 0 */ + memset ((tlv + RI_TLV_HDR_SIZE), 0, RI_TLV_BODY_SIZE (tlv)); + tlv->length = 0; + + return; +} + +static void +initialize_params (struct ospf_router_info *ori) +{ + u_int32_t cap; + struct ospf *top; + + /* + * Initialize default Router Information Capabilities. + */ + cap = 0; + cap = cap | RI_TE_SUPPORT; + + set_router_info_capabilities (&ori->router_cap, cap); + + /* If Area address is not null and exist, retrieve corresponding structure */ + top = ospf_lookup (); + zlog_info ("RI-> Initialize Router Info for %s scope within area %s", + OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", + inet_ntoa (OspfRI.area_id)); + + /* Try to get the Area context at this step. Do it latter if not available */ + if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) + OspfRI.area = ospf_area_lookup_by_area_id (top, OspfRI.area_id); + + /* + * Initialize default PCE Information values + */ + /* PCE address == OSPF Router ID */ + set_pce_address (top->router_id, &ori->pce_info); + + /* PCE scope */ + cap = 7; /* Set L, R and Rd bits to one = intra & inter-area path computation */ + set_pce_path_scope (cap, &ori->pce_info); + + /* PCE Capabilities */ + cap = + PCE_CAP_BIDIRECTIONAL | PCE_CAP_DIVERSE_PATH | PCE_CAP_OBJECTIVES | + PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ; + set_pce_cap_flag (cap, &ori->pce_info); + + /* Finally compute PCE header */ + set_pce_header (&ori->pce_info); + + return; +} + +static int +is_mandated_params_set (struct ospf_router_info ori) +{ + int rc = 0; + + if (ntohs (ori.router_cap.header.type) == 0) + goto out; + + if ((ntohs (ori.pce_info.pce_header.header.type) == RI_TLV_PCE) + && (ntohs (ori.pce_info.pce_address.header.type) == 0) + && (ntohs (ori.pce_info.pce_cap_flag.header.type) == 0)) + goto out; + + rc = 1; + +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are callback functions against generic Opaque-LSAs handling. + *------------------------------------------------------------------------*/ +static void +ospf_router_info_ism_change (struct ospf_interface *oi, int old_state) +{ + /* So far, nothing to do here. */ + return; + +} + +static void +ospf_router_info_nsm_change (struct ospf_neighbor *nbr, int old_state) +{ + + /* So far, nothing to do here. */ + return; +} + +/*------------------------------------------------------------------------* + * Followings are OSPF protocol processing functions for ROUTER INFORMATION + *------------------------------------------------------------------------*/ + +static void +build_tlv_header (struct stream *s, struct ri_tlv_header *tlvh) +{ + + stream_put (s, tlvh, sizeof (struct ri_tlv_header)); + return; +} + +static void +build_tlv (struct stream *s, struct ri_tlv_header *tlvh) +{ + + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh + 1, RI_TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +ospf_router_info_lsa_body_set (struct stream *s) +{ + + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + + /* Build Router Information TLV */ + build_tlv (s, &OspfRI.router_cap.header); + + /* Add RI PCE TLV if it is set */ + /* Compute PCE Info header first */ + if ((set_pce_header (&OspfRI.pce_info)) != 0) + { + + /* Build PCE TLV */ + build_tlv_header (s, &OspfRI.pce_info.pce_header.header); + + /* Build PCE address sub-tlv */ + build_tlv (s, &OspfRI.pce_info.pce_address.header); + + /* Build PCE path scope sub-tlv */ + build_tlv (s, &OspfRI.pce_info.pce_scope.header); + + /* Build PCE domain sub-tlv */ + for (ALL_LIST_ELEMENTS_RO (OspfRI.pce_info.pce_domain, node, domain)) + build_tlv (s, &domain->header); + + /* Build PCE neighbor sub-tlv */ + for (ALL_LIST_ELEMENTS_RO + (OspfRI.pce_info.pce_neighbor, node, neighbor)) + build_tlv (s, &neighbor->header); + + /* Build PCE cap flag sub-tlv */ + build_tlv (s, &OspfRI.pce_info.pce_cap_flag.header); + } + + return; +} + +/* Create new opaque-LSA. */ +static struct ospf_lsa * +ospf_router_info_lsa_new () +{ + struct ospf *top; + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new = NULL; + u_char options, lsa_type; + struct in_addr lsa_id; + u_int32_t tmp; + u_int16_t length; + + /* Create a stream for LSA. */ + if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) + { + zlog_warn ("ospf_router_info_lsa_new: stream_new() ?"); + goto out; + } + lsah = (struct lsa_header *) STREAM_DATA (s); + + options = OSPF_OPTION_E; /* Enable AS external as we flood RI with Opaque Type 11 */ + options |= OSPF_OPTION_O; /* Don't forget this :-) */ + + lsa_type = OspfRI.scope; + /* LSA ID == 0 for Router Information see RFC 4970 */ + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); + lsa_id.s_addr = htonl (tmp); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_debug + ("LSA[Type%d:%s]: Create an Opaque-LSA/ROUTER INFORMATION instance", + lsa_type, inet_ntoa (lsa_id)); + + top = ospf_lookup (); + + /* Set opaque-LSA header fields. */ + lsa_header_set (s, options, lsa_type, lsa_id, top->router_id); + + /* Set opaque-LSA body fields. */ + ospf_router_info_lsa_body_set (s); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create an OSPF LSA instance. */ + if ((new = ospf_lsa_new ()) == NULL) + { + zlog_warn ("ospf_router_info_lsa_new: ospf_lsa_new() ?"); + stream_free (s); + goto out; + } + if ((new->data = ospf_lsa_data_new (length)) == NULL) + { + zlog_warn ("ospf_router_info_lsa_new: ospf_lsa_data_new() ?"); + ospf_lsa_unlock (&new); + new = NULL; + stream_free (s); + goto out; + } + + new->area = OspfRI.area; /* Area must be null if the Opaque type is AS scope, fulfill otherwise */ + + SET_FLAG (new->flags, OSPF_LSA_SELF); + memcpy (new->data, lsah, length); + stream_free (s); + +out:return new; +} + +static int +ospf_router_info_lsa_originate1 (void *arg) +{ + struct ospf_lsa *new; + struct ospf *top; + struct ospf_area *area; + int rc = -1; + + /* First check if the area is known if flooding scope is Area */ + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) + { + area = (struct ospf_area *) arg; + if (area->area_id.s_addr != OspfRI.area_id.s_addr) + { + zlog_debug + ("RI -> This is not the Router Information Area. Stop processing"); + goto out; + } + OspfRI.area = area; + } + + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + if ((new = ospf_router_info_lsa_new ()) == NULL) + { + zlog_warn + ("ospf_router_info_lsa_originate1: ospf_router_info_lsa_new() ?"); + goto out; + } + + /* Get ospf info */ + top = ospf_lookup (); + + /* Install this LSA into LSDB. */ + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) + { + zlog_warn ("ospf_router_info_lsa_originate1: ospf_lsa_install() ?"); + ospf_lsa_unlock (&new); + goto out; + } + + /* Now this Router Info parameter entry has associated LSA. */ + SET_FLAG (OspfRI.flags, RIFLG_LSA_ENGAGED); + + /* Update new LSA origination count. */ + top->lsa_originate_count++; + + /* Flood new LSA through AS. */ + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + ospf_flood_through_as (top, NULL /*nbr */ , new); + else + ospf_flood_through_area (OspfRI.area, NULL /*nbr */ , new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + rc = 0; +out:return rc; +} + +static int +ospf_router_info_lsa_originate (void *arg) +{ + + int rc = -1; + + if (OspfRI.status == disabled) + { + zlog_info + ("ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now."); + rc = 0; /* This is not an error case. */ + goto out; + } + + /* Check if Router Information LSA is already engaged */ + if (OspfRI.flags & RIFLG_LSA_ENGAGED) + { + if (OspfRI.flags & RIFLG_LSA_FORCED_REFRESH) + { + OspfRI.flags &= ~RIFLG_LSA_FORCED_REFRESH; + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + } + else + { + if (!is_mandated_params_set (OspfRI)) + zlog_warn + ("ospf_router_info_lsa_originate: lacks mandated ROUTER INFORMATION parameters"); + + /* Ok, let's try to originate an LSA */ + if (ospf_router_info_lsa_originate1 (arg) != 0) + goto out; + } + + rc = 0; +out:return rc; +} + +static struct ospf_lsa * +ospf_router_info_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new = NULL; + struct ospf *top; + + if (OspfRI.status == disabled) + { + /* + * This LSA must have flushed before due to ROUTER INFORMATION status change. + * It seems a slip among routers in the routing domain. + */ + zlog_info + ("ospf_router_info_lsa_refresh: ROUTER INFORMATION is disabled now."); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + + /* Verify that the Router Information ID is supported */ + if (GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)) != 0) + { + zlog_warn + ("ospf_router_info_lsa_refresh: Unsupported Router Information ID"); + goto out; + } + + /* If the lsa's age reached to MaxAge, start flushing procedure. */ + if (IS_LSA_MAXAGE (lsa)) + { + OspfRI.flags &= ~RIFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (lsa); + goto out; + } + + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + if ((new = ospf_router_info_lsa_new ()) == NULL) + { + zlog_warn + ("ospf_router_info_lsa_refresh: ospf_router_info_lsa_new() ?"); + goto out; + } + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Install this LSA into LSDB. */ + /* Given "lsa" will be freed in the next function. */ + top = ospf_lookup (); + if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) + { + zlog_warn ("ospf_router_info_lsa_refresh: ospf_lsa_install() ?"); + ospf_lsa_unlock (&new); + goto out; + } + + /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */ + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + ospf_flood_through_as (top, NULL /*nbr */ , new); + else + ospf_flood_through_area (OspfRI.area, NULL /*nbr */ , new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_debug ("LSA[Type%d:%s]: Refresh Opaque-LSA/ROUTER INFORMATION", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + +out:return new; +} + +static void +ospf_router_info_lsa_schedule (opcode_t opcode) +{ + struct ospf_lsa lsa; + struct lsa_header lsah; + struct ospf *top; + u_int32_t tmp; + + memset (&lsa, 0, sizeof (lsa)); + memset (&lsah, 0, sizeof (lsah)); + + zlog_debug ("RI-> LSA schedule %s%s%s", + opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", + opcode == REFRESH_THIS_LSA ? "Refresh" : "", + opcode == FLUSH_THIS_LSA ? "Flush" : ""); + + top = ospf_lookup (); + if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) + { + zlog_warn + ("ospf_router_info_lsa_schedule(): Router Info is Area scope flooding but area is not set"); + OspfRI.area = ospf_area_lookup_by_area_id (top, OspfRI.area_id); + } + lsa.area = OspfRI.area; + lsa.data = &lsah; + lsah.type = OspfRI.scope; + + /* LSA ID is set to 0 for the Router Information. See RFC 4970 */ + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); + lsah.id.s_addr = htonl (tmp); + + switch (opcode) + { + case REORIGINATE_THIS_LSA: + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) + ospf_opaque_lsa_reoriginate_schedule ((void *) OspfRI.area, + OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA); + else + ospf_opaque_lsa_reoriginate_schedule ((void *) top, + OSPF_OPAQUE_AS_LSA, + OPAQUE_TYPE_ROUTER_INFORMATION_LSA); + break; + case REFRESH_THIS_LSA: + ospf_opaque_lsa_refresh_schedule (&lsa); + break; + case FLUSH_THIS_LSA: + OspfRI.flags &= ~RIFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (&lsa); + break; + default: + zlog_warn ("ospf_router_info_lsa_schedule: Unknown opcode (%u)", + opcode); + break; + } + + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty session control functions. + *------------------------------------------------------------------------*/ + +static u_int16_t +show_vty_router_cap (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *) tlvh; + + if (vty != NULL) + vty_out (vty, " Router Capabilities: 0x%x%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" Router Capabilities: 0x%x", ntohl (top->value)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_address (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_address *top = (struct ri_pce_subtlv_address *) tlvh; + + if (ntohs (top->address.type) == PCE_ADDRESS_TYPE_IPV4) + { + if (vty != NULL) + vty_out (vty, " PCE Address: %s%s", inet_ntoa (top->address.value), + VTY_NEWLINE); + else + zlog_debug (" PCE Address: %s", inet_ntoa (top->address.value)); + } + else + { + /* TODO: Add support to IPv6 with inet_ntop() */ + if (vty != NULL) + vty_out (vty, " PCE Address: 0x%x%s", + ntohl (top->address.value.s_addr), VTY_NEWLINE); + else + zlog_debug (" PCE Address: 0x%x", + ntohl (top->address.value.s_addr)); + } + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_path_scope (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_path_scope *top = + (struct ri_pce_subtlv_path_scope *) tlvh; + + if (vty != NULL) + vty_out (vty, " PCE Path Scope: 0x%x%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE Path Scope: 0x%x", ntohl (top->value)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_domain (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *) tlvh; + struct in_addr tmp; + + if (ntohs (top->type) == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = top->value; + if (vty != NULL) + vty_out (vty, " PCE domain Area: %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + else + zlog_debug (" PCE domain Area: %s", inet_ntoa (tmp)); + } + else + { + if (vty != NULL) + vty_out (vty, " PCE domain AS: %d%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE domain AS: %d", ntohl (top->value)); + } + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_neighbor (struct vty *vty, struct ri_tlv_header *tlvh) +{ + + struct ri_pce_subtlv_neighbor *top = (struct ri_pce_subtlv_neighbor *) tlvh; + struct in_addr tmp; + + if (ntohs (top->type) == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = top->value; + if (vty != NULL) + vty_out (vty, " PCE neighbor Area: %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + else + zlog_debug (" PCE neighbor Area: %s", inet_ntoa (tmp)); + } + else + { + if (vty != NULL) + vty_out (vty, " PCE neighbor AS: %d%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE neighbor AS: %d", ntohl (top->value)); + } + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_subtlv_cap_flag (struct vty *vty, struct ri_tlv_header *tlvh) +{ + struct ri_pce_subtlv_cap_flag *top = (struct ri_pce_subtlv_cap_flag *) tlvh; + + if (vty != NULL) + vty_out (vty, " PCE Capabilities Flag: 0x%x%s", ntohl (top->value), + VTY_NEWLINE); + else + zlog_debug (" PCE Capabilities Flag: 0x%x", ntohl (top->value)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_unknown_tlv (struct vty *vty, struct ri_tlv_header *tlvh) +{ + if (vty != NULL) + vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", + ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); + else + zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", + ntohs (tlvh->type), ntohs (tlvh->length)); + + return RI_TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_pce_info (struct vty *vty, struct ri_tlv_header *ri, uint32_t total) +{ + struct ri_tlv_header *tlvh; + u_int16_t sum = 0; + + for (tlvh = ri; sum < total; tlvh = RI_TLV_HDR_NEXT (tlvh)) + { + switch (ntohs (tlvh->type)) + { + case RI_PCE_SUBTLV_ADDRESS: + sum += show_vty_pce_subtlv_address (vty, tlvh); + break; + case RI_PCE_SUBTLV_PATH_SCOPE: + sum += show_vty_pce_subtlv_path_scope (vty, tlvh); + break; + case RI_PCE_SUBTLV_DOMAIN: + sum += show_vty_pce_subtlv_domain (vty, tlvh); + break; + case RI_PCE_SUBTLV_NEIGHBOR: + sum += show_vty_pce_subtlv_neighbor (vty, tlvh); + break; + case RI_PCE_SUBTLV_CAP_FLAG: + sum += show_vty_pce_subtlv_cap_flag (vty, tlvh); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return sum; +} + +static void +ospf_router_info_show_info (struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = (struct lsa_header *) lsa->data; + struct ri_tlv_header *tlvh; + u_int16_t length = 0, sum = 0; + + /* Initialize TLV browsing */ + length = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; + + for (tlvh = RI_TLV_HDR_TOP (lsah); sum < length; + tlvh = RI_TLV_HDR_NEXT (tlvh)) + { + switch (ntohs (tlvh->type)) + { + case RI_TLV_CAPABILITIES: + sum += show_vty_router_cap (vty, tlvh); + break; + case RI_TLV_PCE: + tlvh++; + sum += RI_TLV_HDR_SIZE; + sum += show_vty_pce_info (vty, tlvh, length - sum); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + + return; +} + +static void +ospf_router_info_config_write_router (struct vty *vty) +{ + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + struct in_addr tmp; + + if (OspfRI.status == enabled) + { + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + vty_out (vty, " router-info as%s", VTY_NEWLINE); + else + vty_out (vty, " router-info area %s%s", inet_ntoa (OspfRI.area_id), + VTY_NEWLINE); + + if (pce->pce_address.header.type != 0) + vty_out (vty, " pce address %s%s", + inet_ntoa (pce->pce_address.address.value), VTY_NEWLINE); + + if (pce->pce_cap_flag.header.type != 0) + vty_out (vty, " pce flag 0x%x%s", ntohl (pce->pce_cap_flag.value), + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (domain->header.type != 0) + { + if (domain->type == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = domain->value; + vty_out (vty, " pce domain area %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + } + else + { + vty_out (vty, " pce domain as %d%s", ntohl (domain->value), + VTY_NEWLINE); + } + } + } + + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (neighbor->header.type != 0) + { + if (neighbor->type == PCE_DOMAIN_TYPE_AREA) + { + tmp.s_addr = neighbor->value; + vty_out (vty, " pce neighbor area %s%s", inet_ntoa (tmp), + VTY_NEWLINE); + } + else + { + vty_out (vty, " pce neighbor as %d%s", + ntohl (neighbor->value), VTY_NEWLINE); + } + } + } + + if (pce->pce_scope.header.type != 0) + vty_out (vty, " pce scope 0x%x%s", + ntohl (OspfRI.pce_info.pce_scope.value), VTY_NEWLINE); + } + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty command functions. + *------------------------------------------------------------------------*/ + +DEFUN (router_info, + router_info_area_cmd, + "router-info area A.B.C.D", + OSPF_RI_STR + "Enable the Router Information functionality with Area flooding scope\n" + "OSPF area ID in IP format") +{ + + u_int8_t scope; + + if (OspfRI.status == enabled) + return CMD_SUCCESS; + + /* Check and get Area value if present */ + if (argc == 1) + { + if (!inet_aton (argv[0], &OspfRI.area_id)) + { + vty_out (vty, "Please specify Router Info Area by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + scope = OSPF_OPAQUE_AREA_LSA; + } + else + { + OspfRI.area_id.s_addr = 0; + scope = OSPF_OPAQUE_AS_LSA; + } + + /* First start to register Router Information callbacks */ + if ((ospf_router_info_register (scope)) != 0) + { + zlog_warn ("Enable to register Router Information callbacks. Abort!"); + return CMD_WARNING; + } + + OspfRI.status = enabled; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("RI-> Router Information (%s flooding): OFF -> ON", + OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); + + /* + * Following code is intended to handle two cases; + * + * 1) Router Information was disabled at startup time, but now become enabled. + * 2) Router Information was once enabled then disabled, and now enabled again. + */ + + initialize_params (&OspfRI); + + /* Refresh RI LSA if already engaged */ + if (OspfRI.flags & RIFLG_LSA_ENGAGED) + { + zlog_debug ("RI-> Initial origination following configuration"); + ospf_router_info_lsa_schedule (REORIGINATE_THIS_LSA); + } + return CMD_SUCCESS; + +} + +ALIAS (router_info, + router_info_as_cmd, + "router-info as", + OSPF_RI_STR + "Enable the Router Information functionality with AS flooding scope\n") + +DEFUN (no_router_info, + no_router_info_cmd, + "no router-info", + NO_STR + "Disable the Router Information functionality\n") +{ + + if (OspfRI.status == disabled) + return CMD_SUCCESS; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("RI-> Router Information: ON -> OFF"); + + if (OspfRI.flags & RIFLG_LSA_ENGAGED) + ospf_router_info_lsa_schedule (FLUSH_THIS_LSA); + + /* Unregister the callbacks */ + ospf_router_info_unregister (); + + OspfRI.status = disabled; + + return CMD_SUCCESS; +} + +DEFUN (pce_address, + pce_address_cmd, + "pce address A.B.C.D", + PCE_STR + "Stable IP address of the PCE\n" + "PCE address in IPv4 address format\n") +{ + struct in_addr value; + struct ospf_pce_info *pi = &OspfRI.pce_info; + + if (!inet_aton (argv[0], &value)) + { + vty_out (vty, "Please specify PCE Address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (pi->pce_address.header.type) == 0 + || ntohl (pi->pce_address.address.value.s_addr) != ntohl (value.s_addr)) + { + + set_pce_address (value, pi); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + + return CMD_SUCCESS; +} + +DEFUN (no_pce_address, + no_pce_address_cmd, + "no pce address", + NO_STR + PCE_STR + "Disable PCE address\n") +{ + + unset_param (&OspfRI.pce_info.pce_address.header); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_path_scope, + pce_path_scope_cmd, + "pce scope BITPATTERN", + PCE_STR + "Path scope visibilities of the PCE for path computation\n" + "32-bit Hexadecimal value\n") +{ + uint32_t scope; + struct ospf_pce_info *pi = &OspfRI.pce_info; + + if (sscanf (argv[0], "0x%x", &scope) != 1) + { + vty_out (vty, "pce_path_scope: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohl (pi->pce_scope.header.type) == 0 || scope != pi->pce_scope.value) + { + set_pce_path_scope (scope, pi); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + + return CMD_SUCCESS; +} + +DEFUN (no_pce_path_scope, + no_pce_path_scope_cmd, + "no pce scope", + NO_STR + PCE_STR + "Disable PCE path scope\n") +{ + + unset_param (&OspfRI.pce_info.pce_address.header); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_domain, + pce_domain_cmd, + "pce domain as <0-65535>", + PCE_STR + "Configure PCE domain AS number\n" + "AS number where the PCE as visibilities for path computation\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "pce_domain: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check if the domain is not already in the domain list */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (ntohl (domain->header.type) == 0 && as == domain->value) + goto out; + } + + /* Create new domain if not found */ + set_pce_domain (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + +out:return CMD_SUCCESS; +} + +DEFUN (no_pce_domain, + no_pce_domain_cmd, + "no pce domain as <0-65535>", + NO_STR + PCE_STR + "Disable PCE domain AS number\n" + "AS number where the PCE as visibilities for path computation\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "no_pce_domain: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Unset corresponding PCE domain */ + unset_pce_domain (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_neigbhor, + pce_neighbor_cmd, + "pce neighbor as <0-65535>", + PCE_STR + "Configure PCE neighbor domain AS number\n" + "AS number of PCE neighbors\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_neighbor *neighbor; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "pce_neighbor: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check if the domain is not already in the domain list */ + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (ntohl (neighbor->header.type) == 0 && as == neighbor->value) + goto out; + } + + /* Create new domain if not found */ + set_pce_neighbor (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + +out:return CMD_SUCCESS; +} + +DEFUN (no_pce_neighbor, + no_pce_neighbor_cmd, + "no pce neighbor as <0-65535>", + NO_STR + PCE_STR + "Disable PCE neighbor AS number\n" + "AS number of PCE neighbor\n" + "AS number in decimal <0-65535>\n") +{ + + uint32_t as; + struct ospf_pce_info *pce = &OspfRI.pce_info; + + if (sscanf (argv[0], "%d", &as) != 1) + { + vty_out (vty, "no_pce_neighbor: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Unset corresponding PCE domain */ + unset_pce_neighbor (PCE_DOMAIN_TYPE_AS, as, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (pce_cap_flag, + pce_cap_flag_cmd, + "pce flag BITPATTERN", + PCE_STR + "Capabilities of the PCE for path computation\n" + "32-bit Hexadecimal value\n") +{ + + uint32_t cap; + struct ospf_pce_info *pce = &OspfRI.pce_info; + + if (sscanf (argv[0], "0x%x", &cap) != 1) + { + vty_out (vty, "pce_cap_flag: fscanf: %s%s", safe_strerror (errno), + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohl (pce->pce_cap_flag.header.type) == 0 + || cap != pce->pce_cap_flag.value) + { + set_pce_cap_flag (cap, pce); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } + + return CMD_SUCCESS; +} + +DEFUN (no_pce_cap_flag, + no_pce_cap_flag_cmd, + "no pce flag", + NO_STR + PCE_STR + "Disable PCE capabilities\n") +{ + + unset_param (&OspfRI.pce_info.pce_cap_flag.header); + + /* Refresh RI LSA if already engaged */ + if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_router_info, + show_ip_ospf_router_info_cmd, + "show ip ospf router-info", + SHOW_STR + IP_STR + OSPF_STR + "Router Information\n") +{ + + if (OspfRI.status == enabled) + { + vty_out (vty, "--- Router Information parameters ---%s", VTY_NEWLINE); + show_vty_router_cap (vty, &OspfRI.router_cap.header); + } + else + { + if (vty != NULL) + vty_out (vty, " Router Information is disabled on this router%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_opsf_router_info_pce, + show_ip_ospf_router_info_pce_cmd, + "show ip ospf router-info pce", + SHOW_STR + IP_STR + OSPF_STR + "Router Information\n" + "PCE information\n") +{ + + struct ospf_pce_info *pce = &OspfRI.pce_info; + struct listnode *node; + struct ri_pce_subtlv_domain *domain; + struct ri_pce_subtlv_neighbor *neighbor; + + if (OspfRI.status == enabled) + { + vty_out (vty, "--- PCE parameters ---%s", VTY_NEWLINE); + + if (pce->pce_address.header.type != 0) + show_vty_pce_subtlv_address (vty, &pce->pce_address.header); + + if (pce->pce_scope.header.type != 0) + show_vty_pce_subtlv_path_scope (vty, &pce->pce_scope.header); + + for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) + { + if (domain->header.type != 0) + show_vty_pce_subtlv_domain (vty, &domain->header); + } + + for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) + { + if (neighbor->header.type != 0) + show_vty_pce_subtlv_neighbor (vty, &neighbor->header); + } + + if (pce->pce_cap_flag.header.type != 0) + show_vty_pce_subtlv_cap_flag (vty, &pce->pce_cap_flag.header); + + } + else + { + vty_out (vty, " Router Information is disabled on this router%s", + VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +/* Install new CLI commands */ +static void +ospf_router_info_register_vty (void) +{ + install_element (VIEW_NODE, &show_ip_ospf_router_info_cmd); + install_element (VIEW_NODE, &show_ip_ospf_router_info_pce_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_router_info_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_router_info_pce_cmd); + + install_element (OSPF_NODE, &router_info_area_cmd); + install_element (OSPF_NODE, &router_info_as_cmd); + install_element (OSPF_NODE, &no_router_info_cmd); + install_element (OSPF_NODE, &pce_address_cmd); + install_element (OSPF_NODE, &pce_path_scope_cmd); + install_element (OSPF_NODE, &pce_domain_cmd); + install_element (OSPF_NODE, &no_pce_domain_cmd); + install_element (OSPF_NODE, &pce_neighbor_cmd); + install_element (OSPF_NODE, &no_pce_neighbor_cmd); + install_element (OSPF_NODE, &pce_cap_flag_cmd); + + return; +} diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h new file mode 100644 index 000000000..c507434e4 --- /dev/null +++ b/ospfd/ospf_ri.h @@ -0,0 +1,191 @@ +/* + * This is an implementation of RFC4970 Router Information + * with support of RFC5088 PCE Capabilites announcement + * + * Module name: Router Information + * Version: 0.99.22 + * Created: 2012-02-01 by Olivier Dugeon + * Copyright (C) 2012 Orange Labs http://www.orange.com/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ROUTER_INFO_H +#define _ZEBRA_OSPF_ROUTER_INFO_H + +/* + * Opaque LSA's link state ID for Router Information is + * structured as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * | 1 | MBZ |........|........| + * +--------+--------+--------+--------+ + * |<-Type->||<-- Instance --->| + * + * + * Type: IANA has assigned '4' for Router Information. + * MBZ: Reserved, must be set to zero. + * Instance: User may select an arbitrary 16-bit value. + * + */ + +/* + * 24 16 8 0 + * +--------+--------+--------+--------+ --- + * | LS age |Options | 9,10,11| A + * +--------+--------+--------+--------+ | + * | 4 | 0 | Instance | | + * +--------+--------+--------+--------+ | + * | Advertising router | | Standard (Opaque) LSA header; + * +--------+--------+--------+--------+ | Type 9,10 or 11 are used. + * | LS sequence number | | + * +--------+--------+--------+--------+ | + * | LS checksum | Length | V + * +--------+--------+--------+--------+ --- + * | Type | Length | A + * +--------+--------+--------+--------+ | TLV part for Router Information; Values might be + * | Values ... | V structured as a set of sub-TLVs. + * +--------+--------+--------+--------+ --- + */ + +/* + * Following section defines TLV (tag, length, value) structures, + * used for Router Information. + */ +struct ri_tlv_header +{ + u_int16_t type; /* RI_TLV_XXX (see below) */ + u_int16_t length; /* Value portion only, in byte */ +}; + +#define RI_TLV_HDR_SIZE (sizeof (struct ri_tlv_header)) +#define RI_TLV_BODY_SIZE(tlvh) (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))) +#define RI_TLV_SIZE(tlvh) (RI_TLV_HDR_SIZE + RI_TLV_BODY_SIZE(tlvh)) +#define RI_TLV_HDR_TOP(lsah) (struct ri_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) +#define RI_TLV_HDR_NEXT(tlvh) (struct ri_tlv_header *)((char *)(tlvh) + RI_TLV_SIZE(tlvh)) + +/* + * Following section defines TLV body parts. + */ + +/* Up to now, 8 code point have been assigned to Router Information */ +/* Only type 1 Router Capabilities and 6 PCE are supported with this code */ +#define RI_IANA_MAX_TYPE 8 + +/* RFC4970: Router Information Capabilities TLV */ /* Mandatory */ +#define RI_TLV_CAPABILITIES 1 + +struct ri_tlv_router_cap +{ + struct ri_tlv_header header; /* Value length is 4 bytes. */ + u_int32_t value; +}; + +#define RI_GRACE_RESTART 0x01 +#define RI_GRACE_HELPER 0x02 +#define RI_STUB_SUPPORT 0x04 +#define RI_TE_SUPPORT 0x08 +#define RI_P2P_OVER_LAN 0x10 +#define RI_TE_EXPERIMENTAL 0x20 + +#define RI_TLV_LENGTH 4 + +/* RFC5088: PCE Capabilities TLV */ /* Optional */ +/* RI PCE TLV */ +#define RI_TLV_PCE 6 + +struct ri_tlv_pce +{ + struct ri_tlv_header header; +/* A set of PCE-sub-TLVs will follow. */ +}; + +/* PCE Address Sub-TLV */ /* Mandatory */ +#define RI_PCE_SUBTLV_ADDRESS 1 +struct ri_pce_subtlv_address +{ + struct ri_tlv_header header; /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */ +#define PCE_ADDRESS_LENGTH_IPV4 8 +#define PCE_ADDRESS_LENGTH_IPV6 20 + struct + { + u_int16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */ +#define PCE_ADDRESS_TYPE_IPV4 1 +#define PCE_ADDRESS_TYPE_IPV6 2 + u_int16_t reserved; + struct in_addr value; /* PCE address */ + } address; +}; + +/* PCE Path-Scope Sub-TLV */ /* Mandatory */ +#define RI_PCE_SUBTLV_PATH_SCOPE 2 +struct ri_pce_subtlv_path_scope +{ + struct ri_tlv_header header; /* Type = 2; Length = 4 bytes. */ + u_int32_t value; /* L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY bits see RFC5088 page 9 */ +}; + +/* PCE Domain Sub-TLV */ /* Optional */ +#define RI_PCE_SUBTLV_DOMAIN 3 + +#define PCE_DOMAIN_TYPE_AREA 1 +#define PCE_DOMAIN_TYPE_AS 2 + +struct ri_pce_subtlv_domain +{ + struct ri_tlv_header header; /* Type = 3; Length = 8 bytes. */ + u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ + u_int16_t reserved; + u_int32_t value; +}; + +/* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */ +#define RI_PCE_SUBTLV_NEIGHBOR 4 +struct ri_pce_subtlv_neighbor +{ + struct ri_tlv_header header; /* Type = 4; Length = 8 bytes. */ + u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ + u_int16_t reserved; + u_int32_t value; +}; + +/* PCE Capabilities Flags Sub-TLV */ /* Optional */ +#define RI_PCE_SUBTLV_CAP_FLAG 5 + +#define PCE_CAP_GMPLS_LINK 0x0001 +#define PCE_CAP_BIDIRECTIONAL 0x0002 +#define PCE_CAP_DIVERSE_PATH 0x0004 +#define PCE_CAP_LOAD_BALANCE 0x0008 +#define PCE_CAP_SYNCHRONIZED 0x0010 +#define PCE_CAP_OBJECTIVES 0x0020 +#define PCE_CAP_ADDITIVE 0x0040 +#define PCE_CAP_PRIORIZATION 0x0080 +#define PCE_CAP_MULTIPLE_REQ 0x0100 + +struct ri_pce_subtlv_cap_flag +{ + struct ri_tlv_header header; /* Type = 5; Length = n x 4 bytes. */ + u_int32_t value; +}; + +/* Prototypes. */ +extern int ospf_router_info_init (void); +extern void ospf_router_info_term (void); + +#endif /* _ZEBRA_OSPF_ROUTER_INFO_H */ From 3676cb0c029c8f8f06ab703dd441c1e23e5ef333 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 29 Jul 2016 13:39:37 +0100 Subject: [PATCH 1057/1342] *: Remove some for statement declarations We generally require C99. Some compilers, e.g. gcc, barf on 'for' statement declared variables, if std={gnu,c}99 or higher is not given - even while seemingly accepting other C99 constructs. As it's trivial, remove these. --- lib/if.c | 4 +++- lib/zclient.c | 3 ++- zebra/interface.c | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/if.c b/lib/if.c index 45c1accf0..0fc4b609c 100644 --- a/lib/if.c +++ b/lib/if.c @@ -1131,6 +1131,8 @@ if_link_type_str (enum zebra_link_type llt) struct if_link_params * if_link_params_get (struct interface *ifp) { + int i; + if (ifp->link_params != NULL) return ifp->link_params; @@ -1148,7 +1150,7 @@ if_link_params_get (struct interface *ifp) /* Set Max, Reservable and Unreserved Bandwidth */ iflp->max_bw = bw; iflp->max_rsv_bw = bw; - for (int i = 0; i < MAX_CLASS_TYPE; i++) + for (i = 0; i < MAX_CLASS_TYPE; i++) iflp->unrsv_bw[i] = bw; /* Update Link parameters status */ diff --git a/lib/zclient.c b/lib/zclient.c index c2e133310..09bb1807d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -886,6 +886,7 @@ zebra_interface_link_params_write (struct stream *s, struct interface *ifp) { size_t w; struct if_link_params *iflp; + int i; if (s == NULL || ifp == NULL || ifp->link_params == NULL) return 0; @@ -900,7 +901,7 @@ zebra_interface_link_params_write (struct stream *s, struct interface *ifp) w += stream_putf (s, iflp->max_rsv_bw); w += stream_putl (s, MAX_CLASS_TYPE); - for (int i = 0; i < MAX_CLASS_TYPE; i++) + for (i = 0; i < MAX_CLASS_TYPE; i++) w += stream_putf (s, iflp->unrsv_bw[i]); w += stream_putl (s, iflp->admin_grp); diff --git a/zebra/interface.c b/zebra/interface.c index 6fa097f6f..f259eeb2e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -2487,6 +2487,8 @@ DEFUN (no_ipv6_address, static int link_params_config_write (struct vty *vty, struct interface *ifp) { + int i; + if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) return -1; @@ -2502,7 +2504,7 @@ link_params_config_write (struct vty *vty, struct interface *ifp) vty_out(vty, " max-rsv-bw %g%s", iflp->max_rsv_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { - for (int i = 0; i < 8; i++) + for (i = 0; i < 8; i++) vty_out(vty, " unrsv-bw %d %g%s", i, iflp->unrsv_bw[i], VTY_NEWLINE); } From 0ffd69a9bf58ab2e0105336f10753293230a4360 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 3 Aug 2016 15:22:39 +0100 Subject: [PATCH 1058/1342] doc: Add isisd.texi to quagga_TEXINFOS so it gets in dist tarball --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 00d404a74..42af37c73 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -50,7 +50,7 @@ quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ - snmptrap.texi ospf_fundamentals.texi $(figures_txt) + snmptrap.texi ospf_fundamentals.texi isisd.texi $(figures_txt) .png.eps: $(PNGTOEPS) $< "$@" From 220355df533f9c127c32de296513fae180c1568d Mon Sep 17 00:00:00 2001 From: Andrej Ota Date: Mon, 9 May 2016 20:49:01 +0200 Subject: [PATCH 1059/1342] bgpd: fix BGP IPv6 route map error BGP refactoring in commit f3cfc46450cccc5ac035a5a97c5a1a5484205705 introduced an error which broke route map processing for IPv6 where AFI_IP was used instead of AFI_IP6. This patch fixes the typo. Signed-off-by: Andrej Ota Tested-by: NetDEF CI System --- bgpd/bgp_routemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 39fa08c86..98d5f1f1b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2389,7 +2389,7 @@ bgp_route_map_update (const char *unused) route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); if (bgp->rmap[AFI_IP6][i].name) bgp->rmap[AFI_IP6][i].map = - route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); + route_map_lookup_by_name (bgp->rmap[AFI_IP6][i].name); } } } From 06de82eaeb11a1c84798cc222af77cdb07af2e4e Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Mon, 9 May 2016 15:18:56 -0500 Subject: [PATCH 1060/1342] pimd: send pim prune via correct interface when rpf upstream interface for a source changes When the rpf upstream interface for a joined source changes, a prune was being sent out the new rpf upstream interface that was intended for the old upstream router. The prune should be sent out the old rpf upstream interface so that the old route for the multicast source is pruned. Reviewed-by: Jafar Al-Gharaibeh Signed-off-by: Taylor Bouvin Tested-by: NetDEF CI System --- pimd/pim_rpf.c | 12 ++++++------ pimd/pim_rpf.h | 2 +- pimd/pim_zebra.c | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 38339da1b..e7619a5cc 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -121,14 +121,14 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1, } enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, - struct in_addr *old_rpf_addr) + struct pim_rpf *old_rpf) { - struct in_addr save_rpf_addr; struct pim_nexthop save_nexthop; + struct pim_rpf save_rpf; struct pim_rpf *rpf = &up->rpf; save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */ - save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */ + save_rpf = up->rpf; if (pim_nexthop_lookup(&rpf->source_nexthop, up->source_addr)) { @@ -193,11 +193,11 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, } /* detect change in RPF'(S,G) */ - if (save_rpf_addr.s_addr != rpf->rpf_addr.s_addr) { + if (save_rpf.rpf_addr.s_addr != rpf->rpf_addr.s_addr) { /* return old rpf to caller ? */ - if (old_rpf_addr) - *old_rpf_addr = save_rpf_addr; + if (old_rpf) + *old_rpf = save_rpf; return PIM_RPF_CHANGED; } diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index 078e89f3e..9a48ea017 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -31,6 +31,6 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr); enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, - struct in_addr *old_rpf_addr); + struct pim_rpf *old_rpf); #endif /* PIM_RPF_H */ diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 8f85b17bb..0a07c0615 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -341,10 +341,10 @@ static void scan_upstream_rpf_cache() struct pim_upstream *up; for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { - struct in_addr old_rpf_addr; + struct pim_rpf old_rpf; enum pim_rpf_result rpf_result; - rpf_result = pim_rpf_update(up, &old_rpf_addr); + rpf_result = pim_rpf_update(up, &old_rpf); if (rpf_result == PIM_RPF_FAILURE) continue; @@ -368,8 +368,8 @@ static void scan_upstream_rpf_cache() /* send Prune(S,G) to the old upstream neighbor */ - pim_joinprune_send(up->rpf.source_nexthop.interface, - old_rpf_addr, + pim_joinprune_send(old_rpf.source_nexthop.interface, + old_rpf.rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); From 49c370b74df11832239408f68119bd0a0a19a6e8 Mon Sep 17 00:00:00 2001 From: Colin Petrie Date: Wed, 11 May 2016 11:56:58 +0200 Subject: [PATCH 1061/1342] bgpd: fix MRT table dumps for locally-originated routes I've been working on a small patch to correct an issue in the BGP MRT table dump code. It's a quick'n'easy fix initially, and I'd appreciate any feedback on making it better :) Issue: When the BGP table dump code runs, it generates the peer_index_table. This walks the list of peers, and dumps out their IP, ASN, address family, etc. It also sets the peer index number in the peer struct. Then the code walks the RIB, and for each prefix, writes out RIB entries, that refer to the peer index number. However, when it finds prefixes that are locally originated, the associated peer is the 'self' peer, which wasn't in the list of peers, never gets an index number assigned, but because it is calloc'd, the index number is set to 0. End result: locally-originated routes are associated with whichever peer happens to be first in the list of remote peers in the index table :) Example (from one of our route collectors) - these are two of our originated prefixes (bgpdump output): TABLE_DUMP2|1457568002|B|12.0.1.63|7018|84.205.80.0/24||IGP|193.0.4.28|0|0||NAG|64512 10.255.255.255| TABLE_DUMP2|1457568006|B|12.0.1.63|7018|2001:7fb:ff00::/48||IGP|::|0|0||NAG|| The prefixes are announced by us (note it has an empty AS PATH (the field after the prefix)) but also looks like it was received from AS7018 (12.0.1.63). In fact, the AS7018 peer just happens to be the first peer in the index table. Fix: The simplest fix (which is also the method adopted by both OpenBGPd and the BIRD mrtdump branch) is to create an empty placeholder 'peer' at the start of the peer index table, for all the routes which are locally originated to refer to. I've attached a patch for this. Here's a resulting bgpdump output after the patch: TABLE_DUMP2|1458828539|B|0.0.0.0|0|93.175.150.0/24||IGP|0.0.0.0|0|0||NAG|| Now it is more obvious that the prefix is locally originated. There are more complicated potential ways of fixing it 1) skip the local routes when dumping the RIB. This leads to questions about what an MRT table dump *should* contain :) 2) include the 'self' peer in the list of peers used to generate the index table. etc etc. But I'm quite happy with my 'create a fake peer, and associate local routes with it' method :) Your thoughts and feedback are welcome! Regards, Colin Petrie Systems Engineer RIPE NCC RIS Project Tested-by: NetDEF CI System --- bgpd/bgp_dump.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 1fa0e658e..da0c2ac33 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -226,7 +226,7 @@ bgp_dump_routes_index_table(struct bgp *bgp) { struct peer *peer; struct listnode *node; - uint16_t peerno = 0; + uint16_t peerno = 1; struct stream *obuf; obuf = bgp_dump_obuf; @@ -250,8 +250,18 @@ bgp_dump_routes_index_table(struct bgp *bgp) stream_putw(obuf, 0); } - /* Peer count */ - stream_putw (obuf, listcount(bgp->peer)); + /* Peer count ( plus one extra internal peer ) */ + stream_putw (obuf, listcount(bgp->peer) + 1); + + /* Populate fake peer at index 0, for locally originated routes */ + /* Peer type (IPv4) */ + stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); + /* Peer BGP ID (0.0.0.0) */ + stream_putl (obuf, 0); + /* Peer IP address (0.0.0.0) */ + stream_putl (obuf, 0); + /* Peer ASN (0) */ + stream_putl (obuf, 0); /* Walk down all peers */ for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) From 93b493a2b010df4f67c7173c0928c8f86d9e1aa2 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Wed, 11 May 2016 15:26:39 +0300 Subject: [PATCH 1062/1342] bgpd: fix wrong help strings of "match peer" and "no match peer" commands Signed-off-by: Igor Ryzhov Tested-by: NetDEF CI System --- bgpd/bgp_routemap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 98d5f1f1b..8d3a8f560 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2399,8 +2399,8 @@ DEFUN (match_peer, "match peer (A.B.C.D|X:X::X:X)", MATCH_STR "Match peer address\n" - "IPv6 address of peer\n" - "IP address of peer\n") + "IP address of peer\n" + "IPv6 address of peer\n") { return bgp_route_match_add (vty, vty->index, "peer", argv[0]); } @@ -2434,8 +2434,8 @@ ALIAS (no_match_peer, NO_STR MATCH_STR "Match peer address\n" - "IPv6 address of peer\n" - "IP address of peer\n") + "IP address of peer\n" + "IPv6 address of peer\n") ALIAS (no_match_peer, no_match_peer_local_cmd, From b8cb7c3fd44cfd0781a5e80a369ecb19eee9a4a7 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 17 May 2016 07:10:33 -0400 Subject: [PATCH 1063/1342] lib: fix memory leak in zprivs_caps_init --- lib/privs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/privs.c b/lib/privs.c index e6d76b600..3fb96aed1 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -307,11 +307,18 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) current_caps = cap_get_proc(); if (current_caps) + { current_caps_text = cap_to_text(current_caps, NULL); + cap_free(current_caps); + } wanted_caps_text = cap_to_text(zprivs_state.caps, NULL); fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???"); fprintf(stderr, "Have caps: %s\n", current_caps_text ? current_caps_text : "???"); + if (current_caps_text) + cap_free(current_caps_text); + if (wanted_caps_text) + cap_free(wanted_caps_text); exit (1); } From ee5fbe26f2b7561457a1d0c8b5ce72b512638cb0 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 17 May 2016 07:10:38 -0400 Subject: [PATCH 1064/1342] lib: dump memory stats on core --- lib/sigevent.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sigevent.c b/lib/sigevent.c index c80a72901..a120028d8 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -237,6 +237,8 @@ core_handler(int signo , siginfo, program_counter(context) #endif ); + /* dump memory stats on core */ + log_memstats_stderr ("core_handler"); abort(); } From d83b8d6d73021815a87e000c50863a105af80226 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 17 May 2016 07:10:41 -0400 Subject: [PATCH 1065/1342] lib: add AF_ETHERNET/AFI_ETHER --- lib/plist.c | 5 +++ lib/prefix.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++- lib/prefix.h | 43 ++++++++++++++++++++ lib/zebra.h | 3 +- 4 files changed, 160 insertions(+), 3 deletions(-) diff --git a/lib/plist.c b/lib/plist.c index abce63376..2176c035a 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -734,6 +734,11 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, return CMD_WARNING; } break; + case AFI_ETHER: + default: + vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE); + return CMD_WARNING; + break; } /* ge and le check. */ diff --git a/lib/prefix.c b/lib/prefix.c index aeb627bd0..43fc31713 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -194,8 +194,9 @@ str2family(const char *string) return AF_INET; else if (!strcmp("ipv6", string)) return AF_INET6; - else - return -1; + else if (!strcmp("ethernet", string)) + return AF_ETHERNET; + return -1; } /* Address Famiy Identifier to Address Family converter. */ @@ -208,6 +209,8 @@ afi2family (afi_t afi) else if (afi == AFI_IP6) return AF_INET6; #endif /* HAVE_IPV6 */ + else if (afi == AFI_ETHER) + return AF_ETHERNET; return 0; } @@ -220,9 +223,25 @@ family2afi (int family) else if (family == AF_INET6) return AFI_IP6; #endif /* HAVE_IPV6 */ + else if (family == AF_ETHERNET) + return AFI_ETHER; return 0; } +const char * +afi2str(afi_t afi) +{ + switch (afi) { + case AFI_IP: + return "IPv4"; + case AFI_IP6: + return "IPv6"; + case AFI_ETHER: + return "ethernet"; + } + return NULL; +} + const char * safi2str(safi_t safi) { @@ -286,6 +305,10 @@ prefix_copy (struct prefix *dest, const struct prefix *src) dest->u.lp.id = src->u.lp.id; dest->u.lp.adv_router = src->u.lp.adv_router; } + else if (src->family == AF_ETHERNET) + { + dest->u.prefix_eth = src->u.prefix_eth; + } else { zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d", @@ -315,6 +338,10 @@ prefix_same (const struct prefix *p1, const struct prefix *p2) if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr)) return 1; #endif /* HAVE_IPV6 */ + if (p1->family == AF_ETHERNET) { + if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN)) + return 1; + } } return 0; } @@ -406,6 +433,8 @@ prefix_family_str (const struct prefix *p) if (p->family == AF_INET6) return "inet6"; #endif /* HAVE_IPV6 */ + if (p->family == AF_ETHERNET) + return "ether"; return "unspec"; } @@ -476,6 +505,60 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p) return ret; } +/* When string format is invalid return 0. */ +int +str2prefix_eth (const char *str, struct prefix_eth *p) +{ + int ret = 0; + int plen = 48; + char *pnt; + char *cp = NULL; + const char *str_addr = str; + unsigned int a[6]; + int i; + + /* Find slash inside string. */ + pnt = strchr (str, '/'); + + if (pnt) + { + /* Get prefix length. */ + plen = (u_char) atoi (++pnt); + if (plen > 48) + { + ret = 0; + goto done; + } + + cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); + strncpy (cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + + str_addr = cp; + } + + /* Convert string to prefix. */ + if (sscanf(str_addr, "%2x:%2x:%2x:%2x:%2x:%2x", + a+0, a+1, a+2, a+3, a+4, a+5) != 6) + { + ret = 0; + goto done; + } + for (i = 0; i < 6; ++i) + { + p->eth_addr.octet[i] = a[i] & 0xff; + } + p->prefixlen = plen; + p->family = AF_ETHERNET; + ret = 1; + +done: + if (cp) + XFREE (MTYPE_TMP, cp); + + return ret; +} + /* Convert masklen into IP address's netmask (network byte order). */ void masklen2ip (const int masklen, struct in_addr *netmask) @@ -762,6 +845,8 @@ prefix_blen (const struct prefix *p) return IPV6_MAX_BYTELEN; break; #endif /* HAVE_IPV6 */ + case AF_ETHERNET: + return ETHER_ADDR_LEN; } return 0; } @@ -784,6 +869,11 @@ str2prefix (const char *str, struct prefix *p) return ret; #endif /* HAVE_IPV6 */ + /* Next we try to convert string to struct prefix_eth. */ + ret = str2prefix_eth (str, (struct prefix_eth *) p); + if (ret) + return ret; + return 0; } @@ -793,6 +883,24 @@ prefix2str (union prefix46constptr pu, char *str, int size) const struct prefix *p = pu.p; char buf[BUFSIZ]; + if (p->family == AF_ETHERNET) { + int i; + char *s = str; + + assert(size > (3*ETHER_ADDR_LEN) + 1 /* slash */ + 3 /* plen */ ); + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + sprintf(s, "%02x", p->u.prefix_eth.octet[i]); + if (i < (ETHER_ADDR_LEN - 1)) { + *(s+2) = ':'; + s += 3; + } else { + s += 2; + } + } + sprintf(s, "/%d", p->prefixlen); + return 0; + } + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ); snprintf (str, size, "%s/%d", buf, p->prefixlen); return str; diff --git a/lib/prefix.h b/lib/prefix.h index 4a3175070..2cf0b20b0 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -23,8 +23,30 @@ #ifndef _ZEBRA_PREFIX_H #define _ZEBRA_PREFIX_H +#ifdef SUNOS_5 +# include +#else +# ifdef GNU_LINUX +# include +# else +# include +# endif +#endif #include "sockunion.h" +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN ETHERADDRL +#endif + +/* + * there isn't a portable ethernet address type. We define our + * own to simplify internal handling + */ +struct ethaddr { + u_char octet[ETHER_ADDR_LEN]; +} __packed; + + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -34,6 +56,15 @@ * interface. */ +/* different OSes use different names */ +#if defined(AF_PACKET) +#define AF_ETHERNET AF_PACKET +#else +#if defined(AF_LINK) +#define AF_ETHERNET AF_LINK +#endif +#endif + /* IPv4 and IPv6 unified prefix structure. */ struct prefix { @@ -51,6 +82,7 @@ struct prefix struct in_addr id; struct in_addr adv_router; } lp; + struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; } u __attribute__ ((aligned (8))); @@ -90,6 +122,14 @@ struct prefix_rd u_char val[8] __attribute__ ((aligned (8))); }; +/* Prefix for ethernet. */ +struct prefix_eth +{ + u_char family; + u_char prefixlen; + struct ethaddr eth_addr __attribute__ ((aligned (8))); /* AF_ETHERNET */ +}; + /* Prefix for a generic pointer */ struct prefix_ptr { @@ -174,6 +214,7 @@ extern int str2family(const char *); extern int afi2family (afi_t); extern afi_t family2afi (int); extern const char *safi2str(safi_t safi); +extern const char *afi2str(afi_t afi); /* Check bit of the prefix. */ extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen); @@ -197,6 +238,8 @@ extern struct prefix *sockunion2prefix (const union sockunion *dest, extern struct prefix *sockunion2hostprefix (const union sockunion *, struct prefix *p); extern void prefix2sockunion (const struct prefix *, union sockunion *); +extern int str2prefix_eth (const char *, struct prefix_eth *); + extern struct prefix_ipv4 *prefix_ipv4_new (void); extern void prefix_ipv4_free (struct prefix_ipv4 *); extern int str2prefix_ipv4 (const char *, struct prefix_ipv4 *); diff --git a/lib/zebra.h b/lib/zebra.h index cb83a112b..70d498a4f 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -493,7 +493,8 @@ extern const char *zserv_command_string (unsigned int command); typedef enum { AFI_IP = 1, AFI_IP6 = 2, -#define AFI_MAX 3 + AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */ +#define AFI_MAX 4 } afi_t; /* Subsequent Address Family Identifier. */ From 4afa3ddd17464ecce91b6ed9df27b1231fb3e939 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 24 May 2016 16:52:02 +0200 Subject: [PATCH 1066/1342] bgpd: Add new configuration cli for graceful restart. There is support to configure graceful restart timer. This is the time to wait to delete stale routes before a BGP open message is received. bgp graceful-restart restart-time <1-3600> no bgp graceful-restart [<1-255>] * bgpd/bgp_vty.c * Define command strings for above CLI * bgpd/bgpd.c * bgp_config_write(): Output graceful restart-time configuration Signed-off-by: Philippe Guibert Tested-by: NetDEF CI System --- bgpd/bgp_vty.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgpd.c | 3 +++ 2 files changed, 53 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a8383cf86..3b69a1bca 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1044,6 +1044,26 @@ DEFUN (bgp_graceful_restart_stalepath_time, return CMD_SUCCESS; } +DEFUN (bgp_graceful_restart_restart_time, + bgp_graceful_restart_restart_time_cmd, + "bgp graceful-restart restart-time <1-3600>", + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the time to wait to delete stale routes before a BGP open message is received\n" + "Delay value (seconds)\n") +{ + struct bgp *bgp; + u_int32_t restart; + + bgp = vty->index; + if (! bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("restart-time", restart, argv[0], 1, 3600); + bgp->restart_time = restart; + return CMD_SUCCESS; +} + DEFUN (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_cmd, "no bgp graceful-restart stalepath-time", @@ -1062,6 +1082,24 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, return CMD_SUCCESS; } +DEFUN (no_bgp_graceful_restart_restart_time, + no_bgp_graceful_restart_restart_time_cmd, + "no bgp graceful-restart restart-time", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the time to wait to delete stale routes before a BGP open message is received\n") +{ + struct bgp *bgp; + + bgp = vty->index; + if (! bgp) + return CMD_WARNING; + + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + return CMD_SUCCESS; +} + ALIAS (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_val_cmd, "no bgp graceful-restart stalepath-time <1-3600>", @@ -1071,6 +1109,15 @@ ALIAS (no_bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") +ALIAS (no_bgp_graceful_restart_restart_time, + no_bgp_graceful_restart_restart_time_val_cmd, + "no bgp graceful-restart restart-time <1-3600>", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the time to wait to delete stale routes before a BGP open message is received\n" + "Delay value (seconds)\n") + /* "bgp fast-external-failover" configuration. */ DEFUN (bgp_fast_external_failover, bgp_fast_external_failover_cmd, @@ -9901,6 +9948,9 @@ bgp_vty_init (void) install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd); + install_element (BGP_NODE, &bgp_graceful_restart_restart_time_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_val_cmd); /* "bgp fast-external-failover" commands */ install_element (BGP_NODE, &bgp_fast_external_failover_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 351701177..e86665b12 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5484,6 +5484,9 @@ bgp_config_write (struct vty *vty) if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) vty_out (vty, " bgp graceful-restart stalepath-time %d%s", bgp->stalepath_time, VTY_NEWLINE); + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out (vty, " bgp graceful-restart restart-time %d%s", + bgp->restart_time, VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_GRACEFUL_RESTART)) vty_out (vty, " bgp graceful-restart%s", VTY_NEWLINE); From dfb9bd7aaadc2f5abb9bc9aecbd73b9d8b3a788c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 24 May 2016 18:58:07 +0200 Subject: [PATCH 1067/1342] bgpd: minor header/API clean up Adds "const" on: - peer_update_source_addr_set() - peer_description_set() Adds parameter names on: - bgp_timers_set() (really confusing, this one, with 2 unexplained args of same type) Adds new setter: - peer_afc_set(), calling peer_activate/peer_deactivate. (intended for API consumers, matches peer->afc) Signed-off-by: David Lamparter --- bgpd/bgpd.c | 13 +++++++++++-- bgpd/bgpd.h | 9 +++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e86665b12..952192708 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1179,6 +1179,15 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi) return 0; } +int +peer_afc_set (struct peer *peer, afi_t afi, safi_t safi, int enable) +{ + if (enable) + return peer_activate (peer, afi, safi); + else + return peer_deactivate (peer, afi, safi); +} + static void peer_nsf_stop (struct peer *peer) { @@ -2905,7 +2914,7 @@ peer_ebgp_multihop_unset (struct peer *peer) /* Neighbor description. */ int -peer_description_set (struct peer *peer, char *desc) +peer_description_set (struct peer *peer, const char *desc) { if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); @@ -2998,7 +3007,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname) } int -peer_update_source_addr_set (struct peer *peer, union sockunion *su) +peer_update_source_addr_set (struct peer *peer, const union sockunion *su) { struct peer_group *group; struct listnode *node, *nnode; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d8afbf386..53f8cb7cd 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -898,7 +898,7 @@ extern int bgp_confederation_peers_check (struct bgp *, as_t); extern int bgp_confederation_peers_add (struct bgp *, as_t); extern int bgp_confederation_peers_remove (struct bgp *, as_t); -extern int bgp_timers_set (struct bgp *, u_int32_t, u_int32_t); +extern int bgp_timers_set (struct bgp *, u_int32_t keepalive, u_int32_t holdtime); extern int bgp_timers_unset (struct bgp *); extern int bgp_default_local_preference_set (struct bgp *, u_int32_t); @@ -914,6 +914,7 @@ extern int peer_group_remote_as_delete (struct peer_group *); extern int peer_activate (struct peer *, afi_t, safi_t); extern int peer_deactivate (struct peer *, afi_t, safi_t); +extern int peer_afc_set (struct peer *, afi_t, safi_t, int); extern int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *, afi_t, safi_t, as_t *); @@ -930,11 +931,11 @@ extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_ebgp_multihop_set (struct peer *, int); extern int peer_ebgp_multihop_unset (struct peer *); -extern int peer_description_set (struct peer *, char *); +extern int peer_description_set (struct peer *, const char *); extern int peer_description_unset (struct peer *); extern int peer_update_source_if_set (struct peer *, const char *); -extern int peer_update_source_addr_set (struct peer *, union sockunion *); +extern int peer_update_source_addr_set (struct peer *, const union sockunion *); extern int peer_update_source_unset (struct peer *); extern int peer_default_originate_set (struct peer *, afi_t, safi_t, const char *); @@ -946,7 +947,7 @@ extern int peer_port_unset (struct peer *); extern int peer_weight_set (struct peer *, u_int16_t); extern int peer_weight_unset (struct peer *); -extern int peer_timers_set (struct peer *, u_int32_t, u_int32_t); +extern int peer_timers_set (struct peer *, u_int32_t keepalive, u_int32_t holdtime); extern int peer_timers_unset (struct peer *); extern int peer_timers_connect_set (struct peer *, u_int32_t); From 584083d50511e19b228cce1e4a1cbcb28fae6b49 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 24 May 2016 18:58:08 +0200 Subject: [PATCH 1068/1342] bgpd: divorce router-id logic from CLI & zebra Logic for determining the router-id was spread out over bgp_zebra.c and bgp_vty.c. Move to bgpd/bgpd.c and have these two call more properly encapsulated functions. Signed-off-by: David Lamparter --- bgpd/bgp_vty.c | 9 +++------ bgpd/bgp_zebra.c | 9 +-------- bgpd/bgp_zebra.h | 1 + bgpd/bgpd.c | 23 ++++++++++++++++++++++- bgpd/bgpd.h | 3 ++- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3b69a1bca..925e2676f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -51,8 +51,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" -extern struct in_addr router_id_zebra; - /* Utility function to get address family from current node. */ afi_t bgp_node_afi (struct vty *vty) @@ -489,8 +487,7 @@ DEFUN (bgp_router_id, return CMD_WARNING; } - bgp->router_id_static = id; - bgp_router_id_set (bgp, &id); + bgp_router_id_static_set (bgp, id); return CMD_SUCCESS; } @@ -524,8 +521,8 @@ DEFUN (no_bgp_router_id, } } - bgp->router_id_static.s_addr = 0; - bgp_router_id_set (bgp, &router_id_zebra); + id.s_addr = 0; + bgp_router_id_static_set (bgp, id); return CMD_SUCCESS; } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4066a9a18..85380f0fc 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -53,8 +53,6 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; - struct listnode *node, *nnode; - struct bgp *bgp; zebra_router_id_update_read(zclient->ibuf,&router_id); @@ -67,12 +65,7 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, router_id_zebra = router_id.u.prefix4; - for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) - { - if (!bgp->router_id_static.s_addr) - bgp_router_id_set (bgp, &router_id.u.prefix4); - } - + bgp_router_id_zebra_bump (); return 0; } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index e69a0bc57..25651581b 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */ #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) extern struct stream *bgp_nexthop_buf; +extern struct in_addr router_id_zebra; extern void bgp_zebra_init (struct thread_master *master); extern void bgp_zebra_destroy (void); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 952192708..db952c7fc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -160,7 +160,7 @@ bgp_config_check (struct bgp *bgp, int config) } /* Set BGP router identifier. */ -int +static int bgp_router_id_set (struct bgp *bgp, struct in_addr *id) { struct peer *peer; @@ -188,6 +188,27 @@ bgp_router_id_set (struct bgp *bgp, struct in_addr *id) return 0; } +void +bgp_router_id_zebra_bump (void) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) + { + if (!bgp->router_id_static.s_addr) + bgp_router_id_set (bgp, &router_id_zebra); + } +} + +int +bgp_router_id_static_set (struct bgp *bgp, struct in_addr id) +{ + bgp->router_id_static = id; + bgp_router_id_set (bgp, id.s_addr ? &id : &router_id_zebra); + return 0; +} + /* BGP's cluster-id control. */ int bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 53f8cb7cd..a6ced5b8e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -886,7 +886,8 @@ extern int bgp_flag_check (struct bgp *, int); extern void bgp_lock (struct bgp *); extern void bgp_unlock (struct bgp *); -extern int bgp_router_id_set (struct bgp *, struct in_addr *); +extern void bgp_router_id_zebra_bump (void); +extern int bgp_router_id_static_set (struct bgp *, struct in_addr); extern int bgp_cluster_id_set (struct bgp *, struct in_addr *); extern int bgp_cluster_id_unset (struct bgp *); From f458d88e57e982e8f00a3d2db35a2c6e0bb331fa Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 24 May 2016 18:58:09 +0200 Subject: [PATCH 1069/1342] bgpd: ditch unused bgp_node_*() functions Signed-off-by: David Lamparter Tested-by: NetDEF CI System --- bgpd/bgp_table.h | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index bee129632..3b4e6cf3d 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -117,44 +117,6 @@ bgp_node_table (struct bgp_node *node) return bgp_node_to_rnode (node)->table->info; } -/* - * bgp_node_info - * - * Returns the 'info' pointer corresponding to a bgp node. - */ -static inline void * -bgp_node_info (const struct bgp_node *node) -{ - return node->info; -} - -/* - * bgp_node_set_info - */ -static inline void -bgp_node_set_info (struct bgp_node *node, void *info) -{ - node->info = info; -} - -/* - * bgp_node_prefix - */ -static inline struct prefix * -bgp_node_prefix (struct bgp_node *node) -{ - return &node->p; -} - -/* - * bgp_node_prefixlen - */ -static inline u_char -bgp_node_prefixlen (struct bgp_node *node) -{ - return bgp_node_prefix (node)->prefixlen; -} - /* * bgp_node_parent_nolock * From 3affb6c04881f99aafbbb12de76bdde1dbea0408 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 26 Jan 2016 14:34:41 +0000 Subject: [PATCH 1070/1342] HACKING: Update HACKING with anything relevant from pending and prune * HACKING.md: Add USEFUL URLs section, add link to patchwork * HACKING.pending: Prune out stuff moved to HACKING or well out of date or unreachable. Tested-by: NetDEF CI System --- HACKING.md | 7 +++++++ HACKING.pending | 42 ------------------------------------------ 2 files changed, 7 insertions(+), 42 deletions(-) diff --git a/HACKING.md b/HACKING.md index 3a449da78..e5ae385af 100644 --- a/HACKING.md +++ b/HACKING.md @@ -498,3 +498,10 @@ from ‘master’: presuming ‘quagga’ corresponds to a file in your .git/remotes with configuration for the appropriate Quagga.net repository. + +USEFUL URLs +=========== + +* David Lamparter runs a patchwork instance at + + diff --git a/HACKING.pending b/HACKING.pending index dfce5ceca..73d3194fa 100644 --- a/HACKING.pending +++ b/HACKING.pending @@ -1,34 +1,8 @@ This file contains pointers to work done on quagga that is not in the quagga git repository or quagga bugzilla. -* bug/patch trackers - -** diac24 patchwork instance - -David Lamparter runs a patchwork instance at - - http://patchwork.diac24.net/project/quagga/list/ - -which contains about 225 patches to quagga. Many of these are -collected in his git repository. - * public git repositories -** git remote add quagga-re git://github.com/Quagga-RE/quagga-RE.git - -Maintained by Denis Ovsienko, and geared towards producing a -production-ready branch of Quagga, in the Quagga-RE-stable branch. - -** git remote add equinox git://git.spaceboyz.net/equinox/quagga.git/ - -This repository has topic branches for patches intended for inclusion -in the main quagga tree, named patches/, plus some other branches. - -** git remote add balajig http://github.com/balajig/quagga-next.git - -Balaji G has prepared a git repository where a number of patches to -the list have been stored. - ** git remote add mtr http://github.com/tomhenderson/quagga-mtr.git Tom Henderson of Boeing has created a repository to work on @@ -36,19 +10,3 @@ multi-topology routing support for OSPF. Work on this repository takes place on the branch mtr, which has a branch point of 0.99.17 * posted patches - -** Boeing - -Boeing has posted patches - - quagga-0.99.9.ospfv3-addressfamilies.patch - quagga-0.99.9.ospfv3-manetmdr.patch - -against 0.99.9 at - - http://hipserver.mct.phantomworks.org/ietf/ospf/ - -Both patches include functional enhancements as well as support for -gcc 2.95. - -[TODO: Are any of these obsolete with respect to mtr/mtr?] From 2f6aa36e8d72d712738fad2c53ab95f7fcbefc61 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 26 Jan 2016 14:00:10 +0000 Subject: [PATCH 1071/1342] HACKING: Fix internal section links Seems when pandoc converts tex to markdown it doesn't output internal reference links in a format it recognises itself. Fix. --- HACKING.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/HACKING.md b/HACKING.md index e5ae385af..0a178e0c5 100644 --- a/HACKING.md +++ b/HACKING.md @@ -84,8 +84,7 @@ upgrade may cause daemons to fail to start because of unrecognised commands. Deprecated commands should be excised in the next unstable cycle. A list of deprecated commands should be collated for each release. -See also section [sec:dll-versioning] below regarding SHARED LIBRARY -VERSIONING. +See also [Section SHARED LIBRARY VERSIONING](#sec:dll-versioning) below. YOUR FIRST CONTRIBUTIONS ======================== @@ -363,8 +362,8 @@ merge them together to one branch (potentially local and/or “throw-awayâ€) for testing or use, while retaining smaller, independent branches that are easier to merge. -All content guidelines in section [sec:patch-submission], PATCH -SUBMISSION apply. +All content guidelines in [Section PATCH SUBMISSION](#sec:patch-submission) +apply. PATCH SUBMISSION {#sec:patch-submission} ================ @@ -381,8 +380,8 @@ PATCH SUBMISSION {#sec:patch-submission} git diff -up mybranch..remotes/quagga.net/master It is preferable to use git format-patch, and even more preferred to - publish a git repository (see GIT COMMIT SUBMISSION, section - [sec:git-submission]). + publish a git repository (see + [Section GIT COMMIT SUBMISSION](#sec:git-submission)). If not using git format-patch, Include the commit message in the email. From d3cf6c689a64ab83ba574e7df2472129603f1875 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 26 Jan 2016 14:00:11 +0000 Subject: [PATCH 1072/1342] HACKING: Add required reading section & commit should give full rights details * HACKING.tex: (COMMIT MESSAGES) It's pretty critical that commit messages give all the detail required to figure out what authorship/copyright claims might come into play. (REQUIRED READING) Add a section on what people are implicitly agreeing to when they contribute. It's fairly obvious, common sense stuff. Spell it out though. Note that COMMIT MESSAGES are also required reading. (Cover page) Draw attention to REQUIRED READING. A previous version was: Acked-by: Vincent Jardin --- HACKING.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/HACKING.md b/HACKING.md index 0a178e0c5..9c84fb496 100644 --- a/HACKING.md +++ b/HACKING.md @@ -6,13 +6,45 @@ fontsize: 11pt toc: true date: \today include-before: - \large This is a living document. Suggestions for updates, via the + \large This is a living document. + + \large This is a living document describing the processes and guidelines + for working on Quagga. You *must* read Section + ["REQUIRED READING"](#sec:required), before contributing to Quagga. + + Suggestions for updates, via the [quagga-dev list](http://lists.quagga.net/mailman/listinfo/quagga-dev), are welcome. \newpage ... \newpage +REQUIRED READING {#sec:required} +================ + +Note well: By proposing a change to Quagga, by whatever means, you are +implicitly agreeing: + +- To licence your contribution according to the licence of any files in + Quagga being modified, _and_ according to the COPYING file in the + top-level directory of Quagga, other than where the contribution + explicitly and clearly indicates otherwise. + +- That it is your responsibility to ensure you hold whatever rights are + required to be able to contribute your changes under the licenses of the + files in Quagga being modified, and the top-level COPYING file. + +- That it is your responsibility to give with the contribution a full + account of all interests held and claims in the contribution; such as + through copyright, trademark and patent laws or otherwise; that are known + to you or your associates (e.g. your employer). + +Before contributing to Quagga, you *must* also read +[Section COMMIT MESSAGES](#sec:commit-messages). You _should_ ideally read the entire +document, as it contains useful information on the community norms and how +to implement them. + + GUIDELINES FOR HACKING ON QUAGGA {#sec:guidelines} ================================ @@ -166,8 +198,8 @@ rather than: Note that the former approach requires ensuring that SOME\_SYMBOL will be defined (watch your AC\_DEFINEs). -COMMIT MESSAGES -=============== +COMMIT MESSAGES {#sec:commit-messages} +====================================== The commit message requirements are: @@ -198,6 +230,18 @@ The commit message requirements are: changes to the code are intended (and hence be able to spot any accidental unintended changes). +- The commit message *must* give details of all the authors of the change, + beyond the person listed in the Author field. Any and all affiliations + which may have a bearing on copyright in any way should be clearly + stated, unless those affiliations are already obvious from other + details, e.g. from the email address. This would cover employment and + contracting obligations (give details). + +- If the change introduces a new dependency on any code or other + copyrighted material, please explicitly note this. Give details of what + that external material is, the copyright licence the material may be + used under, and the nature of the dependency. + The one-line summary must be limited to 54 characters, and all other lines to 72 characters. From d1aa80f04d12c096b10ba0862edbe6c30b5f7ebb Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 26 Jan 2016 14:00:12 +0000 Subject: [PATCH 1073/1342] HACKING: Note that "Signed-off-by" not used for authorship/rights info * "Signed-off-by" is overloaded, and possibly not even well understood. As per the text, it should not be used to indicate authorship or other rights information, within Quagga. --- HACKING.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/HACKING.md b/HACKING.md index 9c84fb496..85ae2998d 100644 --- a/HACKING.md +++ b/HACKING.md @@ -40,10 +40,15 @@ implicitly agreeing: to you or your associates (e.g. your employer). Before contributing to Quagga, you *must* also read -[Section COMMIT MESSAGES](#sec:commit-messages). You _should_ ideally read the entire -document, as it contains useful information on the community norms and how -to implement them. +[Section COMMIT MESSAGES](#sec:commit-messages). +You _should_ ideally read the entire document, as it contains useful +information on the community norms and how to implement them. + +Please note that authorship and any relevant other rights information should +be _explicitly_ stated with the contribution. A "Signed-off-by" line is +_not_ sufficient. The "Signed-off-by" line is not used by the Quagga +project. GUIDELINES FOR HACKING ON QUAGGA {#sec:guidelines} ================================ @@ -236,7 +241,9 @@ The commit message requirements are: stated, unless those affiliations are already obvious from other details, e.g. from the email address. This would cover employment and contracting obligations (give details). - + + Note: Do not rely on "Signed-off-by" for this, be explicit. + - If the change introduces a new dependency on any code or other copyrighted material, please explicitly note this. Give details of what that external material is, the copyright licence the material may be From 57439bf2dd0e2aa9c5a4c95919503dae1e360a19 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 5 Feb 2016 14:46:58 +0000 Subject: [PATCH 1074/1342] HACKING: New code _MUST_ use a bounded-buffer in handling untrusted data. * Guidelines: New code must use a bounded-buffer abstraction that provides at least some level of sanity checks on accesses. Direct pointer twiddling based on untrustable buffers is not generally acceptable in new code in Quagga. Tested-by: NetDEF CI System --- HACKING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HACKING.md b/HACKING.md index 85ae2998d..f926ed61b 100644 --- a/HACKING.md +++ b/HACKING.md @@ -64,6 +64,13 @@ due to whitespace issues, to minimise merging conflicts. Be particularly careful not to break platforms/protocols that you cannot test. +Parsers or packet-writers of data from untrusted parties, particularly +remote ones, *MUST* use the lib/stream bounded-buffer abstraction, and use +its checked getters and putters. Twiddling of pointers based on contents of +untrusted data is _strongly_ discouraged - any such code is not acceptable, +unless there are very good reasons (e.g. compatibility with external or old +code that is not easily rewritten). + New code should have good comments, which explain why the code is correct. Changes to existing code should in many cases upgrade the comments when necessary for a reviewer to conclude that the change has no unintended From cbd976b54d51fea2f3d532e8d5aac66d6294acc2 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 26 Feb 2016 10:34:01 +0000 Subject: [PATCH 1075/1342] HACKING: Document how to add standard copyright claims to files * (REQUIRED READING) Copyright claims may be documented in the standard way, with a "Copyright ..." line near the beginning of the file. Incorporating suggestions and refinements from: Lou Berger --- HACKING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/HACKING.md b/HACKING.md index f926ed61b..3bd1eb37b 100644 --- a/HACKING.md +++ b/HACKING.md @@ -50,6 +50,22 @@ be _explicitly_ stated with the contribution. A "Signed-off-by" line is _not_ sufficient. The "Signed-off-by" line is not used by the Quagga project. +You may document applicable copyright claims to files being modified or +added by your contribution. For new files, the standard way is to add a +string in the following format near the beginning of the file: + + Copyright (C) [, optional contact details] + +When adding copyright claims for modifications to an existing file, please +preface the claim with "Portions: " on a line before it and indent the +"Copyright ..." string. If such a case already exists, add your indented +claim immediately after. E.g.: + + Portions: + Copyright (C) .... + Copyright (C) [optional brief change description] + + GUIDELINES FOR HACKING ON QUAGGA {#sec:guidelines} ================================ From 07e5b645059167a37ccf1079a125114339c0df9e Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Mon, 4 Apr 2016 10:54:55 -0700 Subject: [PATCH 1076/1342] qpb: Add support for protobuf. Infrastructure that allows protocol buffers to be used in Quagga. The changes below comprise of: - Build hooks - Protobuf definitions for common types. - Library routines for working with protobuf, including functions that help translate between common quagga types and their protobuf equivalents. Changes: * qpb/{Makefile.am,README.txt,qpb.h,.gitignore} Add the qpb library, which provides shared code and definitions for using protocol buffers in quagga code. * qpb/qpb.proto Protobuf definitions that can be shared by all of quagga. * qpb/linear_allocator.h An allocator that allocates memory by walking down towards the end of a buffer. This is used to cheaply allocate/deallocate memory on the stack for protobuf operations. * qpb/qpb_allocator.[ch] Thin layer that allows a linear allocator to be used with the protobuf-c library. * common.am This is an automake fragment that is intended to be shared by Makefile.am files in the tree. It currently includes definitions related to protobuf. * configure.ac - Add logic to optionally build protobuf code. By default, protobuf support is enabled if the protobuf C compiler (protoc-c) is available, and the associated header files/library can be found. The user can choose to override this behavior via the new --disable-protobuf/--enable-protobuf flags. - Include the quagga protobuf library (qpb) in the build. * .gitignore Ignore source code generated by protobuf compiler. * Makefile.am Add 'qpb' to the list of subdirectories. Signed-off-by: Avneesh Sachdev Edited: Paul Jakma : Change the sense of the configure enable option to require explicit specifying, as an experimental feature. --- .gitignore | 3 + Makefile.am | 4 +- common.am | 41 +++++ configure.ac | 47 +++++- qpb/.gitignore | 15 ++ qpb/Makefile.am | 30 ++++ qpb/README.txt | 1 + qpb/linear_allocator.h | 207 +++++++++++++++++++++++ qpb/qpb.c | 29 ++++ qpb/qpb.h | 372 +++++++++++++++++++++++++++++++++++++++++ qpb/qpb.proto | 121 ++++++++++++++ qpb/qpb_allocator.c | 67 ++++++++ qpb/qpb_allocator.h | 113 +++++++++++++ 13 files changed, 1047 insertions(+), 3 deletions(-) create mode 100644 common.am create mode 100644 qpb/.gitignore create mode 100644 qpb/Makefile.am create mode 100644 qpb/README.txt create mode 100644 qpb/linear_allocator.h create mode 100644 qpb/qpb.c create mode 100644 qpb/qpb.h create mode 100644 qpb/qpb.proto create mode 100644 qpb/qpb_allocator.c create mode 100644 qpb/qpb_allocator.h diff --git a/.gitignore b/.gitignore index e8de25237..a281555e4 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ build m4/*.m4 !m4/ax_sys_weak_alias.m4 cscope.* +*.pb.h +*.pb-c.h +*.pb-c.c diff --git a/Makefile.am b/Makefile.am index d2efb20eb..87ba3d0c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ +SUBDIRS = lib qpb @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests -DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \ +DIST_SUBDIRS = lib qpb zebra bgpd ripd ripngd ospfd ospf6d \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd diff --git a/common.am b/common.am new file mode 100644 index 000000000..ac7a3230d --- /dev/null +++ b/common.am @@ -0,0 +1,41 @@ +# +# Automake fragment intended to be shared by Makefile.am files in the +# tree. +# + +if HAVE_PROTOBUF + +# Uncomment to use an non-system version of libprotobuf-c. +# +# Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src +# Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la + +Q_PROTOBUF_C_CLIENT_INCLUDES= +Q_PROTOBUF_C_CLIENT_LDOPTS=-lprotobuf-c + +Q_PROTOC=protoc +Q_PROTOC_C=protoc-c + +Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES)) + +Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES) + +# Rules +%.pb.h: %.proto + $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ + +%.pb-c.c %.pb-c.h: %.proto + $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ + +# +# Information about how to link to various libraries. +# +Q_QUAGGA_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libquagga_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) + +Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfpm_pb.la $(Q_QUAGGA_PB_CLIENT_LDOPTS) + +endif # HAVE_PROTOBUF + +Q_CLEANFILES = $(Q_PROTOBUF_SRCS) + +Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS) diff --git a/configure.ac b/configure.ac index c35a111c5..d36b580a0 100755 --- a/configure.ac +++ b/configure.ac @@ -301,6 +301,8 @@ AC_ARG_ENABLE(fpm, AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) +AC_ARG_ENABLE([protobuf], + AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support])) if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then @@ -320,6 +322,48 @@ if test "${enable_fpm}" = "yes"; then AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) fi +# +# Logic for protobuf support. +# +if test "$enable_protobuf" = "yes"; then + have_protobuf=yes + + # Check for protoc-c + AC_CHECK_PROG([PROTOC_C], [protoc-c], [protoc-c], [/bin/false]) + if test "x$PROTOC_C" = "x/bin/false"; then + have_protobuf=no + else + found_protobuf_c=no + PKG_CHECK_MODULES([PROTOBUF_C], libprotobuf-c >= 0.14, + [found_protobuf_c=yes], + [AC_MSG_RESULT([pkg-config did not find libprotobuf-c])]) + + if test "x$found_protobuf_c" = "xyes"; then + LDFLAGS="$LDFLAGS $PROTOBUF_C_LIBS" + CFLAGS="$CFLAGS $PROTOBUF_C_CFLAGS" + else + AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h], [], + [have_protobuf=no; AC_MSG_RESULT([Couldn't find google/protobuf-c.h])]) + fi + fi +fi + +# Fail if the user explicity enabled protobuf support and we couldn't +# find the compiler or libraries. +if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then + AC_MSG_ERROR([Protobuf enabled explicitly but can't find libraries/tools]) +fi + +if test "x$have_protobuf" = "xyes"; then + AC_DEFINE(HAVE_PROTOBUF,, protobuf) +fi + +AM_CONDITIONAL([HAVE_PROTOBUF], [test "x$have_protobuf" = "xyes"]) + +# +# End of logic for protobuf support. +# + if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi @@ -1530,7 +1574,7 @@ AC_CACHE_VAL(ac_cv_htonl_works, ) AC_MSG_RESULT($ac_cv_htonl_works) -AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile +AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile @@ -1570,6 +1614,7 @@ group to run as : ${enable_group} group for vty sockets : ${enable_vty_group} config file mask : ${enable_configfile_mask} log file mask : ${enable_logfile_mask} +zebra protobuf enabled : ${have_protobuf:-no} The above user and group must have read/write access to the state file directory and to the config files in the config file directory." diff --git a/qpb/.gitignore b/qpb/.gitignore new file mode 100644 index 000000000..b133c52a4 --- /dev/null +++ b/qpb/.gitignore @@ -0,0 +1,15 @@ +Makefile +Makefile.in +*.o +tags +TAGS +.deps +.nfs* +*.lo +*.la +*.a +*.libs +.arch-inventory +.arch-ids +*~ +*.loT diff --git a/qpb/Makefile.am b/qpb/Makefile.am new file mode 100644 index 000000000..0fbda61f3 --- /dev/null +++ b/qpb/Makefile.am @@ -0,0 +1,30 @@ +include ../common.am + +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) + +PROTOBUF_INCLUDES=-I$(top_srcdir) +PROTOBUF_PACKAGE = qpb + +lib_LTLIBRARIES = libquagga_pb.la +libquagga_pb_la_LDFLAGS = -version-info 0:0:0 + +if HAVE_PROTOBUF +protobuf_srcs = \ + qpb_allocator.c + +protobuf_srcs_nodist = \ + qpb.pb-c.c +endif + +libquagga_pb_la_SOURCES = \ + linear_allocator.h \ + qpb.h \ + qpb.c \ + qpb_allocator.h \ + $(protobuf_srcs) + +nodist_libquagga_pb_la_SOURCES = $(protobuf_srcs_nodist) + +CLEANFILES = $(Q_CLEANFILES) +BUILT_SOURCES = $(Q_PROTOBUF_SRCS) +EXTRA_DIST = qpb.proto diff --git a/qpb/README.txt b/qpb/README.txt new file mode 100644 index 000000000..99ccd0551 --- /dev/null +++ b/qpb/README.txt @@ -0,0 +1 @@ +Protobuf definitions and code that is applicable to all of quagga. diff --git a/qpb/linear_allocator.h b/qpb/linear_allocator.h new file mode 100644 index 000000000..e3ebbc64f --- /dev/null +++ b/qpb/linear_allocator.h @@ -0,0 +1,207 @@ +/* + * linear_allocator.h + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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. + */ + +/* + * Header file for the linear allocator. + * + * An allocator that allocates memory by walking down towards the end + * of a buffer. No attempt is made to reuse blocks that are freed + * subsequently. The assumption is that the buffer is big enough to + * cover allocations for a given purpose. + */ +#include +#include +#include +#include + +/* + * Alignment for block allocated by the allocator. Must be a power of 2. + */ +#define LINEAR_ALLOCATOR_ALIGNMENT 8 + +#define LINEAR_ALLOCATOR_ALIGN(value) \ + (((value) + LINEAR_ALLOCATOR_ALIGNMENT - 1) & ~(LINEAR_ALLOCATOR_ALIGNMENT - 1)); + +/* + * linear_allocator_align_ptr + */ +static inline char * +linear_allocator_align_ptr (char *ptr) +{ + return (char *) LINEAR_ALLOCATOR_ALIGN ((intptr_t) ptr); +} + +typedef struct linear_allocator_t_ +{ + char *buf; + + /* + * Current location in the buffer. + */ + char *cur; + + /* + * End of buffer. + */ + char *end; + + /* + * Version number of the allocator, this is bumped up when the allocator + * is reset and helps identifies bad frees. + */ + uint32_t version; + + /* + * The number of blocks that are currently allocated. + */ + int num_allocated; +} linear_allocator_t; + +/* + * linear_allocator_block_t + * + * Header structure at the begining of each block. + */ +typedef struct linear_allocator_block_t_ +{ + uint32_t flags; + + /* + * The version of the allocator when this block was allocated. + */ + uint32_t version; + char data[0]; +} linear_allocator_block_t; + +#define LINEAR_ALLOCATOR_BLOCK_IN_USE 0x01 + +#define LINEAR_ALLOCATOR_HDR_SIZE (sizeof(linear_allocator_block_t)) + +/* + * linear_allocator_block_size + * + * The total amount of space a block will take in the buffer, + * including the size of the header. + */ +static inline size_t +linear_allocator_block_size (size_t user_size) +{ + return LINEAR_ALLOCATOR_ALIGN (LINEAR_ALLOCATOR_HDR_SIZE + user_size); +} + +/* + * linear_allocator_ptr_to_block + */ +static inline linear_allocator_block_t * +linear_allocator_ptr_to_block (void *ptr) +{ + void *block_ptr; + block_ptr = ((char *) ptr) - offsetof (linear_allocator_block_t, data); + return block_ptr; +} + +/* + * linear_allocator_init + */ +static inline void +linear_allocator_init (linear_allocator_t * allocator, char *buf, + size_t buf_len) +{ + memset (allocator, 0, sizeof (*allocator)); + + assert (linear_allocator_align_ptr (buf) == buf); + allocator->buf = buf; + allocator->cur = buf; + allocator->end = buf + buf_len; +} + +/* + * linear_allocator_reset + * + * Prepare an allocator for reuse. + * + * *** NOTE ** This implicitly frees all the blocks in the allocator. + */ +static inline void +linear_allocator_reset (linear_allocator_t *allocator) +{ + allocator->num_allocated = 0; + allocator->version++; + allocator->cur = allocator->buf; +} + +/* + * linear_allocator_alloc + */ +static inline void * +linear_allocator_alloc (linear_allocator_t *allocator, size_t user_size) +{ + size_t block_size; + linear_allocator_block_t *block; + + block_size = linear_allocator_block_size (user_size); + + if (allocator->cur + block_size > allocator->end) + { + return NULL; + } + + block = (linear_allocator_block_t *) allocator->cur; + allocator->cur += block_size; + + block->flags = LINEAR_ALLOCATOR_BLOCK_IN_USE; + block->version = allocator->version; + allocator->num_allocated++; + return block->data; +} + +/* + * linear_allocator_free + */ +static inline void +linear_allocator_free (linear_allocator_t *allocator, void *ptr) +{ + linear_allocator_block_t *block; + + if (((char *) ptr) < allocator->buf || ((char *) ptr) >= allocator->end) + { + assert (0); + return; + } + + block = linear_allocator_ptr_to_block (ptr); + if (block->version != allocator->version) + { + assert (0); + return; + } + + block->flags = block->flags & ~LINEAR_ALLOCATOR_BLOCK_IN_USE; + + if (--allocator->num_allocated < 0) + { + assert (0); + } +} diff --git a/qpb/qpb.c b/qpb/qpb.c new file mode 100644 index 000000000..1b2b47fce --- /dev/null +++ b/qpb/qpb.c @@ -0,0 +1,29 @@ +/* + * qpb.c + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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. + */ + +/* + * Main file for the qpb library. + */ + diff --git a/qpb/qpb.h b/qpb/qpb.h new file mode 100644 index 000000000..55c1deb19 --- /dev/null +++ b/qpb/qpb.h @@ -0,0 +1,372 @@ +/* + * qpb.h + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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. + */ + +/* + * Main public header file for the quagga protobuf library. + */ + +#ifndef _QPB_H +#define _QPB_H + +#include "prefix.h" + +#include "qpb/qpb.pb-c.h" + +#include "qpb/qpb_allocator.h" + +/* + * qpb__address_family__set + */ +#define qpb_address_family_set qpb__address_family__set +static inline int +qpb__address_family__set (Qpb__AddressFamily *pb_family, u_char family) +{ + switch (family) { + case AF_INET: + *pb_family = QPB__ADDRESS_FAMILY__IPV4; + return 1; + + case AF_INET6: + *pb_family = QPB__ADDRESS_FAMILY__IPV6; + return 1; + + default: + *pb_family = QPB__ADDRESS_FAMILY__UNKNOWN_AF; + } + + return 0; +} + +/* + * qpb__address_family__get + */ +#define qpb_address_family_get qpb__address_family__get +static inline int +qpb__address_family__get (Qpb__AddressFamily pb_family, u_char *family) +{ + + switch (pb_family) { + case QPB__ADDRESS_FAMILY__IPV4: + *family = AF_INET; + return 1; + + case QPB__ADDRESS_FAMILY__IPV6: + *family = AF_INET6; + return 1; + + case QPB__ADDRESS_FAMILY__UNKNOWN_AF: + return 0; + } + + return 0; +} + +/* + * qpb__l3_prefix__create + */ +#define qpb_l3_prefix_create qpb__l3_prefix__create +static inline Qpb__L3Prefix * +qpb__l3_prefix__create (qpb_allocator_t *allocator, struct prefix *p) +{ + Qpb__L3Prefix *prefix; + + prefix = QPB_ALLOC(allocator, typeof(*prefix)); + if (!prefix) { + return NULL; + } + qpb__l3_prefix__init(prefix); + prefix->length = p->prefixlen; + prefix->bytes.len = (p->prefixlen + 7)/8; + prefix->bytes.data = qpb_alloc(allocator, prefix->bytes.len); + if (!prefix->bytes.data) { + return NULL; + } + + memcpy(prefix->bytes.data, &p->u.prefix, prefix->bytes.len); + + return prefix; +} + +/* + * qpb__l3_prefix__get + */ +#define qpb_l3_prefix_get qpb__l3_prefix__get +static inline int +qpb__l3_prefix__get (const Qpb__L3Prefix *pb_prefix, u_char family, + struct prefix *prefix) +{ + + switch (family) + { + + case AF_INET: + memset(prefix, 0, sizeof(struct prefix_ipv4)); + break; + + case AF_INET6: + memset(prefix, 0, sizeof(struct prefix_ipv6)); + break; + + default: + memset(prefix, 0, sizeof(*prefix)); + } + + prefix->prefixlen = pb_prefix->length; + prefix->family = family; + memcpy(&prefix->u.prefix, pb_prefix->bytes.data, pb_prefix->bytes.len); + return 1; +} + +/* + * qpb__protocol__set + * + * Translate a quagga route type to a protobuf protocol. + */ +#define qpb_protocol_set qpb__protocol__set +static inline int +qpb__protocol__set (Qpb__Protocol *pb_proto, int route_type) +{ + switch (route_type) { + case ZEBRA_ROUTE_KERNEL: + *pb_proto = QPB__PROTOCOL__KERNEL; + break; + + case ZEBRA_ROUTE_CONNECT: + *pb_proto = QPB__PROTOCOL__CONNECTED; + break; + + case ZEBRA_ROUTE_STATIC: + *pb_proto = QPB__PROTOCOL__STATIC; + break; + + case ZEBRA_ROUTE_RIP: + *pb_proto = QPB__PROTOCOL__RIP; + break; + + case ZEBRA_ROUTE_RIPNG: + *pb_proto = QPB__PROTOCOL__RIPNG; + break; + + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + *pb_proto = QPB__PROTOCOL__OSPF; + break; + + case ZEBRA_ROUTE_ISIS: + *pb_proto = QPB__PROTOCOL__ISIS; + break; + + case ZEBRA_ROUTE_BGP: + *pb_proto = QPB__PROTOCOL__BGP; + break; + + case ZEBRA_ROUTE_HSLS: + case ZEBRA_ROUTE_OLSR: + case ZEBRA_ROUTE_BABEL: + case ZEBRA_ROUTE_MAX: + case ZEBRA_ROUTE_SYSTEM: + default: + *pb_proto = QPB__PROTOCOL__OTHER; + } + + return 1; +} + +/* + * qpb__ipv4_address__create + */ +static inline Qpb__Ipv4Address * +qpb__ipv4_address__create (qpb_allocator_t *allocator, + struct in_addr *addr) +{ + Qpb__Ipv4Address *v4; + + v4 = QPB_ALLOC(allocator, typeof(*v4)); + if (!v4) { + return NULL; + } + qpb__ipv4_address__init(v4); + + v4->value = ntohl(addr->s_addr); + return v4; +} + +/* + * qpb__ipv4_address__get + */ +static inline int +qpb__ipv4_address__get (const Qpb__Ipv4Address *v4, struct in_addr *addr) +{ + addr->s_addr = htonl(v4->value); + return 1; +} + +/* + * qpb__ipv6_address__create + */ +static inline Qpb__Ipv6Address * +qpb__ipv6_address__create (qpb_allocator_t *allocator, struct in6_addr *addr) +{ + Qpb__Ipv6Address *v6; + + v6 = QPB_ALLOC(allocator, typeof(*v6)); + if (!v6) + return NULL; + + qpb__ipv6_address__init(v6); + v6->bytes.len = 16; + v6->bytes.data = qpb_alloc(allocator, 16); + if (!v6->bytes.data) + return NULL; + + memcpy(v6->bytes.data, addr->s6_addr, v6->bytes.len); + return v6; +} + +/* + * qpb__ipv6_address__get + * + * Read out information from a protobuf ipv6 address structure. + */ +static inline int +qpb__ipv6_address__get (const Qpb__Ipv6Address *v6, struct in6_addr *addr) +{ + if (v6->bytes.len != 16) + return 0; + + memcpy(addr->s6_addr, v6->bytes.data, v6->bytes.len); + return 1; +} + +/* + * qpb__l3_address__create + */ +#define qpb_l3_address_create qpb__l3_address__create +static inline Qpb__L3Address * +qpb__l3_address__create (qpb_allocator_t *allocator, union g_addr *addr, + u_char family) +{ + Qpb__L3Address *l3_addr; + + l3_addr = QPB_ALLOC(allocator, typeof(*l3_addr)); + if (!l3_addr) + return NULL; + + qpb__l3_address__init(l3_addr); + + switch (family) { + + case AF_INET: + l3_addr->v4 = qpb__ipv4_address__create (allocator, &addr->ipv4); + if (!l3_addr->v4) + return NULL; + + break; + + case AF_INET6: + l3_addr->v6 = qpb__ipv6_address__create (allocator, &addr->ipv6); + if (!l3_addr->v6) + return NULL; + + break; + } + return l3_addr; +} + +/* + * qpb__l3_address__get + * + * Read out a gateway address from a protobuf l3 address. + */ +#define qpb_l3_address_get qpb__l3_address__get +static inline int +qpb__l3_address__get (const Qpb__L3Address *l3_addr, + u_char *family, union g_addr *addr) +{ + if (l3_addr->v4) + { + qpb__ipv4_address__get (l3_addr->v4, &addr->ipv4); + *family = AF_INET; + return 1; + } + + if (l3_addr->v6) + { + qpb__ipv6_address__get(l3_addr->v6, &addr->ipv6); + *family = AF_INET6; + return 1; + } + + return 0; +} + +/* + * qpb__if_identifier__create + */ +#define qpb_if_identifier_create qpb__if_identifier__create +static inline Qpb__IfIdentifier * +qpb__if_identifier__create (qpb_allocator_t *allocator, uint if_index) +{ + Qpb__IfIdentifier *if_id; + + if_id = QPB_ALLOC(allocator, typeof(*if_id)); + if (!if_id) { + return NULL; + } + qpb__if_identifier__init(if_id); + if_id->has_index = 1; + if_id->index = if_index; + return if_id; +} + +/* + * qpb__if_identifier__get + * + * Get interface name and/or if_index from an if identifier. + */ +#define qpb_if_identifier_get qpb__if_identifier__get +static inline int +qpb__if_identifier__get (Qpb__IfIdentifier *if_id, uint *if_index, + char **name) +{ + char *str; + uint ix; + + if (!if_index) + if_index = &ix; + + if (!name) + name = &str; + + if (if_id->has_index) + *if_index = if_id->index; + else + *if_index = 0; + + *name = if_id->name; + return 1; +} + +#endif diff --git a/qpb/qpb.proto b/qpb/qpb.proto new file mode 100644 index 000000000..7ee409df8 --- /dev/null +++ b/qpb/qpb.proto @@ -0,0 +1,121 @@ +/* + * qpb.proto + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * Permission is granted to use, copy, modify and/or distribute this + * software under either one of the licenses below. + * + * Note that if you use other files from the Quagga tree directly or + * indirectly, then the licenses in those files still apply. + * + * Please retain both licenses below when modifying this code in the + * Quagga tree. + */ + +/* + * License Option 1: GPL + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * License Option 2: ISC License + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Protobuf definitions pertaining to the Quagga Protobuf component. + */ +package qpb; + +enum AddressFamily { + UNKNOWN_AF = 0; + IPV4 = 1; // IP version 4 + IPV6 = 2; // IP version 6 +}; + +enum SubAddressFamily { + UNKNOWN_SAF = 0; + UNICAST = 1; + MULTICAST = 2; +}; + +// +// An IP version 4 address, such as 10.1.1.1. +// +message Ipv4Address { + required fixed32 value = 1 ; +}; + +message Ipv6Address { + + // 16 bytes. + required bytes bytes = 1; +}; + +// +// An IP version 4 or IP version 6 address. +// +message L3Address { + optional Ipv4Address v4 = 1; + optional Ipv6Address v6 = 2; +}; + +// +// An IP prefix, such as 10.1/16. +// We use the message below to represent both IPv4 and IPv6 prefixes. +message L3Prefix { + required uint32 length = 1; + required bytes bytes = 2; +}; + +// +// Something that identifies an interface on a machine. It can either +// be a name (for instance, 'eth0') or a number currently. +// +message IfIdentifier { + optional uint32 index = 1; + optional string name = 2; +}; + +enum Protocol { + UNKNOWN_PROTO = 0; + LOCAL = 1; + CONNECTED = 2; + KERNEL = 3; + STATIC = 4; + RIP = 5; + RIPNG = 6; + OSPF = 7; + ISIS = 8; + BGP = 9; + OTHER = 10; +} \ No newline at end of file diff --git a/qpb/qpb_allocator.c b/qpb/qpb_allocator.c new file mode 100644 index 000000000..4b4830a47 --- /dev/null +++ b/qpb/qpb_allocator.c @@ -0,0 +1,67 @@ +/* + * qpb_allocator.c + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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 "linear_allocator.h" + +#include "qpb_allocator.h" + +/* + * _qpb_alloc + */ +static void * +_qpb_alloc (void *allocator_data, size_t size) +{ + return linear_allocator_alloc (allocator_data, size); +} + +/* + * _qpb_free + */ +static void +_qpb_free (void *allocator_data, void *ptr) +{ + linear_allocator_free (allocator_data, ptr); +} + +static ProtobufCAllocator allocator_template = { + _qpb_alloc, + _qpb_free, + NULL, + 8192, + NULL +}; + +/* + * qpb_allocator_init_linear + * + * Initialize qpb_allocator_t with the given linear allocator. + */ +void +qpb_allocator_init_linear (qpb_allocator_t *allocator, + linear_allocator_t *linear_allocator) +{ + *allocator = allocator_template; + allocator->allocator_data = linear_allocator; +} diff --git a/qpb/qpb_allocator.h b/qpb/qpb_allocator.h new file mode 100644 index 000000000..83ddf56cb --- /dev/null +++ b/qpb/qpb_allocator.h @@ -0,0 +1,113 @@ +/* + * qpb_allocator.h + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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. + */ + +/* + * Header file for quagga protobuf memory management code. + */ + +#ifndef _QPB_ALLOCATOR_H_ +#define _QPB_ALLOCATOR_H_ + +#include + +struct linear_allocator_t_; + +/* + * Alias for ProtobufCAllocator that is easier on the fingers. + */ +typedef ProtobufCAllocator qpb_allocator_t; + +/* + * qpb_alloc + */ +static inline void * +qpb_alloc (qpb_allocator_t *allocator, size_t size) +{ + return allocator->alloc (allocator->allocator_data, size); +} + +/* + * qpb_alloc_ptr_array + * + * Allocate space for the specified number of pointers. + */ +static inline void * +qpb_alloc_ptr_array (qpb_allocator_t *allocator, size_t num_ptrs) +{ + return qpb_alloc (allocator, num_ptrs * sizeof (void *)); +} + +/* + * qpb_free + */ +static inline void +qpb_free (qpb_allocator_t *allocator, void *ptr) +{ + allocator->free (allocator->allocator_data, ptr); +} + +/* + * QPB_ALLOC + * + * Convenience macro to reduce the probability of allocating memory of + * incorrect size. It returns enough memory to store the given type, + * and evaluates to an appropriately typed pointer. + */ +#define QPB_ALLOC(allocator, type) \ + (type *) qpb_alloc(allocator, sizeof(type)) + + +/* + * Externs. + */ +extern void qpb_allocator_init_linear (qpb_allocator_t *, + struct linear_allocator_t_ *); + +/* + * The following macros are for the common case where a qpb allocator + * is being used alongside a linear allocator that allocates memory + * off of the stack. + */ +#define QPB_DECLARE_STACK_ALLOCATOR(allocator, size) \ + qpb_allocator_t allocator; \ + linear_allocator_t lin_ ## allocator; \ + char lin_ ## allocator ## _buf[size] + +#define QPB_INIT_STACK_ALLOCATOR(allocator) \ + do \ + { \ + linear_allocator_init(&(lin_ ## allocator), \ + lin_ ## allocator ## _buf, \ + sizeof(lin_ ## allocator ## _buf)); \ + qpb_allocator_init_linear(&allocator, &(lin_ ## allocator)); \ + } while (0) + +#define QPB_RESET_STACK_ALLOCATOR(allocator) \ + do \ + { \ + linear_allocator_reset (&(lin_ ## allocator)); \ + } while (0) + +#endif /* _QPB_ALLOCATOR_H_ */ From b2624487659d8148ca253147fd7e63560a439c8b Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Mon, 4 Apr 2016 10:54:56 -0700 Subject: [PATCH 1077/1342] build: turn off automake portability warnings Modify configure.ac to disable portability warnings for automake -- our automake code (in particular common.am) uses some constructs specific to gmake. Signed-off-by: Avneesh Sachdev --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d36b580a0..8d92a3d92 100755 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,9 @@ AC_CANONICAL_BUILD() AC_CANONICAL_HOST() AC_CANONICAL_TARGET() -AM_INIT_AUTOMAKE(1.6) +# Disable portability warnings -- our automake code (in particular +# common.am) uses some constructs specific to gmake. +AM_INIT_AUTOMAKE([1.6 -Wno-portability]) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) AM_SILENT_RULES([yes]) From ef20ef7de9fe52931e7a5ce07b8228e87f7f52b6 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Mon, 4 Apr 2016 10:54:57 -0700 Subject: [PATCH 1078/1342] fpm: Add protobuf support for FPM. Code that allows a client to convey routes to a Forwarding Plane Manager component using protobuf instead of netlink.. * fpm/fpm.proto Protobuf definitions pertaining to the Forwarding Plane Manager. In particular, this file defines the AddRoute and DeleteRoute messages. * fpm/fpm.h Tweak FPM message header definition to also allow messages to be encoded in protobuf format. * fpm/{fpm_pb.h,.gitignore,.Makefile.am} Add the fpm_pb library, which contains code for interfacing with the FPM using protobuf. * configure.ac Generate fpm/Makefile. * Makefile.am Add fpm subdirectory to build. * common.am Add flags to be used by clients of the fpm_pb library. Signed-off-by: Avneesh Sachdev --- Makefile.am | 7 ++- configure.ac | 1 + fpm/.gitignore | 15 ++++++ fpm/Makefile.am | 29 ++++++++++++ fpm/fpm.h | 38 ++++++++++++---- fpm/fpm.proto | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ fpm/fpm_pb.c | 28 ++++++++++++ fpm/fpm_pb.h | 63 +++++++++++++++++++++++++ 8 files changed, 288 insertions(+), 12 deletions(-) create mode 100644 fpm/.gitignore create mode 100644 fpm/Makefile.am create mode 100644 fpm/fpm.proto create mode 100644 fpm/fpm_pb.c create mode 100644 fpm/fpm_pb.h diff --git a/Makefile.am b/Makefile.am index 87ba3d0c1..0cd75be8b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib qpb @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ +SUBDIRS = lib qpb fpm @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests -DIST_SUBDIRS = lib qpb zebra bgpd ripd ripngd ospfd ospf6d \ +DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd @@ -12,8 +12,7 @@ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ - tools/zebra.el tools/multiple-bgpd.sh \ - fpm/fpm.h + tools/zebra.el tools/multiple-bgpd.sh if HAVE_LATEX diff --git a/configure.ac b/configure.ac index 8d92a3d92..3818990fd 100755 --- a/configure.ac +++ b/configure.ac @@ -1585,6 +1585,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile tests/libzebra.tests/Makefile redhat/Makefile pkgsrc/Makefile + fpm/Makefile redhat/quagga.spec lib/version.h doc/defines.texi diff --git a/fpm/.gitignore b/fpm/.gitignore new file mode 100644 index 000000000..b133c52a4 --- /dev/null +++ b/fpm/.gitignore @@ -0,0 +1,15 @@ +Makefile +Makefile.in +*.o +tags +TAGS +.deps +.nfs* +*.lo +*.la +*.a +*.libs +.arch-inventory +.arch-ids +*~ +*.loT diff --git a/fpm/Makefile.am b/fpm/Makefile.am new file mode 100644 index 000000000..83ab31ce3 --- /dev/null +++ b/fpm/Makefile.am @@ -0,0 +1,29 @@ +include ../common.am + +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) + +PROTOBUF_INCLUDES=-I$(top_srcdir) +PROTOBUF_PACKAGE = fpm + +lib_LTLIBRARIES = libfpm_pb.la +libfpm_pb_la_LDFLAGS = -version-info 0:0:0 + +if HAVE_PROTOBUF +protobuf_srcs = + +protobuf_srcs_nodist = \ + fpm.pb-c.c +endif + +libfpm_pb_la_SOURCES = \ + fpm.h \ + fpm_pb.h \ + fpm_pb.c \ + $(protobuf_srcs) + +nodist_libfpm_pb_la_SOURCES = $(protobuf_srcs_nodist) + +CLEANFILES = $(Q_CLEANFILES) + +BUILT_SOURCES = $(Q_PROTOBUF_SRCS) +EXTRA_DIST = fpm.proto diff --git a/fpm/fpm.h b/fpm/fpm.h index 9a1dbf2b0..85285996c 100644 --- a/fpm/fpm.h +++ b/fpm/fpm.h @@ -102,6 +102,10 @@ */ #define FPM_MAX_MSG_LEN 4096 +#ifdef __SUNPRO_C +#pragma pack(1) +#endif + /* * Header that precedes each fpm message to/from the FPM. */ @@ -120,13 +124,13 @@ typedef struct fpm_msg_hdr_t_ /* * Length of entire message, including the header, in network byte * order. - * - * Note that msg_len is rounded up to make sure that message is at - * the desired alignment. This means that some payloads may need - * padding at the end. */ uint16_t msg_len; -} fpm_msg_hdr_t; +} __attribute__ ((packed)) fpm_msg_hdr_t; + +#ifdef __SUNPRO_C +#pragma pack() +#endif /* * The current version of the FPM protocol is 1. @@ -139,8 +143,14 @@ typedef enum fpm_msg_type_e_ { /* * Indicates that the payload is a completely formed netlink * message. + * + * XXX Netlink cares about the alignment of messages. When any + * FPM_MSG_TYPE_NETLINK messages are sent over a channel, then all + * messages should be sized such that netlink alignment is + * maintained. */ FPM_MSG_TYPE_NETLINK = 1, + FPM_MSG_TYPE_PROTOBUF = 2, } fpm_msg_type_e; /* @@ -154,6 +164,8 @@ typedef enum fpm_msg_type_e_ { * fpm_msg_align * * Round up the given length to the desired alignment. + * + * **NB**: Alignment is required only when netlink messages are used. */ static inline size_t fpm_msg_align (size_t len) @@ -165,7 +177,13 @@ fpm_msg_align (size_t len) * The (rounded up) size of the FPM message header. This ensures that * the message payload always starts at an aligned address. */ -#define FPM_MSG_HDR_LEN (fpm_msg_align (sizeof (fpm_msg_hdr_t))) +#define FPM_MSG_HDR_LEN (sizeof (fpm_msg_hdr_t)) + +#ifndef COMPILE_ASSERT +#define COMPILE_ASSERT(x) extern int __dummy[2 * !!(x) - 1] +#endif + +COMPILE_ASSERT(FPM_MSG_ALIGNTO == FPM_MSG_HDR_LEN); /* * fpm_data_len_to_msg_len @@ -176,7 +194,7 @@ fpm_msg_align (size_t len) static inline size_t fpm_data_len_to_msg_len (size_t data_len) { - return fpm_msg_align (data_len) + FPM_MSG_HDR_LEN; + return data_len + FPM_MSG_HDR_LEN; } /* @@ -250,7 +268,11 @@ fpm_msg_hdr_ok (const fpm_msg_hdr_t *hdr) if (msg_len < FPM_MSG_HDR_LEN || msg_len > FPM_MAX_MSG_LEN) return 0; - if (fpm_msg_align (msg_len) != msg_len) + /* + * Netlink messages must be aligned properly. + */ + if (hdr->msg_type == FPM_MSG_TYPE_NETLINK && + fpm_msg_align (msg_len) != msg_len) return 0; return 1; diff --git a/fpm/fpm.proto b/fpm/fpm.proto new file mode 100644 index 000000000..26d634630 --- /dev/null +++ b/fpm/fpm.proto @@ -0,0 +1,119 @@ +// +// fpm.proto +// +// @copyright Copyright (C) 2016 Sproute Networks, Inc. +// +// @author Avneesh Sachdev +// +// Permission is granted to use, copy, modify and/or distribute this +// software under either one of the licenses below. +// +// Note that if you use other files from the Quagga tree directly or +// indirectly, then the licenses in those files still apply. +// +// Please retain both licenses below when modifying this code in the +// Quagga tree. +// + +// +// License Option 1: GPL +// +// This program 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 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful,but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// + +// +// License Option 2: ISC License +// +// Permission to use, copy, modify, and/or distribute this software +// for any purpose with or without fee is hereby granted, provided +// that the above copyright notice and this permission notice appear +// in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +// +// Protobuf definitions pertaining to the Forwarding Plane Manager component. +// + +package fpm; + +import "qpb/qpb.proto"; + +// +// A Nexthop for a route. It indicates how packets to a given prefix +// should be forwarded (for instance, send them out of a specified +// interface to a specified address). +// +message Nexthop { + optional qpb.IfIdentifier if_id = 2; + optional qpb.L3Address address = 3; +} + +message RouteKey { + optional qpb.L3Prefix prefix = 1; +} + +message DeleteRoute { + required uint32 vrf_id = 1; + required qpb.AddressFamily address_family = 2; + required qpb.SubAddressFamily sub_address_family = 3; + required RouteKey key = 4; +} + +enum RouteType { + UNKNOWN = 0; + NORMAL = 1; + UNREACHABLE = 2; + BLACKHOLE = 3; +} + +message AddRoute { + required uint32 vrf_id = 1; + required qpb.AddressFamily address_family = 2; + required qpb.SubAddressFamily sub_address_family = 3; + required RouteKey key = 4; + + optional RouteType route_type = 5; + + required qpb.Protocol protocol = 6; + + required int32 metric = 8; + + repeated Nexthop nexthops = 9; +} + +// +// Any message from the FPM. +// +message Message { + enum Type { + UNKNOWN_MSG = 0; + ADD_ROUTE = 1; + DELETE_ROUTE = 2; + }; + + optional Type type = 1; + + optional AddRoute add_route = 2; + optional DeleteRoute delete_route = 3; +} diff --git a/fpm/fpm_pb.c b/fpm/fpm_pb.c new file mode 100644 index 000000000..ba18627ea --- /dev/null +++ b/fpm/fpm_pb.c @@ -0,0 +1,28 @@ +/* + * fpm_pb.c + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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. + */ + +/* + * Main file for the fpm_pb library. + */ diff --git a/fpm/fpm_pb.h b/fpm/fpm_pb.h new file mode 100644 index 000000000..8f74ac06e --- /dev/null +++ b/fpm/fpm_pb.h @@ -0,0 +1,63 @@ +/* + * fpm_pb.h + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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. + */ + +/* + * Public header file for fpm protobuf definitions. + */ + +#ifndef _FPM_PB_H +#define _FPM_PB_H + +#include "route_types.h" +#include "qpb/qpb.h" + +#include "fpm/fpm.pb-c.h" + +/* + * fpm__route_key__create + */ +#define fpm_route_key_create fpm__route_key__create +static inline Fpm__RouteKey * +fpm__route_key__create (qpb_allocator_t *allocator, struct prefix *prefix) +{ + Fpm__RouteKey *key; + + key = QPB_ALLOC (allocator, typeof (*key)); + if (!key) + { + return NULL; + } + fpm__route_key__init (key); + + key->prefix = qpb__l3_prefix__create (allocator, prefix); + if (!key->prefix) + { + return NULL; + } + + return key; +} + +#endif From b8ae330cd3c65808044d344b24f0917b312c4fb9 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Thu, 14 Jul 2016 09:59:30 -0700 Subject: [PATCH 1079/1342] Use only the ISC license for .proto files. Simplify licensing for protobuf files based on discussion on the quagga-dev mailing list. Previously, users could choose between the GPL and the ISC license. Signed-off-by: Avneesh Sachdev Signed-off-by: Avneesh Sachdev --- fpm/fpm.proto | 31 ------------------------------- qpb/qpb.proto | 31 ------------------------------- 2 files changed, 62 deletions(-) diff --git a/fpm/fpm.proto b/fpm/fpm.proto index 26d634630..318e80a92 100644 --- a/fpm/fpm.proto +++ b/fpm/fpm.proto @@ -5,37 +5,6 @@ // // @author Avneesh Sachdev // -// Permission is granted to use, copy, modify and/or distribute this -// software under either one of the licenses below. -// -// Note that if you use other files from the Quagga tree directly or -// indirectly, then the licenses in those files still apply. -// -// Please retain both licenses below when modifying this code in the -// Quagga tree. -// - -// -// License Option 1: GPL -// -// This program 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 of the License, or (at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful,but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -// more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// - -// -// License Option 2: ISC License -// // Permission to use, copy, modify, and/or distribute this software // for any purpose with or without fee is hereby granted, provided // that the above copyright notice and this permission notice appear diff --git a/qpb/qpb.proto b/qpb/qpb.proto index 7ee409df8..8323d3ed7 100644 --- a/qpb/qpb.proto +++ b/qpb/qpb.proto @@ -5,37 +5,6 @@ * * @author Avneesh Sachdev * - * Permission is granted to use, copy, modify and/or distribute this - * software under either one of the licenses below. - * - * Note that if you use other files from the Quagga tree directly or - * indirectly, then the licenses in those files still apply. - * - * Please retain both licenses below when modifying this code in the - * Quagga tree. - */ - -/* - * License Option 1: GPL - * - * This program 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 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * License Option 2: ISC License - * * Permission to use, copy, modify, and/or distribute this software * for any purpose with or without fee is hereby granted, provided * that the above copyright notice and this permission notice appear From 5779fda137803a4b1e534f6ba70781681baf3fda Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Mon, 4 Apr 2016 10:54:58 -0700 Subject: [PATCH 1080/1342] zebra: optionally use protobuf with FPM Change zebra so that it can optionally use protobuf serialization when communicating with a Forwarding Plane Manager component. * zebra/main.c Add the --fpm-format/-F command line option. This allows the user to control the format (protbuf|netlink) that is used to communicate with the FPM. * zebra/zebra_fpm.c - zebra_init_msg_format(), This new function is invoked on process startup to determine the FPM format that should be used. - zfpm_init() Change to accept any 'FPM message format' specified by the user (via the new command line flag). - zebra_encode_route() Tweak to use the selected FPM format. * zebra_fpm_protobuf.c New code to build protobuf messages to be sent to the FPM. * zebra/Makefile.am - Include common.am - Build new file zebra_fpm_protobuf.c when protobuf is available. - Link with the fpm_pb library. Signed-off-by: Avneesh Sachdev --- zebra/Makefile.am | 10 +- zebra/main.c | 14 +- zebra/zebra_fpm.c | 139 ++++++++++++++--- zebra/zebra_fpm.h | 3 +- zebra/zebra_fpm_private.h | 5 + zebra/zebra_fpm_protobuf.c | 311 +++++++++++++++++++++++++++++++++++++ 6 files changed, 454 insertions(+), 28 deletions(-) create mode 100644 zebra/zebra_fpm_protobuf.c diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 90ce7b97d..ab09a36b2 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -1,3 +1,5 @@ +include ../common.am + ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @@ -20,6 +22,10 @@ if HAVE_NETLINK othersrc = zebra_fpm_netlink.c endif +if HAVE_PROTOBUF +protobuf_srcs = zebra_fpm_protobuf.c +endif + AM_CFLAGS = $(WERROR) sbin_PROGRAMS = zebra @@ -30,7 +36,7 @@ zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ - $(othersrc) + $(othersrc) $(protobuf_srcs) testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c \ @@ -42,7 +48,7 @@ noinst_HEADERS = \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h \ ioctl_solaris.h -zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) +zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS) testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) diff --git a/zebra/main.c b/zebra/main.c index 8370732d7..35cb1593e 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -71,6 +71,7 @@ struct option longopts[] = { "batch", no_argument, NULL, 'b'}, { "daemon", no_argument, NULL, 'd'}, { "keep_kernel", no_argument, NULL, 'k'}, + { "fpm_format", required_argument, NULL, 'F'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, @@ -130,6 +131,7 @@ usage (char *progname, int status) "-b, --batch Runs in batch mode\n"\ "-d, --daemon Runs in daemon mode\n"\ "-f, --config_file Set configuration file name\n"\ + "-F, --fpm_format Set fpm format to 'netlink' or 'protobuf'\n"\ "-i, --pid_file Set process identifier file name\n"\ "-z, --socket Set path of zebra socket\n"\ "-k, --keep_kernel Don't delete old routes which installed by "\ @@ -295,6 +297,7 @@ main (int argc, char **argv) char *progname; struct thread thread; char *zserv_path = NULL; + char *fpm_format = NULL; /* Set umask before anything for security */ umask (0027); @@ -310,9 +313,9 @@ main (int argc, char **argv) int opt; #ifdef HAVE_NETLINK - opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vs:C", longopts, 0); + opt = getopt_long (argc, argv, "bdkf:F:i:z:hA:P:ru:g:vs:C", longopts, 0); #else - opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "bdkf:F:i:z:hA:P:ru:g:vC", longopts, 0); #endif /* HAVE_NETLINK */ if (opt == EOF) @@ -336,6 +339,9 @@ main (int argc, char **argv) case 'f': config_file = optarg; break; + case 'F': + fpm_format = optarg; + break; case 'A': vty_addr = optarg; break; @@ -423,9 +429,9 @@ main (int argc, char **argv) #endif /* HAVE_SNMP */ #ifdef HAVE_FPM - zfpm_init (zebrad.master, 1, 0); + zfpm_init (zebrad.master, 1, 0, fpm_format); #else - zfpm_init (zebrad.master, 0, 0); + zfpm_init (zebrad.master, 0, 0, fpm_format); #endif /* Process the configuration file. Among other configuration diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 9cbbf689d..22fc6cac9 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -138,6 +138,15 @@ typedef enum { } zfpm_state_t; +/* + * Message format to be used to communicate with the FPM. + */ +typedef enum +{ + ZFPM_MSG_FORMAT_NONE, + ZFPM_MSG_FORMAT_NETLINK, + ZFPM_MSG_FORMAT_PROTOBUF, +} zfpm_msg_format_e; /* * Globals. */ @@ -149,6 +158,11 @@ typedef struct zfpm_glob_t_ */ int enabled; + /* + * Message format to be used to communicate with the fpm. + */ + zfpm_msg_format_e message_format; + struct thread_master *master; zfpm_state_t state; @@ -863,19 +877,40 @@ zfpm_writes_pending (void) */ static inline int zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf, - size_t in_buf_len) + size_t in_buf_len, fpm_msg_type_e *msg_type) { -#ifndef HAVE_NETLINK - return 0; -#else - + size_t len; int cmd; + len = 0; - cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE; + *msg_type = FPM_MSG_TYPE_NONE; - return zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len); + switch (zfpm_g->message_format) { + case ZFPM_MSG_FORMAT_PROTOBUF: +#ifdef HAVE_PROTOBUF + len = zfpm_protobuf_encode_route (dest, rib, (uint8_t *) in_buf, + in_buf_len); + *msg_type = FPM_MSG_TYPE_PROTOBUF; +#endif + break; + + case ZFPM_MSG_FORMAT_NETLINK: +#ifdef HAVE_NETLINK + *msg_type = FPM_MSG_TYPE_NETLINK; + cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE; + len = zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len); + assert(fpm_msg_align(len) == len); + *msg_type = FPM_MSG_TYPE_NETLINK; #endif /* HAVE_NETLINK */ + break; + + default: + break; + } + + return len; + } /* @@ -883,7 +918,7 @@ zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf, * * Returns the rib that is to be sent to the FPM for a given dest. */ -static struct rib * +struct rib * zfpm_route_for_update (rib_dest_t *dest) { struct rib *rib; @@ -919,6 +954,7 @@ zfpm_build_updates (void) fpm_msg_hdr_t *hdr; struct rib *rib; int is_add, write_msg; + fpm_msg_type_e msg_type; s = zfpm_g->obuf; @@ -943,7 +979,6 @@ zfpm_build_updates (void) hdr = (fpm_msg_hdr_t *) buf; hdr->version = FPM_PROTO_VERSION; - hdr->msg_type = FPM_MSG_TYPE_NETLINK; data = fpm_msg_data (hdr); @@ -963,11 +998,13 @@ zfpm_build_updates (void) } if (write_msg) { - data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data); + data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data, + &msg_type); assert (data_len); if (data_len) { + hdr->msg_type = msg_type; msg_len = fpm_data_len_to_msg_len (data_len); hdr->msg_len = htons (msg_len); stream_forward_endp (s, msg_len); @@ -1569,6 +1606,64 @@ DEFUN ( no_fpm_remote_ip, } +/* + * zfpm_init_message_format + */ +static inline void +zfpm_init_message_format (const char *format) +{ + int have_netlink, have_protobuf; + + have_netlink = have_protobuf = 0; + +#ifdef HAVE_NETLINK + have_netlink = 1; +#endif + +#ifdef HAVE_PROTOBUF + have_protobuf = 1; +#endif + + zfpm_g->message_format = ZFPM_MSG_FORMAT_NONE; + + if (!format) + { + if (have_netlink) + { + zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK; + } + else if (have_protobuf) + { + zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF; + } + return; + } + + if (!strcmp ("netlink", format)) + { + if (!have_netlink) + { + zlog_err ("FPM netlink message format is not available"); + return; + } + zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK; + return; + } + + if (!strcmp ("protobuf", format)) + { + if (!have_protobuf) + { + zlog_err ("FPM protobuf message format is not available"); + return; + } + zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF; + return; + } + + zlog_warn ("Unknown fpm format '%s'", format); +} + /** * fpm_remote_srv_write * @@ -1598,11 +1693,13 @@ int fpm_remote_srv_write (struct vty *vty ) * * @param[in] port port at which FPM is running. * @param[in] enable TRUE if the zebra FPM module should be enabled + * @param[in] format to use to talk to the FPM. Can be 'netink' or 'protobuf'. * * Returns TRUE on success. */ int -zfpm_init (struct thread_master *master, int enable, uint16_t port) +zfpm_init (struct thread_master *master, int enable, uint16_t port, + const char *format) { static int initialized = 0; @@ -1618,16 +1715,6 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port) zfpm_g->sock = -1; zfpm_g->state = ZFPM_STATE_IDLE; - /* - * Netlink must currently be available for the Zebra-FPM interface - * to be enabled. - */ -#ifndef HAVE_NETLINK - enable = 0; -#endif - - zfpm_g->enabled = enable; - zfpm_stats_init (&zfpm_g->stats); zfpm_stats_init (&zfpm_g->last_ivl_stats); zfpm_stats_init (&zfpm_g->cumulative_stats); @@ -1637,6 +1724,16 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port) install_element (CONFIG_NODE, &fpm_remote_ip_cmd); install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd); + zfpm_init_message_format(format); + + /* + * Disable FPM interface if no suitable format is available. + */ + if (zfpm_g->message_format == ZFPM_MSG_FORMAT_NONE) + enable = 0; + + zfpm_g->enabled = enable; + if (!enable) { return 1; } diff --git a/zebra/zebra_fpm.h b/zebra/zebra_fpm.h index 44dec0286..ecd23c768 100644 --- a/zebra/zebra_fpm.h +++ b/zebra/zebra_fpm.h @@ -28,7 +28,8 @@ /* * Externs. */ -extern int zfpm_init (struct thread_master *master, int enable, uint16_t port); +extern int zfpm_init (struct thread_master *master, int enable, uint16_t port, + const char *message_format); extern void zfpm_trigger_update (struct route_node *rn, const char *reason); #endif /* _ZEBRA_FPM_H */ diff --git a/zebra/zebra_fpm_private.h b/zebra/zebra_fpm_private.h index 809a70a44..1c4fd4c22 100644 --- a/zebra/zebra_fpm_private.h +++ b/zebra/zebra_fpm_private.h @@ -53,4 +53,9 @@ extern int zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib, char *in_buf, size_t in_buf_len); +extern int +zfpm_protobuf_encode_route (rib_dest_t *dest, struct rib *rib, + uint8_t *in_buf, size_t in_buf_len); + +extern struct rib *zfpm_route_for_update (rib_dest_t *dest); #endif /* _ZEBRA_FPM_PRIVATE_H */ diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c new file mode 100644 index 000000000..beef310b1 --- /dev/null +++ b/zebra/zebra_fpm_protobuf.c @@ -0,0 +1,311 @@ +/* + * zebra_fpm_protobuf.c + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * 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 + +#include "log.h" +#include "rib.h" + +#include "qpb/qpb.pb-c.h" +#include "qpb/qpb.h" +#include "qpb/qpb_allocator.h" +#include "qpb/linear_allocator.h" +#include "fpm/fpm_pb.h" + +#include "zebra_fpm_private.h" + +/* + * create_delete_route_message + */ +static Fpm__DeleteRoute * +create_delete_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, + struct rib *rib) +{ + Fpm__DeleteRoute *msg; + + msg = QPB_ALLOC(allocator, typeof(*msg)); + if (!msg) { + assert(0); + return NULL; + } + + fpm__delete_route__init(msg); + msg->vrf_id = rib_dest_vrf(dest)->vrf_id; + + qpb_address_family_set(&msg->address_family, rib_dest_af(dest)); + + /* + * XXX Hardcode subaddress family for now. + */ + msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; + msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest)); + if (!msg->key) { + assert(0); + return NULL; + } + + return msg; +} + +/* + * add_nexthop + */ +static inline int +add_nexthop (qpb_allocator_t *allocator, Fpm__AddRoute *msg, rib_dest_t *dest, + struct nexthop *nexthop) +{ + uint32_t if_index; + union g_addr *gateway, *src; + + gateway = src = NULL; + + if_index = nexthop->ifindex; + + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + { + gateway = &nexthop->gate; + if (nexthop->src.ipv4.s_addr) + src = &nexthop->src; + } + + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + { + gateway = &nexthop->gate; + } + + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME) + { + if (nexthop->src.ipv4.s_addr) + src = &nexthop->src; + } + + if (!gateway && if_index == 0) + return 0; + + /* + * We have a valid nexthop. + */ + { + Fpm__Nexthop *pb_nh; + pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh)); + if (!pb_nh) { + assert(0); + return 0; + } + + fpm__nexthop__init(pb_nh); + + if (if_index != 0) { + pb_nh->if_id = qpb_if_identifier_create (allocator, if_index); + } + + if (gateway) { + pb_nh->address = qpb_l3_address_create (allocator, gateway, + rib_dest_af(dest)); + } + + msg->nexthops[msg->n_nexthops++] = pb_nh; + } + + // TODO: Use src. + + return 1; +} + +/* + * create_add_route_message + */ +static Fpm__AddRoute * +create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, + struct rib *rib) +{ + Fpm__AddRoute *msg; + int discard; + struct nexthop *nexthop, *tnexthop; + int recursing; + uint num_nhs, u; + struct nexthop *nexthops[MAX (MULTIPATH_NUM, 64)]; + + msg = QPB_ALLOC(allocator, typeof(*msg)); + if (!msg) { + assert(0); + return NULL; + } + + fpm__add_route__init(msg); + + msg->vrf_id = rib_dest_vrf(dest)->vrf_id; + + qpb_address_family_set (&msg->address_family, rib_dest_af(dest)); + + /* + * XXX Hardcode subaddress family for now. + */ + msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; + msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest)); + qpb_protocol_set (&msg->protocol, rib->type); + + if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) + discard = 1; + else + discard = 0; + + if (discard) + { + if (rib->flags & ZEBRA_FLAG_BLACKHOLE) { + msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE; + } else if (rib->flags & ZEBRA_FLAG_REJECT) { + msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE; + } else { + assert (0); + } + return msg; + } + else { + msg->route_type = FPM__ROUTE_TYPE__NORMAL; + } + + msg->metric = rib->metric; + + /* + * Figure out the set of nexthops to be added to the message. + */ + num_nhs = 0; + for (ALL_NEXTHOPS_RO (rib->nexthop, nexthop, tnexthop, recursing)) + { + if (MULTIPATH_NUM != 0 && num_nhs >= MULTIPATH_NUM) + break; + + if (num_nhs >= ZEBRA_NUM_OF(nexthops)) + break; + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + continue; + + nexthops[num_nhs] = nexthop; + num_nhs++; + } + + if (!num_nhs) { + zfpm_debug ("netlink_encode_route(): No useful nexthop."); + assert(0); + return NULL; + } + + /* + * And add them to the message. + */ + if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) { + assert(0); + return NULL; + } + + msg->n_nexthops = 0; + for (u = 0; u < num_nhs; u++) { + if (!add_nexthop(allocator, msg, dest, nexthops[u])) { + assert(0); + return NULL; + } + } + + assert(msg->n_nexthops == num_nhs); + + return msg; +} + +/* + * create_route_message + */ +static Fpm__Message * +create_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, + struct rib *rib) +{ + Fpm__Message *msg; + + msg = QPB_ALLOC(allocator, typeof(*msg)); + if (!msg) { + assert(0); + return NULL; + } + + fpm__message__init(msg); + + if (!rib) { + msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE; + msg->delete_route = create_delete_route_message(allocator, dest, rib); + if (!msg->delete_route) { + assert(0); + return NULL; + } + return msg; + } + + msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE; + msg->add_route = create_add_route_message(allocator, dest, rib); + if (!msg->add_route) { + assert(0); + return NULL; + } + + return msg; +} + +/* + * zfpm_protobuf_encode_route + * + * Create a protobuf message corresponding to the given route in the + * given buffer space. + * + * Returns the number of bytes written to the buffer. 0 or a negative + * value indicates an error. + */ +int +zfpm_protobuf_encode_route (rib_dest_t *dest, struct rib *rib, + uint8_t *in_buf, size_t in_buf_len) +{ + Fpm__Message *msg; + QPB_DECLARE_STACK_ALLOCATOR (allocator, 4096); + size_t len; + + QPB_INIT_STACK_ALLOCATOR (allocator); + + msg = create_route_message(&allocator, dest, rib); + if (!msg) { + assert(0); + return 0; + } + + len = fpm__message__pack(msg, (uint8_t *) in_buf); + assert(len <= in_buf_len); + + QPB_RESET_STACK_ALLOCATOR (allocator); + return len; +} From 6112d11a978af54f87ac55daa9e965d949cb0041 Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Mon, 4 Apr 2016 10:54:59 -0700 Subject: [PATCH 1081/1342] doc: add blurb on use of protobuf with FPM Add text about using protobuf as an alternative format for the FPM interface. Signed-off-by: Avneesh Sachdev --- doc/main.texi | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/doc/main.texi b/doc/main.texi index 209a70392..0874c5c7e 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -407,8 +407,32 @@ routes that it may have picked up from the kernel. The existing interaction of zebra with the kernel remains unchanged -- that is, the kernel continues to receive FIB updates as before. -The format of the messages exchanged with the FPM is defined by the -file @file{fpm/fpm.h} in the quagga tree. +The encapsulation header for the messages exchanged with the FPM is +defined by the file @file{fpm/fpm.h} in the quagga tree. The routes +themselves are encoded in netlink or protobuf format, with netlink +being the default. + +Protobuf is one of a number of new serialization formats wherein the +message schema is expressed in a purpose-built language. Code for +encoding/decoding to/from the wire format is generated from the +schema. Protobuf messages can be extended easily while maintaining +backward-compatibility with older code. Protobuf has the following +advantages over netlink: + +@itemize +@item +Code for serialization/deserialization is generated +automatically. This reduces the likelihood of bugs, allows third-party +programs to be integrated quickly, and makes it easy to add fields. +@item +The message format is not tied to an OS (Linux), and can be evolved +independently. +@end itemize + +As mentioned before, zebra encodes routes sent to the FPM in netlink +format by default. The format can be controlled via the +@code{--fpm_format} command-line option to zebra, which currently +takes the values @code{netlink} and @code{protobuf}. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, From 7e4025cb65f79d584911042d3e19eee787b9115b Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Fri, 11 Mar 2016 12:21:24 -0800 Subject: [PATCH 1082/1342] build: support for "development build" * configure.ac Add the --enable-dev-build flag. It controls the DEV_BUILD define for autoconf and automake, which can be used to conditionally build in code that is only intended for development.. Signed-off-by: Avneesh Sachdev --- configure.ac | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index 3818990fd..f0277628e 100755 --- a/configure.ac +++ b/configure.ac @@ -306,6 +306,9 @@ AC_ARG_ENABLE(werror, AC_ARG_ENABLE([protobuf], AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support])) +AC_ARG_ENABLE([dev_build], + AS_HELP_STRING([--enable-dev-build], [build for development])) + if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then LDFLAGS="${LDFLAGS} -rdynamic" @@ -324,6 +327,11 @@ if test "${enable_fpm}" = "yes"; then AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) fi +if test "x${enable_dev_build}" = "xyes"; then + AC_DEFINE(DEV_BUILD,,Build for development) +fi +AM_CONDITIONAL([DEV_BUILD], [test "x$enable_dev_build" = "xyes"]) + # # Logic for protobuf support. # From 3bccb4f3df0530bb4d8961b0867ea04c1bca065f Mon Sep 17 00:00:00 2001 From: Avneesh Sachdev Date: Fri, 11 Mar 2016 12:21:26 -0800 Subject: [PATCH 1083/1342] zebra: add developer test functions for FPM code Add test functions for the zebra code that interfaces with the Forwarding Plane Manager. These functions can be invoked in a development build via the recently-added 'invoke' command. For example: # invoke zebra function zfpm_dt_benchmark_protobuf_encode 100000 Changes: * zebra/zebra_fpm_dt.c Add the following functions. Each function encodes or decodes a route in a particular FPM format a specified number of times. - zfpm_dt_benchmark_netlink_encode() - zfpm_dt_benchmark_protobuf_encode() - zfpm_dt_benchmark_protobuf_decode() * zebra/Makefile.am Compile zebra_fpm_dt when building a development build. Signed-off-by: Avneesh Sachdev --- zebra/Makefile.am | 6 +- zebra/zebra_fpm_dt.c | 275 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 zebra/zebra_fpm_dt.c diff --git a/zebra/Makefile.am b/zebra/Makefile.am index ab09a36b2..abd3797da 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -26,6 +26,10 @@ if HAVE_PROTOBUF protobuf_srcs = zebra_fpm_protobuf.c endif +if DEV_BUILD +dev_srcs = zebra_fpm_dt.c +endif + AM_CFLAGS = $(WERROR) sbin_PROGRAMS = zebra @@ -36,7 +40,7 @@ zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ - $(othersrc) $(protobuf_srcs) + $(othersrc) $(protobuf_srcs) $(dev_srcs) testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c \ diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c new file mode 100644 index 000000000..bd171c89b --- /dev/null +++ b/zebra/zebra_fpm_dt.c @@ -0,0 +1,275 @@ +/* + * zebra_fpm_dt.c + * + * @copyright Copyright (C) 2016 Sproute Networks, Inc. + * + * @author Avneesh Sachdev + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * Developer tests for the zebra code that interfaces with the + * forwarding plane manager. + * + * The functions here are built into developer builds of zebra (when + * DEV_BUILD is defined), and can be called via the 'invoke' cli + * command. + * + * For example: + * + * # invoke zebra function zfpm_dt_benchmark_protobuf_encode 100000 + * + */ + +#include +#include "log.h" +#include "vrf.h" + +#include "zebra/rib.h" + +#include "zebra_fpm_private.h" + +#include "qpb/qpb_allocator.h" +#include "qpb/linear_allocator.h" + +#include "qpb/qpb.h" +#include "fpm/fpm.pb-c.h" + +/* + * Externs. + */ +extern int zfpm_dt_benchmark_netlink_encode (int argc, const char **argv); +extern int zfpm_dt_benchmark_protobuf_encode (int argc, const char **argv); +extern int zfpm_dt_benchmark_protobuf_decode (int argc, const char **argv); + +/* + * zfpm_dt_find_route + * + * Selects a suitable rib destination for fpm interface tests. + */ +static int +zfpm_dt_find_route (rib_dest_t **dest_p, struct rib **rib_p) +{ + struct route_node *rnode; + route_table_iter_t iter; + struct route_table *table; + rib_dest_t *dest; + struct rib *rib; + int ret; + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + if (!table) + return 0; + + route_table_iter_init(&iter, table); + while ((rnode = route_table_iter_next(&iter))) + { + dest = rib_dest_from_rnode (rnode); + + if (!dest) + continue; + + rib = zfpm_route_for_update(dest); + if (!rib) + continue; + + if (rib->nexthop_active_num <= 0) + continue; + + *dest_p = dest; + *rib_p = rib; + ret = 1; + goto done; + } + + ret = 0; + + done: + route_table_iter_cleanup(&iter); + return ret; +} +#ifdef HAVE_NETLINK + +/* + * zfpm_dt_benchmark_netlink_encode + */ +int +zfpm_dt_benchmark_netlink_encode (int argc, const char **argv) +{ + int times, i, len; + rib_dest_t *dest; + struct rib *rib; + char buf[4096]; + + times = 100000; + if (argc > 0) { + times = atoi(argv[0]); + } + + if (!zfpm_dt_find_route(&dest, &rib)) { + return 1; + } + + for (i = 0; i < times; i++) { + len = zfpm_netlink_encode_route(RTM_NEWROUTE, dest, rib, buf, sizeof(buf)); + if (len <= 0) { + return 2; + } + } + return 0; +} + +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_PROTOBUF + +/* + * zfpm_dt_benchmark_protobuf_encode + */ +int +zfpm_dt_benchmark_protobuf_encode (int argc, const char **argv) +{ + int times, i, len; + rib_dest_t *dest; + struct rib *rib; + uint8_t buf[4096]; + + times = 100000; + if (argc > 0) { + times = atoi(argv[0]); + } + + if (!zfpm_dt_find_route(&dest, &rib)) { + return 1; + } + + for (i = 0; i < times; i++) { + len = zfpm_protobuf_encode_route(dest, rib, buf, sizeof(buf)); + if (len <= 0) { + return 2; + } + } + return 0; +} + +/* + * zfpm_dt_log_fpm_message + */ +static void +zfpm_dt_log_fpm_message (Fpm__Message *msg) +{ + Fpm__AddRoute *add_route; + Fpm__Nexthop *nexthop; + struct prefix prefix; + u_char family, nh_family; + uint if_index; + char *if_name; + size_t i; + char buf[INET6_ADDRSTRLEN]; + union g_addr nh_addr; + + if (msg->type != FPM__MESSAGE__TYPE__ADD_ROUTE) + return; + + zfpm_debug ("Add route message"); + add_route = msg->add_route; + + if (!qpb_address_family_get (add_route->address_family, &family)) + return; + + if (!qpb_l3_prefix_get (add_route->key->prefix, family, &prefix)) + return; + + zfpm_debug ("Vrf id: %d, Prefix: %s/%d, Metric: %d", add_route->vrf_id, + inet_ntop (family, &prefix.u.prefix, buf, sizeof (buf)), + prefix.prefixlen, add_route->metric); + + /* + * Go over nexthops. + */ + for (i = 0; i < add_route->n_nexthops; i++) + { + nexthop = add_route->nexthops[i]; + if (!qpb_if_identifier_get (nexthop->if_id, &if_index, &if_name)) + continue; + + if (nexthop->address) + qpb_l3_address_get (nexthop->address, &nh_family, &nh_addr); + + zfpm_debug ("Nexthop - if_index: %d (%s), gateway: %s, ", if_index, + if_name ? if_name : "name not specified", + nexthop->address ? inet_ntoa (nh_addr.ipv4) : "None"); + } +} + +/* + * zfpm_dt_benchmark_protobuf_decode + */ +int +zfpm_dt_benchmark_protobuf_decode (int argc, const char **argv) +{ + int times, i, len; + rib_dest_t *dest; + struct rib *rib; + uint8_t msg_buf[4096]; + QPB_DECLARE_STACK_ALLOCATOR (allocator, 8192); + Fpm__Message *fpm_msg; + + QPB_INIT_STACK_ALLOCATOR (allocator); + + times = 100000; + if (argc > 0) + times = atoi(argv[0]); + + if (!zfpm_dt_find_route (&dest, &rib)) + return 1; + + /* + * Encode the route into the message buffer once only. + */ + len = zfpm_protobuf_encode_route (dest, rib, msg_buf, sizeof (msg_buf)); + if (len <= 0) + return 2; + + // Decode once, and display the decoded message + fpm_msg = fpm__message__unpack(&allocator, len, msg_buf); + + if (fpm_msg) + { + zfpm_dt_log_fpm_message(fpm_msg); + QPB_RESET_STACK_ALLOCATOR (allocator); + } + + /* + * Decode encoded message the specified number of times. + */ + for (i = 0; i < times; i++) + { + fpm_msg = fpm__message__unpack (&allocator, len, msg_buf); + + if (!fpm_msg) + return 3; + + // fpm__message__free_unpacked(msg, NULL); + QPB_RESET_STACK_ALLOCATOR (allocator); + } + return 0; +} + +#endif /* HAVE_PROTOBUF */ From a6d400c9158b10207cde40a428ebf2c27f105c0a Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Fri, 18 Sep 2015 08:32:56 -0400 Subject: [PATCH 1084/1342] zebra: Set link-detect on by default Signed-off-by: Roopa Prabhu Reviewed-by: Dinesh G Dutt Reviewed-by: Scott Feldman Edited by Christian Franke: Fix OSPF Virtual Links Edited by Donald Sharp: Add NEWS notification Signed-off-by: Christian Franke Acked-By: paul@jakma.org --- NEWS | 6 ++++++ lib/if.c | 3 +++ ospfd/ospf_interface.c | 3 +++ 3 files changed, 12 insertions(+) diff --git a/NEWS b/NEWS index 8f9dd7a11..155b25c94 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,11 @@ Note: this file lists major user-visible changes only. +* Changes in Quagga [] + +- [zebra] "no link-detect" is no longer the default. To retain current + behavior save your config before updating, else remove it from + you config prior to update. + * Changes in Quagga 0.99.24 User-visible changes: diff --git a/lib/if.c b/lib/if.c index 0fc4b609c..5aa82500e 100644 --- a/lib/if.c +++ b/lib/if.c @@ -135,6 +135,9 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id) ifp->connected = list_new (); ifp->connected->del = (void (*) (void *)) connected_free; + /* Enable Link-detection by default */ + SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + if (if_master.if_new_hook) (*if_master.if_new_hook) (ifp); diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index d54bc473e..8755c0888 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -866,6 +866,9 @@ ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data) snprintf (ifname, sizeof(ifname), "VLINK%d", vlink_count); vi = if_create (ifname, strnlen(ifname, sizeof(ifname))); + /* Ensure that linkdetection is not enabled on the stub interfaces + * created for OSPF virtual links. */ + UNSET_FLAG(vi->status, ZEBRA_INTERFACE_LINKDETECTION); co = connected_new (); co->ifp = vi; listnode_add (vi->connected, co); From 8f4269ddff1becca94687252b9571b096cb45b43 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 18 Sep 2015 11:50:33 +0100 Subject: [PATCH 1085/1342] zebra: Add command to configure default for link-state, and make it sticky * Provide a way for the user to specify their own preference for the default behaviour of link-detect, independent of the compiled in default. Add a global "default link-detect (on|off)" command to zebra, to set the default policy for link-detect accordingly. The command is "sticky" - when set it will stay set and always be written out, regardless of how it compares to the baked-in, compile-time default. The per-interface "link-detect" command is similarly made sticky. * zebra/interface.h: (zebra_if_linkdetect;) enum for link-detect configured state. (struct zebra_if_defaults) Global link-detect default (struct zebra_if) Add field for per-iface link-detect default. * lib/if.c: (if_create_vrf) Remove the default flag setting on if-create here, it's a zebra flag so do it in zebra's if_zebra_new_hook * zebra/interface.c: Add static storage for global defaults. (if_zebra_new_hook) Set the link-detect flag on new ifaces according to the baked in default or else the configured global default. (config_write_zebra_if_defaults,default_linkdetect_cmd) global link-detect command and config write out machinery. (linkdetect_cmd) Set the configuration state rather than the flag. The new hook will then set the interface flag when the if comes up. (if_config_write) Write config according to configured state, not the low-level flag. (zebra_if_init) add new commands. --- lib/command.h | 1 + lib/if.c | 3 - zebra/interface.c | 152 +++++++++++++++++++++++++++++++++++++++------- zebra/interface.h | 18 +++++- 4 files changed, 149 insertions(+), 25 deletions(-) diff --git a/lib/command.h b/lib/command.h index d8029fb39..2c3b1a967 100644 --- a/lib/command.h +++ b/lib/command.h @@ -110,6 +110,7 @@ enum node_type PROTOCOL_NODE, /* protocol filtering node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ + ZEBRA_IF_DEFAULTS_NODE, /* If defaults dummy node */ }; /* Node which has some commands and prompt string and configuration diff --git a/lib/if.c b/lib/if.c index 5aa82500e..0fc4b609c 100644 --- a/lib/if.c +++ b/lib/if.c @@ -135,9 +135,6 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id) ifp->connected = list_new (); ifp->connected->del = (void (*) (void *)) connected_free; - /* Enable Link-detection by default */ - SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); - if (if_master.if_new_hook) (*if_master.if_new_hook) (ifp); diff --git a/zebra/interface.c b/zebra/interface.c index f259eeb2e..75597951c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -49,6 +49,50 @@ const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 }; #endif /* HAVE_RTADV */ +/* We don't have a tidy top-level instance object for zebra, or interfaces */ +static struct zebra_if_defaults zif_defaults = { + .linkdetect = IF_LINKDETECT_UNSPEC, +}; + +/* helper only for if_zebra_linkdetect */ +static void +if_zebra_linkdetect_set_val (struct interface *ifp, zebra_if_linkdetect val) +{ + switch (val) + { + case IF_LINKDETECT_ON: + SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + break; + case IF_LINKDETECT_OFF: + UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + break; + default: break; + } +} + +static void +if_zebra_linkdetect_set (struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + assert (zif != NULL); + int if_was_operative = if_is_operative(ifp); + + /* If user has explicitly configured for the interface, let that set */ + if (zif->linkdetect != IF_LINKDETECT_UNSPEC) + if_zebra_linkdetect_set_val (ifp, zif->linkdetect); + else + { + /* general compiled in default is to set */ + SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + /* but user can specify a default too */ + if_zebra_linkdetect_set_val (ifp, zif_defaults.linkdetect); + } + /* When linkdetection is enabled, interface might come down */ + if (!if_is_operative(ifp) && if_was_operative) if_down(ifp); + /* Alternatively, it may come up after disabling link detection */ + if (if_is_operative(ifp) && !if_was_operative) if_up(ifp); +} + /* Called when new interface is added. */ static int if_zebra_new_hook (struct interface *ifp) @@ -60,6 +104,18 @@ if_zebra_new_hook (struct interface *ifp) zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF; + switch (zif_defaults.linkdetect) + { + case IF_LINKDETECT_OFF: + UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + break; + case IF_LINKDETECT_UNSPEC: + case IF_LINKDETECT_ON: + default: + SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + break; + } + #if defined (HAVE_RTADV) { /* Set default router advertise values. */ @@ -1304,21 +1360,65 @@ DEFUN (no_multicast, return CMD_SUCCESS; } +/* Hacky: create a dummy node just to hang a config-writer callback off it */ +static struct cmd_node zebra_if_defaults_node = { + ZEBRA_IF_DEFAULTS_NODE, + "", + 1, +}; + +static int +config_write_zebra_if_defaults (struct vty *vty) +{ + if (zif_defaults.linkdetect != IF_LINKDETECT_UNSPEC) + vty_out (vty, "default link-detect %s%s", + zif_defaults.linkdetect == IF_LINKDETECT_ON ? "on" : "off", + VTY_NEWLINE); + return 0; +} + +DEFUN(default_linkdetect, + default_linkdetect_cmd, + "default link-detect (on|off)", + "Configure defaults of settings\n" + "Interface link detection\n" + "Interface link-detect defaults to enabled\n" + "Interface link-detect defaults to disabled\n") +{ + zebra_if_linkdetect prev = zif_defaults.linkdetect; + struct listnode *node; + struct interface *ifp; + vrf_iter_t iter; + + if (strcmp (argv[1], "on") == 0) + zif_defaults.linkdetect = IF_LINKDETECT_ON; + else + zif_defaults.linkdetect = IF_LINKDETECT_OFF; + + if (zif_defaults.linkdetect != prev) + for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) + for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp)) + if_zebra_linkdetect_set (ifp); + + return CMD_SUCCESS; +} + DEFUN (linkdetect, linkdetect_cmd, - "link-detect", - "Enable link detection on interface\n") + "link-detect [default]", + "Enable link detection on interface\n" + "Leave link-detect to the default\n") { struct interface *ifp; - int if_was_operative; + struct zebra_if *zif; ifp = (struct interface *) vty->index; - if_was_operative = if_is_operative(ifp); - SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); - - /* When linkdetection is enabled, if might come down */ - if (!if_is_operative(ifp) && if_was_operative) if_down(ifp); - + zif = ifp->info; + assert (zif != NULL); + + zif->linkdetect = IF_LINKDETECT_ON; + if_zebra_linkdetect_set (ifp); + /* FIXME: Will defer status change forwarding if interface does not come down! */ @@ -1333,15 +1433,15 @@ DEFUN (no_linkdetect, "Disable link detection on interface\n") { struct interface *ifp; - int if_was_operative; - + struct zebra_if *zif; + ifp = (struct interface *) vty->index; - if_was_operative = if_is_operative(ifp); - UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); + zif = ifp->info; + assert (zif != NULL); + + zif->linkdetect = IF_LINKDETECT_OFF; + if_zebra_linkdetect_set (ifp); - /* Interface may come up after disabling link detection */ - if (if_is_operative(ifp) && !if_was_operative) if_up(ifp); - /* FIXME: see linkdetect_cmd */ return CMD_SUCCESS; @@ -2573,11 +2673,18 @@ if_config_write (struct vty *vty) while processing config script */ if (ifp->bandwidth != 0) vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) - vty_out(vty, " link-detect%s", VTY_NEWLINE); - else - vty_out(vty, " no link-detect%s", VTY_NEWLINE); - + + switch (if_data->linkdetect) + { + case IF_LINKDETECT_ON: + vty_out(vty, " link-detect%s", VTY_NEWLINE); + break; + case IF_LINKDETECT_OFF: + vty_out(vty, " no link-detect%s", VTY_NEWLINE); + break; + default: break; + } + for (ALL_LIST_ELEMENTS_RO (ifp->connected, addrnode, ifc)) { if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) @@ -2629,6 +2736,8 @@ zebra_if_init (void) /* Install configuration write function. */ install_node (&interface_node, if_config_write); + + install_node (&zebra_if_defaults_node, config_write_zebra_if_defaults); install_node (&link_params_node, NULL); @@ -2642,6 +2751,7 @@ zebra_if_init (void) install_element (CONFIG_NODE, &zebra_interface_vrf_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_element (CONFIG_NODE, &no_interface_vrf_cmd); + install_element (CONFIG_NODE, &default_linkdetect_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); diff --git a/zebra/interface.h b/zebra/interface.h index 8baf186ab..223caf80f 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -38,6 +38,19 @@ #define IF_ZEBRA_SHUTDOWN_OFF 0 #define IF_ZEBRA_SHUTDOWN_ON 1 +/* Global user-configured default for interface link-detect */ +typedef enum { + IF_LINKDETECT_UNSPEC = 0, + IF_LINKDETECT_ON, + IF_LINKDETECT_OFF, +} zebra_if_linkdetect; + +/* Global defaults for interfaces */ +struct zebra_if_defaults { + /* Link-detect default configuration */ + zebra_if_linkdetect linkdetect; +}; + #if defined (HAVE_RTADV) /* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */ struct rtadvconf @@ -185,7 +198,10 @@ struct zebra_if /* Router advertise configuration. */ u_char rtadv_enable; - + + /* Interface specific link-detect configuration state */ + zebra_if_linkdetect linkdetect; + /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; From 23cd586eac3cde789e02c13a1236a4fe33dfc5d9 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 6 Apr 2016 14:03:33 +0100 Subject: [PATCH 1086/1342] zebra: Update news with the status of link-detect and the global default --- NEWS | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 155b25c94..6db831e5c 100644 --- a/NEWS +++ b/NEWS @@ -2,9 +2,23 @@ Note: this file lists major user-visible changes only. * Changes in Quagga [] -- [zebra] "no link-detect" is no longer the default. To retain current - behavior save your config before updating, else remove it from - you config prior to update. +- [zebra] "no link-detect" is no longer the default. + + The previous release of Quagga always explicitly writes-out the + link-detect configuration state. Therefore, to retain current behavior + save your config with the prior release before updating. + + Otherwise, review your configuration. Note, most users will generally + want to have link-detect enabled, and so can just remove 'no + link-detect' from their interface configuration. + + This release also adds a global configuration to specify the default, + which can be specified in the zebra configuration as: + + default link-detect (on|off) + + This will then apply to any interface which does not have link-detect + explicitly configured. * Changes in Quagga 0.99.24 From 7f39242bf44c85bb651506214666b3ebdd78b928 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 24 Aug 2016 15:53:36 +0100 Subject: [PATCH 1087/1342] *: Remove C99ism, CI system runs builds with CFLAGS and compilers that barf --- pimd/pim_igmp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 7baf2e36b..0d6f07aa4 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -111,7 +111,9 @@ static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, static void igmp_sock_dump(array_t *igmp_sock_array) { int size = array_size(igmp_sock_array); - for (int i = 0; i < size; ++i) { + int i; + + for (i = 0; i < size; ++i) { struct igmp_sock *igmp = array_get(igmp_sock_array, i); From 3b847ef4e81c6f1a5d4994680d530045765fd053 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 22 Apr 2016 12:48:49 +0100 Subject: [PATCH 1088/1342] bgpd: Squash spurious "unknown afi" log messages * bgp_packet.c: (bgp_update_receive) doesn't differentiate between NLRIs that are 0 AFI/SAFI cause they weren't set, and those because a peer sent a bogus AFI/SAFI, before sending sending what may be a misleading, spurious log message. Check the .nlri pointer is set and avoid this. Incorporating a suggestion from: G. Paul Ziemba --- bgpd/bgp_packet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 740b0f1ce..9743d064e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1645,6 +1645,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) memset (&attr, 0, sizeof (struct attr)); memset (&extra, 0, sizeof (struct attr_extra)); memset (&nlris, 0, sizeof nlris); + attr.extra = &extra; s = peer->ibuf; @@ -1781,6 +1782,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Parse any given NLRIs */ for (i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) { + if (!nlris[i].nlri) continue; + /* We use afi and safi as indices into tables and what not. It would * be impossible, at this time, to support unknown afi/safis. And * anyway, the peer needs to be configured to enable the afi/safi From c7c5b02480a506c6d687bf0d3a0c2a7d3e7cfbf6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 4 Apr 2016 15:19:37 +0100 Subject: [PATCH 1089/1342] vtysh: auto-generated vtysh_cmd.c file should depend on its creator --- vtysh/Makefile.am | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index d34773522..e44cd49f5 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -36,6 +36,5 @@ vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/zebra/zebra_routemap.c \ $(top_srcdir)/zebra/zebra_fpm.c -vtysh_cmd.c: $(vtysh_cmd_FILES) - ./$(EXTRA_DIST) $(vtysh_cmd_FILES) > vtysh_cmd.c - +vtysh_cmd.c: $(vtysh_cmd_FILES) extract.pl + ./extract.pl $(vtysh_cmd_FILES) > vtysh_cmd.c From 6f235418ad911040c5a6252d11b05cef5984fd8e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 5 Apr 2016 13:21:20 +0100 Subject: [PATCH 1090/1342] zebra: *addattr should use size_t len args, quell signed v unsigned warning --- zebra/rt_netlink.c | 7 ++++--- zebra/rt_netlink.h | 4 ++-- zebra/zebra_fpm_netlink.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e4505de33..42cb9d45b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1328,7 +1328,7 @@ netlink_route_read (struct zebra_vrf *zvrf) /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int -addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen) +addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, size_t alen) { size_t len; struct rtattr *rta; @@ -1348,9 +1348,10 @@ addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen) } int -rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) +rta_addattr_l (struct rtattr *rta, size_t maxlen, int type, void *data, + size_t alen) { - int len; + size_t len; struct rtattr *subrta; len = RTA_LENGTH (alen); diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 63fbbe784..9fc70010f 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -30,10 +30,10 @@ extern int addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data); extern int -addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen); +addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, size_t alen); extern int -rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen); +rta_addattr_l (struct rtattr *rta, size_t maxlen, int type, void *data, size_t alen); extern const char * nl_msg_type_to_str (uint16_t msg_type); diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 01730007f..96e897bf1 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -322,7 +322,7 @@ static int netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf, size_t in_buf_len) { - int bytelen; + size_t bytelen; int nexthop_num = 0; size_t buf_offset; netlink_nh_info_t *nhi; From 34c5d89fed6e8e91ae3cde478f1f4816d69bf09e Mon Sep 17 00:00:00 2001 From: Ayan Banerjee Date: Mon, 9 Nov 2015 20:14:53 -0500 Subject: [PATCH 1091/1342] zebra: ipv6 multipath support This patch enables support for multipath for IPV6. The nexthop information from the protocols have ifindices and nexthop addresses in two different structures. This patch combines them to ensure that the correct APIs can be called. Also, given that IPV6 Linux implementation does not support the rta_XXX APIs for multipath, the communication with the kernel is in terms of a single nh/ifindex pair. Signed-off-by: Ayan Banerjee Signed-off-by: Dinesh Dutt Signed-off-by: Donald Sharp --- zebra/rib.h | 6 +++ zebra/zebra_rib.c | 82 ++++++++++++++++++++++++++++++++++++- zebra/zserv.c | 100 ++++++++++++++++++++++++++++++---------------- 3 files changed, 152 insertions(+), 36 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 1dacc7f78..677e3955d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -449,6 +449,9 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, #define ZEBRA_RIB_NOTFOUND 3 extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); +extern struct nexthop *nexthop_ipv6_ifindex_add (struct rib *, + struct in6_addr *, + ifindex_t); extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t); extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t); @@ -514,6 +517,9 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, u_char distance, vrf_id_t vrf_id); +extern int +rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t); + extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char distance, vrf_id_t vrf_id); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 2e15f99a1..eec29769b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -289,7 +289,7 @@ nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, return nexthop; } -static struct nexthop * +struct nexthop * nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, ifindex_t ifindex) { @@ -2669,6 +2669,86 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } +int +rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi) +{ + struct route_table *table; + struct route_node *rn; + struct rib *same = NULL; + struct nexthop *nexthop; + int ret = 0; + + if (!rib) + return 0; /* why are we getting called with NULL rib */ + + /* Lookup table. */ + table = zebra_vrf_table (AFI_IP6, safi, rib->vrf_id); + + if (! table) + return 0; + + /* Make sure mask is applied. */ + apply_mask_ipv6 (p); + + /* Set default distance by route type. */ + if (rib->distance == 0) + { + rib->distance = route_info[rib->type].distance; + + /* iBGP distance is 200. */ + if (rib->type == ZEBRA_ROUTE_BGP + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) + rib->distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + RNODE_FOREACH_RIB (rn, same) { + if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) { + continue; + } + if (same->type != rib->type) { + continue; + } + + if (same->table != rib->table) { + continue; + } + if (same->type != ZEBRA_ROUTE_CONNECT) { + break; + } + } + + /* If this route is kernel route, set FIB flag to the route. */ + if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + } + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + ret = 1; + /* Free implicit route.*/ + if (same) + { + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", + __func__, rn, same); + rib_dump ((struct prefix *)p, same); + } + rib_delnode (rn, same); + ret = -1; + } + + route_unlock_node (rn); + return ret; +} + /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, diff --git a/zebra/zserv.c b/zebra/zserv.c index d4c5db906..86f141b32 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1080,34 +1080,50 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct stream *s; - struct zapi_ipv6 api; struct in6_addr nexthop; - unsigned long ifindex; + struct rib *rib; + u_char message; + u_char gateway_num; + u_char nexthop_type; struct prefix_ipv6 p; - + safi_t safi; + static struct in6_addr nexthops[MULTIPATH_NUM]; + static unsigned int ifindices[MULTIPATH_NUM]; + + /* Get input stream. */ s = client->ibuf; - ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + /* Allocate new rib. */ + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + /* Type, flags, message. */ - api.type = stream_getc (s); - api.flags = stream_getc (s); - api.message = stream_getc (s); - api.safi = stream_getw (s); + rib->type = stream_getc (s); + rib->flags = stream_getc (s); + message = stream_getc (s); + safi = stream_getw (s); + rib->uptime = time (NULL); - /* IPv4 prefix. */ + /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + /* We need to give nh-addr, nh-ifindex with the same next-hop object + * to the rib to ensure that IPv6 multipathing works; need to coalesce + * these. Clients should send the same number of paired set of + * next-hop-addr/next-hop-ifindices. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) { - u_char nexthop_type; + int nh_count = 0; + int if_count = 0; + int max_nh_if = 0; + unsigned int ifindex; - api.nexthop_num = stream_getc (s); - for (i = 0; i < api.nexthop_num; i++) + gateway_num = stream_getc (s); + for (i = 0; i < gateway_num; i++) { nexthop_type = stream_getc (s); @@ -1115,37 +1131,51 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop, s, 16); + if (nh_count < MULTIPATH_NUM) { + nexthops[nh_count++] = nexthop; + } break; case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); + if (if_count < MULTIPATH_NUM) { + ifindices[if_count++] = ifindex; + } break; } } + + max_nh_if = (nh_count > if_count) ? nh_count : if_count; + for (i = 0; i < max_nh_if; i++) + { + if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) + { + if ((i < if_count) && ifindices[i]) + nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); + else + nexthop_ipv6_add (rib, &nexthops[i]); + } + else + { + if ((i < if_count) && ifindices[i]) + nexthop_ifindex_add (rib, ifindices[i]); + } + } } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; + /* Distance. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + rib->distance = stream_getc (s); - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; + /* Metric. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + rib->metric = stream_getl (s); - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU)) - api.mtu = stream_getl (s); - else - api.mtu = 0; - - if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, - vrf_id, zebrad.rtm_table_default, api.metric, - api.mtu, api.distance, api.safi); - else - rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, - vrf_id, zebrad.rtm_table_default, api.metric, - api.mtu, api.distance, api.safi); + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + + /* Table */ + rib->table=zebrad.rtm_table_default; + rib_add_ipv6_multipath (&p, rib, safi); return 0; } From b8d1f713ba6bc91138debe9f895621b8f91a43c7 Mon Sep 17 00:00:00 2001 From: Ayan Banerjee Date: Mon, 9 Nov 2015 20:14:54 -0500 Subject: [PATCH 1092/1342] bgpd: Enable support for BGP IPV6 multipath. This commit adds these two commands: maximum-paths <1-MULTIPATH_NUM> maximum-paths ibgp <1-MULTIPATH_NUM> under address-family ipv6 mode. In addition adding the ability to pass multiple paths down into zebra from bgp. Signed-off-by: Ayan Banerjee Signed-off-by: Dinesh G Dutt Reviewed-by: Scott Feldman --- bgpd/bgp_main.c | 2 + bgpd/bgp_vty.c | 6 +++ bgpd/bgp_zebra.c | 129 +++++++++++++++++++++++++++++++++++++++-------- bgpd/bgp_zebra.h | 2 + 4 files changed, 119 insertions(+), 20 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 562afc20e..eb0fe1774 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -323,6 +323,8 @@ bgp_exit (int status) zclient_free (zlookup); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); + if (bgp_ifindices_buf) + stream_free (bgp_ifindices_buf); /* reverse bgp_master_init */ if (bm->master) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 925e2676f..0b3262551 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9915,12 +9915,18 @@ bgp_vty_init (void) install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd); + install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_arg_cmd); install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); + install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); /* "timers bgp" commands. */ install_element (BGP_NODE, &bgp_timers_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 85380f0fc..583604a7a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -46,6 +46,7 @@ struct in_addr router_id_zebra; /* Growable buffer for nexthops sent to zebra */ struct stream *bgp_nexthop_buf = NULL; +struct stream *bgp_ifindices_buf = NULL; /* Router-id update message from zebra. */ static int @@ -662,6 +663,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa struct peer *peer; struct bgp_info *mpinfo; size_t oldsize, newsize; + u_int32_t nhcount; if (zclient->sock < 0) return; @@ -682,26 +684,27 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); - /* resize nexthop buffer size if necessary */ - if ((oldsize = stream_get_size (bgp_nexthop_buf)) < - (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1))) - { - newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)); - newsize = stream_resize (bgp_nexthop_buf, newsize); - if (newsize == oldsize) - { - zlog_err ("can't resize nexthop buffer"); - return; - } - } - - stream_reset (bgp_nexthop_buf); + nhcount = 1 + bgp_info_mpath_count (info); if (p->family == AF_INET) { struct zapi_ipv4 api; struct in_addr *nexthop; + /* resize nexthop buffer size if necessary */ + if ((oldsize = stream_get_size (bgp_nexthop_buf)) < + (sizeof (struct in_addr *) * nhcount)) + { + newsize = (sizeof (struct in_addr *) * nhcount); + newsize = stream_resize (bgp_nexthop_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize nexthop buffer"); + return; + } + } + stream_reset (bgp_nexthop_buf); + api.vrf_id = VRF_DEFAULT; api.flags = flags; nexthop = &info->attr->nexthop; @@ -717,7 +720,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1 + bgp_info_mpath_count (info); + api.nexthop_num = nhcount; api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf); api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); @@ -757,10 +760,39 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa ifindex_t ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; + int valid_nh_count = 0; + + /* resize nexthop buffer size if necessary */ + if ((oldsize = stream_get_size (bgp_nexthop_buf)) < + (sizeof (struct in6_addr *) * nhcount)) + { + newsize = (sizeof (struct in6_addr *) * nhcount); + newsize = stream_resize (bgp_nexthop_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize nexthop buffer"); + return; + } + } + stream_reset (bgp_nexthop_buf); + + /* resize ifindices buffer size if necessary */ + if ((oldsize = stream_get_size (bgp_ifindices_buf)) < + (sizeof (unsigned int) * nhcount)) + { + newsize = (sizeof (unsigned int) * nhcount); + newsize = stream_resize (bgp_ifindices_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize nexthop buffer"); + return; + } + } + stream_reset (bgp_ifindices_buf); ifindex = 0; nexthop = NULL; - + assert (info->attr->extra); /* Only global address nexthop exists. */ @@ -791,6 +823,62 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa else if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } + stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); + stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); + valid_nh_count++; + + for (mpinfo = bgp_info_mpath_first (info); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + /* Only global address nexthop exists. */ + if (mpinfo->attr->extra->mp_nexthop_len == 16) + { + nexthop = &mpinfo->attr->extra->mp_nexthop_global; + } + /* If both global and link-local address present. */ + if (mpinfo->attr->extra->mp_nexthop_len == 32) + { + /* Workaround for Cisco's nexthop bug. */ + if (IN6_IS_ADDR_UNSPECIFIED (&mpinfo->attr->extra->mp_nexthop_global) + && mpinfo->peer->su_remote->sa.sa_family == AF_INET6) + { + nexthop = &mpinfo->peer->su_remote->sin6.sin6_addr; + } + else + { + nexthop = &mpinfo->attr->extra->mp_nexthop_local; + } + + if (mpinfo->peer->nexthop.ifp) + { + ifindex = mpinfo->peer->nexthop.ifp->ifindex; + } + } + if (nexthop == NULL) + { + continue; + } + + if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) + { + if (mpinfo->peer->ifname) + { + ifindex = if_nametoindex (mpinfo->peer->ifname); + } + else if (mpinfo->peer->nexthop.ifp) + { + ifindex = mpinfo->peer->nexthop.ifp->ifindex; + } + } + if (ifindex == 0) + { + continue; + } + + stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); + stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); + valid_nh_count++; + } /* Make Zebra API structure. */ api.vrf_id = VRF_DEFAULT; @@ -799,11 +887,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop; + api.nexthop_num = valid_nh_count; + api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &ifindex; + api.ifindex_num = valid_nh_count; + api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; @@ -1071,6 +1159,7 @@ bgp_zebra_init (struct thread_master *master) zclient->ipv6_route_delete = zebra_read_ipv6; bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); + bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE); } void diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 25651581b..ccc554750 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -22,9 +22,11 @@ Boston, MA 02111-1307, USA. */ #define _QUAGGA_BGP_ZEBRA_H #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) +#define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int)) extern struct stream *bgp_nexthop_buf; extern struct in_addr router_id_zebra; +extern struct stream *bgp_ifindices_buf; extern void bgp_zebra_init (struct thread_master *master); extern void bgp_zebra_destroy (void); From 4feb0d02c029e2e4f229f6283f579b8673b0ac11 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Mon, 9 Nov 2015 20:14:55 -0500 Subject: [PATCH 1093/1342] bgpd: IPv6 Multipath broken with nexthop global address IPv6 multipath is broken in BGP if nexthop contains only global address. IPv6 always uses both nextop IPv6 address and ifIndex in sending routes down to zebra. In cases where only the global IPv6 address is present in the nexthop information, the existing code doesn't set the ifIndex. An example of such a case is when a route-map isused with "set ipv6 next-hop" and only global address is specified. This code causes the ifIndex to be determined and set thereby fixing the multipath programming. Signed-off-by: Dinesh G Dutt Reviewed-by: Shrijeet Mukherjee --- bgpd/bgp_zebra.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 583604a7a..00de6b861 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -816,7 +816,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa if (nexthop == NULL) return; - if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) + if (!ifindex) { if (info->peer->ifname) ifindex = ifname2ifindex (info->peer->ifname); @@ -830,11 +830,12 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa for (mpinfo = bgp_info_mpath_first (info); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { + ifindex = 0; + /* Only global address nexthop exists. */ if (mpinfo->attr->extra->mp_nexthop_len == 16) - { nexthop = &mpinfo->attr->extra->mp_nexthop_global; - } + /* If both global and link-local address present. */ if (mpinfo->attr->extra->mp_nexthop_len == 32) { @@ -854,12 +855,13 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa ifindex = mpinfo->peer->nexthop.ifp->ifindex; } } + if (nexthop == NULL) { continue; } - if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) + if (!ifindex) { if (mpinfo->peer->ifname) { @@ -870,6 +872,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa ifindex = mpinfo->peer->nexthop.ifp->ifindex; } } + if (ifindex == 0) { continue; From 60cc95921ae663de325ca3e76e8c05d8224986ab Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Mon, 9 Nov 2015 20:21:41 -0500 Subject: [PATCH 1094/1342] bgpd, doc, lib, zebra: nexthop-tracking in zebra 0. Introduction This is the design specification for next hop tracking feature in Quagga. 1. Background Recursive routes are of the form: p/m --> n [Ex: 1.1.0.0/16 --> 2.2.2.2] where 'n' itself is resolved through another route as follows: p2/m --> h, interface [Ex: 2.2.2.0/24 --> 3.3.3.3, eth0] Usually, BGP routes are recursive in nature and BGP nexthops get resolved through an IGP route. IGP usually adds its routes pointing to an interface (these are called non-recursive routes). When BGP receives a recursive route from a peer, it needs to validate the nexthop. The path is marked valid or invalid based on the reachability status of the nexthop. Nexthop validation is also important for BGP decision process as the metric to reach the nexthop is a parameter to best path selection process. As it goes with routing, this is a dynamic process. Route to the nexthop can change. The nexthop can become unreachable or reachable. In the current BGP implementation, the nexthop validation is done periodically in the scanner run. The default scanner run interval is one minute. Every minute, the scanner task walks the entire BGP table. It checks the validity of each nexthop with Zebra (the routing table manager) through a request and response message exchange between BGP and Zebra process. BGP process is blocked for that duration. The mechanism has two major drawbacks: (1) The scanner task runs to completion. That can potentially starve the other tasks for long periods of time, based on the BGP table size and number of nexthops. (2) Convergence around routing changes that affect the nexthops can be long (around a minute with the default intervals). The interval can be shortened to achieve faster reaction time, but it makes the first problem worse, with the scanner task consuming most of the CPU resources. "Next hop tracking" feature makes this process event-driven. It eliminates periodic nexthop validation and introduces an asynchronous communication path between BGP and Zebra for route change notifications that can then be acted upon. 2. Goal Stating the obvious, the main goal is to remove the two limitations we discussed in the previous section. The goals, in a constructive tone, are the following: - fairness: the scanner run should not consume an unjustly high amount of CPU time. This should give an overall good performance and response time to other events (route changes, session events, IO/user interface). - convergence: BGP must react to nexthop changes instantly and provide sub-second convergence. This may involve diverting the routes from one nexthop to another. 3. Overview of the changes The changes are in both BGP and Zebra modules. The short summary is the following: - Zebra implements a registration mechanism by which clients can register for next hop notification. Consequently, it maintains a separate table, per (VRF, AF) pair, of next hops and interested client-list per next hop. - When the main routing table changes in Zebra, it evaluates the next hop table: for each next hop, it checks if the route table modifications have changed its state. If so, it notifies the interested clients. - BGP is one such client. It registers the next hops corresponding to all of its received routes/paths. It also threads the paths against each nexthop structure. - When BGP receives a next hop notification from Zebra, it walks the corresponding path list. It makes them valid or invalid depending on the next hop notification. It then re-computes best path for the corresponding destination. This may result in re-announcing those destinations to peers. 4. Design 4.1. Modules The core design introduces an "nht" (next hop tracking) module in BGP and "rnh" (recursive nexthop) module in Zebra. The "nht" module provides the following APIs: bgp_find_or_add_nexthop() : find or add a nexthop in BGP nexthop table bgp_find_nexthop() : find a nexthop in BGP nexthop table bgp_parse_nexthop_update() : parse a nexthop update message coming from zebra The "rnh" module provides the following APIs: zebra_add_rnh() : add a recursive nexthop zebra_delete_rnh() : delete a recursive nexthop zebra_lookup_rnh() : lookup a recursive nexthop zebra_add_rnh_client() : register a client for nexthop notifications against a recursive nexthop zebra_remove_rnh_client(): remove the client registration for a recursive nexthop zebra_evaluate_rnh_table(): (re)evaluate the recursive nexthop table (most probably because the main routing table has changed). zebra_cleanup_rnh_client(): Cleanup a client from the "rnh" module data structures (most probably because the client is going away). 4.2. Control flow The next hop registration control flow is the following: <==== BGP Process ====>|<==== Zebra Process ====> | receive module nht module | zserv module rnh module ---------------------------------------------------------------------- | | | bgp_update_ | | | main() | bgp_find_or_add_ | | | nexthop() | | | | | | | zserv_nexthop_ | | | register() | | | | zebra_add_rnh() | | | The next hop notification control flow is the following: <==== Zebra Process ====>|<==== BGP Process ====> | rib module rnh module | zebra module nht module ---------------------------------------------------------------------- | | | meta_queue_ | | | process() | zebra_evaluate_ | | | rnh_table() | | | | | | | bgp_read_nexthop_ | | | update() | | | | bgp_parse_ | | | nexthop_update() | | | 4.3. zclient message format ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are encoded in the following way: /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | AF | prefix len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Nexthop prefix . * . . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . . * . . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | AF | prefix len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Nexthop prefix . * . . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ ZEBRA_NEXTHOP_UPDATE message is encoded as follows: /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | AF | prefix len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Nexthop prefix getting resolved . * . . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | metric | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | #nexthops | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | nexthop type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . resolving Nexthop details . * . . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | nexthop type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . resolving Nexthop details . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 4.4. BGP data structure Legend: /\ struct bgp_node: a BGP destination/route/prefix \/ [ ] struct bgp_info: a BGP path (e.g. route received from a peer) _ (_) struct bgp_nexthop_cache: a BGP nexthop /\ NULL \/--+ ^ | : +--[ ]--[ ]--[ ]--> NULL /\ : \/--+ : | : +--[ ]--[ ]--> NULL : _ : (_)............. 4.5. Zebra data structure rnh table: O / \ O O / \ O O struct rnh { u_char flags; struct rib *state; struct list *client_list; struct route_node *node; }; 5. User interface changes quagga# show ip nht 3.3.3.3 resolved via kernel via 11.0.0.6, swp1 Client list: bgp(fd 12) 11.0.0.10 resolved via connected is directly connected, swp2 Client list: bgp(fd 12) 11.0.0.18 resolved via connected is directly connected, swp4 Client list: bgp(fd 12) 11.11.11.11 resolved via kernel via 10.0.1.2, eth0 Client list: bgp(fd 12) quagga# show ip bgp nexthop Current BGP nexthop cache: 3.3.3.3 valid [IGP metric 0], #paths 3 Last update: Wed Oct 16 04:43:49 2013 11.0.0.10 valid [IGP metric 1], #paths 1 Last update: Wed Oct 16 04:43:51 2013 11.0.0.18 valid [IGP metric 1], #paths 2 Last update: Wed Oct 16 04:43:47 2013 11.11.11.11 valid [IGP metric 0], #paths 1 Last update: Wed Oct 16 04:43:47 2013 quagga# show ipv6 nht quagga# show ip bgp nexthop detail quagga# debug bgp nht quagga# debug zebra nht 6. Sample test cases r2----r3 / \ / r1----r4 - Verify that a change in IGP cost triggers NHT + shutdown the r1-r4 and r2-r4 links + no shut the r1-r4 and r2-r4 links and wait for OSPF to come back up + We should be back to the original nexthop via r4 now - Verify that a NH becoming unreachable triggers NHT + Shutdown all links to r4 - Verify that a NH becoming reachable triggers NHT + no shut all links to r4 7. Future work - route-policy for next hop validation (e.g. ignore default route) - damping for rapid next hop changes - prioritized handling of nexthop changes ((un)reachability vs. metric changes) - handling recursion loop, e.g. 11.11.11.11/32 -> 12.12.12.12 12.12.12.12/32 -> 11.11.11.11 11.0.0.0/8 -> - better statistics Addresses upstream comments. "show ip bgp nexthop detail" couldn't display multiple NHs due to a bug. Fix that. Fix reference counts for the nexthop cache entries Signed-off-by: Pradosh Mohapatra Signed-off-by: Daniel Walton Signed-off-by: Dinesh Dutt Signed-off-by: Donald Sharp Signed-off-by: Vivek Venkatraman Fix reference counts for the nexthop cache entries. Signed-off-by: Vivek Venkatraman Edited-by: Paul Jakma - Fix nexthop_ipv6_add defs in rib.h not having been modified with rib_ prefix. - Remove rib_lookup_and_pushup, appears not to be used except for !HAVE_NETLINK && HAVE_STRUCT_IFALIASREQ case of ioctl.c::if_set_prefix, so it's not being used at all on platform with most testing of RIB. --- bgpd/Makefile.am | 4 +- bgpd/bgp_debug.c | 57 ++++ bgpd/bgp_debug.h | 3 + bgpd/bgp_nexthop.c | 206 +++++++++---- bgpd/bgp_nexthop.h | 20 ++ bgpd/bgp_nht.c | 477 ++++++++++++++++++++++++++++++ bgpd/bgp_nht.h | 62 ++++ bgpd/bgp_route.c | 110 +++---- bgpd/bgp_route.h | 14 +- bgpd/bgp_zebra.c | 12 + doc/next-hop-tracking.txt | 326 +++++++++++++++++++++ lib/Makefile.am | 6 +- lib/log.c | 3 + lib/memtypes.c | 1 + lib/nexthop.c | 168 +++++++++++ lib/nexthop.h | 91 ++++++ lib/zclient.c | 3 + lib/zclient.h | 1 + lib/zebra.h | 6 +- zebra/Makefile.am | 5 +- zebra/debug.c | 30 ++ zebra/debug.h | 3 + zebra/ioctl.c | 1 - zebra/rib.h | 88 ++---- zebra/rt_netlink.c | 13 +- zebra/zebra_fpm_netlink.c | 1 + zebra/zebra_rib.c | 248 +++++----------- zebra/zebra_rnh.c | 603 ++++++++++++++++++++++++++++++++++++++ zebra/zebra_rnh.h | 48 +++ zebra/zebra_rnh_null.c | 10 + zebra/zebra_routemap.c | 1 + zebra/zebra_vty.c | 26 ++ zebra/zserv.c | 94 +++++- zebra/zserv.h | 6 + 34 files changed, 2359 insertions(+), 388 deletions(-) create mode 100644 bgpd/bgp_nht.c create mode 100644 bgpd/bgp_nht.h create mode 100644 doc/next-hop-tracking.txt create mode 100644 lib/nexthop.c create mode 100644 lib/nexthop.h create mode 100644 zebra/zebra_rnh.c create mode 100644 zebra/zebra_rnh.h create mode 100644 zebra/zebra_rnh_null.c diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index d2775f39d..fe1be32ed 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -16,7 +16,7 @@ libbgp_a_SOURCES = \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ - bgp_encap.c bgp_encap_tlv.c + bgp_encap.c bgp_encap_tlv.c bgp_nht.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ @@ -24,7 +24,7 @@ noinst_HEADERS = \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ - bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h + bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 90a378ba2..ba7972281 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -47,6 +47,7 @@ unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_normal; unsigned long conf_bgp_debug_zebra; unsigned long conf_bgp_debug_allow_martians; +unsigned long conf_bgp_debug_nht; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_fsm; @@ -58,6 +59,7 @@ unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_normal; unsigned long term_bgp_debug_zebra; unsigned long term_bgp_debug_allow_martians; +unsigned long term_bgp_debug_nht; /* messages for BGP-4 status */ const struct message bgp_status_msg[] = @@ -472,6 +474,48 @@ ALIAS (no_debug_bgp_events, BGP_STR "BGP events\n") +DEFUN (debug_bgp_nht, + debug_bgp_nht_cmd, + "debug bgp nht", + DEBUG_STR + BGP_STR + "BGP nexthop tracking events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (nht, NHT); + else + { + TERM_DEBUG_ON (nht, NHT); + vty_out (vty, "BGP nexthop tracking debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_nht, + no_debug_bgp_nht_cmd, + "no debug bgp nht", + NO_STR + DEBUG_STR + BGP_STR + "BGP nexthop tracking events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (nht, NHT); + else + { + TERM_DEBUG_OFF (nht, NHT); + vty_out (vty, "BGP nexthop tracking debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_nht, + undebug_bgp_nht_cmd, + "undebug bgp nht", + UNDEBUG_STR + BGP_STR + "BGP next-hop tracking updates\n") + DEFUN (debug_bgp_filter, debug_bgp_filter_cmd, "debug bgp filters", @@ -833,6 +877,8 @@ DEFUN (show_debugging_bgp, vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) vty_out (vty, " BGP allow martian next hop debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (nht, NHT)) + vty_out (vty, " BGP next-hop tracking debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -911,6 +957,12 @@ bgp_config_write_debug (struct vty *vty) vty_out (vty, "debug bgp allow-martians%s", VTY_NEWLINE); write++; } + + if (CONF_BGP_DEBUG (nht, NHT)) + { + vty_out (vty, "debug bgp nht%s", VTY_NEWLINE); + write++; + } return write; } @@ -938,6 +990,8 @@ bgp_debug_init (void) install_element (CONFIG_NODE, &debug_bgp_fsm_cmd); install_element (ENABLE_NODE, &debug_bgp_events_cmd); install_element (CONFIG_NODE, &debug_bgp_events_cmd); + install_element (ENABLE_NODE, &debug_bgp_nht_cmd); + install_element (CONFIG_NODE, &debug_bgp_nht_cmd); install_element (ENABLE_NODE, &debug_bgp_filter_cmd); install_element (CONFIG_NODE, &debug_bgp_filter_cmd); install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd); @@ -966,6 +1020,9 @@ bgp_debug_init (void) install_element (ENABLE_NODE, &no_debug_bgp_events_cmd); install_element (ENABLE_NODE, &undebug_bgp_events_cmd); install_element (CONFIG_NODE, &no_debug_bgp_events_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_nht_cmd); + install_element (ENABLE_NODE, &undebug_bgp_nht_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_nht_cmd); install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd); install_element (ENABLE_NODE, &undebug_bgp_filter_cmd); install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd); diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 42cbd7e79..253bd7fe6 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -68,6 +68,7 @@ extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_normal; extern unsigned long conf_bgp_debug_zebra; extern unsigned long conf_bgp_debug_allow_martians; +extern unsigned long conf_bgp_debug_nht; extern unsigned long term_bgp_debug_as4; extern unsigned long term_bgp_debug_fsm; @@ -79,6 +80,7 @@ extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_normal; extern unsigned long term_bgp_debug_zebra; extern unsigned long term_bgp_debug_allow_martians; +extern unsigned long term_bgp_debug_nht; #define BGP_DEBUG_AS4 0x01 #define BGP_DEBUG_AS4_SEGMENT 0x02 @@ -93,6 +95,7 @@ extern unsigned long term_bgp_debug_allow_martians; #define BGP_DEBUG_NORMAL 0x01 #define BGP_DEBUG_ZEBRA 0x01 #define BGP_DEBUG_ALLOW_MARTIANS 0x01 +#define BGP_DEBUG_NHT 0x01 #define BGP_DEBUG_PACKET_SEND 0x01 #define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 24068141c..badada7dd 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -31,17 +31,21 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "hash.h" #include "jhash.h" #include "filter.h" +#include "nexthop.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_nht.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_damp.h" #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ +extern struct zclient *zclient; + struct bgp_nexthop_cache *zlookup_query (struct in_addr); struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); @@ -58,7 +62,7 @@ static int bgp_scan_interval; static int bgp_import_interval; /* Route table for next-hop lookup cache. */ -static struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; +struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; static struct bgp_table *cache1_table[AFI_MAX]; static struct bgp_table *cache2_table[AFI_MAX]; @@ -68,6 +72,13 @@ static struct bgp_table *bgp_connected_table[AFI_MAX]; /* BGP nexthop lookup query client. */ struct zclient *zlookup = NULL; +char * +bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) +{ + prefix2str(&(bnc->node->p), buf, size); + return buf; +} + /* Add nexthop to the end of the list. */ static void bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) @@ -83,7 +94,7 @@ bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) nexthop->prev = last; } -static void +void bnc_nexthop_free (struct bgp_nexthop_cache *bnc) { struct nexthop *nexthop; @@ -96,59 +107,23 @@ bnc_nexthop_free (struct bgp_nexthop_cache *bnc) } } -static struct bgp_nexthop_cache * +struct bgp_nexthop_cache * bnc_new (void) { - return XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); + struct bgp_nexthop_cache *bnc; + + bnc = XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); + LIST_INIT(&(bnc->paths)); + return bnc; } -static void +void bnc_free (struct bgp_nexthop_cache *bnc) { bnc_nexthop_free (bnc); XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } -static int -bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) -{ - if (next1->type != next2->type) - return 0; - - switch (next1->type) - { - case ZEBRA_NEXTHOP_IPV4: - if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) - return 0; - break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: - if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4) - || next1->ifindex != next2->ifindex) - return 0; - break; - case ZEBRA_NEXTHOP_IFINDEX: - case ZEBRA_NEXTHOP_IFNAME: - if (next1->ifindex != next2->ifindex) - return 0; - break; - case ZEBRA_NEXTHOP_IPV6: - if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) - return 0; - break; - case ZEBRA_NEXTHOP_IPV6_IFINDEX: - case ZEBRA_NEXTHOP_IPV6_IFNAME: - if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) - return 0; - if (next1->ifindex != next2->ifindex) - return 0; - break; - default: - /* do nothing */ - break; - } - return 1; -} - static int bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, struct bgp_nexthop_cache *bnc2) @@ -164,7 +139,7 @@ bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, for (i = 0; i < bnc1->nexthop_num; i++) { - if (! bgp_nexthop_same (next1, next2)) + if (! nexthop_same_no_recurse (next1, next2)) return 1; next1 = next1->next; @@ -382,6 +357,7 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, return bnc->valid; } +#if BGP_SCAN_NEXTHOP /* Reset and free all BGP nexthop cache. */ static void bgp_nexthop_cache_reset (struct bgp_table *table) @@ -397,6 +373,7 @@ bgp_nexthop_cache_reset (struct bgp_table *table) bgp_unlock_node (rn); } } +#endif static void bgp_scan (afi_t afi, safi_t safi) @@ -407,6 +384,7 @@ bgp_scan (afi_t afi, safi_t safi) struct bgp_info *next; struct peer *peer; struct listnode *node, *nnode; +#if BGP_SCAN_NEXTHOP int valid; int current; int changed; @@ -417,6 +395,7 @@ bgp_scan (afi_t afi, safi_t safi) bgp_nexthop_cache_table[afi] = cache2_table[afi]; else bgp_nexthop_cache_table[afi] = cache1_table[afi]; +#endif /* Get default bgp. */ bgp = bgp_get_default (); @@ -446,6 +425,7 @@ bgp_scan (afi_t afi, safi_t safi) if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) { +#if BGP_SCAN_NEXTHOP changed = 0; metricchanged = 0; @@ -478,6 +458,7 @@ bgp_scan (afi_t afi, safi_t safi) afi, SAFI_UNICAST); } } +#endif if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], BGP_CONFIG_DAMPENING) @@ -491,11 +472,13 @@ bgp_scan (afi_t afi, safi_t safi) bgp_process (bgp, rn, afi, SAFI_UNICAST); } +#if BGP_SCAN_NEXTHOP /* Flash old cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_reset (cache2_table[afi]); else bgp_nexthop_cache_reset (cache1_table[afi]); +#endif if (BGP_DEBUG (events, EVENTS)) { @@ -1262,9 +1245,7 @@ static int show_ip_bgp_scan_tables (struct vty *vty, const char detail) { struct bgp_node *rn; - struct bgp_nexthop_cache *bnc; char buf[INET6_ADDRSTRLEN]; - u_char i; if (bgp_scan_thread) vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); @@ -1272,6 +1253,7 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); +#if BGP_SCAN_NEXTHOP vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) @@ -1281,21 +1263,21 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) vty_out (vty, " %s valid [IGP metric %d]%s", inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) - for (i = 0; i < bnc->nexthop_num; i++) - switch (bnc->nexthop[i].type) + for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) + switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: - vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " gate %s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN)); - vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); + vty_out (vty, " gate %s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN)); + vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); + vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); break; default: - vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); + vty_out (vty, " invalid nexthop type %u%s", nexthop->type, VTY_NEWLINE); } } else @@ -1315,17 +1297,17 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) - for (i = 0; i < bnc->nexthop_num; i++) - switch (bnc->nexthop[i].type) + for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) + switch (nexthop->type) { case NEXTHOP_TYPE_IPV6: - vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); + vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); break; default: - vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); + vty_out (vty, " invalid nexthop type %u%s", nexthop->type, VTY_NEWLINE); } } else @@ -1334,7 +1316,9 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) VTY_NEWLINE); } } - +#else + vty_out (vty, "BGP next-hop tracking is on%s", VTY_NEWLINE); +#endif vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_connected_table[AFI_IP]); rn; @@ -1357,6 +1341,80 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) return CMD_SUCCESS; } +static int +show_ip_bgp_nexthop_table (struct vty *vty, int detail) +{ + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + char buf[INET6_ADDRSTRLEN]; + struct nexthop *nexthop; + time_t tbuf; + afi_t afi; + + vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + { + for (rn = bgp_table_top (bgp_nexthop_cache_table[afi]); rn; rn = bgp_route_next (rn)) + { + if ((bnc = rn->info) != NULL) + { + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) + { + vty_out (vty, " %s valid [IGP metric %d], #paths %d%s", + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)), + bnc->metric, bnc->path_count, VTY_NEWLINE); + if (detail) + for (nexthop = bnc->nexthop ; nexthop; nexthop = nexthop->next) + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV6: + vty_out (vty, " gate %s%s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, + buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " gate %s, if %s%s", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, + INET6_ADDRSTRLEN), + ifindex2ifname(nexthop->ifindex), + VTY_NEWLINE); + break; + case NEXTHOP_TYPE_IPV4: + vty_out (vty, " gate %s%s", + inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, + INET6_ADDRSTRLEN), VTY_NEWLINE); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " if %s%s", + ifindex2ifname(nexthop->ifindex), VTY_NEWLINE); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " gate %s, if %s%s", + inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, + INET6_ADDRSTRLEN), + ifindex2ifname(nexthop->ifindex), VTY_NEWLINE); + break; + default: + vty_out (vty, " invalid nexthop type %u%s", + nexthop->type, VTY_NEWLINE); + } + } + else + vty_out (vty, " %s invalid%s", + inet_ntop (AF_INET, &rn->p.u.prefix, buf, sizeof (buf)), VTY_NEWLINE); +#ifdef HAVE_CLOCK_MONOTONIC + tbuf = time(NULL) - (bgp_clock() - bnc->last_update); + vty_out (vty, " Last update: %s", ctime(&tbuf)); +#else + vty_out (vty, " Last update: %s", ctime(&bnc->uptime)); +#endif /* HAVE_CLOCK_MONOTONIC */ + vty_out(vty, "%s", VTY_NEWLINE); + } + } + } + return CMD_SUCCESS; +} + DEFUN (show_ip_bgp_scan, show_ip_bgp_scan_cmd, "show ip bgp scan", @@ -1380,6 +1438,28 @@ DEFUN (show_ip_bgp_scan_detail, return show_ip_bgp_scan_tables (vty, 1); } +DEFUN (show_ip_bgp_nexthop, + show_ip_bgp_nexthop_cmd, + "show ip bgp nexthop", + SHOW_STR + IP_STR + BGP_STR + "BGP nexthop table\n") +{ + return show_ip_bgp_nexthop_table (vty, 0); +} + +DEFUN (show_ip_bgp_nexthop_detail, + show_ip_bgp_nexthop_detail_cmd, + "show ip bgp nexthop detail", + SHOW_STR + IP_STR + BGP_STR + "BGP nexthop table\n") +{ + return show_ip_bgp_nexthop_table (vty, 1); +} + int bgp_config_write_scan_time (struct vty *vty) { @@ -1420,8 +1500,12 @@ bgp_scan_init (void) install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd); + install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd); + install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_nexthop_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_nexthop_detail_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd); } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 85c5a5d07..a239ca061 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -22,6 +22,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define _QUAGGA_BGP_NEXTHOP_H #include "if.h" +#include "queue.h" +#include "prefix.h" #define BGP_SCAN_INTERVAL_DEFAULT 60 #define BGP_IMPORT_INTERVAL_DEFAULT 15 @@ -53,6 +55,20 @@ struct bgp_nexthop_cache /* Nexthop number and nexthop linked list.*/ u_char nexthop_num; struct nexthop *nexthop; + time_t last_update; + u_int16_t flags; + +#define BGP_NEXTHOP_VALID (1 << 0) +#define BGP_NEXTHOP_REGISTERED (1 << 1) + + u_int16_t change_flags; + +#define BGP_NEXTHOP_CHANGED (1 << 0) +#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) + + struct bgp_node *node; + LIST_HEAD(path_list, bgp_info) paths; + unsigned int path_count; }; extern void bgp_scan_init (void); @@ -68,5 +84,9 @@ extern int bgp_nexthop_self (struct attr *); extern void bgp_address_init (void); extern void bgp_address_destroy (void); extern void bgp_scan_destroy (void); +extern struct bgp_nexthop_cache *bnc_new(void); +extern void bnc_free(struct bgp_nexthop_cache *bnc); +extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc); +extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c new file mode 100644 index 000000000..21e1411b8 --- /dev/null +++ b/bgpd/bgp_nht.c @@ -0,0 +1,477 @@ +/* BGP Nexthop tracking + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "thread.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" +#include "log.h" +#include "memory.h" +#include "nexthop.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_nht.h" + +extern struct zclient *zclient; +extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; + +static void register_nexthop(struct bgp_nexthop_cache *bnc); +static void unregister_nexthop (struct bgp_nexthop_cache *bnc); +static void evaluate_paths(struct bgp_nexthop_cache *bnc); +static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p); +static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, + int keep); + +int +bgp_find_nexthop (struct bgp_info *path, int *changed, int *metricchanged) +{ + struct bgp_nexthop_cache *bnc = path->nexthop; + + if (!bnc) + return 0; + + if (changed) + *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); + + if (metricchanged) + *metricchanged = CHECK_FLAG(bnc->change_flags, + BGP_NEXTHOP_METRIC_CHANGED); + + return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); +} + +void +bgp_unlink_nexthop (struct bgp_info *path) +{ + struct bgp_nexthop_cache *bnc = path->nexthop; + + if (!bnc) + return; + + path_nh_map(path, NULL, 0); + + if (LIST_EMPTY(&(bnc->paths))) + { + if (BGP_DEBUG(nht, NHT)) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("bgp_unlink_nexthop: freeing bnc %s", + bnc_str(bnc, buf, INET6_ADDRSTRLEN)); + } + unregister_nexthop(bnc); + bnc->node->info = NULL; + bgp_unlock_node(bnc->node); + bnc_free(bnc); + } +} + +int +bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed, + int *metricchanged) +{ + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + struct prefix p; + + if (make_prefix(afi, ri, &p) < 0) + return 1; + rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); + + if (!rn->info) + { + bnc = bnc_new(); + rn->info = bnc; + bnc->node = rn; + bgp_lock_node(rn); + register_nexthop(bnc); + } + bnc = rn->info; + bgp_unlock_node (rn); + path_nh_map(ri, bnc, 1); + + if (changed) + *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); + + if (metricchanged) + *metricchanged = CHECK_FLAG(bnc->change_flags, + BGP_NEXTHOP_METRIC_CHANGED); + + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) + (bgp_info_extra_get(ri))->igpmetric = bnc->metric; + else if (ri->extra) + ri->extra->igpmetric = 0; + + return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); +} + +void +bgp_parse_nexthop_update (void) +{ + struct stream *s; + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + struct nexthop *nexthop; + struct nexthop *oldnh; + struct nexthop *nhlist_head = NULL; + struct nexthop *nhlist_tail = NULL; + uint32_t metric; + u_char nexthop_num; + struct prefix p; + int i; + + s = zclient->ibuf; + + memset(&p, 0, sizeof(struct prefix)); + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + switch (p.family) + { + case AF_INET: + p.u.prefix4.s_addr = stream_get_ipv4 (s); + break; + case AF_INET6: + stream_get(&p.u.prefix6, s, 16); + break; + default: + break; + } + + rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p); + if (!rn || !rn->info) + { + if (BGP_DEBUG(nht, NHT)) + { + char buf[INET6_ADDRSTRLEN]; + prefix2str(&p, buf, INET6_ADDRSTRLEN); + zlog_debug("parse nexthop update(%s): rn not found", buf); + } + if (rn) + bgp_unlock_node (rn); + return; + } + + bnc = rn->info; + bgp_unlock_node (rn); + bnc->last_update = bgp_clock(); + bnc->change_flags = 0; + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + /* debug print the input */ + if (BGP_DEBUG(nht, NHT)) + { + char buf[INET6_ADDRSTRLEN]; + prefix2str(&p, buf, INET6_ADDRSTRLEN); + zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf, + metric, nexthop_num); + } + + if (metric != bnc->metric) + bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; + + if(nexthop_num != bnc->nexthop_num) + bnc->change_flags |= BGP_NEXTHOP_CHANGED; + + if (nexthop_num) + { + bnc->flags |= BGP_NEXTHOP_VALID; + bnc->metric = metric; + bnc->nexthop_num = nexthop_num; + + for (i = 0; i < nexthop_num; i++) + { + nexthop = nexthop_new(); + nexthop->type = stream_getc (s); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + nexthop->ifindex = stream_getl (s); + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case ZEBRA_NEXTHOP_IPV4_IFNAME: + nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); + nexthop->ifindex = stream_getl (s); + break; +#ifdef HAVE_IPV6 + case ZEBRA_NEXTHOP_IPV6: + stream_get (&nexthop->gate.ipv6, s, 16); + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + stream_get (&nexthop->gate.ipv6, s, 16); + nexthop->ifindex = stream_getl (s); + break; +#endif + default: + /* do nothing */ + break; + } + + if (nhlist_tail) + { + nhlist_tail->next = nexthop; + nhlist_tail = nexthop; + } + else + { + nhlist_tail = nexthop; + nhlist_head = nexthop; + } + + /* No need to evaluate the nexthop if we have already determined + * that there has been a change. + */ + if (bnc->change_flags & BGP_NEXTHOP_CHANGED) + continue; + + for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) + if (nexthop_same_no_recurse(oldnh, nexthop)) + break; + + if (!oldnh) + bnc->change_flags |= BGP_NEXTHOP_CHANGED; + } + bnc_nexthop_free(bnc); + bnc->nexthop = nhlist_head; + } + else + { + bnc->flags &= ~BGP_NEXTHOP_VALID; + bnc_nexthop_free(bnc); + bnc->nexthop = NULL; + } + + evaluate_paths(bnc); +} + +/** + * make_prefix - make a prefix structure from the path (essentially + * path's node. + */ +static int +make_prefix (int afi, struct bgp_info *ri, struct prefix *p) +{ + memset (p, 0, sizeof (struct prefix)); + switch (afi) + { + case AFI_IP: + p->family = AF_INET; + p->prefixlen = IPV4_MAX_BITLEN; + p->u.prefix4 = ri->attr->nexthop; + break; +#ifdef HAVE_IPV6 + case AFI_IP6: + if (ri->attr->extra->mp_nexthop_len != 16 + || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global)) + return -1; + + p->family = AF_INET6; + p->prefixlen = IPV6_MAX_BITLEN; + p->u.prefix6 = ri->attr->extra->mp_nexthop_global; + break; +#endif + default: + break; + } + return 0; +} + +/** + * sendmsg_nexthop -- Format and send a nexthop register/Unregister + * command to Zebra. + * ARGUMENTS: + * struct bgp_nexthop_cache *bnc -- the nexthop structure. + * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER + * RETURNS: + * void. + */ +static void +sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) +{ + struct stream *s; + struct prefix *p; + int ret; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return; + + p = &(bnc->node->p); + s = zclient->obuf; + stream_reset (s); + zclient_create_header (s, command, VRF_DEFAULT); + stream_putw(s, PREFIX_FAMILY(p)); + stream_putc(s, p->prefixlen); + switch (PREFIX_FAMILY(p)) + { + case AF_INET: + stream_put_in_addr (s, &p->u.prefix4); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + stream_put(s, &(p->u.prefix6), 16); + break; +#endif + default: + break; + } + stream_putw_at (s, 0, stream_get_endp (s)); + + ret = zclient_send_message(zclient); + /* TBD: handle the failure */ + if (ret < 0) + zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); + return; +} + +/** + * register_nexthop - register a nexthop with Zebra for notification + * when the route to the nexthop changes. + * ARGUMENTS: + * struct bgp_nexthop_cache *bnc -- the nexthop structure. + * RETURNS: + * void. + */ +static void +register_nexthop (struct bgp_nexthop_cache *bnc) +{ + /* Check if we have already registered */ + if (bnc->flags & BGP_NEXTHOP_REGISTERED) + return; + sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER); + SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); +} + +/** + * unregister_nexthop -- Unregister the nexthop from Zebra. + * ARGUMENTS: + * struct bgp_nexthop_cache *bnc -- the nexthop structure. + * RETURNS: + * void. + */ +static void +unregister_nexthop (struct bgp_nexthop_cache *bnc) +{ + /* Check if we have already registered */ + if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) + return; + + sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); +} + +/** + * evaluate_paths - Evaluate the paths/nets associated with a nexthop. + * ARGUMENTS: + * struct bgp_nexthop_cache *bnc -- the nexthop structure. + * RETURNS: + * void. + */ +static void +evaluate_paths (struct bgp_nexthop_cache *bnc) +{ + struct bgp_node *rn; + struct bgp_info *path; + struct bgp *bgp = bgp_get_default(); + int afi; + + LIST_FOREACH(path, &(bnc->paths), nh_thread) + { + if (!(path->type == ZEBRA_ROUTE_BGP && + path->sub_type == BGP_ROUTE_NORMAL)) + continue; + + rn = path->net; + afi = family2afi(rn->p.family); + + /* Path becomes valid/invalid depending on whether the nexthop + * reachable/unreachable. + */ + if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) != + (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0)) + { + if (CHECK_FLAG (path->flags, BGP_INFO_VALID)) + { + bgp_aggregate_decrement (bgp, &rn->p, path, + afi, SAFI_UNICAST); + bgp_info_unset_flag (rn, path, BGP_INFO_VALID); + } + else + { + bgp_info_set_flag (rn, path, BGP_INFO_VALID); + bgp_aggregate_increment (bgp, &rn->p, path, + afi, SAFI_UNICAST); + } + } + + /* Copy the metric to the path. Will be used for bestpath computation */ + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) + (bgp_info_extra_get(path))->igpmetric = bnc->metric; + else if (path->extra) + path->extra->igpmetric = 0; + + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) || + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED)) + SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); + + bgp_process(bgp, rn, afi, SAFI_UNICAST); + } + RESET_FLAG(bnc->change_flags); +} + +/** + * path_nh_map - make or break path-to-nexthop association. + * ARGUMENTS: + * path - pointer to the path structure + * bnc - pointer to the nexthop structure + * make - if set, make the association. if unset, just break the existing + * association. + */ +static void +path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make) +{ + if (path->nexthop) + { + LIST_REMOVE(path, nh_thread); + path->nexthop->path_count--; + path->nexthop = NULL; + } + if (make) + { + LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread); + path->nexthop = bnc; + path->nexthop->path_count++; + } +} diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h new file mode 100644 index 000000000..41c2b85ba --- /dev/null +++ b/bgpd/bgp_nht.h @@ -0,0 +1,62 @@ +/* BGP Nexthop tracking + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _BGP_NHT_H +#define _BGP_NHT_H + +/** + * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra. + */ +extern void bgp_parse_nexthop_update(void); + +/** + * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object + * ARGUMENTS: + * p - path for which the nexthop object is being looked up + * c - output variable that stores whether the nexthop object has changed + * since last time. + * m - output variable that stores whether the nexthop metric has changed + * since last time. + */ +extern int bgp_find_nexthop(struct bgp_info *p, int *c, int *m); + +/** + * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc + * object. If not found, create a new object and register with ZEBRA for + * nexthop notification. + * ARGUMENTS: + * a - afi: AFI_IP or AF_IP6 + * p - path for which the nexthop object is being looked up + * c - output variable that stores whether the nexthop object has changed + * since last time. + * m - output variable that stores whether the nexthop metric has changed + * since last time. + */ +extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, int *c, int *m); + +/** + * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure. + * ARGUMENTS: + * p - path structure. + */ +extern void bgp_unlink_nexthop(struct bgp_info *p); + +#endif /* _BGP_NHT_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 746c54573..051dc8383 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -55,6 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_nht.c" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -126,20 +127,14 @@ bgp_info_extra_get (struct bgp_info *ri) return ri->extra; } -/* Allocate new bgp info structure. */ -static struct bgp_info * -bgp_info_new (void) -{ - return XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); -} - /* Free bgp route information. */ static void bgp_info_free (struct bgp_info *binfo) { if (binfo->attr) bgp_attr_unintern (&binfo->attr); - + + bgp_unlink_nexthop(binfo); bgp_info_extra_free (&binfo->extra); bgp_info_mpath_free (&binfo->mpath); @@ -1882,6 +1877,23 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, bgp_rib_remove (rn, ri, peer, afi, safi); } +static struct bgp_info * +info_make (int type, int sub_type, struct peer *peer, struct attr *attr, + struct bgp_node *rn) +{ + struct bgp_info *new; + + /* Make new BGP info. */ + new = XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); + new->type = type; + new->sub_type = sub_type; + new->peer = peer; + new->attr = attr; + new->uptime = bgp_clock (); + new->net = rn; + return new; +} + static void bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct attr *attr, struct peer *peer, struct prefix *p, int type, @@ -2029,13 +2041,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, p->prefixlen, rsclient->host); } - /* Make new BGP info. */ - new = bgp_info_new (); - new->type = type; - new->sub_type = sub_type; - new->peer = peer; - new->attr = attr_new; - new->uptime = bgp_clock (); + new = info_make(type, sub_type, peer, attr_new, rn); /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) @@ -2347,7 +2353,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { - if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) + if (bgp_find_or_add_nexthop (afi, ri, NULL, NULL)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); @@ -2376,12 +2382,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } /* Make new BGP info. */ - new = bgp_info_new (); - new->type = type; - new->sub_type = sub_type; - new->peer = peer; - new->attr = attr_new; - new->uptime = bgp_clock (); + new = info_make(type, sub_type, peer, attr_new, rn); /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) @@ -2395,7 +2396,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { - if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) + if (bgp_find_or_add_nexthop (afi, new, NULL, NULL)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else bgp_info_unset_flag (rn, new, BGP_INFO_VALID); @@ -3538,15 +3539,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, return; } } - + /* Make new BGP info. */ - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_STATIC; - new->peer = bgp->peer_self; + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, + attr_new, rn); SET_FLAG (new->flags, BGP_INFO_VALID); - new->attr = attr_new; - new->uptime = bgp_clock (); /* Register new BGP information. */ bgp_info_add (rn, new); @@ -3659,13 +3656,9 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, } /* Make new BGP info. */ - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_STATIC; - new->peer = bgp->peer_self; + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, + rn); SET_FLAG (new->flags, BGP_INFO_VALID); - new->attr = attr_new; - new->uptime = bgp_clock (); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); @@ -3706,8 +3699,14 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, { struct bgp_node *rn; struct bgp_info *ri; + struct bgp_info *new; - rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL); + /* Make new BGP info. */ + rn = bgp_node_get (bgp->rib[afi][safi], p); + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, + bgp_attr_default_intern(BGP_ORIGIN_IGP), rn); + + SET_FLAG (new->flags, BGP_INFO_VALID); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) @@ -3877,13 +3876,9 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, /* Make new BGP info. */ - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_STATIC; - new->peer = bgp->peer_self; - new->attr = attr_new; + new = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, + attr_new, rn); SET_FLAG (new->flags, BGP_INFO_VALID); - new->uptime = bgp_clock (); new->extra = bgp_info_extra_new(); memcpy (new->extra->tag, bgp_static->tag, 3); @@ -4881,13 +4876,10 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, if (aggregate->count > 0) { rn = bgp_node_get (table, p); - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_AGGREGATE; - new->peer = bgp->peer_self; + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self, + bgp_attr_aggregate_intern(bgp, origin, aspath, community, + aggregate->as_set), rn); SET_FLAG (new->flags, BGP_INFO_VALID); - new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); - new->uptime = bgp_clock (); bgp_info_add (rn, new); bgp_unlock_node (rn); @@ -5065,14 +5057,10 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, if (aggregate->count) { rn = bgp_node_get (table, p); - - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_AGGREGATE; - new->peer = bgp->peer_self; + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self, + bgp_attr_aggregate_intern(bgp, origin, aspath, community, + aggregate->as_set), rn); SET_FLAG (new->flags, BGP_INFO_VALID); - new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); - new->uptime = bgp_clock (); bgp_info_add (rn, new); bgp_unlock_node (rn); @@ -5715,16 +5703,12 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; - } + } } - new = bgp_info_new (); - new->type = type; - new->sub_type = BGP_ROUTE_REDISTRIBUTE; - new->peer = bgp->peer_self; + new = info_make(type, BGP_ROUTE_REDISTRIBUTE, bgp->peer_self, + new_attr, bn); SET_FLAG (new->flags, BGP_INFO_VALID); - new->attr = new_attr; - new->uptime = bgp_clock (); bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST); bgp_info_add (bn, new); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 8483f3dac..16b6d5a88 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -21,8 +21,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_ROUTE_H #define _QUAGGA_BGP_ROUTE_H +#include "queue.h" #include "bgp_table.h" +struct bgp_nexthop_cache; + /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. @@ -47,7 +50,16 @@ struct bgp_info /* For linked list. */ struct bgp_info *next; struct bgp_info *prev; - + + /* For nexthop linked list */ + LIST_ENTRY(bgp_info) nh_thread; + + /* Back pointer to the prefix node */ + struct bgp_node *net; + + /* Back pointer to the nexthop structure */ + struct bgp_nexthop_cache *nexthop; + /* Peer structure. */ struct peer *peer; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 00de6b861..484e355c0 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -39,6 +39,8 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_nht.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -70,6 +72,15 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, return 0; } +/* Nexthop update message from zebra. */ +static int +bgp_read_nexthop_update (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + bgp_parse_nexthop_update(); + return 0; +} + /* Inteface addition message from zebra. */ static int bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length, @@ -1160,6 +1171,7 @@ bgp_zebra_init (struct thread_master *master) zclient->interface_down = bgp_interface_down; zclient->ipv6_route_add = zebra_read_ipv6; zclient->ipv6_route_delete = zebra_read_ipv6; + zclient->nexthop_update = bgp_read_nexthop_update; bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE); diff --git a/doc/next-hop-tracking.txt b/doc/next-hop-tracking.txt new file mode 100644 index 000000000..d157866e8 --- /dev/null +++ b/doc/next-hop-tracking.txt @@ -0,0 +1,326 @@ +0. Introduction + +This is the design specification for next hop tracking feature in +Quagga. + +1. Background + +Recursive routes are of the form: + + p/m --> n + [Ex: 1.1.0.0/16 --> 2.2.2.2] + +where 'n' itself is resolved through another route as follows: + + p2/m --> h, interface + [Ex: 2.2.2.0/24 --> 3.3.3.3, eth0] + +Usually, BGP routes are recursive in nature and BGP nexthops get +resolved through an IGP route. IGP usually adds its routes pointing to +an interface (these are called non-recursive routes). + +When BGP receives a recursive route from a peer, it needs to validate +the nexthop. The path is marked valid or invalid based on the +reachability status of the nexthop. Nexthop validation is also +important for BGP decision process as the metric to reach the nexthop +is a parameter to best path selection process. + +As it goes with routing, this is a dynamic process. Route to the +nexthop can change. The nexthop can become unreachable or +reachable. In the current BGP implementation, the nexthop validation +is done periodically in the scanner run. The default scanner run +interval is one minute. Every minute, the scanner task walks the +entire BGP table. It checks the validity of each nexthop with Zebra +(the routing table manager) through a request and response message +exchange between BGP and Zebra process. BGP process is blocked for +that duration. The mechanism has two major drawbacks: + +(1) The scanner task runs to completion. That can potentially starve + the other tasks for long periods of time, based on the BGP table + size and number of nexthops. + +(2) Convergence around routing changes that affect the nexthops can be + long (around a minute with the default intervals). The interval + can be shortened to achieve faster reaction time, but it makes the + first problem worse, with the scanner task consuming most of the + CPU resources. + +"Next hop tracking" feature makes this process event-driven. It +eliminates periodic nexthop validation and introduces an asynchronous +communication path between BGP and Zebra for route change notifications +that can then be acted upon. + +2. Goal + +Stating the obvious, the main goal is to remove the two limitations we +discussed in the previous section. The goals, in a constructive tone, +are the following: + +- fairness: the scanner run should not consume an unjustly high amount + of CPU time. This should give an overall good performance and + response time to other events (route changes, session events, + IO/user interface). + +- convergence: BGP must react to nexthop changes instantly and provide + sub-second convergence. This may involve diverting the routes from + one nexthop to another. + +3. Overview of the changes + +The changes are in both BGP and Zebra modules. The short summary is +the following: + +- Zebra implements a registration mechanism by which clients can + register for next hop notification. Consequently, it maintains a + separate table, per (VRF, AF) pair, of next hops and interested + client-list per next hop. + +- When the main routing table changes in Zebra, it evaluates the next + hop table: for each next hop, it checks if the route table + modifications have changed its state. If so, it notifies the + interested clients. + +- BGP is one such client. It registers the next hops corresponding to + all of its received routes/paths. It also threads the paths against + each nexthop structure. + +- When BGP receives a next hop notification from Zebra, it walks the + corresponding path list. It makes them valid or invalid depending + on the next hop notification. It then re-computes best path for the + corresponding destination. This may result in re-announcing those + destinations to peers. + +4. Design + +4.1. Modules + +The core design introduces an "nht" (next hop tracking) module in BGP +and "rnh" (recursive nexthop) module in Zebra. The "nht" module +provides the following APIs: + +bgp_find_or_add_nexthop() : find or add a nexthop in BGP nexthop table +bgp_find_nexthop() : find a nexthop in BGP nexthop table +bgp_parse_nexthop_update() : parse a nexthop update message coming + from zebra + +The "rnh" module provides the following APIs: + +zebra_add_rnh() : add a recursive nexthop +zebra_delete_rnh() : delete a recursive nexthop +zebra_lookup_rnh() : lookup a recursive nexthop + +zebra_add_rnh_client() : register a client for nexthop notifications + against a recursive nexthop + +zebra_remove_rnh_client(): remove the client registration for a + recursive nexthop + +zebra_evaluate_rnh_table(): (re)evaluate the recursive nexthop table + (most probably because the main routing + table has changed). + +zebra_cleanup_rnh_client(): Cleanup a client from the "rnh" module + data structures (most probably because the + client is going away). + +4.2. Control flow + +The next hop registration control flow is the following: + +<==== BGP Process ====>|<==== Zebra Process ====> + | +receive module nht module | zserv module rnh module +---------------------------------------------------------------------- + | | | +bgp_update_ | | | + main() | bgp_find_or_add_ | | + | nexthop() | | + | | | + | | zserv_nexthop_ | + | | register() | + | | | zebra_add_rnh() + | | | + + +The next hop notification control flow is the following: + +<==== Zebra Process ====>|<==== BGP Process ====> + | +rib module rnh module | zebra module nht module +---------------------------------------------------------------------- + | | | +meta_queue_ | | | + process() | zebra_evaluate_ | | + | rnh_table() | | + | | | + | | bgp_read_nexthop_ | + | | update() | + | | | bgp_parse_ + | | | nexthop_update() + | | | + + +4.3. zclient message format + +ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are +encoded in the following way: + +/* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | AF | prefix len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . Nexthop prefix . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | AF | prefix len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . Nexthop prefix . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +ZEBRA_NEXTHOP_UPDATE message is encoded as follows: + +/* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | AF | prefix len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . Nexthop prefix getting resolved . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | metric | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | #nexthops | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | nexthop type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . resolving Nexthop details . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | nexthop type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . resolving Nexthop details . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +4.4. BGP data structure + +Legend: + +/\ struct bgp_node: a BGP destination/route/prefix +\/ + +[ ] struct bgp_info: a BGP path (e.g. route received from a peer) + + _ +(_) struct bgp_nexthop_cache: a BGP nexthop + + + + /\ NULL + \/--+ ^ + | : + +--[ ]--[ ]--[ ]--> NULL + /\ : + \/--+ : + | : + +--[ ]--[ ]--> NULL + : + _ : + (_)............. + + +4.5. Zebra data structure + +rnh table: + + O + / \ + O O + / \ + O O + + struct rnh + { + u_char flags; + struct rib *state; + struct list *client_list; + struct route_node *node; + }; + +5. User interface changes + +quagga# show ip nht +3.3.3.3 + resolved via kernel + via 11.0.0.6, swp1 + Client list: bgp(fd 12) +11.0.0.10 + resolved via connected + is directly connected, swp2 + Client list: bgp(fd 12) +11.0.0.18 + resolved via connected + is directly connected, swp4 + Client list: bgp(fd 12) +11.11.11.11 + resolved via kernel + via 10.0.1.2, eth0 + Client list: bgp(fd 12) + +quagga# show ip bgp nexthop +Current BGP nexthop cache: + 3.3.3.3 valid [IGP metric 0], #paths 3 + Last update: Wed Oct 16 04:43:49 2013 + + 11.0.0.10 valid [IGP metric 1], #paths 1 + Last update: Wed Oct 16 04:43:51 2013 + + 11.0.0.18 valid [IGP metric 1], #paths 2 + Last update: Wed Oct 16 04:43:47 2013 + + 11.11.11.11 valid [IGP metric 0], #paths 1 + Last update: Wed Oct 16 04:43:47 2013 + +quagga# show ipv6 nht +quagga# show ip bgp nexthop detail + +quagga# debug bgp nht +quagga# debug zebra nht + +6. Sample test cases + + r2----r3 + / \ / + r1----r4 + +- Verify that a change in IGP cost triggers NHT + + shutdown the r1-r4 and r2-r4 links + + no shut the r1-r4 and r2-r4 links and wait for OSPF to come back + up + + We should be back to the original nexthop via r4 now +- Verify that a NH becoming unreachable triggers NHT + + Shutdown all links to r4 +- Verify that a NH becoming reachable triggers NHT + + no shut all links to r4 + +7. Future work + +- route-policy for next hop validation (e.g. ignore default route) +- damping for rapid next hop changes +- prioritized handling of nexthop changes ((un)reachability vs. metric + changes) +- handling recursion loop, e.g. + 11.11.11.11/32 -> 12.12.12.12 + 12.12.12.12/32 -> 11.11.11.11 + 11.0.0.0/8 -> +- better statistics diff --git a/lib/Makefile.am b/lib/Makefile.am index 32998a870..be8495f14 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -13,7 +13,8 @@ libzebra_la_SOURCES = \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c event_counter.c + sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c \ + event_counter.c nexthop.c BUILT_SOURCES = memtypes.h route_types.h gitversion.h @@ -28,7 +29,8 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h libospf.h vrf.h fifo.h event_counter.h + workqueue.h route_types.h libospf.h vrf.h fifo.h event_counter.h \ + nexthop.h noinst_HEADERS = \ plist_int.h diff --git a/lib/log.c b/lib/log.c index 0914bf840..42b7717ee 100644 --- a/lib/log.c +++ b/lib/log.c @@ -895,6 +895,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE), DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE), DESC_ENTRY (ZEBRA_HELLO), + DESC_ENTRY (ZEBRA_NEXTHOP_REGISTER), + DESC_ENTRY (ZEBRA_NEXTHOP_UNREGISTER), + DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE), }; #undef DESC_ENTRY diff --git a/lib/memtypes.c b/lib/memtypes.c index f464c4b00..8abe99d2a 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -87,6 +87,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_RIB_DEST, "RIB destination" }, { MTYPE_RIB_TABLE_INFO, "RIB table info" }, { MTYPE_NETLINK_NAME, "Netlink name" }, + { MTYPE_RNH, "Nexthop tracking object" }, { -1, NULL }, }; diff --git a/lib/nexthop.c b/lib/nexthop.c new file mode 100644 index 000000000..5eb2182de --- /dev/null +++ b/lib/nexthop.c @@ -0,0 +1,168 @@ +/* A generic nexthop structure + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * 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 + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "str.h" +#include "command.h" +#include "if.h" +#include "log.h" +#include "sockunion.h" +#include "linklist.h" +#include "thread.h" +#include "prefix.h" +#include "nexthop.h" + +/* check if nexthops are same, non-recursive */ +int +nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2) +{ + if (next1->type != next2->type) + return 0; + + switch (next1->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) + return 0; + if (next1->ifindex && (next1->ifindex != next2->ifindex)) + return 0; + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + if (next1->ifindex != next2->ifindex) + return 0; + break; +#ifdef HAVE_IPV6 + case NEXTHOP_TYPE_IPV6: + if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) + return 0; + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) + return 0; + if (next1->ifindex != next2->ifindex) + return 0; + break; +#endif /* HAVE_IPV6 */ + default: + /* do nothing */ + break; + } + return 1; +} + +/* + * nexthop_type_to_str + */ +const char * +nexthop_type_to_str (enum nexthop_types_t nh_type) +{ + static const char *desc[] = { + "none", + "Directly connected", + "Interface route", + "IPv4 nexthop", + "IPv4 nexthop with ifindex", + "IPv4 nexthop with ifname", + "IPv6 nexthop", + "IPv6 nexthop with ifindex", + "IPv6 nexthop with ifname", + "Null0 nexthop", + }; + + if (nh_type >= ZEBRA_NUM_OF (desc)) + return ""; + + return desc[nh_type]; +} + +struct nexthop * +nexthop_new (void) +{ + return XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); +} + +/* Add nexthop to the end of a nexthop list. */ +void +nexthop_add (struct nexthop **target, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = *target; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + *target = nexthop; + nexthop->prev = last; +} + +void +copy_nexthops (struct nexthop **tnh, struct nexthop *nh) +{ + struct nexthop *nexthop; + struct nexthop *nh1; + + for (nh1 = nh; nh1; nh1 = nh1->next) + { + nexthop = nexthop_new(); + nexthop->flags = nh->flags; + nexthop->type = nh->type; + nexthop->ifindex = nh->ifindex; + if (nh->ifname) + nexthop->ifname = XSTRDUP(0, nh->ifname); + memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); + memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); + nexthop_add(tnh, nexthop); + + if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) + copy_nexthops(&nexthop->resolved, nh1->resolved); + } +} + +/* Free nexthop. */ +void +nexthop_free (struct nexthop *nexthop) +{ + if (nexthop->ifname) + XFREE (0, nexthop->ifname); + if (nexthop->resolved) + nexthops_free(nexthop->resolved); + XFREE (MTYPE_NEXTHOP, nexthop); +} + +/* Frees a list of nexthops */ +void +nexthops_free (struct nexthop *nexthop) +{ + struct nexthop *nh, *next; + + for (nh = nexthop; nh; nh = next) + { + next = nh->next; + nexthop_free (nh); + } +} diff --git a/lib/nexthop.h b/lib/nexthop.h new file mode 100644 index 000000000..0c0dfcaba --- /dev/null +++ b/lib/nexthop.h @@ -0,0 +1,91 @@ +/* + * Nexthop structure definition. + * Copyright (C) 1997, 98, 99, 2001 Kunihiro Ishiguro + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * 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 _LIB_NEXTHOP_H +#define _LIB_NEXTHOP_H + +#include "prefix.h" + +union g_addr { + struct in_addr ipv4; +#ifdef HAVE_IPV6 + struct in6_addr ipv6; +#endif /* HAVE_IPV6 */ +}; + +enum nexthop_types_t +{ + NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */ + NEXTHOP_TYPE_IFNAME, /* Interface route. */ + NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */ + NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */ + NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */ + NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */ + NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */ + NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */ + NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */ +}; + +/* Nexthop structure. */ +struct nexthop +{ + struct nexthop *next; + struct nexthop *prev; + + /* Interface index. */ + char *ifname; + ifindex_t ifindex; + + enum nexthop_types_t type; + + u_char flags; +#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ +#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ +#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ +#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */ +#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */ + + /* Nexthop address */ + union g_addr gate; + 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; +}; + +struct nexthop *nexthop_new (void); +void nexthop_add (struct nexthop **target, struct nexthop *nexthop); + +void copy_nexthops (struct nexthop **tnh, struct nexthop *nh); +void nexthop_free (struct nexthop *nexthop); +void nexthops_free (struct nexthop *nexthop); + +extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); +extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2); + +#endif /*_LIB_NEXTHOP_H */ diff --git a/lib/zclient.c b/lib/zclient.c index 09bb1807d..097314afa 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1181,6 +1181,9 @@ zclient_read (struct thread *thread) case ZEBRA_INTERFACE_LINK_PARAMS: if (zclient->interface_link_params) (*zclient->interface_link_params) (command, zclient, length); + case ZEBRA_NEXTHOP_UPDATE: + if (zclient->nexthop_update) + (*zclient->nexthop_update) (command, zclient, length, vrf_id); break; default: break; diff --git a/lib/zclient.h b/lib/zclient.h index 151349297..a3452eb32 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -90,6 +90,7 @@ struct zclient int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv6_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); + int (*nexthop_update) (int, struct zclient *, uint16_t, vrf_id_t); }; /* Zebra API message flag. */ diff --git a/lib/zebra.h b/lib/zebra.h index 70d498a4f..a75eb6d18 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -426,7 +426,10 @@ struct in_pktinfo #define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24 #define ZEBRA_VRF_UNREGISTER 25 #define ZEBRA_INTERFACE_LINK_PARAMS 26 -#define ZEBRA_MESSAGE_MAX 27 +#define ZEBRA_NEXTHOP_REGISTER 27 +#define ZEBRA_NEXTHOP_UNREGISTER 28 +#define ZEBRA_NEXTHOP_UPDATE 29 +#define ZEBRA_MESSAGE_MAX 30 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new @@ -521,6 +524,7 @@ typedef enum { #define CHECK_FLAG(V,F) ((V) & (F)) #define SET_FLAG(V,F) (V) |= (F) #define UNSET_FLAG(V,F) (V) &= ~(F) +#define RESET_FLAG(V) (V) = 0 typedef u_int8_t safi_t; diff --git a/zebra/Makefile.am b/zebra/Makefile.am index abd3797da..b23f9f1b9 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -40,17 +40,18 @@ zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ + zebra_rnh.c \ $(othersrc) $(protobuf_srcs) $(dev_srcs) testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c \ - kernel_null.c redistribute_null.c ioctl_null.c misc_null.c + kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h \ - ioctl_solaris.h + ioctl_solaris.h zebra_rnh.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS) diff --git a/zebra/debug.c b/zebra/debug.c index 537c47662..fbeef52b6 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -30,6 +30,7 @@ unsigned long zebra_debug_packet; unsigned long zebra_debug_kernel; unsigned long zebra_debug_rib; unsigned long zebra_debug_fpm; +unsigned long zebra_debug_nht; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, @@ -74,6 +75,8 @@ DEFUN (show_debugging_zebra, if (IS_ZEBRA_DEBUG_FPM) vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE); + if (IS_ZEBRA_DEBUG_NHT) + vty_out (vty, " Zebra next-hop tracking debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -89,6 +92,17 @@ DEFUN (debug_zebra_events, return CMD_WARNING; } +DEFUN (debug_zebra_nht, + debug_zebra_nht_cmd, + "debug zebra nht", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra next hop tracking\n") +{ + zebra_debug_nht = ZEBRA_DEBUG_NHT; + return CMD_WARNING; +} + DEFUN (debug_zebra_packet, debug_zebra_packet_cmd, "debug zebra packet", @@ -197,6 +211,18 @@ DEFUN (no_debug_zebra_events, return CMD_SUCCESS; } +DEFUN (no_debug_zebra_nht, + no_debug_zebra_nht_cmd, + "no debug zebra nht", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra next hop tracking\n") +{ + zebra_debug_nht = 0; + return CMD_SUCCESS; +} + DEFUN (no_debug_zebra_packet, no_debug_zebra_packet_cmd, "no debug zebra packet", @@ -353,6 +379,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &show_debugging_zebra_cmd); install_element (ENABLE_NODE, &debug_zebra_events_cmd); + install_element (ENABLE_NODE, &debug_zebra_nht_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd); @@ -361,6 +388,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd); install_element (ENABLE_NODE, &debug_zebra_fpm_cmd); install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd); @@ -368,6 +396,7 @@ zebra_debug_init (void) install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &debug_zebra_events_cmd); + install_element (CONFIG_NODE, &debug_zebra_nht_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd); install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd); @@ -376,6 +405,7 @@ zebra_debug_init (void) install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd); install_element (CONFIG_NODE, &debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index d9231a22b..0fb4dd9fe 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -37,6 +37,7 @@ #define ZEBRA_DEBUG_RIB_Q 0x02 #define ZEBRA_DEBUG_FPM 0x01 +#define ZEBRA_DEBUG_NHT 0x01 /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -52,12 +53,14 @@ #define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q) #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM) +#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; extern unsigned long zebra_debug_kernel; extern unsigned long zebra_debug_rib; extern unsigned long zebra_debug_fpm; +extern unsigned long zebra_debug_nht; extern void zebra_debug_init (void); diff --git a/zebra/ioctl.c b/zebra/ioctl.c index f7a7ff40b..e1ee4290c 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -196,7 +196,6 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; - rib_lookup_and_pushup (p); memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); diff --git a/zebra/rib.h b/zebra/rib.h index 677e3955d..9773cba87 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -27,18 +27,10 @@ #include "prefix.h" #include "table.h" #include "queue.h" +#include "nexthop.h" #define DISTANCE_INFINITY 255 -/* Routing information base. */ - -union g_addr { - struct in_addr ipv4; -#ifdef HAVE_IPV6 - struct in6_addr ipv6; -#endif /* HAVE_IPV6 */ -}; - struct rib { /* Link list. */ @@ -207,50 +199,6 @@ struct static_route */ }; -enum nexthop_types_t -{ - NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */ - NEXTHOP_TYPE_IFNAME, /* Interface route. */ - NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */ - NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */ - NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */ - NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */ - NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */ - NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */ - NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */ -}; - -/* Nexthop structure. */ -struct nexthop -{ - struct nexthop *next; - struct nexthop *prev; - - /* Interface index. */ - char *ifname; - ifindex_t ifindex; - - enum nexthop_types_t type; - - u_char flags; -#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ -#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ -#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ -#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */ - - /* Nexthop address */ - union g_addr gate; - 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. * @@ -370,6 +318,9 @@ struct zebra_vrf #if defined (HAVE_RTADV) struct rtadv rtadv; #endif /* HAVE_RTADV */ + + /* Recursive Nexthop table */ + struct route_table *rnh_table[AFI_MAX]; }; /* @@ -425,18 +376,20 @@ extern void multicast_mode_ipv4_set (enum multicast_mode mode); extern enum multicast_mode multicast_mode_ipv4_get (void); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); -extern struct nexthop *nexthop_ifindex_add (struct rib *, ifindex_t); -extern struct nexthop *nexthop_ifname_add (struct rib *, char *); -extern struct nexthop *nexthop_blackhole_add (struct rib *); -extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, - struct in_addr *); -extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, - struct in_addr *, - struct in_addr *, - ifindex_t); +extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, ifindex_t); +extern struct nexthop *rib_nexthop_ifname_add (struct rib *, char *); +extern struct nexthop *rib_nexthop_blackhole_add (struct rib *); +extern struct nexthop *rib_nexthop_ipv4_add (struct rib *, struct in_addr *, + struct in_addr *); +extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *, + struct in_addr *, + struct in_addr *, + ifindex_t); + +extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop); + extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); -extern void rib_lookup_and_pushup (struct prefix_ipv4 *); #define rib_dump(prefix ,rib) _rib_dump(__func__, prefix, rib) extern void _rib_dump (const char *, union prefix46constptr, const struct rib *); @@ -448,11 +401,12 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, #define ZEBRA_RIB_FOUND_CONNECTED 2 #define ZEBRA_RIB_NOTFOUND 3 -extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); -extern struct nexthop *nexthop_ipv6_ifindex_add (struct rib *, - struct in6_addr *, - ifindex_t); +extern struct nexthop *rib_nexthop_ipv6_add (struct rib *, struct in6_addr *); +extern struct nexthop *rib_nexthop_ipv6_ifindex_add (struct rib *, + struct in6_addr *, + ifindex_t); +extern struct zebra_vrf *zebra_vrf_lookup (vrf_id_t vrf_id); extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t); extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t); extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 42cb9d45b..105e55938 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -38,6 +38,7 @@ #include "thread.h" #include "privs.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" #include "zebra/rt.h" @@ -851,12 +852,12 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, if (gate) { if (index) - nexthop_ipv4_ifindex_add (rib, gate, src, index); + rib_nexthop_ipv4_ifindex_add (rib, gate, src, index); else - nexthop_ipv4_add (rib, gate, src); + rib_nexthop_ipv4_add (rib, gate, src); } else - nexthop_ifindex_add (rib, index); + rib_nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); @@ -1065,12 +1066,12 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (gate) { if (index) - nexthop_ipv4_ifindex_add (rib, gate, src, index); + rib_nexthop_ipv4_ifindex_add (rib, gate, src, index); else - nexthop_ipv4_add (rib, gate, src); + rib_nexthop_ipv4_add (rib, gate, src); } else - nexthop_ifindex_add (rib, index); + rib_nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 96e897bf1..59e861b91 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -29,6 +29,7 @@ #include "rib.h" #include "rt_netlink.h" +#include "nexthop.h" #include "zebra_fpm_private.h" diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index eec29769b..0aa516cd9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -35,6 +35,7 @@ #include "prefix.h" #include "routemap.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/rib.h" #include "zebra/rt.h" @@ -42,6 +43,7 @@ #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_fpm.h" +#include "zebra/zebra_rnh.h" /* Default rtm_table for all clients */ extern struct zebra_t zebrad; @@ -110,57 +112,17 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority, #define rnode_info(node, ...) \ _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) -/* - * nexthop_type_to_str - */ -const char * -nexthop_type_to_str (enum nexthop_types_t nh_type) -{ - static const char *desc[] = { - "none", - "Directly connected", - "Interface route", - "IPv4 nexthop", - "IPv4 nexthop with ifindex", - "IPv4 nexthop with ifname", - "IPv6 nexthop", - "IPv6 nexthop with ifindex", - "IPv6 nexthop with ifname", - "Null0 nexthop", - }; - - if (nh_type >= ZEBRA_NUM_OF (desc)) - return ""; - - return desc[nh_type]; -} - -/* Add nexthop to the end of a nexthop list. */ -static void -_nexthop_add (struct nexthop **target, struct nexthop *nexthop) -{ - struct nexthop *last; - - for (last = *target; last && last->next; last = last->next) - ; - if (last) - last->next = nexthop; - else - *target = nexthop; - 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) +void +rib_nexthop_add (struct rib *rib, struct nexthop *nexthop) { - _nexthop_add(&rib->nexthop, nexthop); + nexthop_add(&rib->nexthop, nexthop); rib->nexthop_num++; } /* Delete specified nexthop from the list. */ static void -nexthop_delete (struct rib *rib, struct nexthop *nexthop) +rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop) { if (nexthop->next) nexthop->next->prev = nexthop->prev; @@ -171,150 +133,124 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop) rib->nexthop_num--; } -static void nexthops_free(struct nexthop *nexthop); - -/* Free nexthop. */ -static void -nexthop_free (struct nexthop *nexthop) -{ - if (nexthop->ifname) - XFREE (0, nexthop->ifname); - if (nexthop->resolved) - nexthops_free(nexthop->resolved); - 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 * -nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) +rib_nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IFINDEX; nexthop->ifindex = ifindex; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ifname_add (struct rib *rib, char *ifname) +rib_nexthop_ifname_add (struct rib *rib, char *ifname) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IFNAME; nexthop->ifname = XSTRDUP (MTYPE_TMP, ifname); - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) +rib_nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV4; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, - struct in_addr *src, ifindex_t ifindex) +rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, + struct in_addr *src, ifindex_t ifindex) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) +rib_nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6; nexthop->gate.ipv6 = *ipv6; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } static struct nexthop * -nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, - char *ifname) +rib_nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, + char *ifname) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; nexthop->gate.ipv6 = *ipv6; nexthop->ifname = XSTRDUP (MTYPE_TMP, ifname); - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, - ifindex_t ifindex) +rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, + ifindex_t ifindex) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * -nexthop_blackhole_add (struct rib *rib) +rib_nexthop_blackhole_add (struct rib *rib) { struct nexthop *nexthop; - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); - nexthop_add (rib, nexthop); + rib_nexthop_add (rib, nexthop); return nexthop; } @@ -455,7 +391,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, resolved_hop->ifindex = newhop->ifindex; } - _nexthop_add(&nexthop->resolved, resolved_hop); + nexthop_add(&nexthop->resolved, resolved_hop); } resolved = 1; } @@ -592,7 +528,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, resolved_hop->ifindex = newhop->ifindex; } - _nexthop_add(&nexthop->resolved, resolved_hop); + nexthop_add(&nexthop->resolved, resolved_hop); } resolved = 1; } @@ -1440,6 +1376,18 @@ process_subq (struct list * subq, u_char qindex) return 1; } +/* + * All meta queues have been processed. Trigger next-hop evaluation. + */ +static void +meta_queue_process_complete (struct work_queue *dummy) +{ + zebra_evaluate_rnh_table(0, AF_INET); +#ifdef HAVE_IPV6 + zebra_evaluate_rnh_table(0, AF_INET6); +#endif /* HAVE_IPV6 */ +} + /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data * is pointed to the meta queue structure. @@ -1592,6 +1540,7 @@ rib_queue_init (struct zebra_t *zebra) /* fill in the work queue spec */ zebra->ribq->spec.workfunc = &meta_queue_process; zebra->ribq->spec.errorfunc = NULL; + zebra->ribq->spec.completion_func = &meta_queue_process_complete; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; zebra->ribq->spec.hold = rib_process_hold_time; @@ -1815,12 +1764,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (gate) { if (ifindex) - nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); else - nexthop_ipv4_add (rib, gate, src); + rib_nexthop_ipv4_add (rib, gate, src); } else - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); /* If this route is kernel route, set FIB flag to the route. */ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) @@ -1954,58 +1903,6 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) } } -/* Check if requested address assignment will fail due to another - * route being installed by zebra in FIB already. Take necessary - * actions, if needed: remove such a route from FIB and deSELECT - * corresponding RIB entry. Then put affected RN into RIBQ head. - */ -void rib_lookup_and_pushup (struct prefix_ipv4 * p) -{ - struct route_table *table; - struct route_node *rn; - struct rib *rib; - unsigned changed = 0; - - if (NULL == (table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT))) - { - zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); - return; - } - - /* No matches would be the simplest case. */ - if (NULL == (rn = route_node_lookup (table, (struct prefix *) p))) - return; - - /* Unlock node. */ - route_unlock_node (rn); - - /* Check all RIB entries. In case any changes have to be done, requeue - * the RN into RIBQ head. If the routing message about the new connected - * route (generated by the IP address we are going to assign very soon) - * comes before the RIBQ is processed, the new RIB entry will join - * RIBQ record already on head. This is necessary for proper revalidation - * of the rest of the RIB. - */ - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) && - ! RIB_SYSTEM_ROUTE (rib)) - { - changed = 1; - if (IS_ZEBRA_DEBUG_RIB) - { - char buf[PREFIX_STRLEN]; - zlog_debug ("%s: freeing way for connected prefix %s", __func__, - prefix2str(&rn->p, buf, sizeof(buf))); - rib_dump (&rn->p, rib); - } - rib_uninstall (rn, rib); - } - } - if (changed) - rib_queue_add (&zebrad, rn); -} - int rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { @@ -2251,22 +2148,22 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); break; case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->addr.ipv6); + rib_nexthop_ipv6_add (rib, &si->addr.ipv6); break; case STATIC_IPV6_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); + rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } rib_queue_add (&zebrad, rn); @@ -2286,22 +2183,22 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); break; case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; case STATIC_IPV6_GATEWAY: - nexthop_ipv6_add (rib, &si->addr.ipv6); + rib_nexthop_ipv6_add (rib, &si->addr.ipv6); break; case STATIC_IPV6_IFNAME: - nexthop_ifname_add (rib, si->ifname); + rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); + rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } @@ -2396,7 +2293,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); - nexthop_delete (rib, nexthop); + rib_nexthop_delete (rib, nexthop); nexthop_free (nexthop); rib_queue_add (&zebrad, rn); } @@ -2632,12 +2529,12 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (gate) { if (ifindex) - nexthop_ipv6_ifindex_add (rib, gate, ifindex); + rib_nexthop_ipv6_ifindex_add (rib, gate, ifindex); else - nexthop_ipv6_add (rib, gate); + rib_nexthop_ipv6_add (rib, gate); } else - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); /* If this route is kernel route, set FIB flag to the route. */ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) @@ -2878,7 +2775,6 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, return 0; } - /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, @@ -3321,6 +3217,13 @@ rib_tables_iter_next (rib_tables_iter_t *iter) return table; } +/* Lookup VRF by identifier. */ +struct zebra_vrf * +zebra_vrf_lookup (vrf_id_t vrf_id) +{ + return vrf_info_lookup (vrf_id); +} + /* * Create a routing table for the specific AFI/SAFI in the given VRF. */ @@ -3363,6 +3266,9 @@ zebra_vrf_alloc (vrf_id_t vrf_id) zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + zvrf->rnh_table[AFI_IP] = route_table_init(); + zvrf->rnh_table[AFI_IP6] = route_table_init(); + /* Set VRF ID */ zvrf->vrf_id = vrf_id; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c new file mode 100644 index 000000000..3e02812db --- /dev/null +++ b/zebra/zebra_rnh.c @@ -0,0 +1,603 @@ +/* Zebra next hop tracking code + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "str.h" +#include "command.h" +#include "if.h" +#include "log.h" +#include "sockunion.h" +#include "linklist.h" +#include "thread.h" +#include "workqueue.h" +#include "prefix.h" +#include "routemap.h" +#include "stream.h" +#include "nexthop.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" +#include "zebra/zebra_rnh.h" + +#define lookup_rnh_table(v, f) \ +({ \ + struct zebra_vrf *zvrf; \ + struct route_table *t = NULL; \ + zvrf = zebra_vrf_lookup(v); \ + if (zvrf) \ + t = zvrf->rnh_table[family2afi(f)]; \ + t; \ +}) + +static void free_state(struct rib *rib); +static void copy_state(struct rnh *rnh, struct rib *rib); +static int compare_state(struct rib *r1, struct rib *r2); +static int send_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id); +static void print_rnh(struct route_node *rn, struct vty *vty); + +char * +rnh_str (struct rnh *rnh, char *buf, int size) +{ + prefix2str(&(rnh->node->p), buf, size); + return buf; +} + +struct rnh * +zebra_add_rnh (struct prefix *p, vrf_id_t vrfid) +{ + struct route_table *table; + struct route_node *rn; + struct rnh *rnh = NULL; + + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + prefix2str(p, buf, INET6_ADDRSTRLEN); + zlog_debug("add rnh %s in vrf %d", buf, vrfid); + } + table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); + if (!table) + { + zlog_debug("add_rnh: rnh table not found\n"); + return NULL; + } + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask (p); + + /* Lookup (or add) route node.*/ + rn = route_node_get (table, p); + + if (!rn->info) + { + rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); + rnh->client_list = list_new(); + route_lock_node (rn); + rn->info = rnh; + rnh->node = rn; + } + + route_unlock_node (rn); + return (rn->info); +} + +struct rnh * +zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid) +{ + struct route_table *table; + struct route_node *rn; + + table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); + if (!table) + return NULL; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask (p); + + /* Lookup route node.*/ + rn = route_node_lookup (table, p); + if (!rn) + return NULL; + + route_unlock_node (rn); + return (rn->info); +} + +void +zebra_delete_rnh (struct rnh *rnh) +{ + struct route_node *rn; + + if (!rnh || !(rn = rnh->node)) + return; + + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN)); + } + + list_free(rnh->client_list); + free_state(rnh->state); + XFREE(MTYPE_RNH, rn->info); + rn->info = NULL; + route_unlock_node (rn); + return; +} + +void +zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) +{ + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("client %s registers rnh %s", + zebra_route_string(client->proto), + rnh_str(rnh, buf, INET6_ADDRSTRLEN)); + } + if (!listnode_lookup(rnh->client_list, client)) + { + listnode_add(rnh->client_list, client); + send_client(rnh, client, vrf_id); + } +} + +void +zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) +{ + if (IS_ZEBRA_DEBUG_NHT) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("client %s unregisters rnh %s", + zebra_route_string(client->proto), + rnh_str(rnh, buf, INET6_ADDRSTRLEN)); + } + listnode_delete(rnh->client_list, client); + if (list_isempty(rnh->client_list)) + zebra_delete_rnh(rnh); +} + +int +zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) +{ + struct route_table *ptable; + struct route_table *ntable; + struct route_node *prn; + struct route_node *nrn; + struct rnh *rnh; + struct zserv *client; + struct listnode *node; + struct rib *rib; + + ntable = lookup_rnh_table(vrfid, family); + if (!ntable) + { + zlog_debug("evaluate_rnh_table: rnh table not found\n"); + return -1; + } + + ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid); + if (!ptable) + { + zlog_debug("evaluate_rnh_table: prefix table not found\n"); + return -1; + } + + for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + { + if (!nrn->info) + continue; + + prn = route_node_match(ptable, &nrn->p); + if (!prn) + rib = NULL; + else + { + RNODE_FOREACH_RIB(prn, rib) + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + break; + } + } + + rnh = nrn->info; + if (compare_state(rib, rnh->state)) + { + if (IS_ZEBRA_DEBUG_NHT) + { + char bufn[INET6_ADDRSTRLEN]; + char bufp[INET6_ADDRSTRLEN]; + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + if (prn) + prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); + else + strcpy(bufp, "null"); + zlog_debug("rnh %s resolved through route %s - sending " + "nexthop %s event to clients", bufn, bufp, + rib ? "reachable" : "unreachable"); + } + copy_state(rnh, rib); + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + send_client(rnh, client, vrfid); + } + } + return 1; +} + +int +zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client) +{ + struct route_table *ntable; + struct route_node *nrn; + struct rnh *rnh; + + ntable = lookup_rnh_table(vrfid, family); + if (!ntable) + { + zlog_debug("dispatch_rnh_table: rnh table not found\n"); + return -1; + } + + for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + { + if (!nrn->info) + continue; + + rnh = nrn->info; + if (IS_ZEBRA_DEBUG_NHT) + { + char bufn[INET6_ADDRSTRLEN]; + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn, + rnh->state ? "reachable" : "unreachable", + zebra_route_string(client->proto)); + } + send_client(rnh, client, vrfid); + } + return 1; +} + +void +zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty) +{ + struct route_table *table; + struct route_node *rn; + + table = lookup_rnh_table(vrfid, af); + if (!table) + { + zlog_debug("print_rnhs: rnh table not found\n"); + return; + } + + for (rn = route_top(table); rn; rn = route_next(rn)) + if (rn->info) + print_rnh(rn, vty); +} + +int +zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client) +{ + struct route_table *ntable; + struct route_node *nrn; + struct rnh *rnh; + + ntable = lookup_rnh_table(vrfid, family); + if (!ntable) + { + zlog_debug("cleanup_rnh_client: rnh table not found\n"); + return -1; + } + + for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + { + if (!nrn->info) + continue; + + rnh = nrn->info; + if (IS_ZEBRA_DEBUG_NHT) + { + char bufn[INET6_ADDRSTRLEN]; + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + zlog_debug("rnh %s - cleaning state for client %s", bufn, + zebra_route_string(client->proto)); + } + zebra_remove_rnh_client(rnh, client); + } + return 1; +} + +/** + * free_state - free up the rib structure associated with the rnh. + */ +static void +free_state (struct rib *rib) +{ + struct nexthop *nexthop, *next; + + if (!rib) + return; + + /* free RIB and nexthops */ + for (nexthop = rib->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + nexthop_free (nexthop); + } + XFREE (MTYPE_RIB, rib); +} + +/** + * copy_nexthop - copy a nexthop to the rib structure. + */ +static void +rib_copy_nexthop (struct rib *state, struct nexthop *nh) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->flags = nh->flags; + nexthop->type = nh->type; + nexthop->ifindex = nh->ifindex; + if (nh->ifname) + nexthop->ifname = XSTRDUP(0, nh->ifname); + memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); + memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); + + rib_nexthop_add(state, nexthop); +} + +static void +copy_state (struct rnh *rnh, struct rib *rib) +{ + struct rib *state; + struct nexthop *nh; + + if (rnh->state) + { + free_state(rnh->state); + rnh->state = NULL; + } + + if (!rib) + return; + + state = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + state->type = rib->type; + state->metric = rib->metric; + + for (nh = rib->nexthop; nh; nh = nh->next) + rib_copy_nexthop(state, nh); + rnh->state = state; +} + +static int +compare_state (struct rib *r1, struct rib *r2) +{ + struct nexthop *nh1; + struct nexthop *nh2; + u_char found_nh = 0; + + if (!r1 && !r2) + return 0; + + if ((!r1 && r2) || (r1 && !r2)) + return 1; + + if (r1->metric != r2->metric) + return 1; + + if (r1->nexthop_num != r2->nexthop_num) + return 1; + + /* We need to verify that the nexthops for r1 match the nexthops for r2. + * Since it is possible for a rib entry to have the same nexthop multiple + * times (Example: [a,a]) we need to keep track of which r2 nexthops we have + * already used as a match against a r1 nexthop. We track this + * via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you + * are finished. + * + * TRUE: r1 [a,b], r2 [a,b] + * TRUE: r1 [a,b], r2 [b,a] + * FALSE: r1 [a,b], r2 [a,c] + * FALSE: r1 [a,a], r2 [a,b] + */ + for (nh1 = r1->nexthop; nh1; nh1 = nh1->next) + { + found_nh = 0; + for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) + { + if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) + continue; + + if (nexthop_same_no_recurse(nh1, nh2)) + { + SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); + found_nh = 1; + break; + } + } + + if (!found_nh) + { + for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) + if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) + UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); + return 1; + } + } + + for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) + if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) + UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); + + return 0; +} + +static int +send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + struct route_node *rn; + + rn = rnh->node; + rib = rnh->state; + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id); + + stream_putw(s, rn->p.family); + stream_put_prefix (s, &rn->p); + + if (rib) + { + stream_putl (s, rib->metric); + num = 0; + nump = stream_get_endp(s); + stream_putc (s, 0); + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + case ZEBRA_NEXTHOP_IPV4_IFNAME: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; +#ifdef HAVE_IPV6 + case ZEBRA_NEXTHOP_IPV6: + stream_put (s, &nexthop->gate.ipv6, 16); + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + stream_put (s, &nexthop->gate.ipv6, 16); + stream_putl (s, nexthop->ifindex); + break; +#endif /* HAVE_IPV6 */ + default: + /* do nothing */ + break; + } + num++; + } + stream_putc_at (s, nump, num); + } + else + { + stream_putl (s, 0); + stream_putc (s, 0); + } + stream_putw_at (s, 0, stream_get_endp (s)); + return zebra_server_send_message(client); +} + +static void +print_nh (struct nexthop *nexthop, struct vty *vty) +{ + char buf[BUFSIZ]; + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " %s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + vty_out (vty, ", %s", nexthop->ifname); + else if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " is directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " is directly connected, Null0"); + break; + default: + break; + } + vty_out(vty, "%s", VTY_NEWLINE); +} + +static void +print_rnh (struct route_node *rn, struct vty *vty) +{ + struct rnh *rnh; + struct nexthop *nexthop; + struct listnode *node; + struct zserv *client; + char buf[BUFSIZ]; + + rnh = rn->info; + vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), + VTY_NEWLINE); + if (rnh->state) + { + vty_out(vty, " resolved via %s%s", + zebra_route_string(rnh->state->type), VTY_NEWLINE); + for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next) + print_nh(nexthop, vty); + } + else + vty_out(vty, " unresolved%s", VTY_NEWLINE); + + vty_out(vty, " Client list:"); + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto), + client->sock); + vty_out(vty, "%s", VTY_NEWLINE); +} diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h new file mode 100644 index 000000000..97dbba70d --- /dev/null +++ b/zebra/zebra_rnh.h @@ -0,0 +1,48 @@ +/* + * Zebra next hop tracking header + * Copyright (C) 2013 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RNH_H +#define _ZEBRA_RNH_H + +#include "prefix.h" +#include "vty.h" + +/* Nexthop structure. */ +struct rnh +{ + u_char flags; + struct rib *state; + struct list *client_list; + struct route_node *node; +}; + +extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid); +extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid); +extern void zebra_delete_rnh(struct rnh *rnh); +extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id_t); +extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); +extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family); +extern int zebra_dispatch_rnh_table(vrf_id_t vrfid, int family, struct zserv *cl); +extern void zebra_print_rnh_table(vrf_id_t vrfid, int family, struct vty *vty); +extern char *rnh_str(struct rnh *rnh, char *buf, int size); +extern int zebra_cleanup_rnh_client(vrf_id_t vrf, int family, struct zserv *client); +#endif /*_ZEBRA_RNH_H */ diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c new file mode 100644 index 000000000..664667dd2 --- /dev/null +++ b/zebra/zebra_rnh_null.c @@ -0,0 +1,10 @@ +#include +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" + +int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) +{ return 0; } + +void zebra_print_rnh_table (vrf_id_t vrfid, int family, struct vty *vty) +{} diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 49feccd06..bf7e335e5 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -29,6 +29,7 @@ #include "filter.h" #include "plist.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 23660d7dc..e3ef963d4 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -28,8 +28,10 @@ #include "table.h" #include "rib.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id); static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, @@ -1610,6 +1612,28 @@ ALIAS (show_ip_route, "IP routing table\n" VRF_CMD_HELP_STR) +DEFUN (show_ip_nht, + show_ip_nht_cmd, + "show ip nht", + SHOW_STR + IP_STR + "IP nexthop tracking table\n") +{ + zebra_print_rnh_table(0, AF_INET, vty); + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_nht, + show_ipv6_nht_cmd, + "show ipv6 nht", + SHOW_STR + IP_STR + "IPv6 nexthop tracking table\n") +{ + zebra_print_rnh_table(0, AF_INET6, vty); + return CMD_SUCCESS; +} + DEFUN (show_ip_route_prefix_longer, show_ip_route_prefix_longer_cmd, "show ip route A.B.C.D/M longer-prefixes", @@ -3880,6 +3904,8 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd); install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_nht_cmd); + install_element (VIEW_NODE, &show_ipv6_nht_cmd); install_element (VIEW_NODE, &show_ip_route_addr_cmd); install_element (VIEW_NODE, &show_ip_route_prefix_cmd); install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd); diff --git a/zebra/zserv.c b/zebra/zserv.c index 86f141b32..6e65aa157 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -37,12 +37,14 @@ #include "network.h" #include "buffer.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" +#include "zebra/zebra_rnh.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -102,7 +104,7 @@ zserv_flush_data(struct thread *thread) return 0; } -static int +int zebra_server_send_message(struct zserv *client) { if (client->t_suicide) @@ -131,7 +133,7 @@ zebra_server_send_message(struct zserv *client) return 0; } -static void +void zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id) { /* length placeholder, caller can update */ @@ -717,6 +719,65 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, return zebra_server_send_message(client); } +/* Nexthop register */ +static int +zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t vrf_id) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("nexthop_register msg from client %s: length=%d\n", + zebra_route_string(client->proto), length); + + s = client->ibuf; + + while (l < length) + { + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + l += 3; + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + rnh = zebra_add_rnh(&p, 0); + zebra_add_rnh_client(rnh, client, vrf_id); + } + zebra_evaluate_rnh_table(0, AF_INET); + zebra_evaluate_rnh_table(0, AF_INET6); + return 0; +} + +/* Nexthop register */ +static int +zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("nexthop_unregister msg from client %s: length=%d\n", + zebra_route_string(client->proto), length); + + s = client->ibuf; + + while (l < length) + { + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + l += 3; + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + rnh = zebra_lookup_rnh(&p, 0); + if (rnh) + zebra_remove_rnh_client(rnh, client); + } + return 0; +} + static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, vrf_id_t vrf_id) @@ -907,7 +968,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); break; case ZEBRA_NEXTHOP_IFNAME: ifname_len = stream_getc (s); @@ -915,18 +976,18 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); - nexthop_ipv4_add (rib, &nexthop, NULL); + rib_nexthop_ipv4_add (rib, &nexthop, NULL); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); - nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; case ZEBRA_NEXTHOP_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; } } @@ -1150,14 +1211,14 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) { if ((i < if_count) && ifindices[i]) - nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); + rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); else - nexthop_ipv6_add (rib, &nexthops[i]); + rib_nexthop_ipv6_add (rib, &nexthops[i]); } else { if ((i < if_count) && ifindices[i]) - nexthop_ifindex_add (rib, ifindices[i]); + rib_nexthop_ifindex_add (rib, ifindices[i]); } } } @@ -1306,6 +1367,7 @@ zread_hello (struct zserv *client) client->sock); route_type_oaths[proto] = client->sock; + client->proto = proto; } } @@ -1346,6 +1408,9 @@ zebra_score_rib (int client_sock) static void zebra_client_close (struct zserv *client) { + zebra_cleanup_rnh_client(0, AF_INET, client); + zebra_cleanup_rnh_client(0, AF_INET6, client); + /* Close file descriptor. */ if (client->sock) { @@ -1573,6 +1638,11 @@ zebra_client_read (struct thread *thread) break; case ZEBRA_VRF_UNREGISTER: zread_vrf_unregister (client, length, vrf_id); + case ZEBRA_NEXTHOP_REGISTER: + zserv_nexthop_register(client, sock, length, vrf_id); + break; + case ZEBRA_NEXTHOP_UNREGISTER: + zserv_nexthop_unregister(client, sock, length); break; default: zlog_info ("Zebra received unknown command %d", command); @@ -1848,8 +1918,10 @@ DEFUN (show_zebra_client, struct zserv *client; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE); - + vty_out (vty, "Client %s fd %d%s", + zebra_route_string(client->proto), client->sock, + VTY_NEWLINE); + return CMD_SUCCESS; } diff --git a/zebra/zserv.h b/zebra/zserv.h index 9d65998ed..7a2b4a1d1 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -67,6 +67,9 @@ struct zserv /* Router-id information. */ vrf_bitmap_t ridinfo; + + /* client's protocol */ + u_char proto; }; /* Zebra instance */ @@ -112,4 +115,7 @@ extern int zsend_interface_link_params (struct zserv *, struct interface *); extern pid_t pid; +extern void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t); +extern int zebra_server_send_message(struct zserv *client); + #endif /* _ZEBRA_ZEBRA_H */ From 94627e670d661f95217521ef0bfba141e5e37e68 Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Mon, 9 Nov 2015 20:21:45 -0500 Subject: [PATCH 1095/1342] bgpd: Add a null check in bgp_address_del() function when connected addresses are removed. When you flap an interface repeatedly, you can get into situations where the code has not quite finished cleaning up before the next event happens. Gracefully prevent a NULL dereference. Signed-off-by: Pradosh Mohapatra --- bgpd/bgp_nexthop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index badada7dd..b69ed6f76 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -582,6 +582,9 @@ bgp_address_add (struct prefix *p) tmp.addr = p->u.prefix4; addr = hash_get (bgp_address_hash, &tmp, bgp_address_hash_alloc); + if (!addr) + return; + addr->refcnt++; } From 0f2f7a3fa5d55e682d0739d586da021cbd43bc3c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 16 Jun 2016 15:40:02 +0100 Subject: [PATCH 1096/1342] *: Fix duplicate commands from view/enable node consolidation --- bgpd/bgp_filter.c | 2 -- bgpd/bgp_mplsvpn.c | 18 ------------------ bgpd/bgp_nexthop.c | 4 ---- bgpd/bgp_route.c | 4 ---- bgpd/bgp_vty.c | 14 -------------- isisd/isis_spf.c | 4 ---- isisd/isis_te.c | 2 -- lib/vty.c | 10 ++++------ ospf6d/ospf6d.c | 37 ------------------------------------- ospfd/ospf_ri.c | 2 -- zebra/debug.c | 1 - 11 files changed, 4 insertions(+), 94 deletions(-) diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 26819fc15..ab1e504d6 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -691,8 +691,6 @@ bgp_filter_init (void) install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd); install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd); - install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd); - install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd); } void diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 08a4272d6..047105d79 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1062,22 +1062,4 @@ bgp_mplsvpn_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); - - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd); - - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_tags_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_neighbor_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); } diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index b69ed6f76..434b2cdad 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1506,10 +1506,6 @@ bgp_scan_init (void) install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd); install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_nexthop_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_nexthop_detail_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd); } void diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 051dc8383..d3f127079 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -16639,7 +16639,6 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); - install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); @@ -16653,9 +16652,6 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); - - install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); - install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); } void diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0b3262551..32d1ea0dc 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11057,8 +11057,6 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); - install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); /* "show ip bgp rsclient" commands. */ install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); @@ -11071,8 +11069,6 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); - install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); - install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); @@ -11125,9 +11121,6 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_views_cmd); install_element (RESTRICTED_NODE, &show_bgp_views_cmd); - /* "show bgp views" commands. */ - install_element (VIEW_NODE, &show_bgp_views_cmd); - /* non afi/safi forms of commands */ install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); @@ -11161,8 +11154,6 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); - install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); @@ -11173,7 +11164,6 @@ bgp_vty_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); - install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); /* Community-list. */ @@ -12033,8 +12023,6 @@ community_list_vty (void) install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_community_list_cmd); install_element (VIEW_NODE, &show_ip_community_list_arg_cmd); - install_element (ENABLE_NODE, &show_ip_community_list_cmd); - install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd); /* Extcommunity-list. */ install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd); @@ -12053,6 +12041,4 @@ community_list_vty (void) install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); - install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd); - install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd); } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 0657c1c81..6b2456f9f 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1692,8 +1692,4 @@ isis_spf_cmds_init () install_element (VIEW_NODE, &show_isis_topology_cmd); install_element (VIEW_NODE, &show_isis_topology_l1_cmd); install_element (VIEW_NODE, &show_isis_topology_l2_cmd); - - install_element (ENABLE_NODE, &show_isis_topology_cmd); - install_element (ENABLE_NODE, &show_isis_topology_l1_cmd); - install_element (ENABLE_NODE, &show_isis_topology_l2_cmd); } diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 814a8e858..6cb855143 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -1358,8 +1358,6 @@ isis_mpls_te_init (void) /* Register new VTY commands */ install_element (VIEW_NODE, &show_isis_mpls_te_router_cmd); install_element (VIEW_NODE, &show_isis_mpls_te_interface_cmd); - install_element (ENABLE_NODE, &show_isis_mpls_te_router_cmd); - install_element (ENABLE_NODE, &show_isis_mpls_te_interface_cmd); install_element (ISIS_NODE, &isis_mpls_te_on_cmd); install_element (ISIS_NODE, &no_isis_mpls_te_on_cmd); diff --git a/lib/vty.c b/lib/vty.c index bf259fc4b..7ba277fd8 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2668,8 +2668,8 @@ vty_event (enum event event, int sock, struct vty *vty) } } -DEFUN (config_who, - config_who_cmd, +DEFUN (who, + who_cmd, "who", "Display who is on vty\n") { @@ -3098,11 +3098,10 @@ vty_init (struct thread_master *master_thread) /* Install bgp top node. */ install_node (&vty_node, vty_config_write); - install_element (RESTRICTED_NODE, &config_who_cmd); + install_element (RESTRICTED_NODE, &who_cmd); install_element (RESTRICTED_NODE, &show_history_cmd); - install_element (VIEW_NODE, &config_who_cmd); + install_element (VIEW_NODE, &who_cmd); install_element (VIEW_NODE, &show_history_cmd); - install_element (ENABLE_NODE, &config_who_cmd); install_element (CONFIG_NODE, &line_vty_cmd); install_element (CONFIG_NODE, &service_advanced_vty_cmd); install_element (CONFIG_NODE, &no_service_advanced_vty_cmd); @@ -3111,7 +3110,6 @@ vty_init (struct thread_master *master_thread) install_element (ENABLE_NODE, &terminal_monitor_cmd); install_element (ENABLE_NODE, &terminal_no_monitor_cmd); install_element (ENABLE_NODE, &no_terminal_monitor_cmd); - install_element (ENABLE_NODE, &show_history_cmd); install_default (VTY_NODE); install_element (VTY_NODE, &exec_timeout_min_cmd); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index bfcc242a8..fa84d0a57 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1840,43 +1840,6 @@ ospf6_init (void) INSTALL (VIEW, database_type_self_originated_linkstate_id_cmd); INSTALL (VIEW, database_type_self_originated_linkstate_id_detail_cmd); - INSTALL (ENABLE, database_cmd); - INSTALL (ENABLE, database_detail_cmd); - INSTALL (ENABLE, database_type_cmd); - INSTALL (ENABLE, database_type_detail_cmd); - INSTALL (ENABLE, database_id_cmd); - INSTALL (ENABLE, database_id_detail_cmd); - INSTALL (ENABLE, database_linkstate_id_cmd); - INSTALL (ENABLE, database_linkstate_id_detail_cmd); - INSTALL (ENABLE, database_router_cmd); - INSTALL (ENABLE, database_router_detail_cmd); - INSTALL (ENABLE, database_adv_router_cmd); - INSTALL (ENABLE, database_adv_router_detail_cmd); - INSTALL (ENABLE, database_type_id_cmd); - INSTALL (ENABLE, database_type_id_detail_cmd); - INSTALL (ENABLE, database_type_linkstate_id_cmd); - INSTALL (ENABLE, database_type_linkstate_id_detail_cmd); - INSTALL (ENABLE, database_type_router_cmd); - INSTALL (ENABLE, database_type_router_detail_cmd); - INSTALL (ENABLE, database_type_adv_router_cmd); - INSTALL (ENABLE, database_type_adv_router_detail_cmd); - INSTALL (ENABLE, database_adv_router_linkstate_id_cmd); - INSTALL (ENABLE, database_adv_router_linkstate_id_detail_cmd); - INSTALL (ENABLE, database_id_router_cmd); - INSTALL (ENABLE, database_id_router_detail_cmd); - INSTALL (ENABLE, database_type_id_router_cmd); - INSTALL (ENABLE, database_type_id_router_detail_cmd); - INSTALL (ENABLE, database_type_adv_router_linkstate_id_cmd); - INSTALL (ENABLE, database_type_adv_router_linkstate_id_detail_cmd); - INSTALL (ENABLE, database_self_originated_cmd); - INSTALL (ENABLE, database_self_originated_detail_cmd); - INSTALL (ENABLE, database_type_self_originated_cmd); - INSTALL (ENABLE, database_type_self_originated_detail_cmd); - INSTALL (ENABLE, database_type_id_self_originated_cmd); - INSTALL (ENABLE, database_type_id_self_originated_detail_cmd); - INSTALL (ENABLE, database_type_self_originated_linkstate_id_cmd); - INSTALL (ENABLE, database_type_self_originated_linkstate_id_detail_cmd); - /* Make ospf protocol socket. */ ospf6_serv_sock (); thread_add_read (master, ospf6_receive, NULL, ospf6_sock); diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 5b1032b0c..f093208e9 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -1621,8 +1621,6 @@ ospf_router_info_register_vty (void) { install_element (VIEW_NODE, &show_ip_ospf_router_info_cmd); install_element (VIEW_NODE, &show_ip_ospf_router_info_pce_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_router_info_cmd); - install_element (ENABLE_NODE, &show_ip_ospf_router_info_pce_cmd); install_element (OSPF_NODE, &router_info_area_cmd); install_element (OSPF_NODE, &router_info_as_cmd); diff --git a/zebra/debug.c b/zebra/debug.c index fbeef52b6..5dd38f00d 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -377,7 +377,6 @@ zebra_debug_init (void) install_element (VIEW_NODE, &show_debugging_zebra_cmd); - install_element (ENABLE_NODE, &show_debugging_zebra_cmd); install_element (ENABLE_NODE, &debug_zebra_events_cmd); install_element (ENABLE_NODE, &debug_zebra_nht_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_cmd); From a4f40293db1055387d5b901fe0dbb556226b2024 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 9 Nov 2015 20:21:46 -0500 Subject: [PATCH 1097/1342] vtysh: Make ipv6 unicast/multicast address-family work In the absence of this patch, attempting to type "address-family ipv6 unicast" would result in an "Ambiguous command" error and in the case of "address-family ipv6 multicast", the command would silently fail, without the prompt dropping into the address-family mode. The cause is how the parse tree is constructed for ipv6 address family. There was an error in extract.pl.in script and in vtysh.c files which assumed that there was only address family ipv6 command, without unicast or multicast and so the command was failing. Signed-off-by: vivek --- vtysh/extract.pl.in | 2 +- vtysh/vtysh.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 786493a6a..480d114d8 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -46,7 +46,7 @@ $ignore{'"router zebra"'} = "ignore"; $ignore{'"address-family ipv4"'} = "ignore"; $ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family ipv6"'} = "ignore"; -$ignore{'"address-family ipv6 unicast"'} = "ignore"; +$ignore{'"address-family ipv6 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index fe86083e2..ad1657f79 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2564,6 +2564,7 @@ vtysh_init_vty (void) #ifdef HAVE_IPV6 install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_unicast_cmd); + install_element (BGP_NODE, &address_family_ipv6_multicast_cmd); #endif install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); From af309fa58f41457eed226d6650d0b780c053c4d8 Mon Sep 17 00:00:00 2001 From: Pradosh Mohapatra Date: Mon, 9 Nov 2015 20:21:47 -0500 Subject: [PATCH 1098/1342] bgpd: Show more meaningful outq value in 'show ip bgp summary' output. 'outq' field in 'show ip bgp sum' displays the number of formatted packets to a peer. Since the route announcement follows an input-buffered pattern (i.e. adj-rib-out is a separate queue of routes per peer and packets are formatted from the routes at the time of TCP write), the outq field doesn't show any interesting data worth watching. The patch is to display the adj-rib-out queue depth instead. signed-off-by: pmohapat@cumulusnetworks.com reviewed-by: dwalton@cumulusnetworks.com --- bgpd/bgp_advertise.c | 16 ++++++++++------ bgpd/bgp_advertise.h | 26 ++++++++++++++++++++++++++ bgpd/bgp_vty.c | 6 ++++-- lib/fifo.h | 1 + 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index ecf531f73..1b17b66f3 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -186,10 +186,12 @@ bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, struct bgp_advertise *adv; struct bgp_advertise_attr *baa; struct bgp_advertise *next; + struct bgp_advertise_fifo *fhead; adv = adj->adv; baa = adv->baa; next = NULL; + fhead = (struct bgp_advertise_fifo *)&peer->sync[afi][safi]->withdraw; if (baa) { @@ -201,10 +203,12 @@ bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, /* Unintern BGP advertise attribute. */ bgp_advertise_unintern (peer->hash[afi][safi], baa); + + fhead = (struct bgp_advertise_fifo *)&peer->sync[afi][safi]->update; } /* Unlink myself from advertisement FIFO. */ - FIFO_DEL (adv); + BGP_ADV_FIFO_DEL (fhead, adv); /* Free memory. */ bgp_advertise_free (adj->adv); @@ -264,7 +268,7 @@ bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, /* Add new advertisement to advertisement attribute list. */ bgp_advertise_add (adv->baa, adv); - FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); + BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); } void @@ -298,7 +302,7 @@ bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, adv->adj = adj; /* Add to synchronization entry for withdraw announcement. */ - FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); + BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); /* Schedule packet write. */ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); @@ -391,9 +395,9 @@ bgp_sync_init (struct peer *peer) { sync = XCALLOC (MTYPE_BGP_SYNCHRONISE, sizeof (struct bgp_synchronize)); - FIFO_INIT (&sync->update); - FIFO_INIT (&sync->withdraw); - FIFO_INIT (&sync->withdraw_low); + BGP_ADV_FIFO_INIT (&sync->update); + BGP_ADV_FIFO_INIT (&sync->withdraw); + BGP_ADV_FIFO_INIT (&sync->withdraw_low); peer->sync[afi][safi] = sync; peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); } diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 51ba62679..e2857a3bf 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -23,6 +23,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include +/* BGP advertise FIFO. */ +struct bgp_advertise_fifo +{ + struct bgp_advertise *next; + struct bgp_advertise *prev; + u_int32_t count; +}; + /* BGP advertise attribute. */ struct bgp_advertise_attr { @@ -124,6 +132,24 @@ struct bgp_synchronize #define BGP_ADJ_OUT_ADD(N,A) BGP_INFO_ADD(N,A,adj_out) #define BGP_ADJ_OUT_DEL(N,A) BGP_INFO_DEL(N,A,adj_out) +#define BGP_ADV_FIFO_ADD(F, N) \ + do { \ + FIFO_ADD((F), (N)); \ + (F)->count++; \ + } while (0) + +#define BGP_ADV_FIFO_DEL(F, N) \ + do { \ + FIFO_DEL((N)); \ + (F)->count--; \ + } while (0) + +#define BGP_ADV_FIFO_INIT(F) \ + do { \ + FIFO_INIT((F)); \ + (F)->count = 0; \ + } while (0) + /* Prototypes. */ extern void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *, struct attr *, afi_t, safi_t, struct bgp_info *); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 32d1ea0dc..cd3d9a0d0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7352,14 +7352,16 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) vty_out (vty, "4 "); - vty_out (vty, "%5u %7d %7d %8d %4d %4lu ", + vty_out (vty, "%5u %7d %7d %8d %4d %4d ", peer->as, peer->open_in + peer->update_in + peer->keepalive_in + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in, peer->open_out + peer->update_out + peer->keepalive_out + peer->notify_out + peer->refresh_out + peer->dynamic_cap_out, - 0, 0, (unsigned long) peer->obuf->count); + 0, 0, + peer->sync[afi][safi]->update.count + + peer->sync[afi][safi]->withdraw.count); vty_out (vty, "%8s", peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); diff --git a/lib/fifo.h b/lib/fifo.h index 6be75b761..47a1e888e 100644 --- a/lib/fifo.h +++ b/lib/fifo.h @@ -25,6 +25,7 @@ struct fifo { struct fifo *next; struct fifo *prev; + u_int32_t count; }; #define FIFO_INIT(F) \ From 5cf768a3f53029ecc482367a1ceaf7578237b06a Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Mon, 9 Nov 2015 20:21:53 -0500 Subject: [PATCH 1099/1342] bgpd: Support matching on local preference in route-map This patch adds support for matching on local preference in BGP route-map. Signed-off-by: Dinesh Dutt --- bgpd/bgp_routemap.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ doc/routemap.texi | 4 ++ 2 files changed, 107 insertions(+) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 8d3a8f560..a9b6b5025 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -72,6 +72,7 @@ o Cisco route-map metric : Done route-type : (This will not be implemented by bgpd) tag : (This will not be implemented by bgpd) + local-preference : Done set as-path prepend : Done as-path tag : Not yet @@ -613,6 +614,72 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = route_match_ip_route_source_prefix_list_free }; +/* `match local-preference LOCAL-PREF' */ + +/* Match function return 1 if match is success else return zero. */ +static route_map_result_t +route_match_local_pref (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *local_pref; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + local_pref = rule; + bgp_info = object; + + if (bgp_info->attr->local_pref == *local_pref) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match local-preference' match statement. + `arg' is local-pref value */ +static void * +route_match_local_pref_compile (const char *arg) +{ + u_int32_t *local_pref; + char *endptr = NULL; + unsigned long tmpval; + + /* Locpref value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + errno = 0; + tmpval = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || errno || tmpval > UINT32_MAX) + return NULL; + + local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + + if (!local_pref) + return local_pref; + + *local_pref = tmpval; + return local_pref; +} + +/* Free route map's compiled `match local-preference' value. */ +static void +route_match_local_pref_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_local_pref_cmd = +{ + "local-preference", + route_match_local_pref, + route_match_local_pref_compile, + route_match_local_pref_free +}; + /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ @@ -2733,6 +2800,37 @@ ALIAS (no_match_metric, "Match metric of route\n" "Metric value\n") +DEFUN (match_local_pref, + match_local_pref_cmd, + "match local-preference <0-4294967295>", + MATCH_STR + "Match local-preference of route\n" + "Metric value\n") +{ + return bgp_route_match_add (vty, vty->index, "local-preference", argv[0]); +} + +DEFUN (no_match_local_pref, + no_match_local_pref_cmd, + "no match local-preference", + NO_STR + MATCH_STR + "Match local preference of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "local-preference", NULL); + + return bgp_route_match_delete (vty, vty->index, "local-preference", argv[0]); +} + +ALIAS (no_match_local_pref, + no_match_local_pref_val_cmd, + "no match local-preference <0-4294967295>", + NO_STR + MATCH_STR + "Match local preference of route\n" + "Local preference value\n") + DEFUN (match_community, match_community_cmd, "match community (<1-99>|<100-500>|WORD)", @@ -3867,6 +3965,7 @@ bgp_route_map_init (void) route_map_delete_hook (bgp_route_map_update); route_map_install_match (&route_match_peer_cmd); + route_map_install_match (&route_match_local_pref_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_route_source_cmd); @@ -3876,6 +3975,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_aspath_cmd); route_map_install_match (&route_match_community_cmd); route_map_install_match (&route_match_ecommunity_cmd); + route_map_install_match (&route_match_local_pref_cmd); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); route_map_install_match (&route_match_probability_cmd); @@ -3926,6 +4026,9 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_val_cmd); + install_element (RMAP_NODE, &match_local_pref_cmd); + install_element (RMAP_NODE, &no_match_local_pref_cmd); + install_element (RMAP_NODE, &no_match_local_pref_val_cmd); install_element (RMAP_NODE, &match_community_cmd); install_element (RMAP_NODE, &match_community_exact_cmd); install_element (RMAP_NODE, &no_match_community_cmd); diff --git a/doc/routemap.texi b/doc/routemap.texi index 7938c965f..b3ef7ca76 100644 --- a/doc/routemap.texi +++ b/doc/routemap.texi @@ -151,6 +151,10 @@ Matches the specified @var{as_path}. Matches the specified @var{metric}. @end deffn +@deffn {Route-map Command} {match local-preference @var{metric}} {} +Matches the specified @var{local-preference}. +@end deffn + @deffn {Route-map Command} {match community @var{community_list}} {} Matches the specified @var{community_list} @end deffn From 083e5e2d7bc8098b92572792ab807da381db95ea Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Mon, 9 Nov 2015 20:21:54 -0500 Subject: [PATCH 1100/1342] bgpd, doc: Allow route-map policy modifications to also affect route reflectors. By default, attribute modification via route-map policy out is ignored on reflected routes. This patch provides an option to allow this modification to occur. Once enabled, it affects all reflected routes. Signed-off-by: Dinesh G Dutt --- bgpd/bgp_route.c | 6 ++-- bgpd/bgp_vty.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgpd.c | 4 +++ bgpd/bgpd.h | 3 +- doc/bgpd.texi | 6 ++++ 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d3f127079..e5224dc5a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1078,9 +1078,9 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, info.attr = attr; /* The route reflector is not allowed to modify the attributes - of the reflected IBGP routes. */ - if (from->sort == BGP_PEER_IBGP - && peer->sort == BGP_PEER_IBGP) + of the reflected IBGP routes, unless configured to allow it */ + if ((from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) && + !bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { bgp_attr_dup (&dummy_attr, attr); info.attr = &dummy_attr; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cd3d9a0d0..4cd8c5ea7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1527,6 +1527,80 @@ ALIAS (no_bgp_default_local_preference, "local preference (higher=more preferred)\n" "Configure default local preference value\n") +static void +peer_announce_routes_if_rmap_out (struct bgp *bgp) +{ + struct peer *peer; + struct listnode *node, *nnode; + struct bgp_filter *filter; + afi_t afi; + safi_t safi; + + /* Reannounce all routes to appropriate neighbors */ + for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + { + /* check if there's an out route-map on this client */ + filter = &peer->filter[afi][safi]; + if (ROUTE_MAP_OUT_NAME(filter)) + { + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: Announcing routes again for peer %s" + "(afi=%d, safi=%d", __func__, peer->host, afi, + safi); + + bgp_announce_route_all(peer); + } + } + } + } +} + +DEFUN (bgp_rr_allow_outbound_policy, + bgp_rr_allow_outbound_policy_cmd, + "bgp route-reflector allow-outbound-policy", + "BGP specific commands\n" + "Allow modifications made by out route-map\n" + "on ibgp neighbors\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + if (!bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) + { + bgp_flag_set(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY); + peer_announce_routes_if_rmap_out(bgp); + } + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_rr_allow_outbound_policy, + no_bgp_rr_allow_outbound_policy_cmd, + "no bgp route-reflector allow-outbound-policy", + NO_STR + "BGP specific commands\n" + "Allow modifications made by out route-map\n" + "on ibgp neighbors\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) + { + bgp_flag_unset(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY); + peer_announce_routes_if_rmap_out(bgp); + } + + return CMD_SUCCESS; +} + static int peer_remote_as_vty (struct vty *vty, const char *peer_str, const char *as_str, afi_t afi, safi_t safi) @@ -10006,6 +10080,10 @@ bgp_vty_init (void) install_element (BGP_NODE, &no_bgp_default_local_preference_cmd); install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd); + /* bgp ibgp-allow-policy-mods command */ + install_element (BGP_NODE, &bgp_rr_allow_outbound_policy_cmd); + install_element (BGP_NODE, &no_bgp_rr_allow_outbound_policy_cmd); + /* "neighbor remote-as" commands. */ install_element (BGP_NODE, &neighbor_remote_as_cmd); install_element (BGP_NODE, &no_neighbor_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index db952c7fc..7f472c595 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5528,6 +5528,10 @@ bgp_config_write (struct vty *vty) if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE); } + if (bgp_flag_check (bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { + vty_out (vty, " bgp route-reflector allow-outbound-policy%s", + VTY_NEWLINE); + } if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)) vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a6ced5b8e..7bd5a7804 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -107,7 +107,7 @@ struct bgp struct thread *t_startup; /* BGP flags. */ - u_int16_t flags; + u_int32_t flags; #define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0) #define BGP_FLAG_DETERMINISTIC_MED (1 << 1) #define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2) @@ -124,6 +124,7 @@ struct bgp #define BGP_FLAG_ASPATH_CONFED (1 << 13) #define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14) #define BGP_FLAG_DELETING (1 << 15) +#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 16) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 5735111d0..d5aa30c4a 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -753,6 +753,12 @@ Apply a route-map on the neighbor. @var{direct} must be @code{in} or @code{out}. @end deffn +@deffn {BGP} {bgp route-reflector allow-outbound-policy} {} +By default, attribute modification via route-map policy out is not reflected +on reflected routes. This option allows the modifications to be reflected as +well. Once enabled, it affects all reflected routes. +@end deffn + @c ----------------------------------------------------------------------- @node BGP Peer Group @section BGP Peer Group From 92992c69afd0095b183a3b905598d194115b27a7 Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 9 Nov 2015 20:21:57 -0500 Subject: [PATCH 1101/1342] zebra: Dissallow outside programs to delete Quagga routes Do not allow a program outside Quagga to delete a Quagga route from the kernel. To delete a Quagga route, do it inside Quagga. Signed-off-by: James Li --- zebra/rt_netlink.c | 9 ++++++--- zebra/zebra_rib.c | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 105e55938..1a9142666 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -908,6 +908,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; + u_char zebra_flags = 0; char anyaddr[16] = { 0 }; @@ -965,6 +966,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE) return 0; + if (rtm->rtm_protocol == RTPROT_ZEBRA) + SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE); if (rtm->rtm_src_len != 0) { @@ -1084,8 +1087,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, } } else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, - SAFI_UNICAST); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, + index, vrf_id, SAFI_UNICAST); } #ifdef HAVE_IPV6 @@ -1109,7 +1112,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, 0, mtu, 0, SAFI_UNICAST); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, index, vrf_id, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0aa516cd9..a55d358d3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2079,14 +2079,19 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, kernel. */ if (! same) { - if (fib && type == ZEBRA_ROUTE_KERNEL) - { - /* Unset flags. */ - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); - } + if (fib && type == ZEBRA_ROUTE_KERNEL && + CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + zlog_debug ("Zebra route %s/%d was deleted by others from kernel", + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), + p->prefixlen); + } + /* This means someone else, other than Zebra, has deleted + * a Zebra router from the kernel. We will add it back */ + rib_update_kernel(rn, NULL, fib); + } else { if (IS_ZEBRA_DEBUG_KERNEL) @@ -2738,14 +2743,19 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, kernel. */ if (! same) { - if (fib && type == ZEBRA_ROUTE_KERNEL) - { - /* Unset flags. */ - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - - UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); - } + if (fib && type == ZEBRA_ROUTE_KERNEL && + CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + zlog_debug ("Zebra route %s/%d was deleted by others from kernel", + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), + p->prefixlen); + } + /* This means someone else, other than Zebra, has deleted a Zebra + * route from the kernel. We will add it back */ + rib_update_kernel(rn, NULL, fib); + } else { if (IS_ZEBRA_DEBUG_KERNEL) From 62f936e7960a7c08f4ae42ad43726d8d6e8e949d Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Mon, 9 Nov 2015 20:21:59 -0500 Subject: [PATCH 1102/1342] ospf6d, ripd, vtysh: Fix "no set metric" for ospf6 and RIP Allow the user to actually turn off the set metric command in ospf6d and rip. Signed-off-by: Daniel Walton --- ospf6d/ospf6_asbr.c | 26 ++++++++++++++++++++------ ripd/rip_routemap.c | 12 ++++++++++-- vtysh/extract.pl.in | 4 ++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index c3c06edc2..6db1ca963 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1089,17 +1089,30 @@ DEFUN (set_metric, /* delete "set metric" */ DEFUN (no_set_metric, no_set_metric_cmd, - "no set metric <0-4294967295>", + "no set metric", NO_STR - "Set value\n" - "Metric\n" - "METRIC value\n") + SET_STR + "Metric value for destination routing protocol\n") { - int ret = route_map_delete_set ((struct route_map_index *) vty->index, - "metric", argv[0]); + int ret = 0; + + if (argc == 0) + ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric", NULL); + else + ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric", argv[0]); return route_map_command_status (vty, ret); } +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") + /* add "set forwarding-address" */ DEFUN (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd, @@ -1158,6 +1171,7 @@ ospf6_routemap_init (void) /* ASE Metric */ install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); /* ASE Metric */ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 37a986c50..9bafdcde1 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -1000,11 +1000,18 @@ DEFUN (no_set_metric, ALIAS (no_set_metric, no_set_metric_val_cmd, - "no set metric (<0-4294967295>|<+/-metric>)", + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") + +ALIAS (no_set_metric, + no_set_metric_addsub_cmd, + "no set metric <+/-metric>", NO_STR SET_STR "Metric value for destination routing protocol\n" - "Metric value\n" "Add or subtract metric\n") DEFUN (set_ip_nexthop, @@ -1135,6 +1142,7 @@ rip_route_map_init () install_element (RMAP_NODE, &set_metric_addsub_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); + install_element (RMAP_NODE, &no_set_metric_addsub_cmd); install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 480d114d8..0bbc2a751 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -181,7 +181,7 @@ foreach (@ARGV) { } } -my $bad_cli_stomps = 89; +my $bad_cli_stomps = 90; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. @@ -221,7 +221,7 @@ foreach (keys %live) { # Output install_element print < Date: Mon, 9 Nov 2015 20:22:00 -0500 Subject: [PATCH 1103/1342] bgpd: Make "no redistribute" always remove the redistribute statement Signed-off-by: Daniel Walton --- bgpd/bgp_vty.c | 96 ++++-------------------------------------------- bgpd/bgp_zebra.c | 29 --------------- bgpd/bgp_zebra.h | 2 - 3 files changed, 8 insertions(+), 119 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4cd8c5ea7..4c1de16ab 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9527,7 +9527,7 @@ DEFUN (no_bgp_redistribute_ipv4, return bgp_redistribute_unset (vty->index, AFI_IP, type); } -DEFUN (no_bgp_redistribute_ipv4_rmap, +ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_rmap_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", NO_STR @@ -9535,21 +9535,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap, QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") -{ - int type; - - type = proto_redistnum (AFI_IP, argv[0]); - if (type < 0 || type == ZEBRA_ROUTE_BGP) - { - vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); - return CMD_WARNING; - } - bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); - return CMD_SUCCESS; -} - -DEFUN (no_bgp_redistribute_ipv4_metric, +ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_metric_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR @@ -9557,21 +9544,8 @@ DEFUN (no_bgp_redistribute_ipv4_metric, QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") -{ - int type; - - type = proto_redistnum (AFI_IP, argv[0]); - if (type < 0 || type == ZEBRA_ROUTE_BGP) - { - vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); - return CMD_WARNING; - } - bgp_redistribute_metric_unset (vty->index, AFI_IP, type); - return CMD_SUCCESS; -} - -DEFUN (no_bgp_redistribute_ipv4_rmap_metric, +ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_rmap_metric_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR @@ -9581,22 +9555,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric, "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") -{ - int type; - - type = proto_redistnum (AFI_IP, argv[0]); - if (type < 0 || type == ZEBRA_ROUTE_BGP) - { - vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bgp_redistribute_metric_unset (vty->index, AFI_IP, type); - bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); - return CMD_SUCCESS; -} -ALIAS (no_bgp_redistribute_ipv4_rmap_metric, +ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_metric_rmap_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR @@ -9740,7 +9700,7 @@ DEFUN (no_bgp_redistribute_ipv6, return bgp_redistribute_unset (vty->index, AFI_IP6, type); } -DEFUN (no_bgp_redistribute_ipv6_rmap, +ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_rmap_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", NO_STR @@ -9748,21 +9708,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap, QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") -{ - int type; - - type = proto_redistnum (AFI_IP6, argv[0]); - if (type < 0 || type == ZEBRA_ROUTE_BGP) - { - vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); - return CMD_WARNING; - } - bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); - return CMD_SUCCESS; -} - -DEFUN (no_bgp_redistribute_ipv6_metric, +ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_metric_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR @@ -9770,21 +9717,8 @@ DEFUN (no_bgp_redistribute_ipv6_metric, QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") -{ - int type; - - type = proto_redistnum (AFI_IP6, argv[0]); - if (type < 0 || type == ZEBRA_ROUTE_BGP) - { - vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); - return CMD_WARNING; - } - bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); - return CMD_SUCCESS; -} - -DEFUN (no_bgp_redistribute_ipv6_rmap_metric, +ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_rmap_metric_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR @@ -9794,22 +9728,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric, "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") -{ - int type; - - type = proto_redistnum (AFI_IP6, argv[0]); - if (type < 0 || type == ZEBRA_ROUTE_BGP) - { - vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); - bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); - return CMD_SUCCESS; -} -ALIAS (no_bgp_redistribute_ipv6_rmap_metric, +ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_metric_rmap_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 484e355c0..be17d233a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1112,35 +1112,6 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) return CMD_SUCCESS; } -/* Unset redistribution route-map configuration. */ -int -bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type) -{ - if (! bgp->rmap[afi][type].name) - return 0; - - /* Unset route-map. */ - free (bgp->rmap[afi][type].name); - bgp->rmap[afi][type].name = NULL; - bgp->rmap[afi][type].map = NULL; - - return 1; -} - -/* Unset redistribution metric configuration. */ -int -bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) -{ - if (! bgp->redist_metric_flag[afi][type]) - return 0; - - /* Unset metric. */ - bgp->redist_metric_flag[afi][type] = 0; - bgp->redist_metric[afi][type] = 0; - - return 1; -} - void bgp_zclient_reset (void) { diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index ccc554750..9a592c33b 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -42,8 +42,6 @@ extern int bgp_redistribute_set (struct bgp *, afi_t, int); extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *); extern int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t); extern int bgp_redistribute_unset (struct bgp *, afi_t, int); -extern int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int); -extern int bgp_redistribute_metric_unset (struct bgp *, afi_t, int); extern struct interface *if_lookup_by_ipv4 (struct in_addr *); extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *); From dcc21851aa5f284bf57ccb2b662f4ff5b5a44321 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 17:47:20 -0700 Subject: [PATCH 1104/1342] bgpd: Make the private AS number check 4 byte compatible. Signed-off-by: Vipin Kumar Reviewed-by: Dinesh Dutt Reviewed-by: Daniel Walton --- bgpd/bgp_aspath.c | 4 +++- bgpd/bgp_aspath.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 49b65b628..613aa447b 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1281,7 +1281,9 @@ aspath_private_as_check (struct aspath *aspath) for (i = 0; i < seg->length; i++) { if ( (seg->as[i] < BGP_PRIVATE_AS_MIN) - || (seg->as[i] > BGP_PRIVATE_AS_MAX) ) + || (seg->as[i] > BGP_PRIVATE_AS_MAX && + seg->as[i] < BGP_PRIVATE_AS4_MIN) + || (seg->as[i] > BGP_PRIVATE_AS4_MAX)) return 0; } seg = seg->next; diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 2f0a5195c..b467ee5f2 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -31,6 +31,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_PRIVATE_AS_MIN 64512U #define BGP_PRIVATE_AS_MAX 65535U +/* Private 4 byte AS range defined in RFC6996. */ +#define BGP_PRIVATE_AS4_MIN 4200000000U +#define BGP_PRIVATE_AS4_MAX 4294967294U + /* we leave BGP_AS_MAX as the 16bit AS MAX number. */ #define BGP_AS_MAX 65535U #define BGP_AS4_MAX 4294967295U From 5552da8f9abd786fb76019135277003f489626d6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 17 Jun 2016 11:36:59 +0100 Subject: [PATCH 1105/1342] bgpd: Fix use after free in aspath_prepend with confeds * bgp_aspath.c: (aspath_prepend) aspath_delete_confed_seq may result in as2 being updated, and seg2 becoming invalid. E.g. if the first segment of of as2 is confeds. However, code there after unconditionally reads from seg2. Reset seg2, and re-do the empty check on it. Caught by valgrinding tools/aspathtest. --- bgpd/bgp_aspath.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 613aa447b..8c87d172a 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1380,7 +1380,18 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) /* Delete any AS_CONFED_SEQUENCE segment from as2. */ if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) as2 = aspath_delete_confed_seq (as2); - + + /* as2 may have been updated */ + seg2 = as2->segments; + + /* as2 may be empty now due to aspath_delete_confed_seq, recheck */ + if (seg2 == NULL) + { + as2->segments = assegment_dup_all (as1->segments); + aspath_str_update (as2); + return as2; + } + /* Compare last segment type of as1 and first segment type of as2. */ if (seg1->type != seg2->type) return aspath_merge (as1, as2); From d0aa6e8b222f44949b0a190d8ff70d90333b775c Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Fri, 17 Jun 2016 14:45:42 +0100 Subject: [PATCH 1106/1342] bgpd: Make aspath_highest 4-byte compatible for private AS * bgp_aspath.h: Add BGP_AS_IS_PRIVATE macro. * bgp_aspath.c: (aspath_highest) use said macro to also ensure 4-byte private AS range is ignored in calculating highest public ASN. (aspath_private_as_check) consolidate to use said macro. Note: Extracted from 'bgpd: Add replace-as option to remove-private-as' by paul@jakma.org. --- bgpd/bgp_aspath.c | 10 +++------- bgpd/bgp_aspath.h | 4 ++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 8c87d172a..3fd359cc5 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -475,9 +475,8 @@ aspath_highest (struct aspath *aspath) while (seg) { for (i = 0; i < seg->length; i++) - if (seg->as[i] > highest - && (seg->as[i] < BGP_PRIVATE_AS_MIN - || seg->as[i] > BGP_PRIVATE_AS_MAX)) + if (seg->as[i] > highest + && !BGP_AS_IS_PRIVATE(seg->as[i])) highest = seg->as[i]; seg = seg->next; } @@ -1280,10 +1279,7 @@ aspath_private_as_check (struct aspath *aspath) for (i = 0; i < seg->length; i++) { - if ( (seg->as[i] < BGP_PRIVATE_AS_MIN) - || (seg->as[i] > BGP_PRIVATE_AS_MAX && - seg->as[i] < BGP_PRIVATE_AS4_MIN) - || (seg->as[i] > BGP_PRIVATE_AS4_MAX)) + if (!BGP_AS_IS_PRIVATE(seg->as[i])) return 0; } seg = seg->next; diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index b467ee5f2..aa13daa17 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -41,6 +41,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Transition 16Bit AS as defined by IANA */ #define BGP_AS_TRANS 23456U +#define BGP_AS_IS_PRIVATE(ASN) \ + (((ASN) >= BGP_PRIVATE_AS_MIN && (ASN) <= BGP_PRIVATE_AS_MAX) || \ + ((ASN) >= BGP_PRIVATE_AS4_MIN && (ASN) <= BGP_PRIVATE_AS4_MAX)) + /* AS_PATH segment data in abstracted form, no limit is placed on length */ struct assegment { From 78243040fc60babf83ef02572ad7966ebd20192e Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:47:23 -0700 Subject: [PATCH 1107/1342] bgpd: iBGP multipath is broken if 'bgp deterministic-med' is enabled. AS_PATH comparison is broken if CONFED_AS_SEQ are present. This patch fixes this issue Signed-off-by: Daniel Walton --- bgpd/bgp_aspath.c | 6 +++++- bgpd/bgp_aspath.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 3fd359cc5..e5541f6d7 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -427,7 +427,7 @@ aspath_count_confeds (struct aspath *aspath) } unsigned int -aspath_count_hops (struct aspath *aspath) +aspath_count_hops (const struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; @@ -1574,6 +1574,10 @@ aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) seg1 = aspath1->segments; seg2 = aspath2->segments; + /* If both paths are originated in this AS then we do want to compare MED */ + if (!seg1 && !seg2) + return 1; + /* find first non-confed segments for each */ while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE) || (seg1->type == AS_CONFED_SET))) diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index aa13daa17..c8f929f93 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -103,7 +103,7 @@ extern int aspath_firstas_check (struct aspath *, as_t); extern int aspath_confed_check (struct aspath *); extern int aspath_left_confed_check (struct aspath *); extern unsigned long aspath_count (void); -extern unsigned int aspath_count_hops (struct aspath *); +extern unsigned int aspath_count_hops (const struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); extern unsigned int aspath_size (struct aspath *); extern as_t aspath_highest (struct aspath *); From 76a7280ddebd94b20c545e93d9773e7ad4db91de Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:47:24 -0700 Subject: [PATCH 1108/1342] bgpd: Fix aggregation issues found via ANVL There were various failures in ANVL's aggregation tests, this patch fixes those issues found Signed-off-by: Daniel Walton --- bgpd/bgp_aspath.c | 3 +++ bgpd/bgp_attr.c | 1 + bgpd/bgp_route.c | 28 +++++++++++++++++++--------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index e5541f6d7..b7af5e88b 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1064,6 +1064,9 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) if (match != minlen || match != seg1->length || seg1->length != seg2->length) break; + /* We are moving on to the next segment to reset match */ + else + match = 0; seg1 = seg1->next; seg2 = seg2->next; diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 54ff54446..616f77925 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -717,6 +717,7 @@ bgp_attr_default_intern (u_char origin) return new; } +/* Create the attributes for an aggregate */ struct attr * bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, struct aspath *aspath, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e5224dc5a..17b87f49a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4731,6 +4731,7 @@ bgp_aggregate_free (struct bgp_aggregate *aggregate) XFREE (MTYPE_BGP_AGGREGATE, aggregate); } +/* Update an aggregate as routes are added/removed from the BGP table */ static void bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, afi_t afi, safi_t safi, struct bgp_info *del, @@ -4803,11 +4804,11 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, aggregate->count++; + if (origin < ri->attr->origin) + origin = ri->attr->origin; + if (aggregate->as_set) { - if (origin < ri->attr->origin) - origin = ri->attr->origin; - if (aspath) { asmerge = aspath_aggregate (aspath, ri->attr->aspath); @@ -4844,11 +4845,11 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, if (aggregate->summary_only) (bgp_info_extra_get (rinew))->suppress++; + if (origin < rinew->attr->origin) + origin = rinew->attr->origin; + if (aggregate->as_set) { - if (origin < rinew->attr->origin) - origin = rinew->attr->origin; - if (aspath) { asmerge = aspath_aggregate (aspath, rinew->attr->aspath); @@ -4968,6 +4969,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, bgp_unlock_node (child); } +/* Called via bgp_aggregate_set when the user configures aggregate-address */ static void bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) @@ -5014,13 +5016,21 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } + + /* If at least one route among routes that are aggregated has + * ORIGIN with the value INCOMPLETE, then the aggregated route + * MUST have the ORIGIN attribute with the value INCOMPLETE. + * Otherwise, if at least one route among routes that are + * aggregated has ORIGIN with the value EGP, then the aggregated + * route MUST have the ORIGIN attribute with the value EGP. + */ + if (origin < ri->attr->origin) + origin = ri->attr->origin; + /* as-set aggregate route generate origin, as path, community aggregation. */ if (aggregate->as_set) { - if (origin < ri->attr->origin) - origin = ri->attr->origin; - if (aspath) { asmerge = aspath_aggregate (aspath, ri->attr->aspath); From 325fcfb6d83c9add415e24e786035b67b00fd719 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:58:10 -0700 Subject: [PATCH 1109/1342] bgpd: Add clear command to force a bestpath recalculation and re-advertisement of a prefix Add these commands to bgp: clear ip bgp prefix A.B.C.D/M clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M These two commands forces a bestpath calculation to happen again if necessary to re-advertise the prefix. Signed-off-by: Daniel Walton --- bgpd/bgp_route.c | 6 ++- bgpd/bgp_table.h | 1 + bgpd/bgp_vty.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 17b87f49a..48645cf01 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1602,7 +1602,8 @@ bgp_process_main (struct work_queue *wq, void *data) new_select = old_and_new.new; /* Nothing to do. */ - if (old_select && old_select == new_select) + if (old_select && old_select == new_select + && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)) { if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { @@ -1616,6 +1617,9 @@ bgp_process_main (struct work_queue *wq, void *data) } } + /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */ + UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); + if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 3b4e6cf3d..8e963aeee 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -65,6 +65,7 @@ struct bgp_node u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) +#define BGP_NODE_USER_CLEAR (1 << 1) }; /* diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4c1de16ab..406ecb127 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4680,6 +4680,87 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, return CMD_SUCCESS; } +/* Recalculate bestpath and re-advertise a prefix */ +static int +bgp_clear_prefix (struct vty *vty, char *view_name, const char *ip_str, + afi_t afi, safi_t safi, struct prefix_rd *prd) +{ + int ret; + struct prefix match; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp *bgp; + struct bgp_table *table; + struct bgp_table *rib; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* Check IP address argument. */ + ret = str2prefix (ip_str, &match); + if (! ret) + { + vty_out (vty, "%% address is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + match.family = afi2family (afi); + rib = bgp->rib[afi][safi]; + + if (safi == SAFI_MPLS_VPN) + { + for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + if ((rm = bgp_node_match (table, &match)) != NULL) + { + if (rm->p.prefixlen == match.prefixlen) + { + SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR); + bgp_process (bgp, rm, afi, safi); + } + bgp_unlock_node (rm); + } + } + } + } + else + { + if ((rn = bgp_node_match (rib, &match)) != NULL) + { + if (rn->p.prefixlen == match.prefixlen) + { + SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR); + bgp_process (bgp, rn, afi, safi); + } + bgp_unlock_node (rn); + } + } + + return CMD_SUCCESS; +} + static int bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, enum clear_sort sort, enum bgp_clear_type stype, @@ -4842,6 +4923,27 @@ ALIAS (clear_ip_bgp_external, "Address family\n" "Clear all external peers\n") +DEFUN (clear_ip_bgp_prefix, + clear_ip_bgp_prefix_cmd, + "clear ip bgp prefix A.B.C.D/M", + CLEAR_STR + IP_STR + BGP_STR + "Clear bestpath and re-advertise\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_clear_prefix (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL); +} + +ALIAS (clear_ip_bgp_prefix, + clear_bgp_prefix_cmd, + "clear bgp prefix A.B.C.D/M", + CLEAR_STR + BGP_STR + "Clear bestpath and re-advertise\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + + DEFUN (clear_ip_bgp_as, clear_ip_bgp_as_cmd, "clear ip bgp " CMD_AS_RANGE, @@ -5072,6 +5174,22 @@ ALIAS (clear_bgp_all_soft_out, "Clear all peers\n" "Soft reconfig outbound update\n") +DEFUN (clear_bgp_ipv6_safi_prefix, + clear_bgp_ipv6_safi_prefix_cmd, + "clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M", + CLEAR_STR + BGP_STR + "Address family\n" + "Address Family Modifier\n" + "Clear bestpath and re-advertise\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL); + else + return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL); +} + DEFUN (clear_ip_bgp_peer_soft_out, clear_ip_bgp_peer_soft_out_cmd, "clear ip bgp A.B.C.D soft out", @@ -10909,6 +11027,10 @@ bgp_vty_init (void) install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd); + /* clear ip bgp prefix */ + install_element (ENABLE_NODE, &clear_ip_bgp_prefix_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_safi_prefix_cmd); + /* "clear ip bgp neighbor soft out" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd); From 59fe0eecd3498f28ec1b1cdb2de5dcc7c507f83f Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:58:11 -0700 Subject: [PATCH 1110/1342] bgpd: Add [bestpath|multipath] option to 'show ip bgp x.x.x.x' When showing a prefix in bgp allow user to specify output based upon the bestpath chosen, multipath information of all information about a prefix(the default) Signed-off-by: Daniel Walton --- bgpd/bgp_route.c | 355 ++++++++++++++++++++++++++++++++++++++--------- bgpd/bgp_route.h | 7 + 2 files changed, 297 insertions(+), 65 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 48645cf01..72e1005af 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6754,7 +6754,7 @@ static int bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, - int prefix_check) + int prefix_check, enum bgp_path_type pathtype) { int ret; int header; @@ -6805,7 +6805,12 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, header = 0; } display++; - route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, safi); + + if (pathtype == BGP_PATH_ALL || + (pathtype == BGP_PATH_BESTPATH && CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) || + (pathtype == BGP_PATH_MULTIPATH && + (CHECK_FLAG (ri->flags, BGP_INFO_MULTIPATH) || CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)))) + route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, safi); } bgp_unlock_node (rm); @@ -6829,7 +6834,12 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, header = 0; } display++; - route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); + + if (pathtype == BGP_PATH_ALL || + (pathtype == BGP_PATH_BESTPATH && CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) || + (pathtype == BGP_PATH_MULTIPATH && + (CHECK_FLAG (ri->flags, BGP_INFO_MULTIPATH) || CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)))) + route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); } } @@ -6850,7 +6860,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, static int bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, - int prefix_check) + int prefix_check, enum bgp_path_type pathtype) { struct bgp *bgp; @@ -6875,7 +6885,7 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, } return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str, - afi, safi, prd, prefix_check); + afi, safi, prd, prefix_check, pathtype); } /* BGP route print out function. */ @@ -6914,7 +6924,47 @@ DEFUN (show_ip_bgp_route, BGP_STR "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); +} + +DEFUN (show_ip_bgp_route_pathtype, + show_ip_bgp_route_pathtype_cmd, + "show ip bgp A.B.C.D (bestpath|multipath)", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[1], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); +} + +DEFUN (show_bgp_ipv4_safi_route_pathtype, + show_bgp_ipv4_safi_route_pathtype_cmd, + "show bgp ipv4 (unicast|multicast) A.B.C.D (bestpath|multipath)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_MULTIPATH); + else + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); } DEFUN (show_ip_bgp_ipv4_route, @@ -6929,9 +6979,9 @@ DEFUN (show_ip_bgp_ipv4_route, "Network in the BGP routing table to display\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL); - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_ip_bgp_vpnv4_all_route, @@ -6944,9 +6994,10 @@ DEFUN (show_ip_bgp_vpnv4_all_route, "Display information about all VPNv4 NLRIs\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL); } + DEFUN (show_ip_bgp_vpnv4_rd_route, show_ip_bgp_vpnv4_rd_route_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", @@ -6967,7 +7018,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_route, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL); } DEFUN (show_ip_bgp_prefix, @@ -6978,7 +7029,23 @@ DEFUN (show_ip_bgp_prefix, BGP_STR "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); +} + +DEFUN (show_ip_bgp_prefix_pathtype, + show_ip_bgp_prefix_pathtype_cmd, + "show ip bgp A.B.C.D/M (bestpath|multipath)", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[1], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } DEFUN (show_ip_bgp_ipv4_prefix, @@ -6993,11 +7060,48 @@ DEFUN (show_ip_bgp_ipv4_prefix, "IP prefix /, e.g., 35.0.0.0/8\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL); - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); +} + +DEFUN (show_ip_bgp_ipv4_prefix_pathtype, + show_ip_bgp_ipv4_prefix_pathtype_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_MULTIPATH); + else + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } +ALIAS (show_ip_bgp_ipv4_prefix_pathtype, + show_bgp_ipv4_safi_prefix_pathtype_cmd, + "show bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display only the bestpath\n" + "Display only multipaths\n") + DEFUN (show_ip_bgp_vpnv4_all_prefix, show_ip_bgp_vpnv4_all_prefix_cmd, "show ip bgp vpnv4 all A.B.C.D/M", @@ -7008,7 +7112,7 @@ DEFUN (show_ip_bgp_vpnv4_all_prefix, "Display information about all VPNv4 NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL); } DEFUN (show_ip_bgp_vpnv4_rd_prefix, @@ -7031,7 +7135,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_prefix, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1, BGP_PATH_ALL); } DEFUN (show_ip_bgp_view, @@ -7066,7 +7170,7 @@ DEFUN (show_ip_bgp_view_route, "View name\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_ip_bgp_view_prefix, @@ -7079,7 +7183,7 @@ DEFUN (show_ip_bgp_view_prefix, "View name\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp, @@ -7118,7 +7222,7 @@ DEFUN (show_bgp_route, BGP_STR "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi, @@ -7148,9 +7252,58 @@ DEFUN (show_bgp_ipv4_safi_route, "Network in the BGP routing table to display\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); +} + +DEFUN (show_bgp_route_pathtype, + show_bgp_route_pathtype_cmd, + "show bgp X:X::X:X (bestpath|multipath)", + SHOW_STR + BGP_STR + "Network in the BGP routing table to display\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[1], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); +} + +ALIAS (show_bgp_route_pathtype, + show_bgp_ipv6_route_pathtype_cmd, + "show bgp ipv6 X:X::X:X (bestpath|multipath)", + SHOW_STR + BGP_STR + "Address family\n" + "Network in the BGP routing table to display\n" + "Display only the bestpath\n" + "Display only multipaths\n") - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +DEFUN (show_bgp_ipv6_safi_route_pathtype, + show_bgp_ipv6_safi_route_pathtype_cmd, + "show bgp ipv6 (unicast|multicast) X:X::X:X (bestpath|multipath)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_MULTIPATH); + else + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); } DEFUN (show_bgp_ipv4_vpn_route, @@ -7162,7 +7315,7 @@ DEFUN (show_bgp_ipv4_vpn_route, "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_vpn_route, @@ -7174,7 +7327,7 @@ DEFUN (show_bgp_ipv6_vpn_route, "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_vpn_rd_route, @@ -7197,7 +7350,7 @@ DEFUN (show_bgp_ipv4_vpn_rd_route, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_vpn_rd_route, @@ -7220,7 +7373,56 @@ DEFUN (show_bgp_ipv6_vpn_rd_route, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MPLS_VPN, &prd, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL); +} + +DEFUN (show_bgp_prefix_pathtype, + show_bgp_prefix_pathtype_cmd, + "show bgp X:X::X:X/M (bestpath|multipath)", + SHOW_STR + BGP_STR + "IPv6 prefix /\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[1], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); +} + +ALIAS (show_bgp_prefix_pathtype, + show_bgp_ipv6_prefix_pathtype_cmd, + "show bgp ipv6 X:X::X:X/M (bestpath|multipath)", + SHOW_STR + BGP_STR + "Address family\n" + "IPv6 prefix /\n" + "Display only the bestpath\n" + "Display only multipaths\n") + +DEFUN (show_bgp_ipv6_safi_prefix_pathtype, + show_bgp_ipv6_safi_prefix_pathtype_cmd, + "show bgp ipv6 (unicast|multicast) X:X::X:X/M (bestpath|multipath)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display only the bestpath\n" + "Display only multipaths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_MULTIPATH); + else + if (strncmp (argv[2], "b", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); + else + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } DEFUN (show_bgp_ipv4_encap_route, @@ -7232,7 +7434,7 @@ DEFUN (show_bgp_ipv4_encap_route, "Display ENCAP NLRI specific information\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_encap_route, @@ -7244,7 +7446,7 @@ DEFUN (show_bgp_ipv6_encap_route, "Display ENCAP NLRI specific information\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi_rd_route, @@ -7273,7 +7475,7 @@ DEFUN (show_bgp_ipv4_safi_rd_route, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0); + return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_rd_route, @@ -7302,7 +7504,7 @@ DEFUN (show_bgp_ipv6_safi_rd_route, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0); + return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_prefix, @@ -7313,7 +7515,7 @@ DEFUN (show_bgp_ipv4_prefix, IP_STR "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi_prefix, @@ -7327,9 +7529,9 @@ DEFUN (show_bgp_ipv4_safi_prefix, "IP prefix /, e.g., 35.0.0.0/8\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL); - return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_vpn_prefix, @@ -7341,7 +7543,7 @@ DEFUN (show_bgp_ipv4_vpn_prefix, "Display VPN NLRI specific information\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_vpn_prefix, @@ -7353,7 +7555,7 @@ DEFUN (show_bgp_ipv6_vpn_prefix, "Display VPN NLRI specific information\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_encap_prefix, @@ -7366,7 +7568,7 @@ DEFUN (show_bgp_ipv4_encap_prefix, "Display information about ENCAP NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_encap_prefix, @@ -7379,7 +7581,7 @@ DEFUN (show_bgp_ipv6_encap_prefix, "Display information about ENCAP NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi_rd_prefix, @@ -7409,7 +7611,7 @@ DEFUN (show_bgp_ipv4_safi_rd_prefix, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1); + return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_rd_prefix, @@ -7439,7 +7641,7 @@ DEFUN (show_bgp_ipv6_safi_rd_prefix, vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1); + return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1, BGP_PATH_ALL); } DEFUN (show_bgp_afi_safi_view, @@ -7507,7 +7709,7 @@ DEFUN (show_bgp_view_afi_safi_route, vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 0); + return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_view_afi_safi_prefix, @@ -7536,7 +7738,7 @@ DEFUN (show_bgp_view_afi_safi_prefix, vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 1); + return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 1, BGP_PATH_ALL); } /* new001 */ @@ -7582,7 +7784,7 @@ DEFUN (show_bgp_ipv6_route, "Address family\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_route, @@ -7596,9 +7798,9 @@ DEFUN (show_bgp_ipv6_safi_route, "Network in the BGP routing table to display\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL); - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } /* old command */ @@ -7610,7 +7812,7 @@ DEFUN (show_ipv6_bgp_route, BGP_STR "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_prefix, @@ -7620,7 +7822,7 @@ DEFUN (show_bgp_prefix, BGP_STR "IPv6 prefix /\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } @@ -7633,7 +7835,7 @@ DEFUN (show_bgp_ipv6_prefix, "Address family\n" "IPv6 prefix /, e.g., 3ffe::/16\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_prefix, show_bgp_ipv6_safi_prefix_cmd, @@ -7646,9 +7848,9 @@ DEFUN (show_bgp_ipv6_safi_prefix, "IPv6 prefix /, e.g., 3ffe::/16\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL); - return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } /* old command */ @@ -7660,7 +7862,7 @@ DEFUN (show_ipv6_bgp_prefix, BGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_view, @@ -7715,7 +7917,7 @@ DEFUN (show_bgp_view_route, "View name\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_route, @@ -7728,7 +7930,7 @@ DEFUN (show_bgp_view_ipv6_route, "Address family\n" "Network in the BGP routing table to display\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } /* old command */ @@ -7752,7 +7954,7 @@ DEFUN (show_ipv6_mbgp_route, MBGP_STR "Network in the MBGP routing table to display\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL); } /* old command */ @@ -7764,7 +7966,7 @@ DEFUN (show_ipv6_mbgp_prefix, MBGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { - return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_view_prefix, @@ -7776,7 +7978,7 @@ DEFUN (show_bgp_view_prefix, "View name\n" "IPv6 prefix /\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_prefix, @@ -7789,7 +7991,7 @@ DEFUN (show_bgp_view_ipv6_prefix, "Address family\n" "IPv6 prefix /\n") { - return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); + return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } static int @@ -13533,7 +13735,7 @@ DEFUN (show_ip_bgp_view_rsclient_route, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], - AFI_IP, SAFI_UNICAST, NULL, 0); + AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } ALIAS (show_ip_bgp_view_rsclient_route, @@ -13790,7 +13992,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_route, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], (argc == 4) ? argv[3] : argv[2], - AFI_IP, safi, NULL, 0); + AFI_IP, safi, NULL, 0, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv4_safi_rsclient_route, @@ -13872,7 +14074,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], (argc == 4) ? argv[3] : argv[2], - AFI_IP, safi, NULL, 1); + AFI_IP, safi, NULL, 1, BGP_PATH_ALL); } DEFUN (show_ip_bgp_view_rsclient_prefix, @@ -13935,7 +14137,7 @@ DEFUN (show_ip_bgp_view_rsclient_prefix, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], - AFI_IP, SAFI_UNICAST, NULL, 1); + AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } ALIAS (show_ip_bgp_view_rsclient_prefix, @@ -14484,7 +14686,7 @@ DEFUN (show_bgp_view_rsclient_route, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], - AFI_IP6, SAFI_UNICAST, NULL, 0); + AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_rsclient_route, @@ -14547,7 +14749,7 @@ DEFUN (show_bgp_view_ipv6_rsclient_route, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], - AFI_IP6, SAFI_UNICAST, NULL, 0); + AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_rsclient_route, @@ -14635,7 +14837,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_route, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], (argc == 4) ? argv[3] : argv[2], - AFI_IP6, safi, NULL, 0); + AFI_IP6, safi, NULL, 0, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_safi_rsclient_route, @@ -14710,7 +14912,7 @@ DEFUN (show_bgp_view_rsclient_prefix, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], - AFI_IP6, SAFI_UNICAST, NULL, 1); + AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_rsclient_prefix, @@ -14773,7 +14975,7 @@ DEFUN (show_bgp_view_ipv6_rsclient_prefix, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], - AFI_IP6, SAFI_UNICAST, NULL, 1); + AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_rsclient_prefix, @@ -14860,7 +15062,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix, return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], (argc == 4) ? argv[3] : argv[2], - AFI_IP6, safi, NULL, 1); + AFI_IP6, safi, NULL, 1, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix, @@ -16419,11 +16621,16 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_cmd); @@ -16505,10 +16712,15 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd); @@ -16537,10 +16749,17 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); + install_element (VIEW_NODE, &show_bgp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_route_cmd); install_element (VIEW_NODE, &show_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_route_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_route_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_pathtype_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_regexp_cmd); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_filter_list_cmd); @@ -16579,6 +16798,12 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_route_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_prefix_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_pathtype_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_cmd); @@ -16590,7 +16815,7 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); - + install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 16b6d5a88..81df8fa79 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -184,6 +184,13 @@ enum bgp_clear_route_type BGP_CLEAR_ROUTE_MY_RSCLIENT }; +enum bgp_path_type +{ + BGP_PATH_ALL, + BGP_PATH_BESTPATH, + BGP_PATH_MULTIPATH +}; + /* Prototypes. */ extern void bgp_route_init (void); extern void bgp_route_finish (void); From a90dc8752723ef6bad6fc5a7d5180ab313b0317c Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 17:58:13 -0700 Subject: [PATCH 1111/1342] ospfd: Support for 'clear ip ospf interface [IFNAME]' Allow the user to enter the 'clear ip ospf interface [IFNAME]' command this resets the connection between ospf and any peers out the specified interface. Signed-off-by: Vipin Kumar --- ospfd/ospf_main.c | 1 + ospfd/ospf_vty.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ ospfd/ospf_vty.h | 1 + 3 files changed, 47 insertions(+) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index f373650c2..32b64e2aa 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -303,6 +303,7 @@ main (int argc, char **argv) /* OSPF vty inits. */ ospf_vty_init (); ospf_vty_show_init (); + ospf_vty_clear_init (); ospf_route_map_init (); #ifdef HAVE_SNMP diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index f0b850530..bcc4008d9 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -7712,6 +7712,51 @@ static struct cmd_node ospf_node = 1 }; +static void +ospf_interface_clear (struct interface *ifp) +{ + if (!if_is_operative (ifp)) return; + + if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) + zlog (NULL, LOG_DEBUG, "ISM[%s]: clear by reset", ifp->name); + + ospf_if_reset(ifp); +} + +DEFUN (clear_ip_ospf_interface, + clear_ip_ospf_interface_cmd, + "clear ip ospf interface [IFNAME]", + CLEAR_STR + IP_STR + "OSPF information\n" + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + struct listnode *node; + + if (argc == 0) /* Clear all the ospfv2 interfaces. */ + { + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + ospf_interface_clear(ifp); + } + else /* Interface name is specified. */ + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + ospf_interface_clear(ifp); + } + + return CMD_SUCCESS; +} + +void +ospf_vty_clear_init (void) +{ + install_element (ENABLE_NODE, &clear_ip_ospf_interface_cmd); +} + /* Install OSPF related vty commands. */ void diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h index 0602fec4e..4610638d5 100644 --- a/ospfd/ospf_vty.h +++ b/ospfd/ospf_vty.h @@ -54,5 +54,6 @@ extern void ospf_vty_init (void); extern void ospf_vty_show_init (void); extern int ospf_str2area_id (const char *, struct in_addr *, int *); +extern void ospf_vty_clear_init (void); #endif /* _QUAGGA_OSPF_VTY_H */ From e509af86e3579944b7cde942ca3ee3427db1936a Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:40 -0700 Subject: [PATCH 1112/1342] opsf6d: Update router-LSA when nbr's interface-ID changes This is a fix to make sure router-LSA is updated when neighbor's interface ID change is received in hello packet. Signed-off-by: Vipin Kumar --- ospf6d/ospf6_message.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index d382f038a..439f6a6e3 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -245,6 +245,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, char *p; int twoway = 0; int neighborchange = 0; + int neighbor_ifindex_change = 0; int backupseen = 0; hello = (struct ospf6_hello *) @@ -285,10 +286,17 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, on->priority = hello->priority; } - /* always override neighbor's source address and ifindex */ - on->ifindex = ntohl (hello->interface_id); + /* Always override neighbor's source address */ memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); + /* Neighbor ifindex check */ + if (on->ifindex > 0 + && (unsigned int) on->ifindex != ntohl (hello->interface_id)) + { + on->ifindex = ntohl (hello->interface_id); + neighbor_ifindex_change++; + } + /* TwoWay check */ for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); @@ -348,6 +356,9 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, thread_add_event (master, backup_seen, oi, 0); if (neighborchange) thread_add_event (master, neighbor_change, oi, 0); + + if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL) + OSPF6_ROUTER_LSA_SCHEDULE (oi->area); } static void From e87f8083ff677b569048ce7560169b64daee0c57 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:40 -0700 Subject: [PATCH 1113/1342] ospf6d: Support for 'clear ipv6 ospf6 interface [ifname] Clear interface commands for ospfv3. Allow the user to clear all peers out the specified interface. Signed-off-by: Vipin Kumar --- ospf6d/ospf6_interface.c | 60 ++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_interface.h | 2 ++ ospf6d/ospf6d.c | 2 ++ 3 files changed, 64 insertions(+) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 9aa6908fa..7d54dd594 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1907,6 +1907,66 @@ ospf6_interface_init (void) install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); } +/* Clear the specified interface structure */ +static void +ospf6_interface_clear (struct vty *vty, struct interface *ifp) +{ + struct ospf6_interface *oi; + + if (!if_is_operative (ifp)) + return; + + if (ifp->info == NULL) + return; + + oi = (struct ospf6_interface *) ifp->info; + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_debug ("Interface %s: clear by reset", ifp->name); + + /* Reset the interface */ + thread_add_event (master, interface_down, oi, 0); + thread_add_event (master, interface_up, oi, 0); +} + +/* Clear interface */ +DEFUN (clear_ipv6_ospf6_interface, + clear_ipv6_ospf6_interface_cmd, + "clear ipv6 ospf6 interface [IFNAME]", + CLEAR_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + ) +{ + struct interface *ifp; + struct listnode *node; + + if (argc == 0) /* Clear all the ospfv3 interfaces. */ + { + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + ospf6_interface_clear (vty, ifp); + } + else /* Interface name is specified. */ + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + { + vty_out (vty, "No such Interface: %s%s", argv[0], VNL); + return CMD_WARNING; + } + ospf6_interface_clear (vty, ifp); + } + + return CMD_SUCCESS; +} + +void +install_element_ospf6_clear_interface (void) +{ + install_element (ENABLE_NODE, &clear_ipv6_ospf6_interface_cmd); +} + DEFUN (debug_ospf6_interface, debug_ospf6_interface_cmd, "debug ospf6 interface", diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 95a377fbb..220a475ab 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -166,6 +166,8 @@ extern int neighbor_change (struct thread *); extern void ospf6_interface_init (void); +extern void install_element_ospf6_clear_interface (void); + extern int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index fa84d0a57..f9b032275 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1790,6 +1790,8 @@ ospf6_init (void) install_element_ospf6_debug_abr (); install_element_ospf6_debug_flood (); + install_element_ospf6_clear_interface (); + install_element (VIEW_NODE, &show_version_ospf6_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd); From f972dec83308986082b04711c8915e13c0a5e1c1 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:41 -0700 Subject: [PATCH 1114/1342] ospf6d: Add the missing ospf6 running check in show cmds SYMPTOM: If some of the ospfv3 commands like 'show ipv6 ospf6 route' are executed with ospf6d daemon running but before having any ospfv3 configuration, then ospf6d crash is seen. ISSUE: There are a few show commands, which are (unlike others) not checking if ospf6 instance is initialized already. FIX: Add the missing checks, by using OSPF6_CMD_CHECK_RUNNING() in the commands where its needed and not yet used. Signed-off-by: Vipin Kumar Reviewed-by: Pradosh Mohapatra Dinesh Dutt --- ospf6d/ospf6_area.c | 6 ++++++ ospf6d/ospf6_asbr.c | 2 ++ ospf6d/ospf6_top.c | 8 ++++++++ ospf6d/ospf6d.c | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 096748210..1861fe7a1 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -666,6 +666,8 @@ DEFUN (show_ipv6_ospf6_spf_tree, struct ospf6_route *route; struct prefix prefix; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) @@ -701,6 +703,8 @@ DEFUN (show_ipv6_ospf6_area_spf_tree, struct ospf6_route *route; struct prefix prefix; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); if (inet_pton (AF_INET, argv[0], &area_id) != 1) @@ -747,6 +751,8 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, struct ospf6_route_table *spf_table; unsigned char tmp_debug_ospf6_spf = 0; + OSPF6_CMD_CHECK_RUNNING (); + inet_pton (AF_INET, argv[0], &router_id); ospf6_linkstate_prefix (router_id, htonl (0), &prefix); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 6db1ca963..265a178b0 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1291,6 +1291,8 @@ DEFUN (show_ipv6_ospf6_redistribute, { struct ospf6_route *route; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_redistribute_show_config (vty); for (route = ospf6_route_head (ospf6->external_table); route; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 145a88e5a..7ec430961 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -1155,6 +1155,8 @@ DEFUN (show_ipv6_ospf6_route, ROUTE_STR ) { + OSPF6_CMD_CHECK_RUNNING (); + ospf6_route_table_show (vty, argc, argv, ospf6->route_table); return CMD_SUCCESS; } @@ -1186,6 +1188,8 @@ DEFUN (show_ipv6_ospf6_route_match, const char *sargv[CMD_ARGC_MAX]; int i, sargc; + OSPF6_CMD_CHECK_RUNNING (); + /* copy argv to sargv and then append "match" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; @@ -1220,6 +1224,8 @@ DEFUN (show_ipv6_ospf6_route_match_detail, sargv[sargc++] = "detail"; sargv[sargc] = NULL; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } @@ -1284,6 +1290,8 @@ DEFUN (show_ipv6_ospf6_route_type_detail, sargv[sargc++] = "detail"; sargv[sargc] = NULL; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index f9b032275..eae01afe9 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1690,6 +1690,8 @@ DEFUN (show_ipv6_ospf6_linkstate, struct listnode *node; struct ospf6_area *oa; + OSPF6_CMD_CHECK_RUNNING (); + for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { vty_out (vty, "%s SPF Result in Area %s%s%s", @@ -1738,6 +1740,8 @@ DEFUN (show_ipv6_ospf6_linkstate_detail, struct listnode *node; struct ospf6_area *oa; + OSPF6_CMD_CHECK_RUNNING (); + /* copy argv to sargv and then append "detail" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; From 69424be09ccf7233b184b89bb7bd6e98f72d252b Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:41 -0700 Subject: [PATCH 1115/1342] ospf6d: We should accept long form of "no redistribute" When turning off redistribution in ospf6, allow the user to specify the full form of the command entered. Signed-off-by: Daniel Walton --- ospf6d/ospf6_asbr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 265a178b0..870ab1857 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -680,6 +680,15 @@ DEFUN (no_ospf6_redistribute, return CMD_SUCCESS; } +ALIAS (no_ospf6_redistribute, + no_ospf6_redistribute_route_map_cmd, + "no redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", + NO_STR + "Redistribute\n" + QUAGGA_REDIST_HELP_STR_OSPF6D + "Route map reference\n" + "Route map name\n") + int ospf6_redistribute_config_write (struct vty *vty) { @@ -1323,6 +1332,7 @@ ospf6_asbr_init (void) install_element (OSPF6_NODE, &ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); + install_element (OSPF6_NODE, &no_ospf6_redistribute_route_map_cmd); } void From e2a0ebf26c640822c3488e6f371a043a91fdcc1b Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:43 -0700 Subject: [PATCH 1116/1342] bgpd: Display BGP paths with unreachable nexthops as invalid If a BGP path has an unreachable nexthop display that path as invalid Signed-off-by: Daniel Walton --- bgpd/bgp_route.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 72e1005af..93902deab 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5845,7 +5845,8 @@ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo) vty_out (vty, "S"); else if (binfo->extra && binfo->extra->suppress) vty_out (vty, "s"); - else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + else if (CHECK_FLAG (binfo->flags, BGP_INFO_VALID) && + ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, "*"); else vty_out (vty, " "); @@ -6305,7 +6306,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (attr->extra && attr->extra->weight != 0) vty_out (vty, ", weight %u", attr->extra->weight); - if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) + vty_out (vty, ", invalid"); + else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, ", valid"); if (binfo->peer != bgp->peer_self) From 45af55a70379da6e1534185ffa20238aa6026d52 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:43 -0700 Subject: [PATCH 1117/1342] ospfd: Make destination of p2p to multicast for LS-ACKS ISSUE: LSAcks (for directed acks) are being sent to neighbor's unicast address. RFC 2328 says: "The IP destination address for the packet is selected as follows. On physical point-to-point networks, the IP destination is always set to the address AllSPFRouters" Fix is to unconditionally set the destination address for LSAcks over point-to-point links as AllSPFRouters. Quagga OSPF already has similar change for OSPF DBD, LSUpdate and LSrequest packets. Signed-off-by: Vipin Kumar Reviewed-by: Daniel Walton Reviewed-by: Dinesh G Dutt --- ospfd/ospf_packet.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b997f1bfc..f14182235 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3830,9 +3830,12 @@ ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Set destination IP address. */ - op->dst = dst; - + /* Decide destination address. */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + else + op->dst.s_addr = dst.s_addr; + /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); From 24521e24c739b130c247e864d22b734daa4281d1 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:48 -0700 Subject: [PATCH 1118/1342] ospfd: Fix no ip ospf hello-interval OSPF silently ignores 'no ip ospf hello-interval X' and 'no ip ospf hello-interval X' Signed-off-by: Daniel Walton Reviewed-by: Dinesh G Dutt --- ospfd/ospf_vty.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index bcc4008d9..bf3ed692e 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -5184,11 +5184,12 @@ ALIAS (ip_ospf_dead_interval_minimal, DEFUN (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_addr_cmd, - "no ip ospf dead-interval A.B.C.D", + "no ip ospf dead-interval <1-65535> A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" + "Seconds\n" "Address of interface") { struct interface *ifp = vty->index; @@ -5201,9 +5202,9 @@ DEFUN (no_ip_ospf_dead_interval, ifp = vty->index; params = IF_DEF_PARAMS (ifp); - if (argc == 1) + if (argc == 2) { - ret = inet_aton(argv[0], &addr); + ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", @@ -5250,6 +5251,15 @@ DEFUN (no_ip_ospf_dead_interval, return CMD_SUCCESS; } +ALIAS (no_ip_ospf_dead_interval, + no_ip_ospf_dead_interval_seconds_cmd, + "no ip ospf dead-interval <1-65535>", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n") + ALIAS (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_cmd, "no ip ospf dead-interval", @@ -5328,11 +5338,12 @@ ALIAS (ip_ospf_hello_interval, DEFUN (no_ip_ospf_hello_interval, no_ip_ospf_hello_interval_addr_cmd, - "no ip ospf hello-interval A.B.C.D", + "no ip ospf hello-interval <1-65535> A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" + "Seconds\n" "Address of interface") { struct interface *ifp = vty->index; @@ -5343,9 +5354,9 @@ DEFUN (no_ip_ospf_hello_interval, ifp = vty->index; params = IF_DEF_PARAMS (ifp); - if (argc == 1) + if (argc == 2) { - ret = inet_aton(argv[0], &addr); + ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", @@ -5370,6 +5381,15 @@ DEFUN (no_ip_ospf_hello_interval, return CMD_SUCCESS; } +ALIAS (no_ip_ospf_hello_interval, + no_ip_ospf_hello_interval_seconds_cmd, + "no ip ospf hello-interval <1-65535>", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n") + ALIAS (no_ip_ospf_hello_interval, no_ip_ospf_hello_interval_cmd, "no ip ospf hello-interval", @@ -7619,12 +7639,14 @@ ospf_vty_if_init (void) install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_seconds_cmd); /* "ip ospf hello-interval" commands. */ install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_seconds_cmd); /* "ip ospf network" commands. */ install_element (INTERFACE_NODE, &ip_ospf_network_cmd); From f687b62b14dd4e79528e9ba607da1ebdc44cf28d Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Tue, 19 May 2015 18:03:50 -0700 Subject: [PATCH 1119/1342] ospfd: Don't wait for state change to Exchange to start LSReq ANVL test 17.5. The current implementation wouldn't start sending LSReq unti the DB Desc packets have all been received (no M bit). This caused the test choke up. RFC 2328 allows for sending LSReq on receiving the first DbDesc packet as long as the nbr state is Exchange. This patch fixes that. Signed-off-by: Dinesh Dutt Edited-by: Paul Jakma to start the sending of LsReq from the nsm_negotiation_done FSM transition function for ExStart->Exchange, rather than tacking the call to ospf_ls_req_send to the bottom of the DD desc processing function. --- ospfd/ospf_nsm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index b43d88550..5c01a5869 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -306,6 +306,10 @@ nsm_negotiation_done (struct ospf_neighbor *nbr) LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); + /* Send Link State Request. */ + if (nbr->t_ls_req == NULL) + ospf_ls_req_send (nbr); + return 0; } @@ -314,10 +318,10 @@ nsm_exchange_done (struct ospf_neighbor *nbr) { if (ospf_ls_request_isempty (nbr)) return NSM_Full; - - /* Send Link State Request. */ - ospf_ls_req_send (nbr); - + + if (nbr->t_ls_req == NULL) + ospf_ls_req_send (nbr); + return NSM_Loading; } From f1b9611821bb73b6bc664afa263cdaa851e09d34 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:51 -0700 Subject: [PATCH 1120/1342] ospf6d: LA (local-address) bit related inter-op fix. As per the RFC, when the NU bit is set, prefix should be ignored. However, the code is currently ignoring prefix with LA bit too. Fixing that part. In future, we should also set LA bit for the loopback addresses. Not doing this part right away, as quagga wont be backward compatible with its own previous releases. Maybe after a release or so, we should start setting LA bit too. Signed-off-by: Vipin Kumar Reviewed-by: Daniel Walton --- ospf6d/ospf6_intra.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 6606c96d9..c13865c98 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1275,14 +1275,13 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) break; /* Appendix A.4.1.1 */ - if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) || - CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA)) + if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU)) { if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op), buf, sizeof (buf)); - zlog_debug ("%s: Skipping Prefix %s has NU/LA option set", + zlog_debug ("%s: Skipping Prefix %s has NU option set", __func__, buf); } continue; From 8c075ef01d64cba7dd52bdc642ccee22a8538b62 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:53 -0700 Subject: [PATCH 1121/1342] ospf6d: Fixing a couple of issues with ospf6_route_remove () routine. When a route_node has multiple ospf6_routes under it (common subnet case), then the current implementation has an issue in adjusting the route_node->info on a ospf6_route_remove() call. The main reason is that it ends up using exact match to determine if the next ospf6_route belongs to the same route_node or not. Fixing that part to use rnode (the existing back-pointer to the route_node) from the ospf6_route to determine that. Also fixing some of the walks to turn them safe so that the route deletion is fine. Signed-off-by: Vipin Kumar Reviewed-by: Vivek Venkatraman --- ospf6d/ospf6_abr.c | 10 +++++----- ospf6d/ospf6_asbr.c | 5 +++-- ospf6d/ospf6_intra.c | 15 +++++++++------ ospf6d/ospf6_route.c | 2 +- ospf6d/ospf6_spf.c | 5 +++-- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index bb79900e5..7e94cef44 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -106,14 +106,14 @@ void ospf6_abr_disable_area (struct ospf6_area *area) { struct ospf6_area *oa; - struct ospf6_route *ro; + struct ospf6_route *ro, *nro; struct ospf6_lsa *old; struct listnode *node, *nnode; /* Withdraw all summary prefixes previously originated */ - for (ro = ospf6_route_head (area->summary_prefix); ro; - ro = ospf6_route_next (ro)) + for (ro = ospf6_route_head (area->summary_prefix); ro; ro = nro) { + nro = ospf6_route_next (ro); old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) @@ -122,9 +122,9 @@ ospf6_abr_disable_area (struct ospf6_area *area) } /* Withdraw all summary router-routes previously originated */ - for (ro = ospf6_route_head (area->summary_router); ro; - ro = ospf6_route_next (ro)) + for (ro = ospf6_route_head (area->summary_router); ro; ro = nro) { + nro = ospf6_route_next (ro); old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 870ab1857..617f8d622 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -240,7 +240,7 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix prefix; - struct ospf6_route *route; + struct ospf6_route *route, *nroute; char buf[64]; external = (struct ospf6_as_external_lsa *) @@ -274,8 +274,9 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; if (route->path.origin.type != lsa->header->type) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index c13865c98..dbd6ad9b7 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1338,7 +1338,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) struct ospf6_area *oa; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct prefix prefix; - struct ospf6_route *route; + struct ospf6_route *route, *nroute; int prefix_num; struct ospf6_prefix *op; char *start, *current, *end; @@ -1376,8 +1376,9 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; if (route->path.area_id != oa->area_id) @@ -1407,7 +1408,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) void ospf6_intra_route_calculation (struct ospf6_area *oa) { - struct ospf6_route *route; + struct ospf6_route *route, *nroute; u_int16_t type; struct ospf6_lsa *lsa; void (*hook_add) (struct ospf6_route *) = NULL; @@ -1434,8 +1435,9 @@ ospf6_intra_route_calculation (struct ospf6_area *oa) oa->route_table->hook_remove = hook_remove; for (route = ospf6_route_head (oa->route_table); route; - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) && CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD)) { @@ -1515,7 +1517,7 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter) void ospf6_intra_brouter_calculation (struct ospf6_area *oa) { - struct ospf6_route *brouter, *copy; + struct ospf6_route *brouter, *nbrouter, *copy; void (*hook_add) (struct ospf6_route *) = NULL; void (*hook_remove) (struct ospf6_route *) = NULL; u_int32_t brouter_id; @@ -1584,8 +1586,9 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) oa->ospf6->brouter_table->hook_remove = hook_remove; for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter; - brouter = ospf6_route_next (brouter)) + brouter = nbrouter) { + nbrouter = ospf6_route_next (brouter); brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 50575564b..1c6495b8c 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -620,7 +620,7 @@ ospf6_route_remove (struct ospf6_route *route, if (node->info == route) { - if (route->next && ospf6_route_is_same (route->next, route)) + if (route->next && route->next->rnode == node) { node->info = route->next; SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 858398eb7..ab18d3852 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -371,11 +371,12 @@ ospf6_spf_install (struct ospf6_vertex *v, void ospf6_spf_table_finish (struct ospf6_route_table *result_table) { - struct ospf6_route *route; + struct ospf6_route *route, *nroute; struct ospf6_vertex *v; for (route = ospf6_route_head (result_table); route; - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); v = (struct ospf6_vertex *) route->route_option; ospf6_vertex_delete (v); ospf6_route_remove (route, result_table); From 7d39125ea4d54624a4865dd272df5041ccac655e Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:53 -0700 Subject: [PATCH 1122/1342] ospf6d: Adding the initialization check in ospfv3_clean() This is to avoid a crash triggered by process termination when ospf6d daemon is running and 'router ospf6' config has not been done yet. Signed-off-by: Vipin Kumar Reviewed-by: Daniel Walton --- ospf6d/ospf6d.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index eae01afe9..387f6923c 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1854,6 +1854,8 @@ ospf6_init (void) void ospf6_clean (void) { + if (!ospf6) + return; if (ospf6->route_table) ospf6_route_remove_all (ospf6->route_table); if (ospf6->brouter_table) From fa2e78677bde6926dc7cfa29e14925eb6d8e87b3 Mon Sep 17 00:00:00 2001 From: Vivek Venkatraman Date: Tue, 19 May 2015 18:03:54 -0700 Subject: [PATCH 1123/1342] bgpd: Make source interface selection in BGP for nexthop determination more robust Ensure that if 'update-source ' is specified, that interface is chosen as the source for the local nexthops. Otherwise, do a complete match on the local IP address of the connection to determine the source interface for the local nexthops; this will handle scenarios where there is an overlap of subnets between interfaces (e.g., loopback and another interface). Signed-off-by: Vivek Venkatraman --- bgpd/bgp_zebra.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index be17d233a..b9e8a5c2e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -576,7 +576,10 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, if (local->sa.sa_family == AF_INET) { nexthop->v4 = local->sin.sin_addr; - ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); + if (peer->update_if) + ifp = if_lookup_by_name (peer->update_if); + else + ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr); } if (local->sa.sa_family == AF_INET6) { @@ -585,8 +588,10 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, if (peer->ifname) ifp = if_lookup_by_name (peer->ifname); } + else if (peer->update_if) + ifp = if_lookup_by_name (peer->update_if); else - ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); + ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr); } if (!ifp) From 743219e9abe79e8a3828fc00de679098061960bb Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:57 -0700 Subject: [PATCH 1124/1342] ospfd: "show ip ospf neighbor" header spacing The column headers for displaying OSPF neighbors are not aligned, this patch addresses this issue Signed-off-by: Daniel Walton --- ospfd/ospf_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index bf3ed692e..3daaaca97 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3117,7 +3117,7 @@ DEFUN (show_ip_ospf_interface, static void show_ip_ospf_neighbour_header (struct vty *vty) { - vty_out (vty, "%s%15s %3s %-15s %9s %-15s %-20s %5s %5s %5s%s", + vty_out (vty, "%s%-15s %3s %-15s %9s %-15s %-20s %5s %5s %5s%s", VTY_NEWLINE, "Neighbor ID", "Pri", "State", "Dead Time", "Address", "Interface", "RXmtL", "RqstL", "DBsmL", From d8c5f27777051b3ea32f8b5979ecd9bb7b9475b9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 16 Mar 2016 08:10:56 -0400 Subject: [PATCH 1125/1342] bgpd: flag paths for multipath if we RX link-local and global nexthops Paths with global and link-local nexthops should be considered for multipath Signed-off-by: Daniel Walton --- bgpd/bgp_mpath.c | 51 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 48694c633..6465aad1d 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -139,26 +139,45 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); - if (!compare && ae1 && ae2 && (ae1->mp_nexthop_len == ae2->mp_nexthop_len)) + if (!compare && ae1 && ae2) { - switch (ae1->mp_nexthop_len) + if (ae1->mp_nexthop_len == ae2->mp_nexthop_len) + { + switch (ae1->mp_nexthop_len) + { + case 4: + case 12: + compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, + &ae2->mp_nexthop_global_in); + break; + case 16: + compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, + &ae2->mp_nexthop_global); + break; + case 32: + compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, + &ae2->mp_nexthop_global); + if (!compare) + compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, + &ae2->mp_nexthop_local); + break; + } + } + + /* This can happen if one IPv6 peer sends you global and link-local + * nexthops but another IPv6 peer only sends you global + */ + else if (ae1->mp_nexthop_len == 16 || ae1->mp_nexthop_len == 32) { - case 4: - case 12: - compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, - &ae2->mp_nexthop_global_in); - break; - case 16: - compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, - &ae2->mp_nexthop_global); - break; - case 32: compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); if (!compare) - compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, - &ae2->mp_nexthop_local); - break; + { + if (ae1->mp_nexthop_len < ae2->mp_nexthop_len) + compare = -1; + else + compare = 1; + } } } @@ -427,7 +446,7 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, struct listnode *mp_node, *mp_next_node; struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; - char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN]; + char pfx_buf[INET6_ADDRSTRLEN], nh_buf[2][INET6_ADDRSTRLEN]; struct bgp_maxpaths_cfg *mpath_cfg = NULL; mpath_changed = 0; From 768d9098a526841d22a8f0b740a919bd6eccee47 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Tue, 19 May 2015 18:04:13 -0700 Subject: [PATCH 1126/1342] zebra: Suppress displaying default config as part of running config Quagga doesn't display default config as part of the running config, only what is different from the default. However, in the case of rtadv, every link displays the default "ipv6 nd suppress-ra" as part of running config. This patch fixes that. Signed-off-by: Dinesh Dutt --- zebra/rtadv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9450f9a92..d4ef1b885 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -1539,8 +1539,6 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) { if (zif->rtadv.AdvSendAdvertisements) vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); - else - vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE); } From 147a812ed15e171d1db882ac96f0f15723bf8b8f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 21 May 2015 16:06:21 -0700 Subject: [PATCH 1127/1342] vtysh: service integrated-vtysh-config not being written to file The vtysh commands: service integrated-vtysh-config hostname XXXX were not being written to the /etc/quagga/Quagga.conf file with a wr mem when service integrated-vtysh-config was issued. This patch fixes this issue Signed-off-by: Donald Sharp --- vtysh/vtysh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index ad1657f79..2e2203da6 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1957,6 +1957,7 @@ write_config_integrated(void) for (i = 0; i < array_size(vtysh_client); i++) vtysh_client_execute (&vtysh_client[i], line, NULL); + vtysh_config_write (); vtysh_config_dump (fp); fclose (fp); From de24f82d0ea7eadd0db7d5c0d340a0579312237c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Chyt=C5=82a?= Date: Thu, 28 Jun 2007 00:09:28 +0200 Subject: [PATCH 1128/1342] zebra: Add internal support for route tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add internal support for a route tag to be applied to routes. At this point in time, tags are not being used. [forward ported by Cumulus] Signed-off-by: Daniel Walton Signed-off-by: Piotr ChytÅ‚a Signed-off-by: Donald Sharp Edited-by: Paul Jakma - rebase conflicts --- zebra/rib.h | 14 ++- zebra/zebra_rib.c | 36 ++++-- zebra/zebra_vty.c | 295 ++++++++++++++++++++++++---------------------- 3 files changed, 186 insertions(+), 159 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 9773cba87..d31db5579 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -65,6 +65,9 @@ struct rib /* Distance. */ u_char distance; + /* Tag */ + u_short tag; + /* Flags of this route. * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed * to clients via Zserv @@ -178,6 +181,9 @@ struct static_route /* Administrative distance. */ u_char distance; + /* Tag */ + u_short tag; + /* Flag for this static route's type. */ u_char type; #define STATIC_IPV4_GATEWAY 1 @@ -444,11 +450,11 @@ extern unsigned long rib_score_proto (u_char proto); extern int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, u_char flags, u_short tag, u_char distance, vrf_id_t vrf_id); extern int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id); + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id); extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, @@ -468,7 +474,7 @@ extern struct route_table *rib_table_ipv6; extern int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, u_char flags, u_short tag, u_char distance, vrf_id_t vrf_id); extern int @@ -476,7 +482,7 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t); extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id); + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id); extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a55d358d3..e57d1afe1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2147,6 +2147,10 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro if (rib) { + /* if tag value changed , update old value in RIB */ + if (rib->tag != si->tag) + rib->tag = si->tag; + /* Same distance static route is there. Update it with new nexthop. */ route_unlock_node (rn); @@ -2184,6 +2188,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro rib->vrf_id = si->vrf_id; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; + rib->tag = si->tag; switch (si->type) { @@ -2269,7 +2274,8 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance && + rib->tag == si->tag) break; } @@ -2308,7 +2314,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, u_char flags, u_short tag, u_char distance, vrf_id_t vrf_id) { u_char type = 0; @@ -2341,7 +2347,8 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { - if (distance == si->distance) + if (distance == si->distance && + tag == si->tag) { route_unlock_node (rn); return 0; @@ -2351,15 +2358,16 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, } } - /* Distance changed. */ + /* Distance or tag changed. */ if (update) - static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id); + static_delete_ipv4_safi (safi, p, gate, ifname, update->tag, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; + si->tag = tag; si->flags = flags; si->vrf_id = vrf_id; @@ -2403,7 +2411,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id) + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2432,7 +2440,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, for (si = rn->info; si; si = si->next) if (type == si->type && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) - && (! ifname || strcmp (ifname, si->ifname) == 0)) + && (! ifname || strcmp (ifname, si->ifname) == 0) + && (! tag || (tag == si->tag))) break; /* Can't find static route. */ @@ -2788,8 +2797,8 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, - vrf_id_t vrf_id) + const char *ifname, u_char flags, u_short tag, + u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; @@ -2817,6 +2826,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, for (si = rn->info; si; si = si->next) { if (type == si->type + && tag == si->tag && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { @@ -2831,13 +2841,14 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, } if (update) - static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id); + static_delete_ipv6(p, type, gate, ifname, tag, si->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; + si->tag = tag; si->flags = flags; si->vrf_id = vrf_id; @@ -2884,7 +2895,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Delete static route from static route configuration. */ int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, vrf_id_t vrf_id) + const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; @@ -2905,7 +2916,8 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, if (distance == si->distance && type == si->type && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) - && (! ifname || strcmp (ifname, si->ifname) == 0)) + && (! ifname || strcmp (ifname, si->ifname) == 0) + && (! tag || (tag == si->tag))) break; /* Can't find static route. */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e3ef963d4..08144cb8d 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -44,7 +44,8 @@ static int zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, const char *dest_str, const char *mask_str, const char *gate_str, const char *flag_str, - const char *distance_str, const char *vrf_id_str) + const char *tag_str, const char *distance_str, + const char *vrf_id_str) { int ret; u_char distance; @@ -53,6 +54,7 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, struct in_addr mask; const char *ifname; u_char flag = 0; + u_short tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (dest_str, &p); @@ -83,6 +85,10 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + /* tag */ + if (tag_str) + tag = atoi (tag_str); + /* VRF id */ if (vrf_id_str) VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); @@ -96,9 +102,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, return CMD_WARNING; } if (add_cmd) - static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, vrf_id); + static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, tag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id); + static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id); return CMD_SUCCESS; } @@ -122,9 +128,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, if (gate_str == NULL) { if (add_cmd) - static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, vrf_id); + static_add_ipv4_safi (safi, &p, NULL, NULL, flag, tag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id); + static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id); return CMD_SUCCESS; } @@ -138,23 +144,13 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, ifname = gate_str; if (add_cmd) - static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, vrf_id); + static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, tag, distance, vrf_id); else - static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, vrf_id); + static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, tag, distance, vrf_id); return CMD_SUCCESS; } -static int -zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, - const char *mask_str, const char *gate_str, - const char *flag_str, const char *distance_str, - const char *vrf_id_str) -{ - return zebra_static_ipv4_safi (vty, SAFI_UNICAST, add_cmd, dest_str, mask_str, - gate_str, flag_str, distance_str, vrf_id_str); -} - /* Static unicast routes for multicast RPF lookup. */ DEFUN (ip_mroute_dist, ip_mroute_dist_cmd, @@ -168,7 +164,7 @@ DEFUN (ip_mroute_dist, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], - NULL, argc > 2 ? argv[2] : NULL, NULL); + NULL, NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (ip_mroute_dist, @@ -193,7 +189,7 @@ DEFUN (ip_mroute_dist_vrf, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], - NULL, argc > 3 ? argv[2] : NULL, + NULL, NULL, argc > 3 ? argv[2] : NULL, argc > 3 ? argv[3] : argv[2]); } @@ -219,7 +215,7 @@ DEFUN (no_ip_mroute_dist, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], - NULL, argc > 2 ? argv[2] : NULL, NULL); + NULL, NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (no_ip_mroute_dist, @@ -245,7 +241,7 @@ DEFUN (no_ip_mroute_dist_vrf, { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], - NULL, argc > 3 ? argv[2] : NULL, + NULL, NULL, argc > 3 ? argv[2] : NULL, argc > 3 ? argv[3] : argv[2]); } @@ -469,8 +465,8 @@ DEFUN (ip_route, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + NULL, NULL, NULL, NULL); } DEFUN (ip_route_flags, @@ -484,8 +480,8 @@ DEFUN (ip_route_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], NULL, NULL, NULL); } DEFUN (ip_route_flags2, @@ -497,8 +493,8 @@ DEFUN (ip_route_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, NULL, NULL); } /* Mask as A.B.C.D format. */ @@ -513,8 +509,8 @@ DEFUN (ip_route_mask, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, NULL, NULL, NULL); } DEFUN (ip_route_mask_flags, @@ -529,8 +525,8 @@ DEFUN (ip_route_mask_flags, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], NULL, NULL, NULL); } DEFUN (ip_route_mask_flags2, @@ -543,8 +539,8 @@ DEFUN (ip_route_mask_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, NULL, NULL); } /* Distance option value. */ @@ -559,8 +555,8 @@ DEFUN (ip_route_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, NULL, argv[2], NULL); } DEFUN (ip_route_flags_distance, @@ -575,8 +571,8 @@ DEFUN (ip_route_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], NULL, argv[3], NULL); } DEFUN (ip_route_flags_distance2, @@ -589,8 +585,8 @@ DEFUN (ip_route_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, argv[2], NULL); } DEFUN (ip_route_mask_distance, @@ -605,8 +601,8 @@ DEFUN (ip_route_mask_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + NULL, NULL, argv[3], NULL); } DEFUN (ip_route_mask_flags_distance, @@ -622,8 +618,8 @@ DEFUN (ip_route_mask_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4], NULL); } DEFUN (ip_route_mask_flags_distance2, @@ -637,8 +633,8 @@ DEFUN (ip_route_mask_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, argv[3], NULL); } DEFUN (no_ip_route, @@ -652,8 +648,8 @@ DEFUN (no_ip_route, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], NULL, NULL, NULL, NULL); } ALIAS (no_ip_route, @@ -678,8 +674,8 @@ DEFUN (no_ip_route_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + NULL, NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_mask, @@ -694,8 +690,8 @@ DEFUN (no_ip_route_mask, "IP gateway interface name\n" "Null interface\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, NULL, NULL); } ALIAS (no_ip_route_mask, @@ -722,8 +718,8 @@ DEFUN (no_ip_route_mask_flags2, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_distance, @@ -738,8 +734,8 @@ DEFUN (no_ip_route_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], NULL, NULL, argv[2], NULL); } DEFUN (no_ip_route_flags_distance, @@ -755,8 +751,8 @@ DEFUN (no_ip_route_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], argv[2], NULL, argv[3], NULL); } DEFUN (no_ip_route_flags_distance2, @@ -770,8 +766,8 @@ DEFUN (no_ip_route_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], NULL, argv[2], NULL); } DEFUN (no_ip_route_mask_distance, @@ -787,8 +783,8 @@ DEFUN (no_ip_route_mask_distance, "Null interface\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, argv[3], NULL); } DEFUN (no_ip_route_mask_flags_distance, @@ -805,8 +801,8 @@ DEFUN (no_ip_route_mask_flags_distance, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], argv[3], NULL, argv[4], NULL); } DEFUN (no_ip_route_mask_flags_distance2, @@ -821,8 +817,8 @@ DEFUN (no_ip_route_mask_flags_distance2, "Silently discard pkts when matched\n" "Distance value for this route\n") { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], - NULL); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, argv[2], NULL, argv[3], NULL); } DEFUN (ip_route_vrf, @@ -836,8 +832,8 @@ DEFUN (ip_route_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, NULL, NULL, argv[2]); } DEFUN (ip_route_flags_vrf, @@ -852,8 +848,8 @@ DEFUN (ip_route_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], argv[2], NULL, NULL, argv[3]); } DEFUN (ip_route_flags2_vrf, @@ -866,8 +862,8 @@ DEFUN (ip_route_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, NULL, argv[2]); } /* Mask as A.B.C.D format. */ @@ -883,8 +879,8 @@ DEFUN (ip_route_mask_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, NULL, NULL, argv[3]); } DEFUN (ip_route_mask_flags_vrf, @@ -900,8 +896,8 @@ DEFUN (ip_route_mask_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], NULL, NULL, argv[4]); } DEFUN (ip_route_mask_flags2_vrf, @@ -915,8 +911,8 @@ DEFUN (ip_route_mask_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, NULL, argv[3]); } /* Distance option value. */ @@ -932,8 +928,8 @@ DEFUN (ip_route_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, NULL, argv[2], argv[3]); } DEFUN (ip_route_flags_distance_vrf, @@ -949,8 +945,8 @@ DEFUN (ip_route_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], argv[2], NULL, argv[3], argv[4]); } DEFUN (ip_route_flags_distance2_vrf, @@ -964,8 +960,8 @@ DEFUN (ip_route_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], NULL, argv[2], argv[3]); } DEFUN (ip_route_mask_distance_vrf, @@ -981,8 +977,8 @@ DEFUN (ip_route_mask_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (ip_route_mask_flags_distance_vrf, @@ -999,8 +995,8 @@ DEFUN (ip_route_mask_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], NULL, argv[4], argv[5]); } DEFUN (ip_route_mask_flags_distance2_vrf, @@ -1015,8 +1011,8 @@ DEFUN (ip_route_mask_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + NULL, argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_vrf, @@ -1031,8 +1027,9 @@ DEFUN (no_ip_route_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, - (argc > 3) ? argv[3] : argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], + NULL, argv[1], NULL, NULL, NULL, + (argc > 3) ? argv[3] : argv[2]); } ALIAS (no_ip_route_vrf, @@ -1059,8 +1056,8 @@ DEFUN (no_ip_route_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], + NULL, NULL, NULL, NULL, NULL, argv[2]); } DEFUN (no_ip_route_mask_vrf, @@ -1076,8 +1073,9 @@ DEFUN (no_ip_route_mask_vrf, "Null interface\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, - (argc > 4) ? argv[4] : argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, NULL, + (argc > 4) ? argv[4] : argv[3]); } ALIAS (no_ip_route_mask_vrf, @@ -1106,8 +1104,8 @@ DEFUN (no_ip_route_mask_flags2_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, - argv[2]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, NULL, NULL, argv[2]); } DEFUN (no_ip_route_distance_vrf, @@ -1123,8 +1121,8 @@ DEFUN (no_ip_route_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, + argv[1], NULL, NULL, argv[2], argv[3]); } DEFUN (no_ip_route_flags_distance_vrf, @@ -1141,8 +1139,8 @@ DEFUN (no_ip_route_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_flags_distance2_vrf, @@ -1157,8 +1155,8 @@ DEFUN (no_ip_route_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2], - argv[3]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], NULL, argv[2], argv[3]); } DEFUN (no_ip_route_mask_distance_vrf, @@ -1175,8 +1173,8 @@ DEFUN (no_ip_route_mask_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (no_ip_route_mask_flags_distance_vrf, @@ -1194,8 +1192,8 @@ DEFUN (no_ip_route_mask_flags_distance_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4], argv[5]); } DEFUN (no_ip_route_mask_flags_distance2_vrf, @@ -1211,8 +1209,8 @@ DEFUN (no_ip_route_mask_flags_distance2_vrf, "Distance value for this route\n" VRF_CMD_HELP_STR) { - return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], - argv[4]); + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, + argv[2], NULL, argv[3], argv[4]); } char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ @@ -1294,6 +1292,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (rib->mtu) vty_out (vty, ", mtu %u", rib->mtu); + vty_out (vty, ", tag %d", rib->tag); vty_out (vty, ", vrf %u", rib->vrf_id); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); @@ -2468,6 +2467,9 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) vty_out (vty, " %s", "blackhole"); } + if (si->tag) + vty_out (vty, " tag %d", si->tag); + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); @@ -2511,13 +2513,12 @@ DEFUN (show_ip_protocol, return CMD_SUCCESS; } -#ifdef HAVE_IPV6 /* General fucntion for IPv6 static route. */ static int static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, const char *gate_str, const char *ifname, - const char *flag_str, const char *distance_str, - const char *vrf_id_str) + const char *flag_str, const char *tag_str, + const char *distance_str, const char *vrf_id_str) { int ret; u_char distance; @@ -2527,6 +2528,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, u_char type = 0; vrf_id_t vrf_id = VRF_DEFAULT; u_char flag = 0; + u_short tag = 0; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -2561,6 +2563,10 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + /* tag */ + if (tag_str) + tag = atoi (tag_str); + /* When gateway is valid IPv6 addrees, then gate is treated as nexthop address other case gate is treated as interface name. */ ret = inet_pton (AF_INET6, gate_str, &gate_addr); @@ -2596,9 +2602,9 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); if (add_cmd) - static_add_ipv6 (&p, type, gate, ifname, flag, distance, vrf_id); + static_add_ipv6 (&p, type, gate, ifname, flag, tag, distance, vrf_id); else - static_delete_ipv6 (&p, type, gate, ifname, distance, vrf_id); + static_delete_ipv6 (&p, type, gate, ifname, tag, distance, vrf_id); return CMD_SUCCESS; } @@ -2613,7 +2619,7 @@ DEFUN (ipv6_route, "IPv6 gateway interface name\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, - NULL); + NULL, NULL); } DEFUN (ipv6_route_flags, @@ -2628,7 +2634,7 @@ DEFUN (ipv6_route_flags, "Silently discard pkts when matched\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, - NULL); + NULL, NULL); } DEFUN (ipv6_route_ifname, @@ -2641,7 +2647,7 @@ DEFUN (ipv6_route_ifname, "IPv6 gateway interface name\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, - NULL); + NULL, NULL); } DEFUN (ipv6_route_ifname_flags, @@ -2656,7 +2662,7 @@ DEFUN (ipv6_route_ifname_flags, "Silently discard pkts when matched\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, - NULL); + NULL, NULL); } DEFUN (ipv6_route_pref, @@ -2669,7 +2675,7 @@ DEFUN (ipv6_route_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2], NULL); } @@ -2685,7 +2691,7 @@ DEFUN (ipv6_route_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } @@ -2699,7 +2705,7 @@ DEFUN (ipv6_route_ifname_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], NULL); } @@ -2715,7 +2721,7 @@ DEFUN (ipv6_route_ifname_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } @@ -2729,7 +2735,7 @@ DEFUN (no_ipv6_route, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, NULL); } @@ -2755,7 +2761,7 @@ DEFUN (no_ipv6_route_ifname, "IPv6 gateway address\n" "IPv6 gateway interface name\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, NULL); } @@ -2782,7 +2788,7 @@ DEFUN (no_ipv6_route_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2], NULL); } @@ -2800,7 +2806,7 @@ DEFUN (no_ipv6_route_flags_pref, "Distance value for this prefix\n") { /* We do not care about argv[2] */ - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } @@ -2815,7 +2821,7 @@ DEFUN (no_ipv6_route_ifname_pref, "IPv6 gateway interface name\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], NULL); } @@ -2832,7 +2838,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref, "Silently discard pkts when matched\n" "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } @@ -2846,7 +2852,7 @@ DEFUN (ipv6_route_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, NULL, argv[2]); } @@ -2862,7 +2868,7 @@ DEFUN (ipv6_route_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL, argv[3]); } @@ -2876,7 +2882,7 @@ DEFUN (ipv6_route_ifname_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL, argv[3]); } @@ -2892,7 +2898,7 @@ DEFUN (ipv6_route_ifname_flags_vrf, "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL, argv[4]); } @@ -2907,7 +2913,7 @@ DEFUN (ipv6_route_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2], argv[3]); } @@ -2924,7 +2930,7 @@ DEFUN (ipv6_route_flags_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } @@ -2939,7 +2945,7 @@ DEFUN (ipv6_route_ifname_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } @@ -2956,7 +2962,7 @@ DEFUN (ipv6_route_ifname_flags_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } @@ -2971,7 +2977,7 @@ DEFUN (no_ipv6_route_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, (argc > 3) ? argv[3] : argv[2]); } @@ -2999,7 +3005,7 @@ DEFUN (no_ipv6_route_ifname_vrf, "IPv6 gateway interface name\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, (argc > 4) ? argv[4] : argv[3]); } @@ -3028,7 +3034,7 @@ DEFUN (no_ipv6_route_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2], argv[3]); } @@ -3047,7 +3053,7 @@ DEFUN (no_ipv6_route_flags_pref_vrf, VRF_CMD_HELP_STR) { /* We do not care about argv[2] */ - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } @@ -3063,7 +3069,7 @@ DEFUN (no_ipv6_route_ifname_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } @@ -3081,7 +3087,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref_vrf, "Distance value for this prefix\n" VRF_CMD_HELP_STR) { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } @@ -3798,6 +3804,9 @@ static_config_ipv6 (struct vty *vty) if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, " %s", "blackhole"); + if (si->tag) + vty_out (vty, " tag %d", si->tag); + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); @@ -3811,7 +3820,6 @@ static_config_ipv6 (struct vty *vty) } return write; } -#endif /* HAVE_IPV6 */ /* Static ip route configuration write function. */ static int @@ -4036,4 +4044,5 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ipv6_mroute_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_all_cmd); } From eefddcc78abcc91d1d88633a3c6d5a438fe58790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Chyt=C5=82a?= Date: Tue, 1 Dec 2015 09:48:02 -0500 Subject: [PATCH 1129/1342] bgpd, lib, ospfd, zebra: Add ability to read/write tag value Modify zebra to pass the tag value to and from the various protocols. [forward ported by Cumulus] Signed-off-by: Daniel Walton Signed-off-by: Piotr Chytla Signed-off-by: Donald Sharp Edits: Paul Jakma rebase conflicts in bgp_zebra.c --- bgpd/bgp_zebra.c | 52 +++++++++++++++++++++++++++++++++++----------- lib/zclient.c | 6 ++++++ lib/zclient.h | 5 +++++ ospfd/ospf_zebra.c | 6 ++++++ zebra/zserv.c | 28 +++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index b9e8a5c2e..5283d74b1 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -278,17 +278,23 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + if (command == ZEBRA_IPV4_ROUTE_ADD) { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u", + zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), - api.metric); + api.metric, + api.tag); } bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, api.metric, api.type); @@ -299,12 +305,13 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d " - "nexthop %s metric %u", + "nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), - api.metric); + api.metric, + api.tag); } bgp_redistribute_delete((struct prefix *)&p, api.type); } @@ -358,6 +365,11 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + /* Simply ignore link-local address. */ if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) return 0; @@ -367,12 +379,13 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; - zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u", + zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), - api.metric); + api.metric, + api.tag); } bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, api.metric, api.type); @@ -383,12 +396,13 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " - "nexthop %s metric %u", + "nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), - api.metric); + api.metric, + api.tag); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } @@ -680,6 +694,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa struct bgp_info *mpinfo; size_t oldsize, newsize; u_int32_t nhcount; + u_short tag = 0; if (zclient->sock < 0) return; @@ -742,6 +757,12 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if (tag) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TAG); + api.tag = tag; + } + distance = bgp_distance_apply (p, info, bgp); if (distance) @@ -755,11 +776,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa int i; char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u" - " count %d", + " tag %u count %d", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])), - api.metric, api.nexthop_num); + api.metric, api.tag, api.nexthop_num); for (i = 1; i < api.nexthop_num; i++) zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s", i, inet_ntop(AF_INET, api.nexthop[i], buf[1], @@ -921,15 +942,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } + + if (tag) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TAG); + api.tag = tag; + } if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; - zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u", + zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u" + " tag %u", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), - api.metric); + api.metric, api.tag); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, diff --git a/lib/zclient.c b/lib/zclient.c index 097314afa..a1de831f3 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -530,6 +530,8 @@ zclient_connect (struct thread *t) * If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8 * byte value. * + * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value + * * XXX: No attention paid to alignment. */ int @@ -588,6 +590,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, stream_putl (s, api->metric); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) stream_putl (s, api->mtu); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) + stream_putw (s, api->tag); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -644,6 +648,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, stream_putl (s, api->metric); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) stream_putl (s, api->mtu); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) + stream_putw (s, api->tag); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); diff --git a/lib/zclient.h b/lib/zclient.h index a3452eb32..810c927c8 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -99,6 +99,7 @@ struct zclient #define ZAPI_MESSAGE_DISTANCE 0x04 #define ZAPI_MESSAGE_METRIC 0x08 #define ZAPI_MESSAGE_MTU 0x10 +#define ZAPI_MESSAGE_TAG 0x20 /* Zserv protocol message header */ struct zserv_header @@ -132,6 +133,8 @@ struct zapi_ipv4 u_char distance; + u_short tag; + u_int32_t metric; u_int32_t mtu; @@ -210,6 +213,8 @@ struct zapi_ipv6 u_char distance; + u_short tag; + u_int32_t metric; u_int32_t mtu; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 3e359799d..d9b0837b1 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -545,6 +545,7 @@ ospf_zebra_add_discard (struct prefix_ipv4 *p) SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; + api.tag = 0; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api); @@ -569,6 +570,7 @@ ospf_zebra_delete_discard (struct prefix_ipv4 *p) SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; + api.tag = 0; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); @@ -888,6 +890,10 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, api.distance = stream_getc (s); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; ospf = ospf_lookup (); if (ospf == NULL) diff --git a/zebra/zserv.c b/zebra/zserv.c index 6e65aa157..89232c27c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -494,6 +494,12 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, stream_putl (s, rib->metric); SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU); stream_putl (s, rib->mtu); + /* tag */ + if (rib->tag) + { + SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG); + stream_putw(s, rib->tag); + } } /* write real message flags value */ @@ -1003,6 +1009,9 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) rib->mtu = stream_getl (s); + /* Tag */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + rib->tag = stream_getw (s); /* Table */ rib->table=zebrad.rtm_table_default; @@ -1087,6 +1096,12 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) else api.metric = 0; + /* tag */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, vrf_id, api.safi); return 0; @@ -1234,6 +1249,10 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) rib->mtu = stream_getl (s); + /* Tag */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + rib->tag = stream_getw (s); + /* Table */ rib->table=zebrad.rtm_table_default; rib_add_ipv6_multipath (&p, rib, safi); @@ -1289,15 +1308,24 @@ zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) } } + /* Distance. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; + + /* Metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; + /* tag */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id, api.safi); From 2b2e38c3169ae0221645e4dd9b40388660ce3f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Chyt=C5=82a?= Date: Tue, 1 Dec 2015 10:10:41 -0500 Subject: [PATCH 1130/1342] ospfd, vtysh: Add support for Route tags [Forward ported by Cumulus] Credit ------ A huge amount of credit for this patch goes to Piotr Chytla for their 'route tags support' patch that was submitted to quagga-dev in June 2007. Documentation ------------- All ipv4 and ipv6 static route commands now have a "tag" option which allows the user to set a tag between 1 and 65535. quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag ? <1-65535> Tag value quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag 40 quagga(config)# quagga# show ip route 1.1.1.1/32 Routing entry for 1.1.1.1/32 Known via "static", distance 1, metric 0, tag 40, best * 10.1.1.1, via swp1 quagga# The route-map parser supports matching on tags and setting tags ! route-map MATCH_TAG_18 permit 10 match tag 18 ! ! route-map SET_TAG_22 permit 10 set tag 22 ! BGP and OSPF support: - matching on tags when redistribing routes from the RIB into BGP/OSPF. - setting tags when redistribing routes from the RIB into BGP/OSPF. Signed-off-by: Daniel Walton Signed-off-by: Piotr Chytla Signed-off-by: Donald Sharp --- ospfd/ospf_asbr.c | 5 +- ospfd/ospf_asbr.h | 3 +- ospfd/ospf_lsa.c | 6 +- ospfd/ospf_routemap.c | 192 ++++++++++++++++++++++++++++++++++++++++++ ospfd/ospf_zebra.c | 17 +++- ospfd/ospfd.c | 1 + ospfd/ospfd.h | 3 + vtysh/extract.pl.in | 2 +- 8 files changed, 220 insertions(+), 9 deletions(-) diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 122e70b4e..4b536903a 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -135,7 +135,8 @@ ospf_route_map_set_compare (struct route_map_set_values *values1, /* Add an External info for AS-external-LSA. */ struct external_info * ospf_external_info_add (u_char type, struct prefix_ipv4 p, - ifindex_t ifindex, struct in_addr nexthop) + ifindex_t ifindex, struct in_addr nexthop, + u_short tag) { struct external_info *new; struct route_node *rn; @@ -162,7 +163,7 @@ ospf_external_info_add (u_char type, struct prefix_ipv4 p, new->p = p; new->ifindex = ifindex; new->nexthop = nexthop; - new->tag = 0; + new->tag = tag; if (rn) rn->info = new; diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index d151cb149..2709a6c0a 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -62,7 +62,8 @@ extern int ospf_route_map_set_compare (struct route_map_set_values *, extern struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, ifindex_t, - struct in_addr); + struct in_addr, + u_short); extern void ospf_external_info_delete (u_char, struct prefix_ipv4); extern struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index c1b1e0e61..4341cd9fe 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1649,8 +1649,8 @@ ospf_external_lsa_body_set (struct stream *s, struct external_info *ei, /* Put forwarding address. */ stream_put_ipv4 (s, fwd_addr.s_addr); - /* Put route tag -- This value should be introduced from configuration. */ - stream_putl (s, 0); + /* Put route tag -- only first 16bits are used for compatibility */ + stream_putl (s, ei->tag); } /* Create new external-LSA. */ @@ -2163,7 +2163,7 @@ ospf_default_originate_timer (struct thread *thread) /* If there is no default route via redistribute, then originate AS-external-LSA with nexthop 0 (self). */ nexthop.s_addr = 0; - ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop); + ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop, 0); } if ((ei = ospf_default_external_info (ospf))) diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index d0ebce66e..7bd6c3d96 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -417,6 +417,67 @@ struct route_map_rule_cmd route_match_interface_cmd = route_match_interface_free }; +/* Match function return 1 if match is success else return zero. */ +static route_map_result_t +route_match_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_short *tag; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + tag = rule; + ei = object; + + return ((ei->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH); + } + + return RMAP_NOMATCH; +} + +/* Route map `match tag' match statement. `arg' is TAG value */ +static void * +route_match_tag_compile (const char *arg) +{ + u_short *tag; + u_short tmp; + + /* tag value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + tmp = atoi(arg); + if (tmp < 1) + return NULL; + + tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); + + if (!tag) + return tag; + + *tag = tmp; + + return tag; +} + +/* Free route map's compiled 'match tag' value. */ +static void +route_match_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag matching. */ +struct route_map_rule_cmd route_match_tag_cmd = +{ + "tag", + route_match_tag, + route_match_tag_compile, + route_match_tag_free, +}; + + /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t @@ -531,6 +592,67 @@ struct route_map_rule_cmd route_set_metric_type_cmd = route_set_metric_type_free, }; +static route_map_result_t +route_set_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_short *tag; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + tag = rule; + ei = object; + + /* Set tag value */ + ei->tag=*tag; + } + + return RMAP_OKAY; +} + +/* Route map `tag' compile function. Given string is converted to u_short. */ +static void * +route_set_tag_compile (const char *arg) +{ + u_short *tag; + u_short tmp; + + /* tag value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + tmp = atoi(arg); + + if (tmp < 1) + return NULL; + + tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); + + if (!tag) + return tag; + + *tag = tmp; + + return tag; +} + +/* Free route map's tag value. */ +static void +route_set_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag set. */ +struct route_map_rule_cmd route_set_tag_cmd = +{ + "tag", + route_set_tag, + route_set_tag_compile, + route_set_tag_free, +}; + DEFUN (match_ip_nexthop, match_ip_nexthop_cmd, "match ip next-hop (<1-199>|<1300-2699>|WORD)", @@ -716,6 +838,37 @@ ALIAS (no_match_interface, "Match first hop interface of route\n" "Interface name\n") +DEFUN (match_tag, + match_tag_cmd, + "match tag <1-65535>", + MATCH_STR + "Match tag of route\n" + "Tag value\n") +{ + return ospf_route_match_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_match_tag, + no_match_tag_cmd, + "no match tag", + NO_STR + MATCH_STR + "Match tag of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "tag", NULL); + + return ospf_route_match_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_match_tag, + no_match_tag_val_cmd, + "no match tag <1-65535>", + NO_STR + MATCH_STR + "Match tag of route\n" + "Tag value\n") + DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", @@ -785,6 +938,37 @@ ALIAS (no_set_metric_type, "OSPF[6] external type 1 metric\n" "OSPF[6] external type 2 metric\n") +DEFUN (set_tag, + set_tag_cmd, + "set tag <1-65535>", + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + return ospf_route_set_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_set_tag, + no_set_tag_cmd, + "no set tag", + NO_STR + SET_STR + "Tag value for routing protocol\n") +{ + if (argc == 0) + ospf_route_set_delete(vty, vty->index, "tag", NULL); + + return ospf_route_set_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_set_tag, + no_set_tag_val_cmd, + "no set tag <1-65535>", + NO_STR + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") + /* Route-map init */ void ospf_route_map_init (void) @@ -801,9 +985,11 @@ ospf_route_map_init (void) route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); route_map_install_match (&route_match_interface_cmd); + route_map_install_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_metric_type_cmd); + route_map_install_set (&route_set_tag_cmd); install_element (RMAP_NODE, &match_ip_nexthop_cmd); install_element (RMAP_NODE, &no_match_ip_nexthop_cmd); @@ -820,6 +1006,9 @@ ospf_route_map_init (void) install_element (RMAP_NODE, &match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_val_cmd); + install_element (RMAP_NODE, &match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); @@ -827,4 +1016,7 @@ ospf_route_map_init (void) install_element (RMAP_NODE, &set_metric_type_cmd); install_element (RMAP_NODE, &no_set_metric_type_cmd); install_element (RMAP_NODE, &no_set_metric_type_val_cmd); + install_element (RMAP_NODE, &set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_val_cmd); } diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index d9b0837b1..ce268cd2a 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -370,6 +370,12 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) if (distance) SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); + /* Check if path type is ASE and use only 16bit tags */ + if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) || + (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) && + (or->u.ext.tag > 0) && (or->u.ext.tag < UINT16_MAX)) + SET_FLAG (message, ZAPI_MESSAGE_TAG); + /* Make packet. */ s = zclient->obuf; stream_reset (s); @@ -437,6 +443,9 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) stream_putl (s, or->cost); } + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + stream_putw (s, (u_short)or->u.ext.tag); + stream_putw_at (s, 0, stream_get_endp (s)); zclient_send_message(zclient); @@ -911,8 +920,12 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, * || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT)) * return 0; */ - - ei = ospf_external_info_add (api.type, p, ifindex, nexthop); + + /* Protocol tag overwrites all other tag value send by zebra */ + if (ospf->dtag[api.type] > 0) + api.tag = ospf->dtag[api.type]; + + ei = ospf_external_info_add (api.type, p, ifindex, nexthop, api.tag); if (ospf->router_id.s_addr == 0) /* Set flags to generate AS-external-LSA originate event diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a01af602e..98d6d77a5 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -197,6 +197,7 @@ ospf_new (void) { new->dmetric[i].type = -1; new->dmetric[i].value = -1; + new->dtag[i] = 0; } new->default_metric = -1; new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 508f623d0..4181d1142 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -238,6 +238,9 @@ struct ospf -1 means metric value is not set. */ } dmetric [ZEBRA_ROUTE_MAX + 1]; + /* Redistribute tag info. */ + u_short dtag [ZEBRA_ROUTE_MAX + 1]; + /* For redistribute route map. */ struct { diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 0bbc2a751..81adf3585 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -181,7 +181,7 @@ foreach (@ARGV) { } } -my $bad_cli_stomps = 90; +my $bad_cli_stomps = 96; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. From 605aa331d814b0977dd8435168dca5b2b7928996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Chyt=C5=82a?= Date: Tue, 1 Dec 2015 10:03:54 -0500 Subject: [PATCH 1131/1342] bgpd, vtysh: Add support for route tags [Forward ported by Cumulus] Documentation ------------- All ipv4 and ipv6 static route commands now have a "tag" option which allows the user to set a tag between 1 and 65535. quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag ? <1-65535> Tag value quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag 40 quagga(config)# quagga# show ip route 1.1.1.1/32 Routing entry for 1.1.1.1/32 Known via "static", distance 1, metric 0, tag 40, best * 10.1.1.1, via swp1 quagga# The route-map parser supports matching on tags and setting tags ! route-map MATCH_TAG_18 permit 10 match tag 18 ! ! route-map SET_TAG_22 permit 10 set tag 22 ! BGP and OSPF support: - matching on tags when redistribing routes from the RIB into BGP/OSPF. - setting tags when redistribing routes from the RIB into BGP/OSPF. BGP also supports setting a tag via a table-map, when installing BGP routes into the RIB. Signed-off-by: Daniel Walton Signed-off-by: Piotr Chytla Signed-off-by: Donald Sharp Edits by: Paul Jakma weight); MIX(extra->mp_nexthop_global_in.s_addr); MIX(extra->originator_id.s_addr); + MIX(extra->tag); } if (attr->aspath) @@ -540,6 +541,7 @@ attrhash_cmp (const void *p1, const void *p2) && ae1->aggregator_as == ae2->aggregator_as && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr && ae1->weight == ae2->weight + && ae1->tag == ae2->tag && ae1->mp_nexthop_len == ae2->mp_nexthop_len && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) @@ -691,6 +693,7 @@ bgp_attr_default_set (struct attr *attr, u_char origin) attr->aspath = aspath_empty (); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; + attr->extra->tag = 0; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 000ceaaf7..0bbb91233 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -92,6 +92,9 @@ struct attr_extra uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ + + /* route tag */ + u_short tag; }; /* BGP core attribute structure. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 93902deab..bab99616f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5605,7 +5605,7 @@ ALIAS (no_ipv6_aggregate_address_summary_only, void bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, const struct in6_addr *nexthop6, - u_int32_t metric, u_char type) + u_int32_t metric, u_char type, u_short tag) { struct bgp *bgp; struct listnode *node, *nnode; @@ -5632,6 +5632,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + attr.extra->tag = tag; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { @@ -6292,7 +6293,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, VTY_NEWLINE); } - /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */ + /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, Int/Ext/Local, Atomic, best */ vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) @@ -6305,6 +6306,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (attr->extra && attr->extra->weight != 0) vty_out (vty, ", weight %u", attr->extra->weight); + + if (attr->extra && attr->extra->tag != 0) + vty_out (vty, ", tag %d", attr->extra->tag); if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) vty_out (vty, ", invalid"); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 81df8fa79..324e006b4 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -221,7 +221,7 @@ extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, const struct in6_addr *, - u_int32_t, u_char); + u_int32_t, u_char, u_short); extern void bgp_redistribute_delete (struct prefix *, u_char); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index a9b6b5025..204644ab5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -71,7 +71,7 @@ o Cisco route-map length : (This will not be implemented by bgpd) metric : Done route-type : (This will not be implemented by bgpd) - tag : (This will not be implemented by bgpd) + tag : Done local-preference : Done set as-path prepend : Done @@ -91,7 +91,7 @@ o Cisco route-map metric : Done metric-type : Not yet origin : Done - tag : (This will not be implemented by bgpd) + tag : Done weight : Done o Local extensions @@ -1004,6 +1004,72 @@ struct route_map_rule_cmd route_match_probability_cmd = /* `set ip next-hop IP_ADDRESS' */ +/* Match function return 1 if match is success else return zero. */ +static route_map_result_t +route_match_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_short *tag; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + tag = rule; + bgp_info = object; + + if (!bgp_info->attr->extra) + return RMAP_NOMATCH; + + return ((bgp_info->attr->extra->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH); + } + + return RMAP_NOMATCH; +} + + +/* Route map `match tag' match statement. `arg' is TAG value */ +static void * +route_match_tag_compile (const char *arg) +{ + u_short *tag; + u_short tmp; + + /* tag value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + tmp = atoi(arg); + if (tmp < 1) + return NULL; + + tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); + + if (!tag) + return tag; + + *tag = tmp; + + return tag; +} + + +/* Free route map's compiled 'match tag' value. */ +static void +route_match_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag matching. */ +struct route_map_rule_cmd route_match_tag_cmd = +{ + "tag", + route_match_tag, + route_match_tag_compile, + route_match_tag_free, +}; + + /* Set nexthop to object. ojbect must be pointer to struct attr. */ struct rmap_ip_nexthop_set { @@ -1777,6 +1843,73 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = route_set_aggregator_as_free, }; +/* Set tag to object. object must be pointer to struct bgp_info */ +static route_map_result_t +route_set_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_short *tag; + struct bgp_info *bgp_info; + struct attr_extra *ae; + + if (type == RMAP_BGP) + { + tag = rule; + bgp_info = object; + ae = bgp_attr_extra_get (bgp_info->attr); + + /* Set tag value */ + ae->tag=*tag; + + } + + return RMAP_OKAY; +} + +/* Route map `tag' compile function. Given string is converted to u_short. */ +static void * +route_set_tag_compile (const char *arg) +{ + u_short *tag; + u_short tmp; + + /* tag value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + tmp = atoi(arg); + + if (tmp < 1) + return NULL; + + tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); + + if (!tag) + return tag; + + *tag = tmp; + + return tag; +} + +/* Free route map's tag value. */ +static void +route_set_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + + +/* Route map commands for tag set. */ +struct route_map_rule_cmd route_set_tag_cmd = +{ + "tag", + route_set_tag, + route_set_tag_compile, + route_set_tag_free, +}; + + /* `match ipv6 address IP_ACCESS_LIST' */ static route_map_result_t @@ -2998,6 +3131,37 @@ ALIAS (no_match_origin, "local IGP\n" "unknown heritage\n") +DEFUN (match_tag, + match_tag_cmd, + "match tag <1-65535>", + MATCH_STR + "Match tag of route\n" + "Tag value\n") +{ + return bgp_route_match_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_match_tag, + no_match_tag_cmd, + "no match tag", + NO_STR + MATCH_STR + "Match tag of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "tag", NULL); + + return bgp_route_match_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_match_tag, + no_match_tag_val_cmd, + "no match tag <1-65535>", + NO_STR + MATCH_STR + "Match tag of route\n" + "Tag value\n") + DEFUN (set_ip_nexthop, set_ip_nexthop_cmd, "set ip next-hop A.B.C.D", @@ -3663,6 +3827,38 @@ ALIAS (no_set_aggregator_as, "AS number\n" "IP address of aggregator\n") +DEFUN (set_tag, + set_tag_cmd, + "set tag <1-65535>", + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + return bgp_route_set_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_set_tag, + no_set_tag_cmd, + "no set tag", + NO_STR + SET_STR + "Tag value for routing protocol\n") +{ + if (argc == 0) + bgp_route_set_delete(vty, vty->index, "tag", NULL); + + return bgp_route_set_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_set_tag, + no_set_tag_val_cmd, + "no set tag <1-65535>", + NO_STR + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") + + DEFUN (match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD", @@ -3979,6 +4175,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); route_map_install_match (&route_match_probability_cmd); + route_map_install_match (&route_match_tag_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_local_pref_cmd); @@ -3995,6 +4192,7 @@ bgp_route_map_init (void) route_map_install_set (&route_set_originator_id_cmd); route_map_install_set (&route_set_ecommunity_rt_cmd); route_map_install_set (&route_set_ecommunity_soo_cmd); + route_map_install_set (&route_set_tag_cmd); install_element (RMAP_NODE, &match_peer_cmd); install_element (RMAP_NODE, &match_peer_local_cmd); @@ -4043,6 +4241,9 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_val_cmd); + install_element (RMAP_NODE, &match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_val_cmd); install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd); @@ -4094,6 +4295,9 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &set_originator_id_cmd); install_element (RMAP_NODE, &no_set_originator_id_cmd); install_element (RMAP_NODE, &no_set_originator_id_val_cmd); + install_element (RMAP_NODE, &set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_val_cmd); route_map_install_match (&route_match_ipv6_address_cmd); route_map_install_match (&route_match_ipv6_next_hop_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5283d74b1..6c57a6f26 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -296,8 +296,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, api.metric, api.tag); } - bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, - api.metric, api.type); + bgp_redistribute_add ((struct prefix *)&p, &nexthop, NULL, + api.metric, api.type, api.tag); } else { @@ -388,7 +388,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, api.tag); } bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, - api.metric, api.type); + api.metric, api.type, api.tag); } else { @@ -705,6 +705,9 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa flags = 0; peer = info->peer; + if ((info->attr->extra) && (info->attr->extra->tag != 0)) + tag = info->attr->extra->tag; + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { SET_FLAG (flags, ZEBRA_FLAG_IBGP); @@ -758,10 +761,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa api.metric = info->attr->med; if (tag) - { - SET_FLAG (api.message, ZAPI_MESSAGE_TAG); - api.tag = tag; - } + { + SET_FLAG (api.message, ZAPI_MESSAGE_TAG); + api.tag = tag; + } distance = bgp_distance_apply (p, info, bgp); @@ -1005,13 +1008,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if ((info->attr->extra) && (info->attr->extra->tag != 0)) + { + SET_FLAG(api.message, ZAPI_MESSAGE_TAG); + api.tag = info->attr->extra->tag; + } + if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u", + zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, - api.metric); + api.metric, + api.tag); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, @@ -1033,13 +1043,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; + if ((info->attr->extra) && (info->attr->extra->tag != 0)) + { + SET_FLAG(api.message, ZAPI_MESSAGE_TAG); + api.tag = info->attr->extra->tag; + } + if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; - zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u", + zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, - api.metric); + api.metric, + api.tag); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 81adf3585..924cffe2c 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -181,7 +181,7 @@ foreach (@ARGV) { } } -my $bad_cli_stomps = 96; +my $bad_cli_stomps = 102; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. From fb214471c88616d67ece3734128ef04ed4a8ed86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Chyt=C5=82a?= Date: Tue, 1 Dec 2015 13:47:06 -0500 Subject: [PATCH 1132/1342] zebra: add support for route tags [Forward ported by Cumulus] Documentation ------------- All ipv4 and ipv6 static route commands now have a "tag" option which allows the user to set a tag between 1 and 65535. quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag ? <1-65535> Tag value quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag 40 quagga(config)# quagga# show ip route 1.1.1.1/32 Routing entry for 1.1.1.1/32 Known via "static", distance 1, metric 0, tag 40, best * 10.1.1.1, via swp1 quagga# The route-map parser supports matching on tags and setting tags ! route-map MATCH_TAG_18 permit 10 match tag 18 ! ! route-map SET_TAG_22 permit 10 set tag 22 ! BGP and OSPF support: - matching on tags when redistribing routes from the RIB into BGP/OSPF. - setting tags when redistribing routes from the RIB into BGP/OSPF. BGP also supports setting a tag via a table-map, when installing BGP routes into the RIB. Signed-off-by: Daniel Walton Signed-off-by: Piotr Chytla Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 1498 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1490 insertions(+), 8 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 08144cb8d..a14f68b92 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -93,6 +93,10 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, if (vrf_id_str) VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); + /* tag */ + if (tag_str) + tag = atoi(tag_str); + /* Null0 static route. */ if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)) { @@ -469,6 +473,39 @@ DEFUN (ip_route, NULL, NULL, NULL, NULL); } +DEFUN (ip_route_tag, + ip_route_tag_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], NULL, NULL); +} + +DEFUN (ip_route_tag_vrf, + ip_route_tag_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], NULL, argv[3]); +} + DEFUN (ip_route_flags, ip_route_flags_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", @@ -484,6 +521,42 @@ DEFUN (ip_route_flags, argv[2], NULL, NULL, NULL); } +DEFUN (ip_route_flags_tag, + ip_route_flags_tag_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") + +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], NULL, NULL); +} + +DEFUN (ip_route_flags_tag_vrf, + ip_route_flags_tag_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], NULL, argv[4]); +} + DEFUN (ip_route_flags2, ip_route_flags2_cmd, "ip route A.B.C.D/M (reject|blackhole)", @@ -497,6 +570,37 @@ DEFUN (ip_route_flags2, NULL, argv[1], NULL, NULL, NULL); } +DEFUN (ip_route_flags2_tag, + ip_route_flags2_tag_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, + argv[1], argv[2], NULL, NULL); +} + +DEFUN (ip_route_flags2_tag_vrf, + ip_route_flags2_tag_vrf_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, + argv[1], argv[2], NULL, argv[3]); +} + /* Mask as A.B.C.D format. */ DEFUN (ip_route_mask, ip_route_mask_cmd, @@ -513,6 +617,42 @@ DEFUN (ip_route_mask, argv[2], NULL, NULL, NULL, NULL); } +DEFUN (ip_route_mask_tag, + ip_route_mask_tag_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n") + +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + NULL, argv[3], NULL, NULL); +} + +DEFUN (ip_route_mask_tag_vrf, + ip_route_mask_tag_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + NULL, argv[3], NULL, argv[4]); +} + DEFUN (ip_route_mask_flags, ip_route_mask_flags_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", @@ -529,6 +669,43 @@ DEFUN (ip_route_mask_flags, argv[2], argv[3], NULL, NULL, NULL); } +DEFUN (ip_route_mask_flags_tag, + ip_route_mask_flags_tag_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], argv[4], NULL, NULL); +} + +DEFUN (ip_route_mask_flags_tag_vrf, + ip_route_mask_flags_tag_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], argv[3], argv[4], NULL, argv[5]); +} + DEFUN (ip_route_mask_flags2, ip_route_mask_flags2_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole)", @@ -543,6 +720,39 @@ DEFUN (ip_route_mask_flags2, NULL, argv[2], NULL, NULL, NULL); } +DEFUN (ip_route_mask_flags2_tag, + ip_route_mask_flags2_tag_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], NULL, NULL); +} + +DEFUN (ip_route_mask_flags2_tag_vrf, + ip_route_mask_flags2_tag_vrf_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], NULL, argv[4]); +} + /* Distance option value. */ DEFUN (ip_route_distance, ip_route_distance_cmd, @@ -559,6 +769,41 @@ DEFUN (ip_route_distance, argv[1], NULL, NULL, argv[2], NULL); } +DEFUN (ip_route_tag_distance, + ip_route_tag_distance_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], argv[3], NULL); +} + +DEFUN (ip_route_tag_distance_vrf, + ip_route_tag_distance_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + argv[1], NULL, argv[2], argv[3], argv[4]); +} + DEFUN (ip_route_flags_distance, ip_route_flags_distance_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", @@ -575,6 +820,43 @@ DEFUN (ip_route_flags_distance, argv[2], NULL, argv[3], NULL); } +DEFUN (ip_route_flags_tag_distance, + ip_route_flags_tag_distance_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (ip_route_flags_tag_distance_vrf, + ip_route_flags_tag_distance_vrf_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], argv[5]); +} + DEFUN (ip_route_flags_distance2, ip_route_flags_distance2_cmd, "ip route A.B.C.D/M (reject|blackhole) <1-255>", @@ -589,6 +871,39 @@ DEFUN (ip_route_flags_distance2, NULL, argv[1], NULL, argv[2], NULL); } +DEFUN (ip_route_flags_tag_distance2, + ip_route_flags_tag_distance2_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], argv[2], argv[3], NULL); +} + +DEFUN (ip_route_flags_tag_distance2_vrf, + ip_route_flags_tag_distance2_vrf_cmd, + "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, + NULL, argv[1], argv[2], argv[3], argv[4]); +} + DEFUN (ip_route_mask_distance, ip_route_mask_distance_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", @@ -605,6 +920,83 @@ DEFUN (ip_route_mask_distance, NULL, NULL, argv[3], NULL); } +DEFUN (ip_route_mask_tag_distance, + ip_route_mask_tag_distance_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (ip_route_mask_tag_distance_vrf, + ip_route_mask_tag_distance_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], argv[5]); +} + + +DEFUN (ip_route_mask_flags_tag_distance, + ip_route_mask_flags_tag_distance_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], NULL); +} + +DEFUN (ip_route_mask_flags_tag_distance_vrf, + ip_route_mask_flags_tag_distance_vrf_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], argv[6]); +} + DEFUN (ip_route_mask_flags_distance, ip_route_mask_flags_distance_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", @@ -637,7 +1029,42 @@ DEFUN (ip_route_mask_flags_distance2, NULL, argv[2], NULL, argv[3], NULL); } -DEFUN (no_ip_route, +DEFUN (ip_route_mask_flags_tag_distance2, + ip_route_mask_flags_tag_distance2_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (ip_route_mask_flags_tag_distance2_vrf, + ip_route_mask_flags_tag_distance2_vrf_cmd, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], argv[5]); +} + +DEFUN (no_ip_route, no_ip_route_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", NO_STR @@ -652,6 +1079,41 @@ DEFUN (no_ip_route, argv[1], NULL, NULL, NULL, NULL); } +DEFUN (no_ip_route_tag, + no_ip_route_tag_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], NULL, NULL); +} + +DEFUN (no_ip_route_tag_vrf, + no_ip_route_tag_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], NULL, argv[3]); +} + ALIAS (no_ip_route, no_ip_route_flags_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", @@ -664,6 +1126,20 @@ ALIAS (no_ip_route, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ip_route_tag, + no_ip_route_flags_tag_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") + DEFUN (no_ip_route_flags2, no_ip_route_flags2_cmd, "no ip route A.B.C.D/M (reject|blackhole)", @@ -678,6 +1154,39 @@ DEFUN (no_ip_route_flags2, NULL, NULL, NULL, NULL, NULL); } +DEFUN (no_ip_route_flags2_tag, + no_ip_route_flags2_tag_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + NULL, argv[1], NULL, NULL); +} + +DEFUN (no_ip_route_flags2_tag_vrf, + no_ip_route_flags2_tag_vrf_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + NULL, argv[1], NULL, argv[2]); +} + DEFUN (no_ip_route_mask, no_ip_route_mask_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", @@ -694,6 +1203,24 @@ DEFUN (no_ip_route_mask, argv[2], NULL, NULL, NULL, NULL); } +DEFUN (no_ip_route_mask_tag, + no_ip_route_mask_tag_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], + NULL, argv[3], NULL, NULL); +} + ALIAS (no_ip_route_mask, no_ip_route_mask_flags_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", @@ -707,6 +1234,21 @@ ALIAS (no_ip_route_mask, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ip_route_mask_tag, + no_ip_route_mask_flags_tag_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") + DEFUN (no_ip_route_mask_flags2, no_ip_route_mask_flags2_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole)", @@ -722,6 +1264,41 @@ DEFUN (no_ip_route_mask_flags2, NULL, NULL, NULL, NULL, NULL); } +DEFUN (no_ip_route_mask_flags2_tag, + no_ip_route_mask_flags2_tag_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, argv[2], NULL, NULL); +} + +DEFUN (no_ip_route_mask_flags2_tag_vrf, + no_ip_route_mask_flags2_tag_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + NULL, NULL, argv[2], NULL, argv[3]); +} + DEFUN (no_ip_route_distance, no_ip_route_distance_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", @@ -738,6 +1315,43 @@ DEFUN (no_ip_route_distance, argv[1], NULL, NULL, argv[2], NULL); } +DEFUN (no_ip_route_tag_distance, + no_ip_route_tag_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], argv[3], NULL); +} + +DEFUN (no_ip_route_tag_distance_vrf, + no_ip_route_tag_distance_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + NULL, argv[2], argv[3], argv[4]); +} + DEFUN (no_ip_route_flags_distance, no_ip_route_flags_distance_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", @@ -755,6 +1369,45 @@ DEFUN (no_ip_route_flags_distance, argv[1], argv[2], NULL, argv[3], NULL); } +DEFUN (no_ip_route_flags_tag_distance, + no_ip_route_flags_tag_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (no_ip_route_flags_tag_distance_vrf, + no_ip_route_flags_tag_distance_vrf_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4], argv[5]); +} + DEFUN (no_ip_route_flags_distance2, no_ip_route_flags_distance2_cmd, "no ip route A.B.C.D/M (reject|blackhole) <1-255>", @@ -770,6 +1423,41 @@ DEFUN (no_ip_route_flags_distance2, argv[1], NULL, argv[2], NULL); } +DEFUN (no_ip_route_flags_tag_distance2, + no_ip_route_flags_tag_distance2_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], argv[2] , argv[3], NULL); +} + +DEFUN (no_ip_route_flags_tag_distance2_vrf, + no_ip_route_flags_tag_distance2_vrf_cmd, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, + argv[1], argv[2] , argv[3], argv[4]); +} + DEFUN (no_ip_route_mask_distance, no_ip_route_mask_distance_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", @@ -787,6 +1475,45 @@ DEFUN (no_ip_route_mask_distance, argv[2], NULL, NULL, argv[3], NULL); } +DEFUN (no_ip_route_mask_tag_distance, + no_ip_route_mask_tag_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (no_ip_route_mask_tag_distance_vrf, + no_ip_route_mask_tag_distance_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], + argv[2], NULL, argv[3], argv[4], argv[5]); +} + DEFUN (no_ip_route_mask_flags_distance, no_ip_route_mask_flags_distance_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", @@ -805,6 +1532,47 @@ DEFUN (no_ip_route_mask_flags_distance, argv[2], argv[3], NULL, argv[4], NULL); } +DEFUN (no_ip_route_mask_flags_tag_distance, + no_ip_route_mask_flags_tag_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], NULL); +} + +DEFUN (no_ip_route_mask_flags_tag_distance_vrf, + no_ip_route_mask_flags_tag_distance_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6]); +} + DEFUN (no_ip_route_mask_flags_distance2, no_ip_route_mask_flags_distance2_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", @@ -1213,14 +1981,51 @@ DEFUN (no_ip_route_mask_flags_distance2_vrf, argv[2], NULL, argv[3], argv[4]); } -char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ - -DEFUN (ip_protocol, - ip_protocol_cmd, - "ip protocol PROTO route-map ROUTE-MAP", +DEFUN (no_ip_route_mask_flags_tag_distance2, + no_ip_route_mask_flags_tag_distance2_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>", NO_STR - "Apply route map to PROTO\n" - "Protocol name\n" + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], NULL); +} + +DEFUN (no_ip_route_mask_flags_tag_distance2_vrf, + no_ip_route_mask_flags_tag_distance2_vrf_cmd, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Tag of this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR) +{ + return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, + argv[2], argv[3], argv[4], argv[5]); +} + +char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ + +DEFUN (ip_protocol, + ip_protocol_cmd, + "ip protocol PROTO route-map ROUTE-MAP", + NO_STR + "Apply route map to PROTO\n" + "Protocol name\n" "Route map name\n") { int i; @@ -1633,6 +2438,59 @@ DEFUN (show_ipv6_nht, return CMD_SUCCESS; } +DEFUN (show_ip_route_tag, + show_ip_route_tag_cmd, + "show ip route tag <1-65535>", + SHOW_STR + IP_STR + "IP routing table\n" + "Show only routes with tag\n" + "Tag value\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + u_short tag = 0; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argv[0]) + tag = atoi(argv[0]); + + if (argc == 2) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes with matching tag value. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (rib->tag != tag) + continue; + + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +ALIAS (show_ip_route_tag, + show_ip_route_tag_vrf_cmd, + "show ip route tag <1-65535>" VRF_CMD_STR, + SHOW_STR + IP_STR + "IP routing table\n" + "Show only routes with tag\n" + "Tag value\n" + VRF_CMD_HELP_STR) + DEFUN (show_ip_route_prefix_longer, show_ip_route_prefix_longer_cmd, "show ip route A.B.C.D/M longer-prefixes", @@ -2567,6 +3425,10 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, if (tag_str) tag = atoi (tag_str); + /* tag */ + if (tag_str) + tag = atoi(tag_str); + /* When gateway is valid IPv6 addrees, then gate is treated as nexthop address other case gate is treated as interface name. */ ret = inet_pton (AF_INET6, gate_str, &gate_addr); @@ -2622,6 +3484,35 @@ DEFUN (ipv6_route, NULL, NULL); } +DEFUN (ipv6_route_tag, + ipv6_route_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); +} + +DEFUN (ipv6_route_tag_vrf, + ipv6_route_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); +} + DEFUN (ipv6_route_flags, ipv6_route_flags_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", @@ -2637,6 +3528,39 @@ DEFUN (ipv6_route_flags, NULL, NULL); } +DEFUN (ipv6_route_flags_tag, + ipv6_route_flags_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, NULL); +} + +DEFUN (ipv6_route_flags_tag_vrf, + ipv6_route_flags_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, argv[4]); +} + DEFUN (ipv6_route_ifname, ipv6_route_ifname_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", @@ -2650,6 +3574,35 @@ DEFUN (ipv6_route_ifname, NULL, NULL); } +DEFUN (ipv6_route_ifname_tag, + ipv6_route_ifname_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); +} + +DEFUN (ipv6_route_ifname_tag_vrf, + ipv6_route_ifname_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); +} + DEFUN (ipv6_route_ifname_flags, ipv6_route_ifname_flags_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", @@ -2665,6 +3618,39 @@ DEFUN (ipv6_route_ifname_flags, NULL, NULL); } +DEFUN (ipv6_route_ifname_flags_tag, + ipv6_route_ifname_flags_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, NULL); +} + +DEFUN (ipv6_route_ifname_flags_tag_vrf, + ipv6_route_ifname_flags_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, argv[5]); +} + DEFUN (ipv6_route_pref, ipv6_route_pref_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", @@ -2679,6 +3665,37 @@ DEFUN (ipv6_route_pref, NULL); } +DEFUN (ipv6_route_pref_tag, + ipv6_route_pref_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL); +} + +DEFUN (ipv6_route_pref_tag_vrf, + ipv6_route_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]); +} + DEFUN (ipv6_route_flags_pref, ipv6_route_flags_pref_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", @@ -2695,6 +3712,41 @@ DEFUN (ipv6_route_flags_pref, NULL); } +DEFUN (ipv6_route_flags_pref_tag, + ipv6_route_flags_pref_tag_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); +} + +DEFUN (ipv6_route_flags_pref_tag_vrf, + ipv6_route_flags_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); +} + DEFUN (ipv6_route_ifname_pref, ipv6_route_ifname_pref_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", @@ -2709,6 +3761,37 @@ DEFUN (ipv6_route_ifname_pref, NULL); } +DEFUN (ipv6_route_ifname_pref_tag, + ipv6_route_ifname_pref_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (ipv6_route_ifname_pref_tag_vrf, + ipv6_route_ifname_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); +} + DEFUN (ipv6_route_ifname_flags_pref, ipv6_route_ifname_flags_pref_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", @@ -2725,6 +3808,41 @@ DEFUN (ipv6_route_ifname_flags_pref, NULL); } +DEFUN (ipv6_route_ifname_flags_pref_tag, + ipv6_route_ifname_flags_pref_tag_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); +} + +DEFUN (ipv6_route_ifname_flags_pref_tag_vrf, + ipv6_route_ifname_flags_pref_tag_vrf_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); +} + DEFUN (no_ipv6_route, no_ipv6_route_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", @@ -2739,6 +3857,37 @@ DEFUN (no_ipv6_route, NULL); } +DEFUN (no_ipv6_route_tag, + no_ipv6_route_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); +} + +DEFUN (no_ipv6_route_tag_vrf, + no_ipv6_route_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); +} + ALIAS (no_ipv6_route, no_ipv6_route_flags_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", @@ -2751,6 +3900,20 @@ ALIAS (no_ipv6_route, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ipv6_route_tag, + no_ipv6_route_flags_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") + DEFUN (no_ipv6_route_ifname, no_ipv6_route_ifname_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", @@ -2765,6 +3928,37 @@ DEFUN (no_ipv6_route_ifname, NULL); } +DEFUN (no_ipv6_route_ifname_tag, + no_ipv6_route_ifname_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); +} + +DEFUN (no_ipv6_route_ifname_tag_vrf, + no_ipv6_route_ifname_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); +} + ALIAS (no_ipv6_route_ifname, no_ipv6_route_ifname_flags_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", @@ -2777,6 +3971,20 @@ ALIAS (no_ipv6_route_ifname, "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") +ALIAS (no_ipv6_route_ifname_tag, + no_ipv6_route_ifname_flags_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n") + DEFUN (no_ipv6_route_pref, no_ipv6_route_pref_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", @@ -2792,6 +4000,39 @@ DEFUN (no_ipv6_route_pref, NULL); } +DEFUN (no_ipv6_route_pref_tag, + no_ipv6_route_pref_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL); +} + +DEFUN (no_ipv6_route_pref_tag_vrf, + no_ipv6_route_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]); +} + DEFUN (no_ipv6_route_flags_pref, no_ipv6_route_flags_pref_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", @@ -2810,6 +4051,45 @@ DEFUN (no_ipv6_route_flags_pref, NULL); } +DEFUN (no_ipv6_route_flags_pref_tag, + no_ipv6_route_flags_pref_tag_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + /* We do not care about argv[2] */ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); +} + +DEFUN (no_ipv6_route_flags_pref_tag_vrf, + no_ipv6_route_flags_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + /* We do not care about argv[2] */ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); +} + DEFUN (no_ipv6_route_ifname_pref, no_ipv6_route_ifname_pref_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", @@ -2825,6 +4105,39 @@ DEFUN (no_ipv6_route_ifname_pref, NULL); } +DEFUN (no_ipv6_route_ifname_pref_tag, + no_ipv6_route_ifname_pref_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); +} + +DEFUN (no_ipv6_route_ifname_pref_tag_vrf, + no_ipv6_route_ifname_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); +} + DEFUN (no_ipv6_route_ifname_flags_pref, no_ipv6_route_ifname_flags_pref_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", @@ -2842,6 +4155,43 @@ DEFUN (no_ipv6_route_ifname_flags_pref, NULL); } +DEFUN (no_ipv6_route_ifname_flags_pref_tag, + no_ipv6_route_ifname_flags_pref_tag_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); +} + +DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf, + no_ipv6_route_ifname_flags_pref_tag_vrf_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR) +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); +} + DEFUN (ipv6_route_vrf, ipv6_route_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_STR, @@ -3133,6 +4483,59 @@ ALIAS (show_ipv6_route, "IPv6 routing table\n" VRF_CMD_HELP_STR) +DEFUN (show_ipv6_route_tag, + show_ipv6_route_tag_cmd, + "show ipv6 route tag <1-65535>", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Show only routes with tag\n" + "Tag value\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + u_short tag = 0; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (argv[0]) + tag = atoi(argv[0]); + + if (argc == 2) + VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); + + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv6 routes with matching tag value. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + RNODE_FOREACH_RIB (rn, rib) + { + if (rib->tag != tag) + continue; + + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_route_tag, + show_ipv6_route_tag_vrf_cmd, + "show ipv6 route tag <1-65535>" VRF_CMD_STR, + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Show only routes with tag\n" + "Tag value\n" + VRF_CMD_HELP_STR) + DEFUN (show_ipv6_route_prefix_longer, show_ipv6_route_prefix_longer_cmd, "show ipv6 route X:X::X:X/M longer-prefixes", @@ -3887,31 +5290,78 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ip_protocol_cmd); install_element (VIEW_NODE, &show_ip_protocol_cmd); install_element (CONFIG_NODE, &ip_route_cmd); + install_element (CONFIG_NODE, &ip_route_tag_cmd); + install_element (CONFIG_NODE, &ip_route_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags2_cmd); + install_element (CONFIG_NODE, &ip_route_flags2_tag_cmd); + install_element (CONFIG_NODE, &ip_route_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags2_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_flags2_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags2_tag_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_distance_cmd); + install_element (CONFIG_NODE, &ip_route_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_distance_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_vrf_cmd); install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_route_tag_cmd); + install_element (VIEW_NODE, &show_ip_route_tag_vrf_cmd); install_element (VIEW_NODE, &show_ip_nht_cmd); install_element (VIEW_NODE, &show_ipv6_nht_cmd); install_element (VIEW_NODE, &show_ip_route_addr_cmd); @@ -3996,7 +5446,39 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd); + install_element (CONFIG_NODE, &ipv6_route_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_vrf_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_route_tag_cmd); + install_element (VIEW_NODE, &show_ipv6_route_tag_vrf_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); From 3b4fb574b414e7b7776b581688f189f2fc736a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Chyt=C5=82a?= Date: Tue, 1 Dec 2015 10:16:02 -0500 Subject: [PATCH 1133/1342] ripd, ripngd: add support for route tags [Forward ported by Cumulus] Documentation ------------- All ipv4 and ipv6 static route commands now have a "tag" option which allows the user to set a tag between 1 and 65535. quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag ? <1-65535> Tag value quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag 40 quagga(config)# quagga# show ip route 1.1.1.1/32 Routing entry for 1.1.1.1/32 Known via "static", distance 1, metric 0, tag 40, best * 10.1.1.1, via swp1 quagga# The route-map parser supports matching on tags and setting tags ! route-map MATCH_TAG_18 permit 10 match tag 18 ! ! route-map SET_TAG_22 permit 10 set tag 22 ! BGP and OSPF support: - matching on tags when redistribing routes from the RIB into BGP/OSPF. - setting tags when redistribing routes from the RIB into BGP/OSPF. BGP also supports setting a tag via a table-map, when installing BGP routes into the RIB. Signed-off-by: Daniel Walton Signed-off-by: Piotr Chytla Signed-off-by: Donald Sharp --- ripd/rip_routemap.c | 23 ++++++++++++++++++----- ripngd/ripng_routemap.c | 8 ++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 9bafdcde1..cc0ed61ff 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -485,9 +485,22 @@ static void * route_match_tag_compile (const char *arg) { u_short *tag; + u_short tmp; + + /* tag value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + tmp = atoi(arg); + if (tmp < 1) + return NULL; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - *tag = atoi (arg); + + if (!tag) + return tag; + + *tag = tmp; return tag; } @@ -937,7 +950,7 @@ ALIAS (no_match_ip_address_prefix_list, DEFUN (match_tag, match_tag_cmd, - "match tag <0-65535>", + "match tag <1-65535>", MATCH_STR "Match tag of route\n" "Metric value\n") @@ -960,7 +973,7 @@ DEFUN (no_match_tag, ALIAS (no_match_tag, no_match_tag_val_cmd, - "no match tag <0-65535>", + "no match tag <1-65535>", NO_STR MATCH_STR "Match tag of route\n" @@ -1060,7 +1073,7 @@ ALIAS (no_set_ip_nexthop, DEFUN (set_tag, set_tag_cmd, - "set tag <0-65535>", + "set tag <1-65535>", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -1083,7 +1096,7 @@ DEFUN (no_set_tag, ALIAS (no_set_tag, no_set_tag_val_cmd, - "no set tag <0-65535>", + "no set tag <1-65535>", NO_STR SET_STR "Tag value for routing protocol\n" diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index f4fadb67e..a316301ab 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -564,7 +564,7 @@ ALIAS (no_match_interface, DEFUN (match_tag, match_tag_cmd, - "match tag <0-65535>", + "match tag <1-65535>", MATCH_STR "Match tag of route\n" "Metric value\n") @@ -587,7 +587,7 @@ DEFUN (no_match_tag, ALIAS (no_match_tag, no_match_tag_val_cmd, - "no match tag <0-65535>", + "no match tag <1-65535>", NO_STR MATCH_STR "Match tag of route\n" @@ -675,7 +675,7 @@ ALIAS (no_set_ipv6_nexthop_local, DEFUN (set_tag, set_tag_cmd, - "set tag <0-65535>", + "set tag <1-65535>", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -698,7 +698,7 @@ DEFUN (no_set_tag, ALIAS (no_set_tag, no_set_tag_val_cmd, - "no set tag <0-65535>", + "no set tag <1-65535>", NO_STR SET_STR "Tag value for routing protocol\n" From 96d1060a704d88e04fcd446cce078a6131c3f6db Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 1 Jul 2016 14:23:45 +0100 Subject: [PATCH 1134/1342] *: Widen width of Zserv routing tag field. * lib/zebra.h: Introduce a route_tag_t type for route tags generally, and make it 4 bytes wide - so it can directly hold things like an ASN, or the OSPF ASE-LSA tag. * zebra/rib.h: Use route_tag_t instead of u_short. * *: Update 'u_short (*)?(tag|tmp)' to use route_tag_t instead of u_short. Update stream_{get,put} to l instead of w. * ospf_zebra.c: (ospf_zebra_add) test OSPF tag within range of ROUTE_TAG_MAX. --- bgpd/bgp_attr.h | 2 +- bgpd/bgp_route.c | 2 +- bgpd/bgp_route.h | 2 +- bgpd/bgp_routemap.c | 12 ++++++------ bgpd/bgp_zebra.c | 6 +++--- lib/zclient.c | 4 ++-- lib/zclient.h | 4 ++-- lib/zebra.h | 3 +++ ospfd/ospf_asbr.c | 2 +- ospfd/ospf_asbr.h | 2 +- ospfd/ospf_lsa.c | 2 +- ospfd/ospf_routemap.c | 12 ++++++------ ospfd/ospf_zebra.c | 8 ++++---- ospfd/ospfd.h | 2 +- ripd/rip_routemap.c | 10 +++++----- zebra/rib.h | 23 +++++++++++++---------- zebra/zebra_rib.c | 12 +++++++----- zebra/zebra_vty.c | 8 ++++---- zebra/zserv.c | 10 +++++----- 19 files changed, 67 insertions(+), 59 deletions(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 0bbb91233..0cd0b7767 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -94,7 +94,7 @@ struct attr_extra struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ /* route tag */ - u_short tag; + route_tag_t tag; }; /* BGP core attribute structure. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index bab99616f..78cd53b1b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5605,7 +5605,7 @@ ALIAS (no_ipv6_aggregate_address_summary_only, void bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, const struct in6_addr *nexthop6, - u_int32_t metric, u_char type, u_short tag) + u_int32_t metric, u_char type, route_tag_t tag) { struct bgp *bgp; struct listnode *node, *nnode; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 324e006b4..2a72daa35 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -221,7 +221,7 @@ extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, const struct in6_addr *, - u_int32_t, u_char, u_short); + u_int32_t, u_char, route_tag_t); extern void bgp_redistribute_delete (struct prefix *, u_char); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 204644ab5..87f0543d5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1009,7 +1009,7 @@ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct bgp_info *bgp_info; if (type == RMAP_BGP) @@ -1031,8 +1031,8 @@ route_match_tag (void *rule, struct prefix *prefix, static void * route_match_tag_compile (const char *arg) { - u_short *tag; - u_short tmp; + route_tag_t *tag; + route_tag_t tmp; /* tag value shoud be integer. */ if (! all_digit (arg)) @@ -1848,7 +1848,7 @@ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct bgp_info *bgp_info; struct attr_extra *ae; @@ -1870,8 +1870,8 @@ route_set_tag (void *rule, struct prefix *prefix, static void * route_set_tag_compile (const char *arg) { - u_short *tag; - u_short tmp; + route_tag_t *tag; + route_tag_t tmp; /* tag value shoud be integer. */ if (! all_digit (arg)) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 6c57a6f26..38fecd9f2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -279,7 +279,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, api.metric = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getw (s); + api.tag = stream_getl (s); else api.tag = 0; @@ -366,7 +366,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, api.metric = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getw (s); + api.tag = stream_getl (s); else api.tag = 0; @@ -694,7 +694,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa struct bgp_info *mpinfo; size_t oldsize, newsize; u_int32_t nhcount; - u_short tag = 0; + route_tag_t tag = 0; if (zclient->sock < 0) return; diff --git a/lib/zclient.c b/lib/zclient.c index a1de831f3..eb8de1a88 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -591,7 +591,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) stream_putl (s, api->mtu); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) - stream_putw (s, api->tag); + stream_putl (s, api->tag); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); @@ -649,7 +649,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) stream_putl (s, api->mtu); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) - stream_putw (s, api->tag); + stream_putl (s, api->tag); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); diff --git a/lib/zclient.h b/lib/zclient.h index 810c927c8..d46728dac 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -133,7 +133,7 @@ struct zapi_ipv4 u_char distance; - u_short tag; + route_tag_t tag; u_int32_t metric; @@ -213,7 +213,7 @@ struct zapi_ipv6 u_char distance; - u_short tag; + route_tag_t tag; u_int32_t metric; diff --git a/lib/zebra.h b/lib/zebra.h index a75eb6d18..a405d46eb 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -535,4 +535,7 @@ typedef u_int16_t zebra_command_t; /* VRF ID type. */ typedef u_int16_t vrf_id_t; +typedef uint32_t route_tag_t; +#define ROUTE_TAG_MAX UINT32_MAX + #endif /* _ZEBRA_H */ diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 4b536903a..0a411e434 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -136,7 +136,7 @@ ospf_route_map_set_compare (struct route_map_set_values *values1, struct external_info * ospf_external_info_add (u_char type, struct prefix_ipv4 p, ifindex_t ifindex, struct in_addr nexthop, - u_short tag) + route_tag_t tag) { struct external_info *new; struct route_node *rn; diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 2709a6c0a..bc41a149e 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -63,7 +63,7 @@ extern struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, ifindex_t, struct in_addr, - u_short); + route_tag_t); extern void ospf_external_info_delete (u_char, struct prefix_ipv4); extern struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 4341cd9fe..d7954399a 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1649,7 +1649,7 @@ ospf_external_lsa_body_set (struct stream *s, struct external_info *ei, /* Put forwarding address. */ stream_put_ipv4 (s, fwd_addr.s_addr); - /* Put route tag -- only first 16bits are used for compatibility */ + /* Put route tag */ stream_putl (s, ei->tag); } diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 7bd6c3d96..f044e3828 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -422,7 +422,7 @@ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct external_info *ei; if (type == RMAP_OSPF) @@ -440,8 +440,8 @@ route_match_tag (void *rule, struct prefix *prefix, static void * route_match_tag_compile (const char *arg) { - u_short *tag; - u_short tmp; + route_tag_t *tag; + route_tag_t tmp; /* tag value shoud be integer. */ if (! all_digit (arg)) @@ -596,7 +596,7 @@ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct external_info *ei; if (type == RMAP_OSPF) @@ -615,8 +615,8 @@ route_set_tag (void *rule, struct prefix *prefix, static void * route_set_tag_compile (const char *arg) { - u_short *tag; - u_short tmp; + route_tag_t *tag; + route_tag_t tmp; /* tag value shoud be integer. */ if (! all_digit (arg)) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index ce268cd2a..60d98529d 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -370,10 +370,10 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) if (distance) SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); - /* Check if path type is ASE and use only 16bit tags */ + /* Check if path type is ASE */ if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) || (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) && - (or->u.ext.tag > 0) && (or->u.ext.tag < UINT16_MAX)) + (or->u.ext.tag > 0) && (or->u.ext.tag <= ROUTE_TAG_MAX)) SET_FLAG (message, ZAPI_MESSAGE_TAG); /* Make packet. */ @@ -444,7 +444,7 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) } if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) - stream_putw (s, (u_short)or->u.ext.tag); + stream_putl (s, or->u.ext.tag); stream_putw_at (s, 0, stream_get_endp (s)); @@ -900,7 +900,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient, if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getw (s); + api.tag = stream_getl (s); else api.tag = 0; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 4181d1142..0315164b6 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -239,7 +239,7 @@ struct ospf } dmetric [ZEBRA_ROUTE_MAX + 1]; /* Redistribute tag info. */ - u_short dtag [ZEBRA_ROUTE_MAX + 1]; + route_tag_t dtag [ZEBRA_ROUTE_MAX + 1]; /* For redistribute route map. */ struct diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index cc0ed61ff..9bb963881 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -463,7 +463,7 @@ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct rip_info *rinfo; if (type == RMAP_RIP) @@ -484,8 +484,8 @@ route_match_tag (void *rule, struct prefix *prefix, static void * route_match_tag_compile (const char *arg) { - u_short *tag; - u_short tmp; + route_tag_t *tag; + route_tag_t tmp; /* tag value shoud be integer. */ if (! all_digit (arg)) @@ -687,7 +687,7 @@ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct rip_info *rinfo; if(type == RMAP_RIP) @@ -708,7 +708,7 @@ route_set_tag (void *rule, struct prefix *prefix, static void * route_set_tag_compile (const char *arg) { - u_short *tag; + route_tag_t *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); diff --git a/zebra/rib.h b/zebra/rib.h index d31db5579..0191f57ec 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -23,6 +23,7 @@ #ifndef _ZEBRA_RIB_H #define _ZEBRA_RIB_H +#include "zebra.h" #include "linklist.h" #include "prefix.h" #include "table.h" @@ -43,6 +44,9 @@ struct rib /* Refrence count. */ unsigned long refcnt; + /* Tag */ + route_tag_t tag; + /* Uptime. */ time_t uptime; @@ -65,9 +69,6 @@ struct rib /* Distance. */ u_char distance; - /* Tag */ - u_short tag; - /* Flags of this route. * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed * to clients via Zserv @@ -182,7 +183,7 @@ struct static_route u_char distance; /* Tag */ - u_short tag; + route_tag_t tag; /* Flag for this static route's type. */ u_char type; @@ -450,11 +451,12 @@ extern unsigned long rib_score_proto (u_char proto); extern int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char flags, u_short tag, u_char distance, - vrf_id_t vrf_id); + const char *ifname, u_char flags, route_tag_t, + u_char distance, vrf_id_t vrf_id); extern int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id); + const char *ifname, route_tag_t tag, u_char distance, + vrf_id_t vrf_id); extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, @@ -474,15 +476,16 @@ extern struct route_table *rib_table_ipv6; extern int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_short tag, u_char distance, - vrf_id_t vrf_id); + const char *ifname, u_char flags, route_tag_t, + u_char distance, vrf_id_t vrf_id); extern int rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t); extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id); + const char *ifname, route_tag_t, u_char distance, + vrf_id_t vrf_id); extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index e57d1afe1..405528cef 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2314,8 +2314,8 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_char flags, u_short tag, u_char distance, - vrf_id_t vrf_id) + const char *ifname, u_char flags, route_tag_t tag, + u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2411,7 +2411,8 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, - const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id) + const char *ifname, route_tag_t tag, u_char distance, + vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2797,7 +2798,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_short tag, + const char *ifname, u_char flags, route_tag_t tag, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; @@ -2895,7 +2896,8 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Delete static route from static route configuration. */ int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id) + const char *ifname, route_tag_t tag, u_char distance, + vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a14f68b92..38f61e9d2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -54,7 +54,7 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, struct in_addr mask; const char *ifname; u_char flag = 0; - u_short tag = 0; + route_tag_t tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (dest_str, &p); @@ -2451,7 +2451,7 @@ DEFUN (show_ip_route_tag, struct route_node *rn; struct rib *rib; int first = 1; - u_short tag = 0; + route_tag_t tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; if (argv[0]) @@ -3386,7 +3386,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, u_char type = 0; vrf_id_t vrf_id = VRF_DEFAULT; u_char flag = 0; - u_short tag = 0; + route_tag_t tag = 0; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -4496,7 +4496,7 @@ DEFUN (show_ipv6_route_tag, struct route_node *rn; struct rib *rib; int first = 1; - u_short tag = 0; + route_tag_t tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; if (argv[0]) diff --git a/zebra/zserv.c b/zebra/zserv.c index 89232c27c..2319a0674 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -498,7 +498,7 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, if (rib->tag) { SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG); - stream_putw(s, rib->tag); + stream_putl (s, rib->tag); } } @@ -1011,7 +1011,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) rib->mtu = stream_getl (s); /* Tag */ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) - rib->tag = stream_getw (s); + rib->tag = stream_getl (s); /* Table */ rib->table=zebrad.rtm_table_default; @@ -1098,7 +1098,7 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) /* tag */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getw (s); + api.tag = stream_getl (s); else api.tag = 0; @@ -1251,7 +1251,7 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) /* Tag */ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) - rib->tag = stream_getw (s); + rib->tag = stream_getl (s); /* Table */ rib->table=zebrad.rtm_table_default; @@ -1322,7 +1322,7 @@ zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) /* tag */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getw (s); + api.tag = stream_getl (s); else api.tag = 0; From f2eb9caac6425473af8d6d15534439fe715f7426 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:47:21 -0700 Subject: [PATCH 1135/1342] bgpd: atomic-aggregate is lost when we aggregate another aggregate that has atomic-aggregate This patch ensures that we don't accidently loose the atomic-aggregate when we aggregate another aggregate that also has atomic-aggregates. Signed-off-by: Daniel Walton --- bgpd/bgp_attr.c | 5 +++-- bgpd/bgp_attr.h | 2 +- bgpd/bgp_route.c | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ac67c6274..3b96bb24f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -724,7 +724,8 @@ bgp_attr_default_intern (u_char origin) struct attr * bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, struct aspath *aspath, - struct community *community, int as_set) + struct community *community, int as_set, + u_char atomic_aggregate) { struct attr attr; struct attr *new; @@ -757,7 +758,7 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, attre.weight = BGP_ATTR_DEFAULT_WEIGHT; attre.mp_nexthop_len = IPV6_MAX_BYTELEN; - if (! as_set) + if (! as_set || atomic_aggregate) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 0cd0b7767..8457f4022 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -168,7 +168,7 @@ extern struct attr *bgp_attr_default_set (struct attr *attr, u_char); extern struct attr *bgp_attr_default_intern (u_char); extern struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, - struct community *, int as_set); + struct community *, int as_set, u_char); extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 78cd53b1b..7f98f94f6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4753,6 +4753,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, struct bgp_info *new; int first = 1; unsigned long match = 0; + u_char atomic_aggregate = 0; /* ORIGIN attribute: If at least one route among routes that are aggregated has ORIGIN with the value INCOMPLETE, then the @@ -4797,6 +4798,9 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, } #endif /* AGGREGATE_NEXTHOP_CHECK */ + if (ri->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) + atomic_aggregate = 1; + if (ri->sub_type != BGP_ROUTE_AGGREGATE) { if (aggregate->summary_only) @@ -4883,7 +4887,8 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, rn = bgp_node_get (table, p); new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self, bgp_attr_aggregate_intern(bgp, origin, aspath, community, - aggregate->as_set), rn); + aggregate->as_set, + atomic_aggregate), rn); SET_FLAG (new->flags, BGP_INFO_VALID); bgp_info_add (rn, new); @@ -4989,6 +4994,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct aspath *asmerge = NULL; struct community *community = NULL; struct community *commerge = NULL; + u_char atomic_aggregate = 0; table = bgp->rib[afi][safi]; @@ -5010,6 +5016,9 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, if (BGP_INFO_HOLDDOWN (ri)) continue; + if (ri->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) + atomic_aggregate = 1; + if (ri->sub_type != BGP_ROUTE_AGGREGATE) { /* summary-only aggregate route suppress aggregated @@ -5073,7 +5082,8 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, rn = bgp_node_get (table, p); new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self, bgp_attr_aggregate_intern(bgp, origin, aspath, community, - aggregate->as_set), rn); + aggregate->as_set, + atomic_aggregate), rn); SET_FLAG (new->flags, BGP_INFO_VALID); bgp_info_add (rn, new); From c7f25b90902d4be39132b1174440746b571220ce Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:47:22 -0700 Subject: [PATCH 1136/1342] bgpd, ospfd, ospf6d, ripd, ripngd, zebra: 'set metric -12' is broken in the parser Signed-off-by: Daniel Walton --- bgpd/bgp_routemap.c | 20 ++++++++++---------- ospf6d/ospf6_asbr.c | 6 +++--- ospfd/ospf_routemap.c | 31 +++++++++++++++++++++++-------- ripd/rip_routemap.c | 16 ++++++++-------- ripngd/ripng_routemap.c | 16 ++++++++-------- zebra/zebra_routemap.c | 16 ++++++++-------- 6 files changed, 60 insertions(+), 45 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 87f0543d5..c66f260e8 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2397,10 +2397,10 @@ bgp_route_match_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -2420,10 +2420,10 @@ bgp_route_match_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -2443,10 +2443,10 @@ bgp_route_set_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -2466,10 +2466,10 @@ bgp_route_set_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -3575,7 +3575,7 @@ DEFUN (set_community_delete, SET_STR "set BGP community list (for deletion)\n" "Community-list number (standard)\n" - "Communitly-list number (expanded)\n" + "Community-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") { @@ -3608,7 +3608,7 @@ ALIAS (no_set_community_delete, SET_STR "set BGP community list (for deletion)\n" "Community-list number (standard)\n" - "Communitly-list number (expanded)\n" + "Community-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 617f8d622..4b7d214aa 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -978,13 +978,13 @@ route_map_command_status (struct vty *vty, int ret) switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "Can't find rule.%s", VNL); + vty_out (vty, "OSPF6 Can't find rule.%s", VNL); break; case RMAP_COMPILE_ERROR: - vty_out (vty, "Argument is malformed.%s", VNL); + vty_out (vty, "OSPF6 Argument is malformed.%s", VNL); break; default: - vty_out (vty, "route-map add set failed.%s", VNL); + vty_out (vty, "OSPF6 route-map add set failed.%s", VNL); break; } return CMD_WARNING; diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index f044e3828..dc4181204 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -108,10 +108,10 @@ ospf_route_match_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -131,10 +131,10 @@ ospf_route_match_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -154,10 +154,10 @@ ospf_route_set_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -178,10 +178,10 @@ ospf_route_set_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -506,6 +506,21 @@ route_set_metric_compile (const char *arg) u_int32_t *metric; int32_t ret; + /* OSPF doesn't support the +/- in + set metric <+/-metric> check + Ignore the +/- component */ + if (! all_digit (arg)) + { + if ((strncmp (arg, "+", 1) == 0 || strncmp (arg, "-", 1) == 0) && + all_digit (arg+1)) + { + zlog_warn ("OSPF does not support 'set metric +/-'"); + arg++; + } + else + return NULL; + } + metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); ret = atoi (arg); diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 9bb963881..20d3e6e50 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -58,10 +58,10 @@ rip_route_match_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -81,10 +81,10 @@ rip_route_match_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -104,7 +104,7 @@ rip_route_set_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: /* rip, ripng and other protocols share the set metric command @@ -112,7 +112,7 @@ rip_route_set_add (struct vty *vty, struct route_map_index *index, if metric is out of range for rip and ripng, it is not for other protocols. Do not return an error */ if (strcmp(command, "metric")) { - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -133,10 +133,10 @@ rip_route_set_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index a316301ab..eae4566a6 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -55,10 +55,10 @@ ripng_route_match_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -77,10 +77,10 @@ ripng_route_match_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -99,10 +99,10 @@ ripng_route_set_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -121,10 +121,10 @@ ripng_route_set_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index bf7e335e5..5a6a96bf0 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -46,10 +46,10 @@ zebra_route_match_add(struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -69,10 +69,10 @@ zebra_route_match_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -92,10 +92,10 @@ zebra_route_set_add (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } @@ -115,10 +115,10 @@ zebra_route_set_delete (struct vty *vty, struct route_map_index *index, switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: - vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } From 9ae8552c7341071ffac34aec9902fa3dd7dc8fdf Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Tue, 19 May 2015 17:47:22 -0700 Subject: [PATCH 1137/1342] zebra: Gather and display detailed info about clients of Zebra The display of zebra client info is rather paltry: just the name and the FD. For troubleshooting and general helpfulness, its useful to gather more info about each client and display that. This patch does just that. Signed-off-by: Dinesh Dutt --- zebra/redistribute.c | 44 +++++++--- zebra/zebra_rib.c | 5 +- zebra/zebra_rnh.c | 3 + zebra/zserv.c | 201 +++++++++++++++++++++++++++++++++++++++++-- zebra/zserv.h | 28 ++++++ 5 files changed, 260 insertions(+), 21 deletions(-) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 6c5491763..a7a6b2580 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -159,7 +159,10 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); + { + client->redist_v4_add_cnt++; + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); + } } #ifdef HAVE_IPV6 @@ -171,7 +174,10 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); + { + client->redist_v6_add_cnt++; + zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); + } #endif /* HAVE_IPV6 */ } @@ -188,11 +194,15 @@ redistribute_add (struct prefix *p, struct rib *rib) || vrf_bitmap_check (client->redist[rib->type], rib->vrf_id)) { if (p->family == AF_INET) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); -#ifdef HAVE_IPV6 + { + client->redist_v4_add_cnt++; + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); + } if (p->family == AF_INET6) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); -#endif /* HAVE_IPV6 */ + { + client->redist_v6_add_cnt++; + zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); + } } } } @@ -299,7 +309,9 @@ zebra_interface_down_update (struct interface *ifp) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp); + { + zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp); + } } /* Interface information update. */ @@ -315,7 +327,8 @@ zebra_interface_add_update (struct interface *ifp) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) { - zsend_interface_add (client, ifp); + client->ifadd_cnt++; + zsend_interface_add (client, ifp); zsend_interface_link_params (client, ifp); } } @@ -331,7 +344,10 @@ zebra_interface_delete_update (struct interface *ifp) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) - zsend_interface_delete (client, ifp); + { + client->ifdel_cnt++; + zsend_interface_delete (client, ifp); + } } /* Interface address addition. */ @@ -360,7 +376,10 @@ zebra_interface_address_add_update (struct interface *ifp, for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) - zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); + { + client->connected_rt_add_cnt++; + zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); + } } /* Interface address deletion. */ @@ -386,7 +405,10 @@ zebra_interface_address_delete_update (struct interface *ifp, for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) - zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); + { + client->connected_rt_del_cnt++; + zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); + } } /* Interface parameters update */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 405528cef..abb9560ab 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1910,6 +1910,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) struct route_node *rn; struct rib *same; struct nexthop *nexthop; + int ret = 0; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id); @@ -1952,6 +1953,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* Link new rib to node.*/ rib_addnode (rn, rib); + ret = 1; if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", @@ -1969,10 +1971,11 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) rib_dump (p, same); } rib_delnode (rn, same); + ret = -1; } route_unlock_node (rn); - return 0; + return ret; } /* XXX factor with rib_delete_ipv6 */ diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 3e02812db..db2a34d53 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -531,6 +531,9 @@ send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) stream_putc (s, 0); } stream_putw_at (s, 0, stream_get_endp (s)); + + client->nh_last_upd_time = quagga_time(NULL); + client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE; return zebra_server_send_message(client); } diff --git a/zebra/zserv.c b/zebra/zserv.c index 2319a0674..4a8b55f97 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -101,6 +101,8 @@ zserv_flush_data(struct thread *thread) case BUFFER_EMPTY: break; } + + client->last_write_time = quagga_time(NULL); return 0; } @@ -109,6 +111,9 @@ zebra_server_send_message(struct zserv *client) { if (client->t_suicide) return -1; + + stream_set_getp(client->obuf, 0); + client->last_write_cmd = stream_getw_from(client->obuf, 4); switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), stream_get_endp(client->obuf))) { @@ -130,6 +135,8 @@ zebra_server_send_message(struct zserv *client) zserv_flush_data, client, client->sock); break; } + + client->last_write_time = quagga_time(NULL); return 0; } @@ -201,6 +208,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface (s, ifp); + client->ifadd_cnt++; return zebra_server_send_message(client); } @@ -220,6 +228,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface (s, ifp); + client->ifdel_cnt++; return zebra_server_send_message (client); } @@ -334,6 +343,7 @@ zsend_interface_address (int cmd, struct zserv *client, /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); + client->connected_rt_add_cnt++; return zebra_server_send_message(client); } @@ -362,6 +372,11 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) zserv_create_header (s, cmd, ifp->vrf_id); zserv_encode_interface (s, ifp); + if (cmd == ZEBRA_INTERFACE_UP) + client->ifup_cnt++; + else + client->ifdown_cnt++; + return zebra_server_send_message(client); } @@ -579,7 +594,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } #endif /* HAVE_IPV6 */ @@ -748,6 +763,8 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); l += PSIZE(p.prefixlen); rnh = zebra_add_rnh(&p, 0); + + client->nh_reg_time = quagga_time(NULL); zebra_add_rnh_client(rnh, client, vrf_id); } zebra_evaluate_rnh_table(0, AF_INET); @@ -779,7 +796,10 @@ zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) l += PSIZE(p.prefixlen); rnh = zebra_lookup_rnh(&p, 0); if (rnh) - zebra_remove_rnh_client(rnh, client); + { + client->nh_dereg_time = quagga_time(NULL); + zebra_remove_rnh_client(rnh, client); + } } return 0; } @@ -843,7 +863,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } @@ -937,7 +957,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) ifindex_t ifindex; u_char ifname_len; safi_t safi; - + int ret; /* Get input stream. */ s = client->ibuf; @@ -1015,7 +1035,13 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) /* Table */ rib->table=zebrad.rtm_table_default; - rib_add_ipv4_multipath (&p, rib, safi); + ret = rib_add_ipv4_multipath (&p, rib, safi); + + /* Stats */ + if (ret > 0) + client->v4_route_add_cnt++; + else if (ret < 0) + client->v4_route_upd8_cnt++; return 0; } @@ -1104,6 +1130,7 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, vrf_id, api.safi); + client->v4_route_del_cnt++; return 0; } @@ -1165,6 +1192,7 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) safi_t safi; static struct in6_addr nexthops[MULTIPATH_NUM]; static unsigned int ifindices[MULTIPATH_NUM]; + int ret; /* Get input stream. */ s = client->ibuf; @@ -1255,7 +1283,13 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) /* Table */ rib->table=zebrad.rtm_table_default; - rib_add_ipv6_multipath (&p, rib, safi); + ret = rib_add_ipv6_multipath (&p, rib, safi); + /* Stats */ + if (ret > 0) + client->v6_route_add_cnt++; + else if (ret < 0) + client->v6_route_upd8_cnt++; + return 0; } @@ -1332,6 +1366,8 @@ zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id, api.safi); + + client->v6_route_del_cnt++; return 0; } @@ -1492,6 +1528,7 @@ zebra_client_create (int sock) client->redist_default = vrf_bitmap_init (); client->ifinfo = vrf_bitmap_init (); client->ridinfo = vrf_bitmap_init (); + client->connect_time = quagga_time(NULL); /* Add this client to linked list. */ listnode_add (zebrad.client_list, client); @@ -1607,6 +1644,9 @@ zebra_client_read (struct thread *thread) zlog_debug ("zebra message received [%s] %d in VRF %u", zserv_command_string (command), length, vrf_id); + client->last_read_time = quagga_time(NULL); + client->last_read_cmd = command; + switch (command) { case ZEBRA_ROUTER_ID_ADD: @@ -1869,6 +1909,127 @@ zebra_event (enum event event, int sock, struct zserv *client) } } +#define ZEBRA_TIME_BUF 32 +static char * +zserv_time_buf(time_t *time1, char *buf, int buflen) +{ + struct tm *tm; + time_t now; + + assert (buf != NULL); + assert (buflen >= ZEBRA_TIME_BUF); + assert (time1 != NULL); + + if (!*time1) + { + snprintf(buf, buflen, "never "); + return (buf); + } + + now = quagga_time(NULL); + now -= *time1; + tm = gmtime(&now); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (now < ONE_DAY_SECOND) + snprintf (buf, buflen, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (now < ONE_WEEK_SECOND) + snprintf (buf, buflen, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, buflen, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +static void +zebra_show_client_detail (struct vty *vty, struct zserv *client) +{ + char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; + char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; + + vty_out (vty, "Client: %s %s", + zebra_route_string(client->proto), VTY_NEWLINE); + vty_out (vty, "------------------------ %s", VTY_NEWLINE); + vty_out (vty, "FD: %d %s", client->sock, VTY_NEWLINE); + vty_out (vty, "Route Table ID: %d %s", client->rtm_table, VTY_NEWLINE); + + vty_out (vty, "Connect Time: %s %s", + zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + if (client->nh_reg_time) + { + vty_out (vty, "Nexthop Registry Time: %s %s", + zserv_time_buf(&client->nh_reg_time, nhbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + if (client->nh_last_upd_time) + vty_out (vty, "Nexthop Last Update Time: %s %s", + zserv_time_buf(&client->nh_last_upd_time, mbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + else + vty_out (vty, "No Nexthop Update sent%s", VTY_NEWLINE); + } + else + vty_out (vty, "Not registered for Nexthop Updates%s", VTY_NEWLINE); + + vty_out (vty, "Last Msg Rx Time: %s %s", + zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + vty_out (vty, "Last Msg Tx Time: %s %s", + zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF), + VTY_NEWLINE); + if (client->last_read_time) + vty_out (vty, "Last Rcvd Cmd: %s %s", + zserv_command_string(client->last_read_cmd), VTY_NEWLINE); + if (client->last_write_time) + vty_out (vty, "Last Sent Cmd: %s %s", + zserv_command_string(client->last_write_cmd), VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, "Type Add Update Del %s", VTY_NEWLINE); + vty_out (vty, "================================================== %s", VTY_NEWLINE); + vty_out (vty, "IPv4 %-12d%-12d%-12d%s", client->v4_route_add_cnt, + client->v4_route_upd8_cnt, client->v4_route_del_cnt, VTY_NEWLINE); + vty_out (vty, "IPv6 %-12d%-12d%-12d%s", client->v6_route_add_cnt, + client->v6_route_upd8_cnt, client->v6_route_del_cnt, VTY_NEWLINE); + vty_out (vty, "Redist:v4 %-12d%-12d%-12d%s", client->redist_v4_add_cnt, 0, + client->redist_v4_del_cnt, VTY_NEWLINE); + vty_out (vty, "Redist:v6 %-12d%-12d%-12d%s", client->redist_v6_add_cnt, 0, + client->redist_v6_del_cnt, VTY_NEWLINE); + vty_out (vty, "Connected %-12d%-12d%-12d%s", client->ifadd_cnt, 0, + client->ifdel_cnt, VTY_NEWLINE); + vty_out (vty, "Interface Up Notifications: %d%s", client->ifup_cnt, + VTY_NEWLINE); + vty_out (vty, "Interface Down Notifications: %d%s", client->ifdown_cnt, + VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); + return; +} + +static void +zebra_show_client_brief (struct vty *vty, struct zserv *client) +{ + char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; + char wbuf[ZEBRA_TIME_BUF]; + + vty_out (vty, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d%s", + zebra_route_string(client->proto), + zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF), + zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF), + zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF), + client->v4_route_add_cnt+client->v4_route_upd8_cnt, + client->v4_route_del_cnt, + client->v6_route_add_cnt+client->v6_route_upd8_cnt, + client->v6_route_del_cnt, VTY_NEWLINE); + +} + + /* Display default rtm_table for all clients. */ DEFUN (show_table, show_table_cmd, @@ -1946,10 +2107,31 @@ DEFUN (show_zebra_client, struct zserv *client; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - vty_out (vty, "Client %s fd %d%s", - zebra_route_string(client->proto), client->sock, - VTY_NEWLINE); + zebra_show_client_detail(vty, client); + + return CMD_SUCCESS; +} + +/* This command is for debugging purpose. */ +DEFUN (show_zebra_client_summary, + show_zebra_client_summary_cmd, + "show zebra client summary", + SHOW_STR + "Zebra information brief" + "Client information brief") +{ + struct listnode *node; + struct zserv *client; + + vty_out (vty, "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes %s", + VTY_NEWLINE); + vty_out (vty,"--------------------------------------------------------------------------------%s", + VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) + zebra_show_client_brief(vty, client); + vty_out (vty, "Routes column shows (added+updated)/deleted%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -2128,6 +2310,7 @@ zebra_init (void) install_element (CONFIG_NODE, &ip_forwarding_cmd); install_element (CONFIG_NODE, &no_ip_forwarding_cmd); install_element (ENABLE_NODE, &show_zebra_client_cmd); + install_element (ENABLE_NODE, &show_zebra_client_summary_cmd); #ifdef HAVE_NETLINK install_element (VIEW_NODE, &show_table_cmd); diff --git a/zebra/zserv.h b/zebra/zserv.h index 7a2b4a1d1..4af92f0e1 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -70,6 +70,34 @@ struct zserv /* client's protocol */ u_char proto; + + /* Statistics */ + u_int32_t redist_v4_add_cnt; + u_int32_t redist_v4_del_cnt; + u_int32_t redist_v6_add_cnt; + u_int32_t redist_v6_del_cnt; + u_int32_t v4_route_add_cnt; + u_int32_t v4_route_upd8_cnt; + u_int32_t v4_route_del_cnt; + u_int32_t v6_route_add_cnt; + u_int32_t v6_route_del_cnt; + u_int32_t v6_route_upd8_cnt; + u_int32_t connected_rt_add_cnt; + u_int32_t connected_rt_del_cnt; + u_int32_t ifup_cnt; + u_int32_t ifdown_cnt; + u_int32_t ifadd_cnt; + u_int32_t ifdel_cnt; + + time_t connect_time; + time_t last_read_time; + time_t last_write_time; + time_t nh_reg_time; + time_t nh_dereg_time; + time_t nh_last_upd_time; + + int last_read_cmd; + int last_write_cmd; }; /* Zebra instance */ From 9e518dd52b1fbf7d395a6bb49a101d632ced5e5b Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:47:26 -0700 Subject: [PATCH 1138/1342] bgpd: Alow gracefull shutdown of peers Send CEASE NOTIFICATIONS to all peers on "no router bgp" Signed-off-by: Daniel Walton --- bgpd/bgpd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 7f472c595..669782dfc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2210,6 +2210,17 @@ bgp_delete (struct bgp *bgp) THREAD_OFF (bgp->t_startup); + for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) + { + if (peer->status == Established || + peer->status == OpenSent || + peer->status == OpenConfirm) + { + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_PEER_UNCONFIG); + } + } + /* Delete static route. */ bgp_static_delete (bgp); From 988a50c54dbd20290c085a36d4c2893f3d515803 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:58:11 -0700 Subject: [PATCH 1139/1342] bgpd, lib: Clarify the different permutations of soft clearing a peer Cleanup vtysh output for the soft clearing of a bgp peer so that it is clearer what is going to happen. Signed-off-by: Daniel Walton --- bgpd/bgp_vty.c | 418 ++++++++++++++++++++++++------------------------- lib/command.h | 4 + 2 files changed, 213 insertions(+), 209 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 406ecb127..7af4e81a8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4978,8 +4978,8 @@ DEFUN (clear_ip_bgp_all_soft_out, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, @@ -4996,7 +4996,7 @@ ALIAS (clear_ip_bgp_all_soft_out, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) ALIAS (clear_ip_bgp_all_soft_out, clear_ip_bgp_instance_all_soft_out_cmd, @@ -5007,8 +5007,8 @@ ALIAS (clear_ip_bgp_all_soft_out, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_all_ipv4_soft_out, clear_ip_bgp_all_ipv4_soft_out_cmd, @@ -5020,8 +5020,8 @@ DEFUN (clear_ip_bgp_all_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, @@ -5041,7 +5041,7 @@ ALIAS (clear_ip_bgp_all_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, clear_ip_bgp_instance_all_ipv4_soft_out_cmd, @@ -5055,7 +5055,7 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, @@ -5074,8 +5074,8 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft_out, "Clear all peers\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_OUT, NULL); @@ -5090,7 +5090,7 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_out, "Clear all peers\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_all_encap_soft_out, clear_ip_bgp_all_encap_soft_out_cmd, @@ -5125,8 +5125,8 @@ DEFUN (clear_bgp_all_soft_out, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, @@ -5144,8 +5144,8 @@ ALIAS (clear_bgp_all_soft_out, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_all_soft_out, clear_bgp_all_out_cmd, @@ -5153,7 +5153,7 @@ ALIAS (clear_bgp_all_soft_out, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_all_soft_out, clear_bgp_ipv6_all_soft_out_cmd, @@ -5162,8 +5162,8 @@ ALIAS (clear_bgp_all_soft_out, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_all_soft_out, clear_bgp_ipv6_all_out_cmd, @@ -5172,7 +5172,7 @@ ALIAS (clear_bgp_all_soft_out, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_bgp_ipv6_safi_prefix, clear_bgp_ipv6_safi_prefix_cmd, @@ -5197,8 +5197,8 @@ DEFUN (clear_ip_bgp_peer_soft_out, IP_STR BGP_STR "BGP neighbor address to clear\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5211,7 +5211,7 @@ ALIAS (clear_ip_bgp_peer_soft_out, IP_STR BGP_STR "BGP neighbor address to clear\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_peer_ipv4_soft_out, clear_ip_bgp_peer_ipv4_soft_out_cmd, @@ -5223,8 +5223,8 @@ DEFUN (clear_ip_bgp_peer_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, @@ -5244,7 +5244,7 @@ ALIAS (clear_ip_bgp_peer_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, clear_ip_bgp_peer_vpnv4_soft_out_cmd, @@ -5255,8 +5255,8 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5271,7 +5271,7 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_peer_encap_soft_out, clear_ip_bgp_peer_encap_soft_out_cmd, @@ -5307,8 +5307,8 @@ DEFUN (clear_bgp_peer_soft_out, BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5322,8 +5322,8 @@ ALIAS (clear_bgp_peer_soft_out, "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_peer_soft_out, clear_bgp_peer_out_cmd, @@ -5332,7 +5332,7 @@ ALIAS (clear_bgp_peer_soft_out, BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_peer_soft_out, clear_bgp_ipv6_peer_out_cmd, @@ -5342,7 +5342,7 @@ ALIAS (clear_bgp_peer_soft_out, "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_peer_group_soft_out, clear_ip_bgp_peer_group_soft_out_cmd, @@ -5352,8 +5352,8 @@ DEFUN (clear_ip_bgp_peer_group_soft_out, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5367,7 +5367,7 @@ ALIAS (clear_ip_bgp_peer_group_soft_out, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, clear_ip_bgp_peer_group_ipv4_soft_out_cmd, @@ -5380,8 +5380,8 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, @@ -5402,7 +5402,7 @@ ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_bgp_peer_group_soft_out, clear_bgp_peer_group_soft_out_cmd, @@ -5411,8 +5411,8 @@ DEFUN (clear_bgp_peer_group_soft_out, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5426,8 +5426,8 @@ ALIAS (clear_bgp_peer_group_soft_out, "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_peer_group_out_cmd, @@ -5436,7 +5436,7 @@ ALIAS (clear_bgp_peer_group_soft_out, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_ipv6_peer_group_out_cmd, @@ -5446,7 +5446,7 @@ ALIAS (clear_bgp_peer_group_soft_out, "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_external_soft_out, clear_ip_bgp_external_soft_out_cmd, @@ -5455,8 +5455,8 @@ DEFUN (clear_ip_bgp_external_soft_out, IP_STR BGP_STR "Clear all external peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); @@ -5469,7 +5469,7 @@ ALIAS (clear_ip_bgp_external_soft_out, IP_STR BGP_STR "Clear all external peers\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_external_ipv4_soft_out, clear_ip_bgp_external_ipv4_soft_out_cmd, @@ -5481,8 +5481,8 @@ DEFUN (clear_ip_bgp_external_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, @@ -5502,7 +5502,7 @@ ALIAS (clear_ip_bgp_external_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_bgp_external_soft_out, clear_bgp_external_soft_out_cmd, @@ -5510,8 +5510,8 @@ DEFUN (clear_bgp_external_soft_out, CLEAR_STR BGP_STR "Clear all external peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); @@ -5524,8 +5524,8 @@ ALIAS (clear_bgp_external_soft_out, BGP_STR "Address family\n" "Clear all external peers\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_external_soft_out, clear_bgp_external_out_cmd, @@ -5533,7 +5533,7 @@ ALIAS (clear_bgp_external_soft_out, CLEAR_STR BGP_STR "Clear all external peers\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_external_soft_out, clear_bgp_ipv6_external_out_cmd, @@ -5542,7 +5542,7 @@ ALIAS (clear_bgp_external_soft_out, BGP_STR "Address family\n" "Clear all external peers\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_soft_out, clear_ip_bgp_as_soft_out_cmd, @@ -5551,8 +5551,8 @@ DEFUN (clear_ip_bgp_as_soft_out, IP_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5565,7 +5565,7 @@ ALIAS (clear_ip_bgp_as_soft_out, IP_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_ipv4_soft_out, clear_ip_bgp_as_ipv4_soft_out_cmd, @@ -5577,8 +5577,8 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, @@ -5598,7 +5598,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_out, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_vpnv4_soft_out, clear_ip_bgp_as_vpnv4_soft_out_cmd, @@ -5609,8 +5609,8 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_out, "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5625,7 +5625,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out, "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_encap_soft_out, clear_ip_bgp_as_encap_soft_out_cmd, @@ -5660,8 +5660,8 @@ DEFUN (clear_bgp_as_soft_out, CLEAR_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); @@ -5674,8 +5674,8 @@ ALIAS (clear_bgp_as_soft_out, BGP_STR "Address family\n" "Clear peers with the AS number\n" - "Soft reconfig\n" - "Soft reconfig outbound update\n") + BGP_SOFT_STR + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_as_soft_out, clear_bgp_as_out_cmd, @@ -5683,7 +5683,7 @@ ALIAS (clear_bgp_as_soft_out, CLEAR_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) ALIAS (clear_bgp_as_soft_out, clear_bgp_ipv6_as_out_cmd, @@ -5692,7 +5692,7 @@ ALIAS (clear_bgp_as_soft_out, BGP_STR "Address family\n" "Clear peers with the AS number\n" - "Soft reconfig outbound update\n") + BGP_SOFT_OUT_STR) /* Inbound soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft_in, @@ -5702,8 +5702,8 @@ DEFUN (clear_ip_bgp_all_soft_in, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, @@ -5722,8 +5722,8 @@ ALIAS (clear_ip_bgp_all_soft_in, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_ip_bgp_all_soft_in, clear_ip_bgp_all_in_cmd, @@ -5732,7 +5732,7 @@ ALIAS (clear_ip_bgp_all_soft_in, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_all_in_prefix_filter, clear_ip_bgp_all_in_prefix_filter_cmd, @@ -5741,7 +5741,7 @@ DEFUN (clear_ip_bgp_all_in_prefix_filter, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { if (argc== 1) @@ -5761,7 +5761,7 @@ ALIAS (clear_ip_bgp_all_in_prefix_filter, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") @@ -5775,8 +5775,8 @@ DEFUN (clear_ip_bgp_all_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, @@ -5796,7 +5796,7 @@ ALIAS (clear_ip_bgp_all_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, clear_ip_bgp_instance_all_ipv4_soft_in_cmd, @@ -5810,8 +5810,8 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, @@ -5831,7 +5831,7 @@ DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) @@ -5852,7 +5852,7 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) @@ -5872,8 +5872,8 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft_in, "Clear all peers\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_IN, NULL); @@ -5888,7 +5888,7 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_in, "Clear all peers\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_all_encap_soft_in, clear_ip_bgp_all_encap_soft_in_cmd, @@ -5923,8 +5923,8 @@ DEFUN (clear_bgp_all_soft_in, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, @@ -5942,8 +5942,8 @@ ALIAS (clear_bgp_all_soft_in, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_bgp_all_soft_in, clear_bgp_ipv6_all_soft_in_cmd, @@ -5952,8 +5952,8 @@ ALIAS (clear_bgp_all_soft_in, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_bgp_all_soft_in, clear_bgp_all_in_cmd, @@ -5961,7 +5961,7 @@ ALIAS (clear_bgp_all_soft_in, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) ALIAS (clear_bgp_all_soft_in, clear_bgp_ipv6_all_in_cmd, @@ -5970,7 +5970,7 @@ ALIAS (clear_bgp_all_soft_in, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_bgp_all_in_prefix_filter, clear_bgp_all_in_prefix_filter_cmd, @@ -5978,7 +5978,7 @@ DEFUN (clear_bgp_all_in_prefix_filter, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, @@ -5992,7 +5992,7 @@ ALIAS (clear_bgp_all_in_prefix_filter, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_peer_soft_in, @@ -6002,8 +6002,8 @@ DEFUN (clear_ip_bgp_peer_soft_in, IP_STR BGP_STR "BGP neighbor address to clear\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6016,7 +6016,7 @@ ALIAS (clear_ip_bgp_peer_soft_in, IP_STR BGP_STR "BGP neighbor address to clear\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_peer_in_prefix_filter, clear_ip_bgp_peer_in_prefix_filter_cmd, @@ -6025,7 +6025,7 @@ DEFUN (clear_ip_bgp_peer_in_prefix_filter, IP_STR BGP_STR "BGP neighbor address to clear\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out the existing ORF prefix-list\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, @@ -6042,8 +6042,8 @@ DEFUN (clear_ip_bgp_peer_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, @@ -6063,7 +6063,7 @@ ALIAS (clear_ip_bgp_peer_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd, @@ -6075,7 +6075,7 @@ DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out the existing ORF prefix-list\n") { if (strncmp (argv[1], "m", 1) == 0) @@ -6095,8 +6095,8 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft_in, "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6111,7 +6111,7 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_peer_encap_soft_in, clear_ip_bgp_peer_encap_soft_in_cmd, @@ -6147,8 +6147,8 @@ DEFUN (clear_bgp_peer_soft_in, BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6162,8 +6162,8 @@ ALIAS (clear_bgp_peer_soft_in, "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_bgp_peer_soft_in, clear_bgp_peer_in_cmd, @@ -6172,7 +6172,7 @@ ALIAS (clear_bgp_peer_soft_in, BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) ALIAS (clear_bgp_peer_soft_in, clear_bgp_ipv6_peer_in_cmd, @@ -6182,7 +6182,7 @@ ALIAS (clear_bgp_peer_soft_in, "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_bgp_peer_in_prefix_filter, clear_bgp_peer_in_prefix_filter_cmd, @@ -6191,7 +6191,7 @@ DEFUN (clear_bgp_peer_in_prefix_filter, BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out the existing ORF prefix-list\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, @@ -6206,7 +6206,7 @@ ALIAS (clear_bgp_peer_in_prefix_filter, "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out the existing ORF prefix-list\n") DEFUN (clear_ip_bgp_peer_group_soft_in, @@ -6217,8 +6217,8 @@ DEFUN (clear_ip_bgp_peer_group_soft_in, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6232,7 +6232,7 @@ ALIAS (clear_ip_bgp_peer_group_soft_in, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, clear_ip_bgp_peer_group_in_prefix_filter_cmd, @@ -6242,7 +6242,7 @@ DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, @@ -6260,8 +6260,8 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, @@ -6282,7 +6282,7 @@ ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd, @@ -6295,7 +6295,7 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) @@ -6313,8 +6313,8 @@ DEFUN (clear_bgp_peer_group_soft_in, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6328,8 +6328,8 @@ ALIAS (clear_bgp_peer_group_soft_in, "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_peer_group_in_cmd, @@ -6338,7 +6338,7 @@ ALIAS (clear_bgp_peer_group_soft_in, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_ipv6_peer_group_in_cmd, @@ -6348,7 +6348,7 @@ ALIAS (clear_bgp_peer_group_soft_in, "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_bgp_peer_group_in_prefix_filter, clear_bgp_peer_group_in_prefix_filter_cmd, @@ -6357,7 +6357,7 @@ DEFUN (clear_bgp_peer_group_in_prefix_filter, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, @@ -6372,7 +6372,7 @@ ALIAS (clear_bgp_peer_group_in_prefix_filter, "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_external_soft_in, @@ -6382,8 +6382,8 @@ DEFUN (clear_ip_bgp_external_soft_in, IP_STR BGP_STR "Clear all external peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); @@ -6396,7 +6396,7 @@ ALIAS (clear_ip_bgp_external_soft_in, IP_STR BGP_STR "Clear all external peers\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_external_in_prefix_filter, clear_ip_bgp_external_in_prefix_filter_cmd, @@ -6405,7 +6405,7 @@ DEFUN (clear_ip_bgp_external_in_prefix_filter, IP_STR BGP_STR "Clear all external peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, @@ -6422,8 +6422,8 @@ DEFUN (clear_ip_bgp_external_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, @@ -6443,7 +6443,7 @@ ALIAS (clear_ip_bgp_external_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd, @@ -6455,7 +6455,7 @@ DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) @@ -6472,8 +6472,8 @@ DEFUN (clear_bgp_external_soft_in, CLEAR_STR BGP_STR "Clear all external peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); @@ -6486,8 +6486,8 @@ ALIAS (clear_bgp_external_soft_in, BGP_STR "Address family\n" "Clear all external peers\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_bgp_external_soft_in, clear_bgp_external_in_cmd, @@ -6495,7 +6495,7 @@ ALIAS (clear_bgp_external_soft_in, CLEAR_STR BGP_STR "Clear all external peers\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) ALIAS (clear_bgp_external_soft_in, clear_bgp_ipv6_external_in_cmd, @@ -6504,7 +6504,7 @@ ALIAS (clear_bgp_external_soft_in, BGP_STR "Address family\n" "Clear all external peers\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_bgp_external_in_prefix_filter, clear_bgp_external_in_prefix_filter_cmd, @@ -6512,7 +6512,7 @@ DEFUN (clear_bgp_external_in_prefix_filter, CLEAR_STR BGP_STR "Clear all external peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, @@ -6526,7 +6526,7 @@ ALIAS (clear_bgp_external_in_prefix_filter, BGP_STR "Address family\n" "Clear all external peers\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_as_soft_in, @@ -6536,8 +6536,8 @@ DEFUN (clear_ip_bgp_as_soft_in, IP_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6550,7 +6550,7 @@ ALIAS (clear_ip_bgp_as_soft_in, IP_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_as_in_prefix_filter, clear_ip_bgp_as_in_prefix_filter_cmd, @@ -6559,7 +6559,7 @@ DEFUN (clear_ip_bgp_as_in_prefix_filter, IP_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, @@ -6576,8 +6576,8 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, @@ -6597,7 +6597,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_in, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, @@ -6609,7 +6609,7 @@ DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) @@ -6629,8 +6629,8 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_in, "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6645,7 +6645,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in, "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_as_encap_soft_in, clear_ip_bgp_as_encap_soft_in_cmd, @@ -6680,8 +6680,8 @@ DEFUN (clear_bgp_as_soft_in, CLEAR_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); @@ -6694,8 +6694,8 @@ ALIAS (clear_bgp_as_soft_in, BGP_STR "Address family\n" "Clear peers with the AS number\n" - "Soft reconfig\n" - "Soft reconfig inbound update\n") + BGP_SOFT_STR + BGP_SOFT_IN_STR) ALIAS (clear_bgp_as_soft_in, clear_bgp_as_in_cmd, @@ -6703,7 +6703,7 @@ ALIAS (clear_bgp_as_soft_in, CLEAR_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) ALIAS (clear_bgp_as_soft_in, clear_bgp_ipv6_as_in_cmd, @@ -6712,7 +6712,7 @@ ALIAS (clear_bgp_as_soft_in, BGP_STR "Address family\n" "Clear peers with the AS number\n" - "Soft reconfig inbound update\n") + BGP_SOFT_IN_STR) DEFUN (clear_bgp_as_in_prefix_filter, clear_bgp_as_in_prefix_filter_cmd, @@ -6720,7 +6720,7 @@ DEFUN (clear_bgp_as_in_prefix_filter, CLEAR_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, @@ -6734,7 +6734,7 @@ ALIAS (clear_bgp_as_in_prefix_filter, BGP_STR "Address family\n" "Clear peers with the AS number\n" - "Soft reconfig inbound update\n" + BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n") /* Both soft-reconfiguration */ @@ -6745,7 +6745,7 @@ DEFUN (clear_ip_bgp_all_soft, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, @@ -6764,7 +6764,7 @@ ALIAS (clear_ip_bgp_all_soft, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) DEFUN (clear_ip_bgp_all_ipv4_soft, @@ -6777,7 +6777,7 @@ DEFUN (clear_ip_bgp_all_ipv4_soft, "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, @@ -6799,7 +6799,7 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_soft, "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, @@ -6818,7 +6818,7 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft, "Clear all peers\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -6845,7 +6845,7 @@ DEFUN (clear_bgp_all_soft, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, @@ -6863,7 +6863,7 @@ ALIAS (clear_bgp_all_soft, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) ALIAS (clear_bgp_all_soft, clear_bgp_ipv6_all_soft_cmd, @@ -6872,7 +6872,7 @@ ALIAS (clear_bgp_all_soft, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) DEFUN (clear_ip_bgp_peer_soft, clear_ip_bgp_peer_soft_cmd, @@ -6881,7 +6881,7 @@ DEFUN (clear_ip_bgp_peer_soft, IP_STR BGP_STR "BGP neighbor address to clear\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -6897,7 +6897,7 @@ DEFUN (clear_ip_bgp_peer_ipv4_soft, "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, @@ -6916,7 +6916,7 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft, "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -6944,7 +6944,7 @@ DEFUN (clear_bgp_peer_soft, BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -6958,7 +6958,7 @@ ALIAS (clear_bgp_peer_soft, "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig\n") + BGP_SOFT_STR) DEFUN (clear_ip_bgp_peer_group_soft, clear_ip_bgp_peer_group_soft_cmd, @@ -6968,7 +6968,7 @@ DEFUN (clear_ip_bgp_peer_group_soft, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -6985,7 +6985,7 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_soft, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, @@ -7002,7 +7002,7 @@ DEFUN (clear_bgp_peer_group_soft, BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -7016,7 +7016,7 @@ ALIAS (clear_bgp_peer_group_soft, "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - "Soft reconfig\n") + BGP_SOFT_STR) DEFUN (clear_ip_bgp_external_soft, clear_ip_bgp_external_soft_cmd, @@ -7025,7 +7025,7 @@ DEFUN (clear_ip_bgp_external_soft, IP_STR BGP_STR "Clear all external peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); @@ -7041,7 +7041,7 @@ DEFUN (clear_ip_bgp_external_ipv4_soft, "Address family\n" "Address Family modifier\n" "Address Family modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, @@ -7057,7 +7057,7 @@ DEFUN (clear_bgp_external_soft, CLEAR_STR BGP_STR "Clear all external peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); @@ -7070,7 +7070,7 @@ ALIAS (clear_bgp_external_soft, BGP_STR "Address family\n" "Clear all external peers\n" - "Soft reconfig\n") + BGP_SOFT_STR) DEFUN (clear_ip_bgp_as_soft, clear_ip_bgp_as_soft_cmd, @@ -7079,7 +7079,7 @@ DEFUN (clear_ip_bgp_as_soft, IP_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -7095,7 +7095,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft, "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, @@ -7114,7 +7114,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft, "Clear peers with the AS number\n" "Address family\n" "Address Family Modifier\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -7141,7 +7141,7 @@ DEFUN (clear_bgp_as_soft, CLEAR_STR BGP_STR "Clear peers with the AS number\n" - "Soft reconfig\n") + BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); @@ -7154,7 +7154,7 @@ ALIAS (clear_bgp_as_soft, BGP_STR "Address family\n" "Clear peers with the AS number\n" - "Soft reconfig\n") + BGP_SOFT_STR) /* RS-client soft reconfiguration. */ DEFUN (clear_bgp_all_rsclient, @@ -7163,7 +7163,7 @@ DEFUN (clear_bgp_all_rsclient, CLEAR_STR BGP_STR "Clear all peers\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, @@ -7180,7 +7180,7 @@ ALIAS (clear_bgp_all_rsclient, BGP_STR "Address family\n" "Clear all peers\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_all_rsclient, clear_bgp_instance_all_rsclient_cmd, @@ -7190,7 +7190,7 @@ ALIAS (clear_bgp_all_rsclient, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_all_rsclient, clear_bgp_ipv6_instance_all_rsclient_cmd, @@ -7201,7 +7201,7 @@ ALIAS (clear_bgp_all_rsclient, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (clear_ip_bgp_all_rsclient, clear_ip_bgp_all_rsclient_cmd, @@ -7210,7 +7210,7 @@ DEFUN (clear_ip_bgp_all_rsclient, IP_STR BGP_STR "Clear all peers\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, @@ -7229,7 +7229,7 @@ ALIAS (clear_ip_bgp_all_rsclient, "BGP view\n" "view name\n" "Clear all peers\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (clear_bgp_peer_rsclient, clear_bgp_peer_rsclient_cmd, @@ -7238,7 +7238,7 @@ DEFUN (clear_bgp_peer_rsclient, BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 2) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_peer, @@ -7256,7 +7256,7 @@ ALIAS (clear_bgp_peer_rsclient, "Address family\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_peer_rsclient, clear_bgp_instance_peer_rsclient_cmd, @@ -7267,7 +7267,7 @@ ALIAS (clear_bgp_peer_rsclient, "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_peer_rsclient, clear_bgp_ipv6_instance_peer_rsclient_cmd, @@ -7279,7 +7279,7 @@ ALIAS (clear_bgp_peer_rsclient, "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (clear_ip_bgp_peer_rsclient, clear_ip_bgp_peer_rsclient_cmd, @@ -7289,7 +7289,7 @@ DEFUN (clear_ip_bgp_peer_rsclient, BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 2) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_peer, @@ -7309,7 +7309,7 @@ ALIAS (clear_ip_bgp_peer_rsclient, "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" - "Soft reconfig for rsclient RIB\n") + BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (show_bgp_views, show_bgp_views_cmd, diff --git a/lib/command.h b/lib/command.h index 2c3b1a967..cc5dd0891 100644 --- a/lib/command.h +++ b/lib/command.h @@ -485,6 +485,10 @@ struct cmd_token #define CLEAR_STR "Reset functions\n" #define RIP_STR "RIP information\n" #define BGP_STR "BGP information\n" +#define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n" +#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n" +#define BGP_SOFT_OUT_STR "Resend all outbound updates\n" +#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n" #define OSPF_STR "OSPF information\n" #define NEIGHBOR_STR "Specify neighbor router\n" #define DEBUG_STR "Debugging functions (see also 'undebug')\n" From 4c7efde6db75229069be72b34a93f279fe57d23b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 16 Nov 2015 18:19:18 -0500 Subject: [PATCH 1140/1342] zebra: Add check to notice when an interface is unnumbered If an interface is not a loopback and it's prefixlen == 32 assume that it is unnumbered. Signed-off-by: Donald Sharp --- lib/if.h | 1 + zebra/connected.c | 10 +++++++++- zebra/interface.c | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/if.h b/lib/if.h index 9796a4d2e..862f7d471 100644 --- a/lib/if.h +++ b/lib/if.h @@ -282,6 +282,7 @@ struct connected u_char flags; #define ZEBRA_IFA_SECONDARY (1 << 0) #define ZEBRA_IFA_PEER (1 << 1) +#define ZEBRA_IFA_UNNUMBERED (1 << 2) /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if a peer address has been configured. If this flag is set, the destination field must contain the peer address. diff --git a/zebra/connected.c b/zebra/connected.c index 84b0d1cb8..1980007f4 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -77,7 +77,15 @@ connected_announce (struct interface *ifp, struct connected *ifc) { if (!ifc) return; - + + if (!if_is_loopback(ifp) && ifc->address->family == AF_INET) + { + if (ifc->address->prefixlen == 32) + SET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED); + else + UNSET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED); + } + listnode_add (ifp->connected, ifc); /* Update interface address information to protocol daemon. */ diff --git a/zebra/interface.c b/zebra/interface.c index 75597951c..5e89db979 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -736,6 +736,9 @@ connected_dump_vty (struct vty *vty, struct connected *connected) if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY)) vty_out (vty, " secondary"); + if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED)) + vty_out (vty, " unnumbered"); + if (connected->label) vty_out (vty, " %s", connected->label); From 2153090340f059eb787d72ba973ea55e150e9dec Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:38 -0700 Subject: [PATCH 1141/1342] bgpd: Fix BGP_INFO_ATTR_CHANGED being cleared incorrectly back to back route refreshes can set BGP_INFO_ATTR_CHANGED on the first route refresh but then clear it on the second Signed-off-by: Daniel Walton --- bgpd/bgp_route.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7f98f94f6..eedb2a049 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1990,7 +1990,6 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, && attrhash_cmp (ri->attr, attr_new)) { - bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, @@ -2244,8 +2243,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new)) { - bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); - if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) From cb37de4c6863c772b654a851c9fe3eeb1f677692 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:40 -0700 Subject: [PATCH 1142/1342] ospf6d: Fix loss of hello's on interface SYMPTOM: With quagga running on Linux, 'ifdown ' followed by 'ifup can cause OSPFv3 to not receive Hello packets on the interface. ISSUE: Operating System's interface IPv6 readiness may not be guaranteed at the time of interface-up event. Thats because the ipv6 components in an OS may also be listening to the same interface-up event that (in this case) is relayed to OSPFv3. In this failure case, setsockopt with option IPV6_JOIN_GROUP on the interface returned EINVAL. Error logs - OSPF6: Zebra Interface state change: swp1 index 3 flags 11043 metric 1 mtu 1500 OSPF6: Interface Event swp1: [InterfaceUp] OSPF6: Network: setsockopt (20) on ifindex 3 failed: Invalid argument FIX: To take care of this possible race condition, any address-family related setting should be retried. Given it's a rare condition and window of this race should be short, the patch adds a limited retry mechanism for the IPV6 membership setting on the socket. Signed-off-by: Vipin Kumar Reviewed-by: Dinesh Dutt Satish Ashok --- ospf6d/ospf6_interface.c | 13 ++++++++++++- ospf6d/ospf6_interface.h | 6 +++++- ospf6d/ospf6_network.c | 10 +++++++--- ospf6d/ospf6_network.h | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 7d54dd594..3d6ebcda7 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -728,7 +728,18 @@ interface_up (struct thread *thread) } /* Join AllSPFRouters */ - ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP); + if (ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP) < 0) + { + if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX) + { + zlog_info("Scheduling %s for sso retry, trial count: %d", + oi->interface->name, oi->sso_try_cnt); + thread_add_timer (master, interface_up, oi, + OSPF6_INTERFACE_SSO_RETRY_INT); + } + return 0; + } + oi->sso_try_cnt = 0; /* Reset on success */ /* Update interface route */ ospf6_interface_connected_route_update (oi->interface); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 220a475ab..dde589b8f 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -78,6 +78,9 @@ struct ospf6_interface /* Interface State */ u_char state; + /* Interface socket setting trial counter, resets on success */ + u_char sso_try_cnt; + /* OSPF6 Interface flag */ char flag; @@ -140,7 +143,8 @@ extern const char *ospf6_interface_state_str[]; #define OSPF6_INTERFACE_INSTANCE_ID 0 #define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */ #define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ - +#define OSPF6_INTERFACE_SSO_RETRY_INT 1 +#define OSPF6_INTERFACE_SSO_RETRY_MAX 5 /* Function Prototypes */ diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index a77375029..53d6c3594 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -112,7 +112,7 @@ ospf6_serv_sock (void) } /* ospf6 set socket option */ -void +int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; @@ -125,8 +125,12 @@ ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option, &mreq6, sizeof (mreq6)); if (ret < 0) - zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", - option, ifindex, safe_strerror (errno)); + { + zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", + option, ifindex, safe_strerror (errno)); + } + + return ret; } static int diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index f4b74faa7..4fa283951 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -29,7 +29,7 @@ extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock (void); -extern void ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); +extern int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, ifindex_t *, struct iovec *); From c69698704806a9ac5035521b1820057097919227 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:43 -0700 Subject: [PATCH 1143/1342] bgpd: Correct a few fuzz failures in BGP Testing revealed some issues with handling data input. This patch fixes those issues. Signed-off-by: Daniel Walton --- bgpd/bgp_attr.c | 8 +++++--- bgpd/bgp_packet.c | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 3b96bb24f..f6d5d8e7b 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2157,9 +2157,11 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, { zlog (peer->log, LOG_WARNING, "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + zlog_warn ("%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, attr_endp - startp); return BGP_ATTR_PARSE_ERROR; } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 9743d064e..0c47ab546 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1243,6 +1243,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) int mp_capability; u_int8_t notify_data_remote_as[2]; u_int8_t notify_data_remote_id[4]; + u_int16_t *holdtime_ptr; realpeer = NULL; @@ -1250,6 +1251,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) version = stream_getc (peer->ibuf); memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); remote_as = stream_getw (peer->ibuf); + holdtime_ptr = (u_int16_t *)stream_pnt (peer->ibuf); holdtime = stream_getw (peer->ibuf); memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); remote_id.s_addr = stream_get_ipv4 (peer->ibuf); @@ -1522,9 +1524,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) if (holdtime < 3 && holdtime != 0) { - bgp_notify_send (peer, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, + (u_int8_t *)holdtime_ptr, 2); return -1; } From fc2cee2bed4ebf664ba0afa1678027365f3923f7 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 18:03:44 -0700 Subject: [PATCH 1144/1342] zebra: Fix incorrectly flagged nexthop A valid BGP nexthop is sometimes flagged as invalid, this patch fixes that issue. Signed-off-by: Daniel Walton Edited-by: Paul Jakma , also add the check for NEXTHOP_FLAG_ACTIVE which was added in a separate, route-map related commit (6baeed5 lib, zebra: Add route-map support for Next Hop Tracking) --- zebra/zebra_rnh.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index db2a34d53..02a14688f 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -490,7 +490,9 @@ send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + if ((CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) || + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) && + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) From afc9cf97363c0b7ec6c253731a75ac83e70ea190 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 19 May 2015 18:03:50 -0700 Subject: [PATCH 1145/1342] osfd: Make OSPF compliant to the last sentence of this section in RFC 2328 9.5 Sending Hello packets Hello packets are sent out each functioning router interface. They are used to discover and maintain neighbor relationships.[6] On broadcast and NBMA networks, Hello Packets are also used to elect the Designated Router and Backup Designated Router. The format of an Hello packet is detailed in Section A.3.2. The Hello Packet contains the router's Router Priority (used in choosing the Designated Router), and the interval between Hello Packets sent out the interface (HelloInterval). The Hello Packet also indicates how often a neighbor must be heard from to remain active (RouterDeadInterval). Both HelloInterval and RouterDeadInterval must be the same for all routers attached to a common network. The Hello packet also contains the IP address mask of the attached network (Network Mask). On unnumbered point-to-point networks and on virtual links this field should be set to 0.0.0.0. Signed-off-by: Vipin Kumar Reviewed-by: Vivek Venkatraman Reviewed-by: Dinesh G Dutt --- ospfd/ospf_packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index f14182235..facba8950 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3022,7 +3022,8 @@ ospf_make_hello (struct ospf_interface *oi, struct stream *s) int flag = 0; /* Set netmask of interface. */ - if (oi->type != OSPF_IFTYPE_POINTOPOINT && + if (!(CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED) && + oi->type == OSPF_IFTYPE_POINTOPOINT) && oi->type != OSPF_IFTYPE_VIRTUALLINK) masklen2ip (oi->address->prefixlen, &mask); else From 4f84737dee1e84b7219f66e983812abd8a6ca1d3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 22 Dec 2015 15:24:25 -0500 Subject: [PATCH 1146/1342] zebra: Fix some warnings found during compile. This commit fixes some warnings found in Martin's Testbed that compiles sun solaris and freebsd images. Signed-off-by: Donald Sharp --- zebra/if_ioctl.c | 1 + zebra/if_ioctl_solaris.c | 1 + zebra/ioctl_solaris.c | 1 + zebra/rtread_getmsg.c | 1 + 4 files changed, 4 insertions(+) diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 8df877dba..99328a1d2 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -30,6 +30,7 @@ #include "memory.h" #include "log.h" #include "vrf.h" +#include "vty.h" #include "zebra/interface.h" #include "zebra/rib.h" diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 50b4aca62..b399812e4 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -31,6 +31,7 @@ #include "log.h" #include "privs.h" #include "vrf.h" +#include "vty.h" #include "zebra/interface.h" #include "zebra/ioctl_solaris.h" diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index 12737cbf0..b5bf1ccb0 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -28,6 +28,7 @@ #include "ioctl.h" #include "log.h" #include "privs.h" +#include "vty.h" #include "zebra/rib.h" #include "zebra/rt.h" diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 891539416..e1ec67095 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -26,6 +26,7 @@ #include "log.h" #include "if.h" #include "vrf.h" +#include "vty.h" #include "zebra/rib.h" #include "zebra/zserv.h" From cb9ed1d867f6ac9e0bad85c47aabeb10b94be2e5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 14 Jan 2016 09:19:29 -0500 Subject: [PATCH 1147/1342] ospf6d: Fix double increment of Sequence Number When OSPF6 is creating the header for the ROUTER LSA type if the packet being sent has interface information to add to the data, the Sequence Number is at least double incremented. This commit may cause issues with ANVL 16.10. [note: folded in: "ospf6d: Fix Some ANVL test cases 16.6 and partial 16.10" -- Paul Jakma] Signed-off-by: Donald Sharp --- ospf6d/ospf6_intra.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index dbd6ad9b7..3054b59b0 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -246,30 +246,6 @@ ospf6_router_lsa_originate (struct thread *thread) return 0; } - /* Fill LSA Header */ - lsa_header->age = 0; - lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); - lsa_header->id = htonl (link_state_id); - lsa_header->adv_router = oa->ospf6->router_id; - lsa_header->seqnum = - ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, - lsa_header->adv_router, oa->lsdb); - lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); - - /* LSA checksum */ - ospf6_lsa_checksum (lsa_header); - - /* create LSA */ - lsa = ospf6_lsa_create (lsa_header); - - /* Originate */ - ospf6_lsa_originate_area (lsa, oa); - - /* Reset setting for consecutive origination */ - memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa), - 0, (caddr_t) lsdesc - (caddr_t) router_lsa); - lsdesc = (struct ospf6_router_lsdesc *) - ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); link_state_id ++; } @@ -338,7 +314,7 @@ ospf6_router_lsa_originate (struct thread *thread) lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, - lsa_header->adv_router, oa->lsdb); + lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ From e25a9741fb1ba52a69833687caa01f13cd4d1320 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Mon, 9 Nov 2015 20:21:50 -0500 Subject: [PATCH 1148/1342] bgpd: don't count a route with an unreachable nexthop in PfxRcd When a route is received from a peer that we cannot reach do not count that route as a received route. Signed-off-by: Daniel Walton --- bgpd/bgp_route.c | 12 ++++++------ bgpd/bgp_route.h | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index eedb2a049..066637b32 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -247,7 +247,7 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) || ri->peer == ri->peer->bgp->peer_self) return; - if (BGP_INFO_HOLDDOWN (ri) + if (!BGP_INFO_COUNTABLE (ri) && CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { @@ -264,7 +264,7 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) zlog_warn ("%s: Please report to Quagga bugzilla", __func__); } } - else if (!BGP_INFO_HOLDDOWN (ri) + else if (BGP_INFO_COUNTABLE (ri) && !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { SET_FLAG (ri->flags, BGP_INFO_COUNTED); @@ -281,8 +281,8 @@ bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) { SET_FLAG (ri->flags, flag); - /* early bath if we know it's not a flag that changes useability state */ - if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) + /* early bath if we know it's not a flag that changes countability state */ + if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_HISTORY|BGP_INFO_REMOVED)) return; bgp_pcount_adjust (rn, ri); @@ -293,8 +293,8 @@ bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) { UNSET_FLAG (ri->flags, flag); - /* early bath if we know it's not a flag that changes useability state */ - if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) + /* early bath if we know it's not a flag that changes countability state */ + if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_HISTORY|BGP_INFO_REMOVED)) return; bgp_pcount_adjust (rn, ri); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 2a72daa35..332714c4f 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -139,6 +139,10 @@ struct bgp_static u_char tag[3]; }; +#define BGP_INFO_COUNTABLE(BI) \ + (! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \ + && ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED)) + /* Flags which indicate a route is unuseable in some form */ #define BGP_INFO_UNUSEABLE \ (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED) From 6c6c1bf0fc66713cb0b3448a4323042f44016502 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Mon, 9 Nov 2015 20:21:56 -0500 Subject: [PATCH 1149/1342] bgpd: Improve peer scaling Reduce the amount of time it takes to bring up a large number of peers. This is accomplished by removing jitter and reducing the number of seconds to wait before connecting to a peer. Signed-off-by: Daniel Walton Edited-by: Paul Jakma for rebase conflicts, and to add jitter on connect timer back in. Can be removed in an update. --- bgpd/bgp_fsm.c | 2 +- bgpd/bgpd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index c4cfd58e5..4f1838a51 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -106,7 +106,7 @@ bgp_timer_set (struct peer *peer) break; case Connect: - /* After start timer is expired, the peer moves to Connnect + /* After start timer is expired, the peer moves to Connect status. Make sure start timer is off and connect timer is on. */ BGP_TIMER_OFF (peer->t_start); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7bd5a7804..3f6161ce1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -748,7 +748,7 @@ struct bgp_nlri #define BGP_EVENTS_MAX 15 /* BGP timers default value. */ -#define BGP_INIT_START_TIMER 5 +#define BGP_INIT_START_TIMER 1 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 #define BGP_DEFAULT_EBGP_ROUTEADV 30 From 5bcd754ff8d7947978acb44e77dcab323973fb1e Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 19 May 2015 17:58:10 -0700 Subject: [PATCH 1150/1342] bgpd: crash if attributes alone consume > 4096 bytes This patch fixes a crash if attributes on a patch consume more than 4096 bytes. Signed-off-by: Daniel Walton --- bgpd/bgp_packet.c | 35 +++++++++++++++++++++++++++++++---- bgpd/bgpd.c | 14 +++++++++++++- bgpd/bgpd.h | 2 ++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0c47ab546..f42e544b4 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -153,6 +153,8 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; unsigned long attrlen_pos = 0; + int space_remaining = 0; + int space_needed = 0; size_t mpattrlen_pos = 0; size_t mpattr_pos = 0; @@ -171,9 +173,12 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) if (adv->binfo) binfo = adv->binfo; + space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) - + BGP_MAX_PACKET_SIZE_OVERFLOW; + space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p); + /* When remaining space can't include NLRI and it's length. */ - if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <= - (BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size(afi,safi,&rn->p))) + if (space_remaining < space_needed) break; /* If packet is empty, set attribute. */ @@ -217,6 +222,22 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) &rn->p : NULL), afi, safi, from, prd, tag); + space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) - + BGP_MAX_PACKET_SIZE_OVERFLOW; + space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p);; + + /* If the attributes alone do not leave any room for NLRI then + * return */ + if (space_remaining < space_needed) + { + zlog_err ("%s cannot send UPDATE, the attributes do not leave " + "room for NLRI", peer->host); + /* Flush the FIFO update queue */ + while (adv) + adv = bgp_advertise_clean (peer, adv->adj, afi, safi); + return NULL; + } + } if (afi == AFI_IP && safi == SAFI_UNICAST) @@ -347,6 +368,8 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) size_t attrlen_pos = 0; size_t mplen_pos = 0; u_char first_time = 1; + int space_remaining = 0; + int space_needed = 0; s = peer->work; stream_reset (s); @@ -357,8 +380,12 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) adj = adv->adj; rn = adv->rn; - if (STREAM_REMAIN (s) - < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) + space_remaining = STREAM_REMAIN (s) - + BGP_MAX_PACKET_SIZE_OVERFLOW; + space_needed = (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p)); + + if (space_remaining < space_needed) break; if (stream_empty (s)) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 669782dfc..010e224e7 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -868,7 +868,19 @@ peer_new (struct bgp *bgp) /* Create buffers. */ peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer->obuf = stream_fifo_new (); - peer->work = stream_new (BGP_MAX_PACKET_SIZE); + + /* We use a larger buffer for peer->work in the event that: + * - We RX a BGP_UPDATE where the attributes alone are just + * under BGP_MAX_PACKET_SIZE + * - The user configures an outbound route-map that does many as-path + * prepends or adds many communities. At most they can have CMD_ARGC_MAX + * args in a route-map so there is a finite limit on how large they can + * make the attributes. + * + * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid bounds + * checking for every single attribute as we construct an UPDATE. + */ + peer->work = stream_new (BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW); peer->scratch = stream_new (BGP_MAX_PACKET_SIZE); bgp_sync_init (peer); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3f6161ce1..40da02ea6 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -278,6 +278,8 @@ typedef enum BGP_PEER_CONFED, } bgp_peer_sort_t; +#define BGP_MAX_PACKET_SIZE_OVERFLOW 1024 + /* BGP neighbor structure. */ struct peer { From d9ab53ab40dcba66f34ca75695dc930e6093f789 Mon Sep 17 00:00:00 2001 From: Dinesh Dutt Date: Tue, 19 May 2015 17:47:21 -0700 Subject: [PATCH 1151/1342] bgpd, zebra: Use next hop tracking for connected routes too Allow next hop tracking to work with connected routes And cleanup obsolete code in bgp_scan and bgp_import. Signed-off-by: Dinesh Dutt Signed-off-by: Donald Sharp Edits: Paul Jakma Rebase re-ordering conflicts with NHT route-map, potential errors. --- bgpd/bgp_fsm.c | 47 ++ bgpd/bgp_fsm.h | 1 + bgpd/bgp_main.c | 9 +- bgpd/bgp_nexthop.c | 1044 +------------------------------------------- bgpd/bgp_nexthop.h | 30 +- bgpd/bgp_nht.c | 97 ++-- bgpd/bgp_nht.h | 16 +- bgpd/bgp_packet.c | 15 +- bgpd/bgp_packet.h | 1 + bgpd/bgp_route.c | 162 +++++-- bgpd/bgpd.c | 53 ++- bgpd/bgpd.h | 1 + zebra/zebra_rnh.c | 18 +- zebra/zebra_rnh.h | 1 + zebra/zserv.c | 11 +- 15 files changed, 345 insertions(+), 1161 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 4f1838a51..d84a865fb 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -42,6 +42,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_route.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_open.h" +#include "bgpd/bgp_nht.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ @@ -675,6 +676,7 @@ int bgp_start (struct peer *peer) { int status; + int connected = 0; if (BGP_PEER_START_SUPPRESSED (peer)) { @@ -713,6 +715,12 @@ bgp_start (struct peer *peer) return 0; } + /* Register to be notified on peer up */ + if ((peer->ttl == 1) || (peer->gtsm_hops == 1)) + connected = 1; + + bgp_find_or_add_nexthop(family2afi(peer->su.sa.sa_family), NULL, peer, + connected); status = bgp_connect (peer); switch (status) @@ -939,6 +947,45 @@ bgp_ignore (struct peer *peer) return 0; } +void +bgp_fsm_nht_update(struct peer *peer, int valid) +{ + int ret = 0; + + if (!peer) + return; + + switch (peer->status) + { + case Idle: + if (valid) + BGP_EVENT_ADD(peer, BGP_Start); + break; + case Connect: + ret = bgp_connect_check(peer, 0); + if (!ret && valid) + { + BGP_TIMER_OFF(peer->t_connect); + BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); + } + break; + case Active: + if (valid) + { + BGP_TIMER_OFF(peer->t_connect); + BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); + } + case OpenSent: + case OpenConfirm: + case Established: + case Clearing: + case Deleted: + default: + break; + } +} + + /* Finite State Machine structure */ static const struct { int (*func) (struct peer *); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 752d6e2b9..b38e64c92 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -72,6 +72,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA } while (0) /* Prototypes. */ +extern void bgp_fsm_nht_update(struct peer *, int valid); extern int bgp_event (struct thread *); extern int bgp_stop (struct peer *peer); extern void bgp_timer_set (struct peer *); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index eb0fe1774..af9c03052 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -230,7 +230,6 @@ bgp_exit (int status) struct listnode *node, *nnode; int *socket; struct interface *ifp; - extern struct zclient *zlookup; /* it only makes sense for this to be called on a clean exit */ assert (status == 0); @@ -292,9 +291,6 @@ bgp_exit (int status) /* reverse bgp_route_map_init/route_map_init */ route_map_finish (); - /* reverse bgp_scan_init */ - bgp_scan_finish (); - /* reverse access_list_init */ access_list_add_hook (NULL); access_list_delete_hook (NULL); @@ -319,13 +315,14 @@ bgp_exit (int status) bgp_address_destroy(); bgp_scan_destroy(); bgp_zebra_destroy(); - if (zlookup) - zclient_free (zlookup); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); if (bgp_ifindices_buf) stream_free (bgp_ifindices_buf); + /* reverse bgp_scan_init */ + bgp_scan_finish (); + /* reverse bgp_master_init */ if (bm->master) thread_master_free (bm->master); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 434b2cdad..429c63813 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -44,34 +44,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ -extern struct zclient *zclient; - -struct bgp_nexthop_cache *zlookup_query (struct in_addr); -struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); - -/* Only one BGP scan thread are activated at the same time. */ -static struct thread *bgp_scan_thread = NULL; - -/* BGP import thread */ -static struct thread *bgp_import_thread = NULL; - -/* BGP scan interval. */ -static int bgp_scan_interval; - -/* BGP import interval. */ -static int bgp_import_interval; /* Route table for next-hop lookup cache. */ struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; static struct bgp_table *cache1_table[AFI_MAX]; -static struct bgp_table *cache2_table[AFI_MAX]; /* Route table for connected route. */ static struct bgp_table *bgp_connected_table[AFI_MAX]; -/* BGP nexthop lookup query client. */ -struct zclient *zlookup = NULL; - char * bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) { @@ -79,21 +59,6 @@ bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) return buf; } -/* Add nexthop to the end of the list. */ -static void -bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) -{ - struct nexthop *last; - - for (last = bnc->nexthop; last && last->next; last = last->next) - ; - if (last) - last->next = nexthop; - else - bnc->nexthop = nexthop; - nexthop->prev = last; -} - void bnc_nexthop_free (struct bgp_nexthop_cache *bnc) { @@ -124,40 +89,12 @@ bnc_free (struct bgp_nexthop_cache *bnc) XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } -static int -bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, - struct bgp_nexthop_cache *bnc2) -{ - int i; - struct nexthop *next1, *next2; - - if (bnc1->nexthop_num != bnc2->nexthop_num) - return 1; - - next1 = bnc1->nexthop; - next2 = bnc2->nexthop; - - for (i = 0; i < bnc1->nexthop_num; i++) - { - if (! nexthop_same_no_recurse (next1, next2)) - return 1; - - next1 = next1->next; - next2 = next2->next; - } - return 0; -} - /* If nexthop exists on connected network return 1. */ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; - /* If zebra is not enabled return */ - if (zlookup->sock < 0) - return 1; - /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { @@ -189,333 +126,6 @@ bgp_nexthop_onlink (afi_t afi, struct attr *attr) return 0; } -/* Check specified next-hop is reachable or not. */ -static int -bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, - int *metricchanged) -{ - struct bgp_node *rn; - struct prefix p; - struct bgp_nexthop_cache *bnc; - struct attr *attr; - - /* If lookup is not enabled, return valid. */ - if (zlookup->sock < 0) - { - if (ri->extra) - ri->extra->igpmetric = 0; - return 1; - } - - /* Only check IPv6 global address only nexthop. */ - attr = ri->attr; - - if (attr->extra->mp_nexthop_len != 16 - || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) - return 1; - - memset (&p, 0, sizeof (struct prefix)); - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_BITLEN; - p.u.prefix6 = attr->extra->mp_nexthop_global; - - /* IBGP or ebgp-multihop */ - rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); - - if (rn->info) - { - bnc = rn->info; - bgp_unlock_node (rn); - } - else - { - if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) - bnc = bnc_new (); - else - { - if (changed) - { - struct bgp_table *old; - struct bgp_node *oldrn; - - if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) - old = cache2_table[AFI_IP6]; - else - old = cache1_table[AFI_IP6]; - - oldrn = bgp_node_lookup (old, &p); - if (oldrn) - { - struct bgp_nexthop_cache *oldbnc = oldrn->info; - - bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); - - if (bnc->metric != oldbnc->metric) - bnc->metricchanged = 1; - - bgp_unlock_node (oldrn); - } - } - } - rn->info = bnc; - } - - if (changed) - *changed = bnc->changed; - - if (metricchanged) - *metricchanged = bnc->metricchanged; - - if (bnc->valid && bnc->metric) - (bgp_info_extra_get (ri))->igpmetric = bnc->metric; - else if (ri->extra) - ri->extra->igpmetric = 0; - - return bnc->valid; -} - -/* Check specified next-hop is reachable or not. */ -int -bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, - int *changed, int *metricchanged) -{ - struct bgp_node *rn; - struct prefix p; - struct bgp_nexthop_cache *bnc; - struct in_addr addr; - - /* If lookup is not enabled, return valid. */ - if (zlookup->sock < 0) - { - if (ri->extra) - ri->extra->igpmetric = 0; - return 1; - } - - if (afi == AFI_IP6) - return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); - - addr = ri->attr->nexthop; - - memset (&p, 0, sizeof (struct prefix)); - p.family = AF_INET; - p.prefixlen = IPV4_MAX_BITLEN; - p.u.prefix4 = addr; - - /* IBGP or ebgp-multihop */ - rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p); - - if (rn->info) - { - bnc = rn->info; - bgp_unlock_node (rn); - } - else - { - if (NULL == (bnc = zlookup_query (addr))) - bnc = bnc_new (); - else - { - if (changed) - { - struct bgp_table *old; - struct bgp_node *oldrn; - - if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) - old = cache2_table[AFI_IP]; - else - old = cache1_table[AFI_IP]; - - oldrn = bgp_node_lookup (old, &p); - if (oldrn) - { - struct bgp_nexthop_cache *oldbnc = oldrn->info; - - bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); - - if (bnc->metric != oldbnc->metric) - bnc->metricchanged = 1; - - bgp_unlock_node (oldrn); - } - } - } - rn->info = bnc; - } - - if (changed) - *changed = bnc->changed; - - if (metricchanged) - *metricchanged = bnc->metricchanged; - - if (bnc->valid && bnc->metric) - (bgp_info_extra_get(ri))->igpmetric = bnc->metric; - else if (ri->extra) - ri->extra->igpmetric = 0; - - return bnc->valid; -} - -#if BGP_SCAN_NEXTHOP -/* Reset and free all BGP nexthop cache. */ -static void -bgp_nexthop_cache_reset (struct bgp_table *table) -{ - struct bgp_node *rn; - struct bgp_nexthop_cache *bnc; - - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - if ((bnc = rn->info) != NULL) - { - bnc_free (bnc); - rn->info = NULL; - bgp_unlock_node (rn); - } -} -#endif - -static void -bgp_scan (afi_t afi, safi_t safi) -{ - struct bgp_node *rn; - struct bgp *bgp; - struct bgp_info *bi; - struct bgp_info *next; - struct peer *peer; - struct listnode *node, *nnode; -#if BGP_SCAN_NEXTHOP - int valid; - int current; - int changed; - int metricchanged; - - /* Change cache. */ - if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) - bgp_nexthop_cache_table[afi] = cache2_table[afi]; - else - bgp_nexthop_cache_table[afi] = cache1_table[afi]; -#endif - - /* Get default bgp. */ - bgp = bgp_get_default (); - if (bgp == NULL) - return; - - /* Maximum prefix check */ - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - { - if (peer->status != Established) - continue; - - if (peer->afc[afi][SAFI_UNICAST]) - bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1); - if (peer->afc[afi][SAFI_MULTICAST]) - bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1); - if (peer->afc[afi][SAFI_MPLS_VPN]) - bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1); - } - - for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn; - rn = bgp_route_next (rn)) - { - for (bi = rn->info; bi; bi = next) - { - next = bi->next; - - if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) - { -#if BGP_SCAN_NEXTHOP - changed = 0; - metricchanged = 0; - - if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1 - && !CHECK_FLAG(bi->peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) - valid = bgp_nexthop_onlink (afi, bi->attr); - else - valid = bgp_nexthop_lookup (afi, bi->peer, bi, - &changed, &metricchanged); - - current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; - - if (changed) - SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); - else - UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); - - if (valid != current) - { - if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) - { - bgp_aggregate_decrement (bgp, &rn->p, bi, - afi, SAFI_UNICAST); - bgp_info_unset_flag (rn, bi, BGP_INFO_VALID); - } - else - { - bgp_info_set_flag (rn, bi, BGP_INFO_VALID); - bgp_aggregate_increment (bgp, &rn->p, bi, - afi, SAFI_UNICAST); - } - } -#endif - - if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], - BGP_CONFIG_DAMPENING) - && bi->extra && bi->extra->damp_info ) - if (bgp_damp_scan (bi, afi, SAFI_UNICAST)) - bgp_aggregate_increment (bgp, &rn->p, bi, - afi, SAFI_UNICAST); - } - } - if (rn->info) - bgp_process (bgp, rn, afi, SAFI_UNICAST); - } - -#if BGP_SCAN_NEXTHOP - /* Flash old cache. */ - if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) - bgp_nexthop_cache_reset (cache2_table[afi]); - else - bgp_nexthop_cache_reset (cache1_table[afi]); -#endif - - if (BGP_DEBUG (events, EVENTS)) - { - if (afi == AFI_IP) - zlog_debug ("scanning IPv4 Unicast routing tables"); - else if (afi == AFI_IP6) - zlog_debug ("scanning IPv6 Unicast routing tables"); - } - - /* Reevaluate default-originate route-maps and announce/withdraw - * default route if neccesary. */ - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - { - if (peer->status == Established - && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) - && peer->default_rmap[afi][safi].name) - bgp_default_originate (peer, afi, safi, 0); - } -} - -/* BGP scan thread. This thread check nexthop reachability. */ -static int -bgp_scan_timer (struct thread *t) -{ - bgp_scan_thread = - thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); - - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("Performing BGP general scanning"); - - bgp_scan (AFI_IP, SAFI_UNICAST); - - bgp_scan (AFI_IP6, SAFI_UNICAST); - - return 0; -} - /* BGP own address structure */ struct bgp_addr { @@ -763,585 +373,39 @@ bgp_nexthop_self (struct attr *attr) return 0; } -static struct bgp_nexthop_cache * -zlookup_read (void) -{ - struct stream *s; - uint16_t length; - u_char marker; - u_char version; - uint16_t vrf_id; - uint16_t command; - int err; - struct in_addr raddr __attribute__((unused)); - uint32_t metric; - int i; - u_char nexthop_num; - struct nexthop *nexthop; - struct bgp_nexthop_cache *bnc; - - s = zlookup->ibuf; - stream_reset (s); - - err = zclient_read_header (s, zlookup->sock, &length, &marker, &version, - &vrf_id, &command); - if (err < 0) - { - zlog_err("%s: zserv_read_header() failed", __func__); - return NULL; - } - - /* XXX: not doing anything with raddr */ - raddr.s_addr = stream_get_ipv4 (s); - metric = stream_getl (s); - nexthop_num = stream_getc (s); - - if (nexthop_num) - { - bnc = bnc_new (); - bnc->valid = 1; - bnc->metric = metric; - bnc->nexthop_num = nexthop_num; - - for (i = 0; i < nexthop_num; i++) - { - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); - nexthop->type = stream_getc (s); - switch (nexthop->type) - { - case ZEBRA_NEXTHOP_IPV4: - nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); - break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: - nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); - nexthop->ifindex = stream_getl (s); - break; - case ZEBRA_NEXTHOP_IFINDEX: - case ZEBRA_NEXTHOP_IFNAME: - nexthop->ifindex = stream_getl (s); - break; - default: - /* do nothing */ - break; - } - bnc_nexthop_add (bnc, nexthop); - } - } - else - return NULL; - - return bnc; -} - -struct bgp_nexthop_cache * -zlookup_query (struct in_addr addr) -{ - int ret; - struct stream *s; - - /* Check socket. */ - if (zlookup->sock < 0) - return NULL; - - s = zlookup->obuf; - stream_reset (s); - zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, VRF_DEFAULT); - stream_put_in_addr (s, &addr); - - stream_putw_at (s, 0, stream_get_endp (s)); - - ret = writen (zlookup->sock, s->data, stream_get_endp (s)); - if (ret < 0) - { - zlog_err ("can't write to zlookup->sock"); - close (zlookup->sock); - zlookup->sock = -1; - return NULL; - } - if (ret == 0) - { - zlog_err ("zlookup->sock connection closed"); - close (zlookup->sock); - zlookup->sock = -1; - return NULL; - } - - return zlookup_read (); -} - -static struct bgp_nexthop_cache * -zlookup_read_ipv6 (void) -{ - struct stream *s; - uint16_t length, vrf_id, cmd; - u_char version, marker; - struct in6_addr raddr; - uint32_t metric; - int i, err; - u_char nexthop_num; - struct nexthop *nexthop; - struct bgp_nexthop_cache *bnc; - - s = zlookup->ibuf; - stream_reset (s); - - err = zclient_read_header (s, zlookup->sock, &length, &marker, &version, - &vrf_id, &cmd); - if (err < 0) - { - zlog_err("%s: zserv_read_header() failed", __func__); - return NULL; - } - - /* XXX: not actually doing anything with raddr */ - stream_get (&raddr, s, 16); - - metric = stream_getl (s); - nexthop_num = stream_getc (s); - - if (nexthop_num) - { - bnc = bnc_new (); - bnc->valid = 1; - bnc->metric = metric; - bnc->nexthop_num = nexthop_num; - - for (i = 0; i < nexthop_num; i++) - { - nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); - nexthop->type = stream_getc (s); - switch (nexthop->type) - { - case ZEBRA_NEXTHOP_IPV6: - stream_get (&nexthop->gate.ipv6, s, 16); - break; - case ZEBRA_NEXTHOP_IPV6_IFINDEX: - case ZEBRA_NEXTHOP_IPV6_IFNAME: - stream_get (&nexthop->gate.ipv6, s, 16); - nexthop->ifindex = stream_getl (s); - break; - case ZEBRA_NEXTHOP_IFINDEX: - case ZEBRA_NEXTHOP_IFNAME: - nexthop->ifindex = stream_getl (s); - break; - default: - /* do nothing */ - break; - } - bnc_nexthop_add (bnc, nexthop); - } - } - else - return NULL; - - return bnc; -} - -struct bgp_nexthop_cache * -zlookup_query_ipv6 (struct in6_addr *addr) -{ - int ret; - struct stream *s; - - /* Check socket. */ - if (zlookup->sock < 0) - return NULL; - - s = zlookup->obuf; - stream_reset (s); - zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, VRF_DEFAULT); - stream_put (s, addr, 16); - stream_putw_at (s, 0, stream_get_endp (s)); - - ret = writen (zlookup->sock, s->data, stream_get_endp (s)); - if (ret < 0) - { - zlog_err ("can't write to zlookup->sock"); - close (zlookup->sock); - zlookup->sock = -1; - return NULL; - } - if (ret == 0) - { - zlog_err ("zlookup->sock connection closed"); - close (zlookup->sock); - zlookup->sock = -1; - return NULL; - } - - return zlookup_read_ipv6 (); -} - -static int -bgp_import_check (struct prefix *p, u_int32_t *igpmetric, - struct in_addr *igpnexthop) -{ - struct stream *s; - int ret; - u_int16_t length, vrf_id, command; - u_char version, marker; - struct in_addr addr __attribute__((unused)); - struct in_addr nexthop; - u_int32_t metric = 0; - u_char nexthop_num; - u_char nexthop_type; - - /* If lookup connection is not available return valid. */ - if (zlookup->sock < 0) - { - if (igpmetric) - *igpmetric = 0; - return 1; - } - - /* Send query to the lookup connection */ - s = zlookup->obuf; - stream_reset (s); - zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP, VRF_DEFAULT); - - stream_putc (s, p->prefixlen); - stream_put_in_addr (s, &p->u.prefix4); - - stream_putw_at (s, 0, stream_get_endp (s)); - - /* Write the packet. */ - ret = writen (zlookup->sock, s->data, stream_get_endp (s)); - - if (ret < 0) - { - zlog_err ("can't write to zlookup->sock"); - close (zlookup->sock); - zlookup->sock = -1; - return 1; - } - if (ret == 0) - { - zlog_err ("zlookup->sock connection closed"); - close (zlookup->sock); - zlookup->sock = -1; - return 1; - } - - /* Get result. */ - stream_reset (s); - - ret = zclient_read_header (s, zlookup->sock, &length, &marker, &version, - &vrf_id, &command); - if (ret < 0) - { - zlog_err("%s: zserv_read_header() failed", __func__); - return 0; - } - - /* XXX: not using addr */ - addr.s_addr = stream_get_ipv4 (s); - metric = stream_getl (s); - nexthop_num = stream_getc (s); - - /* Set IGP metric value. */ - if (igpmetric) - *igpmetric = metric; - - /* If there is nexthop then this is active route. */ - if (nexthop_num) - { - nexthop.s_addr = 0; - nexthop_type = stream_getc (s); - switch (nexthop_type) - { - case ZEBRA_NEXTHOP_IPV4: - nexthop.s_addr = stream_get_ipv4 (s); - break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: - nexthop.s_addr = stream_get_ipv4 (s); - /* ifindex */ (void)stream_getl (s); - break; - default: - /* do nothing */ - break; - } - *igpnexthop = nexthop; - - return 1; - } - else - return 0; -} - -/* Scan all configured BGP route then check the route exists in IGP or - not. */ -static int -bgp_import (struct thread *t) -{ - struct bgp *bgp; - struct bgp_node *rn; - struct bgp_static *bgp_static; - struct listnode *node, *nnode; - int valid; - u_int32_t metric; - struct in_addr nexthop; - afi_t afi; - safi_t safi; - - bgp_import_thread = - thread_add_timer (bm->master, bgp_import, NULL, bgp_import_interval); - - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("Import timer expired."); - - for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) - { - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++) - for (rn = bgp_table_top (bgp->route[afi][safi]); rn; - rn = bgp_route_next (rn)) - if ((bgp_static = rn->info) != NULL) - { - if (bgp_static->backdoor) - continue; - - valid = bgp_static->valid; - metric = bgp_static->igpmetric; - nexthop = bgp_static->igpnexthop; - - if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) - && afi == AFI_IP && safi == SAFI_UNICAST) - bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric, - &bgp_static->igpnexthop); - else - { - bgp_static->valid = 1; - bgp_static->igpmetric = 0; - bgp_static->igpnexthop.s_addr = 0; - } - - if (bgp_static->valid != valid) - { - if (bgp_static->valid) - bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); - else - bgp_static_withdraw (bgp, &rn->p, afi, safi); - } - else if (bgp_static->valid) - { - if (bgp_static->igpmetric != metric - || bgp_static->igpnexthop.s_addr != nexthop.s_addr - || bgp_static->rmap.name) - bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); - } - } - } - return 0; -} - -/* Connect to zebra for nexthop lookup. */ -static int -zlookup_connect (struct thread *t) -{ - struct zclient *zlookup; - - zlookup = THREAD_ARG (t); - zlookup->t_connect = NULL; - - if (zlookup->sock != -1) - return 0; - - if (zclient_socket_connect (zlookup) < 0) - return -1; - - return 0; -} - -/* Check specified multiaccess next-hop. */ int -bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) +bgp_multiaccess_check_v4 (struct in_addr nexthop, struct peer *peer) { struct bgp_node *rn1; struct bgp_node *rn2; - struct prefix p1; - struct prefix p2; - struct in_addr addr; + struct prefix p; int ret; - ret = inet_aton (peer, &addr); - if (! ret) - return 0; + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = nexthop; - memset (&p1, 0, sizeof (struct prefix)); - p1.family = AF_INET; - p1.prefixlen = IPV4_MAX_BITLEN; - p1.u.prefix4 = nexthop; - memset (&p2, 0, sizeof (struct prefix)); - p2.family = AF_INET; - p2.prefixlen = IPV4_MAX_BITLEN; - p2.u.prefix4 = addr; - - /* If bgp scan is not enabled, return invalid. */ - if (zlookup->sock < 0) + rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p); + if (!rn1) return 0; - rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); - if (! rn1) - return 0; - bgp_unlock_node (rn1); - - rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); - if (! rn2) - return 0; - bgp_unlock_node (rn2); - - /* This is safe, even with above unlocks, since we are just - comparing pointers to the objects, not the objects themselves. */ - if (rn1 == rn2) - return 1; - - return 0; -} - -DEFUN (bgp_scan_time, - bgp_scan_time_cmd, - "bgp scan-time <5-60>", - "BGP specific commands\n" - "Configure background scanner interval\n" - "Scanner interval (seconds)\n") -{ - bgp_scan_interval = atoi (argv[0]); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = peer->su.sin.sin_addr; - if (bgp_scan_thread) + rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p); + if (!rn2) { - thread_cancel (bgp_scan_thread); - bgp_scan_thread = - thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); + bgp_unlock_node(rn1); + return 0; } - return CMD_SUCCESS; -} + ret = (rn1 == rn2) ? 1 : 0; -DEFUN (no_bgp_scan_time, - no_bgp_scan_time_cmd, - "no bgp scan-time", - NO_STR - "BGP specific commands\n" - "Configure background scanner interval\n") -{ - bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; - - if (bgp_scan_thread) - { - thread_cancel (bgp_scan_thread); - bgp_scan_thread = - thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval); - } + bgp_unlock_node(rn1); + bgp_unlock_node(rn2); - return CMD_SUCCESS; -} - -ALIAS (no_bgp_scan_time, - no_bgp_scan_time_val_cmd, - "no bgp scan-time <5-60>", - NO_STR - "BGP specific commands\n" - "Configure background scanner interval\n" - "Scanner interval (seconds)\n") - -static int -show_ip_bgp_scan_tables (struct vty *vty, const char detail) -{ - struct bgp_node *rn; - char buf[INET6_ADDRSTRLEN]; - - if (bgp_scan_thread) - vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); - else - vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); - vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); - -#if BGP_SCAN_NEXTHOP - vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); - for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) - if ((bnc = rn->info) != NULL) - { - if (bnc->valid) - { - vty_out (vty, " %s valid [IGP metric %d]%s", - inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); - if (detail) - for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " gate %s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN)); - vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); - break; - default: - vty_out (vty, " invalid nexthop type %u%s", nexthop->type, VTY_NEWLINE); - } - } - else - vty_out (vty, " %s invalid%s", - inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); - } - - { - for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); - rn; - rn = bgp_route_next (rn)) - if ((bnc = rn->info) != NULL) - { - if (bnc->valid) - { - vty_out (vty, " %s valid [IGP metric %d]%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), - bnc->metric, VTY_NEWLINE); - if (detail) - for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV6: - vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out (vty, " ifidx %u%s", nexthop->ifindex, VTY_NEWLINE); - break; - default: - vty_out (vty, " invalid nexthop type %u%s", nexthop->type, VTY_NEWLINE); - } - } - else - vty_out (vty, " %s invalid%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), - VTY_NEWLINE); - } - } -#else - vty_out (vty, "BGP next-hop tracking is on%s", VTY_NEWLINE); -#endif - vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); - for (rn = bgp_table_top (bgp_connected_table[AFI_IP]); - rn; - rn = bgp_route_next (rn)) - if (rn->info != NULL) - vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, - VTY_NEWLINE); - - { - for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); - rn; - rn = bgp_route_next (rn)) - if (rn->info != NULL) - vty_out (vty, " %s/%d%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), - rn->p.prefixlen, - VTY_NEWLINE); - } - - return CMD_SUCCESS; + return (ret); } static int @@ -1418,29 +482,6 @@ show_ip_bgp_nexthop_table (struct vty *vty, int detail) return CMD_SUCCESS; } -DEFUN (show_ip_bgp_scan, - show_ip_bgp_scan_cmd, - "show ip bgp scan", - SHOW_STR - IP_STR - BGP_STR - "BGP scan status\n") -{ - return show_ip_bgp_scan_tables (vty, 0); -} - -DEFUN (show_ip_bgp_scan_detail, - show_ip_bgp_scan_detail_cmd, - "show ip bgp scan detail", - SHOW_STR - IP_STR - BGP_STR - "BGP scan status\n" - "More detailed output\n") -{ - return show_ip_bgp_scan_tables (vty, 1); -} - DEFUN (show_ip_bgp_nexthop, show_ip_bgp_nexthop_cmd, "show ip bgp nexthop", @@ -1463,49 +504,25 @@ DEFUN (show_ip_bgp_nexthop_detail, return show_ip_bgp_nexthop_table (vty, 1); } -int -bgp_config_write_scan_time (struct vty *vty) -{ - if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT) - vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE); - return CMD_SUCCESS; -} - void bgp_scan_init (void) { - zlookup = zclient_new (bm->master); - zlookup->sock = -1; - zlookup->t_connect = thread_add_event (bm->master, zlookup_connect, zlookup, 0); - - bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; - bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; - cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); - cache2_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP]; bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); - cache2_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); - /* Make BGP scan thread. */ - bgp_scan_thread = thread_add_timer (bm->master, bgp_scan_timer, - NULL, bgp_scan_interval); - /* Make BGP import there. */ - bgp_import_thread = thread_add_timer (bm->master, bgp_import, NULL, 0); - - install_element (BGP_NODE, &bgp_scan_time_cmd); - install_element (BGP_NODE, &no_bgp_scan_time_cmd); - install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); - install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); - install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd); +} + +void +bgp_scan_vty_init() +{ install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd); install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd); - install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); } void @@ -1515,10 +532,6 @@ bgp_scan_finish (void) bgp_table_unlock (cache1_table[AFI_IP]); cache1_table[AFI_IP] = NULL; - if (cache2_table[AFI_IP]) - bgp_table_unlock (cache2_table[AFI_IP]); - cache2_table[AFI_IP] = NULL; - if (bgp_connected_table[AFI_IP]) bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; @@ -1527,10 +540,6 @@ bgp_scan_finish (void) bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; - if (cache2_table[AFI_IP6]) - bgp_table_unlock (cache2_table[AFI_IP6]); - cache2_table[AFI_IP6] = NULL; - if (bgp_connected_table[AFI_IP6]) bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; @@ -1539,12 +548,5 @@ bgp_scan_finish (void) void bgp_scan_destroy (void) { - if (zlookup == NULL) - return; - THREAD_OFF(bgp_import_thread); - THREAD_OFF(bgp_scan_thread); - THREAD_OFF(zlookup->t_connect); bgp_scan_finish(); - zclient_free (zlookup); - zlookup = NULL; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index a239ca061..fe4f5ad4b 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -25,9 +25,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "queue.h" #include "prefix.h" -#define BGP_SCAN_INTERVAL_DEFAULT 60 -#define BGP_IMPORT_INTERVAL_DEFAULT 15 - #define NEXTHOP_FAMILY(nexthop_len) ( \ ((nexthop_len) == 4 || \ (nexthop_len) == 12 ? AF_INET : \ @@ -40,15 +37,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { - /* This nexthop exists in IGP. */ - u_char valid; - - /* Nexthop is changed. */ - u_char changed; - - /* Nexthop is changed. */ - u_char metricchanged; - /* IGP route's metric. */ u_int32_t metric; @@ -58,26 +46,28 @@ struct bgp_nexthop_cache time_t last_update; u_int16_t flags; -#define BGP_NEXTHOP_VALID (1 << 0) -#define BGP_NEXTHOP_REGISTERED (1 << 1) +#define BGP_NEXTHOP_VALID (1 << 0) +#define BGP_NEXTHOP_REGISTERED (1 << 1) +#define BGP_NEXTHOP_CONNECTED (1 << 2) +#define BGP_NEXTHOP_PEER_NOTIFIED (1 << 3) u_int16_t change_flags; -#define BGP_NEXTHOP_CHANGED (1 << 0) -#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) +#define BGP_NEXTHOP_CHANGED (1 << 0) +#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) +#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) struct bgp_node *node; + void *nht_info; /* In BGP, peer session */ LIST_HEAD(path_list, bgp_info) paths; unsigned int path_count; }; -extern void bgp_scan_init (void); -extern void bgp_scan_finish (void); extern int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, int *, int *); extern void bgp_connected_add (struct connected *c); extern void bgp_connected_delete (struct connected *c); -extern int bgp_multiaccess_check_v4 (struct in_addr, char *); +extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *); extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (struct attr *); @@ -89,4 +79,6 @@ extern void bnc_free(struct bgp_nexthop_cache *bnc); extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc); extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size); +extern void bgp_scan_init (void); +extern void bgp_scan_vty_init (void); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 21e1411b8..34b5fd1c1 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -39,6 +39,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_fsm.h" extern struct zclient *zclient; extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; @@ -51,19 +52,15 @@ static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, int keep); int -bgp_find_nexthop (struct bgp_info *path, int *changed, int *metricchanged) +bgp_find_nexthop (struct bgp_info *path, int connected) { struct bgp_nexthop_cache *bnc = path->nexthop; if (!bnc) return 0; - if (changed) - *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); - - if (metricchanged) - *metricchanged = CHECK_FLAG(bnc->change_flags, - BGP_NEXTHOP_METRIC_CHANGED); + if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) + return 0; return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } @@ -78,7 +75,7 @@ bgp_unlink_nexthop (struct bgp_info *path) path_nh_map(path, NULL, 0); - if (LIST_EMPTY(&(bnc->paths))) + if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { if (BGP_DEBUG(nht, NHT)) { @@ -94,15 +91,34 @@ bgp_unlink_nexthop (struct bgp_info *path) } int -bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed, - int *metricchanged) +bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, + int connected) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; struct prefix p; - if (make_prefix(afi, ri, &p) < 0) - return 1; + if (ri) + { + if (make_prefix(afi, ri, &p) < 0) + return 1; + } + else if (peer) + { + if (afi == AFI_IP) + { + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = peer->su.sin.sin_addr; + } + else if (afi == AFI_IP6) + { + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = peer->su.sin6.sin6_addr; + } + } + rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); if (!rn->info) @@ -111,23 +127,27 @@ bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed, rn->info = bnc; bnc->node = rn; bgp_lock_node(rn); - register_nexthop(bnc); + if (connected) + SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); } + bnc = rn->info; bgp_unlock_node (rn); - path_nh_map(ri, bnc, 1); - if (changed) - *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); + if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) + register_nexthop(bnc); - if (metricchanged) - *metricchanged = CHECK_FLAG(bnc->change_flags, - BGP_NEXTHOP_METRIC_CHANGED); + if (ri) + { + path_nh_map(ri, bnc, 1); - if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) - (bgp_info_extra_get(ri))->igpmetric = bnc->metric; - else if (ri->extra) - ri->extra->igpmetric = 0; + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) + (bgp_info_extra_get(ri))->igpmetric = bnc->metric; + else if (ri->extra) + ri->extra->igpmetric = 0; + } + else if (peer) + bnc->nht_info = (void *)peer; return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } @@ -269,6 +289,7 @@ bgp_parse_nexthop_update (void) else { bnc->flags &= ~BGP_NEXTHOP_VALID; + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); bnc_nexthop_free(bnc); bnc->nexthop = NULL; } @@ -326,12 +347,21 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) /* Check socket. */ if (!zclient || zclient->sock < 0) - return; + { + zlog_debug("%s: Can't send NH register, Zebra client not established", + __FUNCTION__); + return; + } p = &(bnc->node->p); s = zclient->obuf; stream_reset (s); zclient_create_header (s, command, VRF_DEFAULT); + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + stream_putc(s, 1); + else + stream_putc(s, 0); + stream_putw(s, PREFIX_FAMILY(p)); stream_putc(s, p->prefixlen); switch (PREFIX_FAMILY(p)) @@ -339,11 +369,9 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) case AF_INET: stream_put_in_addr (s, &p->u.prefix4); break; -#ifdef HAVE_IPV6 case AF_INET6: stream_put(s, &(p->u.prefix6), 16); break; -#endif default: break; } @@ -353,6 +381,11 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) /* TBD: handle the failure */ if (ret < 0) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); + + if (command == ZEBRA_NEXTHOP_REGISTER) + SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + else if (command == ZEBRA_NEXTHOP_UNREGISTER) + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); return; } @@ -371,7 +404,6 @@ register_nexthop (struct bgp_nexthop_cache *bnc) if (bnc->flags & BGP_NEXTHOP_REGISTERED) return; sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER); - SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); } /** @@ -389,7 +421,6 @@ unregister_nexthop (struct bgp_nexthop_cache *bnc) return; sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER); - UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); } /** @@ -406,6 +437,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) struct bgp_info *path; struct bgp *bgp = bgp_get_default(); int afi; + struct peer *peer = (struct peer *)bnc->nht_info; LIST_FOREACH(path, &(bnc->paths), nh_thread) { @@ -448,6 +480,15 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) bgp_process(bgp, rn, afi, SAFI_UNICAST); } + + if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) + { + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host); + bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); + SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); + } + RESET_FLAG(bnc->change_flags); } diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 41c2b85ba..2bced7fbe 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -31,12 +31,9 @@ extern void bgp_parse_nexthop_update(void); * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object * ARGUMENTS: * p - path for which the nexthop object is being looked up - * c - output variable that stores whether the nexthop object has changed - * since last time. - * m - output variable that stores whether the nexthop metric has changed - * since last time. + * connected - True if NH MUST be a connected route */ -extern int bgp_find_nexthop(struct bgp_info *p, int *c, int *m); +extern int bgp_find_nexthop(struct bgp_info *p, int connected); /** * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc @@ -45,12 +42,11 @@ extern int bgp_find_nexthop(struct bgp_info *p, int *c, int *m); * ARGUMENTS: * a - afi: AFI_IP or AF_IP6 * p - path for which the nexthop object is being looked up - * c - output variable that stores whether the nexthop object has changed - * since last time. - * m - output variable that stores whether the nexthop metric has changed - * since last time. + * peer - The BGP peer associated with this NHT + * connected - True if NH MUST be a connected route */ -extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, int *c, int *m); +extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, + struct peer *peer, int connected); /** * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure. diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index f42e544b4..2ec595f79 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -103,8 +103,8 @@ bgp_packet_delete (struct peer *peer) } /* Check file descriptor whether connect is established. */ -static void -bgp_connect_check (struct peer *peer) +int +bgp_connect_check (struct peer *peer, int change_state) { int status; socklen_t slen; @@ -123,20 +123,23 @@ bgp_connect_check (struct peer *peer) { zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); - return; + return -1; } /* When status is 0 then TCP connection is established. */ if (status == 0) { BGP_EVENT_ADD (peer, TCP_connection_open); + return 1; } else { if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect failed (%s)", peer->host, safe_strerror (errno)); - BGP_EVENT_ADD (peer, TCP_connection_open_failed); + if (change_state) + BGP_EVENT_ADD (peer, TCP_connection_open_failed); + return 0; } } @@ -715,7 +718,7 @@ bgp_write (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer); + bgp_connect_check (peer, 1); return 0; } @@ -2492,7 +2495,7 @@ bgp_read (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer); + bgp_connect_check (peer, 1); goto done; } else diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 6b0b7f4d4..74c62c0b3 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -40,6 +40,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Packet send and receive function prototypes. */ extern int bgp_read (struct thread *); extern int bgp_write (struct thread *); +extern int bgp_connect_check (struct peer *, int change_state); extern void bgp_keepalive_send (struct peer *); extern void bgp_open_send (struct peer *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 066637b32..a88a0224f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -55,7 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" -#include "bgpd/bgp_nht.c" +#include "bgpd/bgp_nht.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -998,7 +998,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, || (NEXTHOP_IS_V6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) || (peer->sort == BGP_PEER_EBGP - && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) + && (bgp_multiaccess_check_v4 (attr->nexthop, peer) == 0))) { /* Set IPv4 nexthop. */ if (NEXTHOP_IS_V4) @@ -2129,6 +2129,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; + int connected = 0; memset (&new_attr, 0, sizeof(struct attr)); memset (&new_extra, 0, sizeof(struct attr_extra)); @@ -2209,17 +2210,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) { - /* If the peer is EBGP and nexthop is not on connected route, - discard it. */ - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 - && ! bgp_nexthop_onlink (afi, &new_attr) - && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) - { - reason = "non-connected next-hop;"; - bgp_attr_flush (&new_attr); - goto filtered; - } - /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ if (new_attr.nexthop.s_addr == 0 @@ -2347,20 +2337,29 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && safi == SAFI_UNICAST - && (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED - || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) - || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { - if (bgp_find_or_add_nexthop (afi, ri, NULL, NULL)) + if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && + ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + connected = 1; + else + connected = 0; + + if (bgp_find_or_add_nexthop (afi, ri, NULL, connected)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else - bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + } } else - bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); bgp_attr_flush (&new_attr); @@ -2390,17 +2389,26 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, memcpy ((bgp_info_extra_get (new))->tag, tag, 3); /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && safi == SAFI_UNICAST - && (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED - || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) - || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) - { - if (bgp_find_or_add_nexthop (afi, new, NULL, NULL)) + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) + { + if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && + ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + connected = 1; + else + connected = 0; + + if (bgp_find_or_add_nexthop (afi, new, NULL, connected)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else - bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + } } else bgp_info_set_flag (rn, new, BGP_INFO_VALID); @@ -3532,6 +3540,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, ri->attr = attr_new; ri->uptime = bgp_clock (); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, ri, NULL, 0)) + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, + buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + } + } /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); @@ -3544,7 +3569,25 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, /* Make new BGP info. */ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); - SET_FLAG (new->flags, BGP_INFO_VALID); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, new, NULL, 0)) + bgp_info_set_flag (rn, new, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, + buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + } + } + else + bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Register new BGP information. */ bgp_info_add (rn, new); @@ -3562,7 +3605,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, static void bgp_static_update_main (struct bgp *bgp, struct prefix *p, - struct bgp_static *bgp_static, afi_t afi, safi_t safi) + struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; @@ -3646,6 +3689,23 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, ri->attr = attr_new; ri->uptime = bgp_clock (); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, ri, NULL, 0)) + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, + buf1, INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); + } + } /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); @@ -3659,7 +3719,25 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, /* Make new BGP info. */ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); - SET_FLAG (new->flags, BGP_INFO_VALID); + /* Nexthop reachability check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + if (bgp_find_or_add_nexthop (afi, new, NULL, 0)) + bgp_info_set_flag (rn, new, BGP_INFO_VALID); + else + { + if (BGP_DEBUG(nht, NHT)) + { + char buf1[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, + INET6_ADDRSTRLEN); + zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + } + bgp_info_unset_flag (rn, new, BGP_INFO_VALID); + } + } + else + bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); @@ -3720,6 +3798,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, safi); + bgp_unlink_nexthop(ri); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } @@ -3978,17 +4057,12 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, rn->info = bgp_static; } - /* If BGP scan is not enabled, we should install this route here. */ - if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) - { - bgp_static->valid = 1; - - if (need_update) - bgp_static_withdraw (bgp, &p, afi, safi); + bgp_static->valid = 1; + if (need_update) + bgp_static_withdraw (bgp, &p, afi, safi); - if (! bgp_static->backdoor) - bgp_static_update (bgp, &p, bgp_static, afi, safi); - } + if (! bgp_static->backdoor) + bgp_static_update (bgp, &p, bgp_static, afi, safi); return CMD_SUCCESS; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 010e224e7..eacf80442 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -61,6 +61,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_nht.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ @@ -4564,24 +4565,33 @@ peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, else UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - return 0; - - group = peer->group; - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (! peer->af_group[afi][safi]) - continue; + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + if (! peer->af_group[afi][safi]) + continue; - SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); - peer->pmax[afi][safi] = max; - peer->pmax_threshold[afi][safi] = threshold; - peer->pmax_restart[afi][safi] = restart; - if (warning) - SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); - else - UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + peer->pmax[afi][safi] = max; + peer->pmax_threshold[afi][safi] = threshold; + peer->pmax_restart[afi][safi] = restart; + if (warning) + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + + if ((peer->status == Established) && (peer->afc[afi][safi])) + bgp_maximum_prefix_overflow (peer, afi, safi, 1); + } + } + else + { + if ((peer->status == Established) && (peer->afc[afi][safi])) + bgp_maximum_prefix_overflow (peer, afi, safi, 1); } + return 0; } @@ -5572,9 +5582,6 @@ bgp_config_write (struct vty *vty) if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); - /* BGP scan interval. */ - bgp_config_write_scan_time (vty); - /* BGP flag dampening. */ if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], BGP_CONFIG_DAMPENING)) @@ -5660,12 +5667,16 @@ bgp_master_init (void) void bgp_init (void) { - /* BGP VTY commands installation. */ - bgp_vty_init (); + + /* allocates some vital data structures used by peer commands in vty_init */ + bgp_scan_init (); /* Init zebra. */ bgp_zebra_init (bm->master); + /* BGP VTY commands installation. */ + bgp_vty_init (); + /* BGP inits. */ bgp_attr_init (); bgp_debug_init (); @@ -5673,7 +5684,7 @@ bgp_init (void) bgp_route_init (); bgp_route_map_init (); bgp_address_init (); - bgp_scan_init (); + bgp_scan_vty_init(); bgp_mplsvpn_init (); bgp_encap_init (); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 40da02ea6..87d2fff4c 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -997,4 +997,5 @@ extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); extern int peer_ttl_security_hops_set (struct peer *, int); extern int peer_ttl_security_hops_unset (struct peer *); +extern void bgp_scan_finish (void); #endif /* _QUAGGA_BGPD_H */ diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 02a14688f..7b6d0f82b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -212,7 +212,8 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) { if (!nrn->info) continue; - + + rnh = nrn->info; prn = route_node_match(ptable, &nrn->p); if (!prn) rib = NULL; @@ -223,11 +224,18 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + break; + } + else + break; + } } } - rnh = nrn->info; if (compare_state(rib, rnh->state)) { if (IS_ZEBRA_DEBUG_NHT) @@ -598,7 +606,9 @@ print_rnh (struct route_node *rn, struct vty *vty) print_nh(nexthop, vty); } else - vty_out(vty, " unresolved%s", VTY_NEWLINE); + vty_out(vty, " unresolved%s%s", + CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "", + VTY_NEWLINE); vty_out(vty, " Client list:"); for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 97dbba70d..574c95fab 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -30,6 +30,7 @@ struct rnh { u_char flags; +#define ZEBRA_NHT_CONNECTED 0x1 struct rib *state; struct list *client_list; struct route_node *node; diff --git a/zebra/zserv.c b/zebra/zserv.c index 4a8b55f97..f0e8d121f 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -748,6 +748,7 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t struct stream *s; struct prefix p; u_short l = 0; + u_char connected; if (IS_ZEBRA_DEBUG_NHT) zlog_debug("nexthop_register msg from client %s: length=%d\n", @@ -757,14 +758,19 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t while (l < length) { + connected = stream_getc(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); - l += 3; + l += 4; stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); l += PSIZE(p.prefixlen); rnh = zebra_add_rnh(&p, 0); client->nh_reg_time = quagga_time(NULL); + + if (connected) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + zebra_add_rnh_client(rnh, client, vrf_id); } zebra_evaluate_rnh_table(0, AF_INET); @@ -789,9 +795,10 @@ zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) while (l < length) { + (void)stream_getc(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); - l += 3; + l += 4; stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); l += PSIZE(p.prefixlen); rnh = zebra_lookup_rnh(&p, 0); From 789dfc9fe07e23e6c73a299ecbbcbb6d3d411391 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 6 Sep 2016 11:20:27 +0100 Subject: [PATCH 1152/1342] bgpd: Fix crash in 'show ip bgp nexthop' * bgp_nexthop.c: (show_ip_bgp_nexthop_table) the AFIs are sparse, and start from 1, check there's a table before derefing so as not to crash. --- bgpd/bgp_nexthop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 429c63813..bb3db9f0b 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -421,6 +421,9 @@ show_ip_bgp_nexthop_table (struct vty *vty, int detail) vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) { + if (!bgp_nexthop_cache_table[afi]) + continue; + for (rn = bgp_table_top (bgp_nexthop_cache_table[afi]); rn; rn = bgp_route_next (rn)) { if ((bnc = rn->info) != NULL) From 4b502fdb64db6fcad5359973e3ff7e7c88e93a7d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 27 Jul 2016 17:06:32 +0100 Subject: [PATCH 1153/1342] tests: Fix testbgpmpattr and make check, broken by BGP NHT. * bgp_mp_attr_test.c: Fix segfault due to uninitialised bgp_nexthop_cache globals in nexthop parsing path, which require bgp_scan_init() to have been called. Fixes issue introduced with: 'bgpd, zebra: Use next hop tracking for connected routes too' --- tests/bgp_mp_attr_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 5400dd179..3b1bf1452 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -758,6 +758,7 @@ main (void) bgp_option_set (BGP_OPT_NO_LISTEN); bgp_attr_init (); bgp_address_init (); + bgp_scan_init (); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); From c365b534623279049bc4cc0c5d03fdbcd2d466b0 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 26 Jul 2016 10:58:53 -0400 Subject: [PATCH 1154/1342] bgpd: Remove unused and leaking code --- bgpd/bgp_route.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a88a0224f..4cb6c141b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3778,14 +3778,9 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, { struct bgp_node *rn; struct bgp_info *ri; - struct bgp_info *new; /* Make new BGP info. */ rn = bgp_node_get (bgp->rib[afi][safi], p); - new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, - bgp_attr_default_intern(BGP_ORIGIN_IGP), rn); - - SET_FLAG (new->flags, BGP_INFO_VALID); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) From 19e6c193db0c74ed08dbb5cd30dfa8f6a4377af0 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 6 Sep 2016 17:23:48 +0100 Subject: [PATCH 1155/1342] bgpd: bgp_nexthop_cache not deleted with peers * Fix mild leak, bgp_nexthop_caches were not deleted when their peer was. Not a huge one, but makes valgrinding for other leaks noisier. Credit to Lou Berger for doing the hard work of debugging and pinning down the leak, and supplying an initial fix. That one didn't quite get the refcounting right, it seemed, hence this version. This version also keeps bncs pinned so long as the peer is defined, where Lou's tried to delete whenever the peer went through bgp_stop. That causes lots of zebra traffic if down peers go Active->Connect->Active, etc., so leaving bnc's in place until peer_delete seemed better. * bgp_nht.c: (bgp_unlink_nexthop_by_peer) similar to bgp_unlink_nexthop, but by peer. * bgp_nht.c: (bgp_unlink_nexthop_check) helper to consolidate checking if a bnc should be deleted. (bgp_unlink_nexthop_by_peer) ensure the bnc->nht_info peer reference is removed, and hence allow bncs to be removed by previous. * bgpd.c: (peer_delete) cleanup the peer's bnc. --- bgpd/bgp_nht.c | 65 +++++++++++++++++++++++++++++++++++++++++--------- bgpd/bgp_nht.h | 1 + bgpd/bgpd.c | 5 +++- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 34b5fd1c1..591fbf98e 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -65,16 +65,9 @@ bgp_find_nexthop (struct bgp_info *path, int connected) return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } -void -bgp_unlink_nexthop (struct bgp_info *path) +static void +bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc) { - struct bgp_nexthop_cache *bnc = path->nexthop; - - if (!bnc) - return; - - path_nh_map(path, NULL, 0); - if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { if (BGP_DEBUG(nht, NHT)) @@ -86,10 +79,60 @@ bgp_unlink_nexthop (struct bgp_info *path) unregister_nexthop(bnc); bnc->node->info = NULL; bgp_unlock_node(bnc->node); + bnc->node = NULL; bnc_free(bnc); } } +void +bgp_unlink_nexthop (struct bgp_info *path) +{ + struct bgp_nexthop_cache *bnc = path->nexthop; + + if (!bnc) + return; + + path_nh_map(path, NULL, 0); + + bgp_unlink_nexthop_check (bnc); +} + +void +bgp_unlink_nexthop_by_peer (struct peer *peer) +{ + struct prefix p; + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + afi_t afi = family2afi(peer->su.sa.sa_family); + + if (afi == AFI_IP) + { + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = peer->su.sin.sin_addr; + } + else if (afi == AFI_IP6) + { + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = peer->su.sin6.sin6_addr; + } + else + return; + + rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); + + if (!rn->info) + return; + + bnc = rn->info; + + /* cleanup the peer reference */ + bnc->nht_info = NULL; + + bgp_unlink_nexthop_check (bnc); +} + int bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, int connected) @@ -139,7 +182,7 @@ bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, if (ri) { - path_nh_map(ri, bnc, 1); + path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) (bgp_info_extra_get(ri))->igpmetric = bnc->metric; @@ -147,7 +190,7 @@ bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, ri->extra->igpmetric = 0; } else if (peer) - bnc->nht_info = (void *)peer; + bnc->nht_info = (void *)peer; /* NHT peer reference */ return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 2bced7fbe..5086b0806 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -54,5 +54,6 @@ extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, * p - path structure. */ extern void bgp_unlink_nexthop(struct bgp_info *p); +void bgp_unlink_nexthop_by_peer (struct peer *); #endif /* _BGP_NHT_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index eacf80442..018a59941 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1297,7 +1297,10 @@ peer_delete (struct peer *peer) peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_stop (peer); bgp_fsm_change_status (peer, Deleted); - + + /* Remove from NHT */ + bgp_unlink_nexthop_by_peer (peer); + /* Password configuration */ if (peer->password) { From 810ab34c56a9b9b8870b961bc96986e6b8550863 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Mon, 5 Sep 2016 12:18:15 -0400 Subject: [PATCH 1156/1342] bgp: bgp_nexthop init/free AFI_ETHER related NH tables --- bgpd/bgp_nexthop.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index bb3db9f0b..479ef9493 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -518,7 +518,10 @@ bgp_scan_init (void) cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); - + + cache1_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); + bgp_nexthop_cache_table[AFI_ETHER] = cache1_table[AFI_ETHER]; + bgp_connected_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); } void @@ -546,6 +549,15 @@ bgp_scan_finish (void) if (bgp_connected_table[AFI_IP6]) bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; + + if (cache1_table[AFI_ETHER]) + bgp_table_unlock (cache1_table[AFI_ETHER]); + cache1_table[AFI_ETHER] = NULL; + + if (bgp_connected_table[AFI_ETHER]) + bgp_table_unlock (bgp_connected_table[AFI_ETHER]); + bgp_connected_table[AFI_ETHER] = NULL; + } void From b4e011985232f28d98e4df88c7cb13ee8f95ef46 Mon Sep 17 00:00:00 2001 From: Evgeny Uskov Date: Wed, 13 Jan 2016 13:58:00 +0300 Subject: [PATCH 1157/1342] bgpd: Fix buffer overflow error in bgp_dump_routes_func Now if the number of entries for some prefix is too large, multiple TABLE_DUMP_V2 records are created. In the previous version in such situation bgpd crashed with SIGABRT. --- bgpd/bgp_dump.c | 171 +++++++++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 73 deletions(-) diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index da0c2ac33..01f9b412f 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -307,11 +307,100 @@ bgp_dump_routes_index_table(struct bgp *bgp) } +static struct bgp_info * +bgp_dump_route_node_record (int afi, struct bgp_node *rn, + struct bgp_info *info, unsigned int seq) +{ + struct stream *obuf; + size_t sizep; + size_t endp; + + obuf = bgp_dump_obuf; + stream_reset (obuf); + + /* MRT header */ + if (afi == AFI_IP) + bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST, + BGP_DUMP_ROUTES); + else if (afi == AFI_IP6) + bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST, + BGP_DUMP_ROUTES); + + /* Sequence number */ + stream_putl (obuf, seq); + + /* Prefix length */ + stream_putc (obuf, rn->p.prefixlen); + + /* Prefix */ + if (afi == AFI_IP) + { + /* We'll dump only the useful bits (those not 0), but have to + * align on 8 bits */ + stream_write (obuf, (u_char *) &rn->p.u.prefix4, + (rn->p.prefixlen + 7) / 8); + } + else if (afi == AFI_IP6) + { + /* We'll dump only the useful bits (those not 0), but have to + * align on 8 bits */ + stream_write (obuf, (u_char *) &rn->p.u.prefix6, + (rn->p.prefixlen + 7) / 8); + } + + /* Save where we are now, so we can overwride the entry count later */ + sizep = stream_get_endp (obuf); + + /* Entry count */ + uint16_t entry_count = 0; + + /* Entry count, note that this is overwritten later */ + stream_putw (obuf, 0); + + endp = stream_get_endp (obuf); + for (; info; info = info->next) + { + size_t cur_endp; + + /* Peer index */ + stream_putw (obuf, info->peer->table_dump_index); + + /* Originated */ +#ifdef HAVE_CLOCK_MONOTONIC + stream_putl (obuf, time (NULL) - (bgp_clock () - info->uptime)); +#else + stream_putl (obuf, info->uptime); +#endif /* HAVE_CLOCK_MONOTONIC */ + + /* Dump attribute. */ + /* Skip prefix & AFI/SAFI for MP_NLRI */ + bgp_dump_routes_attr (obuf, info->attr, &rn->p); + + cur_endp = stream_get_endp (obuf); + if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER + + BGP_DUMP_HEADER_SIZE) + { + stream_set_endp (obuf, endp); + break; + } + + entry_count++; + endp = cur_endp; + } + + /* Overwrite the entry count, now that we know the right number */ + stream_putw_at (obuf, sizep, entry_count); + + bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2); + fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); + + return info; +} + /* Runs under child process. */ static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { - struct stream *obuf; struct bgp_info *info; struct bgp_node *rn; struct bgp *bgp; @@ -330,81 +419,17 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq) if(first_run) bgp_dump_routes_index_table(bgp); - obuf = bgp_dump_obuf; - stream_reset(obuf); - /* Walk down each BGP route. */ table = bgp->rib[afi][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { - if(!rn->info) - continue; - - stream_reset(obuf); - - /* MRT header */ - if (afi == AFI_IP) - bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST, - BGP_DUMP_ROUTES); - else if (afi == AFI_IP6) - bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST, - BGP_DUMP_ROUTES); - - /* Sequence number */ - stream_putl(obuf, seq); - - /* Prefix length */ - stream_putc (obuf, rn->p.prefixlen); - - /* Prefix */ - if (afi == AFI_IP) - { - /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ - stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8); - } - else if (afi == AFI_IP6) - { - /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ - stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8); - } - - /* Save where we are now, so we can overwride the entry count later */ - int sizep = stream_get_endp(obuf); - - /* Entry count */ - uint16_t entry_count = 0; - - /* Entry count, note that this is overwritten later */ - stream_putw(obuf, 0); - - for (info = rn->info; info; info = info->next) - { - entry_count++; - - /* Peer index */ - stream_putw(obuf, info->peer->table_dump_index); - - /* Originated */ -#ifdef HAVE_CLOCK_MONOTONIC - stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime)); -#else - stream_putl (obuf, info->uptime); -#endif /* HAVE_CLOCK_MONOTONIC */ - - /* Dump attribute. */ - /* Skip prefix & AFI/SAFI for MP_NLRI */ - bgp_dump_routes_attr (obuf, info->attr, &rn->p); - } - - /* Overwrite the entry count, now that we know the right number */ - stream_putw_at (obuf, sizep, entry_count); - - seq++; - - bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); - fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); - + info = rn->info; + while (info) + { + info = bgp_dump_route_node_record(afi, rn, info, seq); + seq++; + } } fflush (bgp_dump_routes.fp); @@ -851,8 +876,8 @@ bgp_dump_init (void) memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump)); memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump)); - bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER - + BGP_DUMP_HEADER_SIZE); + bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1) + + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE); install_node (&bgp_dump_node, config_write_bgp_dump); From f5603ccd01131a1905b842e36171d0f5c0424496 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 12 Sep 2016 13:53:08 +0100 Subject: [PATCH 1158/1342] isisd: cleanup isis_circuit_lookup, errant from TE changes? --- isisd/isis_circuit.h | 1 - 1 file changed, 1 deletion(-) diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 0671d2487..354a06bdb 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -144,7 +144,6 @@ void isis_circuit_del (struct isis_circuit *circuit); struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp, struct list *list); struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp); -struct isis_circuit * isis_circuit_lookup (struct vty *vty); void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area); void isis_circuit_deconfigure (struct isis_circuit *circuit, From 3732cba03049b18fc414c36254cfc11186b2ba53 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 29 Jul 2016 16:19:40 +0200 Subject: [PATCH 1159/1342] isisd: API: basic circuit config Create isis_vty.c and start moving off CLI functions into that. These then call newly-added "nice" API wrappers. Patch contains significant work authored by Christian Franke. [v2: removed stuff that crept in from the next patch] Signed-off-by: David Lamparter --- isisd/Makefile.am | 3 +- isisd/isis_circuit.c | 879 ++++--------------------------------------- isisd/isis_circuit.h | 12 + isisd/isis_redist.h | 1 + isisd/isis_vty.c | 678 +++++++++++++++++++++++++++++++++ isisd/isisd.h | 6 + 6 files changed, 771 insertions(+), 808 deletions(-) create mode 100644 isisd/isis_vty.c diff --git a/isisd/Makefile.am b/isisd/Makefile.am index e3ecbc00a..bfe2e9477 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -16,7 +16,8 @@ libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ - isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c + isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ + isis_vty.c noinst_HEADERS = \ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 75953ff81..6adda0889 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1248,364 +1248,88 @@ isis_interface_config_write (struct vty *vty) return write; } -DEFUN (ip_router_isis, - ip_router_isis_cmd, - "ip router isis WORD", - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - "IS-IS Routing for IP\n" - "Routing process tag\n") +struct isis_circuit * +isis_circuit_create (struct isis_area *area, struct interface *ifp) { struct isis_circuit *circuit; - struct interface *ifp; - struct isis_area *area; - int rv; - - ifp = (struct interface *) vty->index; - assert (ifp); - - /* Prevent more than one area per circuit */ - circuit = circuit_scan_by_ifp (ifp); - if (circuit) - { - if (circuit->ip_router == 1) - { - if (strcmp (circuit->area->area_tag, argv[0])) - { - vty_out (vty, "ISIS circuit is already defined on %s%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_NOTHING_TODO; - } - return CMD_SUCCESS; - } - } - - if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - area = vty->index; - - circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); - if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) - { - vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); - rv = CMD_WARNING; - } - else - { - isis_circuit_if_bind (circuit, ifp); - - circuit->ip_router = 1; - area->ip_circuits++; - circuit_update_nlpids (circuit); - rv = CMD_SUCCESS; - } - - vty->node = INTERFACE_NODE; - vty->index = ifp; - - if (circuit->ipv6_router) - lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - return rv; + circuit = isis_csm_state_change (ISIS_ENABLE, NULL, area); + assert (circuit->state == C_STATE_CONF || circuit->state == C_STATE_UP); + isis_circuit_if_bind (circuit, ifp); + return circuit; } -DEFUN (no_ip_router_isis, - no_ip_router_isis_cmd, - "no ip router isis WORD", - NO_STR - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - "IS-IS Routing for IP\n" - "Routing process tag\n") +void +isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router) { - struct interface *ifp; - struct isis_area *area; - struct isis_circuit *circuit; + struct isis_area *area = circuit->area; + bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router; + bool was_enabled = circuit->ip_router || circuit->ipv6_router; - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + area->ip_circuits += ip_router - circuit->ip_router; + area->ipv6_circuits += ipv6_router - circuit->ipv6_router; + circuit->ip_router = ip_router; + circuit->ipv6_router = ipv6_router; - area = isis_area_lookup (argv[0]); - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s%s", - argv[0], VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + if (!change) + return; - circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + circuit_update_nlpids (circuit); - circuit->ip_router = 0; - area->ip_circuits--; - if (circuit->ipv6_router == 0) + if (!ip_router && !ipv6_router) isis_csm_state_change (ISIS_DISABLE, circuit, area); + else if (!was_enabled) + isis_csm_state_change (ISIS_ENABLE, circuit, area); else - lsp_regenerate_schedule(area, circuit->is_type, 0); - - return CMD_SUCCESS; -} - -#ifdef HAVE_IPV6 -DEFUN (ipv6_router_isis, - ipv6_router_isis_cmd, - "ipv6 router isis WORD", - "IPv6 interface subcommands\n" - "IPv6 Router interface commands\n" - "IS-IS Routing for IPv6\n" - "Routing process tag\n") -{ - struct isis_circuit *circuit; - struct interface *ifp; - struct isis_area *area; - int rv; - - ifp = (struct interface *) vty->index; - assert (ifp); - - /* Prevent more than one area per circuit */ - circuit = circuit_scan_by_ifp (ifp); - if (circuit) - { - if (circuit->ipv6_router == 1) - { - if (strcmp (circuit->area->area_tag, argv[0])) - { - vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_NOTHING_TODO; - } - return CMD_SUCCESS; - } - } - - if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - area = vty->index; - - circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); - if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) - { - vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); - rv = CMD_WARNING; - } - else - { - isis_circuit_if_bind (circuit, ifp); - - circuit->ipv6_router = 1; - area->ipv6_circuits++; - circuit_update_nlpids (circuit); - rv = CMD_SUCCESS; - } - - vty->node = INTERFACE_NODE; - vty->index = ifp; - - if (circuit->ip_router) lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - return rv; } -DEFUN (no_ipv6_router_isis, - no_ipv6_router_isis_cmd, - "no ipv6 router isis WORD", - NO_STR - "IPv6 interface subcommands\n" - "IPv6 Router interface commands\n" - "IS-IS Routing for IPv6\n" - "Routing process tag\n") -{ - struct interface *ifp; - struct isis_area *area; - struct isis_circuit *circuit; - - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - area = isis_area_lookup (argv[0]); - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s%s", - argv[0], VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - circuit->ipv6_router = 0; - area->ipv6_circuits--; - if (circuit->ip_router == 0) - isis_csm_state_change (ISIS_DISABLE, circuit, area); - else - lsp_regenerate_schedule(area, circuit->is_type, 0); - - return CMD_SUCCESS; -} -#endif /* HAVE_IPV6 */ - -DEFUN (isis_passive, - isis_passive_cmd, - "isis passive", - "IS-IS commands\n" - "Configure the passive mode for interface\n") +int +isis_circuit_passive_set (struct isis_circuit *circuit, bool passive) { - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; + if (circuit->is_passive == passive) + return 0; - if (circuit->is_passive == 1) - return CMD_SUCCESS; + if (if_is_loopback (circuit->interface) && !passive) + return -1; if (circuit->state != C_STATE_UP) { - circuit->is_passive = 1; + circuit->is_passive = passive; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->is_passive = 1; + circuit->is_passive = passive; isis_csm_state_change (ISIS_ENABLE, circuit, area); } - return CMD_SUCCESS; + return 0; } -DEFUN (no_isis_passive, - no_isis_passive_cmd, - "no isis passive", - NO_STR - "IS-IS commands\n" - "Configure the passive mode for interface\n") +void +isis_circuit_is_type_set (struct isis_circuit *circuit, int circ_type) { - struct interface *ifp; - struct isis_circuit *circuit; - - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - /* FIXME: what is wrong with circuit = ifp->info ? */ - circuit = circuit_scan_by_ifp (ifp); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - if (if_is_loopback(ifp)) - { - vty_out (vty, "Can't set no passive for loopback interface%s", - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - if (circuit->is_passive == 0) - return CMD_SUCCESS; - - if (circuit->state != C_STATE_UP) - { - circuit->is_passive = 0; - } - else - { - struct isis_area *area = circuit->area; - isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->is_passive = 0; - isis_csm_state_change (ISIS_ENABLE, circuit, area); - } - - return CMD_SUCCESS; + if (circuit->circ_type != circ_type) + isis_event_circuit_type_change (circuit, circ_type); } -DEFUN (isis_circuit_type, - isis_circuit_type_cmd, - "isis circuit-type (level-1|level-1-2|level-2-only)", - "IS-IS commands\n" - "Configure circuit type for interface\n" - "Level-1 only adjacencies are formed\n" - "Level-1-2 adjacencies are formed\n" - "Level-2 only adjacencies are formed\n") -{ - int circuit_type; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit_type = string2circuit_t (argv[0]); - if (!circuit_type) - { - vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - if (circuit->state == C_STATE_UP && - circuit->area->is_type != IS_LEVEL_1_AND_2 && - circuit->area->is_type != circuit_type) - { - vty_out (vty, "Invalid circuit level for area %s.%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - isis_event_circuit_type_change (circuit, circuit_type); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_circuit_type, - no_isis_circuit_type_cmd, - "no isis circuit-type (level-1|level-1-2|level-2-only)", - NO_STR - "IS-IS commands\n" - "Configure circuit type for interface\n" - "Level-1 only adjacencies are formed\n" - "Level-1-2 adjacencies are formed\n" - "Level-2 only adjacencies are formed\n") +int +isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric) { - int circuit_type; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; + assert (level == IS_LEVEL_1 || level == IS_LEVEL_2); + if (metric > MAX_WIDE_LINK_METRIC) + return -1; + if (circuit->area && circuit->area->oldmetric + && metric > MAX_NARROW_LINK_METRIC) + return -1; - /* - * Set the circuits level to its default value - */ - if (circuit->state == C_STATE_UP) - circuit_type = circuit->area->is_type; - else - circuit_type = IS_LEVEL_1_AND_2; - isis_event_circuit_type_change (circuit, circuit_type); + circuit->te_metric[level - 1] = metric; + circuit->metrics[level - 1].metric_default = metric; - return CMD_SUCCESS; + if (circuit->area) + lsp_regenerate_schedule (circuit->area, level, 0); + return 0; } DEFUN (isis_passwd_md5, @@ -1676,387 +1400,6 @@ DEFUN (no_isis_passwd, return CMD_SUCCESS; } -DEFUN (isis_priority, - isis_priority_cmd, - "isis priority <0-127>", - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n") -{ - int prio; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - prio = atoi (argv[0]); - if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) - { - vty_out (vty, "Invalid priority %d - should be <0-127>%s", - prio, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->priority[0] = prio; - circuit->priority[1] = prio; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_priority, - no_isis_priority_cmd, - "no isis priority", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->priority[0] = DEFAULT_PRIORITY; - circuit->priority[1] = DEFAULT_PRIORITY; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_priority, - no_isis_priority_arg_cmd, - "no isis priority <0-127>", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n") - -DEFUN (isis_priority_l1, - isis_priority_l1_cmd, - "isis priority <0-127> level-1", - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-1 routing\n") -{ - int prio; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - prio = atoi (argv[0]); - if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) - { - vty_out (vty, "Invalid priority %d - should be <0-127>%s", - prio, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->priority[0] = prio; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_priority_l1, - no_isis_priority_l1_cmd, - "no isis priority level-1", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Specify priority for level-1 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->priority[0] = DEFAULT_PRIORITY; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_priority_l1, - no_isis_priority_l1_arg_cmd, - "no isis priority <0-127> level-1", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-1 routing\n") - -DEFUN (isis_priority_l2, - isis_priority_l2_cmd, - "isis priority <0-127> level-2", - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-2 routing\n") -{ - int prio; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - prio = atoi (argv[0]); - if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) - { - vty_out (vty, "Invalid priority %d - should be <0-127>%s", - prio, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->priority[1] = prio; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_priority_l2, - no_isis_priority_l2_cmd, - "no isis priority level-2", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Specify priority for level-2 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->priority[1] = DEFAULT_PRIORITY; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_priority_l2, - no_isis_priority_l2_arg_cmd, - "no isis priority <0-127> level-2", - NO_STR - "IS-IS commands\n" - "Set priority for Designated Router election\n" - "Priority value\n" - "Specify priority for level-2 routing\n") - -/* Metric command */ -DEFUN (isis_metric, - isis_metric_cmd, - "isis metric <0-16777215>", - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n") -{ - int met; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - met = atoi (argv[0]); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 && - met > MAX_NARROW_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 && - met > MAX_WIDE_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->te_metric[0] = met; - circuit->te_metric[1] = met; - - circuit->metrics[0].metric_default = met; - circuit->metrics[1].metric_default = met; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_metric, - no_isis_metric_cmd, - "no isis metric", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; - circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); - - return CMD_SUCCESS; -} - -ALIAS (no_isis_metric, - no_isis_metric_arg_cmd, - "no isis metric <0-16777215>", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n") - -DEFUN (isis_metric_l1, - isis_metric_l1_cmd, - "isis metric <0-16777215> level-1", - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-1 routing\n") -{ - int met; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - met = atoi (argv[0]); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 && - met > MAX_NARROW_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 && - met > MAX_WIDE_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->te_metric[0] = met; - circuit->metrics[0].metric_default = met; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_metric_l1, - no_isis_metric_l1_cmd, - "no isis metric level-1", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Specify metric for level-1 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); - - return CMD_SUCCESS; -} - -ALIAS (no_isis_metric_l1, - no_isis_metric_l1_arg_cmd, - "no isis metric <0-16777215> level-1", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-1 routing\n") - -DEFUN (isis_metric_l2, - isis_metric_l2_cmd, - "isis metric <0-16777215> level-2", - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-2 routing\n") -{ - int met; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - met = atoi (argv[0]); - - /* RFC3787 section 5.1 */ - if (circuit->area && circuit->area->oldmetric == 1 && - met > MAX_NARROW_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-63> " - "when narrow metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - /* RFC4444 */ - if (circuit->area && circuit->area->newmetric == 1 && - met > MAX_WIDE_LINK_METRIC) - { - vty_out (vty, "Invalid metric %d - should be <0-16777215> " - "when wide metric type enabled%s", - met, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->te_metric[1] = met; - circuit->metrics[1].metric_default = met; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_isis_metric_l2, - no_isis_metric_l2_cmd, - "no isis metric level-2", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Specify metric for level-2 routing\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; - - if (circuit->area) - lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); - - return CMD_SUCCESS; -} - -ALIAS (no_isis_metric_l2, - no_isis_metric_l2_arg_cmd, - "no isis metric <0-16777215> level-2", - NO_STR - "IS-IS commands\n" - "Set default metric for circuit\n" - "Default metric value\n" - "Specify metric for level-2 routing\n") -/* end of metrics */ - DEFUN (isis_hello_interval, isis_hello_interval_cmd, "isis hello-interval <1-600>", @@ -2724,86 +2067,43 @@ struct cmd_node interface_node = { 1, }; -DEFUN (isis_network, - isis_network_cmd, - "isis network point-to-point", - "IS-IS commands\n" - "Set network type\n" - "point-to-point network type\n") +int +isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) { - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - /* RFC5309 section 4 */ - if (circuit->circ_type == CIRCUIT_T_P2P) - return CMD_SUCCESS; - - if (circuit->state != C_STATE_UP) + /* Changing the network type to/of loopback or unknown interfaces + * is not supported. */ + if (circ_type == CIRCUIT_T_UNKNOWN + || circ_type == CIRCUIT_T_LOOPBACK + || circuit->circ_type == CIRCUIT_T_UNKNOWN + || circuit->circ_type == CIRCUIT_T_LOOPBACK) { - circuit->circ_type = CIRCUIT_T_P2P; - circuit->circ_type_config = CIRCUIT_T_P2P; - } - else - { - struct isis_area *area = circuit->area; - if (!if_is_broadcast (circuit->interface)) - { - vty_out (vty, "isis network point-to-point " - "is valid only on broadcast interfaces%s", - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->circ_type = CIRCUIT_T_P2P; - circuit->circ_type_config = CIRCUIT_T_P2P; - isis_csm_state_change (ISIS_ENABLE, circuit, area); + if (circuit->circ_type != circ_type) + return -1; + else + return 0; } - return CMD_SUCCESS; -} - -DEFUN (no_isis_network, - no_isis_network_cmd, - "no isis network point-to-point", - NO_STR - "IS-IS commands\n" - "Set network type for circuit\n" - "point-to-point network type\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - /* RFC5309 section 4 */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - return CMD_SUCCESS; + if (circuit->circ_type == circ_type) + return 0; if (circuit->state != C_STATE_UP) { - circuit->circ_type = CIRCUIT_T_BROADCAST; - circuit->circ_type_config = CIRCUIT_T_BROADCAST; + circuit->circ_type = circ_type; + circuit->circ_type_config = circ_type; } else { struct isis_area *area = circuit->area; - if (circuit->interface && - !if_is_broadcast (circuit->interface)) - { - vty_out (vty, "no isis network point-to-point " - "is valid only on broadcast interfaces%s", - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + if (circ_type == CIRCUIT_T_BROADCAST + && !if_is_broadcast(circuit->interface)) + return -1; - isis_csm_state_change (ISIS_DISABLE, circuit, area); - circuit->circ_type = CIRCUIT_T_BROADCAST; - circuit->circ_type_config = CIRCUIT_T_BROADCAST; - isis_csm_state_change (ISIS_ENABLE, circuit, area); + isis_csm_state_change(ISIS_DISABLE, circuit, area); + circuit->circ_type = circ_type; + circuit->circ_type_config = circ_type; + isis_csm_state_change(ISIS_ENABLE, circuit, area); } - - return CMD_SUCCESS; + return 0; } int @@ -2843,39 +2143,10 @@ isis_circuit_init () install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); - install_element (INTERFACE_NODE, &ip_router_isis_cmd); - install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); - - install_element (INTERFACE_NODE, &isis_passive_cmd); - install_element (INTERFACE_NODE, &no_isis_passive_cmd); - - install_element (INTERFACE_NODE, &isis_circuit_type_cmd); - install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); - install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_cmd); - install_element (INTERFACE_NODE, &isis_priority_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); - install_element (INTERFACE_NODE, &isis_priority_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_priority_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_metric_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); - install_element (INTERFACE_NODE, &isis_metric_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_metric_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); @@ -2919,11 +2190,5 @@ isis_circuit_init () install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); - install_element (INTERFACE_NODE, &isis_network_cmd); - install_element (INTERFACE_NODE, &no_isis_network_cmd); - -#ifdef HAVE_IPV6 - install_element (INTERFACE_NODE, &ipv6_router_isis_cmd); - install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd); -#endif + isis_vty_init (); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 354a06bdb..343b492f3 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -24,6 +24,10 @@ #define ISIS_CIRCUIT_H #include "vty.h" +#include "if.h" + +#include "isis_constants.h" +#include "isis_common.h" #define CIRCUIT_MAX 255 @@ -168,4 +172,12 @@ void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, size_t isis_circuit_pdu_size(struct isis_circuit *circuit); void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream); +struct isis_circuit *isis_circuit_create (struct isis_area *area, struct interface *ifp); +void isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router); +int isis_circuit_passive_set (struct isis_circuit *circuit, bool passive); +void isis_circuit_is_type_set (struct isis_circuit *circuit, int is_type); +int isis_circuit_circ_type_set (struct isis_circuit *circuit, int circ_type); + +int isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric); + #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h index 218462005..cc9c2e634 100644 --- a/isisd/isis_redist.h +++ b/isisd/isis_redist.h @@ -44,6 +44,7 @@ struct isis_redist struct isis_area; struct prefix; +struct vty; struct route_table *get_ext_reach(struct isis_area *area, int family, int level); diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c new file mode 100644 index 000000000..4b45df1df --- /dev/null +++ b/isisd/isis_vty.c @@ -0,0 +1,678 @@ +/* + * IS-IS Rout(e)ing protocol - isis_circuit.h + * + * Copyright (C) 2001,2002 Sampo Saaristo + * Tampere University of Technology + * Institute of Communications Engineering + * Copyright (C) 2016 David Lamparter, for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public Licenseas published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "isis_circuit.h" +#include "isis_csm.h" +#include "isis_misc.h" +#include "isisd.h" + +static struct isis_circuit * +isis_circuit_lookup (struct vty *vty) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *) vty->index; + if (!ifp) + { + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return NULL; + } + + circuit = circuit_scan_by_ifp (ifp); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return NULL; + } + + return circuit; +} + +DEFUN (ip_router_isis, + ip_router_isis_cmd, + "(ip|ipv6) router isis WORD", + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + "IS-IS Routing for IP\n" + "Routing process tag\n") +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_area *area; + const char *af = argv[0]; + const char *area_tag = argv[1]; + + ifp = (struct interface *) vty->index; + assert (ifp); + + /* Prevent more than one area per circuit */ + circuit = circuit_scan_by_ifp (ifp); + if (circuit) + { + if (circuit->ip_router == 1) + { + if (strcmp (circuit->area->area_tag, area_tag)) + { + vty_out (vty, "ISIS circuit is already defined on %s%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + return CMD_SUCCESS; + } + } + + area = isis_area_lookup (area_tag); + if (!area) + area = isis_area_create (area_tag); + + if (!circuit) + circuit = isis_circuit_create (area, ifp); + + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; + if (af[2] != '\0') + ipv6 = true; + else + ip = true; + + isis_circuit_af_set (circuit, ip, ipv6); + return CMD_SUCCESS; +} + +DEFUN (no_ip_router_isis, + no_ip_router_isis_cmd, + "no (ip|ipv6) router isis WORD", + NO_STR + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + "IS-IS Routing for IP\n" + "Routing process tag\n") +{ + struct interface *ifp; + struct isis_area *area; + struct isis_circuit *circuit; + const char *af = argv[0]; + const char *area_tag = argv[1]; + + ifp = (struct interface *) vty->index; + if (!ifp) + { + vty_out (vty, "Invalid interface %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + area = isis_area_lookup (area_tag); + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s%s", + argv[0], VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (!circuit) + { + vty_out (vty, "ISIS is not enabled on circuit %s%s", + ifp->name, VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; + if (af[2] != '\0') + ipv6 = false; + else + ip = false; + + isis_circuit_af_set (circuit, ip, ipv6); + return CMD_SUCCESS; +} + +DEFUN (isis_passive, + isis_passive_cmd, + "isis passive", + "IS-IS commands\n" + "Configure the passive mode for interface\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_passive_set (circuit, 1); + return CMD_SUCCESS; +} + +DEFUN (no_isis_passive, + no_isis_passive_cmd, + "no isis passive", + NO_STR + "IS-IS commands\n" + "Configure the passive mode for interface\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (if_is_loopback (circuit->interface)) + { + vty_out (vty, "Can't set no passive for loopback interface%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_passive_set (circuit, 0); + return CMD_SUCCESS; +} + +DEFUN (isis_circuit_type, + isis_circuit_type_cmd, + "isis circuit-type (level-1|level-1-2|level-2-only)", + "IS-IS commands\n" + "Configure circuit type for interface\n" + "Level-1 only adjacencies are formed\n" + "Level-1-2 adjacencies are formed\n" + "Level-2 only adjacencies are formed\n") +{ + int is_type; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + is_type = string2circuit_t (argv[0]); + if (!is_type) + { + vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + if (circuit->state == C_STATE_UP && + circuit->area->is_type != IS_LEVEL_1_AND_2 && + circuit->area->is_type != is_type) + { + vty_out (vty, "Invalid circuit level for area %s.%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + isis_circuit_is_type_set (circuit, is_type); + + return CMD_SUCCESS; +} + +DEFUN (no_isis_circuit_type, + no_isis_circuit_type_cmd, + "no isis circuit-type (level-1|level-1-2|level-2-only)", + NO_STR + "IS-IS commands\n" + "Configure circuit type for interface\n" + "Level-1 only adjacencies are formed\n" + "Level-1-2 adjacencies are formed\n" + "Level-2 only adjacencies are formed\n") +{ + int is_type; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + /* + * Set the circuits level to its default value + */ + if (circuit->state == C_STATE_UP) + is_type = circuit->area->is_type; + else + is_type = IS_LEVEL_1_AND_2; + isis_circuit_is_type_set (circuit, is_type); + + return CMD_SUCCESS; +} + +DEFUN (isis_network, + isis_network_cmd, + "isis network point-to-point", + "IS-IS commands\n" + "Set network type\n" + "point-to-point network type\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (!isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) + { + vty_out (vty, "isis network point-to-point " + "is valid only on broadcast interfaces%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_network, + no_isis_network_cmd, + "no isis network point-to-point", + NO_STR + "IS-IS commands\n" + "Set network type for circuit\n" + "point-to-point network type\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (!isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) + { + vty_out (vty, "isis network point-to-point " + "is valid only on broadcast interfaces%s", + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return CMD_SUCCESS; +} + +DEFUN (isis_priority, + isis_priority_cmd, + "isis priority <0-127>", + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n") +{ + int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) + { + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->priority[0] = prio; + circuit->priority[1] = prio; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_priority, + no_isis_priority_cmd, + "no isis priority", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->priority[0] = DEFAULT_PRIORITY; + circuit->priority[1] = DEFAULT_PRIORITY; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_priority, + no_isis_priority_arg_cmd, + "no isis priority <0-127>", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n") + +DEFUN (isis_priority_l1, + isis_priority_l1_cmd, + "isis priority <0-127> level-1", + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-1 routing\n") +{ + int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) + { + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->priority[0] = prio; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_priority_l1, + no_isis_priority_l1_cmd, + "no isis priority level-1", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Specify priority for level-1 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->priority[0] = DEFAULT_PRIORITY; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_priority_l1, + no_isis_priority_l1_arg_cmd, + "no isis priority <0-127> level-1", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-1 routing\n") + +DEFUN (isis_priority_l2, + isis_priority_l2_cmd, + "isis priority <0-127> level-2", + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-2 routing\n") +{ + int prio; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + prio = atoi (argv[0]); + if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) + { + vty_out (vty, "Invalid priority %d - should be <0-127>%s", + prio, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->priority[1] = prio; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_priority_l2, + no_isis_priority_l2_cmd, + "no isis priority level-2", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Specify priority for level-2 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->priority[1] = DEFAULT_PRIORITY; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_priority_l2, + no_isis_priority_l2_arg_cmd, + "no isis priority <0-127> level-2", + NO_STR + "IS-IS commands\n" + "Set priority for Designated Router election\n" + "Priority value\n" + "Specify priority for level-2 routing\n") + +/* Metric command */ +DEFUN (isis_metric, + isis_metric_cmd, + "isis metric <0-16777215>", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_metric_set (circuit, IS_LEVEL_1, met); + isis_circuit_metric_set (circuit, IS_LEVEL_2, met); + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric, + no_isis_metric_cmd, + "no isis metric", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_metric_set (circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); + isis_circuit_metric_set (circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric, + no_isis_metric_arg_cmd, + "no isis metric <0-16777215>", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n") + +DEFUN (isis_metric_l1, + isis_metric_l1_cmd, + "isis metric <0-16777215> level-1", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-1 routing\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_metric_set (circuit, IS_LEVEL_1, met); + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric_l1, + no_isis_metric_l1_cmd, + "no isis metric level-1", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Specify metric for level-1 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_metric_set (circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric_l1, + no_isis_metric_l1_arg_cmd, + "no isis metric <0-16777215> level-1", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-1 routing\n") + +DEFUN (isis_metric_l2, + isis_metric_l2_cmd, + "isis metric <0-16777215> level-2", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-2 routing\n") +{ + int met; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + met = atoi (argv[0]); + + /* RFC3787 section 5.1 */ + if (circuit->area && circuit->area->oldmetric == 1 && + met > MAX_NARROW_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-63> " + "when narrow metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + /* RFC4444 */ + if (circuit->area && circuit->area->newmetric == 1 && + met > MAX_WIDE_LINK_METRIC) + { + vty_out (vty, "Invalid metric %d - should be <0-16777215> " + "when wide metric type enabled%s", + met, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + isis_circuit_metric_set (circuit, IS_LEVEL_2, met); + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric_l2, + no_isis_metric_l2_cmd, + "no isis metric level-2", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Specify metric for level-2 routing\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_metric_set (circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric_l2, + no_isis_metric_l2_arg_cmd, + "no isis metric <0-16777215> level-2", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + "Specify metric for level-2 routing\n") +/* end of metrics */ + +void +isis_vty_init (void) +{ + install_element (INTERFACE_NODE, &ip_router_isis_cmd); + install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); + + install_element (INTERFACE_NODE, &isis_passive_cmd); + install_element (INTERFACE_NODE, &no_isis_passive_cmd); + + install_element (INTERFACE_NODE, &isis_circuit_type_cmd); + install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); + + install_element (INTERFACE_NODE, &isis_network_cmd); + install_element (INTERFACE_NODE, &no_isis_network_cmd); + + install_element (INTERFACE_NODE, &isis_priority_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); + install_element (INTERFACE_NODE, &isis_priority_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_priority_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_metric_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); + install_element (INTERFACE_NODE, &isis_metric_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_metric_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); +} diff --git a/isisd/isisd.h b/isisd/isisd.h index d2efacacb..2803a64ea 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -25,7 +25,11 @@ #define ISISD_VERSION "0.0.7" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" #include "isisd/isis_redist.h" +#include "isis_flags.h" +#include "dict.h" /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ @@ -137,6 +141,8 @@ struct isis_area *isis_area_lookup (const char *); int isis_area_get (struct vty *vty, const char *area_tag); void print_debug(struct vty *, int, int); +void isis_vty_init (void); + /* Master of threads. */ extern struct thread_master *master; From ccd485d17b13f3b6f5669be9b8820d8807468d98 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 28 Jul 2016 17:23:26 +0200 Subject: [PATCH 1160/1342] isisd: API: basic area config Move out basic area configuration (metric type, overload and attachment bits, dynamic hostname extension enable) into isis_vty.c. [v2: moved stuff back here that accidentally was in the previous patch] Signed-off-by: David Lamparter --- isisd/isis_vty.c | 178 +++++++++++++++++++++++++++++++++++++ isisd/isisd.c | 224 +++++------------------------------------------ isisd/isisd.h | 6 ++ 3 files changed, 207 insertions(+), 201 deletions(-) diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 4b45df1df..06d59a814 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -641,6 +641,172 @@ ALIAS (no_isis_metric_l2, "Specify metric for level-2 routing\n") /* end of metrics */ +static int +validate_metric_style_narrow (struct vty *vty, struct isis_area *area) +{ + struct isis_circuit *circuit; + struct listnode *node; + + if (! vty) + return CMD_ERR_AMBIGUOUS; + + if (! area) + { + vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + { + if ((area->is_type & IS_LEVEL_1) && + (circuit->is_type & IS_LEVEL_1) && + (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if ((area->is_type & IS_LEVEL_2) && + (circuit->is_type & IS_LEVEL_2) && + (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + return CMD_SUCCESS; +} + +DEFUN (metric_style, + metric_style_cmd, + "metric-style (narrow|transition|wide)", + "Use old-style (ISO 10589) or new-style packet formats\n" + "Use old style of TLVs with narrow metric\n" + "Send and accept both styles of TLVs during transition\n" + "Use new style of TLVs to carry wider metric\n") +{ + struct isis_area *area = vty->index; + int ret; + + assert(area); + + if (strncmp (argv[0], "w", 1) == 0) + { + isis_area_metricstyle_set(area, false, true); + return CMD_SUCCESS; + } + + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + + if (strncmp (argv[0], "t", 1) == 0) + isis_area_metricstyle_set(area, true, true); + else if (strncmp (argv[0], "n", 1) == 0) + isis_area_metricstyle_set(area, true, false); + return CMD_SUCCESS; + + return CMD_SUCCESS; +} + +DEFUN (no_metric_style, + no_metric_style_cmd, + "no metric-style", + NO_STR + "Use old-style (ISO 10589) or new-style packet formats\n") +{ + struct isis_area *area = vty->index; + int ret; + + assert (area); + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + + isis_area_metricstyle_set(area, true, false); + return CMD_SUCCESS; +} + +DEFUN (set_overload_bit, + set_overload_bit_cmd, + "set-overload-bit", + "Set overload bit to avoid any transit traffic\n" + "Set overload bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_overload_bit_set(area, true); + return CMD_SUCCESS; +} + +DEFUN (no_set_overload_bit, + no_set_overload_bit_cmd, + "no set-overload-bit", + "Reset overload bit to accept transit traffic\n" + "Reset overload bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_overload_bit_set(area, false); + return CMD_SUCCESS; +} + +DEFUN (set_attached_bit, + set_attached_bit_cmd, + "set-attached-bit", + "Set attached bit to identify as L1/L2 router for inter-area traffic\n" + "Set attached bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_attached_bit_set(area, true); + return CMD_SUCCESS; +} + +DEFUN (no_set_attached_bit, + no_set_attached_bit_cmd, + "no set-attached-bit", + "Reset attached bit\n") +{ + struct isis_area *area = vty->index; + assert (area); + + isis_area_attached_bit_set(area, false); + return CMD_SUCCESS; +} + +DEFUN (dynamic_hostname, + dynamic_hostname_cmd, + "hostname dynamic", + "Dynamic hostname for IS-IS\n" + "Dynamic hostname\n") +{ + struct isis_area *area = vty->index; + assert(area); + + isis_area_dynhostname_set(area, true); + return CMD_SUCCESS; +} + +DEFUN (no_dynamic_hostname, + no_dynamic_hostname_cmd, + "no hostname dynamic", + NO_STR + "Dynamic hostname for IS-IS\n" + "Dynamic hostname\n") +{ + struct isis_area *area = vty->index; + assert(area); + + isis_area_dynhostname_set(area, false); + return CMD_SUCCESS; +} + void isis_vty_init (void) { @@ -675,4 +841,16 @@ isis_vty_init (void) install_element (INTERFACE_NODE, &isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); + + install_element (ISIS_NODE, &metric_style_cmd); + install_element (ISIS_NODE, &no_metric_style_cmd); + + install_element (ISIS_NODE, &set_overload_bit_cmd); + install_element (ISIS_NODE, &no_set_overload_bit_cmd); + + install_element (ISIS_NODE, &set_attached_bit_cmd); + install_element (ISIS_NODE, &no_set_attached_bit_cmd); + + install_element (ISIS_NODE, &dynamic_hostname_cmd); + install_element (ISIS_NODE, &no_dynamic_hostname_cmd); } diff --git a/isisd/isisd.c b/isisd/isisd.c index d3bddc063..11f7d234f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2177,213 +2177,47 @@ ALIAS (no_lsp_gen_interval_l2, "Set interval for level 2 only\n" "Minimum interval in seconds\n") -static int -validate_metric_style_narrow (struct vty *vty, struct isis_area *area) +void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, + bool new_metric) { - struct isis_circuit *circuit; - struct listnode *node; - - if (! vty) - return CMD_ERR_AMBIGUOUS; - - if (! area) - { - vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + if (area->oldmetric != old_metric + || area->newmetric != new_metric) { - if ((area->is_type & IS_LEVEL_1) && - (circuit->is_type & IS_LEVEL_1) && - (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) - { - vty_out (vty, "ISIS circuit %s metric is invalid%s", - circuit->interface->name, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - if ((area->is_type & IS_LEVEL_2) && - (circuit->is_type & IS_LEVEL_2) && - (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) - { - vty_out (vty, "ISIS circuit %s metric is invalid%s", - circuit->interface->name, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } + area->oldmetric = old_metric; + area->newmetric = new_metric; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } - - return CMD_SUCCESS; } -DEFUN (metric_style, - metric_style_cmd, - "metric-style (narrow|transition|wide)", - "Use old-style (ISO 10589) or new-style packet formats\n" - "Use old style of TLVs with narrow metric\n" - "Send and accept both styles of TLVs during transition\n" - "Use new style of TLVs to carry wider metric\n") +void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit) { - struct isis_area *area; - int ret; + char new_overload_bit = overload_bit ? LSPBIT_OL : 0; - area = vty->index; - assert (area); - - if (strncmp (argv[0], "w", 1) == 0) + if (new_overload_bit != area->overload_bit) { - area->newmetric = 1; - area->oldmetric = 0; + area->overload_bit = new_overload_bit; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } - else - { - ret = validate_metric_style_narrow (vty, area); - if (ret != CMD_SUCCESS) - return ret; - - if (strncmp (argv[0], "t", 1) == 0) - { - area->newmetric = 1; - area->oldmetric = 1; - } - else if (strncmp (argv[0], "n", 1) == 0) - { - area->newmetric = 0; - area->oldmetric = 1; - } - } - - return CMD_SUCCESS; -} - -DEFUN (no_metric_style, - no_metric_style_cmd, - "no metric-style", - NO_STR - "Use old-style (ISO 10589) or new-style packet formats\n") -{ - struct isis_area *area; - int ret; - - area = vty->index; - assert (area); - - ret = validate_metric_style_narrow (vty, area); - if (ret != CMD_SUCCESS) - return ret; - - /* Default is narrow metric. */ - area->newmetric = 0; - area->oldmetric = 1; - - return CMD_SUCCESS; -} - -DEFUN (set_overload_bit, - set_overload_bit_cmd, - "set-overload-bit", - "Set overload bit to avoid any transit traffic\n" - "Set overload bit\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - area->overload_bit = LSPBIT_OL; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; } -DEFUN (no_set_overload_bit, - no_set_overload_bit_cmd, - "no set-overload-bit", - "Reset overload bit to accept transit traffic\n" - "Reset overload bit\n") +void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit) { - struct isis_area *area; - - area = vty->index; - assert (area); - - area->overload_bit = 0; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} + char new_attached_bit = attached_bit ? LSPBIT_ATT : 0; -DEFUN (set_attached_bit, - set_attached_bit_cmd, - "set-attached-bit", - "Set attached bit to identify as L1/L2 router for inter-area traffic\n" - "Set attached bit\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - area->attached_bit = LSPBIT_ATT; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (no_set_attached_bit, - no_set_attached_bit_cmd, - "no set-attached-bit", - "Reset attached bit\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - area->attached_bit = 0; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -DEFUN (dynamic_hostname, - dynamic_hostname_cmd, - "hostname dynamic", - "Dynamic hostname for IS-IS\n" - "Dynamic hostname\n") -{ - struct isis_area *area; - - area = vty->index; - assert (area); - - if (!area->dynhostname) - { - area->dynhostname = 1; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); - } - - return CMD_SUCCESS; + if (new_attached_bit != area->attached_bit) + { + area->attached_bit = new_attached_bit; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); + } } -DEFUN (no_dynamic_hostname, - no_dynamic_hostname_cmd, - "no hostname dynamic", - NO_STR - "Dynamic hostname for IS-IS\n" - "Dynamic hostname\n") +void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname) { - struct isis_area *area; - - area = vty->index; - assert (area); - - if (area->dynhostname) + if (area->dynhostname != dynhostname) { - area->dynhostname = 0; - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); + area->dynhostname = dynhostname; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); } - - return CMD_SUCCESS; } DEFUN (spf_interval, @@ -3420,18 +3254,6 @@ isis_init () install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); - install_element (ISIS_NODE, &set_overload_bit_cmd); - install_element (ISIS_NODE, &no_set_overload_bit_cmd); - - install_element (ISIS_NODE, &set_attached_bit_cmd); - install_element (ISIS_NODE, &no_set_attached_bit_cmd); - - install_element (ISIS_NODE, &dynamic_hostname_cmd); - install_element (ISIS_NODE, &no_dynamic_hostname_cmd); - - install_element (ISIS_NODE, &metric_style_cmd); - install_element (ISIS_NODE, &no_metric_style_cmd); - install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 2803a64ea..691d1346a 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -141,6 +141,12 @@ struct isis_area *isis_area_lookup (const char *); int isis_area_get (struct vty *vty, const char *area_tag); void print_debug(struct vty *, int, int); +void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit); +void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit); +void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname); +void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, + bool new_metric); + void isis_vty_init (void); /* Master of threads. */ From f5fbfb26e961d6b4b129f98bc27a3e822620eba3 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 28 Jul 2016 17:23:27 +0200 Subject: [PATCH 1161/1342] isisd: API: circuit password This cleans up circuit password configuration a little bit. (Restructured several times by both Christian Franke and David Lamparter.) Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 81 +++++++++++++------------------------------- isisd/isis_circuit.h | 4 +++ isisd/isis_vty.c | 57 +++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 58 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 6adda0889..707d77ab9 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1332,72 +1332,41 @@ isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric) return 0; } -DEFUN (isis_passwd_md5, - isis_passwd_md5_cmd, - "isis password md5 WORD", - "IS-IS commands\n" - "Configure the authentication password for a circuit\n" - "Authentication type\n" - "Circuit password\n") +int +isis_circuit_passwd_unset (struct isis_circuit *circuit) { - int len; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - circuit->passwd.len = len; - circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; - strncpy ((char *)circuit->passwd.passwd, argv[0], 255); - - return CMD_SUCCESS; + memset(&circuit->passwd, 0, sizeof(circuit->passwd)); + return 0; } -DEFUN (isis_passwd_clear, - isis_passwd_clear_cmd, - "isis password clear WORD", - "IS-IS commands\n" - "Configure the authentication password for a circuit\n" - "Authentication type\n" - "Circuit password\n") +static int +isis_circuit_passwd_set (struct isis_circuit *circuit, u_char passwd_type, const char *passwd) { int len; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - len = strlen (argv[0]); + if (!passwd) + return -1; + + len = strlen(passwd); if (len > 254) - { - vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - circuit->passwd.len = len; - circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; - strncpy ((char *)circuit->passwd.passwd, argv[0], 255); + return -1; - return CMD_SUCCESS; + circuit->passwd.len = len; + strncpy((char *)circuit->passwd.passwd, passwd, 255); + circuit->passwd.type = passwd_type; + return 0; } -DEFUN (no_isis_passwd, - no_isis_passwd_cmd, - "no isis password", - NO_STR - "IS-IS commands\n" - "Configure the authentication password for a circuit\n") +int +isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd) { - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - memset (&circuit->passwd, 0, sizeof (struct isis_passwd)); + return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd); +} - return CMD_SUCCESS; +int +isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd) +{ + return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd); } DEFUN (isis_hello_interval, @@ -2143,10 +2112,6 @@ isis_circuit_init () install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); - install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); - install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); - install_element (INTERFACE_NODE, &no_isis_passwd_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 343b492f3..9843ef372 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -180,4 +180,8 @@ int isis_circuit_circ_type_set (struct isis_circuit *circuit, int circ_type); int isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric); +int isis_circuit_passwd_unset (struct isis_circuit *circuit); +int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd); +int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd); + #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 06d59a814..c6f246534 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -293,6 +293,59 @@ DEFUN (no_isis_network, return CMD_SUCCESS; } +DEFUN (isis_passwd, + isis_passwd_cmd, + "isis password (md5|clear) WORD", + "IS-IS commands\n" + "Configure the authentication password for a circuit\n" + "HMAC-MD5 authentication\n" + "Cleartext password\n" + "Circuit password\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + int rv; + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (argv[0][0] == 'm') + rv = isis_circuit_passwd_hmac_md5_set(circuit, argv[1]); + else + rv = isis_circuit_passwd_cleartext_set(circuit, argv[1]); + if (rv) + { + vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_passwd, + no_isis_passwd_cmd, + "no isis password", + NO_STR + "IS-IS commands\n" + "Configure the authentication password for a circuit\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + isis_circuit_passwd_unset(circuit); + + return CMD_SUCCESS; +} + +ALIAS (no_isis_passwd, + no_isis_passwd_arg_cmd, + "no isis password (md5|clear) WORD", + NO_STR + "IS-IS commands\n" + "Configure the authentication password for a circuit\n" + "HMAC-MD5 authentication\n" + "Cleartext password\n" + "Circuit password\n") + DEFUN (isis_priority, isis_priority_cmd, "isis priority <0-127>", @@ -822,6 +875,10 @@ isis_vty_init (void) install_element (INTERFACE_NODE, &isis_network_cmd); install_element (INTERFACE_NODE, &no_isis_network_cmd); + install_element (INTERFACE_NODE, &isis_passwd_cmd); + install_element (INTERFACE_NODE, &no_isis_passwd_cmd); + install_element (INTERFACE_NODE, &no_isis_passwd_arg_cmd); + install_element (INTERFACE_NODE, &isis_priority_cmd); install_element (INTERFACE_NODE, &no_isis_priority_cmd); install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); From b5d2f5f5085147ff9e9d5ace7705c422cbc6afd0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Jul 2016 17:23:28 +0200 Subject: [PATCH 1162/1342] isisd: API: timers (IIH, CSNP, PSNP) No setters needed since change of fields doesn't require any specific action to make it apply. Just move the CLI defs to isis_vty.c. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 705 ------------------------------------------- isisd/isis_vty.c | 704 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 704 insertions(+), 705 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 707d77ab9..85e4f9c76 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1368,668 +1368,6 @@ isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *pass { return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd); } - -DEFUN (isis_hello_interval, - isis_hello_interval_cmd, - "isis hello-interval <1-600>", - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 seconds, interval depends on multiplier\n") -{ - int interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atoi (argv[0]); - if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) - { - vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_interval[0] = (u_int16_t) interval; - circuit->hello_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_interval, - no_isis_hello_interval_cmd, - "no isis hello-interval", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; - circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_interval, - no_isis_hello_interval_arg_cmd, - "no isis hello-interval <1-600>", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n") - -DEFUN (isis_hello_interval_l1, - isis_hello_interval_l1_cmd, - "isis hello-interval <1-600> level-1", - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-1 IIHs\n") -{ - long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atoi (argv[0]); - if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) - { - vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_interval[0] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_interval_l1, - no_isis_hello_interval_l1_cmd, - "no isis hello-interval level-1", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Specify hello-interval for level-1 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_interval_l1, - no_isis_hello_interval_l1_arg_cmd, - "no isis hello-interval <1-600> level-1", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-1 IIHs\n") - -DEFUN (isis_hello_interval_l2, - isis_hello_interval_l2_cmd, - "isis hello-interval <1-600> level-2", - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-2 IIHs\n") -{ - long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atoi (argv[0]); - if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) - { - vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_interval_l2, - no_isis_hello_interval_l2_cmd, - "no isis hello-interval level-2", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Specify hello-interval for level-2 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_interval_l2, - no_isis_hello_interval_l2_arg_cmd, - "no isis hello-interval <1-600> level-2", - NO_STR - "IS-IS commands\n" - "Set Hello interval\n" - "Hello interval value\n" - "Holdtime 1 second, interval depends on multiplier\n" - "Specify hello-interval for level-2 IIHs\n") - -DEFUN (isis_hello_multiplier, - isis_hello_multiplier_cmd, - "isis hello-multiplier <2-100>", - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n") -{ - int mult; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - mult = atoi (argv[0]); - if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) - { - vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", - mult, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_multiplier[0] = (u_int16_t) mult; - circuit->hello_multiplier[1] = (u_int16_t) mult; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_multiplier, - no_isis_hello_multiplier_cmd, - "no isis hello-multiplier", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; - circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_multiplier, - no_isis_hello_multiplier_arg_cmd, - "no isis hello-multiplier <2-100>", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n") - -DEFUN (isis_hello_multiplier_l1, - isis_hello_multiplier_l1_cmd, - "isis hello-multiplier <2-100> level-1", - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-1 IIHs\n") -{ - int mult; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - mult = atoi (argv[0]); - if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) - { - vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", - mult, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_multiplier[0] = (u_int16_t) mult; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_multiplier_l1, - no_isis_hello_multiplier_l1_cmd, - "no isis hello-multiplier level-1", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Specify hello multiplier for level-1 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_multiplier_l1, - no_isis_hello_multiplier_l1_arg_cmd, - "no isis hello-multiplier <2-100> level-1", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-1 IIHs\n") - -DEFUN (isis_hello_multiplier_l2, - isis_hello_multiplier_l2_cmd, - "isis hello-multiplier <2-100> level-2", - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-2 IIHs\n") -{ - int mult; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - mult = atoi (argv[0]); - if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) - { - vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", - mult, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->hello_multiplier[1] = (u_int16_t) mult; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_multiplier_l2, - no_isis_hello_multiplier_l2_cmd, - "no isis hello-multiplier level-2", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Specify hello multiplier for level-2 IIHs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; - - return CMD_SUCCESS; -} - -ALIAS (no_isis_hello_multiplier_l2, - no_isis_hello_multiplier_l2_arg_cmd, - "no isis hello-multiplier <2-100> level-2", - NO_STR - "IS-IS commands\n" - "Set multiplier for Hello holding time\n" - "Hello multiplier value\n" - "Specify hello multiplier for level-2 IIHs\n") - -DEFUN (isis_hello_padding, - isis_hello_padding_cmd, - "isis hello padding", - "IS-IS commands\n" - "Add padding to IS-IS hello packets\n" - "Pad hello packets\n" - "\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->pad_hellos = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_isis_hello_padding, - no_isis_hello_padding_cmd, - "no isis hello padding", - NO_STR - "IS-IS commands\n" - "Add padding to IS-IS hello packets\n" - "Pad hello packets\n" - "\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->pad_hellos = 0; - - return CMD_SUCCESS; -} - -DEFUN (csnp_interval, - csnp_interval_cmd, - "isis csnp-interval <1-600>", - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) - { - vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->csnp_interval[0] = (u_int16_t) interval; - circuit->csnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_csnp_interval, - no_csnp_interval_cmd, - "no isis csnp-interval", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; - circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_csnp_interval, - no_csnp_interval_arg_cmd, - "no isis csnp-interval <1-600>", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n") - -DEFUN (csnp_interval_l1, - csnp_interval_l1_cmd, - "isis csnp-interval <1-600> level-1", - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-1 CSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) - { - vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->csnp_interval[0] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_csnp_interval_l1, - no_csnp_interval_l1_cmd, - "no isis csnp-interval level-1", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "Specify interval for level-1 CSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_csnp_interval_l1, - no_csnp_interval_l1_arg_cmd, - "no isis csnp-interval <1-600> level-1", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-1 CSNPs\n") - -DEFUN (csnp_interval_l2, - csnp_interval_l2_cmd, - "isis csnp-interval <1-600> level-2", - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-2 CSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) - { - vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->csnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_csnp_interval_l2, - no_csnp_interval_l2_cmd, - "no isis csnp-interval level-2", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "Specify interval for level-2 CSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_csnp_interval_l2, - no_csnp_interval_l2_arg_cmd, - "no isis csnp-interval <1-600> level-2", - NO_STR - "IS-IS commands\n" - "Set CSNP interval in seconds\n" - "CSNP interval value\n" - "Specify interval for level-2 CSNPs\n") - -DEFUN (psnp_interval, - psnp_interval_cmd, - "isis psnp-interval <1-120>", - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) - { - vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->psnp_interval[0] = (u_int16_t) interval; - circuit->psnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_psnp_interval, - no_psnp_interval_cmd, - "no isis psnp-interval", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; - circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_psnp_interval, - no_psnp_interval_arg_cmd, - "no isis psnp-interval <1-120>", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n") - -DEFUN (psnp_interval_l1, - psnp_interval_l1_cmd, - "isis psnp-interval <1-120> level-1", - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-1 PSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) - { - vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->psnp_interval[0] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_psnp_interval_l1, - no_psnp_interval_l1_cmd, - "no isis psnp-interval level-1", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "Specify interval for level-1 PSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_psnp_interval_l1, - no_psnp_interval_l1_arg_cmd, - "no isis psnp-interval <1-120> level-1", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-1 PSNPs\n") - -DEFUN (psnp_interval_l2, - psnp_interval_l2_cmd, - "isis psnp-interval <1-120> level-2", - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-2 PSNPs\n") -{ - unsigned long interval; - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - interval = atol (argv[0]); - if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) - { - vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", - interval, VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - circuit->psnp_interval[1] = (u_int16_t) interval; - - return CMD_SUCCESS; -} - -DEFUN (no_psnp_interval_l2, - no_psnp_interval_l2_cmd, - "no isis psnp-interval level-2", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "Specify interval for level-2 PSNPs\n") -{ - struct isis_circuit *circuit = isis_circuit_lookup (vty); - if (!circuit) - return CMD_ERR_NO_MATCH; - - circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_psnp_interval_l2, - no_psnp_interval_l2_arg_cmd, - "no isis psnp-interval <1-120> level-2", - NO_STR - "IS-IS commands\n" - "Set PSNP interval in seconds\n" - "PSNP interval value\n" - "Specify interval for level-2 PSNPs\n") - struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", @@ -2112,48 +1450,5 @@ isis_circuit_init () install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd); - install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); - - install_element (INTERFACE_NODE, &isis_hello_padding_cmd); - install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); - - install_element (INTERFACE_NODE, &csnp_interval_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); - install_element (INTERFACE_NODE, &csnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd); - install_element (INTERFACE_NODE, &csnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); - - install_element (INTERFACE_NODE, &psnp_interval_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); - install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); - install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); - install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); - isis_vty_init (); } diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index c6f246534..3dd3682ce 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -694,6 +694,667 @@ ALIAS (no_isis_metric_l2, "Specify metric for level-2 routing\n") /* end of metrics */ +DEFUN (isis_hello_interval, + isis_hello_interval_cmd, + "isis hello-interval <1-600>", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 seconds, interval depends on multiplier\n") +{ + int interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) + { + vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_interval[0] = (u_int16_t) interval; + circuit->hello_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_interval, + no_isis_hello_interval_cmd, + "no isis hello-interval", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; + circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval, + no_isis_hello_interval_arg_cmd, + "no isis hello-interval <1-600>", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n") + +DEFUN (isis_hello_interval_l1, + isis_hello_interval_l1_cmd, + "isis hello-interval <1-600> level-1", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-1 IIHs\n") +{ + long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) + { + vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_interval[0] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_interval_l1, + no_isis_hello_interval_l1_cmd, + "no isis hello-interval level-1", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Specify hello-interval for level-1 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval_l1, + no_isis_hello_interval_l1_arg_cmd, + "no isis hello-interval <1-600> level-1", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-1 IIHs\n") + +DEFUN (isis_hello_interval_l2, + isis_hello_interval_l2_cmd, + "isis hello-interval <1-600> level-2", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-2 IIHs\n") +{ + long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) + { + vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_interval_l2, + no_isis_hello_interval_l2_cmd, + "no isis hello-interval level-2", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Specify hello-interval for level-2 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval_l2, + no_isis_hello_interval_l2_arg_cmd, + "no isis hello-interval <1-600> level-2", + NO_STR + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 second, interval depends on multiplier\n" + "Specify hello-interval for level-2 IIHs\n") + +DEFUN (isis_hello_multiplier, + isis_hello_multiplier_cmd, + "isis hello-multiplier <2-100>", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n") +{ + int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) + { + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_multiplier[0] = (u_int16_t) mult; + circuit->hello_multiplier[1] = (u_int16_t) mult; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_multiplier, + no_isis_hello_multiplier_cmd, + "no isis hello-multiplier", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; + circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier, + no_isis_hello_multiplier_arg_cmd, + "no isis hello-multiplier <2-100>", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n") + +DEFUN (isis_hello_multiplier_l1, + isis_hello_multiplier_l1_cmd, + "isis hello-multiplier <2-100> level-1", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-1 IIHs\n") +{ + int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) + { + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_multiplier[0] = (u_int16_t) mult; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_multiplier_l1, + no_isis_hello_multiplier_l1_cmd, + "no isis hello-multiplier level-1", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Specify hello multiplier for level-1 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier_l1, + no_isis_hello_multiplier_l1_arg_cmd, + "no isis hello-multiplier <2-100> level-1", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-1 IIHs\n") + +DEFUN (isis_hello_multiplier_l2, + isis_hello_multiplier_l2_cmd, + "isis hello-multiplier <2-100> level-2", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-2 IIHs\n") +{ + int mult; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + mult = atoi (argv[0]); + if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) + { + vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", + mult, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->hello_multiplier[1] = (u_int16_t) mult; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_multiplier_l2, + no_isis_hello_multiplier_l2_cmd, + "no isis hello-multiplier level-2", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Specify hello multiplier for level-2 IIHs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier_l2, + no_isis_hello_multiplier_l2_arg_cmd, + "no isis hello-multiplier <2-100> level-2", + NO_STR + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + "Specify hello multiplier for level-2 IIHs\n") + +DEFUN (isis_hello_padding, + isis_hello_padding_cmd, + "isis hello padding", + "IS-IS commands\n" + "Add padding to IS-IS hello packets\n" + "Pad hello packets\n" + "\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->pad_hellos = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello_padding, + no_isis_hello_padding_cmd, + "no isis hello padding", + NO_STR + "IS-IS commands\n" + "Add padding to IS-IS hello packets\n" + "Pad hello packets\n" + "\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->pad_hellos = 0; + + return CMD_SUCCESS; +} + +DEFUN (csnp_interval, + csnp_interval_cmd, + "isis csnp-interval <1-600>", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) + { + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->csnp_interval[0] = (u_int16_t) interval; + circuit->csnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_csnp_interval, + no_csnp_interval_cmd, + "no isis csnp-interval", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; + circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval, + no_csnp_interval_arg_cmd, + "no isis csnp-interval <1-600>", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n") + +DEFUN (csnp_interval_l1, + csnp_interval_l1_cmd, + "isis csnp-interval <1-600> level-1", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-1 CSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) + { + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->csnp_interval[0] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_csnp_interval_l1, + no_csnp_interval_l1_cmd, + "no isis csnp-interval level-1", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "Specify interval for level-1 CSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval_l1, + no_csnp_interval_l1_arg_cmd, + "no isis csnp-interval <1-600> level-1", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-1 CSNPs\n") + +DEFUN (csnp_interval_l2, + csnp_interval_l2_cmd, + "isis csnp-interval <1-600> level-2", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-2 CSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) + { + vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->csnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_csnp_interval_l2, + no_csnp_interval_l2_cmd, + "no isis csnp-interval level-2", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "Specify interval for level-2 CSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval_l2, + no_csnp_interval_l2_arg_cmd, + "no isis csnp-interval <1-600> level-2", + NO_STR + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-2 CSNPs\n") + +DEFUN (psnp_interval, + psnp_interval_cmd, + "isis psnp-interval <1-120>", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->psnp_interval[0] = (u_int16_t) interval; + circuit->psnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval, + no_psnp_interval_cmd, + "no isis psnp-interval", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; + circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval, + no_psnp_interval_arg_cmd, + "no isis psnp-interval <1-120>", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n") + +DEFUN (psnp_interval_l1, + psnp_interval_l1_cmd, + "isis psnp-interval <1-120> level-1", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-1 PSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->psnp_interval[0] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval_l1, + no_psnp_interval_l1_cmd, + "no isis psnp-interval level-1", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "Specify interval for level-1 PSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval_l1, + no_psnp_interval_l1_arg_cmd, + "no isis psnp-interval <1-120> level-1", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-1 PSNPs\n") + +DEFUN (psnp_interval_l2, + psnp_interval_l2_cmd, + "isis psnp-interval <1-120> level-2", + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-2 PSNPs\n") +{ + unsigned long interval; + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + interval = atol (argv[0]); + if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) + { + vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + circuit->psnp_interval[1] = (u_int16_t) interval; + + return CMD_SUCCESS; +} + +DEFUN (no_psnp_interval_l2, + no_psnp_interval_l2_cmd, + "no isis psnp-interval level-2", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "Specify interval for level-2 PSNPs\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_psnp_interval_l2, + no_psnp_interval_l2_arg_cmd, + "no isis psnp-interval <1-120> level-2", + NO_STR + "IS-IS commands\n" + "Set PSNP interval in seconds\n" + "PSNP interval value\n" + "Specify interval for level-2 PSNPs\n") + static int validate_metric_style_narrow (struct vty *vty, struct isis_area *area) { @@ -899,6 +1560,49 @@ isis_vty_init (void) install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd); + install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); + + install_element (INTERFACE_NODE, &isis_hello_padding_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); + + install_element (INTERFACE_NODE, &csnp_interval_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); + install_element (INTERFACE_NODE, &csnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &csnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); + + install_element (INTERFACE_NODE, &psnp_interval_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); + install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); + install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); + install_element (ISIS_NODE, &metric_style_cmd); install_element (ISIS_NODE, &no_metric_style_cmd); From 304c7dac53e2b1b3dc135ce2ff1aa38df46ec727 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 28 Jul 2016 17:23:29 +0200 Subject: [PATCH 1163/1342] isisd: API: LSP-MTU & area level Yet more CLI functions in isis_vty.c using more nice setters. Signed-off-by: David Lamparter --- isisd/isis_events.c | 113 ----------------------- isisd/isis_events.h | 5 - isisd/isis_vty.c | 126 +++++++++++++++++++++++++ isisd/isisd.c | 219 ++++++++++++++++++++------------------------ isisd/isisd.h | 2 + 5 files changed, 227 insertions(+), 238 deletions(-) diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 26f02100a..ebd86a55e 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -77,119 +77,6 @@ isis_event_circuit_state_change (struct isis_circuit *circuit, return; } -static void -area_resign_level (struct isis_area *area, int level) -{ - if (area->lspdb[level - 1]) - { - lsp_db_destroy (area->lspdb[level - 1]); - area->lspdb[level - 1] = NULL; - } - if (area->spftree[level - 1]) - { - isis_spftree_del (area->spftree[level - 1]); - area->spftree[level - 1] = NULL; - } -#ifdef HAVE_IPV6 - if (area->spftree6[level - 1]) - { - isis_spftree_del (area->spftree6[level - 1]); - area->spftree6[level - 1] = NULL; - } -#endif - if (area->route_table[level - 1]) - { - route_table_finish (area->route_table[level - 1]); - area->route_table[level - 1] = NULL; - } -#ifdef HAVE_IPV6 - if (area->route_table6[level - 1]) - { - route_table_finish (area->route_table6[level - 1]); - area->route_table6[level - 1] = NULL; - } -#endif /* HAVE_IPV6 */ - - sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", - area->area_tag, level); - THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); - area->lsp_regenerate_pending[level - 1] = 0; -} - -void -isis_event_system_type_change (struct isis_area *area, int newtype) -{ - struct listnode *node; - struct isis_circuit *circuit; - - if (isis->debugs & DEBUG_EVENTS) - zlog_debug ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag, - circuit_t2string (area->is_type), circuit_t2string (newtype)); - - if (area->is_type == newtype) - return; /* No change */ - - switch (area->is_type) - { - case IS_LEVEL_1: - if (newtype == IS_LEVEL_2) - area_resign_level (area, IS_LEVEL_1); - - if (area->lspdb[1] == NULL) - area->lspdb[1] = lsp_db_init (); - if (area->route_table[1] == NULL) - area->route_table[1] = route_table_init (); -#ifdef HAVE_IPV6 - if (area->route_table6[1] == NULL) - area->route_table6[1] = route_table_init (); -#endif /* HAVE_IPV6 */ - break; - - case IS_LEVEL_1_AND_2: - if (newtype == IS_LEVEL_1) - area_resign_level (area, IS_LEVEL_2); - else - area_resign_level (area, IS_LEVEL_1); - break; - - case IS_LEVEL_2: - if (newtype == IS_LEVEL_1) - area_resign_level (area, IS_LEVEL_2); - - if (area->lspdb[0] == NULL) - area->lspdb[0] = lsp_db_init (); - if (area->route_table[0] == NULL) - area->route_table[0] = route_table_init (); -#ifdef HAVE_IPV6 - if (area->route_table6[0] == NULL) - area->route_table6[0] = route_table_init (); -#endif /* HAVE_IPV6 */ - break; - - default: - break; - } - - area->is_type = newtype; - - /* override circuit's is_type */ - if (area->is_type != IS_LEVEL_1_AND_2) - { - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - isis_event_circuit_type_change (circuit, newtype); - } - - spftree_area_init (area); - - if (newtype & IS_LEVEL_1) - lsp_generate (area, IS_LEVEL_1); - if (newtype & IS_LEVEL_2) - lsp_generate (area, IS_LEVEL_2); - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return; -} - static void circuit_commence_level (struct isis_circuit *circuit, int level) { diff --git a/isisd/isis_events.h b/isisd/isis_events.h index c252f3def..e7cfa3509 100644 --- a/isisd/isis_events.h +++ b/isisd/isis_events.h @@ -22,11 +22,6 @@ #ifndef _ZEBRA_ISIS_EVENTS_H #define _ZEBRA_ISIS_EVENTS_H -/* - * Events related to area - */ -void isis_event_system_type_change (struct isis_area *area, int newtype); - /* * Events related to circuit */ diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 3dd3682ce..ef910df9f 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -1521,6 +1521,125 @@ DEFUN (no_dynamic_hostname, return CMD_SUCCESS; } +static int area_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu) +{ + struct isis_area *area = vty->index; + struct listnode *node; + struct isis_circuit *circuit; + + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + { + if(circuit->state != C_STATE_INIT && circuit->state != C_STATE_UP) + continue; + if(lsp_mtu > isis_circuit_pdu_size(circuit)) + { + vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", + circuit->interface->name, isis_circuit_pdu_size(circuit), + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + isis_area_lsp_mtu_set(area, lsp_mtu); + return CMD_SUCCESS; +} + +DEFUN (area_lsp_mtu, + area_lsp_mtu_cmd, + "lsp-mtu <128-4352>", + "Configure the maximum size of generated LSPs\n" + "Maximum size of generated LSPs\n") +{ + unsigned int lsp_mtu; + + VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352); + + return area_lsp_mtu_set(vty, lsp_mtu); +} + +DEFUN(no_area_lsp_mtu, + no_area_lsp_mtu_cmd, + "no lsp-mtu", + NO_STR + "Configure the maximum size of generated LSPs\n") +{ + return area_lsp_mtu_set(vty, DEFAULT_LSP_MTU); +} + +ALIAS(no_area_lsp_mtu, + no_area_lsp_mtu_arg_cmd, + "no lsp-mtu <128-4352>", + NO_STR + "Configure the maximum size of generated LSPs\n" + "Maximum size of generated LSPs\n"); + +DEFUN (is_type, + is_type_cmd, + "is-type (level-1|level-1-2|level-2-only)", + "IS Level for this routing process (OSI only)\n" + "Act as a station router only\n" + "Act as both a station router and an area router\n" + "Act as an area router only\n") +{ + struct isis_area *area; + int type; + + area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + type = string2circuit_t (argv[0]); + if (!type) + { + vty_out (vty, "Unknown IS level %s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + isis_area_is_type_set(area, type); + + return CMD_SUCCESS; +} + +DEFUN (no_is_type, + no_is_type_cmd, + "no is-type (level-1|level-1-2|level-2-only)", + NO_STR + "IS Level for this routing process (OSI only)\n" + "Act as a station router only\n" + "Act as both a station router and an area router\n" + "Act as an area router only\n") +{ + struct isis_area *area; + int type; + + area = vty->index; + assert (area); + + /* + * Put the is-type back to defaults: + * - level-1-2 on first area + * - level-1 for the rest + */ + if (listgetdata (listhead (isis->area_list)) == area) + type = IS_LEVEL_1_AND_2; + else + type = IS_LEVEL_1; + + isis_area_is_type_set(area, type); + + return CMD_SUCCESS; +} + void isis_vty_init (void) { @@ -1614,4 +1733,11 @@ isis_vty_init (void) install_element (ISIS_NODE, &dynamic_hostname_cmd); install_element (ISIS_NODE, &no_dynamic_hostname_cmd); + + install_element (ISIS_NODE, &area_lsp_mtu_cmd); + install_element (ISIS_NODE, &no_area_lsp_mtu_cmd); + install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd); + + install_element (ISIS_NODE, &is_type_cmd); + install_element (ISIS_NODE, &no_is_type_cmd); } diff --git a/isisd/isisd.c b/isisd/isisd.c index 11f7d234f..130e75236 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1615,78 +1615,12 @@ DEFUN (no_net, return area_clear_net_title (vty, argv[0]); } -static -int area_set_lsp_mtu(struct vty *vty, struct isis_area *area, unsigned int lsp_mtu) +void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu) { - struct isis_circuit *circuit; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) - { - if(circuit->state != C_STATE_INIT && circuit->state != C_STATE_UP) - continue; - if(lsp_mtu > isis_circuit_pdu_size(circuit)) - { - vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", - circuit->interface->name, isis_circuit_pdu_size(circuit), - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } - area->lsp_mtu = lsp_mtu; lsp_regenerate_schedule(area, IS_LEVEL_1_AND_2, 1); - - return CMD_SUCCESS; } -DEFUN (area_lsp_mtu, - area_lsp_mtu_cmd, - "lsp-mtu <128-4352>", - "Configure the maximum size of generated LSPs\n" - "Maximum size of generated LSPs\n") -{ - struct isis_area *area; - - area = vty->index; - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - unsigned int lsp_mtu; - - VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352); - - return area_set_lsp_mtu(vty, area, lsp_mtu); -} - -DEFUN(no_area_lsp_mtu, - no_area_lsp_mtu_cmd, - "no lsp-mtu", - NO_STR - "Configure the maximum size of generated LSPs\n") -{ - struct isis_area *area; - - area = vty->index; - if (!area) - { - vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - return area_set_lsp_mtu(vty, area, DEFAULT_LSP_MTU); -} - -ALIAS(no_area_lsp_mtu, - no_area_lsp_mtu_arg_cmd, - "no lsp-mtu <128-4352>", - NO_STR - "Configure the maximum size of generated LSPs\n" - "Maximum size of generated LSPs\n"); - DEFUN (area_passwd_md5, area_passwd_md5_cmd, "area-password md5 WORD", @@ -1963,65 +1897,117 @@ DEFUN (no_domain_passwd, return CMD_SUCCESS; } -DEFUN (is_type, - is_type_cmd, - "is-type (level-1|level-1-2|level-2-only)", - "IS Level for this routing process (OSI only)\n" - "Act as a station router only\n" - "Act as both a station router and an area router\n" - "Act as an area router only\n") +static void +area_resign_level (struct isis_area *area, int level) { - struct isis_area *area; - int type; - - area = vty->index; - - if (!area) + if (area->lspdb[level - 1]) { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; + lsp_db_destroy (area->lspdb[level - 1]); + area->lspdb[level - 1] = NULL; } - - type = string2circuit_t (argv[0]); - if (!type) + if (area->spftree[level - 1]) { - vty_out (vty, "Unknown IS level %s", VTY_NEWLINE); - return CMD_SUCCESS; + isis_spftree_del (area->spftree[level - 1]); + area->spftree[level - 1] = NULL; } +#ifdef HAVE_IPV6 + if (area->spftree6[level - 1]) + { + isis_spftree_del (area->spftree6[level - 1]); + area->spftree6[level - 1] = NULL; + } +#endif + if (area->route_table[level - 1]) + { + route_table_finish (area->route_table[level - 1]); + area->route_table[level - 1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->route_table6[level - 1]) + { + route_table_finish (area->route_table6[level - 1]); + area->route_table6[level - 1] = NULL; + } +#endif /* HAVE_IPV6 */ - isis_event_system_type_change (area, type); - - return CMD_SUCCESS; + sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", + area->area_tag, level); + THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); + area->lsp_regenerate_pending[level - 1] = 0; } -DEFUN (no_is_type, - no_is_type_cmd, - "no is-type (level-1|level-1-2|level-2-only)", - NO_STR - "IS Level for this routing process (OSI only)\n" - "Act as a station router only\n" - "Act as both a station router and an area router\n" - "Act as an area router only\n") +void +isis_area_is_type_set(struct isis_area *area, int is_type) { - struct isis_area *area; - int type; + struct listnode *node; + struct isis_circuit *circuit; - area = vty->index; - assert (area); + if (isis->debugs & DEBUG_EVENTS) + zlog_debug ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag, + circuit_t2string (area->is_type), circuit_t2string (is_type)); - /* - * Put the is-type back to defaults: - * - level-1-2 on first area - * - level-1 for the rest - */ - if (listgetdata (listhead (isis->area_list)) == area) - type = IS_LEVEL_1_AND_2; - else - type = IS_LEVEL_1; + if (area->is_type == is_type) + return; /* No change */ - isis_event_system_type_change (area, type); + switch (area->is_type) + { + case IS_LEVEL_1: + if (is_type == IS_LEVEL_2) + area_resign_level (area, IS_LEVEL_1); + + if (area->lspdb[1] == NULL) + area->lspdb[1] = lsp_db_init (); + if (area->route_table[1] == NULL) + area->route_table[1] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[1] == NULL) + area->route_table6[1] = route_table_init (); +#endif /* HAVE_IPV6 */ + break; - return CMD_SUCCESS; + case IS_LEVEL_1_AND_2: + if (is_type == IS_LEVEL_1) + area_resign_level (area, IS_LEVEL_2); + else + area_resign_level (area, IS_LEVEL_1); + break; + + case IS_LEVEL_2: + if (is_type == IS_LEVEL_1) + area_resign_level (area, IS_LEVEL_2); + + if (area->lspdb[0] == NULL) + area->lspdb[0] = lsp_db_init (); + if (area->route_table[0] == NULL) + area->route_table[0] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[0] == NULL) + area->route_table6[0] = route_table_init (); +#endif /* HAVE_IPV6 */ + break; + + default: + break; + } + + area->is_type = is_type; + + /* override circuit's is_type */ + if (area->is_type != IS_LEVEL_1_AND_2) + { + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + isis_event_circuit_type_change (circuit, is_type); + } + + spftree_area_init (area); + + if (is_type & IS_LEVEL_1) + lsp_generate (area, IS_LEVEL_1); + if (is_type & IS_LEVEL_2) + lsp_generate (area, IS_LEVEL_2); + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return; } static int @@ -3195,13 +3181,6 @@ isis_init () install_element (ISIS_NODE, &net_cmd); install_element (ISIS_NODE, &no_net_cmd); - install_element (ISIS_NODE, &is_type_cmd); - install_element (ISIS_NODE, &no_is_type_cmd); - - install_element (ISIS_NODE, &area_lsp_mtu_cmd); - install_element (ISIS_NODE, &no_area_lsp_mtu_cmd); - install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd); - install_element (ISIS_NODE, &area_passwd_md5_cmd); install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); install_element (ISIS_NODE, &area_passwd_clear_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 691d1346a..2ba44d8fd 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -146,6 +146,8 @@ void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit); void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname); void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, bool new_metric); +void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu); +void isis_area_is_type_set(struct isis_area *area, int is_type); void isis_vty_init (void); From 4570ca47e11602b25e37ab709fa00bdf8c183afb Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 28 Jul 2016 17:23:30 +0200 Subject: [PATCH 1164/1342] isisd: API: timers (LSP, SPF) See previous commits... Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 23 -- isisd/isis_vty.c | 565 +++++++++++++++++++++++++++++++++++++ isisd/isisd.c | 643 ++----------------------------------------- isisd/isisd.h | 4 + 4 files changed, 585 insertions(+), 650 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 85e4f9c76..04c515506 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -199,29 +199,6 @@ circuit_scan_by_ifp (struct interface *ifp) return circuit_lookup_by_ifp (ifp, isis->init_circ_list); } -struct isis_circuit * isis_circuit_lookup (struct vty *vty) -{ - struct interface *ifp; - struct isis_circuit *circuit; - - ifp = (struct interface *) vty->index; - if (!ifp) - { - vty_out (vty, "Invalid interface %s", VTY_NEWLINE); - return NULL; - } - - circuit = circuit_scan_by_ifp (ifp); - if (!circuit) - { - vty_out (vty, "ISIS is not enabled on circuit %s%s", - ifp->name, VTY_NEWLINE); - return NULL; - } - - return circuit; -} - void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *connected) diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index ef910df9f..be4150430 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -1640,6 +1640,531 @@ DEFUN (no_is_type, return CMD_SUCCESS; } +static int +set_lsp_gen_interval (struct vty *vty, struct isis_area *area, + uint16_t interval, int level) +{ + int lvl; + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + + if (interval >= area->lsp_refresh[lvl-1]) + { + vty_out (vty, "LSP gen interval %us must be less than " + "the LSP refresh interval %us%s", + interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + area->lsp_gen_interval[lvl-1] = interval; + } + + return CMD_SUCCESS; +} + +DEFUN (lsp_gen_interval, + lsp_gen_interval_cmd, + "lsp-gen-interval <1-120>", + "Minimum interval between regenerating same LSP\n" + "Minimum interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_gen_interval, + no_lsp_gen_interval_cmd, + "no lsp-gen-interval", + NO_STR + "Minimum interval between regenerating same LSP\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_1 | IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_gen_interval, + no_lsp_gen_interval_arg_cmd, + "no lsp-gen-interval <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Minimum interval in seconds\n") + +DEFUN (lsp_gen_interval_l1, + lsp_gen_interval_l1_cmd, + "lsp-gen-interval level-1 <1-120>", + "Minimum interval between regenerating same LSP\n" + "Set interval for level 1 only\n" + "Minimum interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_1; + return set_lsp_gen_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_gen_interval_l1, + no_lsp_gen_interval_l1_cmd, + "no lsp-gen-interval level-1", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 1 only\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_1; + return set_lsp_gen_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_gen_interval_l1, + no_lsp_gen_interval_l1_arg_cmd, + "no lsp-gen-interval level-1 <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 1 only\n" + "Minimum interval in seconds\n") + +DEFUN (lsp_gen_interval_l2, + lsp_gen_interval_l2_cmd, + "lsp-gen-interval level-2 <1-120>", + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n" + "Minimum interval in seconds\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = atoi (argv[0]); + level = IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +DEFUN (no_lsp_gen_interval_l2, + no_lsp_gen_interval_l2_cmd, + "no lsp-gen-interval level-2", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n") +{ + struct isis_area *area; + uint16_t interval; + int level; + + area = vty->index; + interval = DEFAULT_MIN_LSP_GEN_INTERVAL; + level = IS_LEVEL_2; + return set_lsp_gen_interval (vty, area, interval, level); +} + +ALIAS (no_lsp_gen_interval_l2, + no_lsp_gen_interval_l2_arg_cmd, + "no lsp-gen-interval level-2 <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n" + "Minimum interval in seconds\n") + +DEFUN (spf_interval, + spf_interval_cmd, + "spf-interval <1-120>", + "Minimum interval between SPF calculations\n" + "Minimum interval between consecutive SPFs in seconds\n") +{ + struct isis_area *area; + u_int16_t interval; + + area = vty->index; + interval = atoi (argv[0]); + area->min_spf_interval[0] = interval; + area->min_spf_interval[1] = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_spf_interval, + no_spf_interval_cmd, + "no spf-interval", + NO_STR + "Minimum interval between SPF calculations\n") +{ + struct isis_area *area; + + area = vty->index; + + area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; + area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_spf_interval, + no_spf_interval_arg_cmd, + "no spf-interval <1-120>", + NO_STR + "Minimum interval between SPF calculations\n" + "Minimum interval between consecutive SPFs in seconds\n") + +DEFUN (spf_interval_l1, + spf_interval_l1_cmd, + "spf-interval level-1 <1-120>", + "Minimum interval between SPF calculations\n" + "Set interval for level 1 only\n" + "Minimum interval between consecutive SPFs in seconds\n") +{ + struct isis_area *area; + u_int16_t interval; + + area = vty->index; + interval = atoi (argv[0]); + area->min_spf_interval[0] = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_spf_interval_l1, + no_spf_interval_l1_cmd, + "no spf-interval level-1", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 1 only\n") +{ + struct isis_area *area; + + area = vty->index; + + area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_spf_interval, + no_spf_interval_l1_arg_cmd, + "no spf-interval level-1 <1-120>", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 1 only\n" + "Minimum interval between consecutive SPFs in seconds\n") + +DEFUN (spf_interval_l2, + spf_interval_l2_cmd, + "spf-interval level-2 <1-120>", + "Minimum interval between SPF calculations\n" + "Set interval for level 2 only\n" + "Minimum interval between consecutive SPFs in seconds\n") +{ + struct isis_area *area; + u_int16_t interval; + + area = vty->index; + interval = atoi (argv[0]); + area->min_spf_interval[1] = interval; + + return CMD_SUCCESS; +} + +DEFUN (no_spf_interval_l2, + no_spf_interval_l2_cmd, + "no spf-interval level-2", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 2 only\n") +{ + struct isis_area *area; + + area = vty->index; + + area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_spf_interval, + no_spf_interval_l2_arg_cmd, + "no spf-interval level-2 <1-120>", + NO_STR + "Minimum interval between SPF calculations\n" + "Set interval for level 2 only\n" + "Minimum interval between consecutive SPFs in seconds\n") + +static int +area_max_lsp_lifetime_set(struct vty *vty, int level, + uint16_t interval) +{ + struct isis_area *area = vty->index; + int lvl; + uint16_t refresh_interval = interval - 300; + int set_refresh_interval[ISIS_LEVELS] = {0, 0}; + + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + { + if (!(lvl & level)) + continue; + + if (refresh_interval < area->lsp_refresh[lvl-1]) + { + vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " + "the configured LSP refresh interval %us%s", + lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); + vty_out (vty, "Automatically reducing level %d LSP refresh interval " + "to %us%s", lvl, refresh_interval, VTY_NEWLINE); + set_refresh_interval[lvl-1] = 1; + + if (refresh_interval <= area->lsp_gen_interval[lvl-1]) + { + vty_out (vty, "LSP refresh interval %us must be greater than " + "the configured LSP gen interval %us%s", + refresh_interval, area->lsp_gen_interval[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) + { + if (!(lvl & level)) + continue; + isis_area_max_lsp_lifetime_set(area, lvl, interval); + if (set_refresh_interval[lvl-1]) + isis_area_lsp_refresh_set(area, lvl, refresh_interval); + } + + return CMD_SUCCESS; +} + +DEFUN (max_lsp_lifetime, + max_lsp_lifetime_cmd, + "max-lsp-lifetime <350-65535>", + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, atoi(argv[0])); +} + +DEFUN (no_max_lsp_lifetime, + no_max_lsp_lifetime_cmd, + "no max-lsp-lifetime", + NO_STR + "LSP lifetime in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, + DEFAULT_LSP_LIFETIME); +} + +ALIAS (no_max_lsp_lifetime, + no_max_lsp_lifetime_arg_cmd, + "no max-lsp-lifetime <350-65535>", + NO_STR + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n") + +DEFUN (max_lsp_lifetime_l1, + max_lsp_lifetime_l1_cmd, + "max-lsp-lifetime level-1 <350-65535>", + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1, atoi(argv[0])); +} + +DEFUN (no_max_lsp_lifetime_l1, + no_max_lsp_lifetime_l1_cmd, + "no max-lsp-lifetime level-1", + NO_STR + "LSP lifetime for Level 1 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_1, DEFAULT_LSP_LIFETIME); +} + +ALIAS (no_max_lsp_lifetime_l1, + no_max_lsp_lifetime_l1_arg_cmd, + "no max-lsp-lifetime level-1 <350-65535>", + NO_STR + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n") + +DEFUN (max_lsp_lifetime_l2, + max_lsp_lifetime_l2_cmd, + "max-lsp-lifetime level-2 <350-65535>", + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_2, atoi(argv[0])); +} + +DEFUN (no_max_lsp_lifetime_l2, + no_max_lsp_lifetime_l2_cmd, + "no max-lsp-lifetime level-2", + NO_STR + "LSP lifetime for Level 2 only in seconds\n") +{ + return area_max_lsp_lifetime_set(vty, IS_LEVEL_2, DEFAULT_LSP_LIFETIME); +} + +ALIAS (no_max_lsp_lifetime_l2, + no_max_lsp_lifetime_l2_arg_cmd, + "no max-lsp-lifetime level-2 <350-65535>", + NO_STR + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n") + +static int +area_lsp_refresh_interval_set(struct vty *vty, int level, uint16_t interval) +{ + struct isis_area *area = vty->index; + int lvl; + + if (!area) + { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + if (interval <= area->lsp_gen_interval[lvl-1]) + { + vty_out (vty, "LSP refresh interval %us must be greater than " + "the configured LSP gen interval %us%s", + interval, area->lsp_gen_interval[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) + { + vty_out (vty, "LSP refresh interval %us must be less than " + "the configured LSP lifetime %us less 300%s", + interval, area->max_lsp_lifetime[lvl-1], + VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) + { + if (!(lvl & level)) + continue; + isis_area_lsp_refresh_set(area, lvl, interval); + } + + return CMD_SUCCESS; +} + +DEFUN (lsp_refresh_interval, + lsp_refresh_interval_cmd, + "lsp-refresh-interval <1-65235>", + "LSP refresh interval\n" + "LSP refresh interval in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1_AND_2, atoi(argv[0])); +} + +DEFUN (no_lsp_refresh_interval, + no_lsp_refresh_interval_cmd, + "no lsp-refresh-interval", + NO_STR + "LSP refresh interval in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1_AND_2, + DEFAULT_MAX_LSP_GEN_INTERVAL); +} + +ALIAS (no_lsp_refresh_interval, + no_lsp_refresh_interval_arg_cmd, + "no lsp-refresh-interval <1-65235>", + NO_STR + "LSP refresh interval\n" + "LSP refresh interval in seconds\n") + +DEFUN (lsp_refresh_interval_l1, + lsp_refresh_interval_l1_cmd, + "lsp-refresh-interval level-1 <1-65235>", + "LSP refresh interval for Level 1 only\n" + "LSP refresh interval for Level 1 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1, atoi(argv[0])); +} + +DEFUN (no_lsp_refresh_interval_l1, + no_lsp_refresh_interval_l1_cmd, + "no lsp-refresh-interval level-1", + NO_STR + "LSP refresh interval for Level 1 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_1, + DEFAULT_MAX_LSP_GEN_INTERVAL); +} + +ALIAS (no_lsp_refresh_interval_l1, + no_lsp_refresh_interval_l1_arg_cmd, + "no lsp-refresh-interval level-1 <1-65235>", + NO_STR + "LSP refresh interval for Level 1 only\n" + "LSP refresh interval for Level 1 only in seconds\n") + +DEFUN (lsp_refresh_interval_l2, + lsp_refresh_interval_l2_cmd, + "lsp-refresh-interval level-2 <1-65235>", + "LSP refresh interval for Level 2 only\n" + "LSP refresh interval for Level 2 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_2, atoi(argv[0])); +} + +DEFUN (no_lsp_refresh_interval_l2, + no_lsp_refresh_interval_l2_cmd, + "no lsp-refresh-interval level-2", + NO_STR + "LSP refresh interval for Level 2 only in seconds\n") +{ + return area_lsp_refresh_interval_set(vty, IS_LEVEL_2, + DEFAULT_MAX_LSP_GEN_INTERVAL); +} + +ALIAS (no_lsp_refresh_interval_l2, + no_lsp_refresh_interval_l2_arg_cmd, + "no lsp-refresh-interval level-2 <1-65235>", + NO_STR + "LSP refresh interval for Level 2 only\n" + "LSP refresh interval for Level 2 only in seconds\n") + void isis_vty_init (void) { @@ -1740,4 +2265,44 @@ isis_vty_init (void) install_element (ISIS_NODE, &is_type_cmd); install_element (ISIS_NODE, &no_is_type_cmd); + + install_element (ISIS_NODE, &lsp_gen_interval_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd); + install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd); + install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &spf_interval_cmd); + install_element (ISIS_NODE, &no_spf_interval_cmd); + install_element (ISIS_NODE, &no_spf_interval_arg_cmd); + install_element (ISIS_NODE, &spf_interval_l1_cmd); + install_element (ISIS_NODE, &no_spf_interval_l1_cmd); + install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd); + install_element (ISIS_NODE, &spf_interval_l2_cmd); + install_element (ISIS_NODE, &no_spf_interval_l2_cmd); + install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &max_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); + install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); + + install_element (ISIS_NODE, &lsp_refresh_interval_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); + install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); + install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); + install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); } diff --git a/isisd/isisd.c b/isisd/isisd.c index 130e75236..55a62d38e 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2010,159 +2010,6 @@ isis_area_is_type_set(struct isis_area *area, int is_type) return; } -static int -set_lsp_gen_interval (struct vty *vty, struct isis_area *area, - uint16_t interval, int level) -{ - int lvl; - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) - { - if (!(lvl & level)) - continue; - - if (interval >= area->lsp_refresh[lvl-1]) - { - vty_out (vty, "LSP gen interval %us must be less than " - "the LSP refresh interval %us%s", - interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) - { - if (!(lvl & level)) - continue; - area->lsp_gen_interval[lvl-1] = interval; - } - - return CMD_SUCCESS; -} - -DEFUN (lsp_gen_interval, - lsp_gen_interval_cmd, - "lsp-gen-interval <1-120>", - "Minimum interval between regenerating same LSP\n" - "Minimum interval in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_gen_interval, - no_lsp_gen_interval_cmd, - "no lsp-gen-interval", - NO_STR - "Minimum interval between regenerating same LSP\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MIN_LSP_GEN_INTERVAL; - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_gen_interval, - no_lsp_gen_interval_arg_cmd, - "no lsp-gen-interval <1-120>", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Minimum interval in seconds\n") - -DEFUN (lsp_gen_interval_l1, - lsp_gen_interval_l1_cmd, - "lsp-gen-interval level-1 <1-120>", - "Minimum interval between regenerating same LSP\n" - "Set interval for level 1 only\n" - "Minimum interval in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1; - return set_lsp_gen_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_gen_interval_l1, - no_lsp_gen_interval_l1_cmd, - "no lsp-gen-interval level-1", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 1 only\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MIN_LSP_GEN_INTERVAL; - level = IS_LEVEL_1; - return set_lsp_gen_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_gen_interval_l1, - no_lsp_gen_interval_l1_arg_cmd, - "no lsp-gen-interval level-1 <1-120>", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 1 only\n" - "Minimum interval in seconds\n") - -DEFUN (lsp_gen_interval_l2, - lsp_gen_interval_l2_cmd, - "lsp-gen-interval level-2 <1-120>", - "Minimum interval between regenerating same LSP\n" - "Set interval for level 2 only\n" - "Minimum interval in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_gen_interval_l2, - no_lsp_gen_interval_l2_cmd, - "no lsp-gen-interval level-2", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 2 only\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MIN_LSP_GEN_INTERVAL; - level = IS_LEVEL_2; - return set_lsp_gen_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_gen_interval_l2, - no_lsp_gen_interval_l2_arg_cmd, - "no lsp-gen-interval level-2 <1-120>", - NO_STR - "Minimum interval between regenerating same LSP\n" - "Set interval for level 2 only\n" - "Minimum interval in seconds\n") - void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, bool new_metric) { @@ -2206,450 +2053,32 @@ void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname) } } -DEFUN (spf_interval, - spf_interval_cmd, - "spf-interval <1-120>", - "Minimum interval between SPF calculations\n" - "Minimum interval between consecutive SPFs in seconds\n") -{ - struct isis_area *area; - u_int16_t interval; - - area = vty->index; - interval = atoi (argv[0]); - area->min_spf_interval[0] = interval; - area->min_spf_interval[1] = interval; - - return CMD_SUCCESS; -} - -DEFUN (no_spf_interval, - no_spf_interval_cmd, - "no spf-interval", - NO_STR - "Minimum interval between SPF calculations\n") -{ - struct isis_area *area; - - area = vty->index; - - area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; - area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_spf_interval, - no_spf_interval_arg_cmd, - "no spf-interval <1-120>", - NO_STR - "Minimum interval between SPF calculations\n" - "Minimum interval between consecutive SPFs in seconds\n") - -DEFUN (spf_interval_l1, - spf_interval_l1_cmd, - "spf-interval level-1 <1-120>", - "Minimum interval between SPF calculations\n" - "Set interval for level 1 only\n" - "Minimum interval between consecutive SPFs in seconds\n") -{ - struct isis_area *area; - u_int16_t interval; - - area = vty->index; - interval = atoi (argv[0]); - area->min_spf_interval[0] = interval; - - return CMD_SUCCESS; -} - -DEFUN (no_spf_interval_l1, - no_spf_interval_l1_cmd, - "no spf-interval level-1", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 1 only\n") -{ - struct isis_area *area; - - area = vty->index; - - area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_spf_interval, - no_spf_interval_l1_arg_cmd, - "no spf-interval level-1 <1-120>", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 1 only\n" - "Minimum interval between consecutive SPFs in seconds\n") - -DEFUN (spf_interval_l2, - spf_interval_l2_cmd, - "spf-interval level-2 <1-120>", - "Minimum interval between SPF calculations\n" - "Set interval for level 2 only\n" - "Minimum interval between consecutive SPFs in seconds\n") -{ - struct isis_area *area; - u_int16_t interval; - - area = vty->index; - interval = atoi (argv[0]); - area->min_spf_interval[1] = interval; - - return CMD_SUCCESS; -} - -DEFUN (no_spf_interval_l2, - no_spf_interval_l2_cmd, - "no spf-interval level-2", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 2 only\n") -{ - struct isis_area *area; - - area = vty->index; - - area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; - - return CMD_SUCCESS; -} - -ALIAS (no_spf_interval, - no_spf_interval_l2_arg_cmd, - "no spf-interval level-2 <1-120>", - NO_STR - "Minimum interval between SPF calculations\n" - "Set interval for level 2 only\n" - "Minimum interval between consecutive SPFs in seconds\n") - -static int -set_lsp_max_lifetime (struct vty *vty, struct isis_area *area, - uint16_t interval, int level) -{ - int lvl; - int set_refresh_interval[ISIS_LEVELS] = {0, 0}; - uint16_t refresh_interval; - - refresh_interval = interval - 300; - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) - { - if (!(lvl & level)) - continue; - if (refresh_interval < area->lsp_refresh[lvl-1]) - { - vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " - "the configured LSP refresh interval %us%s", - lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); - vty_out (vty, "Automatically reducing level %d LSP refresh interval " - "to %us%s", lvl, refresh_interval, VTY_NEWLINE); - set_refresh_interval[lvl-1] = 1; - - if (refresh_interval <= area->lsp_gen_interval[lvl-1]) - { - vty_out (vty, "LSP refresh interval %us must be greater than " - "the configured LSP gen interval %us%s", - refresh_interval, area->lsp_gen_interval[lvl-1], - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } - } - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) - { - if (!(lvl & level)) - continue; - area->max_lsp_lifetime[lvl-1] = interval; - /* Automatically reducing lsp_refresh_interval to interval - 300 */ - if (set_refresh_interval[lvl-1]) - area->lsp_refresh[lvl-1] = refresh_interval; - } - - lsp_regenerate_schedule (area, level, 1); - - return CMD_SUCCESS; -} - -DEFUN (max_lsp_lifetime, - max_lsp_lifetime_cmd, - "max-lsp-lifetime <350-65535>", - "Maximum LSP lifetime\n" - "LSP lifetime in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -DEFUN (no_max_lsp_lifetime, - no_max_lsp_lifetime_cmd, - "no max-lsp-lifetime", - NO_STR - "LSP lifetime in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_LSP_LIFETIME; - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -ALIAS (no_max_lsp_lifetime, - no_max_lsp_lifetime_arg_cmd, - "no max-lsp-lifetime <350-65535>", - NO_STR - "Maximum LSP lifetime\n" - "LSP lifetime in seconds\n") - -DEFUN (max_lsp_lifetime_l1, - max_lsp_lifetime_l1_cmd, - "max-lsp-lifetime level-1 <350-65535>", - "Maximum LSP lifetime for Level 1 only\n" - "LSP lifetime for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -DEFUN (no_max_lsp_lifetime_l1, - no_max_lsp_lifetime_l1_cmd, - "no max-lsp-lifetime level-1", - NO_STR - "LSP lifetime for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_LSP_LIFETIME; - level = IS_LEVEL_1; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -ALIAS (no_max_lsp_lifetime_l1, - no_max_lsp_lifetime_l1_arg_cmd, - "no max-lsp-lifetime level-1 <350-65535>", - NO_STR - "Maximum LSP lifetime for Level 1 only\n" - "LSP lifetime for Level 1 only in seconds\n") - -DEFUN (max_lsp_lifetime_l2, - max_lsp_lifetime_l2_cmd, - "max-lsp-lifetime level-2 <350-65535>", - "Maximum LSP lifetime for Level 2 only\n" - "LSP lifetime for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -DEFUN (no_max_lsp_lifetime_l2, - no_max_lsp_lifetime_l2_cmd, - "no max-lsp-lifetime level-2", - NO_STR - "LSP lifetime for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_LSP_LIFETIME; - level = IS_LEVEL_2; - return set_lsp_max_lifetime (vty, area, interval, level); -} - -ALIAS (no_max_lsp_lifetime_l2, - no_max_lsp_lifetime_l2_arg_cmd, - "no max-lsp-lifetime level-2 <350-65535>", - NO_STR - "Maximum LSP lifetime for Level 2 only\n" - "LSP lifetime for Level 2 only in seconds\n") - -static int -set_lsp_refresh_interval (struct vty *vty, struct isis_area *area, - uint16_t interval, int level) -{ - int lvl; - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) - { - if (!(lvl & level)) - continue; - if (interval <= area->lsp_gen_interval[lvl-1]) - { - vty_out (vty, "LSP refresh interval %us must be greater than " - "the configured LSP gen interval %us%s", - interval, area->lsp_gen_interval[lvl-1], - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) - { - vty_out (vty, "LSP refresh interval %us must be less than " - "the configured LSP lifetime %us less 300%s", - interval, area->max_lsp_lifetime[lvl-1], - VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - } - - for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) - { - if (!(lvl & level)) - continue; - area->lsp_refresh[lvl-1] = interval; - } - lsp_regenerate_schedule (area, level, 1); - - return CMD_SUCCESS; -} - -DEFUN (lsp_refresh_interval, - lsp_refresh_interval_cmd, - "lsp-refresh-interval <1-65235>", - "LSP refresh interval\n" - "LSP refresh interval in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_refresh_interval, - no_lsp_refresh_interval_cmd, - "no lsp-refresh-interval", - NO_STR - "LSP refresh interval in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = DEFAULT_MAX_LSP_GEN_INTERVAL; - level = IS_LEVEL_1 | IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -ALIAS (no_lsp_refresh_interval, - no_lsp_refresh_interval_arg_cmd, - "no lsp-refresh-interval <1-65235>", - NO_STR - "LSP refresh interval\n" - "LSP refresh interval in seconds\n") - -DEFUN (lsp_refresh_interval_l1, - lsp_refresh_interval_l1_cmd, - "lsp-refresh-interval level-1 <1-65235>", - "LSP refresh interval for Level 1 only\n" - "LSP refresh interval for Level 1 only in seconds\n") +void +isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, + uint16_t max_lsp_lifetime) { - struct isis_area *area; - uint16_t interval; - int level; + assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_1; - return set_lsp_refresh_interval (vty, area, interval, level); -} - -DEFUN (no_lsp_refresh_interval_l1, - no_lsp_refresh_interval_l1_cmd, - "no lsp-refresh-interval level-1", - NO_STR - "LSP refresh interval for Level 1 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; + if (area->max_lsp_lifetime[level-1] == max_lsp_lifetime) + return; - area = vty->index; - interval = DEFAULT_MAX_LSP_GEN_INTERVAL; - level = IS_LEVEL_1; - return set_lsp_refresh_interval (vty, area, interval, level); + area->max_lsp_lifetime[level-1] = max_lsp_lifetime; + lsp_regenerate_schedule(area, level, 1); } -ALIAS (no_lsp_refresh_interval_l1, - no_lsp_refresh_interval_l1_arg_cmd, - "no lsp-refresh-interval level-1 <1-65235>", - NO_STR - "LSP refresh interval for Level 1 only\n" - "LSP refresh interval for Level 1 only in seconds\n") - -DEFUN (lsp_refresh_interval_l2, - lsp_refresh_interval_l2_cmd, - "lsp-refresh-interval level-2 <1-65235>", - "LSP refresh interval for Level 2 only\n" - "LSP refresh interval for Level 2 only in seconds\n") +void +isis_area_lsp_refresh_set(struct isis_area *area, int level, + uint16_t lsp_refresh) { - struct isis_area *area; - uint16_t interval; - int level; - - area = vty->index; - interval = atoi (argv[0]); - level = IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); -} + assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); -DEFUN (no_lsp_refresh_interval_l2, - no_lsp_refresh_interval_l2_cmd, - "no lsp-refresh-interval level-2", - NO_STR - "LSP refresh interval for Level 2 only in seconds\n") -{ - struct isis_area *area; - uint16_t interval; - int level; + if (area->lsp_refresh[level-1] == lsp_refresh) + return; - area = vty->index; - interval = DEFAULT_MAX_LSP_GEN_INTERVAL; - level = IS_LEVEL_2; - return set_lsp_refresh_interval (vty, area, interval, level); + area->lsp_refresh[level-1] = lsp_refresh; + lsp_regenerate_schedule(area, level, 1); } -ALIAS (no_lsp_refresh_interval_l2, - no_lsp_refresh_interval_l2_arg_cmd, - "no lsp-refresh-interval level-2 <1-65235>", - NO_STR - "LSP refresh interval for Level 2 only\n" - "LSP refresh interval for Level 2 only in seconds\n") - DEFUN (log_adj_changes, log_adj_changes_cmd, "log-adjacency-changes", @@ -3193,46 +2622,6 @@ isis_init () install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_domain_passwd_cmd); - install_element (ISIS_NODE, &lsp_gen_interval_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd); - install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd); - install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd); - - install_element (ISIS_NODE, &spf_interval_cmd); - install_element (ISIS_NODE, &no_spf_interval_cmd); - install_element (ISIS_NODE, &no_spf_interval_arg_cmd); - install_element (ISIS_NODE, &spf_interval_l1_cmd); - install_element (ISIS_NODE, &no_spf_interval_l1_cmd); - install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd); - install_element (ISIS_NODE, &spf_interval_l2_cmd); - install_element (ISIS_NODE, &no_spf_interval_l2_cmd); - install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); - - install_element (ISIS_NODE, &max_lsp_lifetime_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); - install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); - install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); - install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); - - install_element (ISIS_NODE, &lsp_refresh_interval_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); - install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); - install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); - install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); - install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 2ba44d8fd..018664440 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -148,6 +148,10 @@ void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, bool new_metric); void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu); void isis_area_is_type_set(struct isis_area *area, int is_type); +void isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, + uint16_t max_lsp_lifetime); +void isis_area_lsp_refresh_set(struct isis_area *area, int level, + uint16_t lsp_refresh); void isis_vty_init (void); From 68845c19e468480dbdf5483f0b60323674a5ec28 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 28 Jul 2016 17:23:31 +0200 Subject: [PATCH 1165/1342] isisd: API: area (L1), domain (L2) passwords Last isisd CLI cleanup for now. This also folds L1 & L2 configs into common functions, reducing CLI function bloat by a bit. (This patch contains changes authored by both Christian Franke and David Lamparter.) Signed-off-by: David Lamparter --- isisd/isis_vty.c | 117 ++++++++++++++++++ isisd/isisd.c | 300 ++++++----------------------------------------- isisd/isisd.h | 7 +- 3 files changed, 158 insertions(+), 266 deletions(-) diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index be4150430..3f218561c 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -2165,6 +2165,117 @@ ALIAS (no_lsp_refresh_interval_l2, "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") +static int +area_passwd_set(struct vty *vty, int level, + int (*type_set)(struct isis_area *area, int level, + const char *passwd, u_char snp_auth), + const char *passwd, u_char snp_auth) +{ + struct isis_area *area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + if (passwd && strlen(passwd) > 254) + { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + type_set(area, level, passwd, snp_auth); + return CMD_SUCCESS; +} + +DEFUN (area_passwd_md5, + area_passwd_md5_cmd, + "(area-password|domain-password) md5 WORD", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Level-wide password\n") +{ + u_char snp_auth = 0; + int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; + + if (argc > 2) + { + snp_auth = SNP_AUTH_SEND; + if (strncmp(argv[2], "v", 1) == 0) + snp_auth |= SNP_AUTH_RECV; + } + + return area_passwd_set(vty, level, isis_area_passwd_hmac_md5_set, + argv[1], snp_auth); +} + +ALIAS (area_passwd_md5, + area_passwd_md5_snpauth_cmd, + "(area-password|domain-password) md5 WORD authenticate snp (send-only|validate)", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Level-wide password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n") + +DEFUN (area_passwd_clear, + area_passwd_clear_cmd, + "(area-password|domain-password) clear WORD", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Area password\n") +{ + u_char snp_auth = 0; + int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; + + if (argc > 2) + { + snp_auth = SNP_AUTH_SEND; + if (strncmp(argv[2], "v", 1) == 0) + snp_auth |= SNP_AUTH_RECV; + } + + return area_passwd_set(vty, level, isis_area_passwd_cleartext_set, + argv[1], snp_auth); +} + +ALIAS (area_passwd_clear, + area_passwd_clear_snpauth_cmd, + "(area-password|domain-password) clear WORD authenticate snp (send-only|validate)", + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Area password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n") + +DEFUN (no_area_passwd, + no_area_passwd_cmd, + "no (area-password|domain-password)", + NO_STR + "Configure the authentication password for an area\n" + "Set the authentication password for a routing domain\n") +{ + int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; + struct isis_area *area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + return isis_area_passwd_unset (area, level); +} + void isis_vty_init (void) { @@ -2305,4 +2416,10 @@ isis_vty_init (void) install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); + + install_element (ISIS_NODE, &area_passwd_md5_cmd); + install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); + install_element (ISIS_NODE, &area_passwd_clear_cmd); + install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); + install_element (ISIS_NODE, &no_area_passwd_cmd); } diff --git a/isisd/isisd.c b/isisd/isisd.c index 55a62d38e..df99cd14a 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1621,280 +1621,62 @@ void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu) lsp_regenerate_schedule(area, IS_LEVEL_1_AND_2, 1); } -DEFUN (area_passwd_md5, - area_passwd_md5_cmd, - "area-password md5 WORD", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n") +static int +isis_area_passwd_set(struct isis_area *area, int level, u_char passwd_type, + const char *passwd, u_char snp_auth) { - struct isis_area *area; + struct isis_passwd *dest; + struct isis_passwd modified; int len; - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); + dest = (level == IS_LEVEL_1) ? &area->area_passwd : &area->domain_passwd; + memset(&modified, 0, sizeof(modified)); - len = strlen (argv[0]); - if (len > 254) + if (passwd_type != ISIS_PASSWD_TYPE_UNUSED) { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->area_passwd.len = (u_char) len; - area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; - strncpy ((char *)area->area_passwd.passwd, argv[0], 255); + if (!passwd) + return -1; - if (argc > 1) - { - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -ALIAS (area_passwd_md5, - area_passwd_md5_snpauth_cmd, - "area-password md5 WORD authenticate snp (send-only|validate)", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (area_passwd_clear, - area_passwd_clear_cmd, - "area-password clear WORD", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n") -{ - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } + len = strlen(passwd); + if (len > 254) + return -1; - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; + modified.len = len; + strncpy((char*)modified.passwd, passwd, 255); + modified.type = passwd_type; + modified.snp_auth = snp_auth; } - area->area_passwd.len = (u_char) len; - area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; - strncpy ((char *)area->area_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); - } - else + if (memcmp(&modified, dest, sizeof(modified))) { - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + memcpy(dest, &modified, sizeof(modified)); + lsp_regenerate_schedule(area, IS_LEVEL_1|IS_LEVEL_2, 1); } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - return CMD_SUCCESS; + return 0; } -ALIAS (area_passwd_clear, - area_passwd_clear_snpauth_cmd, - "area-password clear WORD authenticate snp (send-only|validate)", - "Configure the authentication password for an area\n" - "Authentication type\n" - "Area password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (no_area_passwd, - no_area_passwd_cmd, - "no area-password", - NO_STR - "Configure the authentication password for an area\n") +int +isis_area_passwd_unset (struct isis_area *area, int level) { - struct isis_area *area; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - memset (&area->area_passwd, 0, sizeof (struct isis_passwd)); - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; + return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_UNUSED, NULL, 0); } -DEFUN (domain_passwd_md5, - domain_passwd_md5_cmd, - "domain-password md5 WORD", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n") -{ - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->domain_passwd.len = (u_char) len; - area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; - strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; -} - -ALIAS (domain_passwd_md5, - domain_passwd_md5_snpauth_cmd, - "domain-password md5 WORD authenticate snp (send-only|validate)", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (domain_passwd_clear, - domain_passwd_clear_cmd, - "domain-password clear WORD", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n") +int +isis_area_passwd_cleartext_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth) { - struct isis_area *area; - int len; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - len = strlen (argv[0]); - if (len > 254) - { - vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); - return CMD_ERR_AMBIGUOUS; - } - - area->domain_passwd.len = (u_char) len; - area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; - strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); - - if (argc > 1) - { - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - if (strncmp(argv[1], "v", 1) == 0) - SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - else - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - else - { - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); - UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); - } - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; + return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_CLEARTXT, + passwd, snp_auth); } -ALIAS (domain_passwd_clear, - domain_passwd_clear_snpauth_cmd, - "domain-password clear WORD authenticate snp (send-only|validate)", - "Set the authentication password for a routing domain\n" - "Authentication type\n" - "Routing domain password\n" - "Authentication\n" - "SNP PDUs\n" - "Send but do not check PDUs on receiving\n" - "Send and check PDUs on receiving\n") - -DEFUN (no_domain_passwd, - no_domain_passwd_cmd, - "no domain-password", - NO_STR - "Set the authentication password for a routing domain\n") +int +isis_area_passwd_hmac_md5_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth) { - struct isis_area *area; - - area = vty->index; - - if (!area) - { - vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); - return CMD_ERR_NO_MATCH; - } - - memset (&area->domain_passwd, 0, sizeof (struct isis_passwd)); - lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); - - return CMD_SUCCESS; + return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_HMAC_MD5, + passwd, snp_auth); } static void @@ -2610,18 +2392,6 @@ isis_init () install_element (ISIS_NODE, &net_cmd); install_element (ISIS_NODE, &no_net_cmd); - install_element (ISIS_NODE, &area_passwd_md5_cmd); - install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); - install_element (ISIS_NODE, &area_passwd_clear_cmd); - install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); - install_element (ISIS_NODE, &no_area_passwd_cmd); - - install_element (ISIS_NODE, &domain_passwd_md5_cmd); - install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd); - install_element (ISIS_NODE, &domain_passwd_clear_cmd); - install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd); - install_element (ISIS_NODE, &no_domain_passwd_cmd); - install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 018664440..eedb451dd 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -152,7 +152,12 @@ void isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, uint16_t max_lsp_lifetime); void isis_area_lsp_refresh_set(struct isis_area *area, int level, uint16_t lsp_refresh); - +/* IS_LEVEL_1 sets area_passwd, IS_LEVEL_2 domain_passwd */ +int isis_area_passwd_unset (struct isis_area *area, int level); +int isis_area_passwd_cleartext_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth); +int isis_area_passwd_hmac_md5_set (struct isis_area *area, int level, + const char *passwd, u_char snp_auth); void isis_vty_init (void); /* Master of threads. */ From f263413f762058d887aa7b2b6c502bd84af3c923 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Jul 2016 17:23:32 +0200 Subject: [PATCH 1166/1342] isisd: drop unused per-type metric values Expense, Error and Delay metrics never quite made it into the real world. Either way isisd does nothing useful with them, so let's drop them from the code. If someone wants to implement them, this patch can still be reverted. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 11 ++++------- isisd/isis_circuit.h | 2 +- isisd/isis_lsp.c | 21 +++++++++++++++------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 04c515506..aa30fcdb7 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -93,10 +93,7 @@ isis_circuit_new () circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; circuit->priority[i] = DEFAULT_PRIORITY; - circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC; - circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; - circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; - circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; + circuit->metric[i] = DEFAULT_CIRCUIT_METRIC; circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; } @@ -901,7 +898,7 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, vty_out (vty, " Metric: %d", circuit->te_metric[0]); else vty_out (vty, " Metric: %d", - circuit->metrics[0].metric_default); + circuit->metric[0]); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", @@ -934,7 +931,7 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, vty_out (vty, " Metric: %d", circuit->te_metric[1]); else vty_out (vty, " Metric: %d", - circuit->metrics[1].metric_default); + circuit->metric[1]); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", @@ -1302,7 +1299,7 @@ isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric) return -1; circuit->te_metric[level - 1] = metric; - circuit->metrics[level - 1].metric_default = metric; + circuit->metric[level - 1] = metric; if (circuit->area) lsp_regenerate_schedule (circuit->area, level, 0); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 9843ef372..9ada1e26a 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -117,7 +117,7 @@ struct isis_circuit u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */ u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */ u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */ - struct metric metrics[2]; /* l1XxxMetric */ + u_int8_t metric[2]; u_int32_t te_metric[2]; struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */ int ip_router; /* Route IP ? */ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 9032de4f4..aac8451bf 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1544,7 +1544,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) { ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability)); - ipreach->metrics = circuit->metrics[level - 1]; + ipreach->metrics.metric_default = circuit->metric[level - 1]; + ipreach->metrics.metric_expense = METRICS_UNSUPPORTED; + ipreach->metrics.metric_error = METRICS_UNSUPPORTED; + ipreach->metrics.metric_delay = METRICS_UNSUPPORTED; masklen2ip (ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr = ((ipreach->mask.s_addr) & (ipv4->prefix.s_addr)); @@ -1569,7 +1572,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) ((ipv4->prefixlen + 7)/8) - 1); if (area->oldmetric) - te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default); + te_ipreach->te_metric = htonl (circuit->metric[level - 1]); else te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]); @@ -1604,7 +1607,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) if (area->oldmetric) ip6reach->metric = - htonl (circuit->metrics[level - 1].metric_default); + htonl (circuit->metric[level - 1]); else ip6reach->metric = htonl (circuit->te_metric[level - 1]); @@ -1643,7 +1646,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) else memcpy (is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); - is_neigh->metrics = circuit->metrics[level - 1]; + is_neigh->metrics.metric_default = circuit->metric[level - 1]; + is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; if (!memcmp (is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) { @@ -1675,7 +1681,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) memcpy (te_is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); if (area->oldmetric) - metric = circuit->metrics[level - 1].metric_default; + metric = circuit->metric[level - 1]; else metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); @@ -1722,7 +1728,10 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); - is_neigh->metrics = circuit->metrics[level - 1]; + is_neigh->metrics.metric_default = circuit->metric[level - 1]; + is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag, sysid_print(is_neigh->neigh_id)); From 515812ddbbb6a41298261688c8ccd0df8e900f17 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 11 Aug 2016 16:59:08 +0200 Subject: [PATCH 1167/1342] isisd: fix isis_circuit_create() Between the awkwardly managed CSM and the tacked-on IPv6 support, the simplified logic to setup a circuit wasn't quite right. Note that the API essentially allows creating a circuit without enabling either IPv4 or IPv6. This wasn't possible before and probably breaks isisd in 'interesting' ways. The CLI won't do this, so it's only an issue when adding on other configuration mechanisms. Reported-by: Martin Winter Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 6 ++++-- isisd/isis_vty.c | 16 ++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index aa30fcdb7..b830794cb 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1225,8 +1225,10 @@ isis_interface_config_write (struct vty *vty) struct isis_circuit * isis_circuit_create (struct isis_area *area, struct interface *ifp) { - struct isis_circuit *circuit; - circuit = isis_csm_state_change (ISIS_ENABLE, NULL, area); + struct isis_circuit *circuit = circuit_scan_by_ifp (ifp); + if (circuit && circuit->area) + return NULL; + circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); assert (circuit->state == C_STATE_CONF || circuit->state == C_STATE_UP); isis_circuit_if_bind (circuit, ifp); return circuit; diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 3f218561c..3ce06b83d 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -72,17 +72,13 @@ DEFUN (ip_router_isis, /* Prevent more than one area per circuit */ circuit = circuit_scan_by_ifp (ifp); - if (circuit) + if (circuit && circuit->area) { - if (circuit->ip_router == 1) + if (strcmp (circuit->area->area_tag, area_tag)) { - if (strcmp (circuit->area->area_tag, area_tag)) - { - vty_out (vty, "ISIS circuit is already defined on %s%s", - circuit->area->area_tag, VTY_NEWLINE); - return CMD_ERR_NOTHING_TODO; - } - return CMD_SUCCESS; + vty_out (vty, "ISIS circuit is already defined on %s%s", + circuit->area->area_tag, VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; } } @@ -90,7 +86,7 @@ DEFUN (ip_router_isis, if (!area) area = isis_area_create (area_tag); - if (!circuit) + if (!circuit || !circuit->area) circuit = isis_circuit_create (area, ifp); bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; From 5a1a087baebcc4a996de66c558bac49419034ee0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 11 Aug 2016 17:02:50 +0200 Subject: [PATCH 1168/1342] isisd: fix isis_circuit_af_set() on fresh circuit A newly-created circuit will be in enabled state but have neither IPv4 nor IPv6 configured. The logic in isis_circuit_af_set assumed that "enabled" is equivalent to "ip || ipv6". This is the only place where this distinction is currently relevant, as the CLI won't allow enabling an interface without enabling either IPv4 or IPv6; and it will also disable a circuit when both are deconfigured. Reported-by: Martin Winter Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index b830794cb..4acd8f3b6 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1239,7 +1239,7 @@ isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_rou { struct isis_area *area = circuit->area; bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router; - bool was_enabled = circuit->ip_router || circuit->ipv6_router; + bool was_enabled = !!circuit->area; area->ip_circuits += ip_router - circuit->ip_router; area->ipv6_circuits += ipv6_router - circuit->ipv6_router; From a798abbe65cc2cdce050a1aef85c6d243d44a575 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Thu, 11 Aug 2016 16:08:05 +0200 Subject: [PATCH 1169/1342] isisd: fix network-type configuration Reported-by: Martin Winter Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 1 - isisd/isis_vty.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 4acd8f3b6..bbe06b551 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1357,7 +1357,6 @@ isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) * is not supported. */ if (circ_type == CIRCUIT_T_UNKNOWN || circ_type == CIRCUIT_T_LOOPBACK - || circuit->circ_type == CIRCUIT_T_UNKNOWN || circuit->circ_type == CIRCUIT_T_LOOPBACK) { if (circuit->circ_type != circ_type) diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 3ce06b83d..f9b96a42d 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -255,7 +255,7 @@ DEFUN (isis_network, if (!circuit) return CMD_ERR_NO_MATCH; - if (!isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) + if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) { vty_out (vty, "isis network point-to-point " "is valid only on broadcast interfaces%s", @@ -278,7 +278,7 @@ DEFUN (no_isis_network, if (!circuit) return CMD_ERR_NO_MATCH; - if (!isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) + if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) { vty_out (vty, "isis network point-to-point " "is valid only on broadcast interfaces%s", From 1187e25191b38a1876fafbfd733a70942ebcb062 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 13 Aug 2016 01:20:20 +0200 Subject: [PATCH 1170/1342] isisd: fix is_type_set Code's "is_type" is "circuit-type" in CLI, "circuit_type" is "network" (type) in CLI, and the function to change is_type is isis_event_circuit_type_change()... *headdesk* Reported-by: Martin Winter Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index bbe06b551..4750c5c4f 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1284,10 +1284,10 @@ isis_circuit_passive_set (struct isis_circuit *circuit, bool passive) } void -isis_circuit_is_type_set (struct isis_circuit *circuit, int circ_type) +isis_circuit_is_type_set (struct isis_circuit *circuit, int is_type) { - if (circuit->circ_type != circ_type) - isis_event_circuit_type_change (circuit, circ_type); + if (circuit->is_type != is_type) + isis_event_circuit_type_change (circuit, is_type); } int From 4c7d7173baa9fe064349f5fe2e0bdcb367475499 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 13 Aug 2016 01:32:52 +0200 Subject: [PATCH 1171/1342] isisd: fold up isis_circuit_is_type_set() see previous commit. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 7 ------- isisd/isis_events.c | 2 +- isisd/isisd.c | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 4750c5c4f..85a682d0d 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1283,13 +1283,6 @@ isis_circuit_passive_set (struct isis_circuit *circuit, bool passive) return 0; } -void -isis_circuit_is_type_set (struct isis_circuit *circuit, int is_type) -{ - if (circuit->is_type != is_type) - isis_event_circuit_type_change (circuit, is_type); -} - int isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric) { diff --git a/isisd/isis_events.c b/isisd/isis_events.c index ebd86a55e..abc4471ca 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -147,7 +147,7 @@ circuit_resign_level (struct isis_circuit *circuit, int level) } void -isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) +isis_circuit_is_type_set (struct isis_circuit *circuit, int newtype) { if (circuit->state != C_STATE_UP) { diff --git a/isisd/isisd.c b/isisd/isisd.c index df99cd14a..9844ae5b0 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1778,7 +1778,7 @@ isis_area_is_type_set(struct isis_area *area, int is_type) if (area->is_type != IS_LEVEL_1_AND_2) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - isis_event_circuit_type_change (circuit, is_type); + isis_circuit_is_type_set (circuit, is_type); } spftree_area_init (area); From af177b245ef3f092ecd0ae75cb75c2d797a7b139 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 15 Aug 2016 13:36:59 +0200 Subject: [PATCH 1172/1342] isisd: warn if there is an MTU issue on circuits Instead of later tripping over an assert, add a proper warning for interfaces whose MTU is too low. Signed-off-by: David Lamparter --- isisd/isis_circuit.c | 3 ++- isisd/isis_vty.c | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 85a682d0d..da0b57a30 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1229,7 +1229,8 @@ isis_circuit_create (struct isis_area *area, struct interface *ifp) if (circuit && circuit->area) return NULL; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); - assert (circuit->state == C_STATE_CONF || circuit->state == C_STATE_UP); + if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) + return circuit; isis_circuit_if_bind (circuit, ifp); return circuit; } diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index f9b96a42d..4148eb55b 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -86,9 +86,16 @@ DEFUN (ip_router_isis, if (!area) area = isis_area_create (area_tag); - if (!circuit || !circuit->area) + if (!circuit || !circuit->area) { circuit = isis_circuit_create (area, ifp); + if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) + { + vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; if (af[2] != '\0') ipv6 = true; From 743dd42b3f5d4bc5f9a86b91364c67217f42c6d1 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 30 Sep 2016 13:55:47 +0100 Subject: [PATCH 1173/1342] bgpd: Fix NHT race with Connect leading to test tool issues * The NHT change: "bgpd, zebra: Use next hop tracking for connected routes too" introduces a race where bgp_connect_check can be called on a peer in Connect state before the TCP handshake has completed. If this happens, then the SO_ERROR sockopt to check the state of the socket is undefined or at least does not return a useful result - it returns 0, as with a connected socket. SO_ERROR should only be called on non-block sockets after the socket has been ready for writing. The net result is that bgpd can then incorrectly advance the peer FSM for the socket (also the main 'peer'), to OpenSent. As part of which, any incoming connection from the peer will pass through collision_detect and may be (incorrectly) closed, depending on the RIDs. This race is reliably hit with testing tools which wait to listen for incoming BGP connections from the RUT to know it is in Connect/Active, and which ignore the TCP connection (no SYN|ACK, no RST), and then launch their own connection. The fix is to better integrate the BGP FSM and the NHT update, to ensure connect_check is not called on peers in Connect state. Note: There may be no need at all for NHT to tickle FSM. * bgpd.h: Add NHT_Update FSM event for NHT valid. * bgp_fsm.c: (bgp_fsm_nht_update) There is no need to have a separate switch based FSM with its own event via an exported function. Have NHT raise the NHT_Update even on the peer, instead of calling a side-channel function into a sub-FSM in the FSM. No need to have code for BGP_Start, FSM can call that. Actions for Connect and Active are the same and just lead to ConnectRetry_timer_expired event - so FSM can just call same transition func as that. No need to call bgp_connect_check on Connect, as Connect implies no connection. (FSM) Handle the NHT_Update event, replacing bgp_fsm_nht_update. Idle -> bgp_start, Connect and Active were doing the same as ConnectRetry_timer_expired so replicate those. Rest are No-Ops. * bgp_nht.c: (evaluate_paths) Raise NHT_Update FSM event. Always valid. * bgp_packet.{c,h}: (bgp_connect_check) NHT change now unnecessary, revert. --- bgpd/bgp_fsm.c | 48 +++++++++-------------------------------------- bgpd/bgp_fsm.h | 1 - bgpd/bgp_nht.c | 2 +- bgpd/bgp_packet.c | 15 ++++++--------- bgpd/bgp_packet.h | 1 - bgpd/bgpd.h | 3 ++- 6 files changed, 18 insertions(+), 52 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index d84a865fb..2e07d938c 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -947,45 +947,6 @@ bgp_ignore (struct peer *peer) return 0; } -void -bgp_fsm_nht_update(struct peer *peer, int valid) -{ - int ret = 0; - - if (!peer) - return; - - switch (peer->status) - { - case Idle: - if (valid) - BGP_EVENT_ADD(peer, BGP_Start); - break; - case Connect: - ret = bgp_connect_check(peer, 0); - if (!ret && valid) - { - BGP_TIMER_OFF(peer->t_connect); - BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); - } - break; - case Active: - if (valid) - { - BGP_TIMER_OFF(peer->t_connect); - BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); - } - case OpenSent: - case OpenConfirm: - case Established: - case Clearing: - case Deleted: - default: - break; - } -} - - /* Finite State Machine structure */ static const struct { int (*func) (struct peer *); @@ -1010,6 +971,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_start, Connect}, /* NHT_Update */ }, { /* Connect */ @@ -1027,6 +989,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_reconnect, Connect},/* NHT_Update */ }, { /* Active, */ @@ -1044,6 +1007,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_start, Connect}, /* NHT_Update */ }, { /* OpenSent, */ @@ -1061,6 +1025,7 @@ static const struct { {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_ignore, OpenSent}, /* NHT_Update */ }, { /* OpenConfirm, */ @@ -1078,6 +1043,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_ignore, OpenConfirm}, /* NHT_Update */ }, { /* Established, */ @@ -1095,6 +1061,7 @@ static const struct { {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_ignore, Established}, /* NHT_Update */ }, { /* Clearing, */ @@ -1112,6 +1079,7 @@ static const struct { {bgp_stop, Clearing}, /* Receive_UPDATE_message */ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_clearing_completed, Idle}, /* Clearing_Completed */ + {bgp_ignore, Clearing}, /* NHT_Update */ }, { /* Deleted, */ @@ -1129,6 +1097,7 @@ static const struct { {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Deleted}, /* Clearing_Completed */ + {bgp_ignore, Deleted}, /* NHT_Update */ }, }; @@ -1149,6 +1118,7 @@ static const char *bgp_event_str[] = "Receive_UPDATE_message", "Receive_NOTIFICATION_message", "Clearing_Completed", + "NHT_Update", }; /* Execute event process. */ diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index b38e64c92..752d6e2b9 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -72,7 +72,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA } while (0) /* Prototypes. */ -extern void bgp_fsm_nht_update(struct peer *, int valid); extern int bgp_event (struct thread *); extern int bgp_stop (struct peer *peer); extern void bgp_timer_set (struct peer *); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 591fbf98e..50f14cee8 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -528,7 +528,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) { if (BGP_DEBUG(nht, NHT)) zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host); - bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); + BGP_EVENT_ADD (peer, NHT_Update); SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2ec595f79..f42e544b4 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -103,8 +103,8 @@ bgp_packet_delete (struct peer *peer) } /* Check file descriptor whether connect is established. */ -int -bgp_connect_check (struct peer *peer, int change_state) +static void +bgp_connect_check (struct peer *peer) { int status; socklen_t slen; @@ -123,23 +123,20 @@ bgp_connect_check (struct peer *peer, int change_state) { zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); - return -1; + return; } /* When status is 0 then TCP connection is established. */ if (status == 0) { BGP_EVENT_ADD (peer, TCP_connection_open); - return 1; } else { if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect failed (%s)", peer->host, safe_strerror (errno)); - if (change_state) - BGP_EVENT_ADD (peer, TCP_connection_open_failed); - return 0; + BGP_EVENT_ADD (peer, TCP_connection_open_failed); } } @@ -718,7 +715,7 @@ bgp_write (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer, 1); + bgp_connect_check (peer); return 0; } @@ -2495,7 +2492,7 @@ bgp_read (struct thread *thread) /* For non-blocking IO check. */ if (peer->status == Connect) { - bgp_connect_check (peer, 1); + bgp_connect_check (peer); goto done; } else diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 74c62c0b3..6b0b7f4d4 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -40,7 +40,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Packet send and receive function prototypes. */ extern int bgp_read (struct thread *); extern int bgp_write (struct thread *); -extern int bgp_connect_check (struct peer *, int change_state); extern void bgp_keepalive_send (struct peer *); extern void bgp_open_send (struct peer *); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 87d2fff4c..0058b5813 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -747,7 +747,8 @@ struct bgp_nlri #define Receive_UPDATE_message 12 #define Receive_NOTIFICATION_message 13 #define Clearing_Completed 14 -#define BGP_EVENTS_MAX 15 +#define NHT_Update 15 +#define BGP_EVENTS_MAX 16 /* BGP timers default value. */ #define BGP_INIT_START_TIMER 1 From 68bfb6190e19898adc0e420b6346cf4778705e60 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Thu, 6 Oct 2016 09:59:32 -0400 Subject: [PATCH 1174/1342] bgp: ignore NHT when bgpd has never connected zebra --- bgpd/bgp_nht.c | 3 ++- bgpd/bgp_zebra.c | 11 +++++++++++ bgpd/bgp_zebra.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 50f14cee8..0cfcaddc8 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -62,7 +62,8 @@ bgp_find_nexthop (struct bgp_info *path, int connected) if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) return 0; - return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); + return (bgp_zebra_num_connects() == 0 || + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } static void diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 38fecd9f2..45d502a57 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -50,6 +50,8 @@ struct in_addr router_id_zebra; struct stream *bgp_nexthop_buf = NULL; struct stream *bgp_ifindices_buf = NULL; +int zclient_num_connects; + /* Router-id update message from zebra. */ static int bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, @@ -1171,12 +1173,15 @@ bgp_zclient_reset (void) static void bgp_zebra_connected (struct zclient *zclient) { + zclient_num_connects++; zclient_send_requests (zclient, VRF_DEFAULT); } void bgp_zebra_init (struct thread_master *master) { + zclient_num_connects = 0; + /* Set default values. */ zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_BGP); @@ -1207,3 +1212,9 @@ bgp_zebra_destroy(void) zclient_free(zclient); zclient = NULL; } + +int +bgp_zebra_num_connects(void) +{ + return zclient_num_connects; +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 9a592c33b..5d4ed6231 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -48,4 +48,6 @@ extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *); extern struct interface *if_lookup_by_ipv6 (struct in6_addr *); extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); +extern int bgp_zebra_num_connects(void); + #endif /* _QUAGGA_BGP_ZEBRA_H */ From e33545cb9d7a8c7875f18b6d44bf75d320ccedfb Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Mon, 10 Oct 2016 09:50:58 -0400 Subject: [PATCH 1175/1342] bgp: fix warning in bgp_nht.c --- bgpd/bgp_nht.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 0cfcaddc8..b5d830eeb 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -40,6 +40,7 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_zebra.h" extern struct zclient *zclient; extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; From bb04351973bd369623a0fbed3ef59e7b4fd0bd05 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Mon, 10 Oct 2016 11:56:52 -0400 Subject: [PATCH 1176/1342] bgp: restore missing check from original ignore NHT change --- bgpd/bgp_nht.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index b5d830eeb..7808505e9 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -194,7 +194,8 @@ bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, else if (peer) bnc->nht_info = (void *)peer; /* NHT peer reference */ - return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); + return (bgp_zebra_num_connects() == 0 || + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } void From 0d8b32a5ee43ccc4a67dd87ab21a4ab553e3bf44 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:00 +0200 Subject: [PATCH 1177/1342] bgpd: fix off-by-one in attribute flags handling bgp_attr_flag_invalid can access beyond the last element of attr_flags_values. Fix this by initializing attr_flags_values_max to the correct value. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- bgpd/bgp_attr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f6d5d8e7b..6aab50af4 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1003,8 +1003,7 @@ const u_int8_t attr_flags_values [] = { [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, }; -static const size_t attr_flags_values_max = - sizeof (attr_flags_values) / sizeof (attr_flags_values[0]); +static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; static int bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) From 7fca43f7184f6eb9fbe952f1eecaafcf079502f2 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:03 +0200 Subject: [PATCH 1178/1342] ospf6d: don't access nexthops out of bounds Given that the && is evaluated lazily from left to right, i < OSPF6_MULTI_PATH_LIMIT should be checked prior to calling ospf6_nexthop_is_set on the array element, not the other way around. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- ospf6d/ospf6_intra.c | 4 ++-- ospf6d/ospf6_route.c | 8 ++++---- ospf6d/ospf6_spf.c | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 3054b59b0..591dab326 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1289,8 +1289,8 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) } else { - for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && + ospf6_nexthop_is_set (&ls_entry->nexthop[i]); i++) ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); } diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 1c6495b8c..3cfbab535 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -821,8 +821,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) OSPF6_PATH_TYPE_SUBSTR (route->path.type), destination, nexthop, IFNAMSIZ, ifname, duration, VNL); - for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (i = 1; i < OSPF6_MULTI_PATH_LIMIT && + ospf6_nexthop_is_set (&route->nexthop[i]); i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, @@ -918,8 +918,8 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) /* Nexthops */ vty_out (vty, "Nexthop:%s", VNL); - for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && + ospf6_nexthop_is_set (&route->nexthop[i]); i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index ab18d3852..ebb38b6cc 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -307,8 +307,8 @@ ospf6_spf_install (struct ospf6_vertex *v, if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" another path found, merge"); - for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && + ospf6_nexthop_is_set (&v->nexthop[i]); i++) { for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++) { @@ -356,8 +356,8 @@ ospf6_spf_install (struct ospf6_vertex *v, route->path.options[1] = v->options[1]; route->path.options[2] = v->options[2]; - for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && + ospf6_nexthop_is_set (&v->nexthop[i]); i++) ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]); if (v->parent) @@ -500,8 +500,8 @@ ospf6_spf_calculation (u_int32_t router_id, ospf6_nexthop_calc (w, v, lsdesc); else { - for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && + ospf6_nexthop_is_set (&v->nexthop[i]); i++) ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); } From 8548973ace90a78035893c3663c18b485425e291 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:04 +0200 Subject: [PATCH 1179/1342] ospf6d: fix off-by-one on display of spf reasons The loop should only iterate to array_size - 1. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- ospf6d/ospf6_spf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index ebb38b6cc..b6dbd0d9f 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -403,7 +403,7 @@ void ospf6_spf_reason_string (unsigned int reason, char *buf, int size) if (!buf) return; - for (bit = 0; bit <= (sizeof(ospf6_spf_reason_str) / sizeof(char *)); bit++) + for (bit = 0; bit < array_size(ospf6_spf_reason_str); bit++) { if ((reason & (1 << bit)) && (len < size)) { From 985823ff91ed784b9affdb0104f617b2c1732dab Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:05 +0200 Subject: [PATCH 1180/1342] isisd: fix an error that was probably a result of copypasting The code should check for the existance of the correct list prior to accessing it. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_circuit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index da0b57a30..1d1a59ef8 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -975,7 +975,7 @@ isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, vty_out(vty, " %s%s", buf, VTY_NEWLINE); } } - if (circuit->ipv6_link && listcount(circuit->ipv6_non_link) > 0) + if (circuit->ipv6_non_link && listcount(circuit->ipv6_non_link) > 0) { vty_out(vty, " IPv6 Prefixes:%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip_addr)) From ef9bc88981570ef8ea744f0ab96730d192328a49 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:06 +0200 Subject: [PATCH 1181/1342] isisd: Fix size of malloc Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- isisd/isis_routemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index 3e0ab047e..3443a0a59 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -230,7 +230,7 @@ route_set_metric_compile(const char *arg) if (arg[0] == '\0' || *endp != '\0' || metric > MAX_WIDE_PATH_METRIC) return NULL; - ret = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(ret)); + ret = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*ret)); *ret = metric; return ret; From cfb1fae25f8c092e0d17073eaf7bd428ce1cd546 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 31 Aug 2016 13:31:16 +0200 Subject: [PATCH 1182/1342] zebra: stack overrun in IPv6 RA receive code (CVE-2016-1245) The IPv6 RA code also receives ICMPv6 RS and RA messages. Unfortunately, by bad coding practice, the buffer size specified on receiving such messages mixed up 2 constants that in fact have different values. The code itself has: #define RTADV_MSG_SIZE 4096 While BUFSIZ is system-dependent, in my case (x86_64 glibc): /usr/include/_G_config.h:#define _G_BUFSIZ 8192 /usr/include/libio.h:#define _IO_BUFSIZ _G_BUFSIZ /usr/include/stdio.h:# define BUFSIZ _IO_BUFSIZ FreeBSD, OpenBSD, NetBSD and Illumos are not affected, since all of them have BUFSIZ == 1024. As the latter is passed to the kernel on recvmsg(), it's possible to overwrite 4kB of stack -- with ICMPv6 packets that can be globally sent to any of the system's addresses (using fragmentation to get to 8k). (The socket has filters installed limiting this to RS and RA packets, but does not have a filter for source address or TTL.) Issue discovered by trying to test other stuff, which randomly caused the stack to be smaller than 8kB in that code location, which then causes the kernel to report EFAULT (Bad address). Signed-off-by: David Lamparter Reviewed-by: Donald Sharp --- zebra/rtadv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index d4ef1b885..2f62714d8 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -482,7 +482,7 @@ rtadv_read (struct thread *thread) /* Register myself. */ rtadv_event (zvrf, RTADV_READ, sock); - len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); + len = rtadv_recv_packet (sock, buf, sizeof (buf), &from, &ifindex, &hoplimit); if (len < 0) { From de58bdb9cdbd88baae7123856462380df365b7ff Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 18 Oct 2016 14:03:37 +0100 Subject: [PATCH 1183/1342] build: remove werror from buildtest.sh for now --- buildtest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildtest.sh b/buildtest.sh index ca0c03628..04fc2cc96 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -4,7 +4,7 @@ # builds some git commit of Quagga in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror" +basecfg="--prefix=/usr --enable-user=quagga --enable-group=quagga --enable-vty-group=quagga --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/quagga --enable-exampledir=/etc/quagga/samples --localstatedir=/var/run/quagga --libdir=/usr/lib64/quagga --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd" configs_base="gcc|$basecfg" From 258f3dad6471a680c2c583a300cfd396efe9a037 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 18 Oct 2016 14:03:52 +0100 Subject: [PATCH 1184/1342] release: Bump version to 1.1.0 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f0277628e..ce1bb7ea7 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 1.0.20160315, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.1.0, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From 5477ee7b9d8d24d2bb61335c62f3d6c5e99fc901 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 11 Jan 2017 11:18:22 +0000 Subject: [PATCH 1185/1342] Revert "opsf6d: Update router-LSA when nbr's interface-ID changes" This reverts commit e509af86e3579944b7cde942ca3ee3427db1936a. See Bug #885 --- ospf6d/ospf6_message.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 439f6a6e3..d382f038a 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -245,7 +245,6 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, char *p; int twoway = 0; int neighborchange = 0; - int neighbor_ifindex_change = 0; int backupseen = 0; hello = (struct ospf6_hello *) @@ -286,17 +285,10 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, on->priority = hello->priority; } - /* Always override neighbor's source address */ + /* always override neighbor's source address and ifindex */ + on->ifindex = ntohl (hello->interface_id); memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); - /* Neighbor ifindex check */ - if (on->ifindex > 0 - && (unsigned int) on->ifindex != ntohl (hello->interface_id)) - { - on->ifindex = ntohl (hello->interface_id); - neighbor_ifindex_change++; - } - /* TwoWay check */ for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); @@ -356,9 +348,6 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, thread_add_event (master, backup_seen, oi, 0); if (neighborchange) thread_add_event (master, neighbor_change, oi, 0); - - if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL) - OSPF6_ROUTER_LSA_SCHEDULE (oi->area); } static void From b7ceefea77a246fe5c1dcd1b91bf6079d1b97c02 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 10 Jan 2017 23:33:50 +0000 Subject: [PATCH 1186/1342] lib: limit size of vty buffer to 4096 bytes This removes the automatic resizing of the vty input buffer and places a hard size cap of 4096 bytes. It also fixes a potentially unsafe strcpy. [Edits by Paul Jakma, paul@jakma.org] --- lib/command.c | 2 +- lib/vty.c | 58 ++++++++++++++++++++++++++++----------------------- lib/vty.h | 1 - vtysh/vtysh.c | 2 +- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/lib/command.c b/lib/command.c index ab46fc4a6..242c98b4c 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2901,7 +2901,7 @@ config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num) int ret; *line_num = 0; - while (fgets (vty->buf, VTY_BUFSIZ, fp)) + while (fgets (vty->buf, vty->max, fp)) { ++(*line_num); diff --git a/lib/vty.c b/lib/vty.c index 7ba277fd8..6d6479774 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -40,6 +40,8 @@ #include #include +#define VTY_BUFSIZ 4096 + /* Vty events */ enum event { @@ -507,17 +509,6 @@ vty_write (struct vty *vty, const char *buf, size_t nbytes) buffer_put (vty->obuf, buf, nbytes); } -/* Ensure length of input buffer. Is buffer is short, double it. */ -static void -vty_ensure (struct vty *vty, int length) -{ - if (vty->max <= length) - { - vty->max *= 2; - vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max); - } -} - /* Basic function to insert character into vty. */ static void vty_self_insert (struct vty *vty, char c) @@ -525,7 +516,9 @@ vty_self_insert (struct vty *vty, char c) int i; int length; - vty_ensure (vty, vty->length + 1); + if (vty->length + 1 > VTY_BUFSIZ) + return; + length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); vty->buf[vty->cp] = c; @@ -542,26 +535,29 @@ vty_self_insert (struct vty *vty, char c) static void vty_self_insert_overwrite (struct vty *vty, char c) { - vty_ensure (vty, vty->length + 1); - vty->buf[vty->cp++] = c; - - if (vty->cp > vty->length) - vty->length++; - - if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) - return; + if (vty->cp == vty->length) + { + vty_self_insert (vty, c); + return; + } + vty->buf[vty->cp++] = c; vty_write (vty, &c, 1); } -/* Insert a word into vty interface with overwrite mode. */ +/** + * Insert a string into vty->buf at the current cursor position. + * + * If the resultant string would be larger than VTY_BUFSIZ it is + * truncated to fit. + */ static void vty_insert_word_overwrite (struct vty *vty, char *str) { - int len = strlen (str); - vty_write (vty, str, len); - strcpy (&vty->buf[vty->cp], str); - vty->cp += len; + size_t nwrite = MIN ((int) strlen (str), VTY_BUFSIZ - vty->cp); + vty_write (vty, str, nwrite); + strncpy (&vty->buf[vty->cp], str, nwrite); + vty->cp += nwrite; vty->length = vty->cp; } @@ -2198,12 +2194,21 @@ vtysh_read (struct thread *thread) printf ("line: %.*s\n", nbytes, buf); #endif /* VTYSH_DEBUG */ + if (vty->length + nbytes > VTY_BUFSIZ) + { + /* Clear command line buffer. */ + vty->cp = vty->length = 0; + vty_clear_buf (vty); + vty_out (vty, "%% Command is too long.%s", VTY_NEWLINE); + goto out; + } + for (p = buf; p < buf+nbytes; p++) { - vty_ensure(vty, vty->length+1); vty->buf[vty->length++] = *p; if (*p == '\0') { + /* Pass this line to parser. */ ret = vty_execute (vty); /* Note that vty_execute clears the command buffer and resets @@ -2224,6 +2229,7 @@ vtysh_read (struct thread *thread) } } +out: vty_event (VTYSH_READ, sock, vty); return 0; diff --git a/lib/vty.h b/lib/vty.h index 806f2c603..1e3b12439 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -25,7 +25,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "sockunion.h" -#define VTY_BUFSIZ 512 #define VTY_MAXHIST 20 /* VTY struct. */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2e2203da6..7068ea3ab 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -443,7 +443,7 @@ vtysh_config_from_file (struct vty *vty, FILE *fp) int ret; struct cmd_element *cmd; - while (fgets (vty->buf, VTY_BUFSIZ, fp)) + while (fgets (vty->buf, vty->max, fp)) { ret = command_config_read_one_line (vty, &cmd, 1); From 7d66284a5817a1613b1e4d64a0775ec04fdf8c01 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 19 Jan 2017 10:39:23 +0000 Subject: [PATCH 1187/1342] lib: ensure vty buf is nul terminated and wrap puts to it with checks * vty.c: Fix str* overruns in previous commit, which I reported to the author. Add bit more checking of updates to vty buffer. Swap VTY_BUFSIZ over to vty->max, as that should be the external API. * vty.c: (vty_buf_assert) conditions that should always be assertable for vty buffer. (vty_buf_put) little wrapper to check char puts to vty input buffer, and unconditionally write nul at very end of buffer as guard. Won't always work, as some places use mem* to manipulate. (vty_self_insert{,_overwrite}) Length check needs to leave room for nul. Use vty_buf_put. (vty_insert_word_overwrite) Length check needs to leave room for nul. (*) Add vty_buf_assert calls. Merging in fixes from Quentin Young --- lib/vty.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 6d6479774..afaf2b06e 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -94,6 +94,23 @@ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; static int do_log_commands = 0; +static void +vty_buf_assert (struct vty *vty) +{ + assert (vty->cp <= vty->length); + assert (vty->length < vty->max); + assert (vty->buf[vty->length] == '\0'); +} + +/* Sanity/safety wrappers around access to vty->buf */ +static void +vty_buf_put (struct vty *vty, char c) +{ + vty_buf_assert (vty); + vty->buf[vty->cp] = c; + vty->buf[vty->max - 1] = '\0'; +} + /* VTY standard output function. */ int vty_out (struct vty *vty, const char *format, ...) @@ -515,33 +532,46 @@ vty_self_insert (struct vty *vty, char c) { int i; int length; - - if (vty->length + 1 > VTY_BUFSIZ) + + vty_buf_assert (vty); + + /* length is sans nul, max is with */ + if (vty->length + 1 >= vty->max) return; length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); - vty->buf[vty->cp] = c; + vty->length++; + vty->buf[vty->length] = '\0'; + + vty_buf_put (vty, c); vty_write (vty, &vty->buf[vty->cp], length + 1); for (i = 0; i < length; i++) vty_write (vty, &telnet_backward_char, 1); vty->cp++; - vty->length++; + + vty_buf_assert (vty); } /* Self insert character 'c' in overwrite mode. */ static void vty_self_insert_overwrite (struct vty *vty, char c) { + vty_buf_assert (vty); + if (vty->cp == vty->length) { vty_self_insert (vty, c); return; } - vty->buf[vty->cp++] = c; + vty_buf_put (vty, c); + vty->cp++; + + vty_buf_assert (vty); + vty_write (vty, &c, 1); } @@ -554,33 +584,46 @@ vty_self_insert_overwrite (struct vty *vty, char c) static void vty_insert_word_overwrite (struct vty *vty, char *str) { - size_t nwrite = MIN ((int) strlen (str), VTY_BUFSIZ - vty->cp); - vty_write (vty, str, nwrite); - strncpy (&vty->buf[vty->cp], str, nwrite); + vty_buf_assert (vty); + + size_t nwrite = MIN ((int) strlen (str), vty->max - vty->cp - 1); + memcpy (&vty->buf[vty->cp], str, nwrite); vty->cp += nwrite; vty->length = vty->cp; + vty->buf[vty->length] = '\0'; + vty_buf_assert (vty); + + vty_write (vty, str, nwrite); } /* Forward character. */ static void vty_forward_char (struct vty *vty) { + vty_buf_assert (vty); + if (vty->cp < vty->length) { vty_write (vty, &vty->buf[vty->cp], 1); vty->cp++; } + + vty_buf_assert (vty); } /* Backward character. */ static void vty_backward_char (struct vty *vty) { + vty_buf_assert (vty); + if (vty->cp > 0) { vty->cp--; vty_write (vty, &telnet_backward_char, 1); } + + vty_buf_assert (vty); } /* Move to the beginning of the line. */ @@ -615,7 +658,9 @@ vty_history_print (struct vty *vty) length = strlen (vty->hist[vty->hp]); memcpy (vty->buf, vty->hist[vty->hp], length); vty->cp = vty->length = length; - + vty->buf[vty->length] = '\0'; + vty_buf_assert (vty); + /* Redraw current line */ vty_redraw_line (vty); } @@ -671,6 +716,8 @@ vty_redraw_line (struct vty *vty) { vty_write (vty, vty->buf, vty->length); vty->cp = vty->length; + + vty_buf_assert (vty); } /* Forward word. */ @@ -775,10 +822,12 @@ vty_delete_char (struct vty *vty) vty_down_level (vty); return; } - + if (vty->cp == vty->length) return; /* completion need here? */ + vty_buf_assert (vty); + size = vty->length - vty->cp; vty->length--; @@ -825,6 +874,7 @@ vty_kill_line (struct vty *vty) memset (&vty->buf[vty->cp], 0, size); vty->length = vty->cp; + vty_buf_assert (vty); } /* Kill line from the beginning. */ @@ -2194,7 +2244,7 @@ vtysh_read (struct thread *thread) printf ("line: %.*s\n", nbytes, buf); #endif /* VTYSH_DEBUG */ - if (vty->length + nbytes > VTY_BUFSIZ) + if (vty->length + nbytes >= vty->max) { /* Clear command line buffer. */ vty->cp = vty->length = 0; From 99e00a19bb8afcf081d1551b886c6d85188e6c60 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 23 Jan 2017 14:47:32 +0000 Subject: [PATCH 1188/1342] lib: Bump library version-info --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index be8495f14..cb9e1fb57 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -5,7 +5,7 @@ AM_CFLAGS = $(WERROR) DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la -libzebra_la_LDFLAGS = -version-info 0:0:0 +libzebra_la_LDFLAGS = -version-info 1:0:0 libzebra_la_SOURCES = \ network.c pid_output.c getopt.c getopt1.c daemon.c \ From a64c66b105929b0f0fc19743f34dc29c760df967 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 6 Jan 2017 16:30:03 +0700 Subject: [PATCH 1189/1342] zebra: fix build on OpenBSD >= 5.9 RTF_XRESOLVE was removed from the OpenBSD tree recently. --- zebra/kernel_socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5e68c5675..64c6cbbf2 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -242,7 +242,9 @@ static const struct message rtm_flag_str[] = #ifdef RTF_CLONING {RTF_CLONING, "CLONING"}, #endif /* RTF_CLONING */ +#ifdef RTF_XRESOLVE {RTF_XRESOLVE, "XRESOLVE"}, +#endif /* RTF_XRESOLVE */ #ifdef RTF_LLINFO {RTF_LLINFO, "LLINFO"}, #endif /* RTF_LLINFO */ From 71e0ba780bd7ba1a6fdc71ff673e3ef5aee61e08 Mon Sep 17 00:00:00 2001 From: Nick Hilliard Date: Tue, 27 Dec 2016 22:51:51 +0000 Subject: [PATCH 1190/1342] vtysh: make warnings about node installs a non-default compile-time option * lib/command.c: (install_element) Suppress duplicate command install warnings for vtysh --- lib/command.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/command.c b/lib/command.c index 242c98b4c..bb94c2889 100644 --- a/lib/command.c +++ b/lib/command.c @@ -638,9 +638,11 @@ install_element (enum node_type ntype, struct cmd_element *cmd) if (hash_lookup (cnode->cmd_hash, cmd) != NULL) { +#ifdef DEV_BUILD fprintf (stderr, "Multiple command installs to node %d of command:\n%s\n", ntype, cmd->string); +#endif return; } From f5a4488a0dda521f19e96f2615f4a8b134c5878b Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Mon, 1 Aug 2016 18:14:38 -0500 Subject: [PATCH 1191/1342] vtysh: Fix, guard against NULL pointer dereference getpwuid() may fail returning a null value leaving subsequent code vulnerable to a null pointer dereference. Tested-by: NetDEF CI System --- vtysh/vtysh_user.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 248b18120..584b61f51 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -176,7 +176,11 @@ vtysh_auth (void) struct vtysh_user *user; struct passwd *passwd; - passwd = getpwuid (geteuid ()); + if ((passwd = getpwuid (geteuid ())) == NULL) + { + fprintf (stderr, "could not lookup user ID %d\n", (int) geteuid()); + exit (1); + } user = user_lookup (passwd->pw_name); if (user && user->nopassword) From 126b0e7c2915fb7ec3e5f72e625433a83568c7d6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 18 Nov 2016 14:40:41 +0000 Subject: [PATCH 1192/1342] vty: Add ctrl-v to allow, e.g., '?' to be input for regex * Support the standard ctrl-v control sequence. Otherwise there is no way to do this from the venerable telnet vty. vtysh supports this (configurably) via readline. * lib/vty.c: (VTY_ESC_LITERAL) New mode, for ctrl-v. (vty_read) Additional mode to go ctrl-v -> VTY_ESC_LITERAL, and always insert next char. Acked-by: Vincent.Jardin@6wind.com --- doc/basic.texi | 9 +++++++++ lib/vty.c | 17 ++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/doc/basic.texi b/doc/basic.texi index 4485665af..92e8d9ebd 100644 --- a/doc/basic.texi +++ b/doc/basic.texi @@ -552,6 +552,12 @@ Kill line from the beginning, erasing input. @kindex C-t Transpose character. +@item C-v +@kindex C-v +Interpret following character literally. Do not treat it specially. +This can be used to, e.g., type in a literal @kbd{?} rather than do +help completion. + @end table @node CLI Advanced Commands @@ -593,4 +599,7 @@ You can use command line help by typing @code{help} at the beginning of the line. Typing @kbd{?} at any point in the line will show possible completions. +To enter an actual @kbd{?} character rather show completions, e.g. to +enter into a regexp, use @kbd{@key{C}-v ?}. + @end table diff --git a/lib/vty.c b/lib/vty.c index afaf2b06e..7ca835436 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -1386,8 +1386,9 @@ vty_execute (struct vty *vty) #define CONTROL(X) ((X) - '@') #define VTY_NORMAL 0 -#define VTY_PRE_ESCAPE 1 -#define VTY_ESCAPE 2 +#define VTY_PRE_ESCAPE 1 /* Esc seen */ +#define VTY_ESCAPE 2 /* ANSI terminal escape (Esc-[) seen */ +#define VTY_LITERAL 3 /* Next char taken as literal */ /* Escape character command map. */ static void @@ -1515,7 +1516,14 @@ vty_read (struct thread *thread) vty_escape_map (buf[i], vty); continue; } - + + if (vty->escape == VTY_LITERAL) + { + vty_self_insert (vty, buf[i]); + vty->escape = VTY_NORMAL; + continue; + } + /* Pre-escape status. */ if (vty->escape == VTY_PRE_ESCAPE) { @@ -1587,6 +1595,9 @@ vty_read (struct thread *thread) case CONTROL('U'): vty_kill_line_from_beginning (vty); break; + case CONTROL('V'): + vty->escape = VTY_LITERAL; + break; case CONTROL('W'): vty_backward_kill_word (vty); break; From e992eb98d1ec8da84c7d0dffb1388bfbe935f16b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 5 Jan 2017 12:46:17 +0000 Subject: [PATCH 1193/1342] HACKING: set a4paper by default --- HACKING.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/HACKING.md b/HACKING.md index 3bd1eb37b..c898d96cb 100644 --- a/HACKING.md +++ b/HACKING.md @@ -1,13 +1,11 @@ --- title: Conventions for working on Quagga papersize: a4paper -geometry: scale=0.82 +geometry: a4paper,scale=0.82 fontsize: 11pt toc: true date: \today include-before: - \large This is a living document. - \large This is a living document describing the processes and guidelines for working on Quagga. You *must* read Section ["REQUIRED READING"](#sec:required), before contributing to Quagga. From a66b46208f10f4453dd63cec8a99a2218c7b4764 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 9 Jan 2017 13:06:56 +0000 Subject: [PATCH 1194/1342] HACKING: Add 'Objectives', 'Governance', and an initial 'Code of Conduct' --- HACKING.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/HACKING.md b/HACKING.md index c898d96cb..0b96ce813 100644 --- a/HACKING.md +++ b/HACKING.md @@ -17,6 +17,116 @@ include-before: \newpage +OBJECTIVES {#sec:goals} +========== + +The objectives of the Quagga project are to develop and implement high +quality routing protocols and related software, maximising: + +* Free software: + * Quagga is and will remain a copyleft, free software project + * Some non-core parts may be available under compatible, permissive + licenses to facilitate code sharing, where contributors agree. + * The test and integration orchestration infrastructure shall be free + software, developed similarly to the rest of Quagga. Proprietary + conformance suites may be among the test tools orchestrated. +* Openness and transparency + * The business of the project shall be conducted on its public email + lists, to the greatest extent possible. + * The design of the software will be governed by open discussion on + the public email lists. + * Participants shall endeavour to be transparent about their interests + in the project, and any associations likely to be relevant. +* Ethical behaviour: + * The licenses of all copyright holders will be respected, and the + project will err in their favour where there is reasonable doubt or + legal advice to that effect. + * Participants will behave with respect for others, and in a manner that + builds and maintains the trust needed for productive collaboration. + +See also the Section on [CODE OF CONDUCT](#sec:codeconduct). + +Governance {#sec:governance} +========== + +The governance of Quagga is currently in flux. + +Quagga was forked from GNU Zebra by Paul Jakma, who holds the domain name. +Governance was soon devolved to a collective group, the maintainers. + +Governance at this moment is again fully in the hands of Paul Jakma, to be +recast. + +Holding of project assets +------------------------- + +One or more mature, independent trustees, with technical and free software +experience, will be appointed as the executor(s) for key assets of the +project to ensure continuity, such as the domain name. + +Should a corporate vehicle ever be created to hold such assets it __must__: + +* Publish up to date accounts on a regular business. +* Generally operate openly and transparently. +* Have control distributed, with a significant degree of control held + independent of any contributors with business interests in the software. +* Carry out no other business itself that may be seen to conflict or compete + with the business of others in the community. +* Have all officers disclose all interests that could be + seen to have a bearing on the project, as far as is reasonable. + +It not clear at this time that the overheads and potential liabilities of +such a vehicle would be appropriate for this project. These principles +should though still be applied, where possible, to any non-corporate body +formed around the project. + +CODE OF CONDUCT {#sec:codeconduct} +=============== + +Participants will treat each other with respect and integrity. Participants +will build and treasure the trust that is required for parties to +successfully collaborate together on free software. Particularly when those +parties may have competing interests. The following principles and +guidelines should be followed to foster that trust: + +* Participants should be open about their goals, and their interests. + - Business associations with other participants should be disclosed, + so far as is reasonable and where applicable. E.g., if there is voting + on matters, or in endorsements or objections to contributions. + - Other associations and interests that may be relevant should be + disclosed, to the degree necessary to avoid any perception + by others of conflicts of interests or of deception. + - Be open about your goals, so as to maximise the common understanding + and minimise any misunderstandings and disputes. +* Design should be done in the open + - Do your design on list, ahead of significant implementation. Avoid + "Surprise!" development where possible. + - Where significant implementation work must be done behind closed + doors, accept that you may be asked to rework it, potentially from + scratch once you take it public. + - Get "buy in" from others ahead of time, to avoid disappointment. +* Interaction + - Feedback on design should be constructive, thoughtful and + understanding. + - Avoid personalising matters. Discuss the idea, the code, the abstract + subject and avoid unnecessary personal pronouns. + - Avoid language that paints either party into a corner. Leave some room + for doubt. Ask questions, rather than make assertions, where possible. +* Disputes should be resolved through calm, analytic discussion + - Separate out as much of the matter under dispute into principles that + can be agreed on, and into the objective domain (by measurement or + logic). + - Seek ways to resolve any remaining subjective differences by alternate + paths that can accommodate both sides, e.g., through abstraction or + modularisation. + - Aim for Win-Win. +* Respect others + - Avoid passive-aggressive behaviours. E.g., tit-for-tat + non-constructive behaviour. Be explicit. + - It is acceptable for management to allocate resources on development + according to their need. It is not acceptable to try use external, + management intervention to over-turn positions held by participants. + REQUIRED READING {#sec:required} ================ From f0705d523420ece274410c3df9f4b8fb043094c0 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 11 Jan 2017 10:02:32 +0000 Subject: [PATCH 1195/1342] HACKING: Update useful URLs --- HACKING.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/HACKING.md b/HACKING.md index 0b96ce813..e7e4cd7e2 100644 --- a/HACKING.md +++ b/HACKING.md @@ -683,6 +683,14 @@ configuration for the appropriate Quagga.net repository. USEFUL URLs =========== -* David Lamparter runs a patchwork instance at +* The project homepage is at: + + + +* Patchwork tracks patches emailed to the quagga-dev list at: + +* Bugs can be reported via Bugzilla at: + + From 3b0e3008e41c967e459f87b6ca8658ef26f49bc9 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 23 Jan 2017 15:14:08 +0000 Subject: [PATCH 1196/1342] configure: Bump version to 1.1.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ce1bb7ea7..2f7796964 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 1.1.0, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.1.1, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From 631fcd2e51b02b3d5548bee4108044921fb3e58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 19 Oct 2016 16:02:31 +0300 Subject: [PATCH 1197/1342] zebra: use FIB state for nexthop tracking The FIB override routes can override ZEBRA_FLAG_SELECTED routes in FIB. Use the FIB state instead to report correct nexthop when FIB override routes are present. --- zebra/zebra_rnh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 7b6d0f82b..97d359783 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -223,7 +223,7 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { From b41bb62e039454f53e54959b2c3f7eea816e6422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 19 Oct 2016 16:02:32 +0300 Subject: [PATCH 1198/1342] zebra: fix nht validity checking to be same as when it's resolved This reverts commit 7e3a435bd99 "A valid BGP nexthop is flagged as invalid" Problem is BGP thinks the nexthop is accessible when it's recursive, and selects it, but zebra rejects it at route install time. Causing FIB and BGP state to be out-of-sync. Fix nht to follow same rules as zebra rib. --- zebra/zebra_rnh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 97d359783..5762d3f2c 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -498,8 +498,8 @@ send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if ((CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) || - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) && + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) && + ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); From c9cc52af9edf0f23a1434c944812064de220a7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 19 Oct 2016 16:02:33 +0300 Subject: [PATCH 1199/1342] bgpd: honor disable-connected-check option with next hop tracking Make bgpd ignore connected state again if configured to do so. --- bgpd/bgp_fsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 2e07d938c..7da63eaab 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -716,7 +716,8 @@ bgp_start (struct peer *peer) } /* Register to be notified on peer up */ - if ((peer->ttl == 1) || (peer->gtsm_hops == 1)) + if ((peer->ttl == 1 || peer->gtsm_hops == 1) && + ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; bgp_find_or_add_nexthop(family2afi(peer->su.sa.sa_family), NULL, peer, From e3443a21552b6a3cd6ebdbb98336eede217a478f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 19 Oct 2016 16:02:34 +0300 Subject: [PATCH 1200/1342] bgpd: simplify ebgp-multihop and ttl-security handling Change to track configured value in ->ttl and ->gtsm_hops; not the value set to sockopt. Instead, setting of socket's ttl and minttl options are now merged to one function which calculates it on demand. This greatly simplifies the code. --- bgpd/bgp_fsm.c | 2 +- bgpd/bgp_network.c | 58 +++++------ bgpd/bgp_network.h | 1 + bgpd/bgp_route.c | 4 +- bgpd/bgp_vty.c | 26 ++--- bgpd/bgp_zebra.c | 13 ++- bgpd/bgpd.c | 237 +++++++++------------------------------------ bgpd/bgpd.h | 7 +- 8 files changed, 95 insertions(+), 253 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 7da63eaab..67c50c475 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -716,7 +716,7 @@ bgp_start (struct peer *peer) } /* Register to be notified on peer up */ - if ((peer->ttl == 1 || peer->gtsm_hops == 1) && + if ((peer_ttl(peer) == 1 || peer->gtsm_hops == 1) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 51a6f6022..c7d338903 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -146,47 +146,39 @@ bgp_update_sock_send_buffer_size (int fd) } } -static void +void bgp_set_socket_ttl (struct peer *peer, int bgp_sock) { char buf[INET_ADDRSTRLEN]; - int ret; + int ret, ttl, minttl; - /* In case of peer is EBGP, we should set TTL for this connection. */ - if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP)) + if (bgp_sock < 0) + return; + + if (peer->gtsm_hops) { - ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl); - if (ret) - { - zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", - __func__, - inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), - errno); - } + ttl = 255; + minttl = 256 - peer->gtsm_hops; } - else if (peer->gtsm_hops) + else { - /* On Linux, setting minttl without setting ttl seems to mess with the - outgoing ttl. Therefore setting both. - */ - ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, MAXTTL); - if (ret) - { - zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", - __func__, - inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), - errno); - } - ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock, - MAXTTL + 1 - peer->gtsm_hops); - if (ret) - { - zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", - __func__, - inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), - errno); - } + ttl = peer_ttl (peer); + minttl = 0; } + + ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, ttl); + if (ret) + zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", + __func__, + inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), + errno); + + ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock, minttl); + if (ret && (errno != ENOTSUP || minttl)) + zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", + __func__, + inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), + errno); } /* Accept bgp connection. */ diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 127684306..31995caf4 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -28,6 +28,7 @@ extern void bgp_close (void); extern int bgp_connect (struct peer *); extern void bgp_getsockname (struct peer *); +extern void bgp_set_socket_ttl (struct peer *peer, int bgp_sock); extern int bgp_md5_set (struct peer *); #endif /* _QUAGGA_BGP_NETWORK_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4cb6c141b..010fd4d2f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2339,7 +2339,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && + if (peer->sort == BGP_PEER_EBGP && peer_ttl (peer) == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; else @@ -2391,7 +2391,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && + if (peer->sort == BGP_PEER_EBGP && peer_ttl (peer) == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; else diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 7af4e81a8..8eeaff922 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3058,7 +3058,7 @@ peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str) if (! peer) return CMD_WARNING; - return bgp_vty_return (vty, peer_ebgp_multihop_unset (peer)); + return bgp_vty_return (vty, peer_ebgp_multihop_set (peer, 0)); } /* neighbor ebgp-multihop. */ @@ -4380,7 +4380,7 @@ DEFUN (no_neighbor_ttl_security, if (! peer) return CMD_WARNING; - return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer)); + return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, 0)); } /* Address family configuration. */ @@ -8364,6 +8364,7 @@ bgp_show_peer (struct vty *vty, struct peer *p) char timebuf[BGP_UPTIME_LEN]; afi_t afi; safi_t safi; + int ttl; bgp = p->bgp; @@ -8663,21 +8664,12 @@ bgp_show_peer (struct vty *vty, struct peer *p) } /* EBGP Multihop and GTSM */ - if (p->sort != BGP_PEER_IBGP) - { - if (p->gtsm_hops > 0) - vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", - p->gtsm_hops, VTY_NEWLINE); - else if (p->ttl > 1) - vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", - p->ttl, VTY_NEWLINE); - } - else - { - if (p->gtsm_hops > 0) - vty_out (vty, " Internal BGP neighbor may be up to %d hops away.%s", - p->gtsm_hops, VTY_NEWLINE); - } + ttl = p->gtsm_hops; + if (! ttl) + ttl = peer_ttl (p); + vty_out (vty, " %s BGP neighbor may be up to %d hops away.%s", + p->sort == BGP_PEER_IBGP ? "Internal" : "External", + ttl, VTY_NEWLINE); /* Local address. */ if (p->su_local) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 45d502a57..ba87ad1c8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -172,11 +172,10 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length, for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) - continue; - - if (ifp == peer->nexthop.ifp) - BGP_EVENT_ADD (peer, BGP_Stop); + if (peer->gtsm_hops != 1 && peer_ttl (peer) != 1) + continue; + if (ifp == peer->nexthop.ifp) + BGP_EVENT_ADD (peer, BGP_Stop); } } } @@ -716,7 +715,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); } - if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) + if ((peer->sort == BGP_PEER_EBGP && peer_ttl (peer) != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); @@ -991,7 +990,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) SET_FLAG (flags, ZEBRA_FLAG_IBGP); } - if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) + if ((peer->sort == BGP_PEER_EBGP && peer_ttl (peer) != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 018a59941..56e4322b9 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -646,7 +646,8 @@ peer_global_config_reset (struct peer *peer) { peer->weight = 0; peer->change_local_as = 0; - peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); + peer->ttl = 0; + peer->gtsm_hops = 0; if (peer->update_source) { sockunion_free (peer->update_source); @@ -925,9 +926,6 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as, /* Last read and reset time set */ peer->readtime = peer->resettime = bgp_clock (); - /* Default TTL set. */ - peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1; - /* Make peer's address string. */ sockunion2str (su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); @@ -957,7 +955,6 @@ peer_create_accept (struct bgp *bgp) static void peer_as_change (struct peer *peer, as_t as) { - bgp_peer_sort_t type; struct peer *conf; /* Stop peer. */ @@ -972,7 +969,6 @@ peer_as_change (struct peer *peer, as_t as) else BGP_EVENT_ADD (peer, BGP_Stop); } - type = peer_sort (peer); peer->as = as; if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION) @@ -995,12 +991,6 @@ peer_as_change (struct peer *peer, as_t as) else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; - /* TTL reset */ - if (peer_sort (peer) == BGP_PEER_IBGP) - peer->ttl = 255; - else if (type == BGP_PEER_IBGP) - peer->ttl = 1; - /* reflector-client reset */ if (peer_sort (peer) != BGP_PEER_IBGP) { @@ -1506,7 +1496,7 @@ peer_group_get (struct bgp *bgp, const char *name) group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; - group->conf->ttl = 1; + group->conf->ttl = 0; group->conf->gtsm_hops = 0; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER); @@ -1806,6 +1796,16 @@ peer_group_remote_as (struct bgp *bgp, const char *group_name, as_t *as) return 0; } +int +peer_ttl (struct peer *peer) +{ + if (peer->ttl) + return peer->ttl; + if (peer->gtsm_hops || peer->sort == BGP_PEER_IBGP) + return 255; + return 1; +} + int peer_group_delete (struct peer_group *group) { @@ -1938,10 +1938,6 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; } - /* ebgp-multihop reset */ - if (peer_sort (group->conf) == BGP_PEER_IBGP) - group->conf->ttl = 255; - /* local-as reset */ if (peer_sort (group->conf) != BGP_PEER_EBGP) { @@ -2870,29 +2866,17 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) struct peer *peer1; if (peer->sort == BGP_PEER_IBGP) - return 0; + return BGP_ERR_NO_IBGP_WITH_TTLHACK; - /* see comment in peer_ttl_security_hops_set() */ - if (ttl != MAXTTL) - { - if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - group = peer->group; - if (group->conf->gtsm_hops != 0) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) - { - if (peer1->sort == BGP_PEER_IBGP) - continue; + if (peer->gtsm_hops != 0) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - if (peer1->gtsm_hops != 0) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - } - } - else + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { - if (peer->gtsm_hops != 0) + if (peer1->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } @@ -2901,62 +2885,18 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) - sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + bgp_set_socket_ttl (peer, peer->fd); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) - { - if (peer->sort == BGP_PEER_IBGP) - continue; - - peer->ttl = group->conf->ttl; - - if (peer->fd >= 0) - sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); - } - } - return 0; -} - -int -peer_ebgp_multihop_unset (struct peer *peer) -{ - struct peer_group *group; - struct listnode *node, *nnode; - - if (peer->sort == BGP_PEER_IBGP) - return 0; - - if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - - if (peer_group_active (peer)) - peer->ttl = peer->group->conf->ttl; - else - peer->ttl = 1; - - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) - sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + { + peer->ttl = ttl; + bgp_set_socket_ttl (peer, peer->fd); + } } - else - { - group = peer->group; - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) - { - if (peer->sort == BGP_PEER_IBGP) - continue; - peer->ttl = 1; - - if (peer->fd >= 0) - sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); - } - } return 0; } @@ -4652,78 +4592,41 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) return 0; } -static int is_ebgp_multihop_configured (struct peer *peer) -{ - struct peer_group *group; - struct listnode *node, *nnode; - struct peer *peer1; - - if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - group = peer->group; - if ((peer_sort(peer) != BGP_PEER_IBGP) && - (group->conf->ttl != 1)) - return 1; - - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) - { - if ((peer_sort (peer1) != BGP_PEER_IBGP) && - (peer1->ttl != 1)) - return 1; - } - } - else - { - if ((peer_sort(peer) != BGP_PEER_IBGP) && - (peer->ttl != 1)) - return 1; - } - return 0; -} - /* Set # of hops between us and BGP peer. */ int peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) { struct peer_group *group; struct listnode *node, *nnode; - int ret; + struct peer *peer1; zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); - /* We cannot configure ttl-security hops when ebgp-multihop is already - set. For non peer-groups, the check is simple. For peer-groups, it's - slightly messy, because we need to check both the peer-group structure - and all peer-group members for any trace of ebgp-multihop configuration - before actually applying the ttl-security rules. Cisco really made a - mess of this configuration parameter, and OpenBGPD got it right. - */ - - if (peer->gtsm_hops == 0) - { - if (is_ebgp_multihop_configured (peer)) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + if (peer->ttl != 0) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - /* specify MAXTTL on outgoing packets */ - /* Routine handles iBGP peers correctly */ - ret = peer_ebgp_multihop_set (peer, MAXTTL); - if (ret != 0) - return ret; + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) + { + if (peer1->ttl != 0) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + } } - + peer->gtsm_hops = gtsm_hops; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0) - sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); + bgp_set_socket_ttl (peer, peer->fd); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - peer->gtsm_hops = group->conf->gtsm_hops; + peer->gtsm_hops = gtsm_hops; /* Change setting of existing peer * established then change value (may break connectivity) @@ -4732,9 +4635,7 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) */ if (peer->status == Established) { - if (peer->fd >= 0 && peer->gtsm_hops != 0) - sockopt_minttl (peer->su.sa.sa_family, peer->fd, - MAXTTL + 1 - peer->gtsm_hops); + bgp_set_socket_ttl (peer, peer->fd); } else if (peer->status < Established) { @@ -4748,42 +4649,6 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) return 0; } -int -peer_ttl_security_hops_unset (struct peer *peer) -{ - struct peer_group *group; - struct listnode *node, *nnode; - struct peer *opeer; - - zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); - - /* if a peer-group member, then reset to peer-group default rather than 0 */ - if (peer_group_active (peer)) - peer->gtsm_hops = peer->group->conf->gtsm_hops; - else - peer->gtsm_hops = 0; - - opeer = peer; - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - if (peer->fd >= 0) - sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); - } - else - { - group = peer->group; - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) - { - peer->gtsm_hops = 0; - - if (peer->fd >= 0) - sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); - } - } - - return peer_ebgp_multihop_unset (opeer); -} - int peer_clear (struct peer *peer) { @@ -5094,19 +4959,13 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE)) vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); - /* EBGP multihop. */ - if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 && - !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) - if (! peer_group_active (peer) || - g_peer->ttl != peer->ttl) - vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, - VTY_NEWLINE); - - /* ttl-security hops */ - if (peer->gtsm_hops != 0) - if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) - vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, - peer->gtsm_hops, VTY_NEWLINE); + /* TTL option */ + if (peer->gtsm_hops && ! peer_group_active (peer)) + vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, + peer->gtsm_hops, VTY_NEWLINE); + else if (peer->ttl && ! peer_group_active (peer)) + vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, + VTY_NEWLINE); /* disable-connected-check. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0058b5813..a4c608dec 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -832,8 +832,8 @@ enum bgp_clear_type #define BGP_ERR_TCPSIG_FAILED -29 #define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30 #define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 -#define BGP_ERR_MAX -32 -#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -33 +#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -32 +#define BGP_ERR_MAX -33 extern struct bgp_master *bm; @@ -913,6 +913,7 @@ extern int peer_rsclient_active (struct peer *); extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); extern int peer_group_remote_as (struct bgp *, const char *, as_t *); +extern int peer_ttl (struct peer *peer); extern int peer_delete (struct peer *peer); extern int peer_group_delete (struct peer_group *); extern int peer_group_remote_as_delete (struct peer_group *); @@ -934,7 +935,6 @@ extern int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_ebgp_multihop_set (struct peer *, int); -extern int peer_ebgp_multihop_unset (struct peer *); extern int peer_description_set (struct peer *, const char *); extern int peer_description_unset (struct peer *); @@ -996,7 +996,6 @@ extern int peer_clear (struct peer *); extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); extern int peer_ttl_security_hops_set (struct peer *, int); -extern int peer_ttl_security_hops_unset (struct peer *); extern void bgp_scan_finish (void); #endif /* _QUAGGA_BGPD_H */ From a8f9790a9bae34b4ef6b1c0c9391d2a9cc991f47 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Thu, 28 Jul 2016 14:41:20 -0500 Subject: [PATCH 1201/1342] config: Give the option of disabling run as user/group Leave "user/group" unset when explicitly configuring with "--disable-user" / "--enable-user=no" and "--disable-group" / "--enable-group=no" This allows quagga to skip unsupported system calls such as setuid() on certain platfroms. Signed-off-by: Jafar Al-Gharaibeh Signed-off-by: Jafar Al-Gharaibeh Tested-by: NetDEF CI System --- configure.ac | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 2f7796964..c99d1117b 100755 --- a/configure.ac +++ b/configure.ac @@ -405,16 +405,22 @@ AC_SUBST(ISIS_TOPOLOGY_INCLUDES) AC_SUBST(ISIS_TOPOLOGY_DIR) AC_SUBST(ISIS_TOPOLOGY_LIB) -if test "${enable_user}" = "yes" || test x"${enable_user}" = x""; then - enable_user="quagga" -elif test "${enable_user}" = "no"; then - enable_user="root" +if test x"${enable_user}" = x"no"; then + enable_user="" +else + if test x"${enable_user}" = x"yes" || test x"${enable_user}" = x""; then + enable_user="quagga" + fi + AC_DEFINE_UNQUOTED(QUAGGA_USER, "${enable_user}", Quagga User) fi -if test "${enable_group}" = "yes" || test x"${enable_group}" = x""; then - enable_group="quagga" -elif test "${enable_group}" = "no"; then - enable_group="root" +if test x"${enable_group}" = x"no"; then + enable_group="" +else + if test x"${enable_group}" = x"yes" || test x"${enable_group}" = x""; then + enable_group="quagga" + fi + AC_DEFINE_UNQUOTED(QUAGGA_GROUP, "${enable_group}", Quagga Group) fi if test x"${enable_vty_group}" = x"yes" ; then @@ -427,8 +433,6 @@ fi AC_SUBST([enable_user]) AC_SUBST([enable_group]) AC_SUBST([enable_vty_group]) -AC_DEFINE_UNQUOTED(QUAGGA_USER, "${enable_user}", Quagga User) -AC_DEFINE_UNQUOTED(QUAGGA_GROUP, "${enable_group}", Quagga Group) enable_configfile_mask=${enable_configfile_mask:-0600} AC_DEFINE_UNQUOTED(CONFIGFILE_MASK, ${enable_configfile_mask}, Mask for config files) From 64f8c7d80fd9685936613f6c564b9572dd28561d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 21 Aug 2016 09:23:04 +0300 Subject: [PATCH 1202/1342] configure: fix static linking with readline When static linking is used, the order of the libraries is important, and the libraries using a symbol from another library should be listed *before* the library providing that symbol (see http://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking) for details. When vtysh is linked statically, the command line contains "-lcurses -lreadline", which causes a build failure due to unresolved symbols. This is because readline is using symbols from the curses library: the order should be the opposite. This patch fixes that problem by putting the -lreadline at the beginning of the LIBREADLINE variable calcualted by the configure script. Signed-off-by: Thomas Petazzoni Signed-off-by: Baruch Siach Signed-off-by: Thomas Petazzoni Signed-off-by: Baruch Siach --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c99d1117b..e601da5d9 100755 --- a/configure.ac +++ b/configure.ac @@ -703,7 +703,7 @@ dnl [TODO] on Linux, and in [TODO] on Solaris. )] )] ) - AC_CHECK_LIB(readline, main, LIBREADLINE="$LIBREADLINE -lreadline",, + AC_CHECK_LIB(readline, main, LIBREADLINE="-lreadline $LIBREADLINE",, "$LIBREADLINE") if test $ac_cv_lib_readline_main = no; then AC_MSG_ERROR([vtysh needs libreadline but was not found and usable on your system.]) From 9ed99f040f0dd14d0aca82e159f67d27e64042ae Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 21 Aug 2016 09:23:05 +0300 Subject: [PATCH 1203/1342] lib/memory: fix indirect static link with zlib quagga SNMP support depends on netsnmp, that optionally depends on OpenSSL, which in turn requires zlib. zlib exports the 'zcalloc' symbol, which collides with a function of the same name in memory.c. This is not a problem when linking dynamically, since quagga does not use zlib directly. But static linking fails with the error: CCLD ospfd .../output/host/usr/mips64el-buildroot-linux-uclibc/sysroot/usr/lib/libz.a(zutil.o): In function `zcalloc': zutil.c:(.text+0x48): multiple definition of `zcalloc' .../output/build/quagga-1.0.20160315/lib/.libs/libzebra.a(memory.o):memory.c:(.text+0x1a0): first defined here Rename 'zcalloc' to 'zzcalloc' to avoid symbol collision. Signed-off-by: Baruch Siach Signed-off-by: Baruch Siach --- lib/memory.c | 14 ++++++++------ lib/memory.h | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/memory.c b/lib/memory.c index 13e1fb7c0..b8305dde4 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -80,9 +80,11 @@ zmalloc (int type, size_t size) /* * Allocate memory as in zmalloc, and also clear the memory. + * Add an extra 'z' prefix to function name to avoid collision when linking + * statically with zlib that exports the 'zcalloc' symbol. */ void * -zcalloc (int type, size_t size) +zzcalloc (int type, size_t size) { void *memory; @@ -97,9 +99,9 @@ zcalloc (int type, size_t size) } /* - * Given a pointer returned by zmalloc or zcalloc, free it and + * Given a pointer returned by zmalloc or zzcalloc, free it and * return a pointer to a new size, basically acting like realloc(). - * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the + * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the * same type. * Effects: Returns a pointer to the new memory, or aborts. */ @@ -109,7 +111,7 @@ zrealloc (int type, void *ptr, size_t size) void *memory; if (ptr == NULL) /* is really alloc */ - return zcalloc(type, size); + return zzcalloc(type, size); memory = realloc (ptr, size); if (memory == NULL) @@ -122,7 +124,7 @@ zrealloc (int type, void *ptr, size_t size) /* * Free memory allocated by z*alloc or zstrdup. - * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the + * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the * same type. * Effects: The memory is freed and may no longer be referenced. */ @@ -196,7 +198,7 @@ mtype_zcalloc (const char *file, int line, int type, size_t size) mstat[type].c_calloc++; mstat[type].t_calloc++; - memory = zcalloc (type, size); + memory = zzcalloc (type, size); mtype_log ("xcalloc", memory, file, line, type); return memory; diff --git a/lib/memory.h b/lib/memory.h index 23962235d..501352993 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -56,7 +56,7 @@ extern struct mlist mlists[]; mtype_zstrdup (__FILE__, __LINE__, (mtype), (str)) #else #define XMALLOC(mtype, size) zmalloc ((mtype), (size)) -#define XCALLOC(mtype, size) zcalloc ((mtype), (size)) +#define XCALLOC(mtype, size) zzcalloc ((mtype), (size)) #define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size)) #define XFREE(mtype, ptr) do { \ zfree ((mtype), (ptr)); \ @@ -67,7 +67,7 @@ extern struct mlist mlists[]; /* Prototypes of memory function. */ extern void *zmalloc (int type, size_t size); -extern void *zcalloc (int type, size_t size); +extern void *zzcalloc (int type, size_t size); extern void *zrealloc (int type, void *ptr, size_t size); extern void zfree (int type, void *ptr); extern char *zstrdup (int type, const char *str); From 95509a6f55c63b72541fa390f7dda7fab2fa3210 Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Thu, 29 Sep 2016 10:25:35 -0700 Subject: [PATCH 1204/1342] Extend BGP_SEND_ASPATH_CHECK to cover confederations Extend the check for BGP_SEND_ASPATH_CHECK to also cover confederations. --- bgpd/bgp_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 010fd4d2f..19c642989 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -896,7 +896,6 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, peer->host, peer->as); return 0; } -#endif /* BGP_SEND_ASPATH_CHECK */ /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) @@ -911,6 +910,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, return 0; } } +#endif /* BGP_SEND_ASPATH_CHECK */ /* Route-Reflect check. */ if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) From dc633bd1833c4b9df44df27135ce12fef884b53f Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 26 Dec 2016 17:25:26 +0000 Subject: [PATCH 1205/1342] lib/stream: Add stream_discard, to discard read data from a stream * stream.c: (stream_discard) Discard the already data from a stream, as indicated by the getp. Move remaining, unread data, to the beginning of the stream. get and end stream pointers are updated as appropriate. If all data has been consumed, then this behaves identically to stream_reset. --- lib/stream.c | 25 +++++++++++++++++++++++++ lib/stream.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/lib/stream.c b/lib/stream.c index b50992d6a..ed677c137 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -960,6 +960,31 @@ stream_reset (struct stream *s) s->getp = s->endp = 0; } +/* Discard read data (prior to the getp), and move the unread data + * to the beginning of the stream. + * + * See also stream_fifo_* functions, for another approach to managing + * streams. + */ +void +stream_discard (struct stream *s) +{ + STREAM_VERIFY_SANE (s); + + if (s->getp == 0) + return; + + if (s->getp == s->endp) + { + stream_reset (s); + return; + } + + s->data = memmove (s->data, s->data + s->getp, s->endp - s->getp); + s->endp -= s->getp; + s->getp = 0; +} + /* Write stream contens to the file discriptor. */ int stream_flush (struct stream *s, int fd) diff --git a/lib/stream.h b/lib/stream.h index 06b0ee12c..9127bcd23 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -218,6 +218,8 @@ extern size_t stream_write (struct stream *, const void *, size_t); /* reset the stream. See Note above */ extern void stream_reset (struct stream *); +/* move unread data to start of stream, discarding read data */ +extern void stream_discard (struct stream *); extern int stream_flush (struct stream *, int); extern int stream_empty (struct stream *); /* is the stream empty? */ From d395fd1996df70eb5e6ecc4fc1cf90e8303f43a6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jun 2016 02:20:27 -0400 Subject: [PATCH 1206/1342] pimd: Remove dead code. No need to keep '#if 0' code. If we need it in the future, just go back into the history and grab it. Signed-off-by: Donald Sharp Signed-off-by: Donald Sharp Acked-by: Jafar Al-Gharaibeh --- pimd/pim_zebra.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 0a07c0615..7072a3b28 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -51,23 +51,6 @@ static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask); -#if 0 -static void zclient_broken(struct zclient *zclient) -{ - struct listnode *ifnode; - struct interface *ifp; - - zlog_warn("%s %s: broken zclient connection", - __FILE__, __PRETTY_FUNCTION__); - - for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { - pim_if_addr_del_all(ifp); - } - - /* upon return, zclient will discard connected addresses */ -} -#endif - /* Router-id update message from zebra. */ static int pim_router_id_update_zebra(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) From 3e6a3a64359ae6fa370fbd9c843b7c0d04a946c3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jun 2016 02:20:28 -0400 Subject: [PATCH 1207/1342] pimd: Remove source_new unneeded parameter The interface name is already passed in as part of the 'struct igmp_group *group' pointer. No need to do it twice. Signed-off-by: Donald Sharp Signed-off-by: Donald Sharp Acked-by: Jafar Al-Gharaibeh --- pimd/pim_igmp.h | 3 +++ pimd/pim_igmpv3.c | 40 ++++++++++++++++------------------------ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index d45f223ba..f8a31cdff 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -173,4 +173,7 @@ void igmp_startup_mode_on(struct igmp_sock *igmp); void igmp_group_timer_on(struct igmp_group *group, long interval_msec, const char *ifname); +struct igmp_source * +source_new (struct igmp_group *group, + struct in_addr src_addr); #endif /* PIM_IGMP_H */ diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 3657f2f94..1a2e936f2 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -477,9 +477,9 @@ struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, return 0; } -static struct igmp_source *source_new(struct igmp_group *group, - struct in_addr src_addr, - const char *ifname) +struct igmp_source * +source_new (struct igmp_group *group, + struct in_addr src_addr) { struct igmp_source *src; @@ -491,7 +491,7 @@ static struct igmp_source *source_new(struct igmp_group *group, zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s", source_str, group_str, group->group_igmp_sock->fd, - ifname); + group->group_igmp_sock->interface->name); } src = XMALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src)); @@ -501,13 +501,13 @@ static struct igmp_source *source_new(struct igmp_group *group, return 0; /* error, not found, could not create */ } - src->t_source_timer = 0; + src->t_source_timer = NULL; src->source_group = group; /* back pointer */ src->source_addr = src_addr; src->source_creation = pim_time_monotonic_sec(); src->source_flags = 0; src->source_query_retransmit_count = 0; - src->source_channel_oil = 0; + src->source_channel_oil = NULL; listnode_add(group->group_source_list, src); @@ -521,8 +521,7 @@ static struct igmp_source *source_new(struct igmp_group *group, static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp, struct igmp_group *group, - struct in_addr src_addr, - const char *ifname) + struct in_addr src_addr) { struct igmp_source *src; @@ -531,7 +530,7 @@ static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp, return src; } - src = source_new(group, src_addr, ifname); + src = source_new(group, src_addr); if (!src) { return 0; } @@ -560,7 +559,7 @@ static void allow(struct igmp_sock *igmp, struct in_addr from, src_addr = sources + i; - source = add_source_by_addr(igmp, group, *src_addr, ifp->name); + source = add_source_by_addr(igmp, group, *src_addr); if (!source) { continue; } @@ -616,8 +615,7 @@ static void isex_excl(struct igmp_group *group, } else { /* E.4: if not found, create source with timer=GMI: (A-X-Y) */ - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; @@ -659,8 +657,7 @@ static void isex_incl(struct igmp_group *group, } else { /* I.4: if not found, create source with timer=0 (B-A) */ - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; @@ -737,8 +734,7 @@ static void toin_incl(struct igmp_group *group, } else { /* If not found, create new source */ - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; @@ -783,8 +779,7 @@ static void toin_excl(struct igmp_group *group, } else { /* If not found, create new source */ - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; @@ -862,8 +857,7 @@ static void toex_incl(struct igmp_group *group, } else { /* If source not found, create source with timer=0: (B-A)=0 */ - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; @@ -916,8 +910,7 @@ static void toex_excl(struct igmp_group *group, else { /* if not found, create source with Group Timer: (A-X-Y)=Group Timer */ long group_timer_msec; - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; @@ -1421,8 +1414,7 @@ static void block_excl(struct igmp_group *group, if (!source) { /* 3: if not found, create source with Group Timer: (A-X-Y)=Group Timer */ long group_timer_msec; - source = source_new(group, *src_addr, - group->group_igmp_sock->interface->name); + source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; From f8aef5fd4aa48eceedb67fb8919378e33617bc5d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jun 2016 02:20:29 -0400 Subject: [PATCH 1208/1342] pimd: Remove igmp_add_group_by_addr unneeded parameter The interface name is already passed in as part of the 'struct igrmp *group' pointer. No need to do it twice. Signed-off-by: Donald Sharp Signed-off-by: Donald Sharp Tested-by: NetDEF CI System Acked-by: Jafar Al-Gharaibeh --- pimd/pim_igmp.c | 13 ++++++------- pimd/pim_igmp.h | 3 +-- pimd/pim_igmpv3.c | 11 +++++------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 0d6f07aa4..ad3c7b555 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -624,7 +624,7 @@ static int igmp_v2_report(struct igmp_sock *igmp, memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return -1; } @@ -681,7 +681,7 @@ static int igmp_v1_report(struct igmp_sock *igmp, memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return -1; } @@ -1359,8 +1359,7 @@ static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, } struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr, - const char *ifname) + struct in_addr group_addr) { struct igmp_group *group; @@ -1398,8 +1397,8 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, } group->group_source_list->del = (void (*)(void *)) igmp_source_free; - group->t_group_timer = 0; - group->t_group_query_retransmit_timer = 0; + group->t_group_timer = NULL; + group->t_group_query_retransmit_timer = NULL; group->group_specific_query_retransmit_count = 0; group->group_addr = group_addr; group->group_igmp_sock = igmp; @@ -1416,7 +1415,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Creating new IGMP group %s on socket %d interface %s", - group_str, group->group_igmp_sock->fd, ifname); + group_str, igmp->fd, igmp->interface->name); } /* diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index f8a31cdff..ab396159e 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -163,8 +163,7 @@ struct igmp_group { }; struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr, - const char *ifname); + struct in_addr group_addr); void igmp_group_delete_empty_include(struct igmp_group *group); diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 1a2e936f2..8a32a3272 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -542,12 +542,11 @@ static void allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { - struct interface *ifp = igmp->interface; struct igmp_group *group; int i; /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } @@ -688,7 +687,7 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } @@ -810,7 +809,7 @@ void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } @@ -960,7 +959,7 @@ void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } @@ -1481,7 +1480,7 @@ void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ - group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); + group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } From 18343eeff67b9b17b7d688a13a1f0829db1ad436 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jun 2016 02:30:46 -0400 Subject: [PATCH 1209/1342] pimd: Add support for displaying ip mroute When you enter a static mroute under an interface the 'show run' is not displaying this information. Add code to allow this. Signed-off-by: Donald Sharp Reviewed-by: Daniel Walton Reviewed-by: Don Slice Signed-off-by: Donald Sharp Reviewed-by: Daniel Walton Reviewed-by: Don Slice Tested-by: NetDEF CI System Acked-by: Jafar Al-Gharaibeh --- pimd/pim_static.c | 31 +++++++++++++++++++++++++++++++ pimd/pim_static.h | 1 + pimd/pim_vty.c | 3 +++ 3 files changed, 35 insertions(+) diff --git a/pimd/pim_static.c b/pimd/pim_static.c index cbbcaaa9b..5114901da 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -22,6 +22,8 @@ #include +#include "vty.h" + #include "pim_static.h" #include "pim_time.h" #include "pim_str.h" @@ -305,3 +307,32 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr return 0; } + +int +pim_static_write_mroute (struct vty *vty, struct interface *ifp) +{ + struct listnode *node; + struct static_route *sroute; + int count = 0; + char sbuf[100]; + char gbuf[100]; + + for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute)) + { + pim_inet4_dump ("", sroute->group, gbuf, sizeof (gbuf)); + pim_inet4_dump ("", sroute->source, sbuf, sizeof (sbuf)); + if (sroute->iif == ifp->ifindex) + { + int i; + for (i = 0; i < MAXVIFS; i++) + if (sroute->oif_ttls[i]) + { + struct interface *oifp = if_lookup_by_index (i); + vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE); + count ++; + } + } + } + + return count; +} diff --git a/pimd/pim_static.h b/pimd/pim_static.h index 3a096932d..b3be09e91 100644 --- a/pimd/pim_static.h +++ b/pimd/pim_static.h @@ -43,5 +43,6 @@ void pim_static_route_free(struct static_route *s_route); int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source); int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source); +int pim_static_write_mroute (struct vty *vty, struct interface *ifp); #endif /* PIM_STATIC_H_ */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 810dbe807..56de83c8b 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -32,6 +32,7 @@ #include "pim_str.h" #include "pim_ssmpingd.h" #include "pim_pim.h" +#include "pim_static.h" int pim_debug_config_write(struct vty *vty) { @@ -191,6 +192,8 @@ int pim_interface_config_write(struct vty *vty) ++writes; } } + + writes += pim_static_write_mroute (vty, ifp); } vty_out(vty, "!%s", VTY_NEWLINE); ++writes; From 456cb633436c567a173dadb9b6fb4610266c2ef9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 2 Jun 2016 02:37:52 -0400 Subject: [PATCH 1210/1342] pimd: Add ability to safely ignore route-maps pim was not parsing route-map code and causing issues using vtysh because of this. Add code to safely ignore the route-map code and set us up for future expansion into route-maps if neeeded. Signed-off-by: Donald Sharp Signed-off-by: Donald Sharp Tested-by: NetDEF CI System Acked-by: Jafar Al-Gharaibeh --- pimd/Makefile.am | 3 ++- pimd/pim_main.c | 4 ++++ pimd/pim_routemap.c | 32 ++++++++++++++++++++++++++++++++ pimd/pimd.h | 2 ++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 pimd/pim_routemap.c diff --git a/pimd/Makefile.am b/pimd/Makefile.am index f57c4c254..d04543685 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -52,7 +52,8 @@ libpim_a_SOURCES = \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ - pim_igmp_join.c pim_ssmpingd.c pim_int.c pim_static.c + pim_igmp_join.c pim_ssmpingd.c pim_int.c pim_static.c \ + pim_routemap.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 5f4711e86..ea70a8fcf 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -36,6 +36,8 @@ #include "vty.h" #include "sigevent.h" #include "version.h" +#include "prefix.h" +#include "plist.h" #include "pimd.h" #include "pim_version.h" @@ -200,6 +202,8 @@ int main(int argc, char** argv, char** envp) { memory_init(); vrf_init(); access_list_init(); + prefix_list_init (); + pim_route_map_init (); pim_init(); /* diff --git a/pimd/pim_routemap.c b/pimd/pim_routemap.c new file mode 100644 index 000000000..9cc13be68 --- /dev/null +++ b/pimd/pim_routemap.c @@ -0,0 +1,32 @@ +/* PIM Route-map Code + * Copyright (C) 2016 Cumulus Networks + * + * 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 + +#include "routemap.h" + +#include "pimd.h" + +void +pim_route_map_init (void) +{ + route_map_init (); + route_map_init_vty (); +} diff --git a/pimd/pimd.h b/pimd/pimd.h index aed26bea2..9a7e60583 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -159,4 +159,6 @@ struct list *qpim_static_route_list; /* list of routes added static void pim_init(void); void pim_terminate(void); +extern void pim_route_map_init (void); + #endif /* PIMD_H */ From 68cfaabc2e281b6ef9810138db3b42e52f1f0060 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 6 Jun 2016 21:10:24 +0200 Subject: [PATCH 1211/1342] zebra: fix a crash in static_add_ipv6 caused by a NULL dereference si will be NULL after end of the preceeding for loop. update is the right static route info to use for deleting the old route. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Tested-by: NetDEF CI System Acked-by: Donald Sharp --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index abb9560ab..2aecf5dac 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2845,7 +2845,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, } if (update) - static_delete_ipv6(p, type, gate, ifname, tag, si->distance, vrf_id); + static_delete_ipv6(p, type, gate, ifname, tag, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); From 5a7a23b09fed1cb26b901e3160c2f6e560cfd679 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 6 Jun 2016 21:13:15 +0200 Subject: [PATCH 1212/1342] isisd: exit if daemonizing fails The other daemons in Quagga exit with an error if they cannot fork. Change isisd to behave consistently. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Tested-by: NetDEF CI System Acked-by: Donald Sharp --- isisd/isis_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 1dda43bcc..bbb1fb2a3 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -358,8 +358,11 @@ main (int argc, char **argv, char **envp) return(0); /* demonize */ - if (daemon_mode) - daemon (0, 0); + if (daemon_mode && daemon (0, 0) < 0) + { + zlog_err("IS-IS daemon failed: %s", strerror(errno)); + exit (1); + } /* Process ID file creation. */ if (pid_file[0] != '\0') From 8db38639cc4cf796484b352c57f2709151f0e2e4 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 6 Jun 2016 21:49:59 +0200 Subject: [PATCH 1213/1342] ospf6d: remove unused broken function ospf6_interface_if_del has not been in use since for quite some years and is broken. (Will crash ospf6d if oi->area == NULL) Since it is not used, just remove it. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Tested-by: NetDEF CI System Acked-by: Donald Sharp --- ospf6d/ospf6_interface.c | 23 ----------------------- ospf6d/ospf6_interface.h | 1 - ospf6d/ospf6_zebra.c | 7 ------- 3 files changed, 31 deletions(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 3d6ebcda7..14a93c85b 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -339,29 +339,6 @@ ospf6_interface_if_add (struct interface *ifp) ospf6_interface_state_update(oi->interface); } -void -ospf6_interface_if_del (struct interface *ifp) -{ - struct ospf6_interface *oi; - - oi = (struct ospf6_interface *) ifp->info; - if (oi == NULL) - return; - - /* interface stop */ - if (oi->area) - thread_execute (master, interface_down, oi, 0); - - listnode_delete (oi->area->if_list, oi); - oi->area = (struct ospf6_area *) NULL; - - /* cut link */ - oi->interface = NULL; - ifp->info = NULL; - - ospf6_interface_delete (oi); -} - void ospf6_interface_state_update (struct interface *ifp) { diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index dde589b8f..2fbb83c4b 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -157,7 +157,6 @@ extern void ospf6_interface_enable (struct ospf6_interface *); extern void ospf6_interface_disable (struct ospf6_interface *); extern void ospf6_interface_if_add (struct interface *); -extern void ospf6_interface_if_del (struct interface *); extern void ospf6_interface_state_update (struct interface *); extern void ospf6_interface_connected_route_update (struct interface *); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 5d5db0b93..f80bb23f9 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -120,13 +120,6 @@ ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length, zlog_debug ("Zebra Interface delete: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); -#if 0 - /* XXX: ospf6_interface_if_del is not the right way to handle this, - * because among other thinkable issues, it will also clear all - * settings as they are contained in the struct ospf6_interface. */ - ospf6_interface_if_del (ifp); -#endif /*0*/ - ifp->ifindex = IFINDEX_INTERNAL; return 0; } From 51b45a52adf944ac391c0e90f86597454ab4d657 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 6 Jun 2016 22:04:30 +0200 Subject: [PATCH 1214/1342] zebra: make fpm netlink_route_info_fill more robust Having an RTM_ADDROUTE with a rib == NULL would lead to a crash due to a NULL pointer dereference. Since an RTM_ADDROUTE without a rib object doesn't make much sense, print a warning and remove the concerned route instead. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Tested-by: NetDEF CI System --- zebra/zebra_fpm_netlink.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 59e861b91..175d351a1 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -252,11 +252,16 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd, * An RTM_DELROUTE need not be accompanied by any nexthops, * particularly in our communication with the FPM. */ - if (cmd == RTM_DELROUTE && !rib) + if (cmd == RTM_DELROUTE) goto skip; - if (rib) - ri->rtm_protocol = netlink_proto_from_route_type (rib->type); + if (!rib) + { + zlog_err("netlink_route_info_fill RTM_ADDROUTE called without rib info"); + return 0; + } + + ri->rtm_protocol = netlink_proto_from_route_type (rib->type); if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; From c0a613f3a2be8e40265704fd00166cd5342ca409 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 6 Jun 2016 22:22:15 +0200 Subject: [PATCH 1215/1342] bgpd: fix potential crash in community_list_dup_check extcommunity_list_set may set the ->config for an entry to NULL. In this case, the old code in community_list_dup_check would cause a NULL pointer dereference. Adjust the code so it behaves the same in the absence of NULL pointers and otherwise checks if both are NULL to determine equality. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Tested-by: NetDEF CI System Acked-by: Donald Sharp --- bgpd/bgp_clist.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index bb06028b0..1f1a4e7f2 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -644,7 +644,10 @@ community_list_dup_check (struct community_list *list, break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: - if (strcmp (entry->config, new->config) == 0) + if (entry->config && new->config + && strcmp (entry->config, new->config) == 0) + return 1; + if (!entry->config && !new->config) return 1; break; default: From 6ff2acde9291b855c44edf9a7a0423580c901d03 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Thu, 9 Jun 2016 16:44:21 +0300 Subject: [PATCH 1216/1342] vtysh: send "no interface" command to all daemons that support it Signed-off-by: Igor Ryzhov Signed-off-by: Igor Ryzhov Acked-by: Donald Sharp Tested-by: NetDEF CI System --- vtysh/vtysh.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 7068ea3ab..75d1fc076 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1336,8 +1336,7 @@ ALIAS_SH (VTYSH_ZEBRA, "Interface's name\n" VRF_CMD_HELP_STR) -/* TODO Implement "no interface command in isisd. */ -DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D, +DEFSH (VTYSH_INTERFACE, vtysh_no_interface_cmd, "no interface IFNAME", NO_STR From c96e78dde1f118eaee4269aa2c91ef70850e5423 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 9 Jun 2016 15:34:59 -0400 Subject: [PATCH 1217/1342] pimd: Fix of using uninitialized Memory Valgrind is reporting that pimd is using uninitialized memory for comparisons. This commit addresses the issues found there. Signed-off-by: Donald Sharp Signed-off-by: Donald Sharp --- pimd/pim_iface.c | 1 + pimd/pim_ifchannel.c | 7 +++++-- pimd/pim_igmpv3.c | 5 ----- pimd/pim_pim.c | 5 ----- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 2533d0fd7..ddad6cb75 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -107,6 +107,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->igmp_socket_list = 0; pim_ifp->pim_neighbor_list = 0; pim_ifp->pim_ifchannel_list = 0; + pim_ifp->pim_generation_id = 0; /* list of struct igmp_sock */ pim_ifp->igmp_socket_list = list_new(); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index e801f4eeb..ad97879d6 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -223,6 +223,11 @@ static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp, ch->t_ifjoin_prune_pending_timer = 0; ch->ifjoin_creation = 0; + ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); + ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval (ch); + + ch->ifassert_winner.s_addr = 0; + /* Assert state */ ch->t_ifassert_timer = 0; reset_ifassert_state(ch); @@ -236,8 +241,6 @@ static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp, else PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); - ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); - /* Attach to list */ listnode_add(pim_ifp->pim_ifchannel_list, ch); diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 8a32a3272..180de9d71 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1661,14 +1661,9 @@ void pim_igmp_send_membership_query(struct igmp_group *group, querier_query_interval, qqic, checksum); } -#if 0 memset(&to, 0, sizeof(to)); -#endif to.sin_family = AF_INET; to.sin_addr = dst_addr; -#if 0 - to.sin_port = htons(0); -#endif tolen = sizeof(to); sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index c52247578..c52b0d393 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -473,14 +473,9 @@ int pim_msg_send(int fd, *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)); } -#if 0 memset(&to, 0, sizeof(to)); -#endif to.sin_family = AF_INET; to.sin_addr = dst; -#if 0 - to.sin_port = htons(0); -#endif tolen = sizeof(to); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { From 449b29e8bd9fb1ae2e57cea7074e1b9778343455 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 13 Jun 2016 17:29:12 +0200 Subject: [PATCH 1218/1342] lib: linklist: add listnode_add_before() This utility function, to join the zoo that the Quagga linked-list implementation has accumulated, does an insert-before while returning the newly allocated node. It is similar to: - listnode_add_after(), but - complementary direction - returns allocated node - list_add_node_prev(), but - supports before == NULL - returns allocated node In general, the entire linked-list implementation is in bad shape, and while it needs a cleanup / rewrite / replacement, this would both cause significant conflicts and block other cleanups... Signed-off-by: David Lamparter Signed-off-by: David Lamparter --- lib/linklist.c | 38 ++++++++++++++++++++++++++++++++++++++ lib/linklist.h | 1 + 2 files changed, 39 insertions(+) diff --git a/lib/linklist.c b/lib/linklist.c index 4b16f07dd..8b6a85282 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -159,6 +159,44 @@ listnode_add_after (struct list *list, struct listnode *pp, void *val) list->count++; } +struct listnode * +listnode_add_before (struct list *list, struct listnode *pp, void *val) +{ + struct listnode *nn; + + assert (val != NULL); + + nn = listnode_new (); + nn->data = val; + + if (pp == NULL) + { + if (list->tail) + list->tail->next = nn; + else + list->head = nn; + + nn->prev = list->tail; + nn->next = pp; + + list->tail = nn; + } + else + { + if (pp->prev) + pp->prev->next = nn; + else + list->head = nn; + + nn->prev = pp->prev; + nn->next = pp; + + pp->prev = nn; + } + list->count++; + return nn; +} + /* Move given listnode to tail of the list */ void listnode_move_to_tail (struct list *l, struct listnode *n) diff --git a/lib/linklist.h b/lib/linklist.h index 6209c8b9d..96aaf4319 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -68,6 +68,7 @@ extern void list_free (struct list *); extern void listnode_add (struct list *, void *); extern void listnode_add_sort (struct list *, void *); extern void listnode_add_after (struct list *, struct listnode *, void *); +extern struct listnode *listnode_add_before (struct list *, struct listnode *, void *); extern void listnode_move_to_tail (struct list *, struct listnode *); extern void listnode_delete (struct list *, void *); extern struct listnode *listnode_lookup (struct list *, void *); From 47fb0a8eb8138572a9117156223259413a956e81 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 13 Jun 2016 17:29:13 +0200 Subject: [PATCH 1219/1342] lib: add thread_add_timer_tv (struct timeval) Another zoo extension, this adds a timer scheduling function that takes a struct timeval argument (which is actually what the wrappers boil down to, yet it's not exposed...) Signed-off-by: David Lamparter Signed-off-by: David Lamparter --- lib/thread.c | 11 +++++++++++ lib/thread.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/lib/thread.c b/lib/thread.c index 6fcddd789..39e79ad8c 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -896,6 +896,17 @@ funcname_thread_add_timer_msec (struct thread_master *m, arg, &trel, debugargpass); } +/* Add timer event thread with "millisecond" resolution */ +struct thread * +funcname_thread_add_timer_tv (struct thread_master *m, + int (*func) (struct thread *), + void *arg, struct timeval *tv, + debugargdef) +{ + return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, + arg, tv, debugargpass); +} + /* Add a background thread, with an optional millisec delay */ struct thread * funcname_thread_add_background (struct thread_master *m, diff --git a/lib/thread.h b/lib/thread.h index dafd438a8..3f162163d 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -176,6 +176,7 @@ enum quagga_clkid { #define thread_add_write(m,f,a,v) funcname_thread_add_write(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_timer_tv(m,f,a,v) funcname_thread_add_timer_tv(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f,__FILE__,__LINE__) #define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f,__FILE__,__LINE__) @@ -198,6 +199,10 @@ extern struct thread *funcname_thread_add_timer (struct thread_master *, extern struct thread *funcname_thread_add_timer_msec (struct thread_master *, int (*)(struct thread *), void *, long, debugargdef); +extern struct thread *funcname_thread_add_timer_tv (struct thread_master *, + int (*)(struct thread *), + void *, struct timeval *, + debugargdef); extern struct thread *funcname_thread_add_event (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); From cfb4826340ab177b3cfbce4f138187f41860b68e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 13 Jun 2016 17:29:14 +0200 Subject: [PATCH 1220/1342] lib: AgentX: use threads instead of eventloop hack AgentX fd/timeout handling is rather hackishly monkeyed into thread.c. Replace with code that uses plain thread_* functions. NB: Net-SNMP's API rivals Quagga's in terms of age and absence of documentation. netsnmp_check_outstanding_agent_requests() in particular seems to be unused and is therefore untested. The most useful documentation on this is actually the blog post Vincent Bernat wrote when he originally integrated this into lldpd and Quagga: https://vincent.bernat.im/en/blog/2012-snmp-event-loop.html Signed-off-by: David Lamparter Signed-off-by: David Lamparter --- lib/agentx.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++- lib/thread.c | 50 +------------------------ 2 files changed, 104 insertions(+), 50 deletions(-) diff --git a/lib/agentx.c b/lib/agentx.c index be6b4320e..5d7d057da 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -24,11 +24,108 @@ #if defined HAVE_SNMP && defined SNMP_AGENTX #include #include +#include +#include #include "command.h" #include "smux.h" -int agentx_enabled = 0; +static int agentx_enabled = 0; + +static struct thread_master *agentx_tm; +static struct thread *timeout_thr = NULL; +static struct list *events = NULL; + +static void agentx_events_update(void); + +static int +agentx_timeout(struct thread *t) +{ + timeout_thr = NULL; + + snmp_timeout (); + run_alarms (); + netsnmp_check_outstanding_agent_requests (); + agentx_events_update (); + return 0; +} + +static int +agentx_read(struct thread *t) +{ + fd_set fds; + struct listnode *ln = THREAD_ARG (t); + list_delete_node (events, ln); + + FD_ZERO (&fds); + FD_SET (THREAD_FD (t), &fds); + snmp_read (&fds); + + netsnmp_check_outstanding_agent_requests (); + agentx_events_update (); + return 0; +} + +static void +agentx_events_update(void) +{ + int maxfd = 0; + int block = 1; + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + fd_set fds; + struct listnode *ln; + struct thread *thr; + int fd, thr_fd; + + THREAD_OFF (timeout_thr); + + FD_ZERO (&fds); + snmp_select_info (&maxfd, &fds, &timeout, &block); + + if (!block) + timeout_thr = thread_add_timer_tv (agentx_tm, agentx_timeout, NULL, &timeout); + + ln = listhead (events); + thr = ln ? listgetdata (ln) : NULL; + thr_fd = thr ? THREAD_FD (thr) : -1; + + /* "two-pointer" / two-list simultaneous iteration + * ln/thr/thr_fd point to the next existing event listener to hit while + * fd counts to catch up */ + for (fd = 0; fd < maxfd; fd++) + { + /* caught up */ + if (thr_fd == fd) + { + struct listnode *nextln = listnextnode (ln); + if (!FD_ISSET (fd, &fds)) + { + thread_cancel (thr); + list_delete_node (events, ln); + } + ln = nextln; + thr = ln ? listgetdata (ln) : NULL; + thr_fd = thr ? THREAD_FD (thr) : -1; + } + /* need listener, but haven't hit one where it would be */ + else if (FD_ISSET (fd, &fds)) + { + struct listnode *newln; + thr = thread_add_read (agentx_tm, agentx_read, NULL, fd); + newln = listnode_add_before (events, ln, thr); + thr->arg = newln; + } + } + + /* leftover event listeners at this point have fd > maxfd, delete them */ + while (ln) + { + struct listnode *nextln = listnextnode (ln); + thread_cancel (listgetdata (ln)); + list_delete_node (events, ln); + ln = nextln; + } +} /* AgentX node. */ static struct cmd_node agentx_node = @@ -77,6 +174,8 @@ DEFUN (agentx_enable, if (!agentx_enabled) { init_snmp("quagga"); + events = list_new(); + agentx_events_update (); agentx_enabled = 1; return CMD_SUCCESS; } @@ -99,6 +198,8 @@ DEFUN (no_agentx, void smux_init (struct thread_master *tm) { + agentx_tm = tm; + netsnmp_enable_subagent (); snmp_disable_log (); snmp_enable_calllog (); @@ -207,6 +308,7 @@ smux_trap (struct variable *vp, size_t vp_len, send_v2trap (notification_vars); snmp_free_varbind (notification_vars); + agentx_events_update (); return 1; } diff --git a/lib/thread.c b/lib/thread.c index 39e79ad8c..b65078c68 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -32,15 +32,6 @@ #include "command.h" #include "sigevent.h" -#if defined HAVE_SNMP && defined SNMP_AGENTX -#include -#include -#include -#include - -extern int agentx_enabled; -#endif - #if defined(__APPLE__) #include #include @@ -1174,12 +1165,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) while (1) { int num = 0; -#if defined HAVE_SNMP && defined SNMP_AGENTX - struct timeval snmp_timer_wait; - int snmpblock = 0; - int fdsetsize; -#endif - + /* Signals pre-empt everything */ quagga_sigevent_process (); @@ -1214,26 +1200,6 @@ thread_fetch (struct thread_master *m, struct thread *fetch) timer_wait = timer_wait_bg; } -#if defined HAVE_SNMP && defined SNMP_AGENTX - /* When SNMP is enabled, we may have to select() on additional - FD. snmp_select_info() will add them to `readfd'. The trick - with this function is its last argument. We need to set it to - 0 if timer_wait is not NULL and we need to use the provided - new timer only if it is still set to 0. */ - if (agentx_enabled) - { - fdsetsize = FD_SETSIZE; - snmpblock = 1; - if (timer_wait) - { - snmpblock = 0; - memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval)); - } - snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); - if (snmpblock == 0) - timer_wait = &snmp_timer_wait; - } -#endif num = fd_select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); /* Signals should get quick treatment */ @@ -1245,20 +1211,6 @@ thread_fetch (struct thread_master *m, struct thread *fetch) return NULL; } -#if defined HAVE_SNMP && defined SNMP_AGENTX - if (agentx_enabled) - { - if (num > 0) - snmp_read(&readfd); - else if (num == 0) - { - snmp_timeout(); - run_alarms(); - } - netsnmp_check_outstanding_agent_requests(); - } -#endif - /* Check foreground timers. Historically, they have had higher priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ From 5cb81ce51d5c2ed6b6f7ce51dcfa5388b1836c27 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:06:56 +0200 Subject: [PATCH 1221/1342] bgpd: setting nexthop doesn't need inet_pton Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- bgpd/bgp_routemap.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index c66f260e8..921687a7f 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2190,7 +2190,6 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, struct in6_addr peer_address; struct bgp_info *bgp_info; struct peer *peer; - char peer_addr_buf[INET6_ADDRSTRLEN]; if (type == RMAP_BGP) { @@ -2203,19 +2202,13 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, && peer->su_remote && sockunion_family (peer->su_remote) == AF_INET6) { - inet_pton (AF_INET6, sockunion2str (peer->su_remote, - peer_addr_buf, - INET6_ADDRSTRLEN), - &peer_address); + peer_address = peer->su_remote->sin6.sin6_addr; } else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) && peer->su_local && sockunion_family (peer->su_local) == AF_INET6) { - inet_pton (AF_INET, sockunion2str (peer->su_local, - peer_addr_buf, - INET6_ADDRSTRLEN), - &peer_address); + peer_address = peer->su_local->sin6.sin6_addr; } if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) From 708ea62f82f34c8674042b369ee8cba5d7b34c02 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:06:57 +0200 Subject: [PATCH 1222/1342] bgpd: check return value of zebra_interface_state_read zebra_interface_state_read can return NULL in cornercases. The other daemons check for this, so should bgpd. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- bgpd/bgp_zebra.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index ba87ad1c8..40ecbce01 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -107,6 +107,9 @@ bgp_interface_delete (int command, struct zclient *zclient, s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); + if (! ifp) + return 0; + ifp->ifindex = IFINDEX_INTERNAL; if (BGP_DEBUG(zebra, ZEBRA)) From 32e41f75fd1735071e0fa0bdd918e9b1241d1837 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:06:59 +0200 Subject: [PATCH 1223/1342] bgpd: don't leak memory in community_regexp_include Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- bgpd/bgp_clist.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 1f1a4e7f2..800bd0129 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -402,17 +402,22 @@ community_str_get (struct community *com, int i) static int community_regexp_include (regex_t * reg, struct community *com, int i) { - const char *str; + char *str; + int rv; /* When there is no communities attribute it is treated as empty * string. */ if (com == NULL || com->size == 0) - str = ""; + str = XSTRDUP(MTYPE_COMMUNITY_STR, ""); else str = community_str_get (com, i); /* Regular expression match. */ - if (regexec (reg, str, 0, NULL, 0) == 0) + rv = regexec (reg, str, 0, NULL, 0); + + XFREE(MTYPE_COMMUNITY_STR, str); + + if (rv == 0) return 1; /* No match. */ From c8e80972d5b99fb8baaa367a726f1dc36a840744 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:01 +0200 Subject: [PATCH 1224/1342] bgpd: fix memory leaks in show commands sockunion_str2su allocates a struct sockunion that used to be leaked in the show commands. Use str2sockunion and keep the information on the stack instead. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp Signed-off-by: Philippe Guibert --- bgpd/bgp_encap.c | 38 +++++++++++++++++--------------------- bgpd/bgp_mplsvpn.c | 18 ++++++++---------- bgpd/bgp_route.c | 10 ++++++---- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index edd9d7675..cd58ac25c 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -649,24 +649,23 @@ DEFUN (show_bgp_ipv4_encap_neighbor_routes, "Neighbor to display information about\n" "Display routes learned from neighbor\n") { - union sockunion *su; + union sockunion su; struct peer *peer; - - su = sockunion_str2su (argv[0]); - if (su == NULL) + + if (str2sockunion(argv[0], &su)) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0); + return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_encap_neighbor_routes, @@ -680,24 +679,23 @@ DEFUN (show_bgp_ipv6_encap_neighbor_routes, "Neighbor to display information about\n" "Display routes learned from neighbor\n") { - union sockunion *su; + union sockunion su; struct peer *peer; - su = sockunion_str2su (argv[0]); - if (su == NULL) + if (str2sockunion(argv[0], &su)) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_neighbor, su, 0); + return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, @@ -715,7 +713,7 @@ DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, "Display routes learned from neighbor\n") { int ret; - union sockunion *su; + union sockunion su; struct peer *peer; struct prefix_rd prd; @@ -726,21 +724,20 @@ DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, return CMD_WARNING; } - su = sockunion_str2su (argv[1]); - if (su == NULL) + if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_neighbor, su, 0); + return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, @@ -758,7 +755,7 @@ DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, "Display routes learned from neighbor\n") { int ret; - union sockunion *su; + union sockunion su; struct peer *peer; struct prefix_rd prd; @@ -769,21 +766,20 @@ DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, return CMD_WARNING; } - su = sockunion_str2su (argv[1]); - if (su == NULL) + if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_neighbor, su, 0); + return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv4_encap_neighbor_advertised_routes, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 047105d79..ac3ee0808 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -969,7 +969,7 @@ DEFUN (show_bgp_ipv4_vpn_rd_neighbor_routes, "Display routes learned from neighbor\n") { int ret; - union sockunion *su; + union sockunion su; struct peer *peer; struct prefix_rd prd; @@ -980,21 +980,20 @@ DEFUN (show_bgp_ipv4_vpn_rd_neighbor_routes, return CMD_WARNING; } - su = sockunion_str2su (argv[1]); - if (su == NULL) + if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, AFI_IP, &prd, bgp_show_type_neighbor, su, 0); + return bgp_show_mpls_vpn (vty, AFI_IP, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_vpn_rd_neighbor_routes, show_bgp_ipv6_vpn_rd_neighbor_routes_cmd, @@ -1010,7 +1009,7 @@ DEFUN (show_bgp_ipv6_vpn_rd_neighbor_routes, "Display routes learned from neighbor\n") { int ret; - union sockunion *su; + union sockunion su; struct peer *peer; struct prefix_rd prd; @@ -1021,21 +1020,20 @@ DEFUN (show_bgp_ipv6_vpn_rd_neighbor_routes, return CMD_WARNING; } - su = sockunion_str2su (argv[1]); - if (su == NULL) + if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - peer = peer_lookup (NULL, su); + peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - return bgp_show_mpls_vpn (vty, AFI_IP6, &prd, bgp_show_type_neighbor, su, 0); + return bgp_show_mpls_vpn (vty, AFI_IP6, &prd, bgp_show_type_neighbor, &su, 0); } void diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 19c642989..ec2f967f1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -9428,7 +9428,7 @@ bgp_show_community (struct vty *vty, const char *view_name, int argc, struct community *com; struct buffer *b; struct bgp *bgp; - int i; + int i, rv; char *str; int first = 0; @@ -9479,9 +9479,11 @@ bgp_show_community (struct vty *vty, const char *view_name, int argc, return CMD_WARNING; } - return bgp_show (vty, bgp, afi, safi, - (exact ? bgp_show_type_community_exact : - bgp_show_type_community), com); + rv = bgp_show (vty, bgp, afi, safi, + (exact ? bgp_show_type_community_exact : + bgp_show_type_community), com); + community_free(com); + return rv; } DEFUN (show_ip_bgp_community, From 5bd78b9f409b0a7d4b6a9e15d495ca2c53757a4d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:02 +0200 Subject: [PATCH 1225/1342] ospfd: fix double assignment in ospf_vl_set_timers Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- ospfd/ospf_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 3daaaca97..1772f24fe 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -886,7 +886,7 @@ static int ospf_vl_set_timers (struct ospf_vl_data *vl_data, struct ospf_vl_config_data *vl_config) { - struct interface *ifp = ifp = vl_data->vl_oi->ifp; + struct interface *ifp = vl_data->vl_oi->ifp; /* Virtual Link data initialised to defaults, so only set if a value given */ if (vl_config->hello_interval) From d1da1e9d18f46d80da4e91fdabafb03fa4272a01 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:07 +0200 Subject: [PATCH 1226/1342] pimd: don't leak original_s_route on error original_s_route is allocated on the heap and was not freed during the error case. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- pimd/pim_static.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 5114901da..078beab24 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -196,6 +196,10 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr pim_static_route_free(s_route); } + if (original_s_route) { + pim_static_route_free(original_s_route); + } + return -1; } From 93ad10e27beebb0416cf33d2f0acf96425064a48 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:08 +0200 Subject: [PATCH 1227/1342] ripd: print md5 auth digest correctly The dump of the md5 hash was missing one byte of the hash. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- ripd/ripd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index a5bc067a9..da9e7b007 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -746,9 +746,9 @@ rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv) zlog_debug (" family 0x%X type %d (MD5 data)", ntohs (rte->family), ntohs (rte->tag)); zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X", + "%02X%02X%02X%02X%02X%02X%02X%02X", p[0], p[1], p[2], p[3], p[4], p[5], p[6], - p[7], p[9], p[10], p[11], p[12], p[13], + p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } else From 5d9fae294228ad39d12913312485429b9129a3b0 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:09 +0200 Subject: [PATCH 1228/1342] vtysh: handle case if there is no match in "write terminal $daemon" While the DEFUN should match the list of clients registered in vtysh, it seems better to handle the case explicitly instead of relying on the client list and the DEFUN signature being in sync. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- vtysh/vtysh.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 75d1fc076..23653f041 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1899,6 +1899,9 @@ DEFUN (vtysh_write_terminal_daemon, break; } + if (i == array_size(vtysh_client)) + return CMD_ERR_NO_MATCH; + ret = vtysh_client_execute(&vtysh_client[i], "show running-config\n", stdout); return ret; From 99f567205357570091ba109caad126b7bafcf8ce Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 14 Jun 2016 20:07:10 +0200 Subject: [PATCH 1229/1342] vtysh: fix a memory leak in vtysh_client_execute buf is dynamically allocated and needs to be freed in the error handling path too. Signed-off-by: Christian Franke Signed-off-by: Christian Franke Acked-by: Donald Sharp --- vtysh/vtysh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 23653f041..d0cc2ebb5 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -137,6 +137,7 @@ vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) { fprintf (stderr, ERR_WHERE_STRING \ "warning - pbuf beyond buffer end.\n"); + XFREE(MTYPE_TMP, buf); return CMD_WARNING; } From be987c2804730f39828e2e047fb09f05ebd9915a Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 16 Jun 2016 11:26:44 -0400 Subject: [PATCH 1230/1342] lib: Clean command.c Removed dead code paths and fixed a typo. Signed-off-by: Quentin Young Signed-off-by: Quentin Young Tested-by: NetDEF CI System --- lib/command.c | 69 +-------------------------------------------------- 1 file changed, 1 insertion(+), 68 deletions(-) diff --git a/lib/command.c b/lib/command.c index bb94c2889..662f8a3d8 100644 --- a/lib/command.c +++ b/lib/command.c @@ -441,7 +441,7 @@ format_parser_end_multiple(struct format_parser_state *state) char *dummy; if (!state->in_multiple) - format_parser_error(state, "Unepexted ')'"); + format_parser_error(state, "Unexpected ')'"); if (vector_active(state->curvect) == 0) format_parser_error(state, "Empty multiple section"); @@ -785,54 +785,6 @@ cmd_node_vector (vector v, enum node_type ntype) return cnode->cmd_vector; } -#if 0 -/* Filter command vector by symbol. This function is not actually used; - * should it be deleted? */ -static int -cmd_filter_by_symbol (char *command, char *symbol) -{ - int i, lim; - - if (strcmp (symbol, "IPV4_ADDRESS") == 0) - { - i = 0; - lim = strlen (command); - while (i < lim) - { - if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/')) - return 1; - i++; - } - return 0; - } - if (strcmp (symbol, "STRING") == 0) - { - i = 0; - lim = strlen (command); - while (i < lim) - { - if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-')) - return 1; - i++; - } - return 0; - } - if (strcmp (symbol, "IFNAME") == 0) - { - i = 0; - lim = strlen (command); - while (i < lim) - { - if (! isalnum ((int) command[i])) - return 1; - i++; - } - return 0; - } - return 0; -} -#endif - /* Completion match types. */ enum match_type { @@ -1145,14 +1097,6 @@ cmd_ipv6_prefix_match (const char *str) if (mask < 0 || mask > 128) return no_match; -/* I don't know why mask < 13 makes command match partly. - Forgive me to make this comments. I Want to set static default route - because of lack of function to originate default in ospf6d; sorry - yasu - if (mask < 13) - return partly_match; -*/ - return exact_match; } @@ -2458,15 +2402,6 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib *status = CMD_ERR_AMBIGUOUS; return NULL; } - /* - else if (ret == 2) - { - vector_free (cmd_vector); - cmd_matches_free(&matches); - *status = CMD_ERR_NO_MATCH; - return NULL; - } - */ } /* Prepare match vector. */ @@ -2538,8 +2473,6 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib memcpy (lcdstr, matchvec->index[0], lcd); lcdstr[lcd] = '\0'; - /* match_str = (char **) &lcdstr; */ - /* Free matchvec. */ for (i = 0; i < vector_active (matchvec); i++) { From 54f1476c2ab201808fae1ec9f2ee1a5460f7882b Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 20 Jun 2016 13:58:05 -0400 Subject: [PATCH 1231/1342] zebra: Change bitwise operations to purpose-built macros Some bitfields for zebra_debug_* flags were being modified with bitwise operators instead of the purpose-built macros in lib/zebra.h. Changed such instances to use the macros. Signed-off-by: Quentin Young Signed-off-by: Quentin Young Acked-by: Jafar Al-Gharaibeh Tested-by: NetDEF CI System --- zebra/debug.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/zebra/debug.c b/zebra/debug.c index 5dd38f00d..7d023ce5a 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -111,8 +111,8 @@ DEFUN (debug_zebra_packet, "Debug option set for zebra packet\n") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; - zebra_debug_packet |= ZEBRA_DEBUG_SEND; - zebra_debug_packet |= ZEBRA_DEBUG_RECV; + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); return CMD_SUCCESS; } @@ -127,11 +127,11 @@ DEFUN (debug_zebra_packet_direct, { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet |= ZEBRA_DEBUG_SEND; + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet |= ZEBRA_DEBUG_RECV; + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); if (strncmp ("detail", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet |= ZEBRA_DEBUG_DETAIL; + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_DETAIL); return CMD_SUCCESS; } @@ -147,10 +147,10 @@ DEFUN (debug_zebra_packet_detail, { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet |= ZEBRA_DEBUG_SEND; + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet |= ZEBRA_DEBUG_RECV; - zebra_debug_packet |= ZEBRA_DEBUG_DETAIL; + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); + SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_DETAIL); return CMD_SUCCESS; } @@ -246,9 +246,9 @@ DEFUN (no_debug_zebra_packet_direct, "Debug option set for send packet\n") { if (strncmp ("send", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet &= ~ZEBRA_DEBUG_SEND; + UNSET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) - zebra_debug_packet &= ~ZEBRA_DEBUG_RECV; + UNSET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); return CMD_SUCCESS; } From 56ae5c4847f53f10e2151039556ec76a7a94c7fb Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Fri, 17 Jun 2016 16:01:12 -0500 Subject: [PATCH 1232/1342] zserv: get rid of code duplication in nexthop_lookup[_mrib] functions z[send/read]_ipv4_nexthop_lookup functions have been duplicated for multicast mrib lookup. The mrib versions are identical to the unicast versions except for a couple of places. The differences do not justify duplicating two functions and 80 lines of codes. Code refactoring and an if statement with a few lines of code are enough to handle the differences with a lot less and cleaner code. Signed-off-by: Jafar Al-Gharaibeh Signed-off-by: Jafar Al-Gharaibeh Tested-by: NetDEF CI System --- zebra/zserv.c | 121 +++++++++++--------------------------------------- 1 file changed, 27 insertions(+), 94 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index f0e8d121f..2c0c5b464 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -585,6 +585,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, } num++; } + stream_putc_at (s, nump, num); } else @@ -599,9 +600,14 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr, } #endif /* HAVE_IPV6 */ +/* + In the case of ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB: + query unicast rib if nexthop is not found on mrib + and return both route metric and protocol distance. +*/ static int zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, - vrf_id_t vrf_id) + int cmd, vrf_id_t vrf_id) { struct stream *s; struct rib *rib; @@ -609,92 +615,32 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, u_char num; struct nexthop *nexthop; - /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id); - /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, vrf_id); + zserv_create_header (s, cmd, vrf_id); stream_put_in_addr (s, &addr); - if (rib) - { - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: Matching rib entry found.", __func__); - stream_putl (s, rib->metric); - num = 0; - nump = stream_get_endp(s); - 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) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - { - stream_putc (s, nexthop->type); - switch (nexthop->type) - { - case ZEBRA_NEXTHOP_IPV4: - stream_put_in_addr (s, &nexthop->gate.ipv4); - break; - case ZEBRA_NEXTHOP_IPV4_IFINDEX: - stream_put_in_addr (s, &nexthop->gate.ipv4); - stream_putl (s, nexthop->ifindex); - break; - case ZEBRA_NEXTHOP_IFINDEX: - case ZEBRA_NEXTHOP_IFNAME: - stream_putl (s, nexthop->ifindex); - break; - default: - /* do nothing */ - break; - } - num++; - } - stream_putc_at (s, nump, num); - } - else + /* Lookup nexthop - eBGP excluded */ + if (cmd == ZEBRA_IPV4_NEXTHOP_LOOKUP) + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id); + else /* ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB */ { - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: No matching rib entry found.", __func__); - stream_putl (s, 0); - stream_putc (s, 0); + rib = rib_match_ipv4_multicast (addr, NULL, vrf_id); + /* handle the distance field here since + * it is only needed for MRIB command */ + if (rib) + stream_putc (s, rib->distance); + else + stream_putc (s, 0); /* distance */ } - stream_putw_at (s, 0, stream_get_endp (s)); - - return zebra_server_send_message(client); -} - -/* - Modified version of zsend_ipv4_nexthop_lookup(): - Query unicast rib if nexthop is not found on mrib. - Returns both route metric and protocol distance. -*/ -static int -zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, - struct rib *rib) -{ - struct stream *s; - unsigned long nump; - u_char num; - struct nexthop *nexthop; - - /* Get output stream. */ - s = client->obuf; - stream_reset (s); - - /* Fill in result. */ - zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, - rib ? rib->vrf_id : VRF_DEFAULT); - stream_put_in_addr (s, &addr); - if (rib) { - stream_putc (s, rib->distance); + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Matching rib entry found.", __func__); stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); /* remember position for nexthop_num */ @@ -725,12 +671,13 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, } num++; } - + stream_putc_at (s, nump, num); /* store nexthop_num */ } else { - stream_putc (s, 0); /* distance */ + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: No matching rib entry found.", __func__); stream_putl (s, 0); /* metric */ stream_putc (s, 0); /* nexthop_num */ } @@ -1143,7 +1090,7 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) /* Nexthop lookup for IPv4. */ static int -zread_ipv4_nexthop_lookup (struct zserv *client, u_short length, +zread_ipv4_nexthop_lookup (int cmd, struct zserv *client, u_short length, vrf_id_t vrf_id) { struct in_addr addr; @@ -1153,20 +1100,8 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length, if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: looking up %s", __func__, inet_ntop (AF_INET, &addr, buf, BUFSIZ)); - return zsend_ipv4_nexthop_lookup (client, addr, vrf_id); -} - -/* MRIB Nexthop lookup for IPv4. */ -static int -zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length, - vrf_id_t vrf_id) -{ - struct in_addr addr; - struct rib *rib; - addr.s_addr = stream_get_ipv4 (client->ibuf); - rib = rib_match_ipv4_multicast (addr, NULL, vrf_id); - return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib); + return zsend_ipv4_nexthop_lookup (client, addr, cmd, vrf_id); } /* Nexthop lookup for IPv4. */ @@ -1695,10 +1630,8 @@ zebra_client_read (struct thread *thread) zebra_redistribute_default_delete (command, client, length, vrf_id); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP: - zread_ipv4_nexthop_lookup (client, length, vrf_id); - break; case ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB: - zread_ipv4_nexthop_lookup_mrib (client, length, vrf_id); + zread_ipv4_nexthop_lookup (command, client, length, vrf_id); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: From dafa05e65fe4b3b3ed5525443f554215ba14f42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 19 Jan 2017 17:27:01 +0200 Subject: [PATCH 1233/1342] nhrpd: implement next hop resolution protocol This provides DMVPN support and integrates to strongSwan. Please read README.nhrpd and README.kernel for more details. --- .gitignore | 2 + Makefile.am | 4 +- SERVICES | 1 + configure.ac | 27 +- lib/log.c | 5 + lib/log.h | 4 +- lib/memtypes.c | 14 + lib/route_types.txt | 2 + nhrpd/Makefile.am | 35 ++ nhrpd/README.kernel | 145 +++++++ nhrpd/README.nhrpd | 137 ++++++ nhrpd/debug.h | 42 ++ nhrpd/linux.c | 153 +++++++ nhrpd/list.h | 191 +++++++++ nhrpd/netlink.h | 24 ++ nhrpd/netlink_arp.c | 275 ++++++++++++ nhrpd/netlink_gre.c | 141 +++++++ nhrpd/nhrp_cache.c | 341 +++++++++++++++ nhrpd/nhrp_event.c | 280 +++++++++++++ nhrpd/nhrp_interface.c | 404 ++++++++++++++++++ nhrpd/nhrp_main.c | 246 +++++++++++ nhrpd/nhrp_nhs.c | 369 ++++++++++++++++ nhrpd/nhrp_packet.c | 312 ++++++++++++++ nhrpd/nhrp_peer.c | 860 ++++++++++++++++++++++++++++++++++++++ nhrpd/nhrp_protocol.h | 128 ++++++ nhrpd/nhrp_route.c | 345 +++++++++++++++ nhrpd/nhrp_shortcut.c | 402 ++++++++++++++++++ nhrpd/nhrp_vc.c | 217 ++++++++++ nhrpd/nhrp_vty.c | 928 +++++++++++++++++++++++++++++++++++++++++ nhrpd/nhrpd.h | 400 ++++++++++++++++++ nhrpd/os.h | 5 + nhrpd/reqid.c | 49 +++ nhrpd/resolver.c | 190 +++++++++ nhrpd/vici.c | 482 +++++++++++++++++++++ nhrpd/vici.h | 24 ++ nhrpd/zbuf.c | 219 ++++++++++ nhrpd/zbuf.h | 189 +++++++++ nhrpd/znl.c | 160 +++++++ nhrpd/znl.h | 29 ++ vtysh/Makefile.am | 1 + vtysh/vtysh.c | 1 + vtysh/vtysh.h | 5 +- zebra/client_main.c | 1 + zebra/zebra_rib.c | 2 + zebra/zebra_rnh.c | 21 +- zebra/zebra_vty.c | 2 + 46 files changed, 7803 insertions(+), 11 deletions(-) create mode 100644 nhrpd/Makefile.am create mode 100644 nhrpd/README.kernel create mode 100644 nhrpd/README.nhrpd create mode 100644 nhrpd/debug.h create mode 100644 nhrpd/linux.c create mode 100644 nhrpd/list.h create mode 100644 nhrpd/netlink.h create mode 100644 nhrpd/netlink_arp.c create mode 100644 nhrpd/netlink_gre.c create mode 100644 nhrpd/nhrp_cache.c create mode 100644 nhrpd/nhrp_event.c create mode 100644 nhrpd/nhrp_interface.c create mode 100644 nhrpd/nhrp_main.c create mode 100644 nhrpd/nhrp_nhs.c create mode 100644 nhrpd/nhrp_packet.c create mode 100644 nhrpd/nhrp_peer.c create mode 100644 nhrpd/nhrp_protocol.h create mode 100644 nhrpd/nhrp_route.c create mode 100644 nhrpd/nhrp_shortcut.c create mode 100644 nhrpd/nhrp_vc.c create mode 100644 nhrpd/nhrp_vty.c create mode 100644 nhrpd/nhrpd.h create mode 100644 nhrpd/os.h create mode 100644 nhrpd/reqid.c create mode 100644 nhrpd/resolver.c create mode 100644 nhrpd/vici.c create mode 100644 nhrpd/vici.h create mode 100644 nhrpd/zbuf.c create mode 100644 nhrpd/zbuf.h create mode 100644 nhrpd/znl.c create mode 100644 nhrpd/znl.h diff --git a/.gitignore b/.gitignore index a281555e4..a8da62f17 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ quagga-[0-9.][0-9.][0-9.]*.tar.gz quagga-[0-9.][0-9.][0-9.]*.tar.gz.asc .nfs* libtool +.libs .arch-inventory .arch-ids {arch} @@ -34,6 +35,7 @@ build .msg .rebase-* *~ +*.o *.loT m4/*.m4 !m4/ax_sys_weak_alias.m4 diff --git a/Makefile.am b/Makefile.am index 0cd75be8b..3dea48989 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib qpb fpm @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ +SUBDIRS = lib qpb fpm @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @NHRPD@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests -DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d \ +DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d nhrpd \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd diff --git a/SERVICES b/SERVICES index c69d0c1a7..0322d451d 100644 --- a/SERVICES +++ b/SERVICES @@ -18,3 +18,4 @@ ospf6d 2606/tcp ospfapi 2607/tcp isisd 2608/tcp pimd 2611/tcp +nhrpd 2612/tcp diff --git a/configure.ac b/configure.ac index e601da5d9..558984413 100755 --- a/configure.ac +++ b/configure.ac @@ -76,6 +76,7 @@ AC_PROG_CPP AM_PROG_CC_C_O AC_PROG_RANLIB AC_PROG_EGREP +PKG_PROG_PKG_CONFIG dnl autoconf 2.59 appears not to support AC_PROG_SED dnl AC_PROG_SED @@ -245,6 +246,8 @@ AC_ARG_ENABLE(ospfd, AS_HELP_STRING([--disable-ospfd], [do not build ospfd])) AC_ARG_ENABLE(ospf6d, AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) +AC_ARG_ENABLE(nhrpd, + AS_HELP_STRING([--disable-nhrpd], [do not build nhrpd])) AC_ARG_ENABLE(watchquagga, AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) AC_ARG_ENABLE(isisd, @@ -1190,6 +1193,17 @@ else fi AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") +if test x"$opsys" != x"gnu-linux"; then + dnl NHRPd works currently with Linux only. + enable_nhrpd="no" +fi +if test "${enable_nhrpd}" = "no";then + NHRPD="" +else + NHRPD="nhrpd" +fi +AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd") + if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else @@ -1245,6 +1259,7 @@ AC_SUBST(RIPD) AC_SUBST(RIPNGD) AC_SUBST(OSPFD) AC_SUBST(OSPF6D) +AC_SUBST(NHRPD) AC_SUBST(WATCHQUAGGA) AC_SUBST(ISISD) AC_SUBST(PIMD) @@ -1279,6 +1294,14 @@ fi AC_SUBST(HAVE_LIBPCREPOSIX) AC_SUBST(LIB_REGEX) +dnl ------------------ +dnl check C-Ares library +dnl ------------------ +if test "${enable_nhrpd}" != "no";then + PKG_CHECK_MODULES([CARES], [libcares]) +fi + + dnl ------------------ dnl check Net-SNMP library dnl ------------------ @@ -1555,6 +1578,7 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID) AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID) AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID) AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID) +AC_DEFINE_UNQUOTED(PATH_NHRPD_PID, "$quagga_statedir/nhrpd.pid",nhrpd PID) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID) AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID) AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID) @@ -1565,6 +1589,7 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket) AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket) AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket) +AC_DEFINE_UNQUOTED(NHRP_VTYSH_PATH, "$quagga_statedir/nhrpd.vty",nhrpd vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket) AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket) AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory) @@ -1592,7 +1617,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile - pimd/Makefile + pimd/Makefile nhrpd/Makefile tests/bgpd.tests/Makefile tests/libzebra.tests/Makefile redhat/Makefile diff --git a/lib/log.c b/lib/log.c index 42b7717ee..d4370669c 100644 --- a/lib/log.c +++ b/lib/log.c @@ -53,6 +53,7 @@ const char *zlog_proto_names[] = "ISIS", "PIM", "MASC", + "NHRP", NULL, }; @@ -986,6 +987,8 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_BGP; else if (strncmp (s, "ba", 2) == 0) return ZEBRA_ROUTE_BABEL; + else if (strncmp (s, "n", 1) == 0) + return ZEBRA_ROUTE_NHRP; } if (afi == AFI_IP6) { @@ -1005,6 +1008,8 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_BGP; else if (strncmp (s, "ba", 2) == 0) return ZEBRA_ROUTE_BABEL; + else if (strncmp (s, "n", 1) == 0) + return ZEBRA_ROUTE_NHRP; } return -1; } diff --git a/lib/log.h b/lib/log.h index 7aa0896b7..59968aeec 100644 --- a/lib/log.h +++ b/lib/log.h @@ -24,6 +24,7 @@ #define _ZEBRA_LOG_H #include +#include /* Here is some guidance on logging levels to use: * @@ -54,7 +55,8 @@ typedef enum ZLOG_OSPF6, ZLOG_ISIS, ZLOG_PIM, - ZLOG_MASC + ZLOG_MASC, + ZLOG_NHRP, } zlog_proto_t; /* If maxlvl is set to ZLOG_DISABLED, then no messages will be sent diff --git a/lib/memtypes.c b/lib/memtypes.c index 8abe99d2a..ba2bacfa8 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -280,6 +280,19 @@ struct memory_list memory_list_pim[] = { -1, NULL }, }; +struct memory_list memory_list_nhrp[] = +{ + { MTYPE_NHRP_IF, "NHRP interface" }, + { MTYPE_NHRP_VC, "NHRP virtual connection" }, + { MTYPE_NHRP_PEER, "NHRP peer entry" }, + { MTYPE_NHRP_CACHE, "NHRP cache entry" }, + { MTYPE_NHRP_NHS, "NHRP next hop server" }, + { MTYPE_NHRP_REGISTRATION, "NHRP registration entries" }, + { MTYPE_NHRP_SHORTCUT, "NHRP shortcut" }, + { MTYPE_NHRP_ROUTE, "NHRP routing entry" }, + { -1, NULL } +}; + struct memory_list memory_list_vtysh[] = { { MTYPE_VTYSH_CONFIG, "Vtysh configuration", }, @@ -297,5 +310,6 @@ struct mlist mlists[] __attribute__ ((unused)) = { { memory_list_isis, "ISIS" }, { memory_list_bgp, "BGP" }, { memory_list_pim, "PIM" }, + { memory_list_nhrp, "NHRP" }, { NULL, NULL}, }; diff --git a/lib/route_types.txt b/lib/route_types.txt index 1b8560793..811d24e09 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -60,6 +60,7 @@ ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM" ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS" ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR" ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel" +ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, "NHRP" ## help strings ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" @@ -76,3 +77,4 @@ ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)" ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)" ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)" ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)" +ZEBRA_ROUTE_NHRP, "Next Hop Resolution Protocol (NHRP)" diff --git a/nhrpd/Makefile.am b/nhrpd/Makefile.am new file mode 100644 index 000000000..00ecc7f3f --- /dev/null +++ b/nhrpd/Makefile.am @@ -0,0 +1,35 @@ +## Process this file with automake to produce Makefile.in. + +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DQUAGGA_NO_DEPRECATED_INTERFACES +DEFS = @DEFS@ @CARES_CFLAGS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +AM_CFLAGS = $(PICFLAGS) #$(WERROR) +AM_LDFLAGS = $(PICLDFLAGS) + +sbin_PROGRAMS = nhrpd + +nhrpd_SOURCES = \ + zbuf.c \ + znl.c \ + resolver.c \ + linux.c \ + netlink_arp.c \ + netlink_gre.c \ + vici.c \ + reqid.c \ + nhrp_event.c \ + nhrp_packet.c \ + nhrp_interface.c \ + nhrp_vc.c \ + nhrp_peer.c \ + nhrp_cache.c \ + nhrp_nhs.c \ + nhrp_route.c \ + nhrp_shortcut.c \ + nhrp_vty.c \ + nhrp_main.c + +nhrpd_LDADD = ../lib/libzebra.la @LIBCAP@ @CARES_LIBS@ + +#dist_examples_DATA = nhrpd.conf.sample diff --git a/nhrpd/README.kernel b/nhrpd/README.kernel new file mode 100644 index 000000000..5831316f1 --- /dev/null +++ b/nhrpd/README.kernel @@ -0,0 +1,145 @@ +KERNEL REQUIREMENTS +=================== + +The linux kernel has had various major regressions, performance +issues and subtle bugs (especially in pmtu). Here is a short list +of some -stable kernels and the first point release that is supposedly +working well with opennhrp/dmvpn: + 3.12.8 or later + 3.14.54 or later + 3.18.22 or later[1] + +[1] But you need to apply the following two backported commits: + 3cdaa5be9e ipv4: Don't increase PMTU with Datagram Too Big message + cb6ccf09d6 route: Use ipv4_mtu instead of raw rt_pmtu + +See below for list of known issues in various kernel versions. + +Kernels earlier than 3.12 need CONFIG_ARPD enabled in the configuration. +Many distributions do not enable it by default, and you may need to +compile your own kernel. + +KERNEL BUGS +=========== + +DMVPN and mGRE support in the kernel has been brittle. There are various +regressions in multiple kernel versions. + +This list tries to collect them to one source of information: + +- forward pmtu is disabled intentionally (but tunnel devices rely on it) + Broken since 3.14-rc1: + commit "ipv4: introduce ip_dst_mtu_maybe_forward and protect forwarding path against pmtu spoofing" + Workaround: + Set sysctl net.ipv4.ip_forward_use_pmtu=1 + (Should fix kernel to have this by default on for tunnel devices) + +- subtle path mtu mishandling issues + Broken since (uncertain) + Fixed in 4.1-rc2: + commit "ipv4: Don't increase PMTU with Datagram Too Big message." + commit "route: Use ipv4_mtu instead of raw rt_pmtu" + +- fragmentation of large packets inside tunnel not working + Broken since 3.11-rc1 + commit "ip_tunnels: Use skb-len to PMTU check." + Fixed in 3.14.54, 3.18.22, 4.1.9, 4.2-rc3 + commit "ip_tunnel: fix ipv4 pmtu check to honor inner ip header df" + +- ipsec will crash during xfrm gc + Broke since 3.15-rc1 + commit "flowcache: Make flow cache name space aware" + Fixed in 3.18.10, 4.0 + commit "flowcache: Fix kernel panic in flow_cache_flush_task" + +- TSO on GRE tunnels failed, and resulted in very slow performance + Broke since 3.14.24, 3.18-rc3 + commit "gre: Use inner mac length when computing tunnel length" + Fixed in 3.14.30, 3.18.4 + commit "gre: fix the inner mac header in nbma tunnel xmit path" + commit "gre: Set inner mac header in gro complete" + +- NAPI GRO handling was broken; causing immediate crash (32-bit only?) + Broken since 3.13-rc1 + commit "net: gro: allow to build full sized skb" + Fixed 3.14.5, 3.15-rc7 + commit "net: gro: make sure skb->cb[] initial content has not to be zero" + +- ip_gre dst caching broke NBMA GRE tunnels + Broken since 3.14-rc1 + Fixed in 3.14.5, 3.15-rc6 + commit "ipv4: ip_tunnels: disable cache for nbma gre tunnels" + +- Few packets can be lost when neighbor entry is in NUD_PROBE state, + and there is continuous traffic to it. + Broken since dawn of time + Fixed in 3.15-rc1 + commit "neigh: probe application via netlink in NUD_PROBE" + +- GRO was implemented for GRE, but the hw capabilities were not updated + correctly. In practice forwarding from non-GRE (physical) interface + to GRE interface with gro/gso/tx offloads enabled (also on the target + interface) does not work properly. + Broken around 3.9 to 3.11, need to check details. + +- recvfrom() returned incorrect NBMA address, breaking NAT detection + Broken since 3.10-rc1 + commit "GRE: Refactor GRE tunneling code." + Fixed in 3.10.27, 3.12.8, 3.13-rc7 + commit "ip_gre: fix msg_name parsing for recvfrom/recvmsg" + +- sendto() was broken causing opennhrp not work at all + Broken since 3.10-rc1 + commit "GRE: Refactor GRE tunneling code." + Fixed in 3.10.12, 3.11-rc6 + commit "ip_gre: fix ipgre_header to return correct offset" + +- PMTU was broken due to GRE driver rewrite + Broken since 3.10-rc1 + commit "GRE: Refactor GRE tunneling code." + Fixed in 3.11-rc1 + commit "ip_tunnels: Use skb-len to PMTU check." + +- PMTU was broken due to routing cache removal + Broken since 3.6-rc1 + commit "ipv4: Cache input routes in fib_info nexthops" + Fixed in 3.11-rc1 + commit "ipv4: use next hop exceptions also for input routes" + + 3 other commits + Patches exist for 3.10, but they were not approved to 3.10-stable. + +- Race condition during bootup: changing ARP flag did not flush + existing neighbor entries, causing problems if traffic was routed + to gre interface before opennhrp was running. + Broken since dawn of time + Fixed in 3.11-rc1 + commit "arp: flush arp cache on IFF_NOARP change" + +- Crash in IPsec + Broken since 3.9-rc1 + commit "xfrm: removes a superfluous check and add a statistic" + Fixed in 3.10-rc3 + commit "xfrm: properly handle invalid states as an error" + +- An incorrect ip_gre change broke NHRP traffic over GRE + Broken since 3.8-rc2 + commit "ip_gre: make ipgre_tunnel_xmit() not parse network header as IP unconditionally" + Fixed in 3.8.5, 3.9-rc4 + commit "Revert "ip_gre: make ipgre_tunnel_xmit() not parse network header as IP unconditionally"" + +- Multicast traffic over mGRE was broken. + Broken since 2.6.34-rc2 + commit "gre: fix hard header destination address checking" + Fixed in 2.6.39-rc2 + commit "net: gre: provide multicast mappings for ipv4 and ipv6" + +- Serious performance issues causing small throughput on medium to large DMVPN networks + Broken since dawn of time + Fixed in 2.6.35 + multiple commits rewriting ipsec caching + +- Even though around 2.6.24 is the first version where opennhrp started + to work, there has been various PMTU, performance, and functionality + bugs before 2.6.34. That's one of the first version I consider stable + wrt. to opennhrp functionality. + diff --git a/nhrpd/README.nhrpd b/nhrpd/README.nhrpd new file mode 100644 index 000000000..569b3f446 --- /dev/null +++ b/nhrpd/README.nhrpd @@ -0,0 +1,137 @@ +Quagga / NHRP Design and Configuration Notes +============================================ + +Quagga/NHRP is an NHRP (RFC2332) implementation for Linux. The primary +use case is to implement DMVPN. The aim is thus to be compatible with +Cisco DMVPN (and potentially with FlexVPN in the future). + + +Current Status +-------------- + +- IPsec integration with strongSwan (requires patched strongSwan) +- IPv4 over IPv4 NBMA GRE +- IPv6 over IPv4 NBMA GRE -- majority of code exist; but is not tested +- Spoke (NHC) functionality complete +- Hub (NHS) functionality complete +- Multicast support is not done yet + (so OSPF will not work, use BGP for now) + +The code is not (yet) compatible with Cisco FlexVPN style DMVPN. It +would require relaying IKEv2 routing messages from strongSwan to nhrpd +and parsing that. It is doable, but not implemented for the time being. + + +Routing Design +-------------- + +In contrast to opennhrp routing design, Quagga/NHRP routes each NHRP +domain address individually (similar to Cisco FlexVPN). + +To create NBMA GRE tunnel you might use following: + ip tunnel add gre1 mode gre key 42 ttl 64 dev eth0 + ip addr add 10.255.255.2/32 dev gre1 + ip link set gre1 up + +This has two important differences compared to opennhrp setup: + 1. The 'tunnel add' now specifies physical device binding. Quagga/NHRP + wants to know stable protocol address to NBMA address mapping. Thus, + add 'dev ' binding, or specify 'local '. If + neither of this is specified, NHRP will not be enabled on the interface. + Alternatively you can skip 'dev' binding on tunnel if you allow + nhrpd to manage it using 'tunnel source' command (see below). + + 2. The 'addr add' now has host prefix. In opennhrp you would have used + the GRE subnet prefix length here instead, e.g. /24. + +Quagga/NHRP will automatically create additional host routes pointing to +gre1 when a connection with these hosts is established. The gre1 subnet +should be announced by routing protocol. This allows routing protocol +to decide which is the closest hub and get the gre addresses' traffic. + +The second benefit is that hubs can then easily exchange host prefixes +of directly connected gre addresses. And thus routing of gre addresses +inside hubs is based on routing protocol's shortest path choice -- not +on random choice from next hop server list. + + +Configuring nhrpd +----------------- + +The configuration is done using vtysh, and most commands do what they +do in Cisco. As minimal configuration example one can do: + configure terminal + interface gre1 + tunnel protection vici profile dmvpn + tunnel source eth0 + ip nhrp network-id 1 + ip nhrp shortcut + ip nhrp registration no-unique + ip nhrp nhs dynamic nbma hubs.example.com + +There's important notes about the "ip nhrp nhs" command: + + 1. The 'dynamic' works only against Cisco (or nhrpd), but is not + compatible with opennhrp. To use dynamic detection of opennhrp hub's + protocol address use the GRE broadcast address there. For the above + example of 10.255.255.0/24 the configuration should read instead: + ip nhrp nhs 10.255.255.255 nbma hubs.example.com + + 2. nbma works like opennhrp dynamic-map. That is, all of the + A-records are configured as NBMA addresses of different hubs, and + each hub protocol address will be dynamically detected. + + +Hub functionality +----------------- + +Sending Traffic Indication (redirect) notifications is now accomplished +using NFLOG. + +Use: +iptables -A FORWARD -i gre1 -o gre1 \ + -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \ + --hashlimit-mode srcip,dstip --hashlimit-srcmask 16 --hashlimit-dstmask 16 \ + --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128 + +or similar to get rate-limited samples of the packets that match traffic +flow needing redirection. This kernel NFLOG target's nflog-group is configured +in global nhrp config with: + nhrp nflog-group 1 + +To start sending these traffic notices out from hubs, use the nhrp per-interface +directive: + ip nhrp redirect + +opennhrp used PF_PACKET and tried to create packet filter to get only +the packets of interest. Though, this was bad if shortcut fails to +establish (remote policy, or both are behind NAT or restrictive +firewalls), all of the relayaed traffic would match always. + + +Getting information via vtysh +----------------------------- + +Some commands of interest: + - show dmvpn + - show ip nhrp cache + - show ip nhrp shortcut + - show ip route nhrp + - clear ip nhrp cache + - clear ip nhrp shortcut + + +Integration with strongSwan +--------------------------- + +Contrary to opennhrp, Quagga/NHRP has tight integration with IKE daemon. +Currently strongSwan is supported using the VICI protocol. strongSwan +is connected using UNIX socket (hardcoded now as /var/run/charon.vici). +Thus nhrpd needs to be run as user that can open that file. + +Currently, you will need patched strongSwan. The working tree is at: + http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras + +And the branch with patches against latest release are: + http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras-release + diff --git a/nhrpd/debug.h b/nhrpd/debug.h new file mode 100644 index 000000000..b1f49aa8b --- /dev/null +++ b/nhrpd/debug.h @@ -0,0 +1,42 @@ +#include "log.h" + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define likely(_x) __builtin_expect(!!(_x), 1) +#define unlikely(_x) __builtin_expect(!!(_x), 0) +#else +#define likely(_x) !!(_x) +#define unlikely(_x) !!(_x) +#endif + +#define NHRP_DEBUG_COMMON (1 << 0) +#define NHRP_DEBUG_KERNEL (1 << 1) +#define NHRP_DEBUG_IF (1 << 2) +#define NHRP_DEBUG_ROUTE (1 << 3) +#define NHRP_DEBUG_VICI (1 << 4) +#define NHRP_DEBUG_EVENT (1 << 5) +#define NHRP_DEBUG_ALL (0xFFFF) + +extern unsigned int debug_flags; + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + +#define debugf(level, ...) \ + do { \ + if (unlikely(debug_flags & level)) \ + zlog_debug(__VA_ARGS__); \ + } while(0) + +#elif defined __GNUC__ + +#define debugf(level, _args...) \ + do { \ + if (unlikely(debug_flags & level)) \ + zlog_debug(_args); \ + } while(0) + +#else + +static inline void debugf(int level, const char *format, ...) { } + +#endif + diff --git a/nhrpd/linux.c b/nhrpd/linux.c new file mode 100644 index 000000000..1e9c69eb8 --- /dev/null +++ b/nhrpd/linux.c @@ -0,0 +1,153 @@ +/* NHRP daemon Linux specific glue + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nhrp_protocol.h" +#include "os.h" +#include "netlink.h" + +static int nhrp_socket_fd = -1; + +int os_socket(void) +{ + if (nhrp_socket_fd < 0) + nhrp_socket_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_NHRP)); + return nhrp_socket_fd; +} + +int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, size_t addrlen) +{ + struct sockaddr_ll lladdr; + struct iovec iov = { + .iov_base = (void*) buf, + .iov_len = len, + }; + struct msghdr msg = { + .msg_name = &lladdr, + .msg_namelen = sizeof(lladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + int status; + + if (addrlen > sizeof(lladdr.sll_addr)) + return -1; + + memset(&lladdr, 0, sizeof(lladdr)); + lladdr.sll_family = AF_PACKET; + lladdr.sll_protocol = htons(ETH_P_NHRP); + lladdr.sll_ifindex = ifindex; + lladdr.sll_halen = addrlen; + memcpy(lladdr.sll_addr, addr, addrlen); + + status = sendmsg(nhrp_socket_fd, &msg, 0); + if (status < 0) + return -1; + + return 0; +} + +int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, size_t *addrlen) +{ + struct sockaddr_ll lladdr; + struct iovec iov = { + .iov_base = buf, + .iov_len = *len, + }; + struct msghdr msg = { + .msg_name = &lladdr, + .msg_namelen = sizeof(lladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + int r; + + r = recvmsg(nhrp_socket_fd, &msg, MSG_DONTWAIT); + if (r < 0) + return r; + + *len = r; + *ifindex = lladdr.sll_ifindex; + + if (*addrlen <= (size_t) lladdr.sll_addr) { + if (memcmp(lladdr.sll_addr, "\x00\x00\x00\x00", 4) != 0) { + memcpy(addr, lladdr.sll_addr, lladdr.sll_halen); + *addrlen = lladdr.sll_halen; + } else { + *addrlen = 0; + } + } + + return 0; +} + +static int linux_configure_arp(const char *iface, int on) +{ + struct ifreq ifr; + + strncpy(ifr.ifr_name, iface, IFNAMSIZ); + if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr)) + return -1; + + if (on) + ifr.ifr_flags &= ~IFF_NOARP; + else + ifr.ifr_flags |= IFF_NOARP; + + if (ioctl(nhrp_socket_fd, SIOCSIFFLAGS, &ifr)) + return -1; + + return 0; +} + +static int linux_icmp_redirect_off(const char *iface) +{ + char fname[256]; + int fd, ret = -1; + + sprintf(fname, "/proc/sys/net/ipv4/conf/%s/send_redirects", iface); + fd = open(fname, O_WRONLY); + if (fd < 0) + return -1; + if (write(fd, "0\n", 2) == 2) + ret = 0; + close(fd); + + return ret; +} + +int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af) +{ + int ret = -1; + + switch (af) { + case AF_INET: + ret = linux_icmp_redirect_off("all"); + ret |= linux_icmp_redirect_off(ifname); + ret |= netlink_configure_arp(ifindex, AF_INET); + ret |= linux_configure_arp(ifname, 1); + break; + } + + return ret; +} diff --git a/nhrpd/list.h b/nhrpd/list.h new file mode 100644 index 000000000..32f21ed5e --- /dev/null +++ b/nhrpd/list.h @@ -0,0 +1,191 @@ +/* Linux kernel style list handling function + * + * Written from scratch by Timo Teräs , but modeled + * after the linux kernel code. + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef LIST_H +#define LIST_H + +#ifndef NULL +#define NULL 0L +#endif + +#ifndef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next; + struct hlist_node **pprev; +}; + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline int hlist_hashed(const struct hlist_node *n) +{ + return n->pprev != NULL; +} + +static inline void hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + + *pprev = next; + if (next) + next->pprev = pprev; + + n->next = NULL; + n->pprev = NULL; +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + + n->next = first; + if (first) + first->pprev = &n->next; + n->pprev = &h->first; + h->first = n; +} + +static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *prev) +{ + n->next = prev->next; + n->pprev = &prev->next; + prev->next = n; +} + +static inline struct hlist_node **hlist_tail_ptr(struct hlist_head *h) +{ + struct hlist_node *n = h->first; + if (n == NULL) + return &h->first; + while (n->next != NULL) + n = n->next; + return &n->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); pos = n) + +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_INITIALIZER(l) { .next = &l, .prev = &l } + +static inline void list_init(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +static inline int list_hashed(const struct list_head *n) +{ + return n->next != n && n->next != NULL; +} + +static inline int list_empty(const struct list_head *n) +{ + return !list_hashed(n); +} + +#define list_next(ptr, type, member) \ + (list_hashed(ptr) ? container_of((ptr)->next,type,member) : NULL) + +#define list_entry(ptr, type, member) container_of(ptr,type,member) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif diff --git a/nhrpd/netlink.h b/nhrpd/netlink.h new file mode 100644 index 000000000..f05596ba1 --- /dev/null +++ b/nhrpd/netlink.h @@ -0,0 +1,24 @@ +/* NHRP netlink/neighbor table API + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +union sockunion; +struct interface; + +extern int netlink_nflog_group; +extern int netlink_req_fd; + +int netlink_init(void); +int netlink_configure_arp(unsigned int ifindex, int pf); +void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma); +void netlink_set_nflog_group(int nlgroup); + +void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr); +void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index); diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c new file mode 100644 index 000000000..a418ecabd --- /dev/null +++ b/nhrpd/netlink_arp.c @@ -0,0 +1,275 @@ +/* NHRP netlink/neighbor table arpd code + * Copyright (c) 2014-2016 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "nhrpd.h" +#include "netlink.h" +#include "znl.h" + +int netlink_req_fd = -1; +int netlink_nflog_group; +static int netlink_log_fd = -1; +static struct thread *netlink_log_thread; +static int netlink_listen_fd = -1; + +typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb); + +void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma) +{ + struct nlmsghdr *n; + struct ndmsg *ndm; + struct zbuf *zb = zbuf_alloc(512); + + n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE); + ndm = znl_push(zb, sizeof(*ndm)); + *ndm = (struct ndmsg) { + .ndm_family = sockunion_family(proto), + .ndm_ifindex = ifp->ifindex, + .ndm_type = RTN_UNICAST, + .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED, + }; + znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto), family2addrsize(sockunion_family(proto))); + if (nbma) + znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma), family2addrsize(sockunion_family(nbma))); + znl_nlmsg_complete(zb, n); + zbuf_send(zb, netlink_req_fd); + zbuf_recv(zb, netlink_req_fd); + zbuf_free(zb); +} + +static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb) +{ + struct ndmsg *ndm; + struct rtattr *rta; + struct nhrp_cache *c; + struct interface *ifp; + struct zbuf payload; + union sockunion addr; + size_t len; + char buf[SU_ADDRSTRLEN]; + int state; + + ndm = znl_pull(zb, sizeof(*ndm)); + if (!ndm) return; + + sockunion_family(&addr) = AF_UNSPEC; + while ((rta = znl_rta_pull(zb, &payload)) != NULL) { + len = zbuf_used(&payload); + switch (rta->rta_type) { + case NDA_DST: + sockunion_set(&addr, ndm->ndm_family, zbuf_pulln(&payload, len), len); + break; + } + } + + ifp = if_lookup_by_index(ndm->ndm_ifindex); + if (!ifp || sockunion_family(&addr) == AF_UNSPEC) + return; + + c = nhrp_cache_get(ifp, &addr, 0); + if (!c) + return; + + if (msg->nlmsg_type == RTM_GETNEIGH) { + debugf(NHRP_DEBUG_KERNEL, "Netlink: who-has %s dev %s", + sockunion2str(&addr, buf, sizeof buf), + ifp->name); + + if (c->cur.type >= NHRP_CACHE_CACHED) { + nhrp_cache_set_used(c, 1); + netlink_update_binding(ifp, &addr, &c->cur.peer->vc->remote.nbma); + } + } else { + debugf(NHRP_DEBUG_KERNEL, "Netlink: update %s dev %s nud %x", + sockunion2str(&addr, buf, sizeof buf), + ifp->name, ndm->ndm_state); + + state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state : NUD_FAILED; + nhrp_cache_set_used(c, state == NUD_REACHABLE); + } +} + +static int netlink_route_recv(struct thread *t) +{ + uint8_t buf[ZNL_BUFFER_SIZE]; + int fd = THREAD_FD(t); + struct zbuf payload, zb; + struct nlmsghdr *n; + + zbuf_init(&zb, buf, sizeof(buf), 0); + while (zbuf_recv(&zb, fd) > 0) { + while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) { + debugf(NHRP_DEBUG_KERNEL, "Netlink: Received msg_type %u, msg_flags %u", + n->nlmsg_type, n->nlmsg_flags); + switch (n->nlmsg_type) { + case RTM_GETNEIGH: + case RTM_NEWNEIGH: + case RTM_DELNEIGH: + netlink_neigh_msg(n, &payload); + break; + } + } + } + + thread_add_read(master, netlink_route_recv, 0, fd); + + return 0; +} + +static void netlink_log_register(int fd, int group) +{ + struct nlmsghdr *n; + struct nfgenmsg *nf; + struct nfulnl_msg_config_cmd cmd; + struct zbuf *zb = zbuf_alloc(512); + + n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_CONFIG, NLM_F_REQUEST | NLM_F_ACK); + nf = znl_push(zb, sizeof(*nf)); + *nf = (struct nfgenmsg) { + .nfgen_family = AF_UNSPEC, + .version = NFNETLINK_V0, + .res_id = htons(group), + }; + cmd.command = NFULNL_CFG_CMD_BIND; + znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd)); + znl_nlmsg_complete(zb, n); + + zbuf_send(zb, fd); + zbuf_free(zb); +} + +static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb) +{ + struct nfgenmsg *nf; + struct rtattr *rta; + struct zbuf rtapl, pktpl; + struct interface *ifp; + struct nfulnl_msg_packet_hdr *pkthdr = NULL; + uint32_t *in_ndx = NULL; + + nf = znl_pull(zb, sizeof(*nf)); + if (!nf) return; + + memset(&pktpl, 0, sizeof(pktpl)); + while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) { + switch (rta->rta_type) { + case NFULA_PACKET_HDR: + pkthdr = znl_pull(&rtapl, sizeof(*pkthdr)); + break; + case NFULA_IFINDEX_INDEV: + in_ndx = znl_pull(&rtapl, sizeof(*in_ndx)); + break; + case NFULA_PAYLOAD: + pktpl = rtapl; + break; + /* NFULA_HWHDR exists and is supposed to contain source + * hardware address. However, for ip_gre it seems to be + * the nexthop destination address if the packet matches + * route. */ + } + } + + if (!pkthdr || !in_ndx || !zbuf_used(&pktpl)) + return; + + ifp = if_lookup_by_index(htonl(*in_ndx)); + if (!ifp) + return; + + nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl); +} + +static int netlink_log_recv(struct thread *t) +{ + uint8_t buf[ZNL_BUFFER_SIZE]; + int fd = THREAD_FD(t); + struct zbuf payload, zb; + struct nlmsghdr *n; + + netlink_log_thread = NULL; + + zbuf_init(&zb, buf, sizeof(buf), 0); + while (zbuf_recv(&zb, fd) > 0) { + while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) { + debugf(NHRP_DEBUG_KERNEL, "Netlink-log: Received msg_type %u, msg_flags %u", + n->nlmsg_type, n->nlmsg_flags); + switch (n->nlmsg_type) { + case (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_PACKET: + netlink_log_indication(n, &payload); + break; + } + } + } + + THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd); + + return 0; +} + +void netlink_set_nflog_group(int nlgroup) +{ + if (netlink_log_fd >= 0) { + THREAD_OFF(netlink_log_thread); + close(netlink_log_fd); + netlink_log_fd = -1; + } + netlink_nflog_group = nlgroup; + if (nlgroup) { + netlink_log_fd = znl_open(NETLINK_NETFILTER, 0); + netlink_log_register(netlink_log_fd, nlgroup); + THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd); + } +} + +int netlink_init(void) +{ + netlink_req_fd = znl_open(NETLINK_ROUTE, 0); + netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH); + thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd); + + return 0; +} + +int netlink_configure_arp(unsigned int ifindex, int pf) +{ + struct nlmsghdr *n; + struct ndtmsg *ndtm; + struct rtattr *rta; + struct zbuf *zb = zbuf_alloc(512); + int r; + + n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE); + ndtm = znl_push(zb, sizeof(*ndtm)); + *ndtm = (struct ndtmsg) { + .ndtm_family = pf, + }; + + znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache", 10); + + rta = znl_rta_nested_push(zb, NDTA_PARMS); + znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex); + znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1); + znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0); + znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0); + znl_rta_nested_complete(zb, rta); + + znl_nlmsg_complete(zb, n); + r = zbuf_send(zb, netlink_req_fd); + zbuf_recv(zb, netlink_req_fd); + zbuf_free(zb); + + return r; +} diff --git a/nhrpd/netlink_gre.c b/nhrpd/netlink_gre.c new file mode 100644 index 000000000..7cd30aa30 --- /dev/null +++ b/nhrpd/netlink_gre.c @@ -0,0 +1,141 @@ +/* NHRP netlink/GRE tunnel configuration code + * Copyright (c) 2014-2016 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "netlink.h" +#include "znl.h" + +static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, int ifindex) +{ + struct nlmsghdr *n; + struct ifinfomsg *ifi; + struct zbuf payload, rtapayload; + struct rtattr *rta; + + debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex); + + n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST); + ifi = znl_push(zb, sizeof(*ifi)); + *ifi = (struct ifinfomsg) { + .ifi_index = ifindex, + }; + znl_nlmsg_complete(zb, n); + + if (zbuf_send(zb, netlink_req_fd) < 0 || + zbuf_recv(zb, netlink_req_fd) < 0) + return -1; + + n = znl_nlmsg_pull(zb, &payload); + if (!n) return -1; + + if (n->nlmsg_type != RTM_NEWLINK) + return -1; + + ifi = znl_pull(&payload, sizeof(struct ifinfomsg)); + if (!ifi) + return -1; + + debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u", + ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags); + + if (ifi->ifi_index != ifindex) + return -1; + + while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) + if (rta->rta_type == IFLA_LINKINFO) + break; + if (!rta) return -1; + + payload = rtapayload; + while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) + if (rta->rta_type == IFLA_INFO_DATA) + break; + if (!rta) return -1; + + *data = rtapayload; + return 0; +} + +void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr) +{ + struct zbuf *zb = zbuf_alloc(8192), data, rtapl; + struct rtattr *rta; + + *link_index = 0; + *gre_key = 0; + saddr->s_addr = 0; + + if (__netlink_gre_get_data(zb, &data, ifindex) < 0) + goto err; + + while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { + switch (rta->rta_type) { + case IFLA_GRE_LINK: + *link_index = zbuf_get32(&rtapl); + break; + case IFLA_GRE_IKEY: + case IFLA_GRE_OKEY: + *gre_key = zbuf_get32(&rtapl); + break; + case IFLA_GRE_LOCAL: + saddr->s_addr = zbuf_get32(&rtapl); + break; + } + } +err: + zbuf_free(zb); +} + +void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index) +{ + struct nlmsghdr *n; + struct ifinfomsg *ifi; + struct rtattr *rta_info, *rta_data, *rta; + struct zbuf *zr = zbuf_alloc(8192), data, rtapl; + struct zbuf *zb = zbuf_alloc(8192); + size_t len; + + if (__netlink_gre_get_data(zr, &data, ifindex) < 0) + goto err; + + n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST); + ifi = znl_push(zb, sizeof(*ifi)); + *ifi = (struct ifinfomsg) { + .ifi_index = ifindex, + }; + rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO); + znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3); + rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA); + + znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index); + while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { + if (rta->rta_type == IFLA_GRE_LINK) + continue; + len = zbuf_used(&rtapl); + znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len); + } + + znl_rta_nested_complete(zb, rta_data); + znl_rta_nested_complete(zb, rta_info); + + znl_nlmsg_complete(zb, n); + zbuf_send(zb, netlink_req_fd); + zbuf_recv(zb, netlink_req_fd); +err: + zbuf_free(zb); + zbuf_free(zr); +} diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c new file mode 100644 index 000000000..447a814c0 --- /dev/null +++ b/nhrpd/nhrp_cache.c @@ -0,0 +1,341 @@ +/* NHRP cache + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "zebra.h" +#include "memory.h" +#include "thread.h" +#include "hash.h" +#include "nhrpd.h" + +#include "netlink.h" + +unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES]; + +const char * const nhrp_cache_type_str[] = { + [NHRP_CACHE_INVALID] = "invalid", + [NHRP_CACHE_INCOMPLETE] = "incomplete", + [NHRP_CACHE_NEGATIVE] = "negative", + [NHRP_CACHE_CACHED] = "cached", + [NHRP_CACHE_DYNAMIC] = "dynamic", + [NHRP_CACHE_NHS] = "nhs", + [NHRP_CACHE_STATIC] = "static", + [NHRP_CACHE_LOCAL] = "local", +}; + +static unsigned int nhrp_cache_protocol_key(void *peer_data) +{ + struct nhrp_cache *p = peer_data; + return sockunion_hash(&p->remote_addr); +} + +static int nhrp_cache_protocol_cmp(const void *cache_data, const void *key_data) +{ + const struct nhrp_cache *a = cache_data; + const struct nhrp_cache *b = key_data; + return sockunion_same(&a->remote_addr, &b->remote_addr); +} + +static void *nhrp_cache_alloc(void *data) +{ + struct nhrp_cache *p, *key = data; + + p = XMALLOC(MTYPE_NHRP_CACHE, sizeof(struct nhrp_cache)); + if (p) { + *p = (struct nhrp_cache) { + .cur.type = NHRP_CACHE_INVALID, + .new.type = NHRP_CACHE_INVALID, + .remote_addr = key->remote_addr, + .ifp = key->ifp, + .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list), + }; + nhrp_cache_counts[p->cur.type]++; + } + + return p; +} + +static void nhrp_cache_free(struct nhrp_cache *c) +{ + struct nhrp_interface *nifp = c->ifp->info; + + zassert(c->cur.type == NHRP_CACHE_INVALID && c->cur.peer == NULL); + zassert(c->new.type == NHRP_CACHE_INVALID && c->new.peer == NULL); + nhrp_cache_counts[c->cur.type]--; + notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE); + zassert(!notifier_active(&c->notifier_list)); + hash_release(nifp->cache_hash, c); + XFREE(MTYPE_NHRP_CACHE, c); +} + +struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote_addr, int create) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_cache key; + + if (!nifp->cache_hash) { + nifp->cache_hash = hash_create(nhrp_cache_protocol_key, nhrp_cache_protocol_cmp); + if (!nifp->cache_hash) + return NULL; + } + + key.remote_addr = *remote_addr; + key.ifp = ifp; + + return hash_get(nifp->cache_hash, &key, create ? nhrp_cache_alloc : NULL); +} + +static int nhrp_cache_do_free(struct thread *t) +{ + struct nhrp_cache *c = THREAD_ARG(t); + c->t_timeout = NULL; + nhrp_cache_free(c); + return 0; +} + +static int nhrp_cache_do_timeout(struct thread *t) +{ + struct nhrp_cache *c = THREAD_ARG(t); + c->t_timeout = NULL; + if (c->cur.type != NHRP_CACHE_INVALID) + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + return 0; +} + +static void nhrp_cache_update_route(struct nhrp_cache *c) +{ + struct prefix pfx; + struct nhrp_peer *p = c->cur.peer; + + sockunion2hostprefix(&c->remote_addr, &pfx); + + if (p && nhrp_peer_check(p, 1)) { + netlink_update_binding(p->ifp, &c->remote_addr, &p->vc->remote.nbma); + nhrp_route_announce(1, c->cur.type, &pfx, c->ifp, NULL, c->cur.mtu); + if (c->cur.type >= NHRP_CACHE_DYNAMIC) { + nhrp_route_update_nhrp(&pfx, c->ifp); + c->nhrp_route_installed = 1; + } else if (c->nhrp_route_installed) { + nhrp_route_update_nhrp(&pfx, NULL); + c->nhrp_route_installed = 0; + } + if (!c->route_installed) { + notifier_call(&c->notifier_list, NOTIFY_CACHE_UP); + c->route_installed = 1; + } + } else { + if (c->nhrp_route_installed) { + nhrp_route_update_nhrp(&pfx, NULL); + c->nhrp_route_installed = 0; + } + if (c->route_installed) { + sockunion2hostprefix(&c->remote_addr, &pfx); + notifier_call(&c->notifier_list, NOTIFY_CACHE_DOWN); + nhrp_route_announce(0, c->cur.type, &pfx, NULL, NULL, 0); + c->route_installed = 0; + } + } +} + +static void nhrp_cache_peer_notifier(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_cache *c = container_of(n, struct nhrp_cache, peer_notifier); + + switch (cmd) { + case NOTIFY_PEER_UP: + nhrp_cache_update_route(c); + break; + case NOTIFY_PEER_DOWN: + case NOTIFY_PEER_IFCONFIG_CHANGED: + notifier_call(&c->notifier_list, NOTIFY_CACHE_DOWN); + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + break; + case NOTIFY_PEER_NBMA_CHANGING: + if (c->cur.type == NHRP_CACHE_DYNAMIC) + c->cur.peer->vc->abort_migration = 1; + break; + } +} + +static void nhrp_cache_reset_new(struct nhrp_cache *c) +{ + THREAD_OFF(c->t_auth); + if (list_hashed(&c->newpeer_notifier.notifier_entry)) + nhrp_peer_notify_del(c->new.peer, &c->newpeer_notifier); + nhrp_peer_unref(c->new.peer); + memset(&c->new, 0, sizeof(c->new)); + c->new.type = NHRP_CACHE_INVALID; +} + +static void nhrp_cache_update_timers(struct nhrp_cache *c) +{ + THREAD_OFF(c->t_timeout); + + switch (c->cur.type) { + case NHRP_CACHE_INVALID: + if (!c->t_auth) + THREAD_TIMER_MSEC_ON(master, c->t_timeout, nhrp_cache_do_free, c, 10); + break; + default: + if (c->cur.expires) + THREAD_TIMER_ON(master, c->t_timeout, nhrp_cache_do_timeout, c, c->cur.expires - recent_relative_time().tv_sec); + break; + } +} + +static void nhrp_cache_authorize_binding(struct nhrp_reqid *r, void *arg) +{ + struct nhrp_cache *c = container_of(r, struct nhrp_cache, eventid); + char buf[SU_ADDRSTRLEN]; + + debugf(NHRP_DEBUG_COMMON, "cache: %s %s: %s", + c->ifp->name, sockunion2str(&c->remote_addr, buf, sizeof buf), + (const char *) arg); + + nhrp_reqid_free(&nhrp_event_reqid, r); + + if (arg && strcmp(arg, "accept") == 0) { + if (c->cur.peer) { + netlink_update_binding(c->cur.peer->ifp, &c->remote_addr, NULL); + nhrp_peer_notify_del(c->cur.peer, &c->peer_notifier); + nhrp_peer_unref(c->cur.peer); + } + nhrp_cache_counts[c->cur.type]--; + nhrp_cache_counts[c->new.type]++; + c->cur = c->new; + c->cur.peer = nhrp_peer_ref(c->cur.peer); + nhrp_cache_reset_new(c); + if (c->cur.peer) + nhrp_peer_notify_add(c->cur.peer, &c->peer_notifier, nhrp_cache_peer_notifier); + nhrp_cache_update_route(c); + notifier_call(&c->notifier_list, NOTIFY_CACHE_BINDING_CHANGE); + } else { + nhrp_cache_reset_new(c); + } + + nhrp_cache_update_timers(c); +} + +static int nhrp_cache_do_auth_timeout(struct thread *t) +{ + struct nhrp_cache *c = THREAD_ARG(t); + c->t_auth = NULL; + nhrp_cache_authorize_binding(&c->eventid, (void *) "timeout"); + return 0; +} + +static void nhrp_cache_newpeer_notifier(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_cache *c = container_of(n, struct nhrp_cache, newpeer_notifier); + + switch (cmd) { + case NOTIFY_PEER_UP: + if (nhrp_peer_check(c->new.peer, 1)) { + evmgr_notify("authorize-binding", c, nhrp_cache_authorize_binding); + THREAD_TIMER_ON(master, c->t_auth, nhrp_cache_do_auth_timeout, c, 10); + } + break; + case NOTIFY_PEER_DOWN: + case NOTIFY_PEER_IFCONFIG_CHANGED: + nhrp_cache_reset_new(c); + break; + } +} + +int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, int holding_time, struct nhrp_peer *p, uint32_t mtu, union sockunion *nbma_oa) +{ + if (c->cur.type > type || c->new.type > type) { + nhrp_peer_unref(p); + return 0; + } + + /* Sanitize MTU */ + switch (sockunion_family(&c->remote_addr)) { + case AF_INET: + if (mtu < 576 || mtu >= 1500) + mtu = 0; + /* Opennhrp announces nbma mtu, but we use protocol mtu. + * This heuristic tries to fix up it. */ + if (mtu > 1420) mtu = (mtu & -16) - 80; + break; + default: + mtu = 0; + break; + } + + nhrp_cache_reset_new(c); + if (c->cur.type == type && c->cur.peer == p && c->cur.mtu == mtu) { + if (holding_time > 0) c->cur.expires = recent_relative_time().tv_sec + holding_time; + if (nbma_oa) c->cur.remote_nbma_natoa = *nbma_oa; + else memset(&c->cur.remote_nbma_natoa, 0, sizeof c->cur.remote_nbma_natoa); + nhrp_peer_unref(p); + } else { + c->new.type = type; + c->new.peer = p; + c->new.mtu = mtu; + if (nbma_oa) c->new.remote_nbma_natoa = *nbma_oa; + + if (holding_time > 0) + c->new.expires = recent_relative_time().tv_sec + holding_time; + else if (holding_time < 0) + c->new.type = NHRP_CACHE_INVALID; + + if (c->new.type == NHRP_CACHE_INVALID || + c->new.type >= NHRP_CACHE_STATIC || + c->map) { + nhrp_cache_authorize_binding(&c->eventid, (void *) "accept"); + } else { + nhrp_peer_notify_add(c->new.peer, &c->newpeer_notifier, nhrp_cache_newpeer_notifier); + nhrp_cache_newpeer_notifier(&c->newpeer_notifier, NOTIFY_PEER_UP); + THREAD_TIMER_ON(master, c->t_auth, nhrp_cache_do_auth_timeout, c, 60); + } + } + nhrp_cache_update_timers(c); + + return 1; +} + +void nhrp_cache_set_used(struct nhrp_cache *c, int used) +{ + c->used = used; + if (c->used) + notifier_call(&c->notifier_list, NOTIFY_CACHE_USED); +} + +struct nhrp_cache_iterator_ctx { + void (*cb)(struct nhrp_cache *, void *); + void *ctx; +}; + +static void nhrp_cache_iterator(struct hash_backet *b, void *ctx) +{ + struct nhrp_cache_iterator_ctx *ic = ctx; + ic->cb(b->data, ic->ctx); +} + +void nhrp_cache_foreach(struct interface *ifp, void (*cb)(struct nhrp_cache *, void *), void *ctx) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_cache_iterator_ctx ic = { + .cb = cb, + .ctx = ctx, + }; + + if (nifp->cache_hash) + hash_iterate(nifp->cache_hash, nhrp_cache_iterator, &ic); +} + +void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n, notifier_fn_t fn) +{ + notifier_add(n, &c->notifier_list, fn); +} + +void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *n) +{ + notifier_del(n); +} diff --git a/nhrpd/nhrp_event.c b/nhrpd/nhrp_event.c new file mode 100644 index 000000000..aab9ec642 --- /dev/null +++ b/nhrpd/nhrp_event.c @@ -0,0 +1,280 @@ +/* NHRP event manager + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include "thread.h" +#include "zbuf.h" +#include "log.h" +#include "nhrpd.h" + +const char *nhrp_event_socket_path; +struct nhrp_reqid_pool nhrp_event_reqid; + +struct event_manager { + struct thread *t_reconnect, *t_read, *t_write; + struct zbuf ibuf; + struct zbuf_queue obuf; + int fd; + uint8_t ibuf_data[4*1024]; +}; + +static int evmgr_reconnect(struct thread *t); + +static void evmgr_connection_error(struct event_manager *evmgr) +{ + THREAD_OFF(evmgr->t_read); + THREAD_OFF(evmgr->t_write); + zbuf_reset(&evmgr->ibuf); + zbufq_reset(&evmgr->obuf); + + if (evmgr->fd >= 0) + close(evmgr->fd); + evmgr->fd = -1; + if (nhrp_event_socket_path) + THREAD_TIMER_MSEC_ON(master, evmgr->t_reconnect, evmgr_reconnect, + evmgr, 10); +} + +static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb) +{ + struct zbuf zl; + uint32_t eventid = 0; + size_t len; + char buf[256], result[64] = ""; + + while (zbuf_may_pull_until(zb, "\n", &zl)) { + len = zbuf_used(&zl) - 1; + if (len >= sizeof(buf)-1) + continue; + memcpy(buf, zbuf_pulln(&zl, len), len); + buf[len] = 0; + + debugf(NHRP_DEBUG_EVENT, "evmgr: msg: %s", buf); + sscanf(buf, "eventid=%d", &eventid); + sscanf(buf, "result=%63s", result); + } + debugf(NHRP_DEBUG_EVENT, "evmgr: received: eventid=%d result=%s", eventid, result); + if (eventid && result[0]) { + struct nhrp_reqid *r = nhrp_reqid_lookup(&nhrp_event_reqid, eventid); + if (r) r->cb(r, result); + } +} + +static int evmgr_read(struct thread *t) +{ + struct event_manager *evmgr = THREAD_ARG(t); + struct zbuf *ibuf = &evmgr->ibuf; + struct zbuf msg; + + evmgr->t_read = NULL; + if (zbuf_read(ibuf, evmgr->fd, (size_t) -1) < 0) { + evmgr_connection_error(evmgr); + return 0; + } + + /* Process all messages in buffer */ + while (zbuf_may_pull_until(ibuf, "\n\n", &msg)) + evmgr_recv_message(evmgr, &msg); + + THREAD_READ_ON(master, evmgr->t_read, evmgr_read, evmgr, evmgr->fd); + return 0; +} + +static int evmgr_write(struct thread *t) +{ + struct event_manager *evmgr = THREAD_ARG(t); + int r; + + evmgr->t_write = NULL; + r = zbufq_write(&evmgr->obuf, evmgr->fd); + if (r > 0) { + THREAD_WRITE_ON(master, evmgr->t_write, evmgr_write, evmgr, evmgr->fd); + } else if (r < 0) { + evmgr_connection_error(evmgr); + } + + return 0; +} + +static void evmgr_hexdump(struct zbuf *zb, const uint8_t *val, size_t vallen) +{ + static const char xd[] = "0123456789abcdef"; + size_t i; + char *ptr; + + ptr = zbuf_pushn(zb, 2*vallen); + if (!ptr) return; + + for (i = 0; i < vallen; i++) { + uint8_t b = val[i]; + *(ptr++) = xd[b >> 4]; + *(ptr++) = xd[b & 0xf]; + } +} + +static void evmgr_put(struct zbuf *zb, const char *fmt, ...) +{ + const char *pos, *nxt, *str; + const uint8_t *bin; + const union sockunion *su; + int len; + va_list va; + + va_start(va, fmt); + for (pos = fmt; (nxt = strchr(pos, '%')) != NULL; pos = nxt + 2) { + zbuf_put(zb, pos, nxt-pos); + switch (nxt[1]) { + case '%': + zbuf_put8(zb, '%'); + break; + case 'u': + zb->tail += snprintf((char *) zb->tail, zbuf_tailroom(zb), "%u", va_arg(va, uint32_t)); + break; + case 's': + str = va_arg(va, const char *); + zbuf_put(zb, str, strlen(str)); + break; + case 'U': + su = va_arg(va, const union sockunion *); + if (sockunion2str(su, (char *) zb->tail, zbuf_tailroom(zb))) + zb->tail += strlen((char *) zb->tail); + else + zbuf_set_werror(zb); + break; + case 'H': + bin = va_arg(va, const uint8_t *); + len = va_arg(va, int); + evmgr_hexdump(zb, bin, len); + break; + } + } + va_end(va); + zbuf_put(zb, pos, strlen(pos)); +} + +static void evmgr_submit(struct event_manager *evmgr, struct zbuf *obuf) +{ + if (obuf->error) { + zbuf_free(obuf); + return; + } + zbuf_put(obuf, "\n", 1); + zbufq_queue(&evmgr->obuf, obuf); + if (evmgr->fd >= 0) + THREAD_WRITE_ON(master, evmgr->t_write, evmgr_write, evmgr, evmgr->fd); +} + +static int evmgr_reconnect(struct thread *t) +{ + struct event_manager *evmgr = THREAD_ARG(t); + int fd; + + evmgr->t_reconnect = NULL; + if (evmgr->fd >= 0 || !nhrp_event_socket_path) return 0; + + fd = sock_open_unix(nhrp_event_socket_path); + if (fd < 0) { + zlog_warn("%s: failure connecting nhrp-event socket: %s", + __PRETTY_FUNCTION__, strerror(errno)); + zbufq_reset(&evmgr->obuf); + THREAD_TIMER_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10); + return 0; + } + + zlog_info("Connected to Event Manager"); + evmgr->fd = fd; + THREAD_READ_ON(master, evmgr->t_read, evmgr_read, evmgr, evmgr->fd); + + return 0; +} + +static struct event_manager evmgr_connection; + +void evmgr_init(void) +{ + struct event_manager *evmgr = &evmgr_connection; + + evmgr->fd = -1; + zbuf_init(&evmgr->ibuf, evmgr->ibuf_data, sizeof(evmgr->ibuf_data), 0); + zbufq_init(&evmgr->obuf); + THREAD_TIMER_MSEC_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10); +} + +void evmgr_set_socket(const char *socket) +{ + if (nhrp_event_socket_path) + free((char *) nhrp_event_socket_path); + nhrp_event_socket_path = strdup(socket); + evmgr_connection_error(&evmgr_connection); +} + +void evmgr_terminate(void) +{ +} + +void evmgr_notify(const char *name, struct nhrp_cache *c, void (*cb)(struct nhrp_reqid *, void *)) +{ + struct event_manager *evmgr = &evmgr_connection; + struct nhrp_vc *vc; + struct nhrp_interface *nifp = c->ifp->info; + struct zbuf *zb; + afi_t afi = family2afi(sockunion_family(&c->remote_addr)); + + if (!nhrp_event_socket_path) { + cb(&c->eventid, (void*) "accept"); + return; + } + + debugf(NHRP_DEBUG_EVENT, "evmgr: sending event %s", name); + + vc = c->new.peer ? c->new.peer->vc : NULL; + zb = zbuf_alloc(1024 + (vc ? (vc->local.certlen + vc->remote.certlen) * 2 : 0)); + + if (cb) { + nhrp_reqid_free(&nhrp_event_reqid, &c->eventid); + evmgr_put(zb, + "eventid=%u\n", + nhrp_reqid_alloc(&nhrp_event_reqid, &c->eventid, cb)); + } + + evmgr_put(zb, + "event=%s\n" + "type=%s\n" + "old_type=%s\n" + "num_nhs=%u\n" + "interface=%s\n" + "local_addr=%U\n", + name, + nhrp_cache_type_str[c->new.type], + nhrp_cache_type_str[c->cur.type], + (unsigned int) nhrp_cache_counts[NHRP_CACHE_NHS], + c->ifp->name, + &nifp->afi[afi].addr); + + if (vc) { + evmgr_put(zb, + "vc_initiated=%s\n" + "local_nbma=%U\n" + "local_cert=%H\n" + "remote_addr=%U\n" + "remote_nbma=%U\n" + "remote_cert=%H\n", + c->new.peer->requested ? "yes" : "no", + &vc->local.nbma, + vc->local.cert, vc->local.certlen, + &c->remote_addr, &vc->remote.nbma, + vc->remote.cert, vc->remote.certlen); + } + + evmgr_submit(evmgr, zb); +} + diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c new file mode 100644 index 000000000..8118927ab --- /dev/null +++ b/nhrpd/nhrp_interface.c @@ -0,0 +1,404 @@ +/* NHRP interface + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include "zebra.h" +#include "linklist.h" +#include "memory.h" +#include "thread.h" + +#include "nhrpd.h" +#include "os.h" +#include "netlink.h" + +static int nhrp_if_new_hook(struct interface *ifp) +{ + struct nhrp_interface *nifp; + afi_t afi; + + nifp = XCALLOC(MTYPE_NHRP_IF, sizeof(struct nhrp_interface)); + if (!nifp) return 0; + + ifp->info = nifp; + nifp->ifp = ifp; + + notifier_init(&nifp->notifier_list); + for (afi = 0; afi < AFI_MAX; afi++) { + struct nhrp_afi_data *ad = &nifp->afi[afi]; + ad->holdtime = NHRPD_DEFAULT_HOLDTIME; + list_init(&ad->nhslist_head); + } + + return 0; +} + +static int nhrp_if_delete_hook(struct interface *ifp) +{ + XFREE(MTYPE_NHRP_IF, ifp->info); + return 0; +} + +void nhrp_interface_init(void) +{ + if_add_hook(IF_NEW_HOOK, nhrp_if_new_hook); + if_add_hook(IF_DELETE_HOOK, nhrp_if_delete_hook); +} + +void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_afi_data *if_ad = &nifp->afi[afi]; + unsigned short new_mtu; + + if (if_ad->configured_mtu < 0) + new_mtu = nifp->nbmaifp ? nifp->nbmaifp->mtu : 0; + else + new_mtu = if_ad->configured_mtu; + if (new_mtu >= 1500) + new_mtu = 0; + + if (new_mtu != if_ad->mtu) { + debugf(NHRP_DEBUG_IF, "%s: MTU changed to %d", ifp->name, new_mtu); + if_ad->mtu = new_mtu; + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_MTU_CHANGED); + } +} + +static void nhrp_interface_update_source(struct interface *ifp) +{ + struct nhrp_interface *nifp = ifp->info; + + if (!nifp->source || !nifp->nbmaifp || + nifp->linkidx == nifp->nbmaifp->ifindex) + return; + + nifp->linkidx = nifp->nbmaifp->ifindex; + debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name, nifp->linkidx); + netlink_gre_set_link(ifp->ifindex, nifp->linkidx); +} + +static void nhrp_interface_interface_notifier(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_interface *nifp = container_of(n, struct nhrp_interface, nbmanifp_notifier); + struct interface *nbmaifp = nifp->nbmaifp; + struct nhrp_interface *nbmanifp = nbmaifp->info; + char buf[SU_ADDRSTRLEN]; + + switch (cmd) { + case NOTIFY_INTERFACE_CHANGED: + nhrp_interface_update_mtu(nifp->ifp, AFI_IP); + nhrp_interface_update_source(nifp->ifp); + break; + case NOTIFY_INTERFACE_ADDRESS_CHANGED: + nifp->nbma = nbmanifp->afi[AFI_IP].addr; + nhrp_interface_update(nifp->ifp); + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED); + debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %s", + nifp->ifp->name, + sockunion2str(&nifp->nbma, buf, sizeof buf)); + break; + } +} + +static void nhrp_interface_update_nbma(struct interface *ifp) +{ + struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL; + struct interface *nbmaifp = NULL; + union sockunion nbma; + + sockunion_family(&nbma) = AF_UNSPEC; + + if (nifp->source) + nbmaifp = if_lookup_by_name(nifp->source); + + switch (ifp->ll_type) { + case ZEBRA_LLT_IPGRE: { + struct in_addr saddr = {0}; + netlink_gre_get_info(ifp->ifindex, &nifp->grekey, &nifp->linkidx, &saddr); + debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name, nifp->grekey, nifp->linkidx, saddr.s_addr); + if (saddr.s_addr) + sockunion_set(&nbma, AF_INET, (u_char *) &saddr.s_addr, sizeof(saddr.s_addr)); + else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL) + nbmaifp = if_lookup_by_index(nifp->linkidx); + } + break; + default: + break; + } + + if (nbmaifp) + nbmanifp = nbmaifp->info; + + if (nbmaifp != nifp->nbmaifp) { + if (nifp->nbmaifp) + notifier_del(&nifp->nbmanifp_notifier); + nifp->nbmaifp = nbmaifp; + if (nbmaifp) { + notifier_add(&nifp->nbmanifp_notifier, &nbmanifp->notifier_list, nhrp_interface_interface_notifier); + debugf(NHRP_DEBUG_IF, "%s: bound to %s", ifp->name, nbmaifp->name); + } + } + + if (nbmaifp) { + if (sockunion_family(&nbma) == AF_UNSPEC) + nbma = nbmanifp->afi[AFI_IP].addr; + nhrp_interface_update_mtu(ifp, AFI_IP); + nhrp_interface_update_source(ifp); + } + + if (!sockunion_same(&nbma, &nifp->nbma)) { + nifp->nbma = nbma; + nhrp_interface_update(nifp->ifp); + debugf(NHRP_DEBUG_IF, "%s: NBMA address changed", ifp->name); + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED); + } + + nhrp_interface_update(ifp); +} + +static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, int force) +{ + const int family = afi2family(afi); + struct nhrp_interface *nifp = ifp->info; + struct nhrp_afi_data *if_ad = &nifp->afi[afi]; + struct nhrp_cache *nc; + struct connected *c, *best; + struct listnode *cnode; + union sockunion addr; + char buf[PREFIX_STRLEN]; + + /* Select new best match preferring primary address */ + best = NULL; + for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + if (PREFIX_FAMILY(c->address) != family) + continue; + if (best == NULL) { + best = c; + continue; + } + if ((best->flags & ZEBRA_IFA_SECONDARY) && !(c->flags & ZEBRA_IFA_SECONDARY)) { + best = c; + continue; + } + if (!(best->flags & ZEBRA_IFA_SECONDARY) && (c->flags & ZEBRA_IFA_SECONDARY)) + continue; + if (best->address->prefixlen > c->address->prefixlen) { + best = c; + continue; + } + if (best->address->prefixlen < c->address->prefixlen) + continue; + } + + /* On NHRP interfaces a host prefix is required */ + if (best && if_ad->configured && best->address->prefixlen != 8 * prefix_blen(best->address)) { + zlog_notice("%s: %s is not a host prefix", ifp->name, + prefix2str(best->address, buf, sizeof buf)); + best = NULL; + } + + /* Update address if it changed */ + if (best) + prefix2sockunion(best->address, &addr); + else + memset(&addr, 0, sizeof(addr)); + + if (!force && sockunion_same(&if_ad->addr, &addr)) + return; + + if (sockunion_family(&if_ad->addr) != AF_UNSPEC) { + nc = nhrp_cache_get(ifp, &if_ad->addr, 0); + if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, NULL, 0, NULL); + } + + debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s", + ifp->name, afi == AFI_IP ? 4 : 6, + best ? prefix2str(best->address, buf, sizeof buf) : "(none)"); + if_ad->addr = addr; + + if (if_ad->configured && sockunion_family(&if_ad->addr) != AF_UNSPEC) { + nc = nhrp_cache_get(ifp, &addr, 1); + if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL); + } + + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); +} + +void nhrp_interface_update(struct interface *ifp) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_afi_data *if_ad; + afi_t afi; + int enabled = 0; + + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_CHANGED); + + for (afi = 0; afi < AFI_MAX; afi++) { + if_ad = &nifp->afi[afi]; + + if (sockunion_family(&nifp->nbma) == AF_UNSPEC || + ifp->ifindex == IFINDEX_INTERNAL || !if_is_up(ifp) || + !if_ad->network_id) { + if (if_ad->configured) { + if_ad->configured = 0; + nhrp_interface_update_address(ifp, afi, 1); + } + continue; + } + + if (!if_ad->configured) { + os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi)); + if_ad->configured = 1; + nhrp_interface_update_address(ifp, afi, 1); + } + + enabled = 1; + } + + if (enabled != nifp->enabled) { + nifp->enabled = enabled; + notifier_call(&nifp->notifier_list, enabled ? NOTIFY_INTERFACE_UP : NOTIFY_INTERFACE_DOWN); + } +} + +int nhrp_interface_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + + /* read and add the interface in the iflist. */ + ifp = zebra_interface_add_read(client->ibuf, vrf_id); + if (ifp == NULL) + return 0; + + debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s", + ifp->name, ifp->ifindex, + ifp->ll_type, if_link_type_str(ifp->ll_type)); + + nhrp_interface_update_nbma(ifp); + + return 0; +} + +int nhrp_interface_delete(int cmd, struct zclient *client, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s; + + s = client->ibuf; + ifp = zebra_interface_state_read(s, vrf_id); + if (ifp == NULL) + return 0; + + debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name); + ifp->ifindex = IFINDEX_INTERNAL; + nhrp_interface_update(ifp); + /* if_delete(ifp); */ + return 0; +} + +int nhrp_interface_up(int cmd, struct zclient *client, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + + ifp = zebra_interface_state_read(client->ibuf, vrf_id); + if (ifp == NULL) + return 0; + + debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name); + nhrp_interface_update_nbma(ifp); + + return 0; +} + +int nhrp_interface_down(int cmd, struct zclient *client, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + + ifp = zebra_interface_state_read(client->ibuf, vrf_id); + if (ifp == NULL) + return 0; + + debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name); + nhrp_interface_update(ifp); + return 0; +} + +int nhrp_interface_address_add(int cmd, struct zclient *client, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *ifc; + char buf[PREFIX_STRLEN]; + + ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id); + if (ifc == NULL) + return 0; + + debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s", + ifc->ifp->name, + prefix2str(ifc->address, buf, sizeof buf)); + + nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); + + return 0; +} + +int nhrp_interface_address_delete(int cmd, struct zclient *client, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *ifc; + char buf[PREFIX_STRLEN]; + + ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id); + if (ifc == NULL) + return 0; + + debugf(NHRP_DEBUG_IF, "if-addr-del: %s: %s", + ifc->ifp->name, + prefix2str(ifc->address, buf, sizeof buf)); + + nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); + connected_free(ifc); + + return 0; +} + +void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn) +{ + struct nhrp_interface *nifp = ifp->info; + notifier_add(n, &nifp->notifier_list, fn); +} + +void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n) +{ + notifier_del(n); +} + +void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile) +{ + struct nhrp_interface *nifp = ifp->info; + + if (nifp->ipsec_profile) free(nifp->ipsec_profile); + nifp->ipsec_profile = profile ? strdup(profile) : NULL; + + if (nifp->ipsec_fallback_profile) free(nifp->ipsec_fallback_profile); + nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL; +} + +void nhrp_interface_set_source(struct interface *ifp, const char *ifname) +{ + struct nhrp_interface *nifp = ifp->info; + + if (nifp->source) free(nifp->source); + nifp->source = ifname ? strdup(ifname) : NULL; + + nhrp_interface_update_nbma(ifp); +} diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c new file mode 100644 index 000000000..29349a038 --- /dev/null +++ b/nhrpd/nhrp_main.c @@ -0,0 +1,246 @@ +/* NHRP daemon main functions + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "zebra.h" +#include "privs.h" +#include "getopt.h" +#include "thread.h" +#include "sigevent.h" +#include "version.h" +#include "log.h" +#include "memory.h" +#include "command.h" + +#include "nhrpd.h" +#include "netlink.h" + +unsigned int debug_flags = 0; + +struct thread_master *master; +struct timeval current_time; +static const char *pid_file = PATH_NHRPD_PID; +static char config_default[] = SYSCONFDIR NHRP_DEFAULT_CONFIG; +static char *config_file = NULL; +static char *vty_addr = NULL; +static int vty_port = NHRP_VTY_PORT; +static int do_daemonise = 0; + +/* nhrpd options. */ +struct option longopts[] = { + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "user", required_argument, NULL, 'u'}, + { "group", required_argument, NULL, 'g'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* nhrpd privileges */ +static zebra_capabilities_t _caps_p [] = { + ZCAP_NET_RAW, + ZCAP_NET_ADMIN, + ZCAP_DAC_OVERRIDE, /* for now needed to write to /proc/sys/net/ipv4//send_redirect */ +}; + +static struct zebra_privs_t nhrpd_privs = { +#ifdef QUAGGA_USER + .user = QUAGGA_USER, +#endif +#ifdef QUAGGA_GROUP + .group = QUAGGA_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = ZEBRA_NUM_OF(_caps_p), +}; + +static void usage(const char *progname, int status) +{ + if (status != 0) + fprintf(stderr, "Try `%s --help' for more information.\n", progname); + else + printf( +"Usage : %s [OPTION...]\n\ +Daemon which manages NHRP protocol.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-u, --user User to run as\n\ +-g, --group Group to run as\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + + exit(status); +} + +static void parse_arguments(const char *progname, int argc, char **argv) +{ + int opt; + + while (1) { + opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0); + if(opt < 0) break; + + switch (opt) { + case 0: + break; + case 'd': + do_daemonise = -1; + break; + case 'f': + config_file = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'z': + zclient_serv_path_set(optarg); + break; + case 'A': + vty_addr = optarg; + break; + case 'P': + vty_port = atoi (optarg); + if (vty_port <= 0 || vty_port > 0xffff) + vty_port = NHRP_VTY_PORT; + break; + case 'u': + nhrpd_privs.user = optarg; + break; + case 'g': + nhrpd_privs.group = optarg; + break; + case 'v': + print_version(progname); + exit(0); + break; + case 'h': + usage(progname, 0); + break; + default: + usage(progname, 1); + break; + } + } +} + +static void nhrp_sigusr1(void) +{ + zlog_rotate(NULL); +} + +static void nhrp_request_stop(void) +{ + debugf(NHRP_DEBUG_COMMON, "Exiting..."); + + nhrp_shortcut_terminate(); + nhrp_nhs_terminate(); + nhrp_zebra_terminate(); + vici_terminate(); + evmgr_terminate(); + nhrp_vc_terminate(); + vrf_terminate(); + /* memory_terminate(); */ + /* vty_terminate(); */ + cmd_terminate(); + /* signal_terminate(); */ + zprivs_terminate(&nhrpd_privs); + + debugf(NHRP_DEBUG_COMMON, "Remove pid file."); + if (pid_file) unlink(pid_file); + debugf(NHRP_DEBUG_COMMON, "Done."); + + closezlog(zlog_default); + + exit(0); +} + +static struct quagga_signal_t sighandlers[] = { + { .signal = SIGUSR1, .handler = &nhrp_sigusr1, }, + { .signal = SIGINT, .handler = &nhrp_request_stop, }, + { .signal = SIGTERM, .handler = &nhrp_request_stop, }, +}; + +int main(int argc, char **argv) +{ + struct thread thread; + const char *progname; + + /* Set umask before anything for security */ + umask(0027); + progname = basename(argv[0]); + zlog_default = openzlog(progname, ZLOG_NHRP, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); + + parse_arguments(progname, argc, argv); + + /* Library inits. */ + master = thread_master_create(); + zprivs_init(&nhrpd_privs); + signal_init(master, array_size(sighandlers), sighandlers); + cmd_init(1); + vty_init(master); + memory_init(); + nhrp_interface_init(); + vrf_init(); + resolver_init(); + + /* Run with elevated capabilities, as for all netlink activity + * we need privileges anyway. */ + nhrpd_privs.change(ZPRIVS_RAISE); + + netlink_init(); + evmgr_init(); + nhrp_vc_init(); + nhrp_packet_init(); + vici_init(); + nhrp_zebra_init(); + nhrp_shortcut_init(); + + nhrp_config_init(); + + /* Get zebra configuration file. */ + zlog_set_level(NULL, ZLOG_DEST_STDOUT, do_daemonise ? ZLOG_DISABLED : LOG_DEBUG); + vty_read_config(config_file, config_default); + + if (do_daemonise && daemon(0, 0) < 0) { + zlog_err("daemonise: %s", safe_strerror(errno)); + exit (1); + } + + /* write pid file */ + if (pid_output(pid_file) < 0) { + zlog_err("error while writing pidfile"); + exit (1); + } + + /* Create VTY socket */ + vty_serv_sock(vty_addr, vty_port, NHRP_VTYSH_PATH); + zlog_notice("nhrpd starting: vty@%d", vty_port); + + /* Main loop */ + while (thread_fetch(master, &thread)) + thread_call(&thread); + + return 0; +} diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c new file mode 100644 index 000000000..d463e0625 --- /dev/null +++ b/nhrpd/nhrp_nhs.c @@ -0,0 +1,369 @@ +/* NHRP NHC nexthop server functions (registration) + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "zebra.h" +#include "zbuf.h" +#include "memory.h" +#include "thread.h" +#include "nhrpd.h" +#include "nhrp_protocol.h" + +static int nhrp_nhs_resolve(struct thread *t); + +struct nhrp_registration { + struct list_head reglist_entry; + struct thread *t_register; + struct nhrp_nhs *nhs; + struct nhrp_reqid reqid; + unsigned int timeout; + unsigned mark : 1; + union sockunion proto_addr; + struct nhrp_peer *peer; + struct notifier_block peer_notifier; +}; + +static int nhrp_reg_send_req(struct thread *t); + +static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) +{ + struct nhrp_packet_parser *p = arg; + struct nhrp_registration *r = container_of(reqid, struct nhrp_registration, reqid); + struct nhrp_nhs *nhs = r->nhs; + struct interface *ifp = nhs->ifp; + struct nhrp_interface *nifp = ifp->info; + struct nhrp_extension_header *ext; + struct nhrp_cie_header *cie; + struct nhrp_cache *c; + struct zbuf extpl; + union sockunion cie_nbma, cie_proto, *proto; + char buf[64]; + int ok = 0, holdtime; + + nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid); + + if (p->hdr->type != NHRP_PACKET_REGISTRATION_REPLY) { + debugf(NHRP_DEBUG_COMMON, "NHS: Registration failed"); + return; + } + + debugf(NHRP_DEBUG_COMMON, "NHS: Reg.reply received"); + + ok = 1; + while ((cie = nhrp_cie_pull(&p->payload, p->hdr, &cie_nbma, &cie_proto)) != NULL) { + proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &p->src_proto; + debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %s: %d", + sockunion2str(proto, buf, sizeof(buf)), + cie->code); + if (!((cie->code == NHRP_CODE_SUCCESS) || + (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED && nhs->hub))) + ok = 0; + } + + if (!ok) + return; + + /* Parse extensions */ + sockunion_family(&nifp->nat_nbma) = AF_UNSPEC; + while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_NAT_ADDRESS: + /* NHS adds second CIE if NAT is detected */ + if (nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto) && + nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto)) { + nifp->nat_nbma = cie_nbma; + debugf(NHRP_DEBUG_IF, "%s: NAT detected, real NBMA address: %s", + ifp->name, sockunion2str(&nifp->nbma, buf, sizeof(buf))); + } + break; + } + } + + /* Success - schedule next registration, and route NHS */ + r->timeout = 2; + holdtime = nifp->afi[nhs->afi].holdtime; + THREAD_OFF(r->t_register); + + /* RFC 2332 5.2.3 - Registration is recommend to be renewed + * every one third of holdtime */ + THREAD_TIMER_ON(master, r->t_register, nhrp_reg_send_req, r, holdtime / 3); + + r->proto_addr = p->dst_proto; + c = nhrp_cache_get(ifp, &p->dst_proto, 1); + if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime, nhrp_peer_ref(r->peer), 0, NULL); +} + +static int nhrp_reg_timeout(struct thread *t) +{ + struct nhrp_registration *r = THREAD_ARG(t); + struct nhrp_cache *c; + + r->t_register = NULL; + + if (r->timeout >= 16 && sockunion_family(&r->proto_addr) != AF_UNSPEC) { + nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid); + c = nhrp_cache_get(r->nhs->ifp, &r->proto_addr, 0); + if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL, 0, NULL); + sockunion_family(&r->proto_addr) = AF_UNSPEC; + } + + r->timeout <<= 1; + if (r->timeout > 64) r->timeout = 2; + THREAD_TIMER_MSEC_ON(master, r->t_register, nhrp_reg_send_req, r, 10); + + return 0; +} + +static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_registration *r = container_of(n, struct nhrp_registration, peer_notifier); + char buf[SU_ADDRSTRLEN]; + + switch (cmd) { + case NOTIFY_PEER_UP: + case NOTIFY_PEER_DOWN: + case NOTIFY_PEER_IFCONFIG_CHANGED: + case NOTIFY_PEER_MTU_CHANGED: + debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %s", + sockunion2str(&r->peer->vc->remote.nbma, buf, sizeof buf)); + THREAD_TIMER_OFF(r->t_register); + THREAD_TIMER_MSEC_ON(master, r->t_register, nhrp_reg_send_req, r, 10); + break; + } +} + +static int nhrp_reg_send_req(struct thread *t) +{ + struct nhrp_registration *r = THREAD_ARG(t); + struct nhrp_nhs *nhs = r->nhs; + char buf1[SU_ADDRSTRLEN], buf2[SU_ADDRSTRLEN]; + struct interface *ifp = nhs->ifp; + struct nhrp_interface *nifp = ifp->info; + struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi]; + union sockunion *dst_proto; + struct zbuf *zb; + struct nhrp_packet_header *hdr; + struct nhrp_extension_header *ext; + struct nhrp_cie_header *cie; + + r->t_register = NULL; + if (!nhrp_peer_check(r->peer, 2)) { + debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %s", + sockunion2str(&r->peer->vc->remote.nbma, buf1, sizeof buf1)); + THREAD_TIMER_ON(master, r->t_register, nhrp_reg_send_req, r, 120); + return 0; + } + + THREAD_TIMER_ON(master, r->t_register, nhrp_reg_timeout, r, r->timeout); + + /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */ + dst_proto = &nhs->proto_addr; + if (sockunion_family(dst_proto) == AF_UNSPEC) + dst_proto = &if_ad->addr; + + sockunion2str(&if_ad->addr, buf1, sizeof(buf1)); + sockunion2str(dst_proto, buf2, sizeof(buf2)); + debugf(NHRP_DEBUG_COMMON, "NHS: Register %s -> %s (timeout %d)", buf1, buf2, r->timeout); + + /* No protocol address configured for tunnel interface */ + if (sockunion_family(&if_ad->addr) == AF_UNSPEC) + return 0; + + zb = zbuf_alloc(1400); + hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST, &nifp->nbma, &if_ad->addr, dst_proto); + hdr->hop_count = 0; + if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE)) + hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE); + + hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &r->reqid, nhrp_reg_reply)); + + /* FIXME: push CIE for each local protocol address */ + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL); + cie->prefix_length = 0xff; + cie->holding_time = htons(if_ad->holdtime); + cie->mtu = htons(if_ad->mtu); + + nhrp_ext_request(zb, hdr, ifp); + + /* Cisco NAT detection extension */ + hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT); + ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr); + cie->prefix_length = 8 * sockunion_get_addrlen(&nifp->nbma); + nhrp_ext_complete(zb, ext); + + nhrp_packet_complete(zb, hdr); + nhrp_peer_send(r->peer, zb); + zbuf_free(zb); + + return 0; +} + +static void nhrp_reg_delete(struct nhrp_registration *r) +{ + nhrp_peer_notify_del(r->peer, &r->peer_notifier); + nhrp_peer_unref(r->peer); + list_del(&r->reglist_entry); + THREAD_OFF(r->t_register); + XFREE(MTYPE_NHRP_REGISTRATION, r); +} + +static struct nhrp_registration *nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr) +{ + struct nhrp_registration *r; + + list_for_each_entry(r, &nhs->reglist_head, reglist_entry) + if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr)) + return r; + return NULL; +} + +static void nhrp_nhs_resolve_cb(struct resolver_query *q, int n, union sockunion *addrs) +{ + struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve); + struct nhrp_interface *nifp = nhs->ifp->info; + struct nhrp_registration *reg, *regn; + int i; + + nhs->t_resolve = NULL; + if (n < 0) { + /* Failed, retry in a moment */ + THREAD_TIMER_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 5); + return; + } + + THREAD_TIMER_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 2*60*60); + + list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) + reg->mark = 1; + + nhs->hub = 0; + for (i = 0; i < n; i++) { + if (sockunion_same(&addrs[i], &nifp->nbma)) { + nhs->hub = 1; + continue; + } + + reg = nhrp_reg_by_nbma(nhs, &addrs[i]); + if (reg) { + reg->mark = 0; + continue; + } + + reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg)); + reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]); + reg->nhs = nhs; + reg->timeout = 1; + list_init(®->reglist_entry); + list_add_tail(®->reglist_entry, &nhs->reglist_head); + nhrp_peer_notify_add(reg->peer, ®->peer_notifier, nhrp_reg_peer_notify); + THREAD_TIMER_MSEC_ON(master, reg->t_register, nhrp_reg_send_req, reg, 50); + } + + list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry) { + if (reg->mark) + nhrp_reg_delete(reg); + } +} + +static int nhrp_nhs_resolve(struct thread *t) +{ + struct nhrp_nhs *nhs = THREAD_ARG(t); + + resolver_resolve(&nhs->dns_resolve, AF_INET, nhs->nbma_fqdn, nhrp_nhs_resolve_cb); + + return 0; +} + +int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_nhs *nhs; + + if (sockunion_family(proto_addr) != AF_UNSPEC && + sockunion_family(proto_addr) != afi2family(afi)) + return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH; + + list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) { + if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC && + sockunion_family(proto_addr) != AF_UNSPEC && + sockunion_same(&nhs->proto_addr, proto_addr)) + return NHRP_ERR_ENTRY_EXISTS; + + if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0) + return NHRP_ERR_ENTRY_EXISTS; + } + + nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs)); + if (!nhs) return NHRP_ERR_NO_MEMORY; + + *nhs = (struct nhrp_nhs) { + .afi = afi, + .ifp = ifp, + .proto_addr = *proto_addr, + .nbma_fqdn = strdup(nbma_fqdn), + .reglist_head = LIST_INITIALIZER(nhs->reglist_head), + }; + list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head); + THREAD_TIMER_MSEC_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 1000); + + return NHRP_OK; +} + +int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_nhs *nhs, *nnhs; + int ret = NHRP_ERR_ENTRY_NOT_FOUND; + + if (sockunion_family(proto_addr) != AF_UNSPEC && + sockunion_family(proto_addr) != afi2family(afi)) + return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH; + + list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head, nhslist_entry) { + if (!sockunion_same(&nhs->proto_addr, proto_addr)) + continue; + if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0) + continue; + + nhrp_nhs_free(nhs); + ret = NHRP_OK; + } + + return ret; +} + +int nhrp_nhs_free(struct nhrp_nhs *nhs) +{ + struct nhrp_registration *r, *rn; + + list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry) + nhrp_reg_delete(r); + THREAD_OFF(nhs->t_resolve); + list_del(&nhs->nhslist_entry); + free((void*) nhs->nbma_fqdn); + XFREE(MTYPE_NHRP_NHS, nhs); + return 0; +} + +void nhrp_nhs_terminate(void) +{ + struct interface *ifp; + struct nhrp_interface *nifp; + struct nhrp_nhs *nhs, *tmp; + struct listnode *node; + afi_t afi; + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + nifp = ifp->info; + for (afi = 0; afi < AFI_MAX; afi++) { + list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head, nhslist_entry) + nhrp_nhs_free(nhs); + } + } +} diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c new file mode 100644 index 000000000..5d2866a67 --- /dev/null +++ b/nhrpd/nhrp_packet.c @@ -0,0 +1,312 @@ +/* NHRP packet handling functions + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include "nhrpd.h" +#include "zbuf.h" +#include "thread.h" +#include "hash.h" + +#include "nhrp_protocol.h" +#include "os.h" + +struct nhrp_reqid_pool nhrp_packet_reqid; + +static uint16_t family2proto(int family) +{ + switch (family) { + case AF_INET: return ETH_P_IP; + case AF_INET6: return ETH_P_IPV6; + } + return 0; +} + +static int proto2family(uint16_t proto) +{ + switch (proto) { + case ETH_P_IP: return AF_INET; + case ETH_P_IPV6: return AF_INET6; + } + return AF_UNSPEC; +} + +struct nhrp_packet_header *nhrp_packet_push( + struct zbuf *zb, uint8_t type, + const union sockunion *src_nbma, + const union sockunion *src_proto, + const union sockunion *dst_proto) +{ + struct nhrp_packet_header *hdr; + + hdr = zbuf_push(zb, struct nhrp_packet_header); + if (!hdr) return NULL; + + *hdr = (struct nhrp_packet_header) { + .afnum = htons(family2afi(sockunion_family(src_nbma))), + .protocol_type = htons(family2proto(sockunion_family(src_proto))), + .version = NHRP_VERSION_RFC2332, + .type = type, + .hop_count = 64, + .src_nbma_address_len = sockunion_get_addrlen(src_nbma), + .src_protocol_address_len = sockunion_get_addrlen(src_proto), + .dst_protocol_address_len = sockunion_get_addrlen(dst_proto), + }; + + zbuf_put(zb, sockunion_get_addr(src_nbma), hdr->src_nbma_address_len); + zbuf_put(zb, sockunion_get_addr(src_proto), hdr->src_protocol_address_len); + zbuf_put(zb, sockunion_get_addr(dst_proto), hdr->dst_protocol_address_len); + + return hdr; +} + +struct nhrp_packet_header *nhrp_packet_pull( + struct zbuf *zb, + union sockunion *src_nbma, + union sockunion *src_proto, + union sockunion *dst_proto) +{ + struct nhrp_packet_header *hdr; + + hdr = zbuf_pull(zb, struct nhrp_packet_header); + if (!hdr) return NULL; + + sockunion_set( + src_nbma, afi2family(htons(hdr->afnum)), + zbuf_pulln(zb, hdr->src_nbma_address_len + hdr->src_nbma_subaddress_len), + hdr->src_nbma_address_len + hdr->src_nbma_subaddress_len); + sockunion_set( + src_proto, proto2family(htons(hdr->protocol_type)), + zbuf_pulln(zb, hdr->src_protocol_address_len), + hdr->src_protocol_address_len); + sockunion_set( + dst_proto, proto2family(htons(hdr->protocol_type)), + zbuf_pulln(zb, hdr->dst_protocol_address_len), + hdr->dst_protocol_address_len); + + return hdr; +} + +uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len) +{ + const uint16_t *pdu16 = (const uint16_t *) pdu; + uint32_t csum = 0; + int i; + + for (i = 0; i < len / 2; i++) + csum += pdu16[i]; + if (len & 1) + csum += htons(pdu[len - 1]); + + while (csum & 0xffff0000) + csum = (csum & 0xffff) + (csum >> 16); + + return (~csum) & 0xffff; +} + +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr) +{ + unsigned short size; + + if (hdr->extension_offset) + nhrp_ext_push(zb, hdr, NHRP_EXTENSION_END | NHRP_EXTENSION_FLAG_COMPULSORY); + + size = zb->tail - (uint8_t *)hdr; + hdr->packet_size = htons(size); + hdr->checksum = 0; + hdr->checksum = nhrp_packet_calculate_checksum((uint8_t *) hdr, size); +} + +struct nhrp_cie_header *nhrp_cie_push( + struct zbuf *zb, + uint8_t code, + const union sockunion *nbma, + const union sockunion *proto) +{ + struct nhrp_cie_header *cie; + + cie = zbuf_push(zb, struct nhrp_cie_header); + *cie = (struct nhrp_cie_header) { + .code = code, + }; + if (nbma) { + cie->nbma_address_len = sockunion_get_addrlen(nbma); + zbuf_put(zb, sockunion_get_addr(nbma), cie->nbma_address_len); + } + if (proto) { + cie->protocol_address_len = sockunion_get_addrlen(proto); + zbuf_put(zb, sockunion_get_addr(proto), cie->protocol_address_len); + } + + return cie; +} + +struct nhrp_cie_header *nhrp_cie_pull( + struct zbuf *zb, + struct nhrp_packet_header *hdr, + union sockunion *nbma, + union sockunion *proto) +{ + struct nhrp_cie_header *cie; + + cie = zbuf_pull(zb, struct nhrp_cie_header); + if (!cie) return NULL; + + if (cie->nbma_address_len + cie->nbma_subaddress_len) { + sockunion_set( + nbma, afi2family(htons(hdr->afnum)), + zbuf_pulln(zb, cie->nbma_address_len + cie->nbma_subaddress_len), + cie->nbma_address_len + cie->nbma_subaddress_len); + } else { + sockunion_family(nbma) = AF_UNSPEC; + } + + if (cie->protocol_address_len) { + sockunion_set( + proto, proto2family(htons(hdr->protocol_type)), + zbuf_pulln(zb, cie->protocol_address_len), + cie->protocol_address_len); + } else { + sockunion_family(proto) = AF_UNSPEC; + } + + return cie; +} + +struct nhrp_extension_header *nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type) +{ + struct nhrp_extension_header *ext; + ext = zbuf_push(zb, struct nhrp_extension_header); + if (!ext) return NULL; + + if (!hdr->extension_offset) + hdr->extension_offset = htons(zb->tail - (uint8_t*) hdr - sizeof(struct nhrp_extension_header)); + + *ext = (struct nhrp_extension_header) { + .type = htons(type), + .length = 0, + }; + return ext; +} + +void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext) +{ + ext->length = htons(zb->tail - (uint8_t*)ext - sizeof(struct nhrp_extension_header)); +} + +struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload) +{ + struct nhrp_extension_header *ext; + uint16_t plen; + + ext = zbuf_pull(zb, struct nhrp_extension_header); + if (!ext) return NULL; + + plen = htons(ext->length); + zbuf_init(payload, zbuf_pulln(zb, plen), plen, plen); + return ext; +} + +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp) +{ + /* Place holders for standard extensions */ + nhrp_ext_push(zb, hdr, NHRP_EXTENSION_FORWARD_TRANSIT_NHS | NHRP_EXTENSION_FLAG_COMPULSORY); + nhrp_ext_push(zb, hdr, NHRP_EXTENSION_REVERSE_TRANSIT_NHS | NHRP_EXTENSION_FLAG_COMPULSORY); + nhrp_ext_push(zb, hdr, NHRP_EXTENSION_RESPONDER_ADDRESS | NHRP_EXTENSION_FLAG_COMPULSORY); +} + +int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_afi_data *ad = &nifp->afi[htons(hdr->afnum)]; + struct nhrp_extension_header *dst; + struct nhrp_cie_header *cie; + uint16_t type; + + type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY; + if (type == NHRP_EXTENSION_END) + return 0; + + dst = nhrp_ext_push(zb, hdr, htons(ext->type)); + if (!dst) goto err; + + switch (type) { + case NHRP_EXTENSION_RESPONDER_ADDRESS: + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &ad->addr); + if (!cie) goto err; + cie->holding_time = htons(ad->holdtime); + break; + default: + if (type & NHRP_EXTENSION_FLAG_COMPULSORY) + goto err; + case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: + case NHRP_EXTENSION_REVERSE_TRANSIT_NHS: + /* Supported compulsory extensions, and any + * non-compulsory that is not explicitly handled, + * should be just copied. */ + zbuf_copy(zb, extpayload, zbuf_used(extpayload)); + break; + } + nhrp_ext_complete(zb, dst); + return 0; +err: + zbuf_set_werror(zb); + return -1; +} + +static int nhrp_packet_recvraw(struct thread *t) +{ + int fd = THREAD_FD(t), ifindex; + struct zbuf *zb; + struct interface *ifp; + struct nhrp_peer *p; + union sockunion remote_nbma; + uint8_t addr[64]; + size_t len, addrlen; + + thread_add_read(master, nhrp_packet_recvraw, 0, fd); + + zb = zbuf_alloc(1500); + if (!zb) return 0; + + len = zbuf_size(zb); + addrlen = sizeof(addr); + if (os_recvmsg(zb->buf, &len, &ifindex, addr, &addrlen) < 0) + goto err; + + zb->head = zb->buf; + zb->tail = zb->buf + len; + + switch (addrlen) { + case 4: + sockunion_set(&remote_nbma, AF_INET, addr, addrlen); + break; + default: + goto err; + } + + ifp = if_lookup_by_index(ifindex); + if (!ifp) goto err; + + p = nhrp_peer_get(ifp, &remote_nbma); + if (!p) goto err; + + nhrp_peer_recv(p, zb); + nhrp_peer_unref(p); + return 0; + +err: + zbuf_free(zb); + return 0; +} + +int nhrp_packet_init(void) +{ + thread_add_read(master, nhrp_packet_recvraw, 0, os_socket()); + return 0; +} diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c new file mode 100644 index 000000000..45bfd7deb --- /dev/null +++ b/nhrpd/nhrp_peer.c @@ -0,0 +1,860 @@ +/* NHRP peer functions + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "zebra.h" +#include "memory.h" +#include "thread.h" +#include "hash.h" + +#include "nhrpd.h" +#include "nhrp_protocol.h" +#include "os.h" + +struct ipv6hdr { + uint8_t priority_version; + uint8_t flow_lbl[3]; + uint16_t payload_len; + uint8_t nexthdr; + uint8_t hop_limit; + struct in6_addr saddr; + struct in6_addr daddr; +}; + +static void nhrp_packet_debug(struct zbuf *zb, const char *dir); + +static void nhrp_peer_check_delete(struct nhrp_peer *p) +{ + struct nhrp_interface *nifp = p->ifp->info; + + if (p->ref || notifier_active(&p->notifier_list)) + return; + + THREAD_OFF(p->t_fallback); + hash_release(nifp->peer_hash, p); + nhrp_interface_notify_del(p->ifp, &p->ifp_notifier); + nhrp_vc_notify_del(p->vc, &p->vc_notifier); + XFREE(MTYPE_NHRP_PEER, p); +} + +static int nhrp_peer_notify_up(struct thread *t) +{ + struct nhrp_peer *p = THREAD_ARG(t); + struct nhrp_vc *vc = p->vc; + struct interface *ifp = p->ifp; + struct nhrp_interface *nifp = ifp->info; + + p->t_fallback = NULL; + if (nifp->enabled && (!nifp->ipsec_profile || vc->ipsec)) { + p->online = 1; + nhrp_peer_ref(p); + notifier_call(&p->notifier_list, NOTIFY_PEER_UP); + nhrp_peer_unref(p); + } + + return 0; +} + +static void __nhrp_peer_check(struct nhrp_peer *p) +{ + struct nhrp_vc *vc = p->vc; + struct interface *ifp = p->ifp; + struct nhrp_interface *nifp = ifp->info; + unsigned online; + + online = nifp->enabled && (!nifp->ipsec_profile || vc->ipsec); + if (p->online != online) { + THREAD_OFF(p->t_fallback); + if (online && notifier_active(&p->notifier_list)) { + /* If we requested the IPsec connection, delay + * the up notification a bit to allow things + * settle down. This allows IKE to install + * SPDs and SAs. */ + THREAD_TIMER_MSEC_ON( + master, p->t_fallback, + nhrp_peer_notify_up, p, 50); + } else { + nhrp_peer_ref(p); + p->online = online; + if (online) { + notifier_call(&p->notifier_list, NOTIFY_PEER_UP); + } else { + p->requested = p->fallback_requested = 0; + notifier_call(&p->notifier_list, NOTIFY_PEER_DOWN); + } + nhrp_peer_unref(p); + } + } +} + +static void nhrp_peer_vc_notify(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_peer *p = container_of(n, struct nhrp_peer, vc_notifier); + + switch (cmd) { + case NOTIFY_VC_IPSEC_CHANGED: + __nhrp_peer_check(p); + break; + case NOTIFY_VC_IPSEC_UPDATE_NBMA: + nhrp_peer_ref(p); + notifier_call(&p->notifier_list, NOTIFY_PEER_NBMA_CHANGING); + nhrp_peer_unref(p); + break; + } +} + +static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_peer *p = container_of(n, struct nhrp_peer, ifp_notifier); + struct nhrp_interface *nifp; + struct nhrp_vc *vc; + + nhrp_peer_ref(p); + switch (cmd) { + case NOTIFY_INTERFACE_UP: + case NOTIFY_INTERFACE_DOWN: + __nhrp_peer_check(p); + break; + case NOTIFY_INTERFACE_NBMA_CHANGED: + /* Source NBMA changed, rebind to new VC */ + nifp = p->ifp->info; + vc = nhrp_vc_get(&nifp->nbma, &p->vc->remote.nbma, 1); + if (vc && p->vc != vc) { + nhrp_vc_notify_del(p->vc, &p->vc_notifier); + p->vc = vc; + nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify); + __nhrp_peer_check(p); + } + /* Fall-through to post config update */ + case NOTIFY_INTERFACE_ADDRESS_CHANGED: + notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED); + break; + case NOTIFY_INTERFACE_MTU_CHANGED: + notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED); + break; + } + nhrp_peer_unref(p); +} + +static unsigned int nhrp_peer_key(void *peer_data) +{ + struct nhrp_peer *p = peer_data; + return sockunion_hash(&p->vc->remote.nbma); +} + +static int nhrp_peer_cmp(const void *cache_data, const void *key_data) +{ + const struct nhrp_peer *a = cache_data; + const struct nhrp_peer *b = key_data; + return a->ifp == b->ifp && a->vc == b->vc; +} + +static void *nhrp_peer_create(void *data) +{ + struct nhrp_peer *p, *key = data; + + p = XMALLOC(MTYPE_NHRP_PEER, sizeof(*p)); + if (p) { + *p = (struct nhrp_peer) { + .ref = 0, + .ifp = key->ifp, + .vc = key->vc, + .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list), + }; + nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify); + nhrp_interface_notify_add(p->ifp, &p->ifp_notifier, nhrp_peer_ifp_notify); + } + return p; +} + +struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *remote_nbma) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_peer key, *p; + struct nhrp_vc *vc; + + if (!nifp->peer_hash) { + nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp); + if (!nifp->peer_hash) return NULL; + } + + vc = nhrp_vc_get(&nifp->nbma, remote_nbma, 1); + if (!vc) return NULL; + + key.ifp = ifp; + key.vc = vc; + + p = hash_get(nifp->peer_hash, &key, nhrp_peer_create); + nhrp_peer_ref(p); + if (p->ref == 1) __nhrp_peer_check(p); + + return p; +} + +struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p) +{ + if (p) p->ref++; + return p; +} + +void nhrp_peer_unref(struct nhrp_peer *p) +{ + if (p) { + p->ref--; + nhrp_peer_check_delete(p); + } +} + +static int nhrp_peer_request_timeout(struct thread *t) +{ + struct nhrp_peer *p = THREAD_ARG(t); + struct nhrp_vc *vc = p->vc; + struct interface *ifp = p->ifp; + struct nhrp_interface *nifp = ifp->info; + + p->t_fallback = NULL; + + if (p->online) + return 0; + + if (nifp->ipsec_fallback_profile && !p->prio && !p->fallback_requested) { + p->fallback_requested = 1; + vici_request_vc(nifp->ipsec_fallback_profile, + &vc->local.nbma, &vc->remote.nbma, p->prio); + THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p, 30); + } else { + p->requested = p->fallback_requested = 0; + } + + return 0; +} + +int nhrp_peer_check(struct nhrp_peer *p, int establish) +{ + struct nhrp_vc *vc = p->vc; + struct interface *ifp = p->ifp; + struct nhrp_interface *nifp = ifp->info; + + if (p->online) + return 1; + if (!establish) + return 0; + if (p->requested) + return 0; + if (sockunion_family(&vc->local.nbma) == AF_UNSPEC) + return 0; + + p->prio = establish > 1; + p->requested = 1; + vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma, p->prio); + THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p, + (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30); + + return 0; +} + +void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n, notifier_fn_t fn) +{ + notifier_add(n, &p->notifier_list, fn); +} + +void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n) +{ + notifier_del(n); + nhrp_peer_check_delete(p); +} + +void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb) +{ + char buf[2][256]; + + nhrp_packet_debug(zb, "Send"); + + if (!p->online) + return; + + debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %s -> %s", + sockunion2str(&p->vc->local.nbma, buf[0], sizeof buf[0]), + sockunion2str(&p->vc->remote.nbma, buf[1], sizeof buf[1])); + + os_sendmsg(zb->head, zbuf_used(zb), + p->ifp->ifindex, + sockunion_get_addr(&p->vc->remote.nbma), + sockunion_get_addrlen(&p->vc->remote.nbma)); + zbuf_reset(zb); +} + +static void nhrp_handle_resolution_req(struct nhrp_packet_parser *p) +{ + struct zbuf *zb, payload; + struct nhrp_packet_header *hdr; + struct nhrp_cie_header *cie; + struct nhrp_extension_header *ext; + struct nhrp_interface *nifp; + struct nhrp_peer *peer; + + if (!(p->if_ad->flags & NHRP_IFF_SHORTCUT)) { + debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled"); + /* FIXME: Send error indication? */ + return; + } + + if (p->if_ad->network_id && + p->route_type == NHRP_ROUTE_OFF_NBMA && + p->route_prefix.prefixlen < 8) { + debugf(NHRP_DEBUG_COMMON, "Shortcut to more generic than /8 dropped"); + return; + } + + debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Resolution Req"); + + if (nhrp_route_address(p->ifp, &p->src_proto, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP) + return; + +#if 0 + /* FIXME: Update requestors binding if CIE specifies holding time */ + nhrp_cache_update_binding( + NHRP_CACHE_CACHED, &p->src_proto, + nhrp_peer_get(p->ifp, &p->src_nbma), + htons(cie->holding_time)); +#endif + + nifp = peer->ifp->info; + + /* Create reply */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REPLY, &p->src_nbma, &p->src_proto, &p->dst_proto); + + /* Copied information from request */ + hdr->flags = p->hdr->flags & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER|NHRP_FLAG_RESOLUTION_SOURCE_STABLE); + hdr->flags |= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE | NHRP_FLAG_RESOLUTION_AUTHORATIVE); + hdr->u.request_id = p->hdr->u.request_id; + + /* CIE payload */ + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &p->if_ad->addr); + cie->holding_time = htons(p->if_ad->holdtime); + cie->mtu = htons(p->if_ad->mtu); + if (p->if_ad->network_id && p->route_type == NHRP_ROUTE_OFF_NBMA) + cie->prefix_length = p->route_prefix.prefixlen; + else + cie->prefix_length = 8 * sockunion_get_addrlen(&p->if_ad->addr); + + /* Handle extensions */ + while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_NAT_ADDRESS: + if (sockunion_family(&nifp->nat_nbma) == AF_UNSPEC) + break; + ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); + if (!ext) goto err; + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nat_nbma, &p->if_ad->addr); + if (!cie) goto err; + nhrp_ext_complete(zb, ext); + break; + default: + if (nhrp_ext_reply(zb, hdr, p->ifp, ext, &payload) < 0) + goto err; + break; + } + } + + nhrp_packet_complete(zb, hdr); + nhrp_peer_send(peer, zb); +err: + nhrp_peer_unref(peer); + zbuf_free(zb); +} + +static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) +{ + struct interface *ifp = p->ifp; + struct zbuf *zb, payload; + struct nhrp_packet_header *hdr; + struct nhrp_cie_header *cie; + struct nhrp_extension_header *ext; + struct nhrp_cache *c; + union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr, *nbma_natoa; + int holdtime, natted = 0; + size_t paylen; + void *pay; + + debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req"); + + if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma)) + natted = 1; + + /* Create reply */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REPLY, + &p->src_nbma, &p->src_proto, &p->if_ad->addr); + + /* Copied information from request */ + hdr->flags = p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE | NHRP_FLAG_REGISTRATION_NAT); + hdr->u.request_id = p->hdr->u.request_id; + + /* Copy payload CIEs */ + paylen = zbuf_used(&p->payload); + pay = zbuf_pushn(zb, paylen); + if (!pay) goto err; + memcpy(pay, zbuf_pulln(&p->payload, paylen), paylen); + zbuf_init(&payload, pay, paylen, paylen); + + while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto)) != NULL) { + if (cie->prefix_length != 0xff && !(p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) { + cie->code = NHRP_CODE_BINDING_NON_UNIQUE; + continue; + } + + /* We currently support only unique prefix registrations */ + if (cie->prefix_length != 0xff) { + cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; + continue; + } + + proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC) ? &p->src_proto : &cie_proto; + nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC) ? &p->src_nbma : &cie_nbma; + nbma_natoa = NULL; + if (natted) { + nbma_natoa = nbma_addr; + nbma_addr = &p->peer->vc->remote.nbma; + } + + holdtime = htons(cie->holding_time); + if (!holdtime) holdtime = p->if_ad->holdtime; + + c = nhrp_cache_get(ifp, proto_addr, 1); + if (!c) { + cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES; + continue; + } + + if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime, nhrp_peer_ref(p->peer), htons(cie->mtu), nbma_natoa)) { + cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; + continue; + } + + cie->code = NHRP_CODE_SUCCESS; + } + + /* Handle extensions */ + while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_NAT_ADDRESS: + ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); + if (!ext) goto err; + zbuf_copy(zb, &payload, zbuf_used(&payload)); + if (natted) { + nhrp_cie_push(zb, NHRP_CODE_SUCCESS, + &p->peer->vc->remote.nbma, + &p->src_proto); + } + nhrp_ext_complete(zb, ext); + break; + default: + if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0) + goto err; + break; + } + } + + nhrp_packet_complete(zb, hdr); + nhrp_peer_send(p->peer, zb); +err: + zbuf_free(zb); +} + +static int parse_ether_packet(struct zbuf *zb, uint16_t protocol_type, union sockunion *src, union sockunion *dst) +{ + switch (protocol_type) { + case ETH_P_IP: { + struct iphdr *iph = zbuf_pull(zb, struct iphdr); + if (iph) { + if (src) sockunion_set(src, AF_INET, (uint8_t*) &iph->saddr, sizeof(iph->saddr)); + if (dst) sockunion_set(dst, AF_INET, (uint8_t*) &iph->daddr, sizeof(iph->daddr)); + } + } + break; + case ETH_P_IPV6: { + struct ipv6hdr *iph = zbuf_pull(zb, struct ipv6hdr); + if (iph) { + if (src) sockunion_set(src, AF_INET6, (uint8_t*) &iph->saddr, sizeof(iph->saddr)); + if (dst) sockunion_set(dst, AF_INET6, (uint8_t*) &iph->daddr, sizeof(iph->daddr)); + } + } + break; + default: + return 0; + } + return 1; +} + +void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, struct zbuf *pkt) +{ + union sockunion dst; + struct zbuf *zb, payload; + struct nhrp_interface *nifp = ifp->info; + struct nhrp_afi_data *if_ad; + struct nhrp_packet_header *hdr; + struct nhrp_peer *p; + char buf[2][SU_ADDRSTRLEN]; + + if (!nifp->enabled) return; + + payload = *pkt; + if (!parse_ether_packet(&payload, protocol_type, &dst, NULL)) + return; + + if (nhrp_route_address(ifp, &dst, NULL, &p) != NHRP_ROUTE_NBMA_NEXTHOP) + return; + + if_ad = &nifp->afi[family2afi(sockunion_family(&dst))]; + if (!(if_ad->flags & NHRP_IFF_REDIRECT)) { + debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s about packet to %s ignored", + sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]), + sockunion2str(&dst, buf[1], sizeof buf[1])); + return; + } + + debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s (online=%d) about packet to %s", + sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]), + p->online, + sockunion2str(&dst, buf[1], sizeof buf[1])); + + /* Create reply */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma, &if_ad->addr, &dst); + hdr->hop_count = 0; + + /* Payload is the packet causing indication */ + zbuf_copy(zb, pkt, zbuf_used(pkt)); + nhrp_packet_complete(zb, hdr); + nhrp_peer_send(p, zb); + nhrp_peer_unref(p); + zbuf_free(zb); +} + +static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp) +{ + struct zbuf origmsg = pp->payload; + struct nhrp_packet_header *hdr; + struct nhrp_reqid *reqid; + union sockunion src_nbma, src_proto, dst_proto; + char buf[2][SU_ADDRSTRLEN]; + + hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto); + if (!hdr) return; + + debugf(NHRP_DEBUG_COMMON, "Error Indication from %s about packet to %s ignored", + sockunion2str(&pp->src_proto, buf[0], sizeof buf[0]), + sockunion2str(&dst_proto, buf[1], sizeof buf[1])); + + reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id)); + if (reqid) + reqid->cb(reqid, pp); +} + +static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p) +{ + union sockunion dst; + char buf[2][SU_ADDRSTRLEN]; + + if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL, &dst)) + return; + + debugf(NHRP_DEBUG_COMMON, "Traffic Indication from %s about packet to %s: %s", + sockunion2str(&p->src_proto, buf[0], sizeof buf[0]), + sockunion2str(&dst, buf[1], sizeof buf[1]), + (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut" : "ignored"); + + if (p->if_ad->flags & NHRP_IFF_SHORTCUT) + nhrp_shortcut_initiate(&dst); +} + +enum packet_type_t { + PACKET_UNKNOWN = 0, + PACKET_REQUEST, + PACKET_REPLY, + PACKET_INDICATION, +}; + +static struct { + enum packet_type_t type; + const char *name; + void (*handler)(struct nhrp_packet_parser *); +} packet_types[] = { + [NHRP_PACKET_RESOLUTION_REQUEST] = { + .type = PACKET_REQUEST, + .name = "Resolution-Request", + .handler = nhrp_handle_resolution_req, + }, + [NHRP_PACKET_RESOLUTION_REPLY] = { + .type = PACKET_REPLY, + .name = "Resolution-Reply", + }, + [NHRP_PACKET_REGISTRATION_REQUEST] = { + .type = PACKET_REQUEST, + .name = "Registration-Request", + .handler = nhrp_handle_registration_request, + }, + [NHRP_PACKET_REGISTRATION_REPLY] = { + .type = PACKET_REPLY, + .name = "Registration-Reply", + }, + [NHRP_PACKET_PURGE_REQUEST] = { + .type = PACKET_REQUEST, + .name = "Purge-Request", + }, + [NHRP_PACKET_PURGE_REPLY] = { + .type = PACKET_REPLY, + .name = "Purge-Reply", + }, + [NHRP_PACKET_ERROR_INDICATION] = { + .type = PACKET_INDICATION, + .name = "Error-Indication", + .handler = nhrp_handle_error_ind, + }, + [NHRP_PACKET_TRAFFIC_INDICATION] = { + .type = PACKET_INDICATION, + .name = "Traffic-Indication", + .handler = nhrp_handle_traffic_ind, + } +}; + +static void nhrp_peer_forward(struct nhrp_peer *p, struct nhrp_packet_parser *pp) +{ + struct zbuf *zb, extpl; + struct nhrp_packet_header *hdr; + struct nhrp_extension_header *ext, *dst; + struct nhrp_cie_header *cie; + struct nhrp_interface *nifp = pp->ifp->info; + struct nhrp_afi_data *if_ad = pp->if_ad; + union sockunion cie_nbma, cie_protocol; + uint16_t type, len; + + if (pp->hdr->hop_count == 0) + return; + + /* Create forward packet - copy header */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto, &pp->dst_proto); + hdr->flags = pp->hdr->flags; + hdr->hop_count = pp->hdr->hop_count - 1; + hdr->u.request_id = pp->hdr->u.request_id; + + /* Copy payload */ + zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload)); + + /* Copy extensions */ + while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { + type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY; + len = htons(ext->length); + + if (type == NHRP_EXTENSION_END) + break; + + dst = nhrp_ext_push(zb, hdr, htons(ext->type)); + if (!dst) goto err; + + switch (type) { + case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: + case NHRP_EXTENSION_REVERSE_TRANSIT_NHS: + zbuf_put(zb, extpl.head, len); + if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS) == + (packet_types[hdr->type].type == PACKET_REPLY)) { + /* Check NHS list for forwarding loop */ + while ((cie = nhrp_cie_pull(&extpl, pp->hdr, &cie_nbma, &cie_protocol)) != NULL) { + if (sockunion_same(&p->vc->remote.nbma, &cie_nbma)) + goto err; + } + /* Append our selves to the list */ + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr); + if (!cie) goto err; + cie->holding_time = htons(if_ad->holdtime); + } + break; + default: + if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) + /* FIXME: RFC says to just copy, but not + * append our selves to the transit NHS list */ + goto err; + case NHRP_EXTENSION_RESPONDER_ADDRESS: + /* Supported compulsory extensions, and any + * non-compulsory that is not explicitly handled, + * should be just copied. */ + zbuf_copy(zb, &extpl, len); + break; + } + nhrp_ext_complete(zb, dst); + } + + nhrp_packet_complete(zb, hdr); + nhrp_peer_send(p, zb); + zbuf_free(zb); + return; +err: + nhrp_packet_debug(pp->pkt, "FWD-FAIL"); + zbuf_free(zb); +} + +static void nhrp_packet_debug(struct zbuf *zb, const char *dir) +{ + char buf[2][SU_ADDRSTRLEN]; + union sockunion src_nbma, src_proto, dst_proto; + struct nhrp_packet_header *hdr; + struct zbuf zhdr; + int reply; + + if (likely(!(debug_flags & NHRP_DEBUG_COMMON))) + return; + + zbuf_init(&zhdr, zb->buf, zb->tail-zb->buf, zb->tail-zb->buf); + hdr = nhrp_packet_pull(&zhdr, &src_nbma, &src_proto, &dst_proto); + + sockunion2str(&src_proto, buf[0], sizeof buf[0]); + sockunion2str(&dst_proto, buf[1], sizeof buf[1]); + + reply = packet_types[hdr->type].type == PACKET_REPLY; + debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %s -> %s", + dir, + packet_types[hdr->type].name ? : "Unknown", + hdr->type, + reply ? buf[1] : buf[0], + reply ? buf[0] : buf[1]); +} + +struct nhrp_route_info { + int local; + struct interface *ifp; + struct nhrp_vc *vc; +}; + +void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) +{ + char buf[2][SU_ADDRSTRLEN]; + struct nhrp_packet_header *hdr; + struct nhrp_vc *vc = p->vc; + struct interface *ifp = p->ifp; + struct nhrp_interface *nifp = ifp->info; + struct nhrp_packet_parser pp; + struct nhrp_peer *peer = NULL; + struct nhrp_reqid *reqid; + const char *info = NULL; + union sockunion *target_addr; + unsigned paylen, extoff, extlen, realsize; + afi_t afi; + + debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s", + sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), + sockunion2str(&vc->local.nbma, buf[1], sizeof buf[1])); + + if (!p->online) { + info = "peer not online"; + goto drop; + } + + if (nhrp_packet_calculate_checksum(zb->head, zbuf_used(zb)) != 0) { + info = "bad checksum"; + goto drop; + } + + realsize = zbuf_used(zb); + hdr = nhrp_packet_pull(zb, &pp.src_nbma, &pp.src_proto, &pp.dst_proto); + if (!hdr) { + info = "corrupt header"; + goto drop; + } + + pp.ifp = ifp; + pp.pkt = zb; + pp.hdr = hdr; + pp.peer = p; + + afi = htons(hdr->afnum); + if (hdr->type > ZEBRA_NUM_OF(packet_types) || + hdr->version != NHRP_VERSION_RFC2332 || + afi >= AFI_MAX || + packet_types[hdr->type].type == PACKET_UNKNOWN || + htons(hdr->packet_size) > realsize) { + zlog_info("From %s: error: packet type %d, version %d, AFI %d, size %d (real size %d)", + sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), + (int) hdr->type, (int) hdr->version, (int) afi, + (int) htons(hdr->packet_size), + (int) realsize); + goto drop; + } + pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[afi]; + + extoff = htons(hdr->extension_offset); + if (extoff) { + if (extoff >= realsize) { + info = "extoff larger than packet"; + goto drop; + } + paylen = extoff - (zb->head - zb->buf); + } else { + paylen = zbuf_used(zb); + } + zbuf_init(&pp.payload, zbuf_pulln(zb, paylen), paylen, paylen); + extlen = zbuf_used(zb); + zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen); + + if (!nifp->afi[afi].network_id) { + info = "nhrp not enabled"; + goto drop; + } + + nhrp_packet_debug(zb, "Recv"); + + /* FIXME: Check authentication here. This extension needs to be + * pre-handled. */ + + /* Figure out if this is local */ + target_addr = (packet_types[hdr->type].type == PACKET_REPLY) ? &pp.src_proto : &pp.dst_proto; + + if (sockunion_same(&pp.src_proto, &pp.dst_proto)) + pp.route_type = NHRP_ROUTE_LOCAL; + else + pp.route_type = nhrp_route_address(pp.ifp, target_addr, &pp.route_prefix, &peer); + + switch (pp.route_type) { + case NHRP_ROUTE_LOCAL: + nhrp_packet_debug(zb, "!LOCAL"); + if (packet_types[hdr->type].type == PACKET_REPLY) { + reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id)); + if (reqid) { + reqid->cb(reqid, &pp); + break; + } else { + nhrp_packet_debug(zb, "!UNKNOWN-REQID"); + /* FIXME: send error-indication */ + } + } + case NHRP_ROUTE_OFF_NBMA: + if (packet_types[hdr->type].handler) { + packet_types[hdr->type].handler(&pp); + break; + } + break; + case NHRP_ROUTE_NBMA_NEXTHOP: + nhrp_peer_forward(peer, &pp); + break; + case NHRP_ROUTE_BLACKHOLE: + break; + } + +drop: + if (info) { + zlog_info("From %s: error: %s", + sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), + info); + } + if (peer) nhrp_peer_unref(peer); + zbuf_free(zb); +} diff --git a/nhrpd/nhrp_protocol.h b/nhrpd/nhrp_protocol.h new file mode 100644 index 000000000..a4bc9fa6b --- /dev/null +++ b/nhrpd/nhrp_protocol.h @@ -0,0 +1,128 @@ +/* nhrp_protocol.h - NHRP protocol definitions + * + * Copyright (c) 2007-2012 Timo Teräs + * + * This software is licensed under the MIT License. + * See MIT-LICENSE.txt for additional details. + */ + +#ifndef NHRP_PROTOCOL_H +#define NHRP_PROTOCOL_H + +#include + +/* NHRP Ethernet protocol number */ +#define ETH_P_NHRP 0x2001 + +/* NHRP Version */ +#define NHRP_VERSION_RFC2332 1 + +/* NHRP Packet Types */ +#define NHRP_PACKET_RESOLUTION_REQUEST 1 +#define NHRP_PACKET_RESOLUTION_REPLY 2 +#define NHRP_PACKET_REGISTRATION_REQUEST 3 +#define NHRP_PACKET_REGISTRATION_REPLY 4 +#define NHRP_PACKET_PURGE_REQUEST 5 +#define NHRP_PACKET_PURGE_REPLY 6 +#define NHRP_PACKET_ERROR_INDICATION 7 +#define NHRP_PACKET_TRAFFIC_INDICATION 8 + +/* NHRP Extension Types */ +#define NHRP_EXTENSION_FLAG_COMPULSORY 0x8000 +#define NHRP_EXTENSION_END 0 +#define NHRP_EXTENSION_PAYLOAD 0 +#define NHRP_EXTENSION_RESPONDER_ADDRESS 3 +#define NHRP_EXTENSION_FORWARD_TRANSIT_NHS 4 +#define NHRP_EXTENSION_REVERSE_TRANSIT_NHS 5 +#define NHRP_EXTENSION_AUTHENTICATION 7 +#define NHRP_EXTENSION_VENDOR 8 +#define NHRP_EXTENSION_NAT_ADDRESS 9 + +/* NHRP Error Indication Codes */ +#define NHRP_ERROR_UNRECOGNIZED_EXTENSION 1 +#define NHRP_ERROR_LOOP_DETECTED 2 +#define NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE 6 +#define NHRP_ERROR_PROTOCOL_ERROR 7 +#define NHRP_ERROR_SDU_SIZE_EXCEEDED 8 +#define NHRP_ERROR_INVALID_EXTENSION 9 +#define NHRP_ERROR_INVALID_RESOLUTION_REPLY 10 +#define NHRP_ERROR_AUTHENTICATION_FAILURE 11 +#define NHRP_ERROR_HOP_COUNT_EXCEEDED 15 + +/* NHRP CIE Codes */ +#define NHRP_CODE_SUCCESS 0 +#define NHRP_CODE_ADMINISTRATIVELY_PROHIBITED 4 +#define NHRP_CODE_INSUFFICIENT_RESOURCES 5 +#define NHRP_CODE_NO_BINDING_EXISTS 11 +#define NHRP_CODE_BINDING_NON_UNIQUE 13 +#define NHRP_CODE_UNIQUE_ADDRESS_REGISTERED 14 + +/* NHRP Flags for Resolution request/reply */ +#define NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER 0x8000 +#define NHRP_FLAG_RESOLUTION_AUTHORATIVE 0x4000 +#define NHRP_FLAG_RESOLUTION_DESTINATION_STABLE 0x2000 +#define NHRP_FLAG_RESOLUTION_UNIQUE 0x1000 +#define NHRP_FLAG_RESOLUTION_SOURCE_STABLE 0x0800 +#define NHRP_FLAG_RESOLUTION_NAT 0x0002 + +/* NHRP Flags for Registration request/reply */ +#define NHRP_FLAG_REGISTRATION_UNIQUE 0x8000 +#define NHRP_FLAG_REGISTRATION_NAT 0x0002 + +/* NHRP Flags for Purge request/reply */ +#define NHRP_FLAG_PURGE_NO_REPLY 0x8000 + +/* NHRP Authentication extension types (ala Cisco) */ +#define NHRP_AUTHENTICATION_PLAINTEXT 0x00000001 + +/* NHRP Packet Structures */ +struct nhrp_packet_header { + /* Fixed header */ + uint16_t afnum; + uint16_t protocol_type; + uint8_t snap[5]; + uint8_t hop_count; + uint16_t packet_size; + uint16_t checksum; + uint16_t extension_offset; + uint8_t version; + uint8_t type; + uint8_t src_nbma_address_len; + uint8_t src_nbma_subaddress_len; + + /* Mandatory header */ + uint8_t src_protocol_address_len; + uint8_t dst_protocol_address_len; + uint16_t flags; + union { + uint32_t request_id; + struct { + uint16_t code; + uint16_t offset; + } error; + } u; +} __attribute__((packed)); + +struct nhrp_cie_header { + uint8_t code; + uint8_t prefix_length; + uint16_t unused; + uint16_t mtu; + uint16_t holding_time; + uint8_t nbma_address_len; + uint8_t nbma_subaddress_len; + uint8_t protocol_address_len; + uint8_t preference; +} __attribute__((packed)); + +struct nhrp_extension_header { + uint16_t type; + uint16_t length; +} __attribute__((packed)); + +struct nhrp_cisco_authentication_extension { + uint32_t type; + uint8_t secret[8]; +} __attribute__((packed)); + +#endif diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c new file mode 100644 index 000000000..cc6b5fa24 --- /dev/null +++ b/nhrpd/nhrp_route.c @@ -0,0 +1,345 @@ +/* NHRP routing functions + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "nhrpd.h" +#include "table.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "zclient.h" + +static struct zclient *zclient; +static struct route_table *zebra_rib[AFI_MAX]; + +struct route_info { + union sockunion via; + struct interface *ifp; + struct interface *nhrp_ifp; +}; + +static void nhrp_zebra_connected(struct zclient *zclient) +{ + /* No real VRF support yet -- bind only to the default vrf */ + zclient_send_requests (zclient, VRF_DEFAULT); +} + +static struct route_node *nhrp_route_update_get(const struct prefix *p, int create) +{ + struct route_node *rn; + afi_t afi = family2afi(PREFIX_FAMILY(p)); + + if (!zebra_rib[afi]) + return NULL; + + if (create) { + rn = route_node_get(zebra_rib[afi], p); + if (!rn->info) { + rn->info = XCALLOC(MTYPE_NHRP_ROUTE, sizeof(struct route_info)); + route_lock_node(rn); + } + return rn; + } else { + return route_node_lookup(zebra_rib[afi], p); + } +} + +static void nhrp_route_update_put(struct route_node *rn) +{ + struct route_info *ri = rn->info; + + if (!ri->ifp && !ri->nhrp_ifp && sockunion_family(&ri->via) == AF_UNSPEC) { + XFREE(MTYPE_NHRP_ROUTE, rn->info); + rn->info = NULL; + route_unlock_node(rn); + } + route_unlock_node(rn); +} + +static void nhrp_route_update_zebra(const struct prefix *p, union sockunion *nexthop, struct interface *ifp) +{ + struct route_node *rn; + struct route_info *ri; + + rn = nhrp_route_update_get(p, (sockunion_family(nexthop) != AF_UNSPEC) || ifp); + if (rn) { + ri = rn->info; + ri->via = *nexthop; + ri->ifp = ifp; + nhrp_route_update_put(rn); + } +} + +void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) +{ + struct route_node *rn; + struct route_info *ri; + + rn = nhrp_route_update_get(p, ifp != NULL); + if (rn) { + ri = rn->info; + ri->nhrp_ifp = ifp; + nhrp_route_update_put(rn); + } +} + +void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu) +{ + struct in_addr *nexthop_ipv4; + int flags = 0; + + if (zclient->sock < 0) + return; + + switch (type) { + case NHRP_CACHE_NEGATIVE: + SET_FLAG(flags, ZEBRA_FLAG_REJECT); + break; + case NHRP_CACHE_DYNAMIC: + case NHRP_CACHE_NHS: + case NHRP_CACHE_STATIC: + /* Regular route, so these are announced + * to other routing daemons */ + break; + default: + SET_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE); + break; + } + SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); + + if (p->family == AF_INET) { + struct zapi_ipv4 api; + + memset(&api, 0, sizeof(api)); + api.flags = flags; + api.type = ZEBRA_ROUTE_NHRP; + api.safi = SAFI_UNICAST; + + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + if (nexthop) { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + nexthop_ipv4 = (struct in_addr *) sockunion_get_addr(nexthop); + api.nexthop_num = 1; + api.nexthop = &nexthop_ipv4; + } + if (ifp) { + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifp->ifindex; + } + if (mtu) { + SET_FLAG(api.message, ZAPI_MESSAGE_MTU); + api.mtu = mtu; + } + + if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug("Zebra send: IPv4 route %s %s/%d nexthop %s metric %u" + " count %d dev %s", + add ? "add" : "del", + inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), + p->prefixlen, + nexthop ? inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])) : "", + api.metric, api.nexthop_num, ifp->name); + } + + zapi_ipv4_route( + add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE, + zclient, (struct prefix_ipv4 *) p, &api); + } +} + +int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) +{ + struct stream *s; + struct interface *ifp = NULL; + struct prefix prefix; + union sockunion nexthop_addr; + unsigned char message, nexthop_num, ifindex_num; + unsigned ifindex; + char buf[2][PREFIX_STRLEN]; + int i, afaddrlen, added; + + s = zclient->ibuf; + memset(&prefix, 0, sizeof(prefix)); + sockunion_family(&nexthop_addr) = AF_UNSPEC; + + /* Type, flags, message. */ + /*type =*/ stream_getc(s); + /*flags =*/ stream_getc(s); + message = stream_getc(s); + + /* Prefix */ + switch (cmd) { + case ZEBRA_IPV4_ROUTE_ADD: + case ZEBRA_IPV4_ROUTE_DELETE: + prefix.family = AF_INET; + break; + case ZEBRA_IPV6_ROUTE_ADD: + case ZEBRA_IPV6_ROUTE_DELETE: + prefix.family = AF_INET6; + break; + default: + return -1; + } + afaddrlen = family2addrsize(prefix.family); + prefix.prefixlen = stream_getc(s); + stream_get(&prefix.u.val, s, PSIZE(prefix.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX)) { + nexthop_num = stream_getc(s); + for (i = 0; i < nexthop_num; i++) { + stream_get(buf[0], s, afaddrlen); + if (i == 0) sockunion_set(&nexthop_addr, prefix.family, (u_char*) buf[0], afaddrlen); + } + ifindex_num = stream_getc(s); + for (i = 0; i < ifindex_num; i++) { + ifindex = stream_getl(s); + if (i == 0 && ifindex != IFINDEX_INTERNAL) + ifp = if_lookup_by_index(ifindex); + } + } + if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE)) + /*distance =*/ stream_getc(s); + if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) + /*metric =*/ stream_getl(s); + + added = (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD); + debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s", + added ? "add" : "del", + prefix2str(&prefix, buf[0], sizeof buf[0]), + sockunion2str(&nexthop_addr, buf[1], sizeof buf[1]), + ifp ? ifp->name : "(none)"); + + nhrp_route_update_zebra(&prefix, &nexthop_addr, ifp); + nhrp_shortcut_prefix_change(&prefix, !added); + + return 0; +} + +int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p, union sockunion *via, struct interface **ifp) +{ + struct route_node *rn; + struct route_info *ri; + struct prefix lookup; + afi_t afi = family2afi(sockunion_family(addr)); + char buf[PREFIX_STRLEN]; + + sockunion2hostprefix(addr, &lookup); + + rn = route_node_match(zebra_rib[afi], &lookup); + if (!rn) return 0; + + ri = rn->info; + if (ri->nhrp_ifp) { + debugf(NHRP_DEBUG_ROUTE, "lookup %s: nhrp_if=%s", + prefix2str(&lookup, buf, sizeof buf), + ri->nhrp_ifp->name); + + if (via) sockunion_family(via) = AF_UNSPEC; + if (ifp) *ifp = ri->nhrp_ifp; + } else { + debugf(NHRP_DEBUG_ROUTE, "lookup %s: zebra route dev %s", + prefix2str(&lookup, buf, sizeof buf), + ri->ifp ? ri->ifp->name : "(none)"); + + if (via) *via = ri->via; + if (ifp) *ifp = ri->ifp; + } + if (p) *p = rn->p; + route_unlock_node(rn); + return 1; +} + +enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunion *addr, struct prefix *p, struct nhrp_peer **peer) +{ + struct interface *ifp = in_ifp; + struct nhrp_interface *nifp; + struct nhrp_cache *c; + union sockunion via[4]; + uint32_t network_id = 0; + afi_t afi = family2afi(sockunion_family(addr)); + int i; + + if (ifp) { + nifp = ifp->info; + network_id = nifp->afi[afi].network_id; + + c = nhrp_cache_get(ifp, addr, 0); + if (c && c->cur.type == NHRP_CACHE_LOCAL) { + if (p) memset(p, 0, sizeof(*p)); + return NHRP_ROUTE_LOCAL; + } + } + + for (i = 0; i < 4; i++) { + if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp)) + return NHRP_ROUTE_BLACKHOLE; + if (ifp) { + /* Departing from nbma network? */ + nifp = ifp->info; + if (network_id && network_id != nifp->afi[afi].network_id) + return NHRP_ROUTE_OFF_NBMA; + } + if (sockunion_family(&via[i]) == AF_UNSPEC) + break; + /* Resolve via node, but return the prefix of first match */ + addr = &via[i]; + p = NULL; + } + + if (ifp) { + c = nhrp_cache_get(ifp, addr, 0); + if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) { + if (p) memset(p, 0, sizeof(*p)); + if (c->cur.type == NHRP_CACHE_LOCAL) + return NHRP_ROUTE_LOCAL; + if (peer) *peer = nhrp_peer_ref(c->cur.peer); + return NHRP_ROUTE_NBMA_NEXTHOP; + } + } + + return NHRP_ROUTE_BLACKHOLE; +} + +void nhrp_zebra_init(void) +{ + zebra_rib[AFI_IP] = route_table_init(); + zebra_rib[AFI_IP6] = route_table_init(); + + zclient = zclient_new(master); + zclient->zebra_connected = nhrp_zebra_connected; + zclient->interface_add = nhrp_interface_add; + zclient->interface_delete = nhrp_interface_delete; + zclient->interface_up = nhrp_interface_up; + zclient->interface_down = nhrp_interface_down; + zclient->interface_address_add = nhrp_interface_address_add; + zclient->interface_address_delete = nhrp_interface_address_delete; + zclient->ipv4_route_add = nhrp_route_read; + zclient->ipv4_route_delete = nhrp_route_read; + zclient->ipv6_route_add = nhrp_route_read; + zclient->ipv6_route_delete = nhrp_route_read; + + zclient_init(zclient, ZEBRA_ROUTE_NHRP); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_KERNEL, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_CONNECT, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_STATIC, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_RIP, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_OSPF, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_ISIS, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_BGP, VRF_DEFAULT); +} + +void nhrp_zebra_terminate(void) +{ + zclient_stop(zclient); + route_table_finish(zebra_rib[AFI_IP]); + route_table_finish(zebra_rib[AFI_IP6]); +} + diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c new file mode 100644 index 000000000..421f2886f --- /dev/null +++ b/nhrpd/nhrp_shortcut.c @@ -0,0 +1,402 @@ +/* NHRP shortcut related functions + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "nhrpd.h" +#include "table.h" +#include "memory.h" +#include "thread.h" +#include "log.h" +#include "nhrp_protocol.h" + +static struct route_table *shortcut_rib[AFI_MAX]; + +static int nhrp_shortcut_do_purge(struct thread *t); +static void nhrp_shortcut_delete(struct nhrp_shortcut *s); +static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s); + +static void nhrp_shortcut_check_use(struct nhrp_shortcut *s) +{ + char buf[PREFIX_STRLEN]; + + if (s->expiring && s->cache && s->cache->used) { + debugf(NHRP_DEBUG_ROUTE, "Shortcut %s used and expiring", + prefix2str(s->p, buf, sizeof buf)); + nhrp_shortcut_send_resolution_req(s); + } +} + +static int nhrp_shortcut_do_expire(struct thread *t) +{ + struct nhrp_shortcut *s = THREAD_ARG(t); + + s->t_timer = NULL; + THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, s->holding_time/3); + s->expiring = 1; + nhrp_shortcut_check_use(s); + + return 0; +} + +static void nhrp_shortcut_cache_notify(struct notifier_block *n, unsigned long cmd) +{ + struct nhrp_shortcut *s = container_of(n, struct nhrp_shortcut, cache_notifier); + + switch (cmd) { + case NOTIFY_CACHE_UP: + if (!s->route_installed) { + nhrp_route_announce(1, s->type, s->p, NULL, &s->cache->remote_addr, 0); + s->route_installed = 1; + } + break; + case NOTIFY_CACHE_USED: + nhrp_shortcut_check_use(s); + break; + case NOTIFY_CACHE_DOWN: + case NOTIFY_CACHE_DELETE: + if (s->route_installed) { + nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0); + s->route_installed = 0; + } + if (cmd == NOTIFY_CACHE_DELETE) + nhrp_shortcut_delete(s); + break; + } +} + +static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, enum nhrp_cache_type type, struct nhrp_cache *c, int holding_time) +{ + s->type = type; + if (c != s->cache) { + if (s->cache) { + nhrp_cache_notify_del(s->cache, &s->cache_notifier); + s->cache = NULL; + } + s->cache = c; + if (s->cache) { + nhrp_cache_notify_add(s->cache, &s->cache_notifier, nhrp_shortcut_cache_notify); + if (s->cache->route_installed) { + /* Force renewal of Zebra announce on prefix change */ + s->route_installed = 0; + nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_UP); + } + } + if (!s->cache || !s->cache->route_installed) + nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_DOWN); + } + if (s->type == NHRP_CACHE_NEGATIVE && !s->route_installed) { + nhrp_route_announce(1, s->type, s->p, NULL, NULL, 0); + s->route_installed = 1; + } else if (s->type == NHRP_CACHE_INVALID && s->route_installed) { + nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0); + s->route_installed = 0; + } + + THREAD_OFF(s->t_timer); + if (holding_time) { + s->expiring = 0; + s->holding_time = holding_time; + THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_expire, s, 2*holding_time/3); + } +} + +static void nhrp_shortcut_delete(struct nhrp_shortcut *s) +{ + struct route_node *rn; + afi_t afi = family2afi(PREFIX_FAMILY(s->p)); + char buf[PREFIX_STRLEN]; + + THREAD_OFF(s->t_timer); + nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); + + debugf(NHRP_DEBUG_ROUTE, "Shortcut %s purged", + prefix2str(s->p, buf, sizeof buf)); + + nhrp_shortcut_update_binding(s, NHRP_CACHE_INVALID, NULL, 0); + + /* Delete node */ + rn = route_node_lookup(shortcut_rib[afi], s->p); + if (rn) { + XFREE(MTYPE_NHRP_SHORTCUT, rn->info); + rn->info = NULL; + route_unlock_node(rn); + route_unlock_node(rn); + } +} + +static int nhrp_shortcut_do_purge(struct thread *t) +{ + struct nhrp_shortcut *s = THREAD_ARG(t); + s->t_timer = NULL; + nhrp_shortcut_delete(s); + return 0; +} + +static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p) +{ + struct nhrp_shortcut *s; + struct route_node *rn; + char buf[PREFIX_STRLEN]; + afi_t afi = family2afi(PREFIX_FAMILY(p)); + + if (!shortcut_rib[afi]) + return 0; + + rn = route_node_get(shortcut_rib[afi], p); + if (!rn->info) { + s = rn->info = XCALLOC(MTYPE_NHRP_SHORTCUT, sizeof(struct nhrp_shortcut)); + s->type = NHRP_CACHE_INVALID; + s->p = &rn->p; + + debugf(NHRP_DEBUG_ROUTE, "Shortcut %s created", + prefix2str(s->p, buf, sizeof buf)); + } else { + s = rn->info; + route_unlock_node(rn); + } + return s; +} + +static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, void *arg) +{ + struct nhrp_packet_parser *pp = arg; + struct nhrp_shortcut *s = container_of(reqid, struct nhrp_shortcut, reqid); + struct nhrp_shortcut *ps; + struct nhrp_extension_header *ext; + struct nhrp_cie_header *cie; + struct nhrp_cache *c = NULL; + union sockunion *proto, cie_proto, *nbma, *nbma_natoa, cie_nbma, nat_nbma; + struct prefix prefix, route_prefix; + struct zbuf extpl; + char bufp[PREFIX_STRLEN], buf[3][SU_ADDRSTRLEN]; + int holding_time = pp->if_ad->holdtime; + + nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); + THREAD_OFF(s->t_timer); + THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 1); + + if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) { + if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION && + pp->hdr->u.error.code == NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE) { + debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution: Protocol address unreachable"); + nhrp_shortcut_update_binding(s, NHRP_CACHE_NEGATIVE, NULL, holding_time); + } else { + debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution failed"); + } + return; + } + + /* Parse extensions */ + memset(&nat_nbma, 0, sizeof nat_nbma); + while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_NAT_ADDRESS: + nhrp_cie_pull(&extpl, pp->hdr, &nat_nbma, &cie_proto); + break; + } + } + + /* Minor sanity check */ + prefix2sockunion(s->p, &cie_proto); + if (!sockunion_same(&cie_proto, &pp->dst_proto)) { + debugf(NHRP_DEBUG_COMMON, "Shortcut: Warning dst_proto altered from %s to %s", + sockunion2str(&cie_proto, buf[0], sizeof buf[0]), + sockunion2str(&pp->dst_proto, buf[1], sizeof buf[1])); + } + + /* One or more CIEs should be given as reply, we support only one */ + cie = nhrp_cie_pull(&pp->payload, pp->hdr, &cie_nbma, &cie_proto); + if (!cie || cie->code != NHRP_CODE_SUCCESS) { + debugf(NHRP_DEBUG_COMMON, "Shortcut: CIE code %d", cie ? cie->code : -1); + return; + } + + proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &pp->dst_proto; + if (cie->holding_time) + holding_time = htons(cie->holding_time); + + prefix = *s->p; + prefix.prefixlen = cie->prefix_length; + + /* Sanity check prefix length */ + if (prefix.prefixlen >= 8*prefix_blen(&prefix)) { + prefix.prefixlen = 8*prefix_blen(&prefix); + } else if (nhrp_route_address(NULL, &pp->dst_proto, &route_prefix, NULL) == NHRP_ROUTE_NBMA_NEXTHOP) { + if (prefix.prefixlen < route_prefix.prefixlen) + prefix.prefixlen = route_prefix.prefixlen; + } + + debugf(NHRP_DEBUG_COMMON, "Shortcut: %s is at proto %s cie-nbma %s nat-nbma %s cie-holdtime %d", + prefix2str(&prefix, bufp, sizeof bufp), + sockunion2str(proto, buf[0], sizeof buf[0]), + sockunion2str(&cie_nbma, buf[1], sizeof buf[1]), + sockunion2str(&nat_nbma, buf[2], sizeof buf[2]), + htons(cie->holding_time)); + + /* Update cache entry for the protocol to nbma binding */ + if (sockunion_family(&nat_nbma) != AF_UNSPEC) { + nbma = &nat_nbma; + nbma_natoa = &cie_nbma; + } else { + nbma = &cie_nbma; + nbma_natoa = NULL; + } + if (sockunion_family(nbma)) { + c = nhrp_cache_get(pp->ifp, proto, 1); + if (c) { + nhrp_cache_update_binding( + c, NHRP_CACHE_CACHED, holding_time, + nhrp_peer_get(pp->ifp, nbma), + htons(cie->mtu), nbma_natoa); + } + } + + /* Update shortcut entry for subnet to protocol gw binding */ + if (c && !sockunion_same(proto, &pp->dst_proto)) { + ps = nhrp_shortcut_get(&prefix); + if (ps) { + ps->addr = s->addr; + nhrp_shortcut_update_binding(ps, NHRP_CACHE_CACHED, c, holding_time); + } + } + + debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled"); +} + +static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) +{ + struct zbuf *zb; + struct nhrp_packet_header *hdr; + struct interface *ifp; + struct nhrp_interface *nifp; + struct nhrp_peer *peer; + + if (nhrp_route_address(NULL, &s->addr, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP) + return; + + if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE) + s->type = NHRP_CACHE_INCOMPLETE; + + ifp = peer->ifp; + nifp = ifp->info; + + /* Create request */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REQUEST, + &nifp->nbma, &nifp->afi[family2afi(sockunion_family(&s->addr))].addr, &s->addr); + hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid, nhrp_shortcut_recv_resolution_rep)); + hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER | + NHRP_FLAG_RESOLUTION_AUTHORATIVE | + NHRP_FLAG_RESOLUTION_SOURCE_STABLE); + + /* RFC2332 - One or zero CIEs, if CIE is present contains: + * - Prefix length: widest acceptable prefix we accept (if U set, 0xff) + * - MTU: MTU of the source station + * - Holding Time: Max time to cache the source information + * */ + /* FIXME: Send holding time, and MTU */ + + nhrp_ext_request(zb, hdr, ifp); + + /* Cisco NAT detection extension */ + hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); + nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); + + nhrp_packet_complete(zb, hdr); + + nhrp_peer_send(peer, zb); + nhrp_peer_unref(peer); + zbuf_free(zb); +} + +void nhrp_shortcut_initiate(union sockunion *addr) +{ + struct prefix p; + struct nhrp_shortcut *s; + + sockunion2hostprefix(addr, &p); + s = nhrp_shortcut_get(&p); + if (s && s->type != NHRP_CACHE_INCOMPLETE) { + s->addr = *addr; + THREAD_OFF(s->t_timer); + THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 30); + nhrp_shortcut_send_resolution_req(s); + } +} + +void nhrp_shortcut_init(void) +{ + shortcut_rib[AFI_IP] = route_table_init(); + shortcut_rib[AFI_IP6] = route_table_init(); +} + +void nhrp_shortcut_terminate(void) +{ + route_table_finish(shortcut_rib[AFI_IP]); + route_table_finish(shortcut_rib[AFI_IP6]); +} + +void nhrp_shortcut_foreach(afi_t afi, void (*cb)(struct nhrp_shortcut *, void *), void *ctx) +{ + struct route_table *rt = shortcut_rib[afi]; + struct route_node *rn; + route_table_iter_t iter; + + if (!rt) return; + + route_table_iter_init(&iter, rt); + while ((rn = route_table_iter_next(&iter)) != NULL) { + if (rn->info) cb(rn->info, ctx); + } + route_table_iter_cleanup(&iter); +} + +struct purge_ctx { + const struct prefix *p; + int deleted; +}; + +void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force) +{ + THREAD_OFF(s->t_timer); + nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); + + if (force) { + /* Immediate purge on route with draw or pending shortcut */ + THREAD_TIMER_MSEC_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 5); + } else { + /* Soft expire - force immediate renewal, but purge + * in few seconds to make sure stale route is not + * used too long. In practice most purges are caused + * by hub bgp change, but target usually stays same. + * This allows to keep nhrp route up, and to not + * cause temporary rerouting via hubs causing latency + * jitter. */ + THREAD_TIMER_MSEC_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 3000); + s->expiring = 1; + nhrp_shortcut_check_use(s); + } +} + +static void nhrp_shortcut_purge_prefix(struct nhrp_shortcut *s, void *ctx) +{ + struct purge_ctx *pctx = ctx; + + if (prefix_match(pctx->p, s->p)) + nhrp_shortcut_purge(s, pctx->deleted || !s->cache); +} + +void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted) +{ + struct purge_ctx pctx = { + .p = p, + .deleted = deleted, + }; + nhrp_shortcut_foreach(family2afi(PREFIX_FAMILY(p)), nhrp_shortcut_purge_prefix, &pctx); +} + diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c new file mode 100644 index 000000000..f9e1ee068 --- /dev/null +++ b/nhrpd/nhrp_vc.c @@ -0,0 +1,217 @@ +/* NHRP virtual connection + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "zebra.h" +#include "memory.h" +#include "stream.h" +#include "hash.h" +#include "thread.h" +#include "jhash.h" + +#include "nhrpd.h" +#include "os.h" + +struct child_sa { + uint32_t id; + struct nhrp_vc *vc; + struct list_head childlist_entry; +}; + +static struct hash *nhrp_vc_hash; +static struct list_head childlist_head[512]; + +static unsigned int nhrp_vc_key(void *peer_data) +{ + struct nhrp_vc *vc = peer_data; + return jhash_2words( + sockunion_hash(&vc->local.nbma), + sockunion_hash(&vc->remote.nbma), + 0); +} + +static int nhrp_vc_cmp(const void *cache_data, const void *key_data) +{ + const struct nhrp_vc *a = cache_data; + const struct nhrp_vc *b = key_data; + return sockunion_same(&a->local.nbma, &b->local.nbma) && + sockunion_same(&a->remote.nbma, &b->remote.nbma); +} + +static void *nhrp_vc_alloc(void *data) +{ + struct nhrp_vc *vc, *key = data; + + vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc)); + if (vc) { + *vc = (struct nhrp_vc) { + .local.nbma = key->local.nbma, + .remote.nbma = key->remote.nbma, + .notifier_list = NOTIFIER_LIST_INITIALIZER(&vc->notifier_list), + }; + } + + return vc; +} + +static void nhrp_vc_free(void *data) +{ + XFREE(MTYPE_NHRP_VC, data); +} + +struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create) +{ + struct nhrp_vc key; + key.local.nbma = *src; + key.remote.nbma = *dst; + return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0); +} + +static void nhrp_vc_check_delete(struct nhrp_vc *vc) +{ + if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list)) + return; + hash_release(nhrp_vc_hash, vc); + nhrp_vc_free(vc); +} + +static void nhrp_vc_update(struct nhrp_vc *vc, long cmd) +{ + vc->updating = 1; + notifier_call(&vc->notifier_list, cmd); + vc->updating = 0; + nhrp_vc_check_delete(vc); +} + +static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc) +{ + vc->local.id[0] = 0; + vc->local.certlen = 0; + vc->remote.id[0] = 0; + vc->remote.certlen = 0; +} + +int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) +{ + char buf[2][SU_ADDRSTRLEN]; + struct child_sa *sa = NULL, *lsa; + uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head); + int abort_migration = 0; + + list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) { + if (lsa->id == child_id) { + sa = lsa; + break; + } + } + + if (!sa) { + if (!vc) return 0; + + sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa)); + if (!sa) return 0; + + *sa = (struct child_sa) { + .id = child_id, + .childlist_entry = LIST_INITIALIZER(sa->childlist_entry), + .vc = NULL, + }; + list_add_tail(&sa->childlist_entry, &childlist_head[child_hash]); + } + + if (sa->vc == vc) + return 0; + + if (vc) { + /* Attach first to new VC */ + vc->ipsec++; + nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED); + } + if (sa->vc && vc) { + /* Notify old VC of migration */ + sa->vc->abort_migration = 0; + debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s", + sockunion2str(&sa->vc->remote.nbma, buf[0], sizeof buf[0]), + sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1])); + nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA); + abort_migration = sa->vc->abort_migration; + } + if (sa->vc) { + /* Deattach old VC */ + sa->vc->ipsec--; + if (!sa->vc->ipsec) nhrp_vc_ipsec_reset(sa->vc); + nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED); + } + + /* Update */ + sa->vc = vc; + if (!vc) { + list_del(&sa->childlist_entry); + XFREE(MTYPE_NHRP_VC, sa); + } + + return abort_migration; +} + +void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, notifier_fn_t action) +{ + notifier_add(n, &vc->notifier_list, action); +} + +void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n) +{ + notifier_del(n); + nhrp_vc_check_delete(vc); +} + + +struct nhrp_vc_iterator_ctx { + void (*cb)(struct nhrp_vc *, void *); + void *ctx; +}; + +static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) +{ + struct nhrp_vc_iterator_ctx *ic = ctx; + ic->cb(b->data, ic->ctx); +} + +void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx) +{ + struct nhrp_vc_iterator_ctx ic = { + .cb = cb, + .ctx = ctx, + }; + hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic); +} + +void nhrp_vc_init(void) +{ + size_t i; + + nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp); + for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) + list_init(&childlist_head[i]); +} + +void nhrp_vc_reset(void) +{ + struct child_sa *sa, *n; + size_t i; + + for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) { + list_for_each_entry_safe(sa, n, &childlist_head[i], childlist_entry) + nhrp_vc_ipsec_updown(sa->id, 0); + } +} + +void nhrp_vc_terminate(void) +{ + nhrp_vc_reset(); + hash_clean(nhrp_vc_hash, nhrp_vc_free); +} diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c new file mode 100644 index 000000000..9b1c69de5 --- /dev/null +++ b/nhrpd/nhrp_vty.c @@ -0,0 +1,928 @@ +/* NHRP vty handling + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "zebra.h" +#include "command.h" +#include "zclient.h" +#include "stream.h" + +#include "nhrpd.h" +#include "netlink.h" + +static struct cmd_node zebra_node = { + .node = ZEBRA_NODE, + .prompt = "%s(config-router)# ", + .vtysh = 1, +}; + +static struct cmd_node nhrp_interface_node = { + .node = INTERFACE_NODE, + .prompt = "%s(config-if)# ", + .vtysh = 1, +}; + +#define NHRP_DEBUG_FLAGS_CMD "(all|common|event|interface|kernel|route|vici)" + +#define NHRP_DEBUG_FLAGS_STR \ + "All messages\n" \ + "Common messages (default)\n" \ + "Event manager messages\n" \ + "Interface messages\n" \ + "Kernel messages\n" \ + "Route messages\n" \ + "VICI messages\n" + +static const struct message debug_flags_desc[] = { + { NHRP_DEBUG_ALL, "all" }, + { NHRP_DEBUG_COMMON, "common" }, + { NHRP_DEBUG_IF, "interface" }, + { NHRP_DEBUG_KERNEL, "kernel" }, + { NHRP_DEBUG_ROUTE, "route" }, + { NHRP_DEBUG_VICI, "vici" }, + { NHRP_DEBUG_EVENT, "event" }, + { 0, NULL }, +}; + +static const struct message interface_flags_desc[] = { + { NHRP_IFF_SHORTCUT, "shortcut" }, + { NHRP_IFF_REDIRECT, "redirect" }, + { NHRP_IFF_REG_NO_UNIQUE, "registration no-unique" }, + { 0, NULL }, +}; + +static int nhrp_vty_return(struct vty *vty, int ret) +{ + static const char * const errmsgs[] = { + [NHRP_ERR_FAIL] = "Command failed", + [NHRP_ERR_NO_MEMORY] = "Out of memory", + [NHRP_ERR_UNSUPPORTED_INTERFACE] = "NHRP not supported on this interface", + [NHRP_ERR_NHRP_NOT_ENABLED] = "NHRP not enabled (set 'nhrp network-id' first)", + [NHRP_ERR_ENTRY_EXISTS] = "Entry exists already", + [NHRP_ERR_ENTRY_NOT_FOUND] = "Entry not found", + [NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH] = "Protocol address family does not match command (ip/ipv6 mismatch)", + }; + const char *str = NULL; + char buf[256]; + + if (ret == NHRP_OK) + return CMD_SUCCESS; + + if (ret > 0 && ret <= (int)ZEBRA_NUM_OF(errmsgs)) + if (errmsgs[ret]) + str = errmsgs[ret]; + + if (!str) { + str = buf; + snprintf(buf, sizeof(buf), "Unknown error %d", ret); + } + + vty_out (vty, "%% %s%s", str, VTY_NEWLINE); + + return CMD_WARNING; +} + +static int toggle_flag( + struct vty *vty, const struct message *flag_desc, + const char *name, int on_off, unsigned *flags) +{ + int i; + + for (i = 0; flag_desc[i].str != NULL; i++) { + if (strcmp(flag_desc[i].str, name) != 0) + continue; + if (on_off) + *flags |= flag_desc[i].key; + else + *flags &= ~flag_desc[i].key; + return CMD_SUCCESS; + } + + vty_out(vty, "%% Invalid value %s%s", name, VTY_NEWLINE); + return CMD_WARNING; +} + +#ifndef NO_DEBUG + +DEFUN(show_debugging_nhrp, show_debugging_nhrp_cmd, + "show debugging nhrp", + SHOW_STR + "Debugging information\n" + "NHRP configuration\n") +{ + int i; + + vty_out(vty, "NHRP debugging status:%s", VTY_NEWLINE); + + for (i = 0; debug_flags_desc[i].str != NULL; i++) { + if (debug_flags_desc[i].key == NHRP_DEBUG_ALL) + continue; + if (!(debug_flags_desc[i].key & debug_flags)) + continue; + + vty_out(vty, " NHRP %s debugging is on%s", + debug_flags_desc[i].str, VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(debug_nhrp, debug_nhrp_cmd, + "debug nhrp " NHRP_DEBUG_FLAGS_CMD, + "Enable debug messages for specific or all parts.\n" + "NHRP information\n" + NHRP_DEBUG_FLAGS_STR) +{ + return toggle_flag(vty, debug_flags_desc, argv[0], 1, &debug_flags); +} + +DEFUN(no_debug_nhrp, no_debug_nhrp_cmd, + "no debug nhrp " NHRP_DEBUG_FLAGS_CMD, + NO_STR + "Disable debug messages for specific or all parts.\n" + "NHRP information\n" + NHRP_DEBUG_FLAGS_STR) +{ + return toggle_flag(vty, debug_flags_desc, argv[0], 0, &debug_flags); +} + +#endif /* NO_DEBUG */ + +static int nhrp_config_write(struct vty *vty) +{ +#ifndef NO_DEBUG + if (debug_flags == NHRP_DEBUG_ALL) { + vty_out(vty, "debug nhrp all%s", VTY_NEWLINE); + } else { + int i; + + for (i = 0; debug_flags_desc[i].str != NULL; i++) { + if (debug_flags_desc[i].key == NHRP_DEBUG_ALL) + continue; + if (!(debug_flags & debug_flags_desc[i].key)) + continue; + vty_out(vty, "debug nhrp %s%s", debug_flags_desc[i].str, VTY_NEWLINE); + } + } + vty_out(vty, "!%s", VTY_NEWLINE); +#endif /* NO_DEBUG */ + + if (nhrp_event_socket_path) { + vty_out(vty, "nhrp event socket %s%s", + nhrp_event_socket_path, VTY_NEWLINE); + } + if (netlink_nflog_group) { + vty_out(vty, "nhrp nflog-group %d%s", + netlink_nflog_group, VTY_NEWLINE); + } + + return 0; +} + +#define IP_STR "IP information\n" +#define IPV6_STR "IPv6 information\n" +#define AFI_CMD "(ip|ipv6)" +#define AFI_STR IP_STR IPV6_STR +#define NHRP_STR "Next Hop Resolution Protocol functions\n" + +static afi_t cmd_to_afi(const char *cmd) +{ + return strncmp(cmd, "ipv6", 4) == 0 ? AFI_IP6 : AFI_IP; +} + +static const char *afi_to_cmd(afi_t afi) +{ + if (afi == AFI_IP6) return "ipv6"; + return "ip"; +} + +DEFUN(nhrp_event_socket, nhrp_event_socket_cmd, + "nhrp event socket SOCKET", + NHRP_STR + "Event Manager commands\n" + "Event Manager unix socket path\n" + "Unix path for the socket") +{ + evmgr_set_socket(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(no_nhrp_event_socket, no_nhrp_event_socket_cmd, + "no nhrp event socket [SOCKET]", + NO_STR + NHRP_STR + "Event Manager commands\n" + "Event Manager unix socket path\n" + "Unix path for the socket") +{ + evmgr_set_socket(NULL); + return CMD_SUCCESS; +} + +DEFUN(nhrp_nflog_group, nhrp_nflog_group_cmd, + "nhrp nflog-group <1-65535>", + NHRP_STR + "Specify NFLOG group number\n" + "NFLOG group number\n") +{ + uint32_t nfgroup; + + VTY_GET_INTEGER_RANGE("nflog-group", nfgroup, argv[0], 1, 65535); + netlink_set_nflog_group(nfgroup); + + return CMD_SUCCESS; +} + +DEFUN(no_nhrp_nflog_group, no_nhrp_nflog_group_cmd, + "no nhrp nflog-group [<1-65535>]", + NO_STR + NHRP_STR + "Specify NFLOG group number\n" + "NFLOG group number\n") +{ + netlink_set_nflog_group(0); + return CMD_SUCCESS; +} + +DEFUN(tunnel_protection, tunnel_protection_cmd, + "tunnel protection vici profile PROFILE {fallback-profile FALLBACK}", + "NHRP/GRE integration\n" + "IPsec protection\n" + "VICI (StrongSwan)\n" + "IPsec profile\n" + "IPsec profile name\n" + "Fallback IPsec profile\n" + "Fallback IPsec profile name\n") +{ + struct interface *ifp = vty->index; + + nhrp_interface_set_protection(ifp, argv[0], argv[1]); + return CMD_SUCCESS; +} + +DEFUN(no_tunnel_protection, no_tunnel_protection_cmd, + "no tunnel protection", + NO_STR + "NHRP/GRE integration\n" + "IPsec protection\n") +{ + struct interface *ifp = vty->index; + + nhrp_interface_set_protection(ifp, NULL, NULL); + return CMD_SUCCESS; +} + +DEFUN(tunnel_source, tunnel_source_cmd, + "tunnel source INTERFACE", + "NHRP/GRE integration\n" + "Tunnel device binding tracking\n" + "Interface name\n") +{ + struct interface *ifp = vty->index; + nhrp_interface_set_source(ifp, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(no_tunnel_source, no_tunnel_source_cmd, + "no tunnel source", + "NHRP/GRE integration\n" + "Tunnel device binding tracking\n" + "Interface name\n") +{ + struct interface *ifp = vty->index; + nhrp_interface_set_source(ifp, NULL); + return CMD_SUCCESS; +} + +DEFUN(if_nhrp_network_id, if_nhrp_network_id_cmd, + AFI_CMD " nhrp network-id <1-4294967295>", + AFI_STR + NHRP_STR + "Enable NHRP and specify network-id\n" + "System local ID to specify interface group\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + + VTY_GET_INTEGER_RANGE("network-id", nifp->afi[afi].network_id, argv[1], 1, 4294967295); + nhrp_interface_update(ifp); + + return CMD_SUCCESS; +} + +DEFUN(if_no_nhrp_network_id, if_no_nhrp_network_id_cmd, + "no " AFI_CMD " nhrp network-id [<1-4294967295>]", + NO_STR + AFI_STR + NHRP_STR + "Enable NHRP and specify network-id\n" + "System local ID to specify interface group\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + + nifp->afi[afi].network_id = 0; + nhrp_interface_update(ifp); + + return CMD_SUCCESS; +} + +DEFUN(if_nhrp_flags, if_nhrp_flags_cmd, + AFI_CMD " nhrp (shortcut|redirect)", + AFI_STR + NHRP_STR + "Allow shortcut establishment\n" + "Send redirect notifications\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + + return toggle_flag(vty, interface_flags_desc, argv[1], 1, &nifp->afi[afi].flags); +} + +DEFUN(if_no_nhrp_flags, if_no_nhrp_flags_cmd, + "no " AFI_CMD " nhrp (shortcut|redirect)", + NO_STR + AFI_STR + NHRP_STR + "Allow shortcut establishment\n" + "Send redirect notifications\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + + return toggle_flag(vty, interface_flags_desc, argv[1], 0, &nifp->afi[afi].flags); +} + +DEFUN(if_nhrp_reg_flags, if_nhrp_reg_flags_cmd, + AFI_CMD " nhrp registration (no-unique)", + AFI_STR + NHRP_STR + "Registration configuration\n" + "Don't set unique flag\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + char name[256]; + snprintf(name, sizeof(name), "registration %s", argv[1]); + return toggle_flag(vty, interface_flags_desc, name, 1, &nifp->afi[afi].flags); +} + +DEFUN(if_no_nhrp_reg_flags, if_no_nhrp_reg_flags_cmd, + "no " AFI_CMD " nhrp registration (no-unique)", + NO_STR + AFI_STR + NHRP_STR + "Registration configuration\n" + "Don't set unique flag\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + char name[256]; + snprintf(name, sizeof(name), "registration %s", argv[1]); + return toggle_flag(vty, interface_flags_desc, name, 0, &nifp->afi[afi].flags); +} + +DEFUN(if_nhrp_holdtime, if_nhrp_holdtime_cmd, + AFI_CMD " nhrp holdtime <1-65000>", + AFI_STR + NHRP_STR + "Specify NBMA address validity time\n" + "Time in seconds that NBMA addresses are advertised valid\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + + VTY_GET_INTEGER_RANGE("holdtime", nifp->afi[afi].holdtime, argv[1], 1, 65000); + nhrp_interface_update(ifp); + + return CMD_SUCCESS; +} + +DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd, + "no " AFI_CMD " nhrp holdtime [1-65000]", + NO_STR + AFI_STR + NHRP_STR + "Specify NBMA address validity time\n" + "Time in seconds that NBMA addresses are advertised valid\n") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + afi_t afi = cmd_to_afi(argv[0]); + + nifp->afi[afi].holdtime = NHRPD_DEFAULT_HOLDTIME; + nhrp_interface_update(ifp); + + return CMD_SUCCESS; +} + +DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd, + "ip nhrp mtu (<576-1500>|opennhrp)", + IP_STR + NHRP_STR + "Configure NHRP advertised MTU\n" + "MTU value\n" + "Advertise bound interface MTU similar to OpenNHRP") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + + if (argv[0][0] == 'o') { + nifp->afi[AFI_IP].configured_mtu = -1; + } else { + VTY_GET_INTEGER_RANGE("mtu", nifp->afi[AFI_IP].configured_mtu, argv[0], 576, 1500); + } + nhrp_interface_update_mtu(ifp, AFI_IP); + + return CMD_SUCCESS; +} + +DEFUN(if_no_nhrp_mtu, if_no_nhrp_mtu_cmd, + "no ip nhrp mtu [(<576-1500>|opennhrp)]", + NO_STR + IP_STR + NHRP_STR + "Configure NHRP advertised MTU\n" + "MTU value\n" + "Advertise bound interface MTU similar to OpenNHRP") +{ + struct interface *ifp = vty->index; + struct nhrp_interface *nifp = ifp->info; + + nifp->afi[AFI_IP].configured_mtu = 0; + nhrp_interface_update_mtu(ifp, AFI_IP); + return CMD_SUCCESS; +} + +DEFUN(if_nhrp_map, if_nhrp_map_cmd, + AFI_CMD " nhrp map (A.B.C.D|X:X::X:X) (A.B.C.D|local)", + AFI_STR + NHRP_STR + "Nexthop Server configuration\n" + "IPv4 protocol address\n" + "IPv6 protocol address\n" + "IPv4 NBMA address\n" + "Handle protocol address locally\n") +{ + struct interface *ifp = vty->index; + afi_t afi = cmd_to_afi(argv[0]); + union sockunion proto_addr, nbma_addr; + struct nhrp_cache *c; + + if (str2sockunion(argv[1], &proto_addr) < 0 || + afi2family(afi) != sockunion_family(&proto_addr)) + return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH); + + c = nhrp_cache_get(ifp, &proto_addr, 1); + if (!c) + return nhrp_vty_return(vty, NHRP_ERR_FAIL); + + c->map = 1; + if (strcmp(argv[2], "local") == 0) { + nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL); + } else{ + if (str2sockunion(argv[2], &nbma_addr) < 0) + return nhrp_vty_return(vty, NHRP_ERR_FAIL); + nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0, + nhrp_peer_get(ifp, &nbma_addr), 0, NULL); + } + + return CMD_SUCCESS; +} + +DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd, + AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", + AFI_STR + NHRP_STR + "Nexthop Server configuration\n" + "IPv4 protocol address\n" + "IPv6 protocol address\n" + "Automatic detection of protocol address\n" + "IPv4 NBMA address\n" + "Fully qualified domain name for NBMA address(es)\n") +{ + struct interface *ifp = vty->index; + afi_t afi = cmd_to_afi(argv[0]); + union sockunion proto_addr; + int ret; + + if (str2sockunion(argv[1], &proto_addr) < 0) + sockunion_family(&proto_addr) = AF_UNSPEC; + + ret = nhrp_nhs_add(ifp, afi, &proto_addr, argv[2]); + return nhrp_vty_return(vty, ret); +} + +DEFUN(if_no_nhrp_nhs, if_no_nhrp_nhs_cmd, + "no " AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", + NO_STR + AFI_STR + NHRP_STR + "Nexthop Server configuration\n" + "IPv4 protocol address\n" + "IPv6 protocol address\n" + "Automatic detection of protocol address\n" + "IPv4 NBMA address\n" + "Fully qualified domain name for NBMA address(es)\n") +{ + struct interface *ifp = vty->index; + afi_t afi = cmd_to_afi(argv[0]); + union sockunion proto_addr; + int ret; + + if (str2sockunion(argv[1], &proto_addr) < 0) + sockunion_family(&proto_addr) = AF_UNSPEC; + + ret = nhrp_nhs_del(ifp, afi, &proto_addr, argv[2]); + return nhrp_vty_return(vty, ret); +} + +struct info_ctx { + struct vty *vty; + afi_t afi; + int count; +}; + +static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) +{ + struct info_ctx *ctx = pctx; + struct vty *vty = ctx->vty; + char buf[2][SU_ADDRSTRLEN]; + + if (ctx->afi != family2afi(sockunion_family(&c->remote_addr))) + return; + + if (!ctx->count) { + vty_out(vty, "%-8s %-8s %-24s %-24s %-6s %s%s", + "Iface", + "Type", + "Protocol", + "NBMA", + "Flags", + "Identity", + VTY_NEWLINE); + } + ctx->count++; + + vty_out(ctx->vty, "%-8s %-8s %-24s %-24s %c%c%c %s%s", + c->ifp->name, + nhrp_cache_type_str[c->cur.type], + sockunion2str(&c->remote_addr, buf[0], sizeof buf[0]), + c->cur.peer ? sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], sizeof buf[1]) : "-", + c->used ? 'U' : ' ', + c->t_timeout ? 'T' : ' ', + c->t_auth ? 'A' : ' ', + c->cur.peer ? c->cur.peer->vc->remote.id : "-", + VTY_NEWLINE); +} + +static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx) +{ + struct info_ctx *ctx = pctx; + struct vty *vty = ctx->vty; + char buf[SU_ADDRSTRLEN]; + + if (ctx->afi != family2afi(sockunion_family(&c->remote_addr))) + return; + + vty_out(ctx->vty, + "Type: %s%s" + "Flags:%s%s%s" + "Protocol-Address: %s/%zu%s", + nhrp_cache_type_str[c->cur.type], + VTY_NEWLINE, + (c->cur.peer && c->cur.peer->online) ? " up": "", + c->used ? " used": "", + VTY_NEWLINE, + sockunion2str(&c->remote_addr, buf, sizeof buf), + 8 * family2addrsize(sockunion_family(&c->remote_addr)), + VTY_NEWLINE); + + if (c->cur.peer) { + vty_out(ctx->vty, + "NBMA-Address: %s%s", + sockunion2str(&c->cur.peer->vc->remote.nbma, buf, sizeof buf), + VTY_NEWLINE); + } + + if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC) { + vty_out(ctx->vty, + "NBMA-NAT-OA-Address: %s%s", + sockunion2str(&c->cur.remote_nbma_natoa, buf, sizeof buf), + VTY_NEWLINE); + } + + vty_out(ctx->vty, "%s", VTY_NEWLINE); +} + +static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx) +{ + struct info_ctx *ctx = pctx; + struct nhrp_cache *c; + struct vty *vty = ctx->vty; + char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN]; + + if (!ctx->count) { + vty_out(vty, "%-8s %-24s %-24s %s%s", + "Type", + "Prefix", + "Via", + "Identity", + VTY_NEWLINE); + } + ctx->count++; + + c = s->cache; + vty_out(ctx->vty, "%-8s %-24s %-24s %s%s", + nhrp_cache_type_str[s->type], + prefix2str(s->p, buf1, sizeof buf1), + c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "", + (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "", + VTY_NEWLINE); +} + +DEFUN(show_ip_nhrp, show_ip_nhrp_cmd, + "show " AFI_CMD " nhrp (cache|shortcut|opennhrp|)", + SHOW_STR + AFI_STR + "NHRP information\n" + "Forwarding cache information\n" + "Shortcut information\n" + "opennhrpctl style cache dump\n") +{ + struct listnode *node; + struct interface *ifp; + struct info_ctx ctx = { + .vty = vty, + .afi = cmd_to_afi(argv[0]), + }; + + if (!argv[1] || argv[1][0] == 'c') { + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) + nhrp_cache_foreach(ifp, show_ip_nhrp_cache, &ctx); + } else if (argv[1][0] == 'o') { + vty_out(vty, "Status: ok%s%s", VTY_NEWLINE, VTY_NEWLINE); + ctx.count++; + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) + nhrp_cache_foreach(ifp, show_ip_opennhrp_cache, &ctx); + } else { + nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx); + } + + if (!ctx.count) { + vty_out(vty, "%% No entries%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +static void show_dmvpn_entry(struct nhrp_vc *vc, void *ctx) +{ + struct vty *vty = ctx; + char buf[2][SU_ADDRSTRLEN]; + + vty_out(vty, "%-24s %-24s %c %-4d %-24s%s", + sockunion2str(&vc->local.nbma, buf[0], sizeof buf[0]), + sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1]), + notifier_active(&vc->notifier_list) ? 'n' : ' ', + vc->ipsec, + vc->remote.id, + VTY_NEWLINE); +} + +DEFUN(show_dmvpn, show_dmvpn_cmd, + "show dmvpn", + SHOW_STR + "DMVPN information\n") +{ + vty_out(vty, "%-24s %-24s %-6s %-4s %-24s%s", + "Src", + "Dst", + "Flags", + "SAs", + "Identity", + VTY_NEWLINE); + + nhrp_vc_foreach(show_dmvpn_entry, vty); + + return CMD_SUCCESS; +} + +static void clear_nhrp_cache(struct nhrp_cache *c, void *data) +{ + struct info_ctx *ctx = data; + if (c->cur.type <= NHRP_CACHE_CACHED) { + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + ctx->count++; + } +} + +static void clear_nhrp_shortcut(struct nhrp_shortcut *s, void *data) +{ + struct info_ctx *ctx = data; + nhrp_shortcut_purge(s, 1); + ctx->count++; +} + +DEFUN(clear_nhrp, clear_nhrp_cmd, + "clear " AFI_CMD " nhrp (cache|shortcut)", + CLEAR_STR + AFI_STR + NHRP_STR + "Dynamic cache entries\n" + "Shortcut entries\n") +{ + struct listnode *node; + struct interface *ifp; + struct info_ctx ctx = { + .vty = vty, + .afi = cmd_to_afi(argv[0]), + .count = 0, + }; + + if (!argv[1] || argv[1][0] == 'c') { + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) + nhrp_cache_foreach(ifp, clear_nhrp_cache, &ctx); + } else { + nhrp_shortcut_foreach(ctx.afi, clear_nhrp_shortcut, &ctx); + } + + if (!ctx.count) { + vty_out(vty, "%% No entries%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_out(vty, "%% %d entries cleared%s", ctx.count, VTY_NEWLINE); + return CMD_SUCCESS; +} + +struct write_map_ctx { + struct vty *vty; + int family; + const char *aficmd; +}; + +static void interface_config_write_nhrp_map(struct nhrp_cache *c, void *data) +{ + struct write_map_ctx *ctx = data; + struct vty *vty = ctx->vty; + char buf[2][SU_ADDRSTRLEN]; + + if (!c->map) return; + if (sockunion_family(&c->remote_addr) != ctx->family) return; + + vty_out(vty, " %s nhrp map %s %s%s", + ctx->aficmd, + sockunion2str(&c->remote_addr, buf[0], sizeof buf[0]), + c->cur.type == NHRP_CACHE_LOCAL ? "local" : + sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], sizeof buf[1]), + VTY_NEWLINE); +} + +static int interface_config_write(struct vty *vty) +{ + struct write_map_ctx mapctx; + struct listnode *node; + struct interface *ifp; + struct nhrp_interface *nifp; + struct nhrp_nhs *nhs; + const char *aficmd; + afi_t afi; + char buf[SU_ADDRSTRLEN]; + int i; + + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { + vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); + if (ifp->desc) + vty_out(vty, " description %s%s", ifp->desc, VTY_NEWLINE); + + nifp = ifp->info; + if (nifp->ipsec_profile) { + vty_out(vty, " tunnel protection vici profile %s", + nifp->ipsec_profile); + if (nifp->ipsec_fallback_profile) + vty_out(vty, " fallback-profile %s", + nifp->ipsec_fallback_profile); + vty_out(vty, "%s", VTY_NEWLINE); + } + if (nifp->source) + vty_out(vty, " tunnel source %s%s", + nifp->source, VTY_NEWLINE); + + for (afi = 0; afi < AFI_MAX; afi++) { + struct nhrp_afi_data *ad = &nifp->afi[afi]; + + aficmd = afi_to_cmd(afi); + + if (ad->network_id) + vty_out(vty, " %s nhrp network-id %u%s", + aficmd, ad->network_id, + VTY_NEWLINE); + + if (ad->holdtime != NHRPD_DEFAULT_HOLDTIME) + vty_out(vty, " %s nhrp holdtime %u%s", + aficmd, ad->holdtime, + VTY_NEWLINE); + + if (ad->configured_mtu < 0) + vty_out(vty, " %s nhrp mtu opennhrp%s", + aficmd, VTY_NEWLINE); + else if (ad->configured_mtu) + vty_out(vty, " %s nhrp mtu %u%s", + aficmd, ad->configured_mtu, + VTY_NEWLINE); + + for (i = 0; interface_flags_desc[i].str != NULL; i++) { + if (!(ad->flags & interface_flags_desc[i].key)) + continue; + vty_out(vty, " %s nhrp %s%s", + aficmd, interface_flags_desc[i].str, VTY_NEWLINE); + } + + mapctx = (struct write_map_ctx) { + .vty = vty, + .family = afi2family(afi), + .aficmd = aficmd, + }; + nhrp_cache_foreach(ifp, interface_config_write_nhrp_map, &mapctx); + + list_for_each_entry(nhs, &ad->nhslist_head, nhslist_entry) { + vty_out(vty, " %s nhrp nhs %s nbma %s%s", + aficmd, + sockunion_family(&nhs->proto_addr) == AF_UNSPEC ? "dynamic" : sockunion2str(&nhs->proto_addr, buf, sizeof buf), + nhs->nbma_fqdn, + VTY_NEWLINE); + } + } + + vty_out (vty, "!%s", VTY_NEWLINE); + } + + return 0; +} + +void nhrp_config_init(void) +{ + install_node(&zebra_node, nhrp_config_write); + install_default(ZEBRA_NODE); + + /* global commands */ + install_element(VIEW_NODE, &show_debugging_nhrp_cmd); + install_element(VIEW_NODE, &show_ip_nhrp_cmd); + install_element(VIEW_NODE, &show_dmvpn_cmd); + install_element(ENABLE_NODE, &show_debugging_nhrp_cmd); + install_element(ENABLE_NODE, &show_ip_nhrp_cmd); + install_element(ENABLE_NODE, &show_dmvpn_cmd); + install_element(ENABLE_NODE, &clear_nhrp_cmd); + + install_element(ENABLE_NODE, &debug_nhrp_cmd); + install_element(ENABLE_NODE, &no_debug_nhrp_cmd); + + install_element(CONFIG_NODE, &debug_nhrp_cmd); + install_element(CONFIG_NODE, &no_debug_nhrp_cmd); + + install_element(CONFIG_NODE, &nhrp_event_socket_cmd); + install_element(CONFIG_NODE, &no_nhrp_event_socket_cmd); + install_element(CONFIG_NODE, &nhrp_nflog_group_cmd); + install_element(CONFIG_NODE, &no_nhrp_nflog_group_cmd); + + /* interface specific commands */ + install_node(&nhrp_interface_node, interface_config_write); + install_default(INTERFACE_NODE); + + install_element(CONFIG_NODE, &interface_cmd); + install_element(CONFIG_NODE, &no_interface_cmd); + install_element(INTERFACE_NODE, &interface_cmd); + install_element(INTERFACE_NODE, &no_interface_cmd); + install_element(INTERFACE_NODE, &tunnel_protection_cmd); + install_element(INTERFACE_NODE, &no_tunnel_protection_cmd); + install_element(INTERFACE_NODE, &tunnel_source_cmd); + install_element(INTERFACE_NODE, &no_tunnel_source_cmd); + install_element(INTERFACE_NODE, &if_nhrp_network_id_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd); + install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd); + install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd); + install_element(INTERFACE_NODE, &if_nhrp_flags_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_flags_cmd); + install_element(INTERFACE_NODE, &if_nhrp_reg_flags_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd); + install_element(INTERFACE_NODE, &if_nhrp_map_cmd); + install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd); +} diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h new file mode 100644 index 000000000..307546e08 --- /dev/null +++ b/nhrpd/nhrpd.h @@ -0,0 +1,400 @@ +/* NHRP daemon internal structures and function prototypes + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef NHRPD_H +#define NHRPD_H + +#include "list.h" + +#include "zbuf.h" +#include "zclient.h" +#include "debug.h" + +#define NHRPD_DEFAULT_HOLDTIME 7200 + +#define NHRP_VTY_PORT 2612 +#define NHRP_DEFAULT_CONFIG "nhrpd.conf" + +extern struct thread_master *master; + +enum { + NHRP_OK = 0, + NHRP_ERR_FAIL, + NHRP_ERR_NO_MEMORY, + NHRP_ERR_UNSUPPORTED_INTERFACE, + NHRP_ERR_NHRP_NOT_ENABLED, + NHRP_ERR_ENTRY_EXISTS, + NHRP_ERR_ENTRY_NOT_FOUND, + NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH, +}; + +struct notifier_block; + +typedef void (*notifier_fn_t)(struct notifier_block *, unsigned long); + +struct notifier_block { + struct list_head notifier_entry; + notifier_fn_t action; +}; + +struct notifier_list { + struct list_head notifier_head; +}; + +#define NOTIFIER_LIST_INITIALIZER(l) \ + { .notifier_head = LIST_INITIALIZER((l)->notifier_head) } + +static inline void notifier_init(struct notifier_list *l) +{ + list_init(&l->notifier_head); +} + +static inline void notifier_add(struct notifier_block *n, struct notifier_list *l, notifier_fn_t action) +{ + n->action = action; + list_add_tail(&n->notifier_entry, &l->notifier_head); +} + +static inline void notifier_del(struct notifier_block *n) +{ + list_del(&n->notifier_entry); +} + +static inline void notifier_call(struct notifier_list *l, int cmd) +{ + struct notifier_block *n, *nn; + list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry) + n->action(n, cmd); +} + +static inline int notifier_active(struct notifier_list *l) +{ + return !list_empty(&l->notifier_head); +} + +struct resolver_query { + void (*callback)(struct resolver_query *, int n, union sockunion *); +}; + +void resolver_init(void); +void resolver_resolve(struct resolver_query *query, int af, const char *hostname, void (*cb)(struct resolver_query *, int, union sockunion *)); + +void nhrp_zebra_init(void); +void nhrp_zebra_terminate(void); + +struct zbuf; +struct nhrp_vc; +struct nhrp_cache; +struct nhrp_nhs; +struct nhrp_interface; + +#define MAX_ID_LENGTH 64 +#define MAX_CERT_LENGTH 2048 + +enum nhrp_notify_type { + NOTIFY_INTERFACE_UP, + NOTIFY_INTERFACE_DOWN, + NOTIFY_INTERFACE_CHANGED, + NOTIFY_INTERFACE_ADDRESS_CHANGED, + NOTIFY_INTERFACE_NBMA_CHANGED, + NOTIFY_INTERFACE_MTU_CHANGED, + + NOTIFY_VC_IPSEC_CHANGED, + NOTIFY_VC_IPSEC_UPDATE_NBMA, + + NOTIFY_PEER_UP, + NOTIFY_PEER_DOWN, + NOTIFY_PEER_IFCONFIG_CHANGED, + NOTIFY_PEER_MTU_CHANGED, + NOTIFY_PEER_NBMA_CHANGING, + + NOTIFY_CACHE_UP, + NOTIFY_CACHE_DOWN, + NOTIFY_CACHE_DELETE, + NOTIFY_CACHE_USED, + NOTIFY_CACHE_BINDING_CHANGE, +}; + +struct nhrp_vc { + struct notifier_list notifier_list; + uint8_t ipsec; + uint8_t updating; + uint8_t abort_migration; + + struct nhrp_vc_peer { + union sockunion nbma; + char id[MAX_ID_LENGTH]; + uint16_t certlen; + uint8_t cert[MAX_CERT_LENGTH]; + } local, remote; +}; + +enum nhrp_route_type { + NHRP_ROUTE_BLACKHOLE, + NHRP_ROUTE_LOCAL, + NHRP_ROUTE_NBMA_NEXTHOP, + NHRP_ROUTE_OFF_NBMA, +}; + +struct nhrp_peer { + unsigned int ref; + unsigned online : 1; + unsigned requested : 1; + unsigned fallback_requested : 1; + unsigned prio : 1; + struct notifier_list notifier_list; + struct interface *ifp; + struct nhrp_vc *vc; + struct thread *t_fallback; + struct notifier_block vc_notifier, ifp_notifier; +}; + +struct nhrp_packet_parser { + struct interface *ifp; + struct nhrp_afi_data *if_ad; + struct nhrp_peer *peer; + struct zbuf *pkt; + struct zbuf payload; + struct zbuf extensions; + struct nhrp_packet_header *hdr; + enum nhrp_route_type route_type; + struct prefix route_prefix; + union sockunion src_nbma, src_proto, dst_proto; +}; + +struct nhrp_reqid_pool { + struct hash *reqid_hash; + uint32_t next_request_id; +}; + +struct nhrp_reqid { + uint32_t request_id; + void (*cb)(struct nhrp_reqid *, void *); +}; + +extern struct nhrp_reqid_pool nhrp_packet_reqid; +extern struct nhrp_reqid_pool nhrp_event_reqid; + +enum nhrp_cache_type { + NHRP_CACHE_INVALID = 0, + NHRP_CACHE_INCOMPLETE, + NHRP_CACHE_NEGATIVE, + NHRP_CACHE_CACHED, + NHRP_CACHE_DYNAMIC, + NHRP_CACHE_NHS, + NHRP_CACHE_STATIC, + NHRP_CACHE_LOCAL, + NHRP_CACHE_NUM_TYPES +}; + +extern const char * const nhrp_cache_type_str[]; +extern unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES]; + +struct nhrp_cache { + struct interface *ifp; + union sockunion remote_addr; + + unsigned map : 1; + unsigned used : 1; + unsigned route_installed : 1; + unsigned nhrp_route_installed : 1; + + struct notifier_block peer_notifier; + struct notifier_block newpeer_notifier; + struct notifier_list notifier_list; + struct nhrp_reqid eventid; + struct thread *t_timeout; + struct thread *t_auth; + + struct { + enum nhrp_cache_type type; + union sockunion remote_nbma_natoa; + struct nhrp_peer *peer; + time_t expires; + uint32_t mtu; + } cur, new; +}; + +struct nhrp_shortcut { + struct prefix *p; + union sockunion addr; + + struct nhrp_reqid reqid; + struct thread *t_timer; + + enum nhrp_cache_type type; + unsigned int holding_time; + unsigned route_installed : 1; + unsigned expiring : 1; + + struct nhrp_cache *cache; + struct notifier_block cache_notifier; +}; + +struct nhrp_nhs { + struct interface *ifp; + struct list_head nhslist_entry; + + unsigned hub : 1; + afi_t afi; + union sockunion proto_addr; + const char *nbma_fqdn; /* IP-address or FQDN */ + + struct thread *t_resolve; + struct resolver_query dns_resolve; + struct list_head reglist_head; +}; + +#define NHRP_IFF_SHORTCUT 0x0001 +#define NHRP_IFF_REDIRECT 0x0002 +#define NHRP_IFF_REG_NO_UNIQUE 0x0100 + +struct nhrp_interface { + struct interface *ifp; + + unsigned enabled : 1; + + char *ipsec_profile, *ipsec_fallback_profile, *source; + union sockunion nbma; + union sockunion nat_nbma; + unsigned int linkidx; + uint32_t grekey; + + struct hash *peer_hash; + struct hash *cache_hash; + + struct notifier_list notifier_list; + + struct interface *nbmaifp; + struct notifier_block nbmanifp_notifier; + + struct nhrp_afi_data { + unsigned flags; + unsigned short configured : 1; + union sockunion addr; + uint32_t network_id; + short configured_mtu; + unsigned short mtu; + unsigned int holdtime; + struct list_head nhslist_head; + } afi[AFI_MAX]; +}; + +int sock_open_unix(const char *path); + +void nhrp_interface_init(void); +void nhrp_interface_update(struct interface *ifp); +void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi); + +int nhrp_interface_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); +int nhrp_interface_delete(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); +int nhrp_interface_up(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); +int nhrp_interface_down(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); +int nhrp_interface_address_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); +int nhrp_interface_address_delete(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); + +void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn); +void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n); +void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile); +void nhrp_interface_set_source(struct interface *ifp, const char *ifname); + +int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); +int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); +int nhrp_nhs_free(struct nhrp_nhs *nhs); +void nhrp_nhs_terminate(void); + +void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp); +void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu); +int nhrp_route_read(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id); +int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p, union sockunion *via, struct interface **ifp); +enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunion *addr, struct prefix *p, struct nhrp_peer **peer); + +void nhrp_config_init(void); + +void nhrp_shortcut_init(void); +void nhrp_shortcut_terminate(void); +void nhrp_shortcut_initiate(union sockunion *addr); +void nhrp_shortcut_foreach(afi_t afi, void (*cb)(struct nhrp_shortcut *, void *), void *ctx); +void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force); +void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted); + +struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote_addr, int create); +void nhrp_cache_foreach(struct interface *ifp, void (*cb)(struct nhrp_cache *, void *), void *ctx); +void nhrp_cache_set_used(struct nhrp_cache *, int); +int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type, int holding_time, struct nhrp_peer *p, uint32_t mtu, union sockunion *nbma_natoa); +void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *, notifier_fn_t); +void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *); + +void nhrp_vc_init(void); +void nhrp_vc_terminate(void); +struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create); +int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc); +void nhrp_vc_notify_add(struct nhrp_vc *, struct notifier_block *, notifier_fn_t); +void nhrp_vc_notify_del(struct nhrp_vc *, struct notifier_block *); +void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx); +void nhrp_vc_reset(void); + +void vici_init(void); +void vici_terminate(void); +void vici_request_vc(const char *profile, union sockunion *src, union sockunion *dst, int prio); + +extern const char *nhrp_event_socket_path; + +void evmgr_init(void); +void evmgr_terminate(void); +void evmgr_set_socket(const char *socket); +void evmgr_notify(const char *name, struct nhrp_cache *c, void (*cb)(struct nhrp_reqid *, void *)); + +struct nhrp_packet_header *nhrp_packet_push( + struct zbuf *zb, uint8_t type, + const union sockunion *src_nbma, + const union sockunion *src_proto, + const union sockunion *dst_proto); +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr); +uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len); + +struct nhrp_packet_header *nhrp_packet_pull( + struct zbuf *zb, + union sockunion *src_nbma, + union sockunion *src_proto, + union sockunion *dst_proto); + +struct nhrp_cie_header *nhrp_cie_push( + struct zbuf *zb, uint8_t code, + const union sockunion *nbma, + const union sockunion *proto); +struct nhrp_cie_header *nhrp_cie_pull( + struct zbuf *zb, + struct nhrp_packet_header *hdr, + union sockunion *nbma, + union sockunion *proto); + +struct nhrp_extension_header *nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type); +void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext); +struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload); +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *); +int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload); + +uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *)); +void nhrp_reqid_free(struct nhrp_reqid_pool *, struct nhrp_reqid *r); +struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *, uint32_t reqid); + +int nhrp_packet_init(void); + +struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *remote_nbma); +struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p); +void nhrp_peer_unref(struct nhrp_peer *p); +int nhrp_peer_check(struct nhrp_peer *p, int establish); +void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *, notifier_fn_t); +void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *); +void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb); +void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb); +void nhrp_peer_send_indication(struct interface *ifp, uint16_t, struct zbuf *); + +#endif diff --git a/nhrpd/os.h b/nhrpd/os.h new file mode 100644 index 000000000..0fbe8b003 --- /dev/null +++ b/nhrpd/os.h @@ -0,0 +1,5 @@ + +int os_socket(void); +int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, size_t addrlen); +int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, size_t *addrlen); +int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af); diff --git a/nhrpd/reqid.c b/nhrpd/reqid.c new file mode 100644 index 000000000..24b319939 --- /dev/null +++ b/nhrpd/reqid.c @@ -0,0 +1,49 @@ +#include "zebra.h" +#include "hash.h" +#include "nhrpd.h" + +static unsigned int nhrp_reqid_key(void *data) +{ + struct nhrp_reqid *r = data; + return r->request_id; +} + +static int nhrp_reqid_cmp(const void *data, const void *key) +{ + const struct nhrp_reqid *a = data, *b = key; + return a->request_id == b->request_id; +} + +uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *)) +{ + if (!p->reqid_hash) { + p->reqid_hash = hash_create(nhrp_reqid_key, nhrp_reqid_cmp); + p->next_request_id = 1; + } + + if (r->cb != cb) { + r->request_id = p->next_request_id; + if (++p->next_request_id == 0) p->next_request_id = 1; + r->cb = cb; + hash_get(p->reqid_hash, r, hash_alloc_intern); + } + return r->request_id; +} + +void nhrp_reqid_free(struct nhrp_reqid_pool *p, struct nhrp_reqid *r) +{ + if (r->cb) { + hash_release(p->reqid_hash, r); + r->cb = NULL; + } +} + +struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *p, uint32_t reqid) +{ + struct nhrp_reqid key; + if (!p->reqid_hash) return 0; + key.request_id = reqid; + return hash_lookup(p->reqid_hash, &key); +} + + diff --git a/nhrpd/resolver.c b/nhrpd/resolver.c new file mode 100644 index 000000000..07bdb735a --- /dev/null +++ b/nhrpd/resolver.c @@ -0,0 +1,190 @@ +/* C-Ares integration to Quagga mainloop + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include "vector.h" +#include "thread.h" +#include "nhrpd.h" + +struct resolver_state { + ares_channel channel; + struct thread *timeout; + vector read_threads, write_threads; +}; + +static struct resolver_state state; + +#define THREAD_RUNNING ((struct thread *)-1) + +static void resolver_update_timeouts(struct resolver_state *r); + +static int resolver_cb_timeout(struct thread *t) +{ + struct resolver_state *r = THREAD_ARG(t); + + r->timeout = THREAD_RUNNING; + ares_process(r->channel, NULL, NULL); + r->timeout = NULL; + resolver_update_timeouts(r); + + return 0; +} + +static int resolver_cb_socket_readable(struct thread *t) +{ + struct resolver_state *r = THREAD_ARG(t); + int fd = THREAD_FD(t); + + vector_set_index(r->read_threads, fd, THREAD_RUNNING); + ares_process_fd(r->channel, fd, ARES_SOCKET_BAD); + if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) { + t = NULL; + THREAD_READ_ON(master, t, resolver_cb_socket_readable, r, fd); + vector_set_index(r->read_threads, fd, t); + } + resolver_update_timeouts(r); + + return 0; +} + +static int resolver_cb_socket_writable(struct thread *t) +{ + struct resolver_state *r = THREAD_ARG(t); + int fd = THREAD_FD(t); + + vector_set_index(r->write_threads, fd, THREAD_RUNNING); + ares_process_fd(r->channel, ARES_SOCKET_BAD, fd); + if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) { + t = NULL; + THREAD_WRITE_ON(master, t, resolver_cb_socket_writable, r, fd); + vector_set_index(r->write_threads, fd, t); + } + resolver_update_timeouts(r); + + return 0; +} + +static void resolver_update_timeouts(struct resolver_state *r) +{ + struct timeval *tv, tvbuf; + + if (r->timeout == THREAD_RUNNING) return; + + THREAD_OFF(r->timeout); + tv = ares_timeout(r->channel, NULL, &tvbuf); + if (tv) { + unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000; + THREAD_TIMER_MSEC_ON(master, r->timeout, resolver_cb_timeout, r, timeoutms); + } +} + +static void ares_socket_cb(void *data, ares_socket_t fd, int readable, int writable) +{ + struct resolver_state *r = (struct resolver_state *) data; + struct thread *t; + + if (readable) { + t = vector_lookup_ensure(r->read_threads, fd); + if (!t) { + THREAD_READ_ON(master, t, resolver_cb_socket_readable, r, fd); + vector_set_index(r->read_threads, fd, t); + } + } else { + t = vector_lookup(r->read_threads, fd); + if (t) { + if (t != THREAD_RUNNING) { + THREAD_OFF(t); + } + vector_unset(r->read_threads, fd); + } + } + + if (writable) { + t = vector_lookup_ensure(r->write_threads, fd); + if (!t) { + THREAD_READ_ON(master, t, resolver_cb_socket_writable, r, fd); + vector_set_index(r->write_threads, fd, t); + } + } else { + t = vector_lookup(r->write_threads, fd); + if (t) { + if (t != THREAD_RUNNING) { + THREAD_OFF(t); + } + vector_unset(r->write_threads, fd); + } + } +} + +void resolver_init(void) +{ + struct ares_options ares_opts; + + state.read_threads = vector_init(1); + state.write_threads = vector_init(1); + + ares_opts = (struct ares_options) { + .sock_state_cb = &ares_socket_cb, + .sock_state_cb_data = &state, + .timeout = 2, + .tries = 3, + }; + + ares_init_options(&state.channel, &ares_opts, + ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT | + ARES_OPT_TRIES); +} + + +static void ares_address_cb(void *arg, int status, int timeouts, struct hostent *he) +{ + struct resolver_query *query = (struct resolver_query *) arg; + union sockunion addr[16]; + size_t i; + + if (status != ARES_SUCCESS) { + debugf(NHRP_DEBUG_COMMON, "[%p] Resolving failed", query); + query->callback(query, -1, NULL); + query->callback = NULL; + return; + } + + for (i = 0; he->h_addr_list[i] != NULL && i < ZEBRA_NUM_OF(addr); i++) { + memset(&addr[i], 0, sizeof(addr[i])); + addr[i].sa.sa_family = he->h_addrtype; + switch (he->h_addrtype) { + case AF_INET: + memcpy(&addr[i].sin.sin_addr, (uint8_t *) he->h_addr_list[i], he->h_length); + break; + case AF_INET6: + memcpy(&addr[i].sin6.sin6_addr, (uint8_t *) he->h_addr_list[i], he->h_length); + break; + } + } + + debugf(NHRP_DEBUG_COMMON, "[%p] Resolved with %d results", query, (int) i); + query->callback(query, i, &addr[0]); + query->callback = NULL; +} + +void resolver_resolve(struct resolver_query *query, int af, const char *hostname, void (*callback)(struct resolver_query *, int, union sockunion *)) +{ + if (query->callback != NULL) { + zlog_err("Trying to resolve '%s', but previous query was not finished yet", hostname); + return; + } + + debugf(NHRP_DEBUG_COMMON, "[%p] Resolving '%s'", query, hostname); + + query->callback = callback; + ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query); + resolver_update_timeouts(&state); +} diff --git a/nhrpd/vici.c b/nhrpd/vici.c new file mode 100644 index 000000000..507dd14a9 --- /dev/null +++ b/nhrpd/vici.c @@ -0,0 +1,482 @@ +/* strongSwan VICI protocol implementation for NHRP + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include "thread.h" +#include "zbuf.h" +#include "log.h" +#include "nhrpd.h" + +#include "vici.h" + +#define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) + +struct blob { + char *ptr; + int len; +}; + +static int blob_equal(const struct blob *b, const char *str) +{ + if (b->len != (int) strlen(str)) return 0; + return memcmp(b->ptr, str, b->len) == 0; +} + +static int blob2buf(const struct blob *b, char *buf, size_t n) +{ + if (b->len >= (int) n) return 0; + memcpy(buf, b->ptr, b->len); + buf[b->len] = 0; + return 1; +} + +struct vici_conn { + struct thread *t_reconnect, *t_read, *t_write; + struct zbuf ibuf; + struct zbuf_queue obuf; + int fd; + uint8_t ibuf_data[VICI_MAX_MSGLEN]; +}; + +struct vici_message_ctx { + const char *sections[8]; + int nsections; +}; + +static int vici_reconnect(struct thread *t); +static void vici_submit_request(struct vici_conn *vici, const char *name, ...); + +static void vici_zbuf_puts(struct zbuf *obuf, const char *str) +{ + size_t len = strlen(str); + zbuf_put8(obuf, len); + zbuf_put(obuf, str, len); +} + +static void vici_connection_error(struct vici_conn *vici) +{ + nhrp_vc_reset(); + + THREAD_OFF(vici->t_read); + THREAD_OFF(vici->t_write); + zbuf_reset(&vici->ibuf); + zbufq_reset(&vici->obuf); + + close(vici->fd); + vici->fd = -1; + THREAD_TIMER_ON(master, vici->t_reconnect, vici_reconnect, vici, 2); +} + +static void vici_parse_message( + struct vici_conn *vici, struct zbuf *msg, + void (*parser)(struct vici_message_ctx *ctx, enum vici_type_t msgtype, const struct blob *key, const struct blob *val), + struct vici_message_ctx *ctx) +{ + uint8_t *type; + struct blob key; + struct blob val; + + while ((type = zbuf_may_pull(msg, uint8_t)) != NULL) { + switch (*type) { + case VICI_SECTION_START: + key.len = zbuf_get8(msg); + key.ptr = zbuf_pulln(msg, key.len); + debugf(NHRP_DEBUG_VICI, "VICI: Section start '%.*s'", key.len, key.ptr); + parser(ctx, *type, &key, NULL); + ctx->nsections++; + break; + case VICI_SECTION_END: + debugf(NHRP_DEBUG_VICI, "VICI: Section end"); + parser(ctx, *type, NULL, NULL); + ctx->nsections--; + break; + case VICI_KEY_VALUE: + key.len = zbuf_get8(msg); + key.ptr = zbuf_pulln(msg, key.len); + val.len = zbuf_get_be16(msg); + val.ptr = zbuf_pulln(msg, val.len); + debugf(NHRP_DEBUG_VICI, "VICI: Key '%.*s'='%.*s'", key.len, key.ptr, val.len, val.ptr); + parser(ctx, *type, &key, &val); + break; + case VICI_LIST_START: + key.len = zbuf_get8(msg); + key.ptr = zbuf_pulln(msg, key.len); + debugf(NHRP_DEBUG_VICI, "VICI: List start '%.*s'", key.len, key.ptr); + break; + case VICI_LIST_ITEM: + val.len = zbuf_get_be16(msg); + val.ptr = zbuf_pulln(msg, val.len); + debugf(NHRP_DEBUG_VICI, "VICI: List item: '%.*s'", val.len, val.ptr); + parser(ctx, *type, &key, &val); + break; + case VICI_LIST_END: + debugf(NHRP_DEBUG_VICI, "VICI: List end"); + break; + default: + debugf(NHRP_DEBUG_VICI, "VICI: Unsupported message component type %d", *type); + return; + } + } +} + +struct handle_sa_ctx { + struct vici_message_ctx msgctx; + int event; + int child_ok; + int kill_ikesa; + uint32_t child_uniqueid, ike_uniqueid; + struct { + union sockunion host; + struct blob id, cert; + } local, remote; +}; + +static void parse_sa_message( + struct vici_message_ctx *ctx, + enum vici_type_t msgtype, + const struct blob *key, const struct blob *val) +{ + struct handle_sa_ctx *sactx = container_of(ctx, struct handle_sa_ctx, msgctx); + struct nhrp_vc *vc; + char buf[512]; + + switch (msgtype) { + case VICI_SECTION_START: + if (ctx->nsections == 3) { + /* Begin of child-sa section, reset child vars */ + sactx->child_uniqueid = 0; + sactx->child_ok = 0; + } + break; + case VICI_SECTION_END: + if (ctx->nsections == 3) { + /* End of child-sa section, update nhrp_vc */ + int up = sactx->child_ok || sactx->event == 1; + if (up) { + vc = nhrp_vc_get(&sactx->local.host, &sactx->remote.host, up); + if (vc) { + blob2buf(&sactx->local.id, vc->local.id, sizeof(vc->local.id)); + if (blob2buf(&sactx->local.cert, (char*)vc->local.cert, sizeof(vc->local.cert))) + vc->local.certlen = sactx->local.cert.len; + blob2buf(&sactx->remote.id, vc->remote.id, sizeof(vc->remote.id)); + if (blob2buf(&sactx->remote.cert, (char*)vc->remote.cert, sizeof(vc->remote.cert))) + vc->remote.certlen = sactx->remote.cert.len; + sactx->kill_ikesa |= nhrp_vc_ipsec_updown(sactx->child_uniqueid, vc); + } + } else { + nhrp_vc_ipsec_updown(sactx->child_uniqueid, 0); + } + } + break; + default: + switch (key->ptr[0]) { + case 'l': + if (blob_equal(key, "local-host") && ctx->nsections == 1) { + if (blob2buf(val, buf, sizeof(buf))) + str2sockunion(buf, &sactx->local.host); + } else if (blob_equal(key, "local-id") && ctx->nsections == 1) { + sactx->local.id = *val; + } else if (blob_equal(key, "local-cert-data") && ctx->nsections == 1) { + sactx->local.cert = *val; + } + break; + case 'r': + if (blob_equal(key, "remote-host") && ctx->nsections == 1) { + if (blob2buf(val, buf, sizeof(buf))) + str2sockunion(buf, &sactx->remote.host); + } else if (blob_equal(key, "remote-id") && ctx->nsections == 1) { + sactx->remote.id = *val; + } else if (blob_equal(key, "remote-cert-data") && ctx->nsections == 1) { + sactx->remote.cert = *val; + } + break; + case 'u': + if (blob_equal(key, "uniqueid") && blob2buf(val, buf, sizeof(buf))) { + if (ctx->nsections == 3) + sactx->child_uniqueid = strtoul(buf, NULL, 0); + else if (ctx->nsections == 1) + sactx->ike_uniqueid = strtoul(buf, NULL, 0); + } + break; + case 's': + if (blob_equal(key, "state") && ctx->nsections == 3) { + sactx->child_ok = + (sactx->event == 0 && + (blob_equal(val, "INSTALLED") || + blob_equal(val, "REKEYED"))); + } + break; + } + break; + } +} + +static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event) +{ + char buf[32]; + struct handle_sa_ctx ctx = { + .event = event, + }; + + vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx); + + if (ctx.kill_ikesa && ctx.ike_uniqueid) { + debugf(NHRP_DEBUG_COMMON, "VICI: Deleting IKE_SA %u", ctx.ike_uniqueid); + snprintf(buf, sizeof buf, "%u", ctx.ike_uniqueid); + vici_submit_request( + vici, "terminate", + VICI_KEY_VALUE, "ike-id", strlen(buf), buf, + VICI_END); + } +} + +static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg) +{ + uint32_t msglen; + uint8_t msgtype; + struct blob name; + + msglen = zbuf_get_be32(msg); + msgtype = zbuf_get8(msg); + debugf(NHRP_DEBUG_VICI, "VICI: Message %d, %d bytes", msgtype, msglen); + + switch (msgtype) { + case VICI_EVENT: + name.len = zbuf_get8(msg); + name.ptr = zbuf_pulln(msg, name.len); + + debugf(NHRP_DEBUG_VICI, "VICI: Event '%.*s'", name.len, name.ptr); + if (blob_equal(&name, "list-sa") || + blob_equal(&name, "child-updown") || + blob_equal(&name, "child-rekey")) + vici_recv_sa(vici, msg, 0); + else if (blob_equal(&name, "child-state-installed") || + blob_equal(&name, "child-state-rekeyed")) + vici_recv_sa(vici, msg, 1); + else if (blob_equal(&name, "child-state-destroying")) + vici_recv_sa(vici, msg, 2); + break; + case VICI_EVENT_UNKNOWN: + zlog_err("VICI: StrongSwan does not support mandatory events (unpatched?)"); + break; + case VICI_EVENT_CONFIRM: + case VICI_CMD_RESPONSE: + break; + default: + zlog_notice("VICI: Unrecognized message type %d", msgtype); + break; + } +} + +static int vici_read(struct thread *t) +{ + struct vici_conn *vici = THREAD_ARG(t); + struct zbuf *ibuf = &vici->ibuf; + struct zbuf pktbuf; + + vici->t_read = NULL; + if (zbuf_read(ibuf, vici->fd, (size_t) -1) < 0) { + vici_connection_error(vici); + return 0; + } + + /* Process all messages in buffer */ + do { + uint32_t *hdrlen = zbuf_may_pull(ibuf, uint32_t); + if (!hdrlen) + break; + if (!zbuf_may_pulln(ibuf, ntohl(*hdrlen))) { + zbuf_reset_head(ibuf, hdrlen); + break; + } + + /* Handle packet */ + zbuf_init(&pktbuf, hdrlen, htonl(*hdrlen)+4, htonl(*hdrlen)+4); + vici_recv_message(vici, &pktbuf); + } while (1); + + THREAD_READ_ON(master, vici->t_read, vici_read, vici, vici->fd); + return 0; +} + +static int vici_write(struct thread *t) +{ + struct vici_conn *vici = THREAD_ARG(t); + int r; + + vici->t_write = NULL; + r = zbufq_write(&vici->obuf, vici->fd); + if (r > 0) { + THREAD_WRITE_ON(master, vici->t_write, vici_write, vici, vici->fd); + } else if (r < 0) { + vici_connection_error(vici); + } + + return 0; +} + +static void vici_submit(struct vici_conn *vici, struct zbuf *obuf) +{ + if (vici->fd < 0) { + zbuf_free(obuf); + return; + } + + zbufq_queue(&vici->obuf, obuf); + THREAD_WRITE_ON(master, vici->t_write, vici_write, vici, vici->fd); +} + +static void vici_submit_request(struct vici_conn *vici, const char *name, ...) +{ + struct zbuf *obuf; + uint32_t *hdrlen; + va_list va; + size_t len; + int type; + + obuf = zbuf_alloc(256); + if (!obuf) return; + + hdrlen = zbuf_push(obuf, uint32_t); + zbuf_put8(obuf, VICI_CMD_REQUEST); + vici_zbuf_puts(obuf, name); + + va_start(va, name); + for (type = va_arg(va, int); type != VICI_END; type = va_arg(va, int)) { + zbuf_put8(obuf, type); + switch (type) { + case VICI_KEY_VALUE: + vici_zbuf_puts(obuf, va_arg(va, const char *)); + len = va_arg(va, size_t); + zbuf_put_be16(obuf, len); + zbuf_put(obuf, va_arg(va, void *), len); + break; + case VICI_END: + break; + default: + break; + } + } + va_end(va); + *hdrlen = htonl(zbuf_used(obuf) - 4); + vici_submit(vici, obuf); +} + +static void vici_register_event(struct vici_conn *vici, const char *name) +{ + struct zbuf *obuf; + uint32_t *hdrlen; + uint8_t namelen; + + namelen = strlen(name); + obuf = zbuf_alloc(4 + 1 + 1 + namelen); + if (!obuf) return; + + hdrlen = zbuf_push(obuf, uint32_t); + zbuf_put8(obuf, VICI_EVENT_REGISTER); + zbuf_put8(obuf, namelen); + zbuf_put(obuf, name, namelen); + *hdrlen = htonl(zbuf_used(obuf) - 4); + + vici_submit(vici, obuf); +} + +static int vici_reconnect(struct thread *t) +{ + struct vici_conn *vici = THREAD_ARG(t); + int fd; + + vici->t_reconnect = NULL; + if (vici->fd >= 0) return 0; + + fd = sock_open_unix("/var/run/charon.vici"); + if (fd < 0) { + zlog_warn("%s: failure connecting VICI socket: %s", + __PRETTY_FUNCTION__, strerror(errno)); + THREAD_TIMER_ON(master, vici->t_reconnect, vici_reconnect, vici, 2); + return 0; + } + + debugf(NHRP_DEBUG_COMMON, "VICI: Connected"); + vici->fd = fd; + THREAD_READ_ON(master, vici->t_read, vici_read, vici, vici->fd); + + /* Send event subscribtions */ + //vici_register_event(vici, "child-updown"); + //vici_register_event(vici, "child-rekey"); + vici_register_event(vici, "child-state-installed"); + vici_register_event(vici, "child-state-rekeyed"); + vici_register_event(vici, "child-state-destroying"); + vici_register_event(vici, "list-sa"); + vici_submit_request(vici, "list-sas", VICI_END); + + return 0; +} + +static struct vici_conn vici_connection; + +void vici_init(void) +{ + struct vici_conn *vici = &vici_connection; + + vici->fd = -1; + zbuf_init(&vici->ibuf, vici->ibuf_data, sizeof(vici->ibuf_data), 0); + zbufq_init(&vici->obuf); + THREAD_TIMER_MSEC_ON(master, vici->t_reconnect, vici_reconnect, vici, 10); +} + +void vici_terminate(void) +{ +} + +void vici_request_vc(const char *profile, union sockunion *src, union sockunion *dst, int prio) +{ + struct vici_conn *vici = &vici_connection; + char buf[2][SU_ADDRSTRLEN]; + + sockunion2str(src, buf[0], sizeof buf[0]); + sockunion2str(dst, buf[1], sizeof buf[1]); + + vici_submit_request( + vici, "initiate", + VICI_KEY_VALUE, "child", strlen(profile), profile, + VICI_KEY_VALUE, "timeout", 2, "-1", + VICI_KEY_VALUE, "async", 1, "1", + VICI_KEY_VALUE, "init-limits", 1, prio ? "0" : "1", + VICI_KEY_VALUE, "my-host", strlen(buf[0]), buf[0], + VICI_KEY_VALUE, "other-host", strlen(buf[1]), buf[1], + VICI_END); +} + +int sock_open_unix(const char *path) +{ + int ret, fd; + struct sockaddr_un addr; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + memset(&addr, 0, sizeof (struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, strlen (path)); + + ret = connect(fd, (struct sockaddr *) &addr, sizeof(addr.sun_family) + strlen(addr.sun_path)); + if (ret < 0) { + close(fd); + return -1; + } + + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + + return fd; +} diff --git a/nhrpd/vici.h b/nhrpd/vici.h new file mode 100644 index 000000000..24b900b43 --- /dev/null +++ b/nhrpd/vici.h @@ -0,0 +1,24 @@ + +enum vici_type_t { + VICI_START = 0, + VICI_SECTION_START = 1, + VICI_SECTION_END = 2, + VICI_KEY_VALUE = 3, + VICI_LIST_START = 4, + VICI_LIST_ITEM = 5, + VICI_LIST_END = 6, + VICI_END = 7 +}; + +enum vici_operation_t { + VICI_CMD_REQUEST = 0, + VICI_CMD_RESPONSE, + VICI_CMD_UNKNOWN, + VICI_EVENT_REGISTER, + VICI_EVENT_UNREGISTER, + VICI_EVENT_CONFIRM, + VICI_EVENT_UNKNOWN, + VICI_EVENT, +}; + +#define VICI_MAX_MSGLEN (512*1024) diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c new file mode 100644 index 000000000..ead7cfd29 --- /dev/null +++ b/nhrpd/zbuf.c @@ -0,0 +1,219 @@ +/* Stream/packet buffer API implementation + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "zassert.h" +#include "zbuf.h" +#include "memory.h" +#include "memtypes.h" +#include "nhrpd.h" + +#define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) + +struct zbuf *zbuf_alloc(size_t size) +{ + struct zbuf *zb; + + zb = XMALLOC(MTYPE_STREAM_DATA, sizeof(*zb) + size); + if (!zb) + return NULL; + + zbuf_init(zb, zb+1, size, 0); + zb->allocated = 1; + + return zb; +} + +void zbuf_init(struct zbuf *zb, void *buf, size_t len, size_t datalen) +{ + *zb = (struct zbuf) { + .buf = buf, + .end = (uint8_t *)buf + len, + .head = buf, + .tail = (uint8_t *)buf + datalen, + }; +} + +void zbuf_free(struct zbuf *zb) +{ + if (zb->allocated) + XFREE(MTYPE_STREAM_DATA, zb); +} + +void zbuf_reset(struct zbuf *zb) +{ + zb->head = zb->tail = zb->buf; + zb->error = 0; +} + +void zbuf_reset_head(struct zbuf *zb, void *ptr) +{ + zassert((void*)zb->buf <= ptr && ptr <= (void*)zb->tail); + zb->head = ptr; +} + +static void zbuf_remove_headroom(struct zbuf *zb) +{ + ssize_t headroom = zbuf_headroom(zb); + if (!headroom) + return; + memmove(zb->buf, zb->head, zbuf_used(zb)); + zb->head -= headroom; + zb->tail -= headroom; +} + +ssize_t zbuf_read(struct zbuf *zb, int fd, size_t maxlen) +{ + ssize_t r; + + if (zb->error) + return -3; + + zbuf_remove_headroom(zb); + if (maxlen > zbuf_tailroom(zb)) + maxlen = zbuf_tailroom(zb); + + r = read(fd, zb->tail, maxlen); + if (r > 0) zb->tail += r; + else if (r == 0) r = -2; + else if (r < 0 && ERRNO_IO_RETRY(errno)) r = 0; + + return r; +} + +ssize_t zbuf_write(struct zbuf *zb, int fd) +{ + ssize_t r; + + if (zb->error) + return -3; + + r = write(fd, zb->head, zbuf_used(zb)); + if (r > 0) { + zb->head += r; + if (zb->head == zb->tail) + zbuf_reset(zb); + } + else if (r == 0) r = -2; + else if (r < 0 && ERRNO_IO_RETRY(errno)) r = 0; + + return r; +} + +ssize_t zbuf_recv(struct zbuf *zb, int fd) +{ + ssize_t r; + + if (zb->error) + return -3; + + zbuf_remove_headroom(zb); + r = recv(fd, zb->tail, zbuf_tailroom(zb), 0); + if (r > 0) zb->tail += r; + else if (r == 0) r = -2; + else if (r < 0 && ERRNO_IO_RETRY(errno)) r = 0; + return r; +} + +ssize_t zbuf_send(struct zbuf *zb, int fd) +{ + ssize_t r; + + if (zb->error) + return -3; + + r = send(fd, zb->head, zbuf_used(zb), 0); + if (r >= 0) + zbuf_reset(zb); + + return r; +} + +void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg) +{ + size_t seplen = strlen(sep), len; + uint8_t *ptr; + + ptr = memmem(zb->head, zbuf_used(zb), sep, seplen); + if (!ptr) return NULL; + + len = ptr - zb->head + seplen; + zbuf_init(msg, zbuf_pulln(zb, len), len, len); + return msg->head; +} + +void zbufq_init(struct zbuf_queue *zbq) +{ + *zbq = (struct zbuf_queue) { + .queue_head = LIST_INITIALIZER(zbq->queue_head), + }; +} + +void zbufq_reset(struct zbuf_queue *zbq) +{ + struct zbuf *buf, *bufn; + + list_for_each_entry_safe(buf, bufn, &zbq->queue_head, queue_list) { + list_del(&buf->queue_list); + zbuf_free(buf); + } +} + +void zbufq_queue(struct zbuf_queue *zbq, struct zbuf *zb) +{ + list_add_tail(&zb->queue_list, &zbq->queue_head); +} + +int zbufq_write(struct zbuf_queue *zbq, int fd) +{ + struct iovec iov[16]; + struct zbuf *zb, *zbn; + ssize_t r; + size_t iovcnt = 0; + + list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list) { + iov[iovcnt++] = (struct iovec) { + .iov_base = zb->head, + .iov_len = zbuf_used(zb), + }; + if (iovcnt >= ZEBRA_NUM_OF(iov)) + break; + } + + r = writev(fd, iov, iovcnt); + if (r < 0) + return r; + + list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list) { + if (r < (ssize_t)zbuf_used(zb)) { + zb->head += r; + return 1; + } + + r -= zbuf_used(zb); + list_del(&zb->queue_list); + zbuf_free(zb); + } + + return 0; +} + +void zbuf_copy(struct zbuf *zdst, struct zbuf *zsrc, size_t len) +{ + const void *src; + void *dst; + + dst = zbuf_pushn(zdst, len); + src = zbuf_pulln(zsrc, len); + if (!dst || !src) return; + memcpy(dst, src, len); +} diff --git a/nhrpd/zbuf.h b/nhrpd/zbuf.h new file mode 100644 index 000000000..73d707344 --- /dev/null +++ b/nhrpd/zbuf.h @@ -0,0 +1,189 @@ +/* Stream/packet buffer API + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef ZBUF_H +#define ZBUF_H + +#include +#include +#include +#include + +#include "zassert.h" +#include "list.h" + +struct zbuf { + struct list_head queue_list; + unsigned allocated : 1; + unsigned error : 1; + uint8_t *buf, *end; + uint8_t *head, *tail; +}; + +struct zbuf_queue { + struct list_head queue_head; +}; + +struct zbuf *zbuf_alloc(size_t size); +void zbuf_init(struct zbuf *zb, void *buf, size_t len, size_t datalen); +void zbuf_free(struct zbuf *zb); + +static inline size_t zbuf_size(struct zbuf *zb) +{ + return zb->end - zb->buf; +} + +static inline size_t zbuf_used(struct zbuf *zb) +{ + return zb->tail - zb->head; +} + +static inline size_t zbuf_tailroom(struct zbuf *zb) +{ + return zb->end - zb->tail; +} + +static inline size_t zbuf_headroom(struct zbuf *zb) +{ + return zb->head - zb->buf; +} + +void zbuf_reset(struct zbuf *zb); +void zbuf_reset_head(struct zbuf *zb, void *ptr); +ssize_t zbuf_read(struct zbuf *zb, int fd, size_t maxlen); +ssize_t zbuf_write(struct zbuf *zb, int fd); +ssize_t zbuf_recv(struct zbuf *zb, int fd); +ssize_t zbuf_send(struct zbuf *zb, int fd); + +static inline void zbuf_set_rerror(struct zbuf *zb) +{ + zb->error = 1; + zb->head = zb->tail; +} + +static inline void zbuf_set_werror(struct zbuf *zb) +{ + zb->error = 1; + zb->tail = zb->end; +} + +static inline void *__zbuf_pull(struct zbuf *zb, size_t size, int error) +{ + void *head = zb->head; + if (size > zbuf_used(zb)) { + if (error) zbuf_set_rerror(zb); + return NULL; + } + zb->head += size; + return head; +} + +#define zbuf_pull(zb, type) ((type *)__zbuf_pull(zb, sizeof(type), 1)) +#define zbuf_pulln(zb, sz) ((void *)__zbuf_pull(zb, sz, 1)) +#define zbuf_may_pull(zb, type) ((type *)__zbuf_pull(zb, sizeof(type), 0)) +#define zbuf_may_pulln(zb, sz) ((void *)__zbuf_pull(zb, sz, 0)) + +void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg); + +static inline void zbuf_get(struct zbuf *zb, void *dst, size_t len) +{ + void *src = zbuf_pulln(zb, len); + if (src) memcpy(dst, src, len); +} + +static inline uint8_t zbuf_get8(struct zbuf *zb) +{ + uint8_t *src = zbuf_pull(zb, uint8_t); + if (src) return *src; + return 0; +} + +static inline uint32_t zbuf_get32(struct zbuf *zb) +{ + struct unaligned32 { + uint32_t value; + } __attribute__((packed)); + + struct unaligned32 *v = zbuf_pull(zb, struct unaligned32); + if (v) return v->value; + return 0; +} + +static inline uint16_t zbuf_get_be16(struct zbuf *zb) +{ + struct unaligned16 { + uint16_t value; + } __attribute__((packed)); + + struct unaligned16 *v = zbuf_pull(zb, struct unaligned16); + if (v) return be16toh(v->value); + return 0; +} + +static inline uint32_t zbuf_get_be32(struct zbuf *zb) +{ + return be32toh(zbuf_get32(zb)); +} + +static inline void *__zbuf_push(struct zbuf *zb, size_t size, int error) +{ + void *tail = zb->tail; + if (size > zbuf_tailroom(zb)) { + if (error) zbuf_set_werror(zb); + return NULL; + } + zb->tail += size; + return tail; +} + +#define zbuf_push(zb, type) ((type *)__zbuf_push(zb, sizeof(type), 1)) +#define zbuf_pushn(zb, sz) ((void *)__zbuf_push(zb, sz, 1)) +#define zbuf_may_push(zb, type) ((type *)__zbuf_may_push(zb, sizeof(type), 0)) +#define zbuf_may_pushn(zb, sz) ((void *)__zbuf_push(zb, sz, 0)) + +static inline void zbuf_put(struct zbuf *zb, const void *src, size_t len) +{ + void *dst = zbuf_pushn(zb, len); + if (dst) memcpy(dst, src, len); +} + +static inline void zbuf_put8(struct zbuf *zb, uint8_t val) +{ + uint8_t *dst = zbuf_push(zb, uint8_t); + if (dst) *dst = val; +} + +static inline void zbuf_put_be16(struct zbuf *zb, uint16_t val) +{ + struct unaligned16 { + uint16_t value; + } __attribute__((packed)); + + struct unaligned16 *v = zbuf_push(zb, struct unaligned16); + if (v) v->value = htobe16(val); +} + +static inline void zbuf_put_be32(struct zbuf *zb, uint32_t val) +{ + struct unaligned32 { + uint32_t value; + } __attribute__((packed)); + + struct unaligned32 *v = zbuf_push(zb, struct unaligned32); + if (v) v->value = htobe32(val); +} + +void zbuf_copy(struct zbuf *zb, struct zbuf *src, size_t len); + +void zbufq_init(struct zbuf_queue *); +void zbufq_reset(struct zbuf_queue *); +void zbufq_queue(struct zbuf_queue *, struct zbuf *); +int zbufq_write(struct zbuf_queue *, int); + +#endif diff --git a/nhrpd/znl.c b/nhrpd/znl.c new file mode 100644 index 000000000..2216d97eb --- /dev/null +++ b/nhrpd/znl.c @@ -0,0 +1,160 @@ +/* Netlink helpers for zbuf + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "znl.h" + +#define ZNL_ALIGN(len) (((len)+3) & ~3) + +void *znl_push(struct zbuf *zb, size_t n) +{ + return zbuf_pushn(zb, ZNL_ALIGN(n)); +} + +void *znl_pull(struct zbuf *zb, size_t n) +{ + return zbuf_pulln(zb, ZNL_ALIGN(n)); +} + +struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags) +{ + struct nlmsghdr *n; + + n = znl_push(zb, sizeof(*n)); + if (!n) return NULL; + + *n = (struct nlmsghdr) { + .nlmsg_type = type, + .nlmsg_flags = flags, + }; + return n; +} + +void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n) +{ + n->nlmsg_len = zb->tail - (uint8_t*)n; +} + +struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload) +{ + struct nlmsghdr *n; + size_t plen; + + n = znl_pull(zb, sizeof(*n)); + if (!n) return NULL; + + plen = n->nlmsg_len - sizeof(*n); + zbuf_init(payload, znl_pull(zb, plen), plen, plen); + zbuf_may_pulln(zb, ZNL_ALIGN(plen) - plen); + + return n; +} + +struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val, size_t len) +{ + struct rtattr *rta; + uint8_t *dst; + + rta = znl_push(zb, ZNL_ALIGN(sizeof(*rta)) + ZNL_ALIGN(len)); + if (!rta) return NULL; + + *rta = (struct rtattr) { + .rta_type = type, + .rta_len = ZNL_ALIGN(sizeof(*rta)) + len, + }; + + dst = (uint8_t *)(rta+1); + memcpy(dst, val, len); + memset(dst+len, 0, ZNL_ALIGN(len) - len); + + return rta; +} + +struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val) +{ + return znl_rta_push(zb, type, &val, sizeof(val)); +} + +struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type) +{ + struct rtattr *rta; + + rta = znl_push(zb, sizeof(*rta)); + if (!rta) return NULL; + + *rta = (struct rtattr) { + .rta_type = type, + }; + return rta; +} + +void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta) +{ + size_t len = zb->tail - (uint8_t*) rta; + size_t align = ZNL_ALIGN(len) - len; + + if (align) { + void *dst = zbuf_pushn(zb, align); + if (dst) memset(dst, 0, align); + } + rta->rta_len = len; +} + +struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload) +{ + struct rtattr *rta; + size_t plen; + + rta = znl_pull(zb, sizeof(*rta)); + if (!rta) return NULL; + + if (rta->rta_len > sizeof(*rta)) { + plen = rta->rta_len - sizeof(*rta); + zbuf_init(payload, znl_pull(zb, plen), plen, plen); + } else { + zbuf_init(payload, NULL, 0, 0); + } + + return rta; +} + +int znl_open(int protocol, int groups) +{ + struct sockaddr_nl addr; + int fd, buf = 128 * 1024; + + fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (fd < 0) + return -1; + + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + fcntl(fd, F_SETFD, FD_CLOEXEC); + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0) + goto error; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_groups = groups; + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + goto error; + + return fd; +error: + close(fd); + return -1; +} + diff --git a/nhrpd/znl.h b/nhrpd/znl.h new file mode 100644 index 000000000..2cd630b5d --- /dev/null +++ b/nhrpd/znl.h @@ -0,0 +1,29 @@ +/* Netlink helpers for zbuf + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "zbuf.h" + +#define ZNL_BUFFER_SIZE 8192 + +void *znl_push(struct zbuf *zb, size_t n); +void *znl_pull(struct zbuf *zb, size_t n); + +struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags); +void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n); +struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload); + +struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val, size_t len); +struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val); +struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type); +void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta); + +struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload); + +int znl_open(int protocol, int groups); + diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index e44cd49f5..983103fff 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -24,6 +24,7 @@ vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \ $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \ $(top_srcdir)/pimd/pim_cmd.c \ + $(top_srcdir)/nhrpd/nhrp_vty.c \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index d0cc2ebb5..a6340cc73 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -60,6 +60,7 @@ struct vtysh_client { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH}, { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH}, { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH}, + { .fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .path = NHRP_VTYSH_PATH}, }; diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 1681a71ae..02ff7fd7a 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -31,9 +31,10 @@ #define VTYSH_ISISD 0x40 #define VTYSH_BABELD 0x80 #define VTYSH_PIMD 0x100 -#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD +#define VTYSH_NHRPD 0x200 +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD|VTYSH_NHRPD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD -#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD +#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD|VTYSH_NHRPD /* vtysh local configuration file. */ #define VTYSH_DEFAULT_CONFIG "vtysh.conf" diff --git a/zebra/client_main.c b/zebra/client_main.c index 43ab29978..75c886773 100644 --- a/zebra/client_main.c +++ b/zebra/client_main.c @@ -120,6 +120,7 @@ struct zebra_info { "ospf", ZEBRA_ROUTE_OSPF }, { "ospf6", ZEBRA_ROUTE_OSPF6 }, { "bgp", ZEBRA_ROUTE_BGP }, + { "nhrp", ZEBRA_ROUTE_NHRP }, { NULL, 0 } }; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 2aecf5dac..9ca02904e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -72,6 +72,7 @@ static const struct [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115}, [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */}, [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, + [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10}, /* no entry/default: 150 */ }; @@ -1423,6 +1424,7 @@ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = { [ZEBRA_ROUTE_BGP] = 3, [ZEBRA_ROUTE_HSLS] = 4, [ZEBRA_ROUTE_BABEL] = 2, + [ZEBRA_ROUTE_NHRP] = 2, }; /* Look into the RN and queue it into one or more priority queues, diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 5762d3f2c..859b6d793 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -223,16 +223,27 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) + if (! CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) + continue; + + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { - if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + if (rib->type == ZEBRA_ROUTE_CONNECT) + break; + + if (rib->type == ZEBRA_ROUTE_NHRP) { - if (rib->type == ZEBRA_ROUTE_CONNECT) + struct nexthop *nexthop; + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (nexthop->type == NEXTHOP_TYPE_IFINDEX || + nexthop->type == NEXTHOP_TYPE_IFNAME) + break; + if (nexthop) break; } - else - break; } + else + break; } } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 38f61e9d2..c73896b3b 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2121,6 +2121,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_NHRP || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; @@ -2341,6 +2342,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_NHRP || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; From 5958b8f790f0049f980b74b3e2916979850e5d09 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 1 Oct 2016 04:06:03 +0200 Subject: [PATCH 1234/1342] ospfd: Update route in zebra when tag changes Signed-off-by: Christian Franke --- ospfd/ospf_ase.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 74c1711ef..fe40b1017 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -598,6 +598,10 @@ ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix, if (op->ifindex != newop->ifindex) return 0; } + + if (or->u.ext.tag != newor->u.ext.tag) + return 0; + return 1; } From ddc160cce1767ef006a812f5213cabfb24e3cd4d Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 1 Oct 2016 20:42:34 +0200 Subject: [PATCH 1235/1342] *: Port Christians tweaks for 32-bit route tags Port over Christian's tweaks from his port of my commit widening the route-tag field width to 32-bit. Commit dc9ffce8786844 "*: Consistently support 32-bit route tags". with "changes which make this actually useful for all the daemons". This is missing the zebra route-map changes. --- bgpd/bgp_routemap.c | 88 +++------------------- lib/routemap.c | 26 +++++++ lib/routemap.h | 3 + lib/zclient.c | 2 +- ospfd/ospf_asbr.h | 2 +- ospfd/ospf_dump.c | 2 +- ospfd/ospf_routemap.c | 85 +++------------------ ospfd/ospf_vty.c | 8 +- pimd/pim_zebra.c | 5 ++ ripd/rip_routemap.c | 70 +++--------------- ripd/ripd.h | 2 +- ripngd/ripng_route.h | 4 +- ripngd/ripng_routemap.c | 62 +++------------- ripngd/ripngd.h | 4 +- zebra/zebra_vty.c | 158 ++++++++++++++++++++-------------------- zebra/zserv.c | 8 +- 16 files changed, 171 insertions(+), 358 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 921687a7f..68c78458e 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1026,47 +1026,13 @@ route_match_tag (void *rule, struct prefix *prefix, return RMAP_NOMATCH; } - -/* Route map `match tag' match statement. `arg' is TAG value */ -static void * -route_match_tag_compile (const char *arg) -{ - route_tag_t *tag; - route_tag_t tmp; - - /* tag value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - tmp = atoi(arg); - if (tmp < 1) - return NULL; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - - if (!tag) - return tag; - - *tag = tmp; - - return tag; -} - - -/* Free route map's compiled 'match tag' value. */ -static void -route_match_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for tag matching. */ -struct route_map_rule_cmd route_match_tag_cmd = +static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, - route_match_tag_compile, - route_match_tag_free, + route_map_rule_tag_compile, + route_map_rule_tag_free, }; @@ -1866,47 +1832,13 @@ route_set_tag (void *rule, struct prefix *prefix, return RMAP_OKAY; } -/* Route map `tag' compile function. Given string is converted to u_short. */ -static void * -route_set_tag_compile (const char *arg) -{ - route_tag_t *tag; - route_tag_t tmp; - - /* tag value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - tmp = atoi(arg); - - if (tmp < 1) - return NULL; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - - if (!tag) - return tag; - - *tag = tmp; - - return tag; -} - -/* Free route map's tag value. */ -static void -route_set_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - - /* Route map commands for tag set. */ -struct route_map_rule_cmd route_set_tag_cmd = +static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, - route_set_tag_compile, - route_set_tag_free, + route_map_rule_tag_compile, + route_map_rule_tag_free, }; @@ -3126,7 +3058,7 @@ ALIAS (no_match_origin, DEFUN (match_tag, match_tag_cmd, - "match tag <1-65535>", + "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Tag value\n") @@ -3149,7 +3081,7 @@ DEFUN (no_match_tag, ALIAS (no_match_tag, no_match_tag_val_cmd, - "no match tag <1-65535>", + "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" @@ -3822,7 +3754,7 @@ ALIAS (no_set_aggregator_as, DEFUN (set_tag, set_tag_cmd, - "set tag <1-65535>", + "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -3845,7 +3777,7 @@ DEFUN (no_set_tag, ALIAS (no_set_tag, no_set_tag_val_cmd, - "no set tag <1-65535>", + "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" diff --git a/lib/routemap.c b/lib/routemap.c index 7302e2311..c39222670 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1299,6 +1299,32 @@ static struct cmd_node rmap_node = 1 }; +/* Common route map rules */ + +void * +route_map_rule_tag_compile (const char *arg) +{ + unsigned long int tmp; + char *endptr; + route_tag_t *tag; + + errno = 0; + tmp = strtoul(arg, &endptr, 0); + if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX) + return NULL; + + tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag)); + *tag = tmp; + + return tag; +} + +void +route_map_rule_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + /* Initialization of route map vector. */ void route_map_init_vty (void) diff --git a/lib/routemap.h b/lib/routemap.h index 2479c81ab..48fafaf28 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -196,4 +196,7 @@ extern void route_map_add_hook (void (*func) (const char *)); extern void route_map_delete_hook (void (*func) (const char *)); extern void route_map_event_hook (void (*func) (route_map_event_t, const char *)); +extern void *route_map_rule_tag_compile (const char *arg); +extern void route_map_rule_tag_free (void *rule); + #endif /* _ZEBRA_ROUTEMAP_H */ diff --git a/lib/zclient.c b/lib/zclient.c index eb8de1a88..a32faaabf 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -530,7 +530,7 @@ zclient_connect (struct thread *t) * If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8 * byte value. * - * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value + * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 4 byte value * * XXX: No attention paid to alignment. */ diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index bc41a149e..0fc330268 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -44,7 +44,7 @@ struct external_info /* Nexthop address. */ struct in_addr nexthop; - /* Additional Route tag. */ + /* Additional Route tag: this is the wire type */ u_int32_t tag; struct route_map_set_values route_map_set; diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 66cc29403..be9fa2a75 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -493,7 +493,7 @@ ospf_as_external_lsa_dump (struct stream *s, u_int16_t length) IS_EXTERNAL_METRIC (al->e[i].tos) ? "E" : "-", al->e[i].tos & 0x7f, GET_METRIC (al->e[i].metric)); zlog_debug (" Forwarding address %s", inet_ntoa (al->e[i].fwd_addr)); - zlog_debug (" External Route Tag %d", al->e[i].route_tag); + zlog_debug (" External Route Tag %u", al->e[i].route_tag); } } diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index dc4181204..31d7ce2fb 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -436,45 +436,13 @@ route_match_tag (void *rule, struct prefix *prefix, return RMAP_NOMATCH; } -/* Route map `match tag' match statement. `arg' is TAG value */ -static void * -route_match_tag_compile (const char *arg) -{ - route_tag_t *tag; - route_tag_t tmp; - - /* tag value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - tmp = atoi(arg); - if (tmp < 1) - return NULL; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - - if (!tag) - return tag; - - *tag = tmp; - - return tag; -} - -/* Free route map's compiled 'match tag' value. */ -static void -route_match_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for tag matching. */ -struct route_map_rule_cmd route_match_tag_cmd = +static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, - route_match_tag_compile, - route_match_tag_free, + route_map_rule_tag_compile, + route_map_rule_tag_free, }; @@ -626,46 +594,13 @@ route_set_tag (void *rule, struct prefix *prefix, return RMAP_OKAY; } -/* Route map `tag' compile function. Given string is converted to u_short. */ -static void * -route_set_tag_compile (const char *arg) -{ - route_tag_t *tag; - route_tag_t tmp; - - /* tag value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - tmp = atoi(arg); - - if (tmp < 1) - return NULL; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - - if (!tag) - return tag; - - *tag = tmp; - - return tag; -} - -/* Free route map's tag value. */ -static void -route_set_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for tag set. */ -struct route_map_rule_cmd route_set_tag_cmd = +static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, - route_set_tag_compile, - route_set_tag_free, + route_map_rule_tag_compile, + route_map_rule_tag_free, }; DEFUN (match_ip_nexthop, @@ -855,7 +790,7 @@ ALIAS (no_match_interface, DEFUN (match_tag, match_tag_cmd, - "match tag <1-65535>", + "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Tag value\n") @@ -878,7 +813,7 @@ DEFUN (no_match_tag, ALIAS (no_match_tag, no_match_tag_val_cmd, - "no match tag <1-65535>", + "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" @@ -955,7 +890,7 @@ ALIAS (no_set_metric_type, DEFUN (set_tag, set_tag_cmd, - "set tag <1-65535>", + "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -978,7 +913,7 @@ DEFUN (no_set_tag, ALIAS (no_set_tag, no_set_tag_val_cmd, - "no set tag <1-65535>", + "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 1772f24fe..f31355ee8 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3872,8 +3872,8 @@ show_as_external_lsa_stdvty (struct ospf_lsa *lsa) zlog_debug( " Forward Address: %s%s", inet_ntoa (al->e[0].fwd_addr), "\n"); - zlog_debug( " External Route Tag: %u%s%s", - ntohl (al->e[0].route_tag), "\n", "\n"); + zlog_debug( " External Route Tag: %lu%s%s", + (u_long)ntohl (al->e[0].route_tag), "\n", "\n"); return 0; } @@ -3900,8 +3900,8 @@ show_as_nssa_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) vty_out (vty, " NSSA: Forward Address: %s%s", inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); - vty_out (vty, " External Route Tag: %u%s%s", - ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, " External Route Tag: %lu%s%s", + (u_long)ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); } return 0; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 7072a3b28..efff10009 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -582,6 +582,11 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient, stream_getl(s) : 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getl (s); + else + api.tag = 0; + switch (command) { case ZEBRA_IPV4_ROUTE_ADD: if (PIM_DEBUG_ZEBRA) { diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 20d3e6e50..4e736944c 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -480,45 +480,13 @@ route_match_tag (void *rule, struct prefix *prefix, return RMAP_NOMATCH; } -/* Route map `match tag' match statement. `arg' is TAG value */ -static void * -route_match_tag_compile (const char *arg) -{ - route_tag_t *tag; - route_tag_t tmp; - - /* tag value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - tmp = atoi(arg); - if (tmp < 1) - return NULL; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - - if (!tag) - return tag; - - *tag = tmp; - - return tag; -} - -/* Free route map's compiled `match tag' value. */ -static void -route_match_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for tag matching. */ -struct route_map_rule_cmd route_match_tag_cmd = +static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, - route_match_tag_compile, - route_match_tag_free + route_map_rule_tag_compile, + route_map_rule_tag_free, }; /* `set metric METRIC' */ @@ -703,33 +671,13 @@ route_set_tag (void *rule, struct prefix *prefix, return RMAP_OKAY; } -/* Route map `tag' compile function. Given string is converted - to u_short. */ -static void * -route_set_tag_compile (const char *arg) -{ - route_tag_t *tag; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - *tag = atoi (arg); - - return tag; -} - -/* Free route map's compiled `ip nexthop' value. */ -static void -route_set_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, - route_set_tag_compile, - route_set_tag_free + route_map_rule_tag_compile, + route_map_rule_tag_free }; #define MATCH_STR "Match values from routing table\n" @@ -950,7 +898,7 @@ ALIAS (no_match_ip_address_prefix_list, DEFUN (match_tag, match_tag_cmd, - "match tag <1-65535>", + "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Metric value\n") @@ -973,7 +921,7 @@ DEFUN (no_match_tag, ALIAS (no_match_tag, no_match_tag_val_cmd, - "no match tag <1-65535>", + "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" @@ -1073,7 +1021,7 @@ ALIAS (no_set_ip_nexthop, DEFUN (set_tag, set_tag_cmd, - "set tag <1-65535>", + "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -1096,7 +1044,7 @@ DEFUN (no_set_tag, ALIAS (no_set_tag, no_set_tag_val_cmd, - "no set tag <1-65535>", + "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" diff --git a/ripd/ripd.h b/ripd/ripd.h index 5e87fcd57..9dba1a57b 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -223,7 +223,7 @@ struct rip_info struct in_addr nexthop_out; u_char metric_set; u_int32_t metric_out; - u_short tag_out; + u_int16_t tag_out; ifindex_t ifindex_out; struct route_node *rp; diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h index fe65c8836..9ff90aa8d 100644 --- a/ripngd/ripng_route.h +++ b/ripngd/ripng_route.h @@ -35,13 +35,13 @@ struct ripng_aggregate u_char metric; /* Tag field of RIPng packet.*/ - u_short tag; + u_int16_t tag; /* Route-map futures - this variables can be changed. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; - u_short tag_out; + u_int16_t tag_out; }; extern void ripng_aggregate_increment (struct route_node *rp, diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index eae4566a6..c596aec15 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -240,7 +240,7 @@ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct ripng_info *rinfo; if (type == RMAP_RIPNG) @@ -257,32 +257,12 @@ route_match_tag (void *rule, struct prefix *prefix, return RMAP_NOMATCH; } -/* Route map `match tag' match statement. `arg' is TAG value */ -static void * -route_match_tag_compile (const char *arg) -{ - u_short *tag; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - *tag = atoi (arg); - - return tag; -} - -/* Free route map's compiled `match tag' value. */ -static void -route_match_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - -/* Route map commands for tag matching. */ static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, - route_match_tag_compile, - route_match_tag_free + route_map_rule_tag_compile, + route_map_rule_tag_free, }; /* `set metric METRIC' */ @@ -452,7 +432,7 @@ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_short *tag; + route_tag_t *tag; struct ripng_info *rinfo; if(type == RMAP_RIPNG) @@ -460,7 +440,7 @@ route_set_tag (void *rule, struct prefix *prefix, /* Fetch routemap's rule information. */ tag = rule; rinfo = object; - + /* Set next hop value. */ rinfo->tag_out = *tag; } @@ -468,33 +448,13 @@ route_set_tag (void *rule, struct prefix *prefix, return RMAP_OKAY; } -/* Route map `tag' compile function. Given string is converted - to u_short. */ -static void * -route_set_tag_compile (const char *arg) -{ - u_short *tag; - - tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); - *tag = atoi (arg); - - return tag; -} - -/* Free route map's compiled `ip nexthop' value. */ -static void -route_set_tag_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, - route_set_tag_compile, - route_set_tag_free + route_map_rule_tag_compile, + route_map_rule_tag_free }; #define MATCH_STR "Match values from routing table\n" @@ -564,7 +524,7 @@ ALIAS (no_match_interface, DEFUN (match_tag, match_tag_cmd, - "match tag <1-65535>", + "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Metric value\n") @@ -587,7 +547,7 @@ DEFUN (no_match_tag, ALIAS (no_match_tag, no_match_tag_val_cmd, - "no match tag <1-65535>", + "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" @@ -675,7 +635,7 @@ ALIAS (no_set_ipv6_nexthop_local, DEFUN (set_tag, set_tag_cmd, - "set tag <1-65535>", + "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -698,7 +658,7 @@ DEFUN (no_set_tag, ALIAS (no_set_tag, no_set_tag_val_cmd, - "no set tag <1-65535>", + "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 93f6ff14a..ef6d56a7b 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -146,7 +146,7 @@ struct ripng struct rte { struct in6_addr addr; /* RIPng destination prefix */ - u_short tag; /* RIPng tag */ + u_int16_t tag; /* RIPng tag */ u_char prefixlen; /* Length of the RIPng prefix */ u_char metric; /* Metric of the RIPng route */ /* The nexthop is stored by the structure @@ -200,7 +200,7 @@ struct ripng_info struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; - u_short tag_out; + u_int16_t tag_out; struct route_node *rp; }; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c73896b3b..2914f15b6 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -475,7 +475,7 @@ DEFUN (ip_route, DEFUN (ip_route_tag, ip_route_tag_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>", + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -491,7 +491,7 @@ DEFUN (ip_route_tag, DEFUN (ip_route_tag_vrf, ip_route_tag_vrf_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -523,7 +523,7 @@ DEFUN (ip_route_flags, DEFUN (ip_route_flags_tag, ip_route_flags_tag_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -541,7 +541,7 @@ DEFUN (ip_route_flags_tag, DEFUN (ip_route_flags_tag_vrf, ip_route_flags_tag_vrf_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -572,7 +572,7 @@ DEFUN (ip_route_flags2, DEFUN (ip_route_flags2_tag, ip_route_flags2_tag_cmd, - "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -587,7 +587,7 @@ DEFUN (ip_route_flags2_tag, DEFUN (ip_route_flags2_tag_vrf, ip_route_flags2_tag_vrf_cmd, - "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -619,7 +619,7 @@ DEFUN (ip_route_mask, DEFUN (ip_route_mask_tag, ip_route_mask_tag_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>", + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -637,7 +637,7 @@ DEFUN (ip_route_mask_tag, DEFUN (ip_route_mask_tag_vrf, ip_route_mask_tag_vrf_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -671,7 +671,7 @@ DEFUN (ip_route_mask_flags, DEFUN (ip_route_mask_flags_tag, ip_route_mask_flags_tag_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -689,7 +689,7 @@ DEFUN (ip_route_mask_flags_tag, DEFUN (ip_route_mask_flags_tag_vrf, ip_route_mask_flags_tag_vrf_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -722,7 +722,7 @@ DEFUN (ip_route_mask_flags2, DEFUN (ip_route_mask_flags2_tag, ip_route_mask_flags2_tag_cmd, - "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>", + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -738,7 +738,7 @@ DEFUN (ip_route_mask_flags2_tag, DEFUN (ip_route_mask_flags2_tag_vrf, ip_route_mask_flags2_tag_vrf_cmd, - "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -771,7 +771,7 @@ DEFUN (ip_route_distance, DEFUN (ip_route_tag_distance, ip_route_tag_distance_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -788,7 +788,7 @@ DEFUN (ip_route_tag_distance, DEFUN (ip_route_tag_distance_vrf, ip_route_tag_distance_vrf_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -822,7 +822,7 @@ DEFUN (ip_route_flags_distance, DEFUN (ip_route_flags_tag_distance, ip_route_flags_tag_distance_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -840,7 +840,7 @@ DEFUN (ip_route_flags_tag_distance, DEFUN (ip_route_flags_tag_distance_vrf, ip_route_flags_tag_distance_vrf_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -873,7 +873,7 @@ DEFUN (ip_route_flags_distance2, DEFUN (ip_route_flags_tag_distance2, ip_route_flags_tag_distance2_cmd, - "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>", + "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -889,7 +889,7 @@ DEFUN (ip_route_flags_tag_distance2, DEFUN (ip_route_flags_tag_distance2_vrf, ip_route_flags_tag_distance2_vrf_cmd, - "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" @@ -922,7 +922,7 @@ DEFUN (ip_route_mask_distance, DEFUN (ip_route_mask_tag_distance, ip_route_mask_tag_distance_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -940,7 +940,7 @@ DEFUN (ip_route_mask_tag_distance, DEFUN (ip_route_mask_tag_distance_vrf, ip_route_mask_tag_distance_vrf_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -960,7 +960,7 @@ DEFUN (ip_route_mask_tag_distance_vrf, DEFUN (ip_route_mask_flags_tag_distance, ip_route_mask_flags_tag_distance_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -979,7 +979,7 @@ DEFUN (ip_route_mask_flags_tag_distance, DEFUN (ip_route_mask_flags_tag_distance_vrf, ip_route_mask_flags_tag_distance_vrf_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -1031,7 +1031,7 @@ DEFUN (ip_route_mask_flags_distance2, DEFUN (ip_route_mask_flags_tag_distance2, ip_route_mask_flags_tag_distance2_cmd, - "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>", + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -1048,7 +1048,7 @@ DEFUN (ip_route_mask_flags_tag_distance2, DEFUN (ip_route_mask_flags_tag_distance2_vrf, ip_route_mask_flags_tag_distance2_vrf_cmd, - "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" @@ -1081,7 +1081,7 @@ DEFUN (no_ip_route, DEFUN (no_ip_route_tag, no_ip_route_tag_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>", + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -1098,7 +1098,7 @@ DEFUN (no_ip_route_tag, DEFUN (no_ip_route_tag_vrf, no_ip_route_tag_vrf_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1128,7 +1128,7 @@ ALIAS (no_ip_route, ALIAS (no_ip_route_tag, no_ip_route_flags_tag_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -1156,7 +1156,7 @@ DEFUN (no_ip_route_flags2, DEFUN (no_ip_route_flags2_tag, no_ip_route_flags2_tag_cmd, - "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>", + "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -1172,7 +1172,7 @@ DEFUN (no_ip_route_flags2_tag, DEFUN (no_ip_route_flags2_tag_vrf, no_ip_route_flags2_tag_vrf_cmd, - "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1205,7 +1205,7 @@ DEFUN (no_ip_route_mask, DEFUN (no_ip_route_mask_tag, no_ip_route_mask_tag_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>", + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -1236,7 +1236,7 @@ ALIAS (no_ip_route_mask, ALIAS (no_ip_route_mask_tag, no_ip_route_mask_flags_tag_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>", + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -1266,7 +1266,7 @@ DEFUN (no_ip_route_mask_flags2, DEFUN (no_ip_route_mask_flags2_tag, no_ip_route_mask_flags2_tag_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>", + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -1283,7 +1283,7 @@ DEFUN (no_ip_route_mask_flags2_tag, DEFUN (no_ip_route_mask_flags2_tag_vrf, no_ip_route_mask_flags2_tag_vrf_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1317,7 +1317,7 @@ DEFUN (no_ip_route_distance, DEFUN (no_ip_route_tag_distance, no_ip_route_tag_distance_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -1335,7 +1335,7 @@ DEFUN (no_ip_route_tag_distance, DEFUN (no_ip_route_tag_distance_vrf, no_ip_route_tag_distance_vrf_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1371,7 +1371,7 @@ DEFUN (no_ip_route_flags_distance, DEFUN (no_ip_route_flags_tag_distance, no_ip_route_flags_tag_distance_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -1390,7 +1390,7 @@ DEFUN (no_ip_route_flags_tag_distance, DEFUN (no_ip_route_flags_tag_distance_vrf, no_ip_route_flags_tag_distance_vrf_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1425,7 +1425,7 @@ DEFUN (no_ip_route_flags_distance2, DEFUN (no_ip_route_flags_tag_distance2, no_ip_route_flags_tag_distance2_cmd, - "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>", + "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -1442,7 +1442,7 @@ DEFUN (no_ip_route_flags_tag_distance2, DEFUN (no_ip_route_flags_tag_distance2_vrf, no_ip_route_flags_tag_distance2_vrf_cmd, - "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1477,7 +1477,7 @@ DEFUN (no_ip_route_mask_distance, DEFUN (no_ip_route_mask_tag_distance, no_ip_route_mask_tag_distance_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>", + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -1496,7 +1496,7 @@ DEFUN (no_ip_route_mask_tag_distance, DEFUN (no_ip_route_mask_tag_distance_vrf, no_ip_route_mask_tag_distance_vrf_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1534,7 +1534,7 @@ DEFUN (no_ip_route_mask_flags_distance, DEFUN (no_ip_route_mask_flags_tag_distance, no_ip_route_mask_flags_tag_distance_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -1554,7 +1554,7 @@ DEFUN (no_ip_route_mask_flags_tag_distance, DEFUN (no_ip_route_mask_flags_tag_distance_vrf, no_ip_route_mask_flags_tag_distance_vrf_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -1983,7 +1983,7 @@ DEFUN (no_ip_route_mask_flags_distance2_vrf, DEFUN (no_ip_route_mask_flags_tag_distance2, no_ip_route_mask_flags_tag_distance2_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>", + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -2001,7 +2001,7 @@ DEFUN (no_ip_route_mask_flags_tag_distance2, DEFUN (no_ip_route_mask_flags_tag_distance2_vrf, no_ip_route_mask_flags_tag_distance2_vrf_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -2442,7 +2442,7 @@ DEFUN (show_ipv6_nht, DEFUN (show_ip_route_tag, show_ip_route_tag_cmd, - "show ip route tag <1-65535>", + "show ip route tag <1-4294967295>", SHOW_STR IP_STR "IP routing table\n" @@ -2485,7 +2485,7 @@ DEFUN (show_ip_route_tag, ALIAS (show_ip_route_tag, show_ip_route_tag_vrf_cmd, - "show ip route tag <1-65535>" VRF_CMD_STR, + "show ip route tag <1-4294967295>" VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" @@ -3488,7 +3488,7 @@ DEFUN (ipv6_route, DEFUN (ipv6_route_tag, ipv6_route_tag_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>", + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3502,7 +3502,7 @@ DEFUN (ipv6_route_tag, DEFUN (ipv6_route_tag_vrf, ipv6_route_tag_vrf_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3532,7 +3532,7 @@ DEFUN (ipv6_route_flags, DEFUN (ipv6_route_flags_tag, ipv6_route_flags_tag_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>", + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3548,7 +3548,7 @@ DEFUN (ipv6_route_flags_tag, DEFUN (ipv6_route_flags_tag_vrf, ipv6_route_flags_tag_vrf_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3578,7 +3578,7 @@ DEFUN (ipv6_route_ifname, DEFUN (ipv6_route_ifname_tag, ipv6_route_ifname_tag_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>", + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3592,7 +3592,7 @@ DEFUN (ipv6_route_ifname_tag, DEFUN (ipv6_route_ifname_tag_vrf, ipv6_route_ifname_tag_vrf_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3622,7 +3622,7 @@ DEFUN (ipv6_route_ifname_flags, DEFUN (ipv6_route_ifname_flags_tag, ipv6_route_ifname_flags_tag_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>", + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3638,7 +3638,7 @@ DEFUN (ipv6_route_ifname_flags_tag, DEFUN (ipv6_route_ifname_flags_tag_vrf, ipv6_route_ifname_flags_tag_vrf_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3669,7 +3669,7 @@ DEFUN (ipv6_route_pref, DEFUN (ipv6_route_pref_tag, ipv6_route_pref_tag_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>", + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3684,7 +3684,7 @@ DEFUN (ipv6_route_pref_tag, DEFUN (ipv6_route_pref_tag_vrf, ipv6_route_pref_tag_vrf_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3716,7 +3716,7 @@ DEFUN (ipv6_route_flags_pref, DEFUN (ipv6_route_flags_pref_tag, ipv6_route_flags_pref_tag_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3733,7 +3733,7 @@ DEFUN (ipv6_route_flags_pref_tag, DEFUN (ipv6_route_flags_pref_tag_vrf, ipv6_route_flags_pref_tag_vrf_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3765,7 +3765,7 @@ DEFUN (ipv6_route_ifname_pref, DEFUN (ipv6_route_ifname_pref_tag, ipv6_route_ifname_pref_tag_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>", + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3780,7 +3780,7 @@ DEFUN (ipv6_route_ifname_pref_tag, DEFUN (ipv6_route_ifname_pref_tag_vrf, ipv6_route_ifname_pref_tag_vrf_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3812,7 +3812,7 @@ DEFUN (ipv6_route_ifname_flags_pref, DEFUN (ipv6_route_ifname_flags_pref_tag, ipv6_route_ifname_flags_pref_tag_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>", + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3829,7 +3829,7 @@ DEFUN (ipv6_route_ifname_flags_pref_tag, DEFUN (ipv6_route_ifname_flags_pref_tag_vrf, ipv6_route_ifname_flags_pref_tag_vrf_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" @@ -3861,7 +3861,7 @@ DEFUN (no_ipv6_route, DEFUN (no_ipv6_route_tag, no_ipv6_route_tag_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>", + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -3876,7 +3876,7 @@ DEFUN (no_ipv6_route_tag, DEFUN (no_ipv6_route_tag_vrf, no_ipv6_route_tag_vrf_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -3904,7 +3904,7 @@ ALIAS (no_ipv6_route, ALIAS (no_ipv6_route_tag, no_ipv6_route_flags_tag_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>", + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -3932,7 +3932,7 @@ DEFUN (no_ipv6_route_ifname, DEFUN (no_ipv6_route_ifname_tag, no_ipv6_route_ifname_tag_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>", + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -3947,7 +3947,7 @@ DEFUN (no_ipv6_route_ifname_tag, DEFUN (no_ipv6_route_ifname_tag_vrf, no_ipv6_route_ifname_tag_vrf_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -3975,7 +3975,7 @@ ALIAS (no_ipv6_route_ifname, ALIAS (no_ipv6_route_ifname_tag, no_ipv6_route_ifname_flags_tag_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>", + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" @@ -4004,7 +4004,7 @@ DEFUN (no_ipv6_route_pref, DEFUN (no_ipv6_route_pref_tag, no_ipv6_route_pref_tag_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>", + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -4020,7 +4020,7 @@ DEFUN (no_ipv6_route_pref_tag, DEFUN (no_ipv6_route_pref_tag_vrf, no_ipv6_route_pref_tag_vrf_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -4055,7 +4055,7 @@ DEFUN (no_ipv6_route_flags_pref, DEFUN (no_ipv6_route_flags_pref_tag, no_ipv6_route_flags_pref_tag_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>", + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -4074,7 +4074,7 @@ DEFUN (no_ipv6_route_flags_pref_tag, DEFUN (no_ipv6_route_flags_pref_tag_vrf, no_ipv6_route_flags_pref_tag_vrf_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -4109,7 +4109,7 @@ DEFUN (no_ipv6_route_ifname_pref, DEFUN (no_ipv6_route_ifname_pref_tag, no_ipv6_route_ifname_pref_tag_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>", + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -4125,7 +4125,7 @@ DEFUN (no_ipv6_route_ifname_pref_tag, DEFUN (no_ipv6_route_ifname_pref_tag_vrf, no_ipv6_route_ifname_pref_tag_vrf_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -4159,7 +4159,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref, DEFUN (no_ipv6_route_ifname_flags_pref_tag, no_ipv6_route_ifname_flags_pref_tag_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>", + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -4177,7 +4177,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref_tag, DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf, no_ipv6_route_ifname_flags_pref_tag_vrf_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" @@ -4487,7 +4487,7 @@ ALIAS (show_ipv6_route, DEFUN (show_ipv6_route_tag, show_ipv6_route_tag_cmd, - "show ipv6 route tag <1-65535>", + "show ipv6 route tag <1-4294967295>", SHOW_STR IP_STR "IPv6 routing table\n" @@ -4530,7 +4530,7 @@ DEFUN (show_ipv6_route_tag, ALIAS (show_ipv6_route_tag, show_ipv6_route_tag_vrf_cmd, - "show ipv6 route tag <1-65535>" VRF_CMD_STR, + "show ipv6 route tag <1-4294967295>" VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" diff --git a/zebra/zserv.c b/zebra/zserv.c index 2c0c5b464..a96bcb1d8 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -986,7 +986,9 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) /* Tag */ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) rib->tag = stream_getl (s); - + else + rib->tag = 0; + /* Table */ rib->table=zebrad.rtm_table_default; ret = rib_add_ipv4_multipath (&p, rib, safi); @@ -1222,7 +1224,9 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) /* Tag */ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) rib->tag = stream_getl (s); - + else + rib->tag = 0; + /* Table */ rib->table=zebrad.rtm_table_default; ret = rib_add_ipv6_multipath (&p, rib, safi); From 7ae2b609875756663e0a7d677609d04baa04b613 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 1 Oct 2016 06:41:40 +0200 Subject: [PATCH 1236/1342] ospf6d: add support for route tags [ported by Paul Jakma, paul@jakma.org] --- ospf6d/ospf6_asbr.c | 191 +++++++++++++++++++++++++++++++++++++++++-- ospf6d/ospf6_asbr.h | 6 +- ospf6d/ospf6_route.h | 1 + ospf6d/ospf6_zebra.c | 20 +++-- 4 files changed, 204 insertions(+), 14 deletions(-) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 4b7d214aa..a442506c7 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -93,7 +93,10 @@ ospf6_as_external_lsa_originate (struct ospf6_route *route) UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); /* external route tag */ - UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); + if (info->tag) + SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); + else + UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); /* Set metric */ OSPF6_ASBR_METRIC_SET (as_external_lsa, route->path.cost); @@ -123,7 +126,10 @@ ospf6_as_external_lsa_originate (struct ospf6_route *route) /* External Route Tag */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) { - /* xxx */ + route_tag_t network_order = htonl(info->tag); + + memcpy (p, &network_order, sizeof(network_order)); + p += sizeof(network_order); } /* Fill LSA Header */ @@ -146,6 +152,29 @@ ospf6_as_external_lsa_originate (struct ospf6_route *route) ospf6_lsa_originate_process (lsa, ospf6); } +static route_tag_t +ospf6_as_external_lsa_get_tag (struct ospf6_lsa *lsa) +{ + struct ospf6_as_external_lsa *external; + ptrdiff_t tag_offset; + route_tag_t network_order; + + if (!lsa) + return 0; + + external = (struct ospf6_as_external_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + if (!CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T)) + return 0; + + tag_offset = sizeof(*external) + OSPF6_PREFIX_SPACE(external->prefix.prefix_length); + if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) + tag_offset += sizeof(struct in6_addr); + + memcpy(&network_order, (caddr_t)external + tag_offset, sizeof(network_order)); + return ntohl(network_order); +} void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) @@ -223,6 +252,8 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) route->path.cost_e2 = 0; } + route->path.tag = ospf6_as_external_lsa_get_tag (lsa); + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]); @@ -413,7 +444,7 @@ ospf6_asbr_redistribute_unset (int type) void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, - u_int nexthop_num, struct in6_addr *nexthop) + u_int nexthop_num, struct in6_addr *nexthop, route_tag_t tag) { int ret; struct ospf6_route troute; @@ -455,6 +486,7 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, memset (&tinfo, 0, sizeof (tinfo)); troute.route_option = &tinfo; tinfo.ifindex = ifindex; + tinfo.tag = tag; ret = route_map_apply (ospf6->rmap[type].map, prefix, RMAP_OSPF6, &troute); @@ -481,6 +513,12 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) memcpy (&info->forwarding, &tinfo.forwarding, sizeof (struct in6_addr)); + info->tag = tinfo.tag; + } + else + { + /* If there is no route-map, simply update the tag */ + info->tag = tag; } info->type = type; @@ -526,6 +564,12 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) memcpy (&info->forwarding, &tinfo.forwarding, sizeof (struct in6_addr)); + info->tag = tinfo.tag; + } + else + { + /* If there is no route-map, simply set the tag */ + info->tag = tag; } info->type = type; @@ -844,6 +888,30 @@ ospf6_routemap_rule_match_interface_cmd = ospf6_routemap_rule_match_interface_free }; +/* Match function for matching route tags */ +static route_map_result_t +ospf6_routemap_rule_match_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + route_tag_t *tag = rule; + struct ospf6_route *route = object; + struct ospf6_external_info *info = route->route_option; + + if (type == RMAP_OSPF6 && info->tag == *tag) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +static struct route_map_rule_cmd +ospf6_routemap_rule_match_tag_cmd = +{ + "tag", + ospf6_routemap_rule_match_tag, + route_map_rule_tag_compile, + route_map_rule_tag_free, +}; + static route_map_result_t ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix, route_map_object_t type, void *object) @@ -969,6 +1037,30 @@ ospf6_routemap_rule_set_forwarding_cmd = ospf6_routemap_rule_set_forwarding_free, }; +static route_map_result_t +ospf6_routemap_rule_set_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + route_tag_t *tag = rule; + struct ospf6_route *route = object; + struct ospf6_external_info *info = route->route_option; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + info->tag = *tag; + return RMAP_OKAY; +} + +static struct route_map_rule_cmd +ospf6_routemap_rule_set_tag_cmd = +{ + "tag", + ospf6_routemap_rule_set_tag, + route_map_rule_tag_compile, + route_map_rule_tag_free, +}; + static int route_map_command_status (struct vty *vty, int ret) { @@ -1037,8 +1129,8 @@ DEFUN (ospf6_routemap_match_interface, DEFUN (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_cmd, "no match interface", - MATCH_STR NO_STR + MATCH_STR "Match first hop interface of route\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, @@ -1049,11 +1141,45 @@ DEFUN (ospf6_routemap_no_match_interface, ALIAS (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_val_cmd, "no match interface WORD", - MATCH_STR NO_STR + MATCH_STR "Match first hop interface of route\n" "Interface name\n") +/* add "match tag" */ +DEFUN (ospf6_routemap_match_tag, + ospf6_routemap_match_tag_cmd, + "match tag <1-4294967295>", + MATCH_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + int ret = route_map_add_match ((struct route_map_index *) vty->index, + "tag", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "match tag" */ +DEFUN (ospf6_routemap_no_match_tag, + ospf6_routemap_no_match_tag_cmd, + "no match tag", + NO_STR + MATCH_STR + "Tag value for routing protocol\n") +{ + int ret = route_map_delete_match ((struct route_map_index *) vty->index, + "tag", argc ? argv[0] : NULL); + return route_map_command_status (vty, ret); +} + +ALIAS (ospf6_routemap_no_match_tag, + ospf6_routemap_no_match_tag_val_cmd, + "no match tag <1-4294967295>", + NO_STR + MATCH_STR + "Tag value for routing protocol\n" + "Tag value\n") + /* add "set metric-type" */ DEFUN (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd, @@ -1150,6 +1276,40 @@ DEFUN (ospf6_routemap_no_set_forwarding, return route_map_command_status (vty, ret); } +/* add "set tag" */ +DEFUN (ospf6_routemap_set_tag, + ospf6_routemap_set_tag_cmd, + "set tag <1-4294967295>", + "Set value\n" + "Tag value for routing protocol\n" + "Tag value\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "tag", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set tag" */ +DEFUN (ospf6_routemap_no_set_tag, + ospf6_routemap_no_set_tag_cmd, + "no set tag", + NO_STR + "Set value\n" + "Tag value for routing protocol\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "tag", argc ? argv[0] : NULL); + return route_map_command_status (vty, ret); +} + +ALIAS (ospf6_routemap_no_set_tag, + ospf6_routemap_no_set_tag_val_cmd, + "no set tag <1-4294967295>", + NO_STR + "Set value\n" + "Tag value for routing protocol\n" + "Tag value\n") + static void ospf6_routemap_init (void) { @@ -1160,10 +1320,12 @@ ospf6_routemap_init (void) route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd); route_map_install_match (&ospf6_routemap_rule_match_interface_cmd); + route_map_install_match (&ospf6_routemap_rule_match_tag_cmd); route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd); route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); + route_map_install_set (&ospf6_routemap_rule_set_tag_cmd); /* Match address prefix-list */ install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); @@ -1174,6 +1336,11 @@ ospf6_routemap_init (void) install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_val_cmd); + /* Match tag */ + install_element (RMAP_NODE, &ospf6_routemap_match_tag_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_match_tag_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_match_tag_val_cmd); + /* ASE Metric Type (e.g. Type-1/Type-2) */ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); @@ -1183,9 +1350,14 @@ ospf6_routemap_init (void) install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); - /* ASE Metric */ + /* Forwarding address */ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); + + /* Tag */ + install_element (RMAP_NODE, &ospf6_routemap_set_tag_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_set_tag_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_set_tag_val_cmd); } @@ -1263,6 +1435,13 @@ ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) VNL); } + /* Tag */ + if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T)) + { + vty_out (vty, " Tag: %u%s", + ospf6_as_external_lsa_get_tag (lsa), VNL); + } + return 0; } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index f3df90b1f..14113b06b 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -47,7 +47,8 @@ struct ospf6_external_info u_int32_t id; struct in6_addr forwarding; - /* u_int32_t tag; */ + + route_tag_t tag; ifindex_t ifindex; }; @@ -82,7 +83,8 @@ extern int ospf6_asbr_is_asbr (struct ospf6 *o); extern void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, - struct in6_addr *nexthop); + struct in6_addr *nexthop, + route_tag_t tag); extern void ospf6_asbr_redistribute_remove (int type, ifindex_t ifindex, struct prefix *prefix); diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 2fb2c1d71..027a648a3 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -97,6 +97,7 @@ struct ospf6_path u_int8_t metric_type; u_int32_t cost; u_int32_t cost_e2; + u_int32_t tag; }; #define OSPF6_PATH_TYPE_NONE 0 diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index f80bb23f9..2976214b0 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -247,6 +247,11 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getl (s); + else + api.tag = 0; + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) { char prefixstr[128], nexthopstr[128]; @@ -256,14 +261,14 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, else snprintf (nexthopstr, sizeof (nexthopstr), "::"); - zlog_debug ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld", + zlog_debug ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld tag %u", (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"), - zebra_route_string(api.type), prefixstr, nexthopstr, ifindex); + zebra_route_string(api.type), prefixstr, nexthopstr, ifindex, api.tag); } if (command == ZEBRA_IPV6_ROUTE_ADD) ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, - api.nexthop_num, nexthop); + api.nexthop_num, nexthop, api.tag); else ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p); @@ -470,9 +475,12 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = (request->path.metric_type == 2 ? request->path.cost_e2 : request->path.cost); - SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = ospf6_distance_apply (request, ospf6); - + if (request->path.tag) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TAG); + api.tag = request->path.tag; + } + dest = (struct prefix_ipv6 *) &request->prefix; if (type == REM) ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api); From 2bbacea824300be05f46094a4d156cb12c0dca13 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 1 Oct 2016 21:43:17 +0200 Subject: [PATCH 1237/1342] ripd: add support for route tags --- ripd/rip_interface.c | 6 +++--- ripd/rip_zebra.c | 17 ++++++++++++++--- ripd/ripd.c | 7 +++++-- ripd/ripd.h | 5 +++-- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 240c9688b..7521fc79d 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -634,7 +634,7 @@ rip_apply_address_add (struct connected *ifc) if ((rip_enable_if_lookup(ifc->ifp->name) >= 0) || (rip_enable_network_lookup2(ifc) >= 0)) rip_redistribute_add(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, - &address, ifc->ifp->ifindex, NULL, 0, 0); + &address, ifc->ifp->ifindex, NULL, 0, 0, 0); } @@ -945,7 +945,7 @@ rip_connect_set (struct interface *ifp, int set) (rip_enable_network_lookup2(connected) >= 0)) rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, connected->ifp->ifindex, - NULL, 0, 0); + NULL, 0, 0, 0); } else { rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, @@ -953,7 +953,7 @@ rip_connect_set (struct interface *ifp, int set) if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT)) rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE, &address, connected->ifp->ifindex, - NULL, 0, 0); + NULL, 0, 0, 0); } } } diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 2670ff7ee..0b51af5a8 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -90,6 +90,12 @@ rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) api.distance = rinfo->distance; } + if (rinfo->tag) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TAG); + api.tag = rinfo->tag; + } + zapi_ipv4_route (cmd, zclient, (struct prefix_ipv4 *)&rp->p, &api); @@ -173,11 +179,16 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getl (s); + else + api.tag = 0; + /* Then fetch IPv4 prefixes. */ if (command == ZEBRA_IPV4_ROUTE_ADD) rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, - &nexthop, api.metric, api.distance); - else + &nexthop, api.metric, api.distance, api.tag); + else rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); return 0; @@ -612,7 +623,7 @@ DEFUN (rip_default_information_originate, rip->default_information = 1; rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0, - NULL, 0, 0); + NULL, 0, 0, 0); } return CMD_SUCCESS; diff --git a/ripd/ripd.c b/ripd/ripd.c index da9e7b007..848d801e2 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1510,7 +1510,8 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, void rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, ifindex_t ifindex, struct in_addr *nexthop, - unsigned int metric, unsigned char distance) + unsigned int metric, unsigned char distance, + route_tag_t tag) { int ret; struct route_node *rp = NULL; @@ -1531,6 +1532,8 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, newinfo.metric = 1; newinfo.external_metric = metric; newinfo.distance = distance; + if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */ + newinfo.tag = tag; newinfo.rp = rp; if (nexthop) newinfo.nexthop = *nexthop; @@ -2939,7 +2942,7 @@ DEFUN (rip_route, node->info = (char *)"static"; - rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0); + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0, 0); return CMD_SUCCESS; } diff --git a/ripd/ripd.h b/ripd/ripd.h index 9dba1a57b..4f8252526 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -400,8 +400,9 @@ extern int rip_request_send (struct sockaddr_in *, struct interface *, u_char, extern int rip_neighbor_lookup (struct sockaddr_in *); extern int rip_redistribute_check (int); -extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, ifindex_t, - struct in_addr *, unsigned int, unsigned char); +extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, ifindex_t, + struct in_addr *, unsigned int, unsigned char, + route_tag_t); extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, ifindex_t); extern void rip_redistribute_withdraw (int); extern void rip_zebra_ipv4_add (struct route_node *); From 5bb328e82137a0a9cc73e887d5074da273562d38 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Sat, 1 Oct 2016 22:35:32 +0200 Subject: [PATCH 1238/1342] ripngd: add support for route tags --- ripngd/ripng_interface.c | 6 +++--- ripngd/ripng_zebra.c | 14 +++++++++++++- ripngd/ripngd.c | 9 ++++++--- ripngd/ripngd.h | 2 +- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index e1f436ebf..1d3757a95 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -383,7 +383,7 @@ ripng_apply_address_add (struct connected *ifc) { if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) || (ripng_enable_network_lookup2(ifc) >= 0)) ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, - &address, ifc->ifp->ifindex, NULL); + &address, ifc->ifp->ifindex, NULL, 0); } @@ -704,13 +704,13 @@ ripng_connect_set (struct interface *ifp, int set) if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) || (ripng_enable_network_lookup2(connected) >= 0)) ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, - &address, connected->ifp->ifindex, NULL); + &address, connected->ifp->ifindex, NULL, 0); } else { ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex); if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT)) ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, - &address, connected->ifp->ifindex, NULL); + &address, connected->ifp->ifindex, NULL, 0); } } } diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 72216164a..a35bc990f 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -91,6 +91,12 @@ ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = rinfo->metric; + if (rinfo->tag) + { + SET_FLAG (api.message, ZAPI_MESSAGE_TAG); + api.tag = rinfo->tag; + } + zapi_ipv6_route (cmd, zclient, (struct prefix_ipv6 *)&rp->p, &api); @@ -172,8 +178,14 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient, else api.metric = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getl (s); + else + api.tag = 0; + if (command == ZEBRA_IPV6_ROUTE_ADD) - ripng_redistribute_add (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop); + ripng_redistribute_add (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, + ifindex, &nexthop, api.tag); else ripng_redistribute_delete (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index d94bea380..824b3a4c3 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -905,7 +905,8 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, /* Add redistributed route to RIPng table. */ void ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, - ifindex_t ifindex, struct in6_addr *nexthop) + ifindex_t ifindex, struct in6_addr *nexthop, + route_tag_t tag) { struct route_node *rp; struct ripng_info *rinfo = NULL, newinfo; @@ -924,6 +925,8 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, newinfo.sub_type = sub_type; newinfo.ifindex = ifindex; newinfo.metric = 1; + if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */ + newinfo.tag = tag; newinfo.rp = rp; if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop)) newinfo.nexthop = *nexthop; @@ -2214,7 +2217,7 @@ DEFUN (ripng_route, } rp->info = (void *)1; - ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL); + ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL, 0); return CMD_SUCCESS; } @@ -2551,7 +2554,7 @@ DEFUN (ripng_default_information_originate, ripng->default_information = 1; str2prefix_ipv6 ("::/0", &p); - ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL); + ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0); } return CMD_SUCCESS; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index ef6d56a7b..a0c6a4e58 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -381,7 +381,7 @@ extern void ripng_info_free (struct ripng_info *rinfo); extern void ripng_event (enum ripng_event, int); extern int ripng_request (struct interface *ifp); extern void ripng_redistribute_add (int, int, struct prefix_ipv6 *, - ifindex_t, struct in6_addr *); + ifindex_t, struct in6_addr *, route_tag_t); extern void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, ifindex_t); extern void ripng_redistribute_withdraw (int type); From c2c63cb3d5e2f56cf2b2d3f00535d275ab23a969 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 10 Oct 2016 19:35:43 -0400 Subject: [PATCH 1239/1342] ospfd: Fix arm compile issue size_t printf formatter is %zd! Signed-off-by: Donald Sharp --- ospfd/ospf_spf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 58a39921a..e1c290e6d 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1290,7 +1290,7 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, area->ts_spf = area->ospf->ts_spf; if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", + zlog_debug ("ospf_spf_calculate: Stop. %zd vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); /* Free SPF vertices, but not the list. List has ospf_vertex_free From a53d4e55a51518ae5735a65405dcee88c59cd5d8 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 20 Oct 2016 23:55:10 -0700 Subject: [PATCH 1240/1342] build: configure.ac - use AC_PROG_CC_C99 instead of cflags to force c99 mode --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 558984413..deb48ebc0 100755 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,7 @@ AM_PROG_CC_C_O AC_PROG_RANLIB AC_PROG_EGREP PKG_PROG_PKG_CONFIG +AC_PROG_CC_C99 dnl autoconf 2.59 appears not to support AC_PROG_SED dnl AC_PROG_SED @@ -145,7 +146,6 @@ if test "x${cflags_specified}" = "x" ; then AC_MSG_RESULT([autodetecting]) AC_C_FLAG([-diag-error 10006]) - AC_C_FLAG([-std=gnu99]) AC_C_FLAG([-g]) AC_C_FLAG([-Os], [ AC_C_FLAG([-O2]) From f2f44eaa321be5a52e5ad67069bd8061603589a1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 12 Nov 2016 17:43:15 +0900 Subject: [PATCH 1241/1342] zebra: fix link-params CLI handling vtysh was breaking in a rather ugly way, and some "no" forms were missing too. --- vtysh/vtysh_config.c | 14 +++++++++++++- zebra/interface.c | 8 ++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index c80c42a4f..e6d88236f 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -184,8 +184,20 @@ vtysh_config_parse_line (const char *line) else if (strncmp (line, " address-family ipv6", strlen (" address-family ipv6")) == 0) config = config_get (BGP_IPV6_NODE, line); + else if (strncmp (line, " link-params", strlen (" link-params")) == 0) + { + config_add_line (config->line, line); + config->index = LINK_PARAMS_NODE; + } + else if (config->index == LINK_PARAMS_NODE && + strncmp (line, " exit", strlen (" exit")) == 0) + { + config_add_line (config->line, line); + config->index = INTERFACE_NODE; + } else if (config->index == RMAP_NODE || - config->index == VTY_NODE) + config->index == INTERFACE_NODE || + config->index == VTY_NODE) config_add_line_uniq (config->line, line); else config_add_line (config->line, line); diff --git a/zebra/interface.c b/zebra/interface.c index 5e89db979..c5835f45c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -2636,6 +2636,7 @@ link_params_config_write (struct vty *vty, struct interface *ifp) if (IS_PARAM_SET(iflp, LP_RMT_AS)) vty_out(vty, " neighbor %s as %u%s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE); + vty_out(vty, " exit%s", VTY_NEWLINE); return 0; } @@ -2786,13 +2787,20 @@ zebra_if_init (void) install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_admin_grp_cmd); install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd); install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_delay_cmd); install_element(LINK_PARAMS_NODE, &link_params_delay_mm_cmd); install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_delay_var_cmd); install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_pkt_loss_cmd); install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_ava_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_res_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); } From 2c0adbf9bc0c2425f567848ba7f790059d18b253 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 18 Nov 2016 15:42:41 -0500 Subject: [PATCH 1242/1342] vtysh, zebra: Fix link-params to use exit-link-params Fix the link-params submode to use the 'exit-link-params' to indicate we are exiting a submode. Fixup all the relevant bits. --- vtysh/extract.pl.in | 4 ++++ vtysh/vtysh.c | 12 ++++++++++++ vtysh/vtysh_config.c | 2 +- zebra/interface.c | 13 ++++++++++++- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 924cffe2c..ca223e582 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -54,6 +54,10 @@ $ignore{'"address-family encap"'} = "ignore"; $ignore{'"address-family encapv4"'} = "ignore"; $ignore{'"address-family encapv6"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; +$ignore{'"exit-link-params"'} = "ignore"; +$ignore{'"vnc defaults"'} = "ignore"; +$ignore{'"vnc nve-group NAME"'} = "ignore"; +$ignore{'"exit-vnc"'} = "ignore"; $ignore{'"key chain WORD"'} = "ignore"; $ignore{'"key <0-2147483647>"'} = "ignore"; $ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index a6340cc73..5d59062df 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1465,6 +1465,17 @@ DEFUNSH (VTYSH_ZEBRA, return CMD_SUCCESS; } +DEFUNSH (VTYSH_ZEBRA, + exit_link_params, + exit_link_params_cmd, + "exit-link-params", + "Exit from Link Params configuration node\n") +{ + if (vty->node == LINK_PARAMS_NODE) + vty->node = INTERFACE_NODE; + return CMD_SUCCESS; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2544,6 +2555,7 @@ vtysh_init_vty (void) install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &vtysh_end_all_cmd); install_element (INTERFACE_NODE, &vtysh_exit_interface_cmd); + install_element (LINK_PARAMS_NODE, &exit_link_params_cmd); install_element (LINK_PARAMS_NODE, &vtysh_end_all_cmd); install_element (LINK_PARAMS_NODE, &vtysh_exit_interface_cmd); install_element (INTERFACE_NODE, &vtysh_quit_interface_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index e6d88236f..2834ef4d6 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -190,7 +190,7 @@ vtysh_config_parse_line (const char *line) config->index = LINK_PARAMS_NODE; } else if (config->index == LINK_PARAMS_NODE && - strncmp (line, " exit", strlen (" exit")) == 0) + strncmp (line, " exit-link-params", strlen (" exit")) == 0) { config_add_line (config->line, line); config->index = INTERFACE_NODE; diff --git a/zebra/interface.c b/zebra/interface.c index c5835f45c..f8b946ff4 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1625,6 +1625,16 @@ DEFUN (link_params, return CMD_SUCCESS; } +DEFUN (exit_link_params, + exit_link_params_cmd, + "exit-link-params", + "Exit from Link Params configuration mode\n") +{ + if (vty->node == LINK_PARAMS_NODE) + vty->node = INTERFACE_NODE; + return CMD_SUCCESS; +} + /* Specific Traffic Engineering parameters commands */ DEFUN (link_params_enable, link_params_enable_cmd, @@ -2636,7 +2646,7 @@ link_params_config_write (struct vty *vty, struct interface *ifp) if (IS_PARAM_SET(iflp, LP_RMT_AS)) vty_out(vty, " neighbor %s as %u%s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE); - vty_out(vty, " exit%s", VTY_NEWLINE); + vty_out(vty, " exit-link-params%s", VTY_NEWLINE); return 0; } @@ -2803,4 +2813,5 @@ zebra_if_init (void) install_element(LINK_PARAMS_NODE, &no_link_params_res_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); + install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); } From 4d48bb360db5148b18524d06616555b06342fa68 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 29 Nov 2016 12:47:12 -0500 Subject: [PATCH 1243/1342] bgpd: fix "show ip bgp" column alignment The "Weight" column is off: BGP table version is 0, local router ID is 10.1.1.1 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 4.1.1.2/32 9.9.9.2 0 32768 ? *> 4.1.1.4/32 9.9.9.2 0 32768 ? Displayed 2 out of 2 total prefixes Reviewed-by: Donald Sharp --- bgpd/bgp_route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ec2f967f1..527d5d987 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6033,12 +6033,12 @@ route_vty_out( if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) - vty_out (vty, "%10u ", attr->med); + vty_out (vty, "%10u", attr->med); else vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) - vty_out (vty, "%7u ", attr->local_pref); + vty_out (vty, "%7u", attr->local_pref); else vty_out (vty, " "); From 670f3dba6721a500418b5793a2b00579198d2bd7 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 28 Nov 2016 16:47:13 -0200 Subject: [PATCH 1244/1342] bgpd: fix invalid memory access in peer_free() We shoult not call bgp_unlock() before calling bgp_delete_connected_nexthop() in the peer_free() function. Otherwise, if bgp->lock reaches zero, bgp_free() is called and peer->bgp becomes an invalid pointer in the bgp_delete_connected_nexthop() function. To fix this, move the call to bgp_unlock() to the end of peer_free(). --- bgpd/bgpd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 56e4322b9..69ab7da63 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -736,8 +736,6 @@ peer_free (struct peer *peer) { assert (peer->status == Deleted); - bgp_unlock(peer->bgp); - /* this /ought/ to have been done already through bgp_stop earlier, * but just to be sure.. */ @@ -782,6 +780,9 @@ peer_free (struct peer *peer) XFREE(MTYPE_TMP, peer->notify.data); bgp_sync_delete (peer); + + bgp_unlock(peer->bgp); + memset (peer, 0, sizeof (struct peer)); XFREE (MTYPE_BGP_PEER, peer); From 574e5007d5155ee261a4da39fc18502f76e40a30 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 17 May 2016 13:33:11 +0100 Subject: [PATCH 1245/1342] bgpd: Add route count from neighbours & established sessions to bgp summary * bgp_vty.c: (bgp_show_summary) The sum of the routes received from each neighbour can be interesting/useful. Add a line with this to end of 'show ... bgp ... summary'. Also, add a count of the number of established sessions. Note, the route count is also available from 'show bgp statistics', along with more. --- bgpd/bgp_vty.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 8eeaff922..9f09016a9 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7480,6 +7480,8 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) struct peer *peer; struct listnode *node, *nnode; unsigned int count = 0; + unsigned int totrcount = 0; + unsigned int totecount = 0; char timebuf[BGP_UPTIME_LEN]; int len; @@ -7561,6 +7563,8 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) if (peer->status == Established) { vty_out (vty, " %8ld", peer->pcount[afi][safi]); + totrcount += peer->pcount[afi][safi]; + totecount++; } else { @@ -7577,8 +7581,14 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) } if (count) - vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE, - count, VTY_NEWLINE); + { + vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE, + count, VTY_NEWLINE); + vty_out (vty, "%sTotal num. Established sessions %d%s", VTY_NEWLINE, + totecount, VTY_NEWLINE); + vty_out (vty, "Total num. of routes received %d%s", + totrcount, VTY_NEWLINE); + } else vty_out (vty, "No %s neighbor is configured%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); From 0c175f82a812c6e86eeb2c11b7f3f96bf46459fa Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 21 Dec 2015 12:57:31 +0000 Subject: [PATCH 1246/1342] ospfd: 'ip ospf network' interface should down iface before changing type * ospf_vty.c: (ip_ospf_network) This function changes the interface type and only then downs/ups the interface if already up. So the down happens with the interface type already altered. However, the interface type can have major ramifications for how underlying state is stored/indexed, which may cause problems. Further, bit of an encapsulation violation to twiddle state here. (no_ip_ospf_network) ditto. * ospf_interface.c: (ospf_if_reset_type) New function to reset the OSPF interface type on an interface. Ensure the interface is downed before the type is changed. * ospf_interface.h: (ospf_if_reset_type) Export, for ospf_vty.c --- ospfd/ospf_interface.c | 23 +++++++++++++++++++++++ ospfd/ospf_interface.h | 1 + ospfd/ospf_vty.c | 40 ++++------------------------------------ 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 8755c0888..a46ca6d46 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -144,6 +144,29 @@ ospf_if_reset_variables (struct ospf_interface *oi) oi->v_ls_ack = 1; } +void +ospf_if_reset_type (struct interface *ifp, u_char type) +{ + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + u_char orig_ism_state; + + if (!oi) + continue; + + orig_ism_state = oi->state; + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + + oi->type = IF_DEF_PARAMS (ifp)->type; + + if (orig_ism_state > ISM_Down) + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); + } +} + /* lookup oi for specified prefix/ifp */ struct ospf_interface * ospf_if_table_lookup (struct interface *ifp, struct prefix *prefix) diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 69b9b4069..707035378 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -276,6 +276,7 @@ extern void ospf_if_init (void); extern void ospf_if_stream_set (struct ospf_interface *); extern void ospf_if_stream_unset (struct ospf_interface *); extern void ospf_if_reset_variables (struct ospf_interface *); +extern void ospf_if_reset_type (struct interface *, u_char type); extern int ospf_if_is_enable (struct ospf_interface *); extern int ospf_if_get_output_cost (struct ospf_interface *); extern void ospf_if_recalculate_output_cost (struct interface *); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index f31355ee8..478d4ffd9 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -5418,7 +5418,6 @@ DEFUN (ip_ospf_network, { struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; - struct route_node *rn; if (old_type == OSPF_IFTYPE_LOOPBACK) { @@ -5439,23 +5438,7 @@ DEFUN (ip_ospf_network, return CMD_SUCCESS; SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); - - for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) - { - struct ospf_interface *oi = rn->info; - - if (!oi) - continue; - - oi->type = IF_DEF_PARAMS (ifp)->type; - - if (oi->state > ISM_Down) - { - OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); - OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); - } - } - + ospf_if_reset_type (ifp, IF_DEF_PARAMS (ifp)->type); return CMD_SUCCESS; } @@ -5479,29 +5462,14 @@ DEFUN (no_ip_ospf_network, { struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; - struct route_node *rn; IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp); if (IF_DEF_PARAMS (ifp)->type == old_type) return CMD_SUCCESS; - - for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) - { - struct ospf_interface *oi = rn->info; - - if (!oi) - continue; - - oi->type = IF_DEF_PARAMS (ifp)->type; - - if (oi->state > ISM_Down) - { - OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); - OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); - } - } - + + ospf_if_reset_type (ifp, IF_DEF_PARAMS (ifp)->type); + return CMD_SUCCESS; } From 867946bb8802c02049bf68a4e97843d777cbcb68 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 21 Dec 2015 13:39:33 +0000 Subject: [PATCH 1247/1342] lib: vty_prefix_list_install should validate afi/safi * lib/plist.c: (vty_prefix_list_install) Check afi/safi is supported and warn if not, as a safeguard and to ensure the user is warned, if somehow that code is ever called for non-IP AFI. --- lib/plist.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/plist.c b/lib/plist.c index 2176c035a..644506b01 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -675,7 +675,16 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, int seqnum = -1; int lenum = 0; int genum = 0; - + + /* This code only works for IP. Provide a safe-guard and user-visible + * warning + */ + if (!(afi == AFI_IP || afi == AFI_IP6)) + { + vty_out (vty, "%% prefix must be IPv4 or IPv6!%s", VTY_NEWLINE); + return CMD_WARNING; + } + /* Sequential number. */ if (seq) seqnum = atoi (seq); From 40fc3dda2b7a345e447d2ef355108c987e59ed13 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 11 Oct 2016 16:00:27 +0100 Subject: [PATCH 1248/1342] build: Add GCC stack-protector/SSP to default flag set * configure.ac: Add GCC SSP / -fstack-protector-strong to default flag set, when available, as part of defence in depth. At least some distros already use SSP by default and it can detect buffer overflows above a certain size. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index deb48ebc0..1331deeb7 100755 --- a/configure.ac +++ b/configure.ac @@ -150,6 +150,7 @@ if test "x${cflags_specified}" = "x" ; then AC_C_FLAG([-Os], [ AC_C_FLAG([-O2]) ]) + AC_C_FLAG([-fstack-protector-strong]) AC_C_FLAG([-fpie]) AC_C_FLAG([-fno-omit-frame-pointer]) AC_C_FLAG([-Wall]) From 5bc62ca9561fa01a989e386cbf6e71cbdef77a3c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 11 Jul 2016 16:21:23 +0100 Subject: [PATCH 1249/1342] isisd,ospf6d,bgpd: Fix GCC 6 warnings on indentation not matching control flow GCC 6 can now give warnings when the indentation of code does not align with the scope of prior control flow statement(s). I.e., where the code visually suggests one kind of control flow, but in actuality follows another. Fix warnings found. They all seem to be simple cases of the indentation being deceptive, but the existing flow being correct. --- bgpd/bgp_route.c | 16 ++++++++-------- bgpd/bgpd.c | 22 +++++++++++----------- isisd/topology/spgrid.c | 7 ++++--- ospf6d/ospf6_interface.c | 2 +- ospfd/ospf_abr.c | 12 ++++++------ 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 527d5d987..476ef0596 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -16221,14 +16221,14 @@ bgp_config_write_distance (struct vty *vty, struct bgp *bgp, bgp->ipv6_distance_ebgp, bgp->ipv6_distance_ibgp, bgp->ipv6_distance_local, VTY_NEWLINE); - for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) - if ((bdistance = rn->info) != NULL) - { - vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, - inet6_ntoa (rn->p.u.prefix6), rn->p.prefixlen, - bdistance->access_list ? bdistance->access_list : "", - VTY_NEWLINE); - } + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, + inet6_ntoa (rn->p.u.prefix6), rn->p.prefixlen, + bdistance->access_list ? bdistance->access_list : "", + VTY_NEWLINE); + } } #endif /* HAVE_IPV6 */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 69ab7da63..6189411ee 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3916,19 +3916,19 @@ peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; - group = peer->group; - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) - { - filter = &peer->filter[afi][safi]; + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + filter = &peer->filter[afi][safi]; - if (! peer->af_group[afi][safi]) - continue; + if (! peer->af_group[afi][safi]) + continue; - if (filter->dlist[direct].name) - free (filter->dlist[direct].name); - filter->dlist[direct].name = NULL; - filter->dlist[direct].alist = NULL; - } + if (filter->dlist[direct].name) + free (filter->dlist[direct].name); + filter->dlist[direct].name = NULL; + filter->dlist[direct].alist = NULL; + } return 0; } diff --git a/isisd/topology/spgrid.c b/isisd/topology/spgrid.c index 22cfa7ba4..e1c87abf2 100644 --- a/isisd/topology/spgrid.c +++ b/isisd/topology/spgrid.c @@ -598,7 +598,7 @@ gen_spgrid_topology (struct vty *vty, struct list *topology) init_rand ( seed1); pl = pl - pm + 1; - for ( x = 0; x < X; x ++ ) + for ( x = 0; x < X; x ++ ) { for ( y = 0; y < Y; y ++ ) { p_t = pm + nrand ( pl ); if ( pn_f ) p_t *= (long) ( (1 + x) * pn ); @@ -606,9 +606,10 @@ gen_spgrid_topology (struct vty *vty, struct list *topology) p[ NODE ( x, y ) ] = p_t; } - p[n0] = 0; - if ( s_f ) p[n0-1] = 0; } + p[n0] = 0; + if ( s_f ) p[n0-1] = 0; + } if ( s_f ) /* additional arcs from artifical source */ { diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 14a93c85b..fa6509f40 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -681,7 +681,7 @@ interface_up (struct thread *thread) if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s has no link local address, can't execute [InterfaceUp]", oi->interface->name); - return 0; + return 0; } /* Recompute cost */ diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index e172e53cd..95c2d4689 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -701,7 +701,7 @@ ospf_abr_translate_nssa (struct ospf_area *area, struct ospf_lsa *lsa) zlog_debug ("ospf_abr_translate_nssa(): Could not translate " "Type-7 for %s to Type-5", inet_ntoa (lsa->data->id)); - return 1; + return 1; } } @@ -948,11 +948,11 @@ ospf_abr_announce_network (struct ospf *ospf, zlog_debug ("ospf_abr_announce_network(): " "this is intra-area route to %s/%d", inet_ntoa (p->prefix), p->prefixlen); - if ((range = ospf_area_range_match (or_area, p)) - && !ospf_area_is_transit (area)) - ospf_abr_update_aggregate (range, or, area); - else - ospf_abr_announce_network_to_area (p, or->cost, area); + if ((range = ospf_area_range_match (or_area, p)) + && !ospf_area_is_transit (area)) + ospf_abr_update_aggregate (range, or, area); + else + ospf_abr_announce_network_to_area (p, or->cost, area); } } } From b174a58467d155b8609f1b5a1f6e27f22afdb81c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 23 Jan 2017 10:55:26 +0000 Subject: [PATCH 1250/1342] ripd: Fix GCC6 warning on misleading indentation --- ripd/ripd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index 848d801e2..4ce5cc362 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2300,7 +2300,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIP %s/%d is filtered by route-map out", inet_ntoa (p->prefix), p->prefixlen); - continue; + continue; } } From 5931124b6c78ec211e3171606fc2ad2dd448b12a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 8 Jul 2016 11:24:09 +0100 Subject: [PATCH 1251/1342] tools: Remove historic scripts --- Makefile.am | 1 - tools/rrcheck.pl | 135 ---------------------------------------------- tools/rrlookup.pl | 123 ------------------------------------------ tools/zc.pl | 111 -------------------------------------- 4 files changed, 370 deletions(-) delete mode 100644 tools/rrcheck.pl delete mode 100644 tools/rrlookup.pl delete mode 100755 tools/zc.pl diff --git a/Makefile.am b/Makefile.am index 3dea48989..b485bc877 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,7 +11,6 @@ DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d nhrpd \ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ - tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ tools/zebra.el tools/multiple-bgpd.sh if HAVE_LATEX diff --git a/tools/rrcheck.pl b/tools/rrcheck.pl deleted file mode 100644 index 279bca841..000000000 --- a/tools/rrcheck.pl +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env perl -## -## Read BGPd logfile and lookup RR's whois database. -## -## Copyright (c) 1997 Kunihiro Ishiguro -## -use Socket; - -## Configuration variables -$whois_host = "whois.jpix.ad.jp"; - -#$logfile = "/usr/local/sbin/logfile" -$logfile = shift || die "Please specify filename"; - -## mail routine -{ - local ($prefix, $origin); - - open (LOG, $logfile) || die "can't open $logfile"; - - $index = ''; - while ($index) { - $index = ; - if ($index =~ /[bgpd]/) { - break; - } - } - - while () { - if (/([\d\.\/]+)\s+([\d\.]+)\s+(\d+)\s+(\d+)\s+([\d ]+)\s+[ie\?]/) { - $prefix = $1; - $nexthop = $2; - $med = $3; - $dummy = $4; - $aspath = $5; - ($origin) = ($aspath =~ /([\d]+)$/); - - print "$nexthop [$origin] $prefix $aspath "; - - $ret = &whois_check ($prefix, $origin); - if ($ret == 0) { - print "Check OK\n"; - } elsif ($ret == 1){ - print "AS orgin mismatch\n"; - } else { - print "prefix doesn't exist \n"; - } - } - } -} - -sub whois_check -{ - local ($prefix, $origin) = @_; - local ($rr_prefix, $rr_origin) = (); - local (@result); - - $origin = "AS" . $origin; - - @result = &whois ($prefix); - - $prefix_match = 0; - foreach (@result) { - if (/^route:.*\s([\d\.\/]+)$/) { - $rr_prefix = $1; - } - if (/^origin:.*\s(AS[\d]+)$/) { - $rr_origin = $1; - - if ($prefix eq $rr_prefix and $origin eq $rr_origin) { - return 0; - } elsif ($prefix eq $rr_prefix) { - $prefix_match = 1; - } - } - } -# alarm_mail ($prefix, $origin, @result); - if ($prefix_match) { - return 1; - } else { - return 2; - } -} - -## get port of whois -sub get_whois_port -{ - local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); - return ($port, $proto); -} - -## whois lookup -sub whois -{ - local ($query) = @_; - local ($port, $proto) = &get_whois_port; - local (@result); - - if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { - $address = pack ("C4",split(/\./,$host)); - } else { - $address = (gethostbyname ($whois_host))[4]; - } - - socket (SOCKET, PF_INET, SOCK_STREAM, $proto); - - if (connect (SOCKET, sockaddr_in ($port, $address))) { - local ($oldhandle) = select (SOCKET); - $| = 1; - select($oldhandle); - - print SOCKET "$query\r\n"; - - @result = ; - return @result; - } -} - -## -sub alarm_mail -{ - local ($prefix, $origin, @result) = @_; - - open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; - - print MAIL "From: root\@rr1.jpix.ad.jp\n"; - print MAIL "Subject: RR $origin $prefix\n"; - print MAIL "MIME-Version: 1.0\n"; - print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; - print MAIL "RR Lookup Error Report\n"; - print MAIL "======================\n"; - print MAIL "Announced route : $prefix from $origin\n\n"; - print MAIL "@result"; - close MAIL; -} diff --git a/tools/rrlookup.pl b/tools/rrlookup.pl deleted file mode 100644 index 84410e81e..000000000 --- a/tools/rrlookup.pl +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env perl -## -## Read BGPd logfile and lookup RR's whois database. -## -## Copyright (c) 1997 Kunihiro Ishiguro -## -use Socket; - -## Configuration variables -$whois_host = "whois.jpix.ad.jp"; - -#$mail_address = "toshio\@iri.co.jp"; -$mail_address = "kunihiro\@zebra.org"; -$mailer = "/usr/sbin/sendmail -oi"; - -#$logfile = "/usr/local/sbin/logfile" -$logfile = "logfile"; -$lookuplog = "lookuplog"; - -## mail routine -{ - local ($prefix, $origin); - - open (LOG, $logfile) || die "can't open $logfile"; - open (LOOKUP, ">$lookuplog") || die "can't open $lookuplog"; - - for (;;) { - while () { - if (/Update\S+ ([\d\.\/]+) .* (\d+) [ie\?]/) { - $prefix = $1; - $origin = $2; - $ret = &whois_check ($prefix, $origin); - if ($ret) { - print LOOKUP "$prefix AS$origin : Check OK\n"; - } else { - print LOOKUP "$prefix AS$origin : Error\n"; - } -# fflush (LOOKUP); - } - } - sleep (3); - } -} - -sub whois_check -{ - local ($prefix, $origin) = @_; - local ($rr_prefix, $rr_origin) = (); - local (@result); - - $origin = "AS" . $origin; - -# print "$prefix $origin\n"; - - @result = &whois ($prefix); - - foreach (@result) { - if (/^route:.*\s([\d\.\/]+)$/) { - $rr_prefix = $1; - } - if (/^origin:.*\s(AS[\d]+)$/) { - $rr_origin = $1; - - if ($prefix eq $rr_prefix and $origin eq $rr_origin) { - return 1; - } - } - } - alarm_mail ($prefix, $origin, @result); - return 0; -} - -## get port of whois -sub get_whois_port -{ - local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); - return ($port, $proto); -} - -## whois lookup -sub whois -{ - local ($query) = @_; - local ($port, $proto) = &get_whois_port; - local (@result); - - if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { - $address = pack ("C4",split(/\./,$host)); - } else { - $address = (gethostbyname ($whois_host))[4]; - } - - socket (SOCKET, PF_INET, SOCK_STREAM, $proto); - - if (connect (SOCKET, sockaddr_in ($port, $address))) { - local ($oldhandle) = select (SOCKET); - $| = 1; - select($oldhandle); - - print SOCKET "$query\r\n"; - - @result = ; - return @result; - } -} - -## -sub alarm_mail -{ - local ($prefix, $origin, @result) = @_; - - open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; - - print MAIL "From: root\@rr1.jpix.ad.jp\n"; - print MAIL "Subject: RR $origin $prefix\n"; - print MAIL "MIME-Version: 1.0\n"; - print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; - print MAIL "RR Lookup Error Report\n"; - print MAIL "======================\n"; - print MAIL "Announced route : $prefix from $origin\n\n"; - print MAIL "@result"; - close MAIL; -} diff --git a/tools/zc.pl b/tools/zc.pl deleted file mode 100755 index 5307fa387..000000000 --- a/tools/zc.pl +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env perl -## -## Zebra interactive console -## Copyright (C) 2000 Vladimir B. Grebenschikov -## -## This file is part of GNU Zebra. -## -## GNU Zebra 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. -## -## GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the -## Free Software Foundation, Inc., 59 Temple Place - Suite 330, -## Boston, MA 02111-1307, USA. - -use Net::Telnet (); -use Getopt::Std; - -#use strict; - -my $host = `hostname -s`; $host =~ s/\s//g; -my $port = 'zebra'; -my $server = 'localhost'; - -# Check arguments -&getopts ('l:e:czborh'); - -&usage () if $opt_h; - -# main -{ - my $login_pass = $opt_l || $ENV{ZEBRA_PASSWORD} || 'zebra'; - my $enable_pass = $opt_e || $ENV{ZEBRA_ENABLE} || ''; - - my $port = ($opt_z ? 'zebra' : 0) || - ($opt_b ? 'bgpd' : 0) || - ($opt_o ? 'ospfd' : 0) || - ($opt_r ? 'ripd' : 0) || 'zebra'; - - my $cmd = join (' ', @ARGV); - - my $t = new Net::Telnet (Timeout => 10, - Prompt => '/[\>\#] $/', - Port => $port); - - $t->open ($server); - - $t->cmd ($login_pass); - if ($enable_pass) { - $t->cmd (String => 'en', - Prompt => '/Password: /'); - $t->cmd ($enable_pass); - } - $t->cmd ('conf t') if "$opt_c"; - - if ($cmd) - { - docmd ($t, $cmd); - exit (0); - } - - my $prompt = sprintf ("%s%s# ", $host, - ($port eq 'zebra') ? '' : "/$port"); - - print "\nZEBRA interactive console ($port)\n\n" if -t STDIN; - - while (1) - { - $| = 1; - print $prompt if -t STDIN; - chomp ($cmd = <>); - if (!defined ($cmd)) - { - print "\n" if -t STDIN; - exit(0); - } - exit (0) if ($cmd eq 'q' || $cmd eq 'quit'); - - docmd ($t, $cmd) if $cmd !~ /^\s*$/; - } - - exit(0); -} - -sub docmd -{ - my ($t, $cmd) = @_; - my @lines = $t->cmd ($cmd); - print join ('', grep (!/[\>\#] $/, @lines)), "\n"; -} - -sub usage -{ - print "USAGE: $0 [-l LOGIN_PASSWORD] [-e ENABLE_PASSWORD] [-z|-b|-o|-r|-h] []\n", - "\t-l - specify login password\n", - "\t-e - specify enable password\n", - "\t-c - execute command in configure mode\n", - "\t-z - connect to zebra daemon\n", - "\t-b - connect to bgpd daemon\n", - "\t-o - connect to ospfd daemon\n", - "\t-r - connect to ripd daemon\n", - "\t-h - help\n"; - exit (1); -} From a6efbab768b94a398adb52f0e2b3fe064cfe2f59 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 1 Dec 2015 16:09:08 +0000 Subject: [PATCH 1252/1342] tools/multiple-bgpd: extend the ring, enable mpath, add links to +-2 instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * multiple-bgpd.sh: Configure mpath to test it. Add links to the ±2 instances in the ring to get a bit more multi-pathing (otherwise, only mpath to the furthest neighbour IF there's an even number of instances). --- tools/multiple-bgpd.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/multiple-bgpd.sh b/tools/multiple-bgpd.sh index 20a92a916..f6edae922 100644 --- a/tools/multiple-bgpd.sh +++ b/tools/multiple-bgpd.sh @@ -2,7 +2,7 @@ # Public domain, not copyrighted.. -NUM=5 +NUM=8 VTYBASE=2610 ASBASE=64560 BGPD=/path/to/bgpd @@ -21,10 +21,16 @@ for H in `seq 1 ${NUM}` ; do # This sets up a ring of bgpd peerings NEXT=$(( ($H % ${NUM}) + 1 )) PREV=$(( (($H + $NUM - 2) % ${NUM}) + 1 )) + NEXT2=$(( (($H+1) % ${NUM}) + 1 )) + PREV2=$(( (($H + $NUM - 3) % ${NUM}) + 1 )) NEXTADDR="${PREFIX}${NEXT}" NEXTAS=$((${ASBASE} + $NEXT)) PREVADDR="${PREFIX}${PREV}" PREVAS=$((${ASBASE} + $PREV)) + NEXT2ADDR="${PREFIX}${NEXT2}" + NEXT2AS=$((${ASBASE} + $NEXT2)) + PREV2ADDR="${PREFIX}${PREV2}" + PREV2AS=$((${ASBASE} + $PREV2)) ASN=$((64560+${H})) # Edit config to suit. @@ -34,9 +40,12 @@ for H in `seq 1 ${NUM}` ; do ! router bgp ${ASN} bgp router-id ${ADDR} + maximum-paths 32 + bgp bestpath as-path multipath-relax network 10.${H}.1.0/24 pathlimit 1 network 10.${H}.2.0/24 pathlimit 2 network 10.${H}.3.0/24 pathlimit 3 + network 10.${H}.0.0/24 neighbor default peer-group neighbor default update-source ${ADDR} neighbor default capability orf prefix-list both @@ -46,6 +55,10 @@ for H in `seq 1 ${NUM}` ; do neighbor ${NEXTADDR} peer-group default neighbor ${PREVADDR} remote-as ${PREVAS} neighbor ${PREVADDR} peer-group default + neighbor ${NEXT2ADDR} remote-as ${NEXT2AS} + neighbor ${NEXT2ADDR} peer-group default + neighbor ${PREV2ADDR} remote-as ${PREV2AS} + neighbor ${PREV2ADDR} peer-group default ! address-family ipv6 network 3ffe:${H}::/48 @@ -58,6 +71,8 @@ for H in `seq 1 ${NUM}` ; do neighbor default route-map test out neighbor ${NEXTADDR} peer-group default neighbor ${PREVADDR} peer-group default + neighbor ${NEXT2ADDR} peer-group default + neighbor ${PREV2ADDR} peer-group default exit-address-family ! ! bgpd still has problems with extcommunity rt/soo @@ -65,7 +80,9 @@ for H in `seq 1 ${NUM}` ; do set extcommunity rt ${ASN}:1 set extcommunity soo ${ASN}:2 set community ${ASN}:1 + ! line vty + exec-timeout 0 0 ! end EOF From 366bb4ab851137e669a2e7db7a45d73b39090249 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 17 May 2016 13:59:55 +0100 Subject: [PATCH 1253/1342] tools: Extend multiple-bgpd.sh to support BIRD, ExaBGP plus more configurables * tools/multiple-bgpd.sh: Extend this script to support having multiple different implementations in the ring. Add config generator and launch functions for BIRD and ExaBGP. Allow the proportion of other instances in the ring to peer with to be configurable as %age via PEERPROP. Allow number of v4 routes to advertise to be configurable via ADV. Allow "external", non-ring BGP peers to be defined via the EXPEER* arrays. --- tools/multiple-bgpd.sh | 525 ++++++++++++++++++++++++++++++++++------- 1 file changed, 441 insertions(+), 84 deletions(-) diff --git a/tools/multiple-bgpd.sh b/tools/multiple-bgpd.sh index f6edae922..c5668e19b 100644 --- a/tools/multiple-bgpd.sh +++ b/tools/multiple-bgpd.sh @@ -2,100 +2,457 @@ # Public domain, not copyrighted.. -NUM=8 +set -u + +# number of bgpd instances, not more than 255 at this point. At least 3 are +# needed to connect in a ring. +NUM=7 + +# The NUM peers can be connected in a ring topology. +# +# This sets the proportion of other peers that each peer should be +# configured to connect to E.g., 20 means each BGP instance will peer with +# 20% of the other peers before and after it in the ring. So 10% of the +# peers prior to this instance in the ring, and 10% of the following peers. +# 100 should lead to a full-mesh, for an odd total number of peers. +# +# A value of 1 will result in each instance having at least 2 peers in the ring. +# +# A value of 0 will disable creating a ring, in which case the only peers +# configured will be those in the EXPEERS list. +PEERPROP=100 + +# number of routes each BGP instance should advertise +ADV=10 +# First octet to use for the IPv4 advertisements. The advertisements +# will be /32s under this /8. E.g. ADVPREF=10 will mean +# 10.x.y.z/32's are advertised. +ADVPREF=10 + +# Base VTY port to allocate Quagga telnet vtys from. VTYBASE+ID will be +# the port. VTYBASE=2610 -ASBASE=64560 -BGPD=/path/to/bgpd +# Base ASN to allocate ASNs to instances. +ASBASE=64500 PREFIX=192.168.145. #PREFIX=3ffe:123:456:: ADDRPLEN=32 CONFBASE=/tmp PIDBASE=/var/run/quagga -CHOWNSTR=quagga:quagga - -for H in `seq 1 ${NUM}` ; do - CONF="${CONFBASE}"/bgpd${H}.conf - ADDR=${PREFIX}${H} - - if [ ! -e "$CONF" ] ; then - # This sets up a ring of bgpd peerings - NEXT=$(( ($H % ${NUM}) + 1 )) - PREV=$(( (($H + $NUM - 2) % ${NUM}) + 1 )) - NEXT2=$(( (($H+1) % ${NUM}) + 1 )) - PREV2=$(( (($H + $NUM - 3) % ${NUM}) + 1 )) - NEXTADDR="${PREFIX}${NEXT}" - NEXTAS=$((${ASBASE} + $NEXT)) - PREVADDR="${PREFIX}${PREV}" - PREVAS=$((${ASBASE} + $PREV)) - NEXT2ADDR="${PREFIX}${NEXT2}" - NEXT2AS=$((${ASBASE} + $NEXT2)) - PREV2ADDR="${PREFIX}${PREV2}" - PREV2AS=$((${ASBASE} + $PREV2)) - ASN=$((64560+${H})) +USER=quagga +GROUP=quagga + +# MRAI to specify, where an implementation supports it. +MRAI=1 +# Connect retry timer +CONNECTRETRY=1 + +# The binary locations for BGP instances. +declare -A BGP_BINS=( + [quagga]=/usr/sbin/bgpd + [bird]=/usr/sbin/bird + [birdgit]=/home/paul/code/bird/bird + [quaggagit]=/home/paul/code/quagga/bgpd/bgpd + [exabgp]=/home/paul/code/exabgp/sbin/exabgp +) + +# Configuration generation functions for the BGP instances. +declare -A BGP_CONFIGGEN=( + [quagga]=quagga_config + [quaggagit]=quagga_config + [bird]=bird_config + [birdgit]=bird_config + [exabgp]=exabgp_config +) + +# Launch functions for the BGP instances. +declare -A BGP_LAUNCH=( + [quagga]=quagga_launch + [quaggagit]=quagga_launch + [bird]=bird_launch + [birdgit]=bird_launch + [quaggagit]=quagga_launch + [exabgp]=exabgp_launch +) + +# the instances to run, in the order they should appear in the ring +# (repeated over until there are $NUM instances). The value must exist as a +# key into the above two arrays. +declare -a BGP_INSTANCES=( + quagga + bird + quaggagit + exabgp +) + +# Peers to configure, that are external to this script. One list of IPs, with +# corresponding list of their ASes. +# +# e.g.: +#EXPEERS=(192.168.147.{1..10}) +#EXPEERASES=($(seq $((ASBASE+11)) $(($ASBASE+20)))) + +EXPEERS=() +EXPEERASES=() + +############################################################################ +# Can override any of the above from a supplied file with declarations +CONFWRITE=Y +if [ $# -gt 0 ] ; then + echo "multiple-bgpd.sh: sourcing config from $1" + [ -f "$1" ] && . "$1" + + # keep config, if exists + [ $# -gt 1 ] && [ "$2" = "k" ] && CONFWRITE=N +fi + +############################################################################ +# Internal variables. + +# Number of peers for each instance to peer with +PEERNUM=$(( ($NUM-1) * $PEERPROP / 100 )) +[ "$PEERNUM" -gt $(($NUM-1)) ] && PEERNUM=$(($NUM-1)) + +# the 'range', i.e. how many of the previous and next peers in the ring to +# connect to +PEERRANGE=$(( $PEERNUM/2 )) +[ "$PEERPROP" -gt 0 -a "$NUM" -ge 3 -a "$PEERRANGE" -le 0 ] && PEERRANGE=1 + +# and a convenience expansion +PEEREXP="" +if [ "$PEERRANGE" -gt 0 ]; then + PEEREXP=($(seq -${PEERRANGE} ${PEERRANGE})) + # dont need 0 + unset PEEREXP[PEERRANGE] +fi + +#echo ${PEEREXP[@]} + +############################################################################ +## helpers + +# translate instance ID to its address. +id2addr () { + local ID=$1 + echo ${PREFIX}${ID} +} + +# return the ID of a peer, in terms of an offset on the given instance's ID. +# +# E.g., given an ID of 1 and an offset of -1, if there are 10 instances overall, +# this will return 10. +peeridoff () { + local ID=$1 + local OFF=$2 + echo $(( (($ID + $OFF - 1 + $NUM) % $NUM) + 1 )) +} + +# return IPv4 address to advertise, for given instance ID and number. +advipaddr () { + local ID=$1 + local N=$2 + echo "$ADVPREF.$(( ($N >> 16) %256 )).$(( ($N >> 8) % 256 )).$(( $N % 256 ))" +} + +############################################################################ +# launch functions +# +# do not daemonise, so that all launched instances can be killed by killing +# the script. +# + +quagga_launch () { + local ID=$1 + local ASN=$2 + local ADDR=$3 + local BIN=$4 + local CONF=$5 + ${BIN} -i "${PIDBASE}"/bgpd${ID}.pid \ + -l ${ADDR} \ + -f "${CONF}" \ + -u $USER -g $GROUP \ + -P $((${VTYBASE}+${ID})) +} + +exabgp_launch () { + local ID=$1 + local ASN=$2 + local ADDR=$3 + local BIN=$4 + local CONF=$5 + + env exabgp.api.file="${PIDBASE}"/exabgp${ID}.ctl \ + exabgp.daemon.pid="${PIDBASE}"/bgpd${ID}.pid \ + exabgp.daemon.daemonize=false \ + exabgp.tcp.bind=${ADDR} \ + exabgp.log.enable=false \ + exabgp.daemon.user=quagga \ + ${BIN} ${CONF} +} + +bird_launch () { + local ID=$1 + local ASN=$2 + local ADDR=$3 + local BIN=$4 + local CONF=$5 + ${BIN} -P "${PIDBASE}"/bird${ID}.pid \ + -c "${CONF}" \ + -s "${PIDBASE}"/bird${ID}.ctl \ + -f +} + +####################################################################### +# +# functions to write the configuration for instances +# + +exabgp_config () { + local ID=$1 + local ASN=$2 + local ADDR=$3 + + local N + local P + + cat <<- EOF + group default { + local-address $ADDR; + local-as $ASN; + router-id $ADDR; + + capability { + asn4 enable; + } + EOF + + for N in $(seq 1 $ADV) ; do + echo " static {" + echo " route `advipaddr $ID $N`/32 {" + echo " next-hop $ADDR;" + echo " }" + echo " }" + done + + for P in ${PEEREXP[@]}; do + [ "$P" -eq 0 ] && continue; + + #local PID=$(( (($ID + $P - 1 + $NUM) % $NUM) + 1 )) + local PID=`peeridoff $ID $P` + #local PADDR="${PREFIX}${PID}" + local PADDR=`id2addr $PID` + local PAS=$((${ASBASE} + $PID)) - # Edit config to suit. - cat > "$CONF" <<- EOF - password whatever - service advanced-vty - ! - router bgp ${ASN} - bgp router-id ${ADDR} - maximum-paths 32 - bgp bestpath as-path multipath-relax - network 10.${H}.1.0/24 pathlimit 1 - network 10.${H}.2.0/24 pathlimit 2 - network 10.${H}.3.0/24 pathlimit 3 - network 10.${H}.0.0/24 - neighbor default peer-group - neighbor default update-source ${ADDR} - neighbor default capability orf prefix-list both - neighbor default soft-reconfiguration inbound - neighbor default route-map test out - neighbor ${NEXTADDR} remote-as ${NEXTAS} - neighbor ${NEXTADDR} peer-group default - neighbor ${PREVADDR} remote-as ${PREVAS} - neighbor ${PREVADDR} peer-group default - neighbor ${NEXT2ADDR} remote-as ${NEXT2AS} - neighbor ${NEXT2ADDR} peer-group default - neighbor ${PREV2ADDR} remote-as ${PREV2AS} - neighbor ${PREV2ADDR} peer-group default - ! - address-family ipv6 - network 3ffe:${H}::/48 - network 3ffe:${H}:1::/48 pathlimit 1 - network 3ffe:${H}:2::/48 pathlimit 3 - network 3ffe:${H}:3::/48 pathlimit 3 - neighbor default activate - neighbor default capability orf prefix-list both - neighbor default default-originate - neighbor default route-map test out - neighbor ${NEXTADDR} peer-group default - neighbor ${PREVADDR} peer-group default - neighbor ${NEXT2ADDR} peer-group default - neighbor ${PREV2ADDR} peer-group default - exit-address-family - ! - ! bgpd still has problems with extcommunity rt/soo - route-map test permit 10 - set extcommunity rt ${ASN}:1 - set extcommunity soo ${ASN}:2 - set community ${ASN}:1 - ! - line vty - exec-timeout 0 0 - ! - end - EOF - chown ${CHOWNSTR} "$CONF" + echo " neighbor $PADDR {" + #echo " local-address $ADDR;" + #echo " local-as $ASN;" + #echo " graceful-restart;" + #echo " router-id $ADDR;" + echo " peer-as $PAS;" + echo " }" + done + + for P in ${!EXPEERS[@]}; do + echo " neighbor ${EXPEERS[$P]} {" + echo " peer-as ${EXPEERASES[$P]};" + echo " }" + done + + cat <<- EOF + } + EOF +} + +quagga_config () { + local ID=$1 + local ASN=$2 + local ADDR=$3 + + local N + local P + + # Edit config to suit. + cat <<- EOF + password foo + service advanced-vty + ! + router bgp ${ASN} + bgp router-id ${ADDR} + !maximum-paths 32 + !bgp bestpath as-path multipath-relax + EOF + + for N in $(seq 1 $ADV) ; do + echo " network `advipaddr $ID $N`/32" + done + + cat <<- EOF + neighbor default peer-group + neighbor default update-source ${ADDR} + neighbor default capability orf prefix-list both + !neighbor default soft-reconfiguration inbound + neighbor default advertisement-interval $MRAI + neighbor default timers connect $CONNECTRETRY + neighbor default route-map test out + EOF + + for P in ${PEEREXP[@]}; do + [ "$P" -eq 0 ] && continue; + + local PID=`peeridoff $ID $P` + local PADDR=`id2addr $PID` + local PAS=$((${ASBASE} + $PID)) + echo " neighbor ${PADDR} remote-as ${PAS}" + echo " neighbor ${PADDR} peer-group default" + done + + for P in ${!EXPEERS[@]}; do + echo " neighbor ${EXPEERS[$P]} remote-as ${EXPEERASES[$P]}" + echo " neighbor ${EXPEERS[$P]} peer-group default" + done + + cat <<- EOF + ! + address-family ipv6 + network 3ffe:${ID}::/48 + network 3ffe:${ID}:1::/48 pathlimit 1 + network 3ffe:${ID}:2::/48 pathlimit 3 + network 3ffe:${ID}:3::/48 pathlimit 3 + neighbor default activate + neighbor default capability orf prefix-list both + neighbor default default-originate + neighbor default route-map test out + EOF + + for P in ${PEEREXP[@]}; do + [ "$P" -eq 0 ] && continue; + + local PID=`peeridoff $ID $P` + local PADDR=`id2addr $PID` + local PAS=$((${ASBASE} + $PID)) + echo " neighbor ${PADDR} peer-group default" + done + + cat <<- EOF + exit-address-family + ! + ! bgpd still has problems with extcommunity rt/soo + route-map test permit 10 + set extcommunity rt ${ASN}:1 + set extcommunity soo ${ASN}:2 + set community ${ASN}:1 + ! + line vty + exec-timeout 0 0 + ! + end + EOF +} + +bird_config () { + local ID=$1 + local ASN=$2 + local ADDR=$3 + + cat <<- EOF + #log "/var/log/bird.log" all; + #debug protocols all; + + # Override router ID + router id ${ADDR}; + listen bgp address ${ADDR}; + + protocol kernel { device routes; import all; } + protocol device { import all; } + + function avoid_martians() + prefix set martians; + { + martians = [ + 224.0.0.0/4+, 240.0.0.0/4+ + ]; + + # Avoid RFC1918 and similar networks + if net ~ martians then return false; + return true; + } + + filter import_filter + { + if ! (avoid_martians()) then reject; + accept; + } + + filter set_comm + { + bgp_community.add ((${ASN}, 1)); + accept; + } + + template bgp peer_conf { + local as ${ASN}; + source address ${ADDR}; + import filter import_filter; + export filter set_comm; + multihop; + } + EOF + + local P; + + for P in ${PEEREXP[@]}; do + [ "$P" -eq 0 ] && continue; + + local PID=`peeridoff $ID $P` + local PADDR=`id2addr $PID` + local PAS=$((${ASBASE} + $PID)) + echo "protocol bgp from peer_conf {" + echo " neighbor ${PADDR} as ${PAS};" + echo "}" + done + + for P in ${!EXPEERS[@]}; do + echo "protocol bgp from peer_conf {" + echo " neighbor ${EXPEERS[$P]} as ${EXPEERASES[$P]};" + echo "}" + done + + + for N in $(seq 1 $ADV) ; do + echo " network `advipaddr $ID $N`/32" + done +} + +####################################################################### + +for ID in $(seq 1 $NUM); do + BGP_INST=${BGP_INSTANCES[${ID} % ${#BGP_INSTANCES[@]}]} + BGPBIN=${BGP_BINS[$BGP_INST]} + CONF="${CONFBASE}"/${BGP_INST}_bgpd${ID}.conf + ASN=$(($ASBASE + ${ID})) + ADDR=`id2addr $ID` + + #if [ ! -e "$CONF" ] ; then + if [ ! -e "$CONF" -o "$CONFWRITE" = "Y" ] ; then + ${BGP_CONFIGGEN[$BGP_INST]} $ID $ASN $ADDR > "$CONF" + chown $USER:$GROUP "$CONF" fi # You may want to automatically add configure a local address # on a loop interface. # # Solaris: ifconfig vni${H} plumb ${ADDR}/${ADDRPLEN} up - # Linux: ip address add ${ADDR}/${ADDRPLEN} dev lo 2> /dev/null - ${BGPD} -i "${PIDBASE}"/bgpd${H}.pid \ - -l ${ADDR} \ - -f "${CONF}" \ - -P $((${VTYBASE}+${H})) \ - -d + # Linux: + #ip address add ${ADDR}/${ADDRPLEN} dev lo 2> /dev/null + + ip link add dummy${ID} type dummy 2> /dev/null + ip link set dev dummy${ID} up + ip address add ${ADDR}/${ADDRPLEN} dev dummy${ID} 2> /dev/null + + ${BGP_LAUNCH[$BGP_INST]} $ID $ASN $ADDR $BGPBIN $CONF & + + sleep 0.1 done + +echo "multiple-bgpd.sh: waiting..." + +wait From a2f0db2be27385211f033271d8b83e9caf362236 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 25 Feb 2016 16:41:56 +0000 Subject: [PATCH 1254/1342] lib: track worst case # of cycles and don't allow granularity to go above * The workqueue code at present errs towards optimising the granularity for throughput of queue items in runs. This perhaps is at the cost of risking excessive delays at times. Make the workqueue take worst-cases into account. * thread.c: (thread_should_yield) When thread should yield, we can return the time taken for free, as it might be useful to caller. work_queue_run * workqueue.h: (struct work_queue) Add fields for worst # of cycles, and (independently) worst time taken. * workqueue.c: (work_queue_new) Worst starts high. (work_queue_run) Track the worst number of cycles taken, where a queue run had to yield before clearing out the queue. Use this as an upper-bound on the granularity, so the granulity can never increase. Track the worst-case delay per work-queue, where it had to yield, thanks to the thread_should_yield return value change. Note that "show thread cpu" already shows stats for the work_queue_run function, inc average and worst cases. Deficiencies: - A spurious outside delay (e.g. process not run in ages) could cause 'worst' to be very low in some particular invocation of a process, and it will stay that way for life of process. - The whole thing of trying to calculate suitable granularities is just fragile and impossible to get 100% right. --- lib/thread.c | 4 ++-- lib/workqueue.c | 38 +++++++++++++++++++++++++++----------- lib/workqueue.h | 2 ++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index b65078c68..de4d76d61 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1264,8 +1264,8 @@ int thread_should_yield (struct thread *thread) { quagga_get_relative (NULL); - return (timeval_elapsed(relative_time, thread->real) > - THREAD_YIELD_TIME_SLOT); + unsigned long t = timeval_elapsed(relative_time, thread->real); + return ((t > THREAD_YIELD_TIME_SLOT) ? t : 0); } void diff --git a/lib/workqueue.c b/lib/workqueue.c index b1a5d5bfe..6453e7bb6 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -85,7 +85,8 @@ work_queue_new (struct thread_master *m, const char *queue_name) listnode_add (work_queues, new); new->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY; - + new->cycles.worst = UINT_MAX; + /* Default values, can be overriden by caller */ new->spec.hold = WORK_QUEUE_DEFAULT_HOLD; @@ -184,29 +185,33 @@ DEFUN(show_work_queues, struct work_queue *wq; vty_out (vty, - "%c %8s %5s %8s %21s%s", + "%c %8s %5s %8s %21s %6s %5s%s", ' ', "List","(ms) ","Q. Runs","Cycle Counts ", + " ","Worst", VTY_NEWLINE); vty_out (vty, - "%c %8s %5s %8s %7s %6s %6s %s%s", + "%c %8s %5s %8s %7s %6s %6s %6s %5s %s%s", 'P', "Items", "Hold", "Total", - "Best","Gran.","Avg.", + "Best","Worst","Gran.","Avg.", "Lat.", "Name", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (work_queues, node, wq)) { - vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s", + vty_out (vty,"%c %8u %5u %8lu %7u %6u %6u %6u %5lu %s%s", (CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'), listcount (wq->items), wq->spec.hold, wq->runs, - wq->cycles.best, wq->cycles.granularity, + wq->cycles.best, + MIN(wq->cycles.best, wq->cycles.worst), + wq->cycles.granularity, (wq->runs) ? (unsigned int) (wq->cycles.total / wq->runs) : 0, + wq->worst_usec, wq->name, VTY_NEWLINE); } @@ -249,6 +254,7 @@ work_queue_run (struct thread *thread) { struct work_queue *wq; struct work_queue_item *item; + unsigned long took; wq_item_status ret; unsigned int cycles = 0; struct listnode *node, *nnode; @@ -268,6 +274,8 @@ work_queue_run (struct thread *thread) * * Best: starts low, can only increase * + * Worst: starts at MAX, can only decrease. + * * Granularity: starts at WORK_QUEUE_MIN_GRANULARITY, can be decreased * if we run to end of time slot, can increase otherwise * by a small factor. @@ -342,7 +350,7 @@ work_queue_run (struct thread *thread) /* test if we should yield */ if ( !(cycles % wq->cycles.granularity) - && thread_should_yield (thread)) + && (took = thread_should_yield (thread))) { yielded = 1; goto stats; @@ -353,24 +361,32 @@ work_queue_run (struct thread *thread) #define WQ_HYSTERESIS_FACTOR 4 + if (cycles > wq->cycles.best) + wq->cycles.best = cycles; + + if (took > wq->worst_usec) + wq->worst_usec = took; + /* we yielded, check whether granularity should be reduced */ if (yielded && (cycles < wq->cycles.granularity)) { wq->cycles.granularity = ((cycles > 0) ? cycles : WORK_QUEUE_MIN_GRANULARITY); + if (cycles < wq->cycles.worst) + wq->cycles.worst = cycles; } /* otherwise, should granularity increase? */ else if (cycles >= (wq->cycles.granularity)) { - if (cycles > wq->cycles.best) - wq->cycles.best = cycles; - - /* along with yielded check, provides hysteresis for granularity */ + /* along with yielded check, provides hysteresis for granularity */ if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR * WQ_HYSTERESIS_FACTOR)) wq->cycles.granularity *= WQ_HYSTERESIS_FACTOR; /* quick ramp-up */ else if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR)) wq->cycles.granularity += WQ_HYSTERESIS_FACTOR; + + /* clamp granularity down to the worst yielded cycle count */ + wq->cycles.granularity = MIN(wq->cycles.granularity, wq->cycles.worst); } #undef WQ_HYSTERIS_FACTOR diff --git a/lib/workqueue.h b/lib/workqueue.h index 5ad25893b..aac786058 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -89,9 +89,11 @@ struct work_queue /* remaining fields should be opaque to users */ struct list *items; /* queue item list */ unsigned long runs; /* runs count */ + unsigned long worst_usec; struct { unsigned int best; + unsigned int worst; unsigned int granularity; unsigned long total; } cycles; /* cycle counts */ From 05c9075b09bea9e2328980df7138da5fd8157dc3 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 17 May 2016 13:28:16 +0100 Subject: [PATCH 1255/1342] bgpd: Modernise BGP defaults for MRAI and connect time Quagga uses historic BGP defaults for its minimum route advertisement interval (MRAI) timers, and its ConnectRetry timer. It uses 30s and 5s for the eBGP and iBGP MRAIs, and 120s for the ConnectRetry timer. These values are quite high, and delay convergence and session establishment, and are unlikely to be desirable in modern networks. The MRAI can, without a doubt, be significantly reduced. The optimal MRAI is related to the size of the network, its diameter in terms of BGP propagation latency particularly. Prior research suggests values of 5s to 15s for Internet BGP, as reasonably conservative values. Further, other implementations have long shipped with 1s or even 0s MRAI values. A too low MRAI, e.g. a 0 MRAI, can greatly increase the number of BGP messages a speaker sends, and hence the bandwidth and even CPU it might use. I.e. some MRAI is better than no MRAI, with current BGP, or it is prone to excessive - even extreme - chattiness. The ConnectRetry timer default also should be set much lower. Lowering the MRAI had previously been suggested by: "Lower the default MRAI timer for iBGP peers to 0 Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp " * bgpd/bgpd.h: Set defaults to: - 3s for the eBGP MRAI - 1s for iBGP MRAI (lower, but non-0, would be nice for this) - 5s for the ConnectRetry timer --- bgpd/bgpd.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a4c608dec..0c13156bf 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -754,10 +754,9 @@ struct bgp_nlri #define BGP_INIT_START_TIMER 1 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 -#define BGP_DEFAULT_EBGP_ROUTEADV 30 -#define BGP_DEFAULT_IBGP_ROUTEADV 5 -#define BGP_CLEAR_CONNECT_RETRY 20 -#define BGP_DEFAULT_CONNECT_RETRY 10 +#define BGP_DEFAULT_EBGP_ROUTEADV 3 +#define BGP_DEFAULT_IBGP_ROUTEADV 1 +#define BGP_DEFAULT_CONNECT_RETRY 5 /* BGP default local preference. */ #define BGP_DEFAULT_LOCAL_PREF 100 From 3dda6b3eccb9a2a88d607372c83c04c796e7daac Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 6 Sep 2016 16:57:40 +0100 Subject: [PATCH 1256/1342] bgpd: Rejiggle exported nht function names and consolidate some code * bgp_nht.h: Tweak the API a bit to simplify and make names a bit clearer on function. Remove AFI argument, it's implied in both bgp_infos and peers. (bgp_find_nexthop) this doesn't so much find a bnc, as check the bnc for the given bgp_info is valid. Rename to (bgp_nexthop_check). (bgp_find_or_add_nexthop) This ensures a bnc exists, so call it (bgp_ensure_nexthop). (bgp_unlink_nexthop_by_peer) Remove via peer. * bgp_nht.c: Adjust to above. (bgp_get_nexthop_rn) helper to get the rn. (bgp_find_nexthop) further helper to get the bnc for path or peer. (bgp_unlink_nexthop_check) helper to check whether a bnc should go. (bgp_ensure_nexthop) Use the helpers. * bgp_{route,fsm}.c: s/bgp_find_or_add_nexthop/bgp_ensure_nexthop/ --- bgpd/bgp_fsm.c | 5 +- bgpd/bgp_nht.c | 159 +++++++++++++++++++++++++++++++---------------- bgpd/bgp_nht.h | 31 +++++---- bgpd/bgp_route.c | 14 ++--- 4 files changed, 132 insertions(+), 77 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 67c50c475..9d866554b 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -507,7 +507,7 @@ bgp_stop (struct peer *peer) /* Reset peer synctime */ peer->synctime = 0; } - + /* Stop read and write threads when exists. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); @@ -720,8 +720,7 @@ bgp_start (struct peer *peer) ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; - bgp_find_or_add_nexthop(family2afi(peer->su.sa.sa_family), NULL, peer, - connected); + bgp_ensure_nexthop (NULL, peer, connected); status = bgp_connect (peer); switch (status) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 7808505e9..8c87a6495 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -53,13 +53,21 @@ static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, int keep); int -bgp_find_nexthop (struct bgp_info *path, int connected) +bgp_nexthop_check (struct bgp_info *path, int connected) { struct bgp_nexthop_cache *bnc = path->nexthop; if (!bnc) return 0; + if (BGP_DEBUG(nht, NHT)) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("%s: NHT checking %s", + __FUNCTION__, + bnc_str (bnc, buf, INET6_ADDRSTRLEN)); + } + if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) return 0; @@ -67,6 +75,67 @@ bgp_find_nexthop (struct bgp_info *path, int connected) CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } +/* Helper to get the rn for the appropriate nexthop for path or peer. + * returns the locked rn - caller must bump down the refcnt. + * + * may return NULL in error cases. + */ +static +struct bgp_node * +bgp_get_nexthop_rn (struct bgp_info *path, struct peer *peer) +{ + struct prefix p; + afi_t afi; + + assert (path || peer); + + if (!(path || peer)) + return NULL; + + if (path) + { + afi = family2afi (path->net->p.family); + if (make_prefix(afi, path, &p) < 0) + return NULL; + } + else + { + afi = family2afi(peer->su.sa.sa_family); + if (afi == AFI_IP) + { + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = peer->su.sin.sin_addr; + } + else if (afi == AFI_IP6) + { + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = peer->su.sin6.sin6_addr; + } + else + return NULL; + } + + return bgp_node_get (bgp_nexthop_cache_table[afi], &p); +} + +static +struct bgp_nexthop_cache * +bgp_find_nexthop (struct bgp_info *path, struct peer *peer) +{ + struct bgp_nexthop_cache *bnc = NULL; + struct bgp_node *rn = bgp_get_nexthop_rn (path, peer); + + if (!rn) + return NULL; + + bnc = rn->info; + bgp_unlock_node (rn); + + return bnc; +} + static void bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc) { @@ -76,13 +145,13 @@ bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc) { char buf[INET6_ADDRSTRLEN]; zlog_debug("bgp_unlink_nexthop: freeing bnc %s", - bnc_str(bnc, buf, INET6_ADDRSTRLEN)); - } + bnc_str (bnc, buf, INET6_ADDRSTRLEN)); + } unregister_nexthop(bnc); bnc->node->info = NULL; - bgp_unlock_node(bnc->node); + bgp_unlock_node (bnc->node); bnc->node = NULL; - bnc_free(bnc); + bnc_free (bnc); } } @@ -94,6 +163,13 @@ bgp_unlink_nexthop (struct bgp_info *path) if (!bnc) return; + if (BGP_DEBUG(nht, NHT)) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("%s: NHT unlinking %s", + __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN)); + } + path_nh_map(path, NULL, 0); bgp_unlink_nexthop_check (bnc); @@ -102,70 +178,36 @@ bgp_unlink_nexthop (struct bgp_info *path) void bgp_unlink_nexthop_by_peer (struct peer *peer) { - struct prefix p; - struct bgp_node *rn; - struct bgp_nexthop_cache *bnc; - afi_t afi = family2afi(peer->su.sa.sa_family); - - if (afi == AFI_IP) - { - p.family = AF_INET; - p.prefixlen = IPV4_MAX_BITLEN; - p.u.prefix4 = peer->su.sin.sin_addr; - } - else if (afi == AFI_IP6) - { - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_BITLEN; - p.u.prefix6 = peer->su.sin6.sin6_addr; - } - else + struct bgp_nexthop_cache *bnc = bgp_find_nexthop (NULL, peer); + + if (!bnc) return; - rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); - - if (!rn->info) - return; - - bnc = rn->info; + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s: NHT unlinking %s", + __FUNCTION__, peer->host); - /* cleanup the peer reference */ bnc->nht_info = NULL; bgp_unlink_nexthop_check (bnc); } int -bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, - int connected) +bgp_ensure_nexthop (struct bgp_info *ri, struct peer *peer, + int connected) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; - struct prefix p; - - if (ri) - { - if (make_prefix(afi, ri, &p) < 0) - return 1; - } - else if (peer) + + rn = bgp_get_nexthop_rn (ri, peer); + + if (!rn) { - if (afi == AFI_IP) - { - p.family = AF_INET; - p.prefixlen = IPV4_MAX_BITLEN; - p.u.prefix4 = peer->su.sin.sin_addr; - } - else if (afi == AFI_IP6) - { - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_BITLEN; - p.u.prefix6 = peer->su.sin6.sin6_addr; - } + zlog_debug("%s: NHT could not ensure, failed to get rn!", + __FUNCTION__); + return 0; } - - rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); - + if (!rn->info) { bnc = bnc_new(); @@ -194,6 +236,13 @@ bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer, else if (peer) bnc->nht_info = (void *)peer; /* NHT peer reference */ + if (BGP_DEBUG(nht, NHT)) + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug("%s: NHT ensured %s", + __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN)); + } + return (bgp_zebra_num_connects() == 0 || CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 5086b0806..dd6300eb6 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -25,33 +25,40 @@ /** * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra. */ -extern void bgp_parse_nexthop_update(void); +void bgp_parse_nexthop_update (void); /** - * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object + * bgp_nexthop_check() - check if the bnc object is valid. * ARGUMENTS: * p - path for which the nexthop object is being looked up * connected - True if NH MUST be a connected route */ -extern int bgp_find_nexthop(struct bgp_info *p, int connected); +int bgp_nexthop_check (struct bgp_info *, int connected); /** - * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc - * object. If not found, create a new object and register with ZEBRA for - * nexthop notification. + * bgp_ensure_nexthop() - Ensure a bgp_nexthop_cache object exists for + * the given prefix or peer. If an existing one is not found, + * create a new object and register with ZEBRA for nexthop + * notification. * ARGUMENTS: - * a - afi: AFI_IP or AF_IP6 - * p - path for which the nexthop object is being looked up - * peer - The BGP peer associated with this NHT + * afi: AFI_IP or AF_IP6 + * struct bgp_info *: path for which the nexthop object is + * being looked up + * OR + * struct peer The BGP peer associated with this NHT * connected - True if NH MUST be a connected route */ -extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p, - struct peer *peer, int connected); +int bgp_ensure_nexthop (struct bgp_info *, struct peer *, int connected); /** * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure. * ARGUMENTS: - * p - path structure. + * struct bgp_info *: path structure. + */ +void bgp_unlink_nexthop (struct bgp_info *); + +/** + * bgp_unlink_nexthop() - Unlink the nexthop object for the given peer. */ extern void bgp_unlink_nexthop(struct bgp_info *p); void bgp_unlink_nexthop_by_peer (struct peer *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 476ef0596..913714349 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -134,7 +134,7 @@ bgp_info_free (struct bgp_info *binfo) if (binfo->attr) bgp_attr_unintern (&binfo->attr); - bgp_unlink_nexthop(binfo); + bgp_unlink_nexthop (binfo); bgp_info_extra_free (&binfo->extra); bgp_info_mpath_free (&binfo->mpath); @@ -2345,7 +2345,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, else connected = 0; - if (bgp_find_or_add_nexthop (afi, ri, NULL, connected)) + if (bgp_ensure_nexthop (ri, NULL, connected)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { @@ -2397,7 +2397,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, else connected = 0; - if (bgp_find_or_add_nexthop (afi, new, NULL, connected)) + if (bgp_ensure_nexthop (new, NULL, connected)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else { @@ -3543,7 +3543,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { - if (bgp_find_or_add_nexthop (afi, ri, NULL, 0)) + if (bgp_ensure_nexthop (ri, NULL, 0)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { @@ -3572,7 +3572,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { - if (bgp_find_or_add_nexthop (afi, new, NULL, 0)) + if (bgp_ensure_nexthop (new, NULL, 0)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else { @@ -3692,7 +3692,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { - if (bgp_find_or_add_nexthop (afi, ri, NULL, 0)) + if (bgp_ensure_nexthop (ri, NULL, 0)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { @@ -3722,7 +3722,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { - if (bgp_find_or_add_nexthop (afi, new, NULL, 0)) + if (bgp_ensure_nexthop (new, NULL, 0)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else { From 5a9f13a4a0df45c72dc425cc930e5e5682ba59ae Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 4 Oct 2016 13:00:00 +0100 Subject: [PATCH 1257/1342] bgpd: Remove change that makes NHT tickle BGP FSM. * bgpd NHT patch makes NHT tickle FSM to restart session attempts that are still very early, pre sending of messages. Not really necessary, and conceptually it may be nicer to just keep these two pieces separate from each other. * bgpd.h: Remove NHT_Update FSM event * bgp_fsm.c: Remove NHT_Update event action from the FSM. * bgp_nht.c: Remove NHT_Update event. --- bgpd/bgp_fsm.c | 9 --------- bgpd/bgp_nht.c | 1 - bgpd/bgpd.h | 1 - 3 files changed, 11 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 9d866554b..9f0b64c13 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -971,7 +971,6 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ - {bgp_start, Connect}, /* NHT_Update */ }, { /* Connect */ @@ -989,7 +988,6 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ - {bgp_reconnect, Connect},/* NHT_Update */ }, { /* Active, */ @@ -1007,7 +1005,6 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ - {bgp_start, Connect}, /* NHT_Update */ }, { /* OpenSent, */ @@ -1025,7 +1022,6 @@ static const struct { {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ - {bgp_ignore, OpenSent}, /* NHT_Update */ }, { /* OpenConfirm, */ @@ -1043,7 +1039,6 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ - {bgp_ignore, OpenConfirm}, /* NHT_Update */ }, { /* Established, */ @@ -1061,7 +1056,6 @@ static const struct { {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ - {bgp_ignore, Established}, /* NHT_Update */ }, { /* Clearing, */ @@ -1079,7 +1073,6 @@ static const struct { {bgp_stop, Clearing}, /* Receive_UPDATE_message */ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_clearing_completed, Idle}, /* Clearing_Completed */ - {bgp_ignore, Clearing}, /* NHT_Update */ }, { /* Deleted, */ @@ -1097,7 +1090,6 @@ static const struct { {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Deleted}, /* Clearing_Completed */ - {bgp_ignore, Deleted}, /* NHT_Update */ }, }; @@ -1118,7 +1110,6 @@ static const char *bgp_event_str[] = "Receive_UPDATE_message", "Receive_NOTIFICATION_message", "Clearing_Completed", - "NHT_Update", }; /* Execute event process. */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8c87a6495..1158ab152 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -580,7 +580,6 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) { if (BGP_DEBUG(nht, NHT)) zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host); - BGP_EVENT_ADD (peer, NHT_Update); SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0c13156bf..2b279cda6 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -747,7 +747,6 @@ struct bgp_nlri #define Receive_UPDATE_message 12 #define Receive_NOTIFICATION_message 13 #define Clearing_Completed 14 -#define NHT_Update 15 #define BGP_EVENTS_MAX 16 /* BGP timers default value. */ From b1b1579bf16e6c3a21216d7f68b1b175ab1303bd Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 21 Sep 2016 18:50:23 +0100 Subject: [PATCH 1258/1342] bgpd: consolidate start timer backoff via a 'BGP_Stop_with_error' FSM event * Exponential increase/back-off on the peer start timer is replicated in a few places. Consolidate by adding a "BGP_Stop_with_error" event so places outside FSM can just raise that event. * bgpd.h: Add BGP_Stop_with_error * bgp_fsm.c: (bgp_event_str[]) Add text for BGP_Stop_with_error. FSM table: Handle BGP_Stop_with_error, identical to bgp_stop in nearly all cases. * bgp_packet.c: (bgp_write,bgp_write_notify) can just raise new event now. --- bgpd/bgp_fsm.c | 9 +++++++++ bgpd/bgp_packet.c | 17 ++--------------- bgpd/bgpd.h | 1 + 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 9f0b64c13..abcefdd77 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -971,6 +971,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_ignore, Idle}, /* BGP_Stop_with_error */ }, { /* Connect */ @@ -988,6 +989,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* Active, */ @@ -1005,6 +1007,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* OpenSent, */ @@ -1022,6 +1025,7 @@ static const struct { {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* OpenConfirm, */ @@ -1039,6 +1043,7 @@ static const struct { {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* Established, */ @@ -1056,6 +1061,7 @@ static const struct { {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ + {bgp_stop_with_error, Clearing}, /* BGP_Stop_with_error */ }, { /* Clearing, */ @@ -1073,6 +1079,7 @@ static const struct { {bgp_stop, Clearing}, /* Receive_UPDATE_message */ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_clearing_completed, Idle}, /* Clearing_Completed */ + {bgp_stop_with_error, Clearing}, /* BGP_Stop_with_error */ }, { /* Deleted, */ @@ -1090,6 +1097,7 @@ static const struct { {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Deleted}, /* Clearing_Completed */ + {bgp_ignore, Deleted}, /* BGP_Stop_with_error */ }, }; @@ -1110,6 +1118,7 @@ static const char *bgp_event_str[] = "Receive_UPDATE_message", "Receive_NOTIFICATION_message", "Clearing_Completed", + "BGP_Stop_with_error", }; /* Execute event process. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index f42e544b4..51b006a60 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -766,15 +766,9 @@ bgp_write (struct thread *thread) break; case BGP_MSG_NOTIFY: peer->notify_out++; - /* Double start timer. */ - peer->v_start *= 2; - - /* Overflow check. */ - if (peer->v_start >= (60 * 2)) - peer->v_start = (60 * 2); /* Flush any existing events */ - BGP_EVENT_ADD (peer, BGP_Stop); + BGP_EVENT_ADD (peer, BGP_Stop_with_error); goto done; case BGP_MSG_KEEPALIVE: @@ -846,14 +840,7 @@ bgp_write_notify (struct peer *peer) /* Type should be notify. */ peer->notify_out++; - /* Double start timer. */ - peer->v_start *= 2; - - /* Overflow check. */ - if (peer->v_start >= (60 * 2)) - peer->v_start = (60 * 2); - - BGP_EVENT_ADD (peer, BGP_Stop); + BGP_EVENT_ADD (peer, BGP_Stop_with_error); return 0; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 2b279cda6..a6cc34ea0 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -747,6 +747,7 @@ struct bgp_nlri #define Receive_UPDATE_message 12 #define Receive_NOTIFICATION_message 13 #define Clearing_Completed 14 +#define BGP_Stop_with_error 15 #define BGP_EVENTS_MAX 16 /* BGP timers default value. */ From b8f8ba1bb24295a47758cb0e0b3072e017e52280 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 28 Sep 2016 16:54:48 +0100 Subject: [PATCH 1259/1342] bgpd: Make the exponential backoff on BGP stop_with_error slower * bgp_fsm.c: (bgp_stop_with_error) peer->v_start * 2^x exponential back off, up to max of 120s, ramps up fast. Use a slower back off, implemented via a helper. (back_off_exp2) The original 2^x back off. (back_off_exp2_bias) Exp back-off, but biased down by the initial value to slow the rampup initially. --- bgpd/bgp_fsm.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index abcefdd77..41f623ff3 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -587,19 +587,41 @@ bgp_stop (struct peer *peer) return 0; } -/* BGP peer is stoped by the error. */ +/* first-val * 2**x back-off, where x is the number of sucessive calls + * originally used for peer v_start back-off + */ +__attribute__((unused)) static int -bgp_stop_with_error (struct peer *peer) +back_off_exp2 (const int first, int val, const int max) { - /* Double start timer. */ - peer->v_start *= 2; + val <<= 1; + return (val < max ? val : max); +} - /* Overflow check. */ - if (peer->v_start >= (60 * 2)) - peer->v_start = (60 * 2); +/* exponential back off, but biased downward by the initial value. + * this bias is significant at lower values, and tends to + * insignificance fairly quickly, so it is equal to the previous at + * scale. Is below first-val * 1.7**x at x == 6, and below first-val + * * 1.75**x at x=10. + * + * I.e., this function is useful to get slower growth for the initial + * points of x. + */ +__attribute__((unused)) +static int +back_off_exp2_bias (const int first, int val, const int max) +{ + val = (val << 1) - (val > first ? first : 0); + return (val < max ? val : max); +} +/* BGP peer is stoped by the error. */ +static int +bgp_stop_with_error (struct peer *peer) +{ + peer->v_start + = back_off_exp2_bias (BGP_INIT_START_TIMER, peer->v_start, 60); bgp_stop (peer); - return 0; } From 86d87e018bd8f9249986be4e6b713ab918fa5e0b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 20 Apr 2016 14:04:22 +0100 Subject: [PATCH 1260/1342] bgpd: Graphviz dot files for the BGP FSM * bgp_fsm_{quagga,4271}.dot: Graphviz DOT files to document the BGP FSM somewhat, for both Quagga and the basics of 4271. May contain errors, and could do with more work, but hopefully a useful start. --- bgpd/bgp_fsm_4271.dot | 34 ++++++++++++++++++++++++ bgpd/bgp_fsm_quagga.dot | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 bgpd/bgp_fsm_4271.dot create mode 100644 bgpd/bgp_fsm_quagga.dot diff --git a/bgpd/bgp_fsm_4271.dot b/bgpd/bgp_fsm_4271.dot new file mode 100644 index 000000000..c03939fd9 --- /dev/null +++ b/bgpd/bgp_fsm_4271.dot @@ -0,0 +1,34 @@ +digraph { + rankdir=LR + //concentrate=true + nojustify="true" + + Idle -> Connect [ label="ManualStart\l|AutomaticStart" ] + Idle -> Active [ label="ManualStart_with_PassiveTcpEstablishment\l|AutomaticStart_with_PassiveTcpEstablishment" ] + + Connect -> Idle [ label="ManualStop"] + Connect -> Connect [ label="ConnectRetryTimer_Expires\l|TcpConnection_Valid\l|Tcp_CR_Invalid\l|Tcp_CR_Acked && DelayOpen == True\l|TcpConnectionConfirmed && DelayOpen == True\l" ] + Connect -> OpenSent [ label="DelayOpenTimer_Expires\l|Tcp_CR_Acked && DelayOpen == False\l|TcpConnectionConfirmed && DelayOpen == False\l" ] + Connect -> Active [ label="TcpConnectionFails && DelayOpenTimer == \"running\"\l" ] + Connect -> Idle [ label="TcpConnectionFails && DelayOpenTimer == \"not running\"\l" ] + Connect -> OpenConfirm [ label="BGPOpen && DelayOpenTimer == \"running\"" ] + Connect -> Idle [ label="NotifMsg|*\l" ] + + Active -> Idle [ label="ManualStop\l|TcpConnectionFails\l|NotifMsg|*" ] + Active -> Connect [ label="ConnectRetryTimer_Expires" ] + Active -> OpenSent [ label="DelayOpenTimer_Expires" ] + Active -> Active [ label="(Tcp_CR_Acked\l|TcpConnectionConfirmed)\l&& DelayOpen = True" ] + Active -> OpenSent [ label="(Tcp_CR_Acked|TcpConnectionConfirmed)\l&& DelayOpen = False" ] + Active -> OpenConfirm [ label="BGPOpen && DelayOpenTimer == \"running\"" ] + + OpenSent -> Idle [ label="ManualStop\l|AutomaticStop\l|HoldTimer_Expires\l|NotifMsg\l|OpenCollisionDump\l" ] + OpenSent -> Active [ label="TcpConnectionFails" ] + OpenSent -> OpenConfirm [ label="BGPOpen" ] + + OpenConfirm -> Idle [ label="ManualStop\l|AutomaticStop\l|HoldTimer_Expires\l|TcpConnectionFails\l|NotifMsg\l|BGPOpen|*\l"] + OpenConfirm -> Established [ label="KeepAliveMsg|"] + OpenConfirm -> OpenConfirm [ label="KeepaliveTimer_Expires" ] + + Established -> Idle [ label="OpenCollisionDump|*"] + Established -> Established [ label="Tcp_CR_Invalid|KeepAliveMsg|UpdateMsg"] +} \ No newline at end of file diff --git a/bgpd/bgp_fsm_quagga.dot b/bgpd/bgp_fsm_quagga.dot new file mode 100644 index 000000000..2b9bee849 --- /dev/null +++ b/bgpd/bgp_fsm_quagga.dot @@ -0,0 +1,59 @@ +digraph { + rankdir=LR + //concentrate=true + nojustify="true" + + Idle + Connect + Active + OpenSent + OpenConfirm + Established + Clearing + Idle -> Deleted + Configured -> Idle + + Idle -> Connect [ label="BGP_Start\l/bgp_start\l" ] + Idle -> Idle [ label="BGP_Stop\l|TCP_connection_open\l|TCP_connection_closed\l|TCP_fatal_error\l/bgp_stop\l"] + + Connect -> Connect [ label="ConnectRetry_timer_expired\l/bgp_reconnect\l" ] + Connect -> Idle [ label="BGP_Stop\l|TCP_connection_open\l|Receive_NOTIFICATION_message\l/bgp_stop\l" ] + Connect -> Idle [ label="TCP_fatal_error\l/bgp_connect_fail\l" ] + Connect -> Idle [ label="Hold_Timer_expired\l|KeepAlive_timer_expired\l|Receive_OPEN_message\l|Receive_KEEPALIVE_message\l|Receive_UPDATE_message\l|Clearing_Completed\l/bgp_ignore"] + Connect -> OpenSent [ label="TCP_connection_open\l/bgp_connect_success\l" ] + Connect -> Active [ label="TCP_connection_open_failed\l/bgp_connect_fail\l" ] + + Active -> Idle [ label="BGP_Stop\l|TCP_connection_closed\l/bgp_stop\l" ] + Active -> Idle [ label="Receive_NOTIFICATION_message\l/bgp_stop_with_error\l" ] + Active -> Idle [ label="TCP_fatal_error\l|Hold_Timer_expired\l|KeepAlive_timer_expired\l|Receive_OPEN_message\l|Receive_KEEPALIVE_message\l|Receive_UPDATE_message\l|Clearing_Completed\l/bgp_ignore\l" ] + Active -> OpenSent [ label="TCP_connection_open\l/bgp_connect_success\l" ] + Active -> Connect [ label="ConnectRetry_timer_expiredl/bgp_start\l" ] + + Accept -> Active [ label="Raise TCP_connection_open on Active" ] + + OpenSent -> Idle [ label="BGP_Stop\l/bgp_stop\l" ] + OpenSent -> Idle [ label="ConnectRetry_timer_expired\l|Clearing_Completed\l|KeepAlive_timer_expired\l/bgp_ignore\l" ] + OpenSent -> Idle [ label="Hold_Timer_expired\l/bgp_fsm_holdtime_expire\l"] + OpenSent -> Idle [ label="Receive_KEEPALIVE_message\l|Receive_UPDATE_message\l/bgp_fsm_event_error" ] + OpenSent -> Idle [ label="Receive_NOTIFICATION_message\l/bgp_stop_with_error" ] + OpenSent -> Active [ label="TCP_connection_open\l|TCP_connection_closed\l|TCP_connection_open_failed\l|TCP_fatal_error\l/bgp_stop\l"] + OpenSent -> OpenConfirm [ label="Receive_OPEN_message\l/bgp_fsm_open" ] + + OpenConfirm -> Idle [ label="BGP_Stop\l|TCP_connection_open\l|TCP_connection_closed\l|TCP_connection_open_failed\l|TCP_fatal_error\l/bgp_stop\l"] + OpenConfirm -> Idle [ label="Hold_Timer_expired\l/bgp_fsm_holdtime_expire" ] + OpenConfirm -> Idle [ label="ConnectRetry_timer_expired\l|Receive_OPEN_message\l|Receive_UPDATE_message\l|Clearing_Completed\l/bgp_ignore"] + OpenConfirm -> Idle [ label="Receive_NOTIFICATION_message\l/bgp_stop_with_error\l" ] + OpenConfirm -> Established [ label="Receive_KEEPALIVE_message\l/bgp_establish\l" ] + + Established -> Clearing [ label="BGP_Stop\l|TCP_connection_open\l|TCP_connection_closed\l|TCP_connection_open_failed\l|TCP_fatal_error\l|ConnectRetry_timer_expired\l|Hold_Timer_expired\l|Receive_OPEN_message\l/bgp_stop\l"] + Established -> Idle [ label="Clearing_Completed\l/bgp_ignore" ] + Established -> Clearing [ label="Receive_NOTIFICATION_message\l/bgp_stop_with_error"] + + Clearing -> Idle [ label="Clearing_Completed\l/bgp_clearing_completed" ] + subgraph cluster_pre_collision_detect { + label="Prior to collision detection" + bgcolor=lightgray + Connect Accept Active OpenSent OpenConfirm + } + +} \ No newline at end of file From f2a4b8fffb1f771371d6bfc425e7a69a14057b06 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 20 Jan 2017 14:45:47 +0000 Subject: [PATCH 1261/1342] nhrpd: Add libgen.h include for basename call --- nhrpd/nhrp_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 29349a038..56ea2713a 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -8,6 +8,7 @@ */ #include +#include #include "zebra.h" #include "privs.h" From 3334bab0d96b2d7064111e025ff6294d6a32d026 Mon Sep 17 00:00:00 2001 From: Job Snijders Date: Fri, 20 Jan 2017 14:47:12 +0000 Subject: [PATCH 1262/1342] bgpd: Add support for BGP Large Communities As described by Michael Lambert to the list: Traditional communities are four-octet entities to support two-octet ASNs and are usually represented as :. Large communities are an enhancement to support four-octet ASNs and are 12 octets long, represented as ::. This issue has been tracked in quagga bugzilla ticket #875, which documents some of the usage and indicates that some testing has been done. TODO: Documentation - update doc/bgpd.texi. * bgp_attr.{c,h}: Add BGP_ATTR_LARGE_COMMUNITIES codepoint. Add (struct lcommunity *) to (struct bgp_attr_extra). * bgp_clist.{c,h}: Large community codepoints and routines. * bgp_route.c: Display support. * bgp_routemap.c: 'match lcommunity', 'set large-community' and 'set large-comm-list' * bgp_vty.c: Peer configuration, add 'large' to 'neighbor send-community ..'. Add "show ip bgp large-community", ""ip large-community-list ...". Authors: Keyur Patel Job Snijders --- bgpd/Makefile.am | 6 +- bgpd/bgp_attr.c | 109 ++++- bgpd/bgp_attr.h | 3 + bgpd/bgp_clist.c | 313 +++++++++++++ bgpd/bgp_clist.h | 18 +- bgpd/bgp_lcommunity.c | 562 +++++++++++++++++++++++ bgpd/bgp_lcommunity.h | 75 +++ bgpd/bgp_mpath.c | 16 + bgpd/bgp_route.c | 1009 ++++++++++++++++++++++++++++++++++++++++- bgpd/bgp_routemap.c | 440 +++++++++++++++++- bgpd/bgp_vty.c | 475 ++++++++++++++++++- bgpd/bgpd.c | 19 +- bgpd/bgpd.h | 2 + lib/memtypes.c | 3 + 14 files changed, 3023 insertions(+), 27 deletions(-) create mode 100644 bgpd/bgp_lcommunity.c create mode 100644 bgpd/bgp_lcommunity.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index fe1be32ed..753b679f8 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -14,7 +14,8 @@ libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ - bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ + bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \ + bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_encap.c bgp_encap_tlv.c bgp_nht.c @@ -22,7 +23,8 @@ noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ - bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ + bgp_ecommunity.h bgp_lcommunity.h \ + bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 6aab50af4..a79a03cc6 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -39,6 +39,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "table.h" #include "bgp_encap_types.h" @@ -65,6 +66,18 @@ static const struct message attr_str [] = { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, { BGP_ATTR_ENCAP, "ENCAP" }, + { 21, ""}, + { 22, ""}, + { 23, ""}, + { 24, ""}, + { 25, ""}, + { 26, ""}, + { 27, ""}, + { 28, ""}, + { 29, ""}, + { 30, ""}, + { 31, ""}, + { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" } }; static const int attr_str_max = array_size(attr_str); @@ -505,6 +518,8 @@ attrhash_key_make (void *p) if (extra) { + if (extra->lcommunity) + MIX(lcommunity_hash_make (extra->lcommunity)); if (extra->ecommunity) MIX(ecommunity_hash_make (extra->ecommunity)); if (extra->cluster) @@ -547,6 +562,7 @@ attrhash_cmp (const void *p1, const void *p2) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) && ae1->ecommunity == ae2->ecommunity + && ae1->lcommunity == ae2->lcommunity && ae1->cluster == ae2->cluster && ae1->transit == ae2->transit && (ae1->encap_tunneltype == ae2->encap_tunneltype) @@ -658,6 +674,13 @@ bgp_attr_intern (struct attr *attr) attre->ecommunity->refcnt++; } + if (attre->lcommunity) + { + if (! attre->lcommunity->refcnt) + attre->lcommunity = lcommunity_intern (attre->lcommunity); + else + attre->lcommunity->refcnt++; + } if (attre->cluster) { if (! attre->cluster->refcnt) @@ -791,6 +814,10 @@ bgp_attr_unintern_sub (struct attr *attr) if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); + + if (attr->extra->lcommunity) + lcommunity_unintern (&attr->extra->lcommunity); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); if (attr->extra->cluster) cluster_unintern (attr->extra->cluster); @@ -853,6 +880,8 @@ bgp_attr_flush (struct attr *attr) if (attre->ecommunity && ! attre->ecommunity->refcnt) ecommunity_free (&attre->ecommunity); + if (attre->lcommunity && ! attre->lcommunity->refcnt) + lcommunity_free (&attre->lcommunity); if (attre->cluster && ! attre->cluster->refcnt) { cluster_free (attre->cluster); @@ -1002,6 +1031,7 @@ const u_int8_t attr_flags_values [] = { [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, + [BGP_ATTR_LARGE_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL }; static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; @@ -1791,6 +1821,37 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_PROCEED; } +/* Large Community attribute. */ +static bgp_attr_parse_ret_t +bgp_attr_large_community (struct bgp_attr_parser_args *args) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + + if (length == 0) + { + if (attr->extra) + attr->extra->lcommunity = NULL; + /* Empty extcomm doesn't seem to be invalid per se */ + return BGP_ATTR_PARSE_PROCEED; + } + + (bgp_attr_extra_get (attr))->lcommunity = + lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); + /* XXX: fix ecommunity_parse to use stream API */ + stream_forward_getp (peer->ibuf, length); + + if (attr->extra && !attr->extra->lcommunity) + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + + return BGP_ATTR_PARSE_PROCEED; +} + /* Extended Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_ext_communities (struct bgp_attr_parser_args *args) @@ -1812,7 +1873,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); - if (!attr->extra->ecommunity) + if (attr->extra && !attr->extra->ecommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2225,6 +2286,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (&attr_args); break; + case BGP_ATTR_LARGE_COMMUNITIES: + ret = bgp_attr_large_community (&attr_args); + break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (&attr_args); break; @@ -2794,6 +2858,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_put (s, attr->community->val, attr->community->size * 4); } + /* + * Large Community attribute. + */ + if (attr->extra && + CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) + && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))) + { + if (attr->extra->lcommunity->size * 12 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); + stream_putw (s, attr->extra->lcommunity->size * 12); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); + stream_putc (s, attr->extra->lcommunity->size * 12); + } + stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); + } + /* Route Reflector. */ if (peer->sort == BGP_PEER_IBGP && from @@ -3002,6 +3088,7 @@ bgp_attr_init (void) attrhash_init (); community_init (); ecommunity_init (); + lcommunity_init (); cluster_init (); transit_init (); } @@ -3013,6 +3100,7 @@ bgp_attr_finish (void) attrhash_finish (); community_finish (); ecommunity_finish (); + lcommunity_finish (); cluster_finish (); transit_finish (); } @@ -3115,6 +3203,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_put (s, attr->community->val, attr->community->size * 4); } + /* Large Community attribute. */ + if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)) + { + if (attr->extra->lcommunity->size * 12 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_COMMUNITIES); + stream_putw (s, attr->extra->lcommunity->size * 12); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_COMMUNITIES); + stream_putc (s, attr->extra->lcommunity->size * 12); + } + + stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); + } + /* Add a MP_NLRI attribute to dump the IPv6 next hop */ if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) ) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 8457f4022..9ff074b2c 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -66,6 +66,9 @@ struct attr_extra /* Extended Communities attribute. */ struct ecommunity *ecommunity; + + /* Large Communities attribute. */ + struct lcommunity *lcommunity; /* Route-Reflector Cluster attribute */ struct cluster_list *cluster; diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 800bd0129..13bdf8e84 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" @@ -44,6 +45,8 @@ community_list_master_lookup (struct community_list_handler *ch, int master) return &ch->community_list; case EXTCOMMUNITY_LIST_MASTER: return &ch->extcommunity_list; + case LARGE_COMMUNITY_LIST_MASTER: + return &ch->lcommunity_list; } return NULL; } @@ -65,6 +68,10 @@ community_entry_free (struct community_entry *entry) if (entry->u.com) community_free (entry->u.com); break; + case LARGE_COMMUNITY_LIST_STANDARD: + if (entry->u.lcom) + lcommunity_free (&entry->u.lcom); + break; case EXTCOMMUNITY_LIST_STANDARD: /* In case of standard extcommunity-list, configuration string is made by ecommunity_ecom2str(). */ @@ -75,6 +82,7 @@ community_entry_free (struct community_entry *entry) break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (entry->config) XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) @@ -315,12 +323,17 @@ community_list_entry_lookup (struct community_list *list, const void *arg, if (community_cmp (entry->u.com, arg)) return entry; break; + case LARGE_COMMUNITY_LIST_STANDARD: + if (lcommunity_cmp (entry->u.lcom, arg)) + return entry; + break; case EXTCOMMUNITY_LIST_STANDARD: if (ecommunity_cmp (entry->u.ecom, arg)) return entry; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, arg) == 0) return entry; break; @@ -446,6 +459,91 @@ community_regexp_match (struct community *com, regex_t * reg) return 0; } +static char * +lcommunity_str_get (struct lcommunity *lcom, int i) +{ + struct lcommunity_val lcomval; + u_int32_t globaladmin; + u_int32_t localdata1; + u_int32_t localdata2; + char *str; + u_char *ptr; + char *pnt; + + ptr = lcom->val; + ptr += (i * LCOMMUNITY_SIZE); + + memcpy (&lcomval, ptr, LCOMMUNITY_SIZE); + + /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */ + str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48); + + ptr = (u_char *)lcomval.val; + globaladmin = (*ptr++ << 24); + globaladmin |= (*ptr++ << 16); + globaladmin |= (*ptr++ << 8); + globaladmin |= (*ptr++); + + localdata1 = (*ptr++ << 24); + localdata1 |= (*ptr++ << 16); + localdata1 |= (*ptr++ << 8); + localdata1 |= (*ptr++); + + localdata2 = (*ptr++ << 24); + localdata2 |= (*ptr++ << 16); + localdata2 |= (*ptr++ << 8); + localdata2 |= (*ptr++); + + sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2); + pnt += strlen (pnt); + *pnt = '\0'; + + return str; +} + +/* Internal function to perform regular expression match for + * * a single community. */ +static int +lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i) +{ + const char *str; + + /* When there is no communities attribute it is treated as empty + * string. */ + if (lcom == NULL || lcom->size == 0) + str = ""; + else + str = lcommunity_str_get (lcom, i); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + +static int +lcommunity_regexp_match (struct lcommunity *com, regex_t * reg) +{ + const char *str; + + /* When there is no communities attribute it is treated as empty + string. */ + if (com == NULL || com->size == 0) + str = ""; + else + str = lcommunity_str (com); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + + static int ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg) { @@ -495,6 +593,30 @@ community_list_match (struct community *com, struct community_list *list) return 0; } +int +lcommunity_list_match (struct lcommunity *lcom, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) + { + if (lcommunity_match (lcom, entry->u.lcom)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) + { + if (lcommunity_regexp_match (lcom, entry->reg)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + } + return 0; +} + int ecommunity_list_match (struct ecommunity *ecom, struct community_list *list) { @@ -647,8 +769,13 @@ community_list_dup_check (struct community_list *list, if (ecommunity_cmp (entry->u.ecom, new->u.ecom)) return 1; break; + case LARGE_COMMUNITY_LIST_STANDARD: + if (lcommunity_cmp (entry->u.lcom, new->u.lcom)) + return 1; + break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (entry->config && new->config && strcmp (entry->config, new->config) == 0) return 1; @@ -770,6 +897,186 @@ community_list_unset (struct community_list_handler *ch, return 0; } +/* Delete all permitted large communities in the list from com. */ +struct lcommunity * +lcommunity_list_match_delete (struct lcommunity *lcom, + struct community_list *list) +{ + struct community_entry *entry; + u_int32_t com_index_to_delete[lcom->size]; + u_char *ptr; + int delete_index = 0; + int i; + + /* Loop over each lcommunity value and evaluate each against the + * community-list. If we need to delete a community value add its index to + * com_index_to_delete. + */ + + for (i = 0; i < lcom->size; i++) + { + ptr = lcom->val + (i * LCOMMUNITY_SIZE); + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + + else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) + && lcommunity_include (entry->u.lcom, ptr) ) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + + else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) + && entry->reg + && lcommunity_regexp_include (entry->reg, lcom, i)) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + } + } + + /* Delete all of the communities we flagged for deletion */ + + for (i = delete_index-1; i >= 0; i--) + { + ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE); + lcommunity_del_val (lcom, ptr); + } + + return lcom; +} + +/* Set lcommunity-list. */ +int +lcommunity_list_set (struct community_list_handler *ch, + const char *name, const char *str, int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct lcommunity *lcom = NULL; + regex_t *regex = NULL; + + /* Get community list. */ + list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER); + + /* When community-list already has entry, new entry should have same + style. If you want to have mixed style community-list, you can + comment out this check. */ + if (!community_list_empty_p (list)) + { + struct community_entry *first; + + first = list->head; + + if (style != first->style) + { + return (first->style == COMMUNITY_LIST_STANDARD + ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT + : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); + } + } + + if (str) + { + if (style == LARGE_COMMUNITY_LIST_STANDARD) + lcom = lcommunity_str2com (str); + else + regex = bgp_regcomp (str); + + if (! lcom && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + } + + entry = community_entry_new (); + entry->direct = direct; + entry->style = style; + entry->any = (str ? 0 : 1); + entry->u.lcom = lcom; + entry->reg = regex; + if (lcom) + entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST); + else if (regex) + entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); + else + entry->config = NULL; + + /* Do not put duplicated community entry. */ + if (community_list_dup_check (list, entry)) + community_entry_free (entry); + else + community_list_entry_add (list, entry); + + return 0; +} + +/* Unset community-list. When str is NULL, delete all of + community-list entry belongs to the specified name. */ +int +lcommunity_list_unset (struct community_list_handler *ch, + const char *name, const char *str, + int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct lcommunity *lcom = NULL; + regex_t *regex = NULL; + + /* Lookup community list. */ + list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER); + if (list == NULL) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + /* Delete all of entry belongs to this community-list. */ + if (!str) + { + community_list_delete (list); + return 0; + } + + if (style == LARGE_COMMUNITY_LIST_STANDARD) + lcom = lcommunity_str2com (str); + else + regex = bgp_regcomp (str); + + if (! lcom && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + + if (lcom) + entry = community_list_entry_lookup (list, lcom, direct); + else + entry = community_list_entry_lookup (list, str, direct); + + if (lcom) + lcommunity_free (&lcom); + if (regex) + bgp_regex_free (regex); + + if (!entry) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + community_list_entry_delete (list, entry, style); + + return 0; +} + /* Set extcommunity-list. */ int extcommunity_list_set (struct community_list_handler *ch, @@ -912,6 +1219,12 @@ community_list_terminate (struct community_list_handler *ch) while ((list = cm->str.head) != NULL) community_list_delete (list); + cm = &ch->lcommunity_list; + while ((list = cm->num.head) != NULL) + community_list_delete (list); + while ((list = cm->str.head) != NULL) + community_list_delete (list); + cm = &ch->extcommunity_list; while ((list = cm->num.head) != NULL) community_list_delete (list); diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 5dcb3b4c1..d9db4189e 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Master Community-list. */ #define COMMUNITY_LIST_MASTER 0 #define EXTCOMMUNITY_LIST_MASTER 1 +#define LARGE_COMMUNITY_LIST_MASTER 2 /* Community-list deny and permit. */ #define COMMUNITY_DENY 0 @@ -38,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */ #define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */ #define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */ +#define LARGE_COMMUNITY_LIST_STANDARD 4 /* Standard Large community-list. */ +#define LARGE_COMMUNITY_LIST_EXPANDED 5 /* Expanded Large community-list. */ /* Community-list. */ struct community_list @@ -80,6 +83,7 @@ struct community_entry { struct community *com; struct ecommunity *ecom; + struct lcommunity *lcom; } u; /* Configuration string. */ @@ -112,6 +116,9 @@ struct community_list_handler /* Exteded community-list. */ struct community_list_master extcommunity_list; + + /* Large community-list. */ + struct community_list_master lcommunity_list; }; /* Error code of community-list. */ @@ -139,6 +146,12 @@ extern int extcommunity_list_set (struct community_list_handler *ch, extern int extcommunity_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); +extern int lcommunity_list_set (struct community_list_handler *ch, + const char *name, const char *str, + int direct, int style); +extern int lcommunity_list_unset (struct community_list_handler *ch, + const char *name, const char *str, + int direct, int style); extern struct community_list_master * community_list_master_lookup (struct community_list_handler *, int); @@ -148,9 +161,12 @@ community_list_lookup (struct community_list_handler *, const char *, int); extern int community_list_match (struct community *, struct community_list *); extern int ecommunity_list_match (struct ecommunity *, struct community_list *); +extern int lcommunity_list_match (struct lcommunity *, struct community_list *); extern int community_list_exact_match (struct community *, struct community_list *); extern struct community * community_list_match_delete (struct community *, struct community_list *); - +extern struct lcommunity * +lcommunity_list_match_delete (struct lcommunity *lcom, + struct community_list *list); #endif /* _QUAGGA_BGP_CLIST_H */ diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c new file mode 100644 index 000000000..cc67e1245 --- /dev/null +++ b/bgpd/bgp_lcommunity.c @@ -0,0 +1,562 @@ +/* BGP Large Communities Attribute + +Copyright (C) 2016 Keyur Patel + +This file is part of GNU Zebra. + +GNU Zebra 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. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_lcommunity.h" +#include "bgpd/bgp_aspath.h" + +/* Hash of community attribute. */ +static struct hash *lcomhash; + +/* Allocate a new lcommunities. */ +static struct lcommunity * +lcommunity_new (void) +{ + return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY, + sizeof (struct lcommunity)); +} + +/* Allocate lcommunities. */ +void +lcommunity_free (struct lcommunity **lcom) +{ + if ((*lcom)->val) + XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val); + if ((*lcom)->str) + XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str); + XFREE (MTYPE_LCOMMUNITY, *lcom); + lcom = NULL; +} + +/* Add a new Large Communities value to Large Communities + Attribute structure. When the value is already exists in the + structure, we don't add the value. Newly added value is sorted by + numerical order. When the value is added to the structure return 1 + else return 0. */ +static int +lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval) +{ + u_int8_t *p; + int ret; + int c; + + /* When this is fist value, just add it. */ + if (lcom->val == NULL) + { + lcom->size++; + lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom)); + memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE); + return 1; + } + + /* If the value already exists in the structure return 0. */ + c = 0; + for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++) + { + ret = memcmp (p, lval->val, LCOMMUNITY_SIZE); + if (ret == 0) + return 0; + if (ret > 0) + break; + } + + /* Add the value to the structure with numerical sorting. */ + lcom->size++; + lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom)); + + memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE, + lcom->val + c * LCOMMUNITY_SIZE, + (lcom->size - 1 - c) * LCOMMUNITY_SIZE); + memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE); + + return 1; +} + +/* This function takes pointer to Large Communites strucutre then + create a new Large Communities structure by uniq and sort each + Large Communities value. */ +struct lcommunity * +lcommunity_uniq_sort (struct lcommunity *lcom) +{ + int i; + struct lcommunity *new; + struct lcommunity_val *lval; + + if (! lcom) + return NULL; + + new = lcommunity_new (); + + for (i = 0; i < lcom->size; i++) + { + lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE)); + lcommunity_add_val (new, lval); + } + return new; +} + +/* Parse Large Communites Attribute in BGP packet. */ +struct lcommunity * +lcommunity_parse (u_int8_t *pnt, u_short length) +{ + struct lcommunity tmp; + struct lcommunity *new; + + /* Length check. */ + if (length % LCOMMUNITY_SIZE) + return NULL; + + /* Prepare tmporary structure for making a new Large Communities + Attribute. */ + tmp.size = length / LCOMMUNITY_SIZE; + tmp.val = pnt; + + /* Create a new Large Communities Attribute by uniq and sort each + Large Communities value */ + new = lcommunity_uniq_sort (&tmp); + + return lcommunity_intern (new); +} + +/* Duplicate the Large Communities Attribute structure. */ +struct lcommunity * +lcommunity_dup (struct lcommunity *lcom) +{ + struct lcommunity *new; + + new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity)); + new->size = lcom->size; + if (new->size) + { + new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE); + memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE); + } + else + new->val = NULL; + return new; +} + +/* Retrun string representation of communities attribute. */ +char * +lcommunity_str (struct lcommunity *lcom) +{ + if (! lcom->str) + lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY); + return lcom->str; +} + +/* Merge two Large Communities Attribute structure. */ +struct lcommunity * +lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2) +{ + if (lcom1->val) + lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val, + (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + else + lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, + (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + + memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE), + lcom2->val, lcom2->size * LCOMMUNITY_SIZE); + lcom1->size += lcom2->size; + + return lcom1; +} + +/* Intern Large Communities Attribute. */ +struct lcommunity * +lcommunity_intern (struct lcommunity *lcom) +{ + struct lcommunity *find; + + assert (lcom->refcnt == 0); + + find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern); + + if (find != lcom) + lcommunity_free (&lcom); + + find->refcnt++; + + if (! find->str) + find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY); + + return find; +} + +/* Unintern Large Communities Attribute. */ +void +lcommunity_unintern (struct lcommunity **lcom) +{ + struct lcommunity *ret; + + if ((*lcom)->refcnt) + (*lcom)->refcnt--; + + /* Pull off from hash. */ + if ((*lcom)->refcnt == 0) + { + /* Large community must be in the hash. */ + ret = (struct lcommunity *) hash_release (lcomhash, *lcom); + assert (ret != NULL); + + lcommunity_free (lcom); + } +} + +/* Utility function to make hash key. */ +unsigned int +lcommunity_hash_make (void *arg) +{ + const struct lcommunity *lcom = arg; + int size = lcom->size * LCOMMUNITY_SIZE; + u_int8_t *pnt = lcom->val; + unsigned int key = 0; + int c; + + for (c = 0; c < size; c += LCOMMUNITY_SIZE) + { + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + key += pnt[c + 4]; + key += pnt[c + 5]; + key += pnt[c + 6]; + key += pnt[c + 7]; + key += pnt[c + 8]; + key += pnt[c + 9]; + key += pnt[c + 10]; + key += pnt[c + 11]; + } + + return key; +} + +/* Compare two Large Communities Attribute structure. */ +int +lcommunity_cmp (const void *arg1, const void *arg2) +{ + const struct lcommunity *lcom1 = arg1; + const struct lcommunity *lcom2 = arg2; + + return (lcom1->size == lcom2->size + && memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0); +} + +/* Return communities hash. */ +struct hash * +lcommunity_hash (void) +{ + return lcomhash; +} + +/* Initialize Large Comminities related hash. */ +void +lcommunity_init (void) +{ + lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp); +} + +void +lcommunity_finish (void) +{ + hash_free (lcomhash); + lcomhash = NULL; +} + +/* Large Communities token enum. */ +enum lcommunity_token +{ + lcommunity_token_unknown = 0, + lcommunity_token_val, +}; + +/* Get next Large Communities token from the string. */ +static const char * +lcommunity_gettoken (const char *str, struct lcommunity_val *lval, + enum lcommunity_token *token) +{ + const char *p = str; + + /* Skip white space. */ + while (isspace ((int) *p)) + { + p++; + str++; + } + + /* Check the end of the line. */ + if (*p == '\0') + return NULL; + + /* Community value. */ + if (isdigit ((int) *p)) + { + int separator = 0; + int digit = 0; + u_int32_t globaladmin = 0; + u_int32_t localdata1 = 0; + u_int32_t localdata2 = 0; + + while (isdigit ((int) *p) || *p == ':') + { + if (*p == ':') + { + if (separator == 2) + { + *token = lcommunity_token_unknown; + return NULL; + } + else + { + separator++; + digit = 0; + if (separator == 1) { + globaladmin = localdata2; + } else { + localdata1 = localdata2; + } + localdata2 = 0; + } + } + else + { + digit = 1; + localdata2 *= 10; + localdata2 += (*p - '0'); + } + p++; + } + if (! digit) + { + *token = lcommunity_token_unknown; + return NULL; + } + + /* + * Copy the large comm. + */ + lval->val[0] = (globaladmin >> 24) & 0xff; + lval->val[1] = (globaladmin >> 16) & 0xff; + lval->val[2] = (globaladmin >> 8) & 0xff; + lval->val[3] = globaladmin & 0xff; + lval->val[4] = (localdata1 >> 24) & 0xff; + lval->val[5] = (localdata1 >> 16) & 0xff; + lval->val[6] = (localdata1 >> 8) & 0xff; + lval->val[7] = localdata1 & 0xff; + lval->val[8] = (localdata2 >> 24) & 0xff; + lval->val[9] = (localdata2 >> 16) & 0xff; + lval->val[10] = (localdata2 >> 8) & 0xff; + lval->val[11] = localdata2 & 0xff; + + *token = lcommunity_token_val; + return p; + } + *token = lcommunity_token_unknown; + return p; +} + +/* + Convert string to large community attribute. + When type is already known, please specify both str and type. + + When string includes keyword for each large community value. + Please specify keyword_included as non-zero value. +*/ +struct lcommunity * +lcommunity_str2com (const char *str) +{ + struct lcommunity *lcom = NULL; + enum lcommunity_token token = lcommunity_token_unknown; + struct lcommunity_val lval; + + while ((str = lcommunity_gettoken (str, &lval, &token))) + { + switch (token) + { + case lcommunity_token_val: + if (lcom == NULL) + lcom = lcommunity_new (); + lcommunity_add_val (lcom, &lval); + break; + case lcommunity_token_unknown: + default: + if (lcom) + lcommunity_free (&lcom); + return NULL; + } + } + return lcom; +} + +int +lcommunity_include (struct lcommunity *lcom, u_char *ptr) +{ + int i; + u_char *lcom_ptr; + + for (i = 0; i < lcom->size; i++) { + lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE); + if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0) + return 1; + } + return 0; +} + +/* Convert large community attribute to string. + The large coms will be in 65535:65531:0 format. +*/ +char * +lcommunity_lcom2str (struct lcommunity *lcom, int format) +{ + int i; + u_int8_t *pnt; +#define LCOMMUNITY_STR_DEFAULT_LEN 40 + int str_size; + int str_pnt; + char *str_buf; + int len = 0; + int first = 1; + u_int32_t globaladmin, localdata1, localdata2; + + if (lcom->size == 0) + { + str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1); + str_buf[0] = '\0'; + return str_buf; + } + + /* Prepare buffer. */ + str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1); + str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1; + str_pnt = 0; + + for (i = 0; i < lcom->size; i++) + { + /* Make it sure size is enough. */ + while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size); + } + + /* Space between each value. */ + if (! first) + str_buf[str_pnt++] = ' '; + + pnt = lcom->val + (i * 12); + + globaladmin = (*pnt++ << 24); + globaladmin |= (*pnt++ << 16); + globaladmin |= (*pnt++ << 8); + globaladmin |= (*pnt++); + + localdata1 = (*pnt++ << 24); + localdata1 |= (*pnt++ << 16); + localdata1 |= (*pnt++ << 8); + localdata1 |= (*pnt++); + + localdata2 = (*pnt++ << 24); + localdata2 |= (*pnt++ << 16); + localdata2 |= (*pnt++ << 8); + localdata2 |= (*pnt++); + + len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin, + localdata1, localdata2); + str_pnt += len; + first = 0; + } + return str_buf; +} + +int +lcommunity_match (const struct lcommunity *lcom1, + const struct lcommunity *lcom2) +{ + int i = 0; + int j = 0; + + if (lcom1 == NULL && lcom2 == NULL) + return 1; + + if (lcom1 == NULL || lcom2 == NULL) + return 0; + + if (lcom1->size < lcom2->size) + return 0; + + /* Every community on com2 needs to be on com1 for this to match */ + while (i < lcom1->size && j < lcom2->size) + { + if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0) + j++; + i++; + } + + if (j == lcom2->size) + return 1; + else + return 0; +} + +/* Delete one lcommunity. */ +void +lcommunity_del_val (struct lcommunity *lcom, u_char *ptr) +{ + int i = 0; + int c = 0; + + if (! lcom->val) + return; + + while (i < lcom->size) + { + if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0) + { + c = lcom->size -i -1; + + if (c > 0) + memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE); + + lcom->size--; + + if (lcom->size > 0) + lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val, + lcom_length (lcom)); + else + { + XFREE (MTYPE_COMMUNITY_VAL, lcom->val); + lcom->val = NULL; + } + return; + } + i++; + } +} diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h new file mode 100644 index 000000000..7841b4b9a --- /dev/null +++ b/bgpd/bgp_lcommunity.h @@ -0,0 +1,75 @@ +/* BGP Large Communities Attribute. + +Copyright (C) 2016 Keyur Patel + +This file is part of GNU Zebra. + +GNU Zebra 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. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _QUAGGA_BGP_LCOMMUNITY_H +#define _QUAGGA_BGP_LCOMMUNITY_H + +/* Extended communities attribute string format. */ +#define LCOMMUNITY_FORMAT_ROUTE_MAP 0 +#define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1 +#define LCOMMUNITY_FORMAT_DISPLAY 2 + +/* Large Communities value is twelve octets long. */ +#define LCOMMUNITY_SIZE 12 + +/* Large Communities attribute. */ +struct lcommunity +{ + /* Reference counter. */ + unsigned long refcnt; + + /* Size of Extended Communities attribute. */ + int size; + + /* Extended Communities value. */ + u_int8_t *val; + + /* Human readable format string. */ + char *str; +}; + +/* Extended community value is eight octet. */ +struct lcommunity_val +{ + char val[LCOMMUNITY_SIZE]; +}; + +#define lcom_length(X) ((X)->size * LCOMMUNITY_SIZE) + +extern void lcommunity_init (void); +extern void lcommunity_finish (void); +extern void lcommunity_free (struct lcommunity **); +extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short); +extern struct lcommunity *lcommunity_dup (struct lcommunity *); +extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *); +extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *); +extern struct lcommunity *lcommunity_intern (struct lcommunity *); +extern int lcommunity_cmp (const void *, const void *); +extern void lcommunity_unintern (struct lcommunity **); +extern unsigned int lcommunity_hash_make (void *); +extern struct hash *lcommunity_hash (void); +extern struct lcommunity *lcommunity_str2com (const char *); +extern char *lcommunity_lcom2str (struct lcommunity *, int); +extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *); +extern char *lcommunity_str (struct lcommunity *); +extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr); +extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr); +#endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 6465aad1d..8195e47f4 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -38,6 +38,7 @@ #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_mpath.h" bool @@ -647,6 +648,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, u_char origin, attr_chg; struct community *community, *commerge; struct ecommunity *ecomm, *ecommerge; + struct lcommunity *lcomm, *lcommerge; struct attr_extra *ae; struct attr attr = { 0 }; @@ -711,6 +713,8 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, ae = attr.extra; ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; + lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL; + for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { @@ -745,6 +749,18 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best, else ecomm = ecommunity_dup (ae->ecommunity); } + + if (ae && ae->lcommunity) + { + if (lcomm) + { + lcommerge = lcommunity_merge (lcomm, ae->lcommunity); + lcomm = lcommunity_uniq_sort (lcommerge); + lcommunity_free (&lcommerge); + } + else + lcomm = lcommunity_dup (ae->lcommunity); + } } attr.aspath = aspath; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 913714349..13596fbed 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1,5 +1,6 @@ /* BGP routing information Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro + Copyright (C) 2016 Job Snijders This file is part of GNU Zebra. @@ -44,6 +45,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_regex.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_filter.h" @@ -6428,8 +6430,13 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) vty_out (vty, " Extended Community: %s%s", attr->extra->ecommunity->str, VTY_NEWLINE); - - /* Line 6 display Originator, Cluster-id */ + + /* Line 6 display Large community */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) + vty_out (vty, " Large Community: %s%s", + attr->extra->lcommunity->str, VTY_NEWLINE); + + /* Line 7 display Originator, Cluster-id */ if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { @@ -6452,7 +6459,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo); - /* Line 7 display Uptime */ + /* Line 8 display Uptime */ #ifdef HAVE_CLOCK_MONOTONIC tbuf = time(NULL) - (bgp_clock() - binfo->uptime); vty_out (vty, " Last update: %s", ctime(&tbuf)); @@ -6486,6 +6493,9 @@ enum bgp_show_type bgp_show_type_community_exact, bgp_show_type_community_list, bgp_show_type_community_list_exact, + bgp_show_type_lcommunity_all, + bgp_show_type_lcommunity, + bgp_show_type_lcommunity_list, bgp_show_type_flap_statistics, bgp_show_type_flap_address, bgp_show_type_flap_prefix, @@ -6648,6 +6658,32 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router if (! community_list_exact_match (ri->attr->community, list)) continue; } + if (type == bgp_show_type_community_all) + { + if (! ri->attr->community) + continue; + } + if (type == bgp_show_type_lcommunity) + { + struct lcommunity *lcom = output_arg; + + if (! ri->attr->extra || ! ri->attr->extra->lcommunity || + ! lcommunity_match (ri->attr->extra->lcommunity, lcom)) + continue; + } + if (type == bgp_show_type_lcommunity_list) + { + struct community_list *list = output_arg; + + if (! ri->attr->extra || + ! lcommunity_list_match (ri->attr->extra->lcommunity, list)) + continue; + } + if (type == bgp_show_type_lcommunity_all) + { + if (! ri->attr->extra || ! ri->attr->extra->lcommunity) + continue; + } if (type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix) { @@ -9163,6 +9199,84 @@ DEFUN (show_ipv6_mbgp_community_all, bgp_show_type_community_all, NULL); } +/* large-community */ +DEFUN (show_ip_bgp_lcommunity_all, + show_ip_bgp_lcommunity_all_cmd, + "show ip bgp large-community", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the large-communities\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_lcommunity_all, NULL); +} + +DEFUN (show_ip_bgp_ipv4_lcommunity_all, + show_ip_bgp_ipv4_lcommunity_all_cmd, + "show ip bgp ipv4 (unicast|multicast) large-community", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_lcommunity_all, NULL); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_lcommunity_all, NULL); +} + +DEFUN (show_bgp_lcommunity_all, + show_bgp_lcommunity_all_cmd, + "show bgp large-community", + SHOW_STR + BGP_STR + "Display routes matching the large-communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_lcommunity_all, NULL); +} + +ALIAS (show_bgp_lcommunity_all, + show_bgp_ipv6_lcommunity_all_cmd, + "show bgp ipv6 large-community", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the large-communities\n") + +/* old command */ +DEFUN (show_ipv6_bgp_lcommunity_all, + show_ipv6_bgp_lcommunity_all_cmd, + "show ipv6 bgp large-community", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the large-communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_lcommunity_all, NULL); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_lcommunity_all, + show_ipv6_mbgp_lcommunity_all_cmd, + "show ipv6 mbgp large-community", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the large-communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_lcommunity_all, NULL); +} + + DEFUN (show_bgp_ipv4_route_map, show_bgp_ipv4_route_map_cmd, "show bgp ipv4 route-map WORD", @@ -11398,6 +11512,795 @@ DEFUN (show_bgp_ipv6_safi_community_list_exact, return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi); } +/* + * Large Community show commands. + */ + +DEFUN (show_bgp_afi_lcommunity_all, + show_bgp_afi_lcommunity_all_cmd, + "show bgp (ipv4|ipv6) large-community", + SHOW_STR + BGP_STR + "Address family\n" + "Address family\n" + "Display routes matching the large-communities\n") +{ + afi_t afi; + safi_t safi = SAFI_UNICAST; + + if (bgp_parse_afi(argv[0], &afi)) { + vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_all, NULL); +} + +static int +bgp_show_lcommunity (struct vty *vty, const char *view_name, int argc, + const char **argv, afi_t afi, safi_t safi) +{ + struct lcommunity *lcom; + struct buffer *b; + struct bgp *bgp; + int i; + char *str; + int first = 0; + + /* BGP structure lookup */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + { + if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) + continue; + first = 1; + } + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + str = buffer_getstr (b); + buffer_free (b); + + lcom = lcommunity_str2com (str); + XFREE (MTYPE_TMP, str); + if (! lcom) + { + vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom); +} + +DEFUN (show_ip_bgp_lcommunity, + show_ip_bgp_lcommunity_cmd, + "show ip bgp large-community (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n") +{ + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_lcommunity, + show_ip_bgp_lcommunity2_cmd, + "show ip bgp large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_ip_bgp_lcommunity, + show_ip_bgp_lcommunity3_cmd, + "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the large-communities\n" + "largecommunity number\n" + "largecommunity number\n" + "largecommunity number\n") + +ALIAS (show_ip_bgp_lcommunity, + show_ip_bgp_lcommunity4_cmd, + "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +DEFUN (show_ip_bgp_ipv4_lcommunity, + show_ip_bgp_ipv4_lcommunity_cmd, + "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST); + + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_lcommunity, + show_ip_bgp_ipv4_lcommunity2_cmd, + "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_ip_bgp_ipv4_lcommunity, + show_ip_bgp_ipv4_lcommunity3_cmd, + "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_ip_bgp_ipv4_lcommunity, + show_ip_bgp_ipv4_lcommunity4_cmd, + "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +DEFUN (show_bgp_lcommunity, + show_bgp_lcommunity_cmd, + "show bgp large-community (AA:BB:CC)", + SHOW_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n") +{ + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_lcommunity, + show_bgp_ipv6_lcommunity_cmd, + "show bgp ipv6 large-community (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the large-communities\n" + "large-community number\n") + +ALIAS (show_bgp_lcommunity, + show_bgp_lcommunity2_cmd, + "show bgp large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_lcommunity, + show_bgp_ipv6_lcommunity2_cmd, + "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_lcommunity, + show_bgp_lcommunity3_cmd, + "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_lcommunity, + show_bgp_ipv6_lcommunity3_cmd, + "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_lcommunity, + show_bgp_lcommunity4_cmd, + "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_lcommunity, + show_bgp_ipv6_lcommunity4_cmd, + "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +/* old command */ +DEFUN (show_ipv6_bgp_lcommunity, + show_ipv6_bgp_lcommunity_cmd, + "show ipv6 bgp large-community (AA:BB:CC)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n") +{ + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_lcommunity, + show_ipv6_bgp_lcommunity2_cmd, + "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +/* old command */ +ALIAS (show_ipv6_bgp_lcommunity, + show_ipv6_bgp_lcommunity3_cmd, + "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +/* old command */ +ALIAS (show_ipv6_bgp_lcommunity, + show_ipv6_bgp_lcommunity4_cmd, + "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +/* old command */ +DEFUN (show_ipv6_mbgp_lcommunity, + show_ipv6_mbgp_lcommunity_cmd, + "show ipv6 mbgp large-community (AA:BB:CC)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the large-communities\n" + "large-community number\n") +{ + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_lcommunity, + show_ipv6_mbgp_lcommunity2_cmd, + "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +/* old command */ +ALIAS (show_ipv6_mbgp_lcommunity, + show_ipv6_mbgp_lcommunity3_cmd, + "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +/* old command */ +ALIAS (show_ipv6_mbgp_lcommunity, + show_ipv6_mbgp_lcommunity4_cmd, + "show ipv6 mbgp laarge-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +DEFUN (show_bgp_ipv4_lcommunity, + show_bgp_ipv4_lcommunity_cmd, + "show bgp ipv4 large-community (AA:BB:CC)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the large-communities\n" + "large-community number\n") +{ + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_bgp_ipv4_lcommunity, + show_bgp_ipv4_lcommunity2_cmd, + "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_ipv4_lcommunity, + show_bgp_ipv4_lcommunity3_cmd, + "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_ipv4_lcommunity, + show_bgp_ipv4_lcommunity4_cmd, + "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +DEFUN (show_bgp_ipv4_safi_lcommunity, + show_bgp_ipv4_safi_lcommunity_cmd, + "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST); + + return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_bgp_ipv4_safi_lcommunity, + show_bgp_ipv4_safi_lcommunity2_cmd, + "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_ipv4_safi_lcommunity, + show_bgp_ipv4_safi_lcommunity3_cmd, + "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_ipv4_safi_lcommunity, + show_bgp_ipv4_safi_lcommunity4_cmd, + "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +DEFUN (show_bgp_view_afi_safi_lcommunity_all, + show_bgp_view_afi_safi_lcommunity_all_cmd, + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-communities\n") +{ + int afi; + int safi; + struct bgp *bgp; + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL); +} + +DEFUN (show_bgp_view_afi_safi_lcommunity, + show_bgp_view_afi_safi_lcommunity_cmd, + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC)", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n") +{ + int afi; + int safi; + + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_lcommunity (vty, argv[0], argc-3, &argv[3], afi, safi); +} + +ALIAS (show_bgp_view_afi_safi_lcommunity, + show_bgp_view_afi_safi_lcommunity2_cmd, + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_view_afi_safi_lcommunity, + show_bgp_view_afi_safi_lcommunity3_cmd, + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_view_afi_safi_lcommunity, + show_bgp_view_afi_safi_lcommunity4_cmd, + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +DEFUN (show_bgp_ipv6_safi_lcommunity, + show_bgp_ipv6_safi_lcommunity_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) large-community AA:BB:CC", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_lcommunity (vty, NULL, argc-1, argv+1, AFI_IP6, safi); +} + +ALIAS (show_bgp_ipv6_safi_lcommunity, + show_bgp_ipv6_safi_lcommunity2_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_ipv6_safi_lcommunity, + show_bgp_ipv6_safi_lcommunity3_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +ALIAS (show_bgp_ipv6_safi_lcommunity, + show_bgp_ipv6_safi_lcommunity4_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n") + +static int +bgp_show_lcommunity_list (struct vty *vty, const char *lcom, + afi_t afi, safi_t safi) +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER); + if (list == NULL) + { + vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom, + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_list, list); +} + +DEFUN (show_ip_bgp_lcommunity_list, + show_ip_bgp_lcommunity_list_cmd, + "show ip bgp large-community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_lcommunity_list, + show_ip_bgp_ipv4_lcommunity_list_cmd, + "show ip bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST); + + return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_lcommunity_list, + show_bgp_lcommunity_list_cmd, + "show bgp large-community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_lcommunity_list, + show_bgp_ipv6_lcommunity_list_cmd, + "show bgp ipv6 large-community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_lcommunity_list, + show_ipv6_bgp_lcommunity_list_cmd, + "show ipv6 bgp large-community-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the large-community-list\n" + "large-community-list name\n") +{ + return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_lcommunity_list, + show_ipv6_mbgp_lcommunity_list_cmd, + "show ipv6 mbgp large-community-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the large-community-list\n" + "large-community-list name\n") +{ + return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST); +} + +DEFUN (show_bgp_ipv4_lcommunity_list, + show_bgp_ipv4_lcommunity_list_cmd, + "show bgp ipv4 large-community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + IP_STR + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv4_safi_lcommunity_list, + show_bgp_ipv4_safi_lcommunity_list_cmd, + "show bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST); + + return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_bgp_ipv6_safi_lcommunity_list, + show_bgp_ipv6_safi_lcommunity_list_cmd, + "show bgp ipv6 (encap|multicast|unicast|vpn) large-community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + safi_t safi; + + if (bgp_parse_safi(argv[0], &safi)) { + vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_lcommunity_list (vty, argv[1], AFI_IP6, safi); +} + static int bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, safi_t safi, enum bgp_show_type type) @@ -16409,6 +17312,24 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd); + + /* large-communities */ + install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd); @@ -16506,6 +17427,22 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); + + /* large-community */ + install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); @@ -16514,6 +17451,7 @@ bgp_route_init (void) /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); @@ -16558,6 +17496,14 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_community_list_cmd); + + /* large-community */ + install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd); + install_element (VIEW_NODE, &show_bgp_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); @@ -16604,6 +17550,10 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); @@ -16753,6 +17703,18 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_lcommunity_cmd); + install_element (VIEW_NODE, &show_ip_bgp_lcommunity2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_lcommunity3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_lcommunity4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); @@ -16826,6 +17788,14 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity4_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); @@ -16862,6 +17832,13 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_cmd); install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_bgp_lcommunity_cmd); + install_element (VIEW_NODE, &show_bgp_lcommunity2_cmd); + install_element (VIEW_NODE, &show_bgp_lcommunity3_cmd); + install_element (VIEW_NODE, &show_bgp_lcommunity4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_list_cmd); install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); @@ -16897,6 +17874,10 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); + install_element (RESTRICTED_NODE, &show_bgp_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_bgp_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); @@ -16921,6 +17902,12 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity2_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity3_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity4_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); @@ -16939,6 +17926,12 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_all_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity2_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity3_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity4_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); @@ -16967,6 +17960,16 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 68c78458e..ccd73b6c5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -51,6 +51,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_filter.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_vty.h" /* Memo of route-map commands. @@ -59,6 +60,7 @@ o Cisco route-map match as-path : Done community : Done + lcommunity : Done interface : Not yet ip address : Done ip next-hop : Done @@ -78,6 +80,8 @@ o Cisco route-map as-path tag : Not yet automatic-tag : (This will not be implemented by bgpd) community : Done + large-community : Done + large-comm-list : Done comm-list : Not yet dampning : Not yet default : (This will not be implemented by bgpd) @@ -840,21 +844,93 @@ struct route_map_rule_cmd route_match_community_cmd = route_match_community_free }; +/* Match function for lcommunity match. */ +static route_map_result_t +route_match_lcommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct bgp_info *bgp_info; + struct rmap_community *rcom; + + if (type == RMAP_BGP) + { + bgp_info = object; + rcom = rule; + + list = community_list_lookup (bgp_clist, rcom->name, + LARGE_COMMUNITY_LIST_MASTER); + if (! list) + return RMAP_NOMATCH; + + if (bgp_info->attr->extra && + lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) + return RMAP_MATCH; + + } + return RMAP_NOMATCH; +} + +/* Compile function for community match. */ +static void * +route_match_lcommunity_compile (const char *arg) +{ + struct rmap_community *rcom; + int len; + char *p; + + rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community)); + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (rcom->name, arg, len); + } + else + { + rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); + rcom->exact = 0; + } + return rcom; +} + +/* Compile function for community match. */ +static void +route_match_lcommunity_free (void *rule) +{ + struct rmap_community *rcom = rule; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name); + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom); +} + +/* Route map commands for community matching. */ +struct route_map_rule_cmd route_match_lcommunity_cmd = +{ + "large-community", + route_match_lcommunity, + route_match_lcommunity_compile, + route_match_lcommunity_free +}; + + /* Match function for extcommunity match. */ static route_map_result_t -route_match_ecommunity (void *rule, struct prefix *prefix, +route_match_ecommunity (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct community_list *list; struct bgp_info *bgp_info; - if (type == RMAP_BGP) + if (type == RMAP_BGP) { bgp_info = object; - + if (!bgp_info->attr->extra) return RMAP_NOMATCH; - + list = community_list_lookup (bgp_clist, (char *) rule, EXTCOMMUNITY_LIST_MASTER); if (! list) @@ -1470,6 +1546,225 @@ struct route_map_rule_cmd route_set_community_cmd = route_set_community_free, }; +/* `set community COMMUNITY' */ +struct rmap_lcom_set +{ + struct lcommunity *lcom; + int additive; + int none; +}; + + +/* For lcommunity set mechanism. */ +static route_map_result_t +route_set_lcommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rmap_lcom_set *rcs; + struct bgp_info *binfo; + struct attr *attr; + struct lcommunity *new = NULL; + struct lcommunity *old; + struct lcommunity *merge; + + if (type == RMAP_BGP) + { + rcs = rule; + binfo = object; + attr = binfo->attr; + old = (attr->extra) ? attr->extra->lcommunity : NULL; + + /* "none" case. */ + if (rcs->none) + { + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); + if (attr->extra) { + attr->extra->lcommunity = NULL; + } + /* See the longer comment down below. */ + if (old && old->refcnt == 0) + lcommunity_free(&old); + return RMAP_OKAY; + } + + if (rcs->additive && old) + { + merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom); + + /* HACK: if the old large-community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + lcommunity_free (&old); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + } + else + { + new = lcommunity_dup (rcs->lcom); + } + + /* will be interned by caller if required */ + bgp_attr_extra_get (attr)->lcommunity = new; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + } + + return RMAP_OKAY; +} + +/* Compile function for set community. */ +static void * +route_set_lcommunity_compile (const char *arg) +{ + struct rmap_lcom_set *rcs; + struct lcommunity *lcom = NULL; + char *sp; + int additive = 0; + int none = 0; + + if (strcmp (arg, "none") == 0) + none = 1; + else + { + sp = strstr (arg, "additive"); + + if (sp && sp > arg) + { + /* "additive" keyworkd is included. */ + additive = 1; + *(sp - 1) = '\0'; + } + + lcom = lcommunity_str2com (arg); + + if (additive) + *(sp - 1) = ' '; + + if (! lcom) + return NULL; + } + + rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); + rcs->lcom = lcom; + rcs->additive = additive; + rcs->none = none; + + return rcs; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_free (void *rule) +{ + struct rmap_lcom_set *rcs = rule; + + if (rcs->lcom) { + lcommunity_free (&rcs->lcom); + } + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_cmd = +{ + "large-community", + route_set_lcommunity, + route_set_lcommunity_compile, + route_set_lcommunity_free, +}; + +/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */ + +/* For large community set mechanism. */ +static route_map_result_t +route_set_lcommunity_delete (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct lcommunity *merge; + struct lcommunity *new; + struct lcommunity *old; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + if (! rule) + return RMAP_OKAY; + + binfo = object; + list = community_list_lookup (bgp_clist, rule, + LARGE_COMMUNITY_LIST_MASTER); + old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL); + + if (list && old) + { + merge = lcommunity_list_match_delete (lcommunity_dup (old), list); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + + /* HACK: if the old community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + lcommunity_free (&old); + + if (new->size == 0) + { + binfo->attr->extra->lcommunity = NULL; + binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + lcommunity_free (&new); + } + else + { + binfo->attr->extra->lcommunity = new; + binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + } + } + } + + return RMAP_OKAY; +} + +/* Compile function for set lcommunity. */ +static void * +route_set_lcommunity_delete_compile (const char *arg) +{ + char *p; + char *str; + int len; + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (str, arg, len); + } + else + str = NULL; + + return str; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_delete_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set lcommunity rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_delete_cmd = +{ + "large-comm-list", + route_set_lcommunity_delete, + route_set_lcommunity_delete_compile, + route_set_lcommunity_delete_free, +}; + + /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ @@ -2957,6 +3252,32 @@ ALIAS (no_match_community, "Community-list name\n" "Do exact matching of communities\n") +DEFUN (match_lcommunity, + match_lcommunity_cmd, + "match large-community (<1-99>|<100-500>|WORD)", + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "large-community", argv[0]); +} + +DEFUN (no_match_lcommunity, + no_match_lcommunity_cmd, + "no match large-community (<1-99>|<100-500>|WORD)", + NO_STR + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n") +{ + return bgp_route_match_delete (vty, vty->index, "large-community", NULL); +} + + DEFUN (match_ecommunity, match_ecommunity_cmd, "match extcommunity (<1-99>|<100-500>|WORD)", @@ -3537,6 +3858,104 @@ ALIAS (no_set_community_delete, "Community-list name\n" "Delete matching communities\n") + +DEFUN (set_lcommunity, + set_lcommunity_cmd, + "set large-community .AA:BB:CC", + SET_STR + "BGP large community attribute\n" + "Large Community number in aa:bb:cc format or additive\n") +{ + int ret; + char *str; + + str = argv_concat (argv, argc, 0); + ret = bgp_route_set_add (vty, vty->index, "large-community", str); + XFREE (MTYPE_TMP, str); + + return ret; +} + +DEFUN (set_lcommunity_none, + set_lcommunity_none_cmd, + "set large-community none", + SET_STR + "BGP large community attribute\n" + "No large community attribute\n") +{ + return bgp_route_set_add (vty, vty->index, "large-community", "none"); +} + +DEFUN (no_set_lcommunity, + no_set_lcommunity_cmd, + "no set large-community", + NO_STR + SET_STR + "BGP large community attribute\n" + "Large community\n") +{ + return bgp_route_set_delete (vty, vty->index, "large-community", NULL); +} + +ALIAS (no_set_lcommunity, + no_set_lcommunity_val_cmd, + "no set large-community .AA:BB:CC", + NO_STR + SET_STR + "BGP large community attribute\n" + "Large community in .AA:BB:CC format or additive\n") + +ALIAS (no_set_lcommunity, + no_set_lcommunity_none_cmd, + "no set large-community none", + NO_STR + SET_STR + "BGP community attribute\n" + "No community attribute\n") + +DEFUN (set_lcommunity_delete, + set_lcommunity_delete_cmd, + "set large-comm-list (<1-99>|<100-500>|WORD) delete", + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") +{ + char *str; + + str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1); + strcpy (str, argv[0]); + strcpy (str + strlen (argv[0]), " delete"); + + bgp_route_set_add (vty, vty->index, "large-comm-list", str); + + XFREE (MTYPE_TMP, str); + return CMD_SUCCESS; +} + +DEFUN (no_set_lcommunity_delete, + no_set_lcommunity_delete_cmd, + "no set large-comm-list", + NO_STR + SET_STR + "set BGP large community list (for deletion)\n") +{ + return bgp_route_set_delete (vty, vty->index, "large-comm-list", NULL); +} + +ALIAS (no_set_lcommunity_delete, + no_set_lcommunity_delete_val_cmd, + "no set large-comm-list (<1-99>|<100-500>|WORD) delete", + NO_STR + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") + DEFUN (set_ecommunity_rt, set_ecommunity_rt_cmd, "set extcommunity rt .ASN:nn_or_IP-address:nn", @@ -4095,6 +4514,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ip_route_source_prefix_list_cmd); route_map_install_match (&route_match_aspath_cmd); route_map_install_match (&route_match_community_cmd); + route_map_install_match (&route_match_lcommunity_cmd); route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_local_pref_cmd); route_map_install_match (&route_match_metric_cmd); @@ -4113,6 +4533,8 @@ bgp_route_map_init (void) route_map_install_set (&route_set_aggregator_as_cmd); route_map_install_set (&route_set_community_cmd); route_map_install_set (&route_set_community_delete_cmd); + route_map_install_set (&route_set_lcommunity_cmd); + route_map_install_set (&route_set_lcommunity_delete_cmd); route_map_install_set (&route_set_vpnv4_nexthop_cmd); route_map_install_set (&route_set_originator_id_cmd); route_map_install_set (&route_set_ecommunity_rt_cmd); @@ -4157,6 +4579,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_match_community_cmd); install_element (RMAP_NODE, &no_match_community_val_cmd); install_element (RMAP_NODE, &no_match_community_exact_cmd); + install_element (RMAP_NODE, &match_lcommunity_cmd); + install_element (RMAP_NODE, &no_match_lcommunity_cmd); install_element (RMAP_NODE, &match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_val_cmd); @@ -4208,6 +4632,14 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &set_community_delete_cmd); install_element (RMAP_NODE, &no_set_community_delete_cmd); install_element (RMAP_NODE, &no_set_community_delete_val_cmd); + install_element (RMAP_NODE, &set_lcommunity_cmd); + install_element (RMAP_NODE, &set_lcommunity_none_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_val_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_none_cmd); + install_element (RMAP_NODE, &set_lcommunity_delete_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_delete_val_cmd); install_element (RMAP_NODE, &set_ecommunity_rt_cmd); install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd); install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9f09016a9..0040d62b6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -38,6 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" @@ -2364,13 +2365,15 @@ DEFUN (no_neighbor_send_community, /* neighbor send-community extended. */ DEFUN (neighbor_send_community_type, neighbor_send_community_type_cmd, - NEIGHBOR_CMD2 "send-community (both|extended|standard)", + NEIGHBOR_CMD2 "send-community (both|all|extended|standard|large)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" - "Send Standard and Extended Community attributes\n" + "Send Standard, Large and Extended Community attributes\n" + "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" - "Send Standard Community attributes\n") + "Send Standard Community attributes\n" + "Send Large Community attributes\n") { if (strncmp (argv[1], "s", 1) == 0) return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), @@ -2380,23 +2383,30 @@ DEFUN (neighbor_send_community_type, return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); + if (strncmp (argv[1], "l", 1) == 0) + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_LARGE_COMMUNITY); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY| - PEER_FLAG_SEND_EXT_COMMUNITY)); + PEER_FLAG_SEND_EXT_COMMUNITY| + PEER_FLAG_SEND_LARGE_COMMUNITY)); } DEFUN (no_neighbor_send_community_type, no_neighbor_send_community_type_cmd, - NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)", + NO_NEIGHBOR_CMD2 "send-community (both|all|extended|standard|large)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" - "Send Standard and Extended Community attributes\n" + "Send Standard, Large and Extended Community attributes\n" + "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" - "Send Standard Community attributes\n") + "Send Standard Community attributes\n" + "Send Large Community attributes\n") { if (strncmp (argv[1], "s", 1) == 0) return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), @@ -2406,11 +2416,16 @@ DEFUN (no_neighbor_send_community_type, return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); + if (strncmp (argv[1], "l", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_LARGE_COMMUNITY); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY | - PEER_FLAG_SEND_EXT_COMMUNITY)); + PEER_FLAG_SEND_EXT_COMMUNITY| + PEER_FLAG_SEND_LARGE_COMMUNITY)); } /* neighbor soft-reconfig. */ @@ -7434,7 +7449,12 @@ DEFUN (show_bgp_memory, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct ecommunity)), VTY_NEWLINE); - + if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY))) + vty_out (vty, "%ld BGP large-community entries, using %s of memory%s", + count, + mtype_memstr (memstrbuf, sizeof (memstrbuf), + count * sizeof (struct lcommunity)), + VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_CLUSTER))) vty_out (vty, "%ld Cluster lists, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), @@ -8242,14 +8262,18 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) - || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) + || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) + || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) { vty_out (vty, " Community attribute sent to this neighbor"); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) - && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) - vty_out (vty, "(both)%s", VTY_NEWLINE); + && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) + && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, "(all)%s", VTY_NEWLINE); else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, "(extended)%s", VTY_NEWLINE); + else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, "(large)%s", VTY_NEWLINE); else vty_out (vty, "(standard)%s", VTY_NEWLINE); } @@ -9099,6 +9123,35 @@ DEFUN (show_ip_bgp_community_info, return CMD_SUCCESS; } +static void +lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct lcommunity *lcom; + + lcom = (struct lcommunity *) backet->data; + vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt, + lcommunity_str (lcom), VTY_NEWLINE); +} + +/* Show BGP's community internal data. */ +DEFUN (show_ip_bgp_lcommunity_info, + show_ip_bgp_lcommunity_info_cmd, + "show ip bgp large-community-info", + SHOW_STR + IP_STR + BGP_STR + "List all bgp large-community information\n") +{ + vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE); + + hash_iterate (lcommunity_hash (), + (void (*) (struct hash_backet *, void *)) + lcommunity_show_all_iterator, + vty); + + return CMD_SUCCESS; +} + DEFUN (show_ip_bgp_attr_info, show_ip_bgp_attr_info_cmd, "show ip bgp attribute-info", @@ -11208,6 +11261,9 @@ bgp_vty_init (void) /* "show ip bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); + /* "show ip bgp large-community" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd); + /* "show ip bgp attribute-info" commands. */ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); @@ -11693,6 +11749,359 @@ DEFUN (show_ip_community_list_arg, return CMD_SUCCESS; } +/* + * Large Community code. + */ +static int +lcommunity_list_set_vty (struct vty *vty, int argc, const char **argv, + int style, int reject_all_digit_name) +{ + int ret; + int direct; + char *str; + + /* Check the list type. */ + if (strncmp (argv[1], "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + direct = COMMUNITY_DENY; + else + { + vty_out (vty, "%% Matching condition must be permit or deny%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* All digit name check. */ + if (reject_all_digit_name && all_digit (argv[0])) + { + vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Concat community string argument. */ + if (argc > 1) + str = argv_concat (argv, argc, 2); + else + str = NULL; + + ret = lcommunity_list_set (bgp_clist, argv[0], str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +static int +lcommunity_list_unset_vty (struct vty *vty, int argc, const char **argv, + int style) +{ + int ret; + int direct = 0; + char *str = NULL; + + if (argc > 1) + { + /* Check the list direct. */ + if (strncmp (argv[1], "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + direct = COMMUNITY_DENY; + else + { + vty_out (vty, "%% Matching condition must be permit or deny%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Concat community string argument. */ + str = argv_concat (argv, argc, 2); + } + + /* Unset community list. */ + ret = lcommunity_list_unset (bgp_clist, argv[0], str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* "large-community-list" keyword help string. */ +#define LCOMMUNITY_LIST_STR "Add a large community list entry\n" +#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n" + +DEFUN (ip_lcommunity_list_standard, + ip_lcommunity_list_standard_cmd, + "ip large-community-list <1-99> (deny|permit) .AA:BB:CC", + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (standard)\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + LCOMMUNITY_VAL_STR) +{ + return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0); +} + +ALIAS (ip_lcommunity_list_standard, + ip_lcommunity_list_standard2_cmd, + "ip large-community-list <1-99> (deny|permit)", + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (standard)\n" + "Specify large community to reject\n" + "Specify large community to accept\n") + +DEFUN (ip_lcommunity_list_expanded, + ip_lcommunity_list_expanded_cmd, + "ip large-community-list <100-500> (deny|permit) .LINE", + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (expanded)\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + "An ordered list as a regular-expression\n") +{ + return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0); +} + +DEFUN (ip_lcommunity_list_name_standard, + ip_lcommunity_list_name_standard_cmd, + "ip large-community-list standard WORD (deny|permit) .AA:BB.CC", + IP_STR + LCOMMUNITY_LIST_STR + "Specify standard large-community-list\n" + "Large Community list name\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + LCOMMUNITY_VAL_STR) +{ + return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1); +} + +ALIAS (ip_lcommunity_list_name_standard, + ip_lcommunity_list_name_standard2_cmd, + "ip large-community-list standard WORD (deny|permit)", + IP_STR + LCOMMUNITY_LIST_STR + "Specify standard large-community-list\n" + "Large Community list name\n" + "Specify large community to reject\n" + "Specify large community to accept\n") + +DEFUN (ip_lcommunity_list_name_expanded, + ip_lcommunity_list_name_expanded_cmd, + "ip large-community-list expanded WORD (deny|permit) .LINE", + IP_STR + LCOMMUNITY_LIST_STR + "Specify expanded large-community-list\n" + "Large Community list name\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + "An ordered list as a regular-expression\n") +{ + return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1); +} + +DEFUN (no_ip_lcommunity_list_standard_all, + no_ip_lcommunity_list_standard_all_cmd, + "no ip large-community-list <1-99>", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (standard)\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_expanded_all, + no_ip_lcommunity_list_expanded_all_cmd, + "no ip large-community-list <100-500>", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (expanded)\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_lcommunity_list_name_standard_all, + no_ip_lcommunity_list_name_standard_all_cmd, + "no ip large-community-list standard WORD", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Specify standard large-community-list\n" + "Large Community list name\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_name_expanded_all, + no_ip_lcommunity_list_name_expanded_all_cmd, + "no ip large-community-list expanded WORD", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Specify expanded large-community-list\n" + "Large Community list name\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_lcommunity_list_standard, + no_ip_lcommunity_list_standard_cmd, + "no ip large-community-list <1-99> (deny|permit) .AA:.AA:NN", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (standard)\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + LCOMMUNITY_VAL_STR) +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_expanded, + no_ip_lcommunity_list_expanded_cmd, + "no ip large-community-list <100-500> (deny|permit) .LINE", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Large Community list number (expanded)\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + "An ordered list as a regular-expression\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_lcommunity_list_name_standard, + no_ip_lcommunity_list_name_standard_cmd, + "no ip large-community-list standard WORD (deny|permit) .AA:.AA:NN", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Specify standard large-community-list\n" + "Large Community list name\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + LCOMMUNITY_VAL_STR) +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_name_expanded, + no_ip_lcommunity_list_name_expanded_cmd, + "no ip large-community-list expanded WORD (deny|permit) .LINE", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Specify expanded large-community-list\n" + "Large community list name\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + "An ordered list as a regular-expression\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +static void +lcommunity_list_show (struct vty *vty, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry == list->head) + { + if (all_digit (list->name)) + vty_out (vty, "Large community %s list %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + "standard" : "(expanded) access", + list->name, VTY_NEWLINE); + else + vty_out (vty, "Named large community %s list %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + "standard" : "expanded", + list->name, VTY_NEWLINE); + } + if (entry->any) + vty_out (vty, " %s%s", + community_direct_str (entry->direct), VTY_NEWLINE); + else + vty_out (vty, " %s %s%s", + community_direct_str (entry->direct), + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + entry->u.ecom->str : entry->config, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_lcommunity_list, + show_ip_lcommunity_list_cmd, + "show ip large-community-list", + SHOW_STR + IP_STR + "List large-community list\n") +{ + struct community_list *list; + struct community_list_master *cm; + + cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); + if (! cm) + return CMD_SUCCESS; + + for (list = cm->num.head; list; list = list->next) + lcommunity_list_show (vty, list); + + for (list = cm->str.head; list; list = list->next) + lcommunity_list_show (vty, list); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_lcommunity_list_arg, + show_ip_lcommunity_list_arg_cmd, + "show ip large-community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + "List large-community list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, argv[0], LARGE_COMMUNITY_LIST_MASTER); + if (! list) + { + vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + lcommunity_list_show (vty, list); + + return CMD_SUCCESS; +} + static int extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv, int style, int reject_all_digit_name) @@ -12115,6 +12524,30 @@ community_list_config_write (struct vty *vty) community_list_config_str (entry), VTY_NEWLINE); write++; } + + + /* lcommunity-list. */ + cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); + + for (list = cm->num.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip large-community-list %s %s %s%s", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), VTY_NEWLINE); + write++; + } + for (list = cm->str.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip large-community-list %s %s %s %s%s", + entry->style == LARGE_COMMUNITY_LIST_STANDARD + ? "standard" : "expanded", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), VTY_NEWLINE); + write++; + } + return write; } @@ -12165,4 +12598,22 @@ community_list_vty (void) install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); + + /* Large Community List */ + install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_standard2_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard2_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd); + install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd); } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6189411ee..6aeecb13d 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -627,6 +627,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY); } /* Clear neighbor default_originate_rmap */ @@ -863,6 +864,7 @@ peer_new (struct bgp *bgp) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY); } peer->orf_plist[afi][safi] = NULL; } @@ -2505,6 +2507,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out }, { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out }, { PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out }, + { PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out }, { PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in }, { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset }, { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset }, @@ -5111,23 +5114,31 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) { if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) - && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) - vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE); + && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) + && peer_af_flag_check(peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, " neighbor %s send-community all%s", addr, VTY_NEWLINE); else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " neighbor %s send-community extended%s", addr, VTY_NEWLINE); + else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, " neighbor %s send-community large%s", + addr, VTY_NEWLINE); else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE); } else { if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) - && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) - vty_out (vty, " no neighbor %s send-community both%s", + && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) + && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, " no neighbor %s send-community all%s", addr, VTY_NEWLINE); else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " no neighbor %s send-community extended%s", addr, VTY_NEWLINE); + else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, " no neighbor %s send-community large%s", + addr, VTY_NEWLINE); else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) vty_out (vty, " no neighbor %s send-community%s", addr, VTY_NEWLINE); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a6cc34ea0..c2df672c2 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -425,6 +425,7 @@ struct peer #define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */ #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */ #define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */ +#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 18) /* Send large Communities */ /* MD5 password */ char *password; @@ -655,6 +656,7 @@ struct bgp_nlri #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 #define BGP_ATTR_ENCAP 23 +#define BGP_ATTR_LARGE_COMMUNITIES 32 /* BGP update origin. */ #define BGP_ORIGIN_IGP 0 diff --git a/lib/memtypes.c b/lib/memtypes.c index ba2bacfa8..f9eae938e 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -157,6 +157,9 @@ struct memory_list memory_list_bgp[] = { MTYPE_BGP_AGGREGATE, "BGP aggregate" }, { MTYPE_BGP_ADDR, "BGP own address" }, { MTYPE_ENCAP_TLV, "ENCAP TLV", }, + { MTYPE_LCOMMUNITY, "Large Community", }, + { MTYPE_LCOMMUNITY_STR, "Large Community str", }, + { MTYPE_LCOMMUNITY_VAL, "Large Community val", }, { -1, NULL } }; From 7fa7acb4926f2a0d1fb5eb0834ae6c60b8ba5147 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 20 Jan 2017 18:16:04 +0000 Subject: [PATCH 1263/1342] bgpd: Fix unhandled enum warning for AFI_ETHER * bgp_open.c: (bgp_afi_safi_valid_indices) We have AFI_ETHER defined, but don't handle it at this point. --- bgpd/bgp_open.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 7b8b6577e..280042306 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -143,6 +143,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) case SAFI_ENCAP: return 1; } + case AFI_ETHER: + default: break; } From 23426d21d5ceccec47d80288e8cf411e44f59e58 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 23 Jan 2017 10:55:55 +0000 Subject: [PATCH 1264/1342] lib: routemap.h depends on prefix.h --- lib/routemap.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/routemap.h b/lib/routemap.h index 48fafaf28..68129e1d9 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -22,6 +22,8 @@ #ifndef _ZEBRA_ROUTEMAP_H #define _ZEBRA_ROUTEMAP_H +#include "prefix.h" + /* Route map's type. */ enum route_map_type { From b1887c852c5c040e109925887ec8c1ca8c428730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 24 Jan 2017 16:42:19 +0200 Subject: [PATCH 1265/1342] doc: add initial nhrpd documentation --- doc/Makefile.am | 6 +- doc/bgpd.8 | 1 + doc/install.texi | 1 + doc/nhrpd.8 | 105 ++++++++++++++++++++++++++++++++++ doc/nhrpd.texi | 143 +++++++++++++++++++++++++++++++++++++++++++++++ doc/quagga.texi | 2 + doc/zebra.8 | 1 + 7 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 doc/nhrpd.8 create mode 100644 doc/nhrpd.texi diff --git a/doc/Makefile.am b/doc/Makefile.am index 42af37c73..a4d6d9562 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -95,6 +95,10 @@ if RIPNGD man_MANS += ripngd.8 endif +if NHRPD +man_MANS += nhrpd.8 +endif + if VTYSH man_MANS += vtysh.1 endif @@ -109,7 +113,7 @@ endif EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ - ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ + ripngd.8 nhrpd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) \ diff --git a/doc/bgpd.8 b/doc/bgpd.8 index 1a873b426..e680ddb23 100644 --- a/doc/bgpd.8 +++ b/doc/bgpd.8 @@ -109,6 +109,7 @@ debugging options, see the Info file, or the source for details. .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), +.BR nhrpd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS diff --git a/doc/install.texi b/doc/install.texi index 811ad9ae8..4ad282a3f 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -283,6 +283,7 @@ ospf6d 2606/tcp # OSPF6d vty ospfapi 2607/tcp # ospfapi isisd 2608/tcp # ISISd vty pimd 2611/tcp # PIMd vty +nhrpd 2612/tcp # nhrpd vty @end example If you use a FreeBSD newer than 2.2.8, the above entries are already diff --git a/doc/nhrpd.8 b/doc/nhrpd.8 new file mode 100644 index 000000000..e227c207f --- /dev/null +++ b/doc/nhrpd.8 @@ -0,0 +1,105 @@ +.TH NHRP 8 "24 January 2017" "Quagga NHRP daemon" "Version 1.1" +.SH NAME +nhrpd \- a Next Hop Routing Protocol routing engine for use with Quagga routing software. +.SH SYNOPSIS +.B nhrpd +[ +.B \-dhv +] [ +.B \-f +.I config-file +] [ +.B \-i +.I pid-file +] [ +.B \-P +.I port-number +] [ +.B \-A +.I vty-address +] [ +.B \-u +.I user +] [ +.B \-g +.I group +] +.SH DESCRIPTION +.B nhrpd +is a routing component that works with the +.B Quagga +routing engine. +.SH OPTIONS +Options available for the +.B nhrpd +command: +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/nhrpd.conf\fR. +.TP +\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR +Specify the group to run as. Default is \fIquagga\fR. +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When nhrpd starts its process identifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart nhrpd. The likely default is \fB\fI/var/run/nhrpd.pid\fR. +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the nhrpd VTY will listen on. This defaults to +2608, as specified in \fB\fI/etc/services\fR. +.TP +\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR +Specify the address that the nhrpd VTY will listen on. Default is all +interfaces. +.TP +\fB\-u\fR, \fB\-\-user \fR\fIuser\fR +Specify the user to run as. Default is \fIquagga\fR. +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. +.SH FILES +.TP +.BI /usr/local/sbin/nhrpd +The default location of the +.B nhrpd +binary. +.TP +.BI /usr/local/etc/nhrpd.conf +The default location of the +.B nhrpd +config file. +.TP +.BI $(PWD)/nhrpd.log +If the +.B nhrpd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBnhrpd\fR. +.SH WARNING +This man page is intended to be a quick reference for command line +options. The definitive document is the Info file \fBQuagga\fR. +.SH DIAGNOSTICS +The nhrpd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBnhrpd\fR supports many +debugging options, see the Info file, or the source for details. +.SH "SEE ALSO" +.BR bgpd (8), +.BR ripd (8), +.BR ripngd (8), +.BR ospfd (8), +.BR ospf6d (8), +.BR zebra (8), +.BR vtysh (1) + +.B nhrpd +eats bugs for breakfast. If you have food for the maintainers try +.BI http://bugzilla.quagga.net +.SH AUTHORS +Timo Teräs diff --git a/doc/nhrpd.texi b/doc/nhrpd.texi new file mode 100644 index 000000000..6caf5a629 --- /dev/null +++ b/doc/nhrpd.texi @@ -0,0 +1,143 @@ +@cindex NHRP +@node NHRP +@chapter NHRP + +@command{nhrpd} is a daemon to support Next Hop Routing Protocol (NHRP). +NHRP is described in RFC2332. + +NHRP is used to improve the efficiency of routing computer network +traffic over Non-Broadcast, Multiple Access (NBMA) Networks. NHRP provides +an ARP-like solution that allows a system to dynamically learn the NBMA +address of the other systems that are part of that network, allowing +these systems to directly communicate without requiring traffic to use +an intermediate hop. + +Cisco Dynamic Multipoint VPN (DMVPN) is based on NHRP, and Quagga nrhpd +implements this scenario. + +@menu +* Routing Design:: +* Configuring NHRP:: +* Hub Functionality:: +* Integration with IKE:: +* NHRP Events:: +* Configuration Example:: +@end menu + +@node Routing Design +@section Routing Design + +nhrpd never handles routing of prefixes itself. You need to run some +real routing protocol (e.g. BGP) to advertise routes over the tunnels. +What nhrpd does it establishes 'shortcut routes' that optimizes the +routing protocol to avoid going through extra nodes in NBMA GRE mesh. + +nhrpd does route NHRP domain addresses individually using per-host prefixes. +This is similar to Cisco FlexVPN; but in contrast to opennhrp which uses +a generic subnet route. + +To create NBMA GRE tunnel you might use the following (linux terminal +commands): +@example +@group + ip tunnel add gre1 mode gre key 42 ttl 64 + ip addr add 10.255.255.2/32 dev gre1 + ip link set gre1 up +@end group +@end example + +Note that the IP-address is assigned as host prefix to gre1. nhrpd will +automatically create additional host routes pointing to gre1 when +a connection with these hosts is established. + +The gre1 subnet prefix should be announced by routing protocol from the +hub nodes (e.g. BGP 'network' announce). This allows the routing protocol +to decide which is the closest hub and determine the relay hub on prefix +basis when direct tunnel is not established. + +nhrpd will redistribute directly connected neighbors to zebra. Within +hub nodes, these routes should be internally redistributed using some +routing protocol (e.g. iBGP) to allow hubs to be able to relay all traffic. + +This can be achieved in hubs with the following bgp configuration (network +command defines the GRE subnet): +@example +@group +router bgp 65555 + network 172.16.0.0/16 + redistribute nhrp +@end group +@end example + + +@node Configuring NHRP +@section Configuring NHRP + +FIXME + +@node Hub Functionality +@section Hub Functionality + +In addition to routing nhrp redistributed host prefixes, the hub nodes +are also responsible to send NHRP Traffic Indication messages that +trigger creation of the shortcut tunnels. + +nhrpd sends Traffic Indication messages based on network traffic captured +using NFLOG. Typically you want to send Traffic Indications for network +traffic that is routed from gre1 back to gre1 in rate limited manner. +This can be achieved with the following iptables rule. + +@example +@group +iptables -A FORWARD -i gre1 -o gre1 \ + -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \ + --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 \ + --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128 +@end group +@end example + +You can fine tune the src/dstmask according to the prefix lengths you +announce internal, add additional IP range matches, or rate limitation +if needed. However, the above should be good in most cases. + +This kernel NFLOG target's nflog-group is configured in global nhrp config +with: +@example +@group +nhrp nflog-group 1 +@end group +@end example + +To start sending these traffic notices out from hubs, use the nhrp +per-interface directive: +@example +@group +interface gre1 + ip nhrp redirect +@end group +@end example + +@node Integration with IKE +@section Integration with IKE + +nhrpd needs tight integration with IKE daemon for various reasons. +Currently only strongSwan is supported as IKE daemon. + +nhrpd connects to strongSwan using VICI protocol based on UNIX socket +(hardcoded now as /var/run/charon.vici). + +strongSwan currently needs few patches applied. Please check out the +@uref{http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras-release,release} +and +@uref{http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras,working tree} +git repositories for the patches. + +@node NHRP Events +@section NHRP Events + +FIXME + +@node Configuration Example +@section Configuration Example + +FIXME diff --git a/doc/quagga.texi b/doc/quagga.texi index 6831b30cd..bcf23de7c 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -86,6 +86,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of * OSPFv2:: * OSPFv3:: * ISIS:: +* NHRP:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: @@ -111,6 +112,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of @include ospfd.texi @include ospf6d.texi @include isisd.texi +@include nhrpd.texi @include bgpd.texi @include routeserver.texi @include vtysh.texi diff --git a/doc/zebra.8 b/doc/zebra.8 index a40909a69..6f70389fe 100644 --- a/doc/zebra.8 +++ b/doc/zebra.8 @@ -119,6 +119,7 @@ debugging options, see the Info file, or the source for details. .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), +.BR nhrpd (8), .BR vtysh (1) .SH BUGS .B zebra From ac728fd929f5b949364089c4f0d95cfa322a7683 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 27 Jan 2017 11:07:24 +0000 Subject: [PATCH 1266/1342] nhrpd: Makefile.am needs to specify the headers, for dist tarballs to work --- nhrpd/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nhrpd/Makefile.am b/nhrpd/Makefile.am index 00ecc7f3f..a9f70e2a3 100644 --- a/nhrpd/Makefile.am +++ b/nhrpd/Makefile.am @@ -32,4 +32,7 @@ nhrpd_SOURCES = \ nhrpd_LDADD = ../lib/libzebra.la @LIBCAP@ @CARES_LIBS@ +noinst_HEADERS = debug.h netlink.h nhrpd.h vici.h znl.h list.h \ + nhrp_protocol.h os.h zbuf.h + #dist_examples_DATA = nhrpd.conf.sample From 461649d3346a15a4b8be64156181bc2dac7a538e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 27 Jan 2017 11:19:48 +0000 Subject: [PATCH 1267/1342] doc: nhrpd.texi needs to referenced by Makefile for dist tarballs --- doc/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index a4d6d9562..c7b289172 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -50,7 +50,8 @@ quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ - snmptrap.texi ospf_fundamentals.texi isisd.texi $(figures_txt) + snmptrap.texi ospf_fundamentals.texi isisd.texi nhrpd.texi \ + $(figures_txt) .png.eps: $(PNGTOEPS) $< "$@" From a04d836427dcea903edf3d6aea3c0978b8ba1300 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 27 Jan 2017 11:37:36 +0000 Subject: [PATCH 1268/1342] release: Add release.sh script and update HACKING.md accordingly. --- HACKING.md | 67 ++++++++++++++++++++------------------- release.sh | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 33 deletions(-) create mode 100755 release.sh diff --git a/HACKING.md b/HACKING.md index e7e4cd7e2..4b0ff5487 100644 --- a/HACKING.md +++ b/HACKING.md @@ -440,57 +440,58 @@ using the srcdir variable. RELEASE PROCEDURE ================= +To make a release: + +- Edit configure.ac, bump the version and commit the change with + a "release: - Create a fresh tar archive of the quagga.net repository, and do a - test build: + test build. Use git archive to ensure it consists of files in the + repository, and to carry out the keyword expansions. Do NOT do this in + a subdirectory of the Quagga sources, autoconf will think it’s a + sub-package and fail to include neccessary files. - vim configure.ac - git commit -m "release: 0.99.99.99" - git tag -u 54CD2E60 quagga-0.99.99.99 - git push savannah tag quagga-0.99.99.99 + git archive ... | tar xC .. - git archive --prefix=quagga-release/ quagga-0.99.99.99 | tar xC /tmp - git log quagga-0.99.99.98..quagga-0.99.99.99 > \ - /tmp/quagga-release/quagga-0.99.99.99.changelog.txt - cd /tmp/quagga-release + autoreconf -i && ./configure && make && make dist-gzip - autoreconf -i - ./configure - make - make dist-gzip +- Similarly test the dist tarball produced. This is the tarball to be + released. This is important. - gunzip < quagga-0.99.99.99.tar.gz > quagga-0.99.99.99.tar - xz -6e < quagga-0.99.99.99.tar > quagga-0.99.99.99.tar.xz - gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar +- Sign the dist tarball to be released + + gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar - scp quagga-0.99.99.99.* username@dl.sv.nongnu.org:/releases/quagga - +The 'release.sh' script, if finishes successfully, will print out +instructions on the files it has created and the details on remaining steps +to be carried out to complete the release. Which roughly are: - Do NOT do this in a subdirectory of the Quagga sources, autoconf - will think it’s a sub-package and fail to include neccessary files. +- Upload the release tarball, its PGP signature, and the full changelog + to the public release area on Savannah - Add the version number on https://bugzilla.quagga.net/, under Administration, Products, “Quaggaâ€, Edit versions, Add a version. -- Edit the wiki on - https://wiki.quagga.net/wiki/index.php/Release\_status - - Post a news entry on Savannah - Send a mail to quagga-dev and quagga-users -The tarball which ‘make dist’ creates is the tarball to be released! The -git-archive step ensures you’re working with code corresponding to that in -the official repository, and also carries out keyword expansion. If any -errors occur, move tags as needed and start over from the fresh checkouts. -Do not append to tarballs, as this has produced non-standards-conforming -tarballs in the past. - -See also: +If any errors occur, move tags as needed and start over again with the +release.sh script. Do not try to append stuff to tarballs, as this has +produced non-standards-conforming tarballs in the past. [TODO: collation of a list of deprecated commands. Possibly can be scripted to extract from vtysh/vtysh\_cmd.c] diff --git a/release.sh b/release.sh new file mode 100755 index 000000000..d57ea981b --- /dev/null +++ b/release.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +if [ $# -ne 2 ] ; then + echo "usage: $0 " + exit +fi + +errmsg () { + echo "Error occurred. To rerun you may first need to delete the tag". + exit 1 +} + +trap errmsg ERR + +REL=${1:?Release version must be given as first argument!} +PREV=${2:?Previous release version must be given as second argument!} + +TMPDIR=`mktemp -d /tmp/quagga-rel-XXXXXXXXX` + +if [ ! -d $TMPDIR ] ; then + echo "Problem making temp directory ${TMPDIR}!" + exit 1; +fi + +echo "Tagging branch head as release ${REL}" + +git tag -u 0x6FE57CA8C1A4AEA6 -m "Quagga release $REL" ${REL} + +mkdir -p ${TMPDIR}/a || exit 1 +mkdir -p ${TMPDIR}/verify || exit 1 + +echo "Making git archive" + +( git archive ${REL} | tar xC ${TMPDIR}/a ) || exit 1 + +git log ${PREV}..${REL} > ${TMPDIR}/a/${REL}.changelog.txt || exit 1 +git log --pretty=%s ${PREV}..${REL} > ${TMPDIR}/a/${REL}.subjects.txt || exit 1 + +cd ${TMPDIR}/a || exit 1 + +echo "Doing test build of archive file and making dist tarball" + +(autoreconf -i && ./configure && make -j && make dist-gzip) || exit 1 + +echo "Verifying dist tarball" + +cp ${REL}.tar.gz ${TMPDIR}/verify || exit 1 + +cd ${TMPDIR}/verify || exit 1 +tar -zxf ${REL}.tar.gz || exit 1 +cd ${REL} || exit 1 +autoreconf -i && ./configure && make -j + +cd ${TMPDIR}/a || exit 1 +gpg -u 0x6FE57CA8C1A4AEA6 -a --detach-sign ${REL}.tar.gz + +cat <<- EOF + +Release tagged as: ${REL} + +Release files are in ${TMPDIR}/a: + + ${TMPDIR}/a/${REL}.tar.gz + ${TMPDIR}/a/${REL}.tar.gz.asc + ${TMPDIR}/a/${REL}.changelog.txt + +If you need to redo the release, you must delete the tag first: + + git tag -d ${REL} + +To finish the release: + +* push the tag to savannah: + + git push tag ${REL} + +* Upload the 3 files to the savannah releases area: + + scp ${TMPDIR}/a/${REL}.tar.gz \ + ${TMPDIR}/a/${REL}.tar.gz.asc \ + ${TMPDIR}/a/${REL}.changelog.txt + @dl.sv.nongnu.org:/releases/quagga + +* Update the version list in bugzilla: + + https://bugzilla.quagga.net/editversions.cgi?action=add&product=Quagga + +* Add a news entry to the Savannah front page. The short list of commit + subjects (${TMPDIR}/a/${REL}.subjects.txt) may be useful here. + +* Email the quagga-dev and quagga-users lists + +EOF From 2d81a7a8e425dcc4ca0cda411e73915f7ec3c1c9 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 20 Apr 2016 14:05:20 +0100 Subject: [PATCH 1269/1342] bgpd: Send OPEN immediately on inbound connections * bgpd_fsm.c: (bgp_connect_success) This is the transition function called when TCP_connection_open occurs in Connect or Active. It sends OPEN, but only for a !ACCEPT_PEER. I.e. only on the local bgpd's outbound connection. This means OPEN will never be sent on a received connection, until OPEN is received on it. Which means if the remote peer delays sending its OPEN on such an inbound connection, the local peer might hit a timer (e.g. connectretry) before then and reset. There should be no harm in sending OPEN ASAP on any new connection with any conforming implementation, indeed this is supposed to be the behaviour. It should speed up things, decrease the window in which collision detection could be hit, and make things more robust. So do so. * bgp_packet.c: (bgp_open_receive) Update the comment. Do not send bgp_open_send on the ACCEPT_PEER connection that has just been transferred over, that's now done in bgp_connect_success, as it should be. The accept peer's output fifo must also be transferred over, to ensure the Open gets sent, if not already, and the write thread state replicated accordingly. * bgp_network.c: (bgp_accept) local AS config needs to set, so we can send Open early on ACCEPT_PEER connections. Note: The Cumulus "Fix FSM to handle active/passive connections better" patch also makes this change, amongst other things. --- bgpd/bgp_fsm.c | 3 +-- bgpd/bgp_network.c | 2 ++ bgpd/bgp_packet.c | 11 ++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 41f623ff3..84fddeb9b 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -678,8 +678,7 @@ bgp_connect_success (struct peer *peer) zlog_debug ("%s passive open", peer->host); } - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - bgp_open_send (peer); + bgp_open_send (peer); return 0; } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index c7d338903..885082fa7 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -251,6 +251,8 @@ bgp_accept (struct thread *thread) peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; + peer->local_as = peer1->local_as; + peer->change_local_as = peer1->change_local_as; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 51b006a60..d3acbd235 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1423,6 +1423,9 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) * Connect Connect * * + * Note that Active->OpenSent historically in Quagga did not send + * OPEN on the accept-peer connection. + * * If both sides are Quagga, they're almost certain to wait for * the same amount of time of course (which doesn't preclude other * implementations also waiting for same time). The race is @@ -1466,6 +1469,11 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) realpeer->ibuf = peer->ibuf; realpeer->packet_size = peer->packet_size; peer->ibuf = NULL; + + /* Transfer output buffer, there may be an OPEN queued to send */ + stream_fifo_free (realpeer->obuf); + realpeer->obuf = peer->obuf; + peer->obuf = NULL; /* Transfer status. */ realpeer->status = peer->status; @@ -1473,7 +1481,6 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* peer pointer change. Open packet send to neighbor. */ peer = realpeer; - bgp_open_send (peer); if (peer->fd < 0) { zlog_err ("bgp_open_receive peer's fd is negative value %d", @@ -1481,6 +1488,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); + if (stream_fifo_head (peer->obuf)) + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* remote router-id check. */ From f408fa2c81a8e5873cb0a8c37fe44e389f65d50e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 25 Apr 2016 15:50:31 +0100 Subject: [PATCH 1270/1342] lib: Add a trivial sockunion_get_port helper function --- lib/sockunion.c | 15 +++++++++++++++ lib/sockunion.h | 1 + 2 files changed, 16 insertions(+) diff --git a/lib/sockunion.c b/lib/sockunion.c index 4a22c6386..8e0ec2493 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -632,6 +632,21 @@ sockunion_get_addr(const union sockunion *su) return NULL; } +unsigned short +sockunion_get_port (const union sockunion *su) +{ + switch (sockunion_family (su)) + { + case AF_INET: + return ntohs(su->sin.sin_port); +#ifdef HAVE_IPV6 + case AF_INET6: + return ntohs(su->sin6.sin6_port); +#endif /* HAVE_IPV6 */ + } + return 0; +} + void sockunion_set(union sockunion *su, int family, const u_char *addr, size_t bytes) { diff --git a/lib/sockunion.h b/lib/sockunion.h index b91c57175..3613073d0 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -94,6 +94,7 @@ extern unsigned int sockunion_hash (const union sockunion *); extern size_t family2addrsize(int family); extern size_t sockunion_get_addrlen(const union sockunion *); extern const u_char *sockunion_get_addr(const union sockunion *); +extern unsigned short sockunion_get_port (const union sockunion *); extern void sockunion_set(union sockunion *, int family, const u_char *addr, size_t bytes); extern union sockunion *sockunion_str2su (const char *str); From ac278ea6b770fd0bf74b3e718c2e6a4d84fcba3a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 26 Apr 2016 11:46:34 +0100 Subject: [PATCH 1271/1342] bgpd: collision-detect should retain Established peers + tidy logic + logs * bgp_network.c: (bgp_accept) We should also reject connections where the main peer is in >Established state. Could potentially also reject connections for main peer == Established here too. Log the port number too, so it's easier to reconcile logs with network dumps. * bgp_packet.c: (bgp_collision_detect) Try factor out some of the conditionals controlling the action of the loop to the top, for readability. Handle existing Established session, by closing the new one, favouring stability and as per RFC, except for GR. (bgp_open_receive) Tidy up the logic a bit for readability, making each case distinct in the main body of the loop. --- bgpd/bgp_network.c | 13 ++- bgpd/bgp_packet.c | 195 ++++++++++++++++++++++++++++----------------- 2 files changed, 133 insertions(+), 75 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 885082fa7..aaa38701f 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -215,11 +215,15 @@ bgp_accept (struct thread *thread) bgp_update_sock_send_buffer_size(bgp_sock); if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); + zlog_debug ("[Event] BGP connection from host %s:%d", + inet_sutop (&su, buf), sockunion_get_port (&su)); /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); - if (! peer1 || peer1->status == Idle) + /* We could perhaps just drop new connections from already Established + * peers here. + */ + if (! peer1 || peer1->status == Idle || peer1->status > Established) { if (BGP_DEBUG (events, EVENTS)) { @@ -227,8 +231,9 @@ bgp_accept (struct thread *thread) zlog_debug ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else - zlog_debug ("[Event] BGP connection IP address %s is Idle state", - inet_sutop (&su, buf)); + zlog_debug ("[Event] BGP connection IP address %s is %s state", + inet_sutop (&su, buf), + LOOKUP (bgp_status_msg, peer1->status)); } close (bgp_sock); return -1; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d3acbd235..16bc4457f 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1201,12 +1201,54 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - /* Under OpenConfirm status, local peer structure already hold - remote router ID. */ - - if (peer != new - && (peer->status == OpenConfirm || peer->status == OpenSent) - && sockunion_same (&peer->su, &new->su)) + if (peer == new) + continue; + if (!sockunion_same (&peer->su, &new->su)) + continue; + + /* Unless allowed via configuration, a connection collision with an + existing BGP connection that is in the Established state causes + closing of the newly created connection. */ + if (peer->status == Established) + { + /* GR may do things slightly differently to classic RFC . Punt to + * open_receive, see below + */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) + continue; + + if (new->fd >= 0) + bgp_notify_send (new, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + return -1; + } + + /* The assumption from here is that the existing peer structure is + * locally initiated, and the 'new' argument from which we've just + * received the Open is newly created inbound. I.e., the assumption + * is that the connection on which the Open was already processed must + * be the outbound one. + * + * That seems slightly unsafe. The older connection could easily have + * been an accepted peer - but we remove that flag before going into + * OpenConfirm. The 'new' connection could be us reading an Open on a + * connection we initiated. + * + * This might even be an confusion RFC4271 somewhat encourages, e.g.: + * + * "the local system closes the BGP connection that already exists + * (the one that is already in the OpenConfirm state), and accepts + * the BGP connection initiated by the remote system." + * + * Quagga historically orders explicitly only on the processing of the + * Opens, as below. Not clear to what extent this ensures it closes + * the inbound and outbound connections as required. + */ + + /* The local_id is always set, so we can match the given remote-ID + * from the OPEN against both OpenConfirm and OpenSent peers. + */ + if (peer->status == OpenConfirm || peer->status == OpenSent) { /* 1. The BGP Identifier of the local system is compared to the BGP Identifier of the remote system (as specified in @@ -1221,7 +1263,8 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) connection initiated by the remote system. */ if (peer->fd >= 0) - bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return 1; } else @@ -1273,9 +1316,11 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Receive OPEN message log */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," - " holdtime %d, id %s", + " holdtime %d, id %s, %sbound connection", peer->host, version, remote_as, holdtime, - inet_ntoa (remote_id)); + inet_ntoa (remote_id), + CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER) + ? "in" : "out"); /* BEGIN to read the capability here, but dont do it yet */ mp_capability = 0; @@ -1381,81 +1426,89 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) if (ret < 0) return ret; - /* Hack part. */ + /* Bit hacky */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - { - if (realpeer->status == Established + { + /* Connection FSM state is intertwined with our peer configuration + * (the RFC encourages this a bit). At _this_ point we have a + * 'realpeer' which represents the configuration and any earlier FSM + * (outbound, unless the remote side has opened two connections to + * us), and a 'peer' which here represents an inbound connection that + * has not yet been reconciled with a 'realpeer'. + * + * As 'peer' has just sent an OPEN that reconciliation must now + * happen, as only the 'realpeer' can ever proceed to Established. + * + * bgp_collision_detect should have resolved any collisions with + * realpeers that are in states OpenSent, OpenConfirm or Established, + * and may have sent a notify on the 'realpeer' connection. + * bgp_accept will have rejected any connections where the 'realpeer' + * is in Idle or >Established (though, that status may have changed + * since). + * + * Need to finish off any reconciliation here, and ensure that + * 'realpeer' is left holding any needed state from the appropriate + * connection (fd, buffers, etc.), and any state from the other + * connection is cleaned up. + */ + + /* Is realpeer in some globally-down state, that precludes any and all + * connections (Idle, Clearing, Deleted, etc.)? + */ + if (realpeer->status == Idle || realpeer->status > Established) + { + if (BGP_DEBUG (events, EVENTS)) + zlog_debug ("%s peer status is %s, closing the new connection", + realpeer->host, + LOOKUP (bgp_status_msg, realpeer->status)); + return -1; + } + + /* GR does things differently, and prefers any new connection attempts + * over an Established one (why not just rely on KEEPALIVE and avoid + * having to special case this?) */ + if (realpeer->status == Established && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE)) { realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT); } - else if (ret == 0 && realpeer->status != Active - && realpeer->status != OpenSent - && realpeer->status != OpenConfirm - && realpeer->status != Connect) + else if (ret == 0) { - /* XXX: This is an awful problem.. + /* If we're here, RFC collision-detect did not reconcile the + * connections, and the 'realpeer' is still available. So + * 'realpeer' must be 'Active' or 'Connect'. * * According to the RFC we should just let this connection (of the * accepted 'peer') continue on to Established if the other - * connection (the 'realpeer' one) is in state Connect, and deal - * with the more larval FSM as/when it gets far enough to receive - * an Open. We don't do that though, we instead close the (more - * developed) accepted connection. - * - * This means there's a race, which if hit, can loop: - * - * FSM for A FSM for B - * realpeer accept-peer realpeer accept-peer + * onnection (the 'realpeer') is in a more larval state, and + * reconcile them when OPEN is sent on the 'realpeer'. * - * Connect Connect - * Active - * OpenSent OpenSent - * - * Idle Active - * OpenSent OpenSent - * - * Idle - * - * Connect Connect + * However, the accepted 'peer' must be reconciled with 'peer' at + * this point, due to the implementation, if 'peer' is to be able + * to proceed. So it should be allowed to go to Established, as + * long as the 'realpeer' was in Active or Connect state - which + * /should/ be the case if we're here. * - * - * Note that Active->OpenSent historically in Quagga did not send - * OPEN on the accept-peer connection. - * - * If both sides are Quagga, they're almost certain to wait for - * the same amount of time of course (which doesn't preclude other - * implementations also waiting for same time). The race is - * exacerbated by high-latency (in bgpd and/or the network). - * - * The reason we do this is because our FSM is tied to our peer - * structure, which carries our configuration information, etc. - * I.e. we can't let the accepted-peer FSM continue on as it is, - * cause it's not associated with any actual peer configuration - - * it's just a dummy. - * - * It's possible we could hack-fix this by just bgp_stop'ing the - * realpeer and continueing on with the 'transfer FSM' below. - * Ideally, we need to seperate FSMs from struct peer. - * - * Setting one side to passive avoids the race, as a workaround. + * So we should only need to sanity check that that is the case + * here, and allow the code to get on with transferring the 'peer' + * connection state over. */ - if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("%s peer status is %s close connection", - realpeer->host, LOOKUP (bgp_status_msg, - realpeer->status)); - bgp_notify_send (peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONNECT_REJECT); - - return -1; + if (realpeer->status != Active && realpeer->status != Connect) + { + if (BGP_DEBUG (events, EVENTS)) + zlog_warn ("%s real peer status should be Active or Connect," + " but is %s", + realpeer->host, + LOOKUP (bgp_status_msg, realpeer->status)); + bgp_notify_send (realpeer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + } } if (BGP_DEBUG (events, EVENTS)) - zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)", - peer->host, + zlog_debug ("%s:%u [Event] Transfer accept BGP peer to real (state %s)", + peer->host, sockunion_get_port (&peer->su), LOOKUP (bgp_status_msg, realpeer->status)); bgp_stop (realpeer); @@ -1469,17 +1522,17 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) realpeer->ibuf = peer->ibuf; realpeer->packet_size = peer->packet_size; peer->ibuf = NULL; - + /* Transfer output buffer, there may be an OPEN queued to send */ stream_fifo_free (realpeer->obuf); realpeer->obuf = peer->obuf; peer->obuf = NULL; - + /* Transfer status. */ realpeer->status = peer->status; bgp_stop (peer); - /* peer pointer change. Open packet send to neighbor. */ + /* peer pointer change */ peer = realpeer; if (peer->fd < 0) { From 1ebafb61a4a2059fdd50aeefd27780d6358dd488 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 27 Apr 2016 09:55:21 +0100 Subject: [PATCH 1272/1342] bgpd: collision detection assumes 'new' peer is the inbound connection * bgp_packet.c: (bgp_collision_detect) for a long time, this has assumed the 'new' peer argument on which an OPEN has just been received must be an 'inbound' connection, and the looked up 'peer' the outbound. However, this doesn't seem a robust assumption. It seems possible it could be the other way around. The consequences are that collision detection could behave inconsistently with other implementations, and result in both sides closing the same connection. Fix to follow the RFC. --- bgpd/bgp_packet.c | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 16bc4457f..4ef470d2b 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1223,26 +1223,9 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) return -1; } - /* The assumption from here is that the existing peer structure is - * locally initiated, and the 'new' argument from which we've just - * received the Open is newly created inbound. I.e., the assumption - * is that the connection on which the Open was already processed must - * be the outbound one. - * - * That seems slightly unsafe. The older connection could easily have - * been an accepted peer - but we remove that flag before going into - * OpenConfirm. The 'new' connection could be us reading an Open on a - * connection we initiated. - * - * This might even be an confusion RFC4271 somewhat encourages, e.g.: - * - * "the local system closes the BGP connection that already exists - * (the one that is already in the OpenConfirm state), and accepts - * the BGP connection initiated by the remote system." - * - * Quagga historically orders explicitly only on the processing of the - * Opens, as below. Not clear to what extent this ensures it closes - * the inbound and outbound connections as required. + /* Note: Quagga historically orders explicitly only on the processing + * of the Opens, treating 'new' as the passive, inbound and connection + * and 'peer' as the active outbound connection. */ /* The local_id is always set, so we can match the given remote-ID @@ -1250,6 +1233,18 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) */ if (peer->status == OpenConfirm || peer->status == OpenSent) { + struct peer *out = peer; + struct peer *in = new; + int ret_close_out = 1, ret_close_in = -1; + + if (!CHECK_FLAG (new->sflags, PEER_STATUS_ACCEPT_PEER)) + { + out = new; + ret_close_out = -1; + in = peer; + ret_close_in = 1; + } + /* 1. The BGP Identifier of the local system is compared to the BGP Identifier of the remote system (as specified in the OPEN message). */ @@ -1262,10 +1257,10 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) already in the OpenConfirm state), and accepts BGP connection initiated by the remote system. */ - if (peer->fd >= 0) - bgp_notify_send (peer, BGP_NOTIFY_CEASE, + if (out->fd >= 0) + bgp_notify_send (out, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); - return 1; + return ret_close_out; } else { @@ -1275,10 +1270,10 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) existing one (the one that is already in the OpenConfirm state). */ - if (new->fd >= 0) - bgp_notify_send (new, BGP_NOTIFY_CEASE, + if (in->fd >= 0) + bgp_notify_send (in, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); - return -1; + return ret_close_in; } } } From c79862373cd310dba8c0a51ff94ddce48be0099e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 21 Sep 2016 17:42:37 +0100 Subject: [PATCH 1273/1342] bgpd: Better/more debug for collisions, inc. logging port of NOTIFYs. --- bgpd/bgp_packet.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 4ef470d2b..23d2f4a79 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1008,23 +1008,26 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) { peer->last_reset = PEER_DOWN_USER_RESET; - zlog_info ("Notification sent to neighbor %s: User reset", peer->host); + zlog_info ("Notification sent to neighbor %s:%u: User reset", + peer->host, sockunion_get_port (&peer->su)); } else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) { peer->last_reset = PEER_DOWN_USER_SHUTDOWN; - zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); + zlog_info ("Notification sent to neighbor %s:%u shutdown", + peer->host, sockunion_get_port (&peer->su)); } else { peer->last_reset = PEER_DOWN_NOTIFY_SEND; - zlog_info ("Notification sent to neighbor %s: type %u/%u", - peer->host, code, sub_code); + zlog_info ("Notification sent to neighbor %s:%u: type %u/%u", + peer->host, sockunion_get_port (&peer->su), + code, sub_code); } } else - zlog_info ("Notification sent to neighbor %s: configuration change", - peer->host); + zlog_info ("Notification sent to neighbor %s:%u: configuration change", + peer->host, sockunion_get_port (&peer->su)); /* Call immediately. */ BGP_WRITE_OFF (peer->t_write); @@ -1218,9 +1221,14 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) continue; if (new->fd >= 0) + { + if (BGP_DEBUG (events, EVENTS)) + zlog_debug ("%s:%u Existing Established peer, sending NOTIFY", + new->host, sockunion_get_port (&new->su)); bgp_notify_send (new, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); - return -1; + } + return -1; } /* Note: Quagga historically orders explicitly only on the processing @@ -1258,8 +1266,13 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) connection initiated by the remote system. */ if (out->fd >= 0) - bgp_notify_send (out, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + { + if (BGP_DEBUG (events, EVENTS)) + zlog_debug ("%s Collision resolution, remote ID higher," + " closing outbound", peer->host); + bgp_notify_send (out, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + } return ret_close_out; } else @@ -1271,8 +1284,14 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id) OpenConfirm state). */ if (in->fd >= 0) - bgp_notify_send (in, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + { + if (BGP_DEBUG (events, EVENTS)) + zlog_debug ("%s Collision resolution, local ID higher," + " closing inbound", peer->host); + + bgp_notify_send (in, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); + } return ret_close_in; } } From 5a0c1be698a044bc838f3e6c8b259fa52cf9981c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 15 Sep 2016 17:13:16 +0100 Subject: [PATCH 1274/1342] bgpd: Config state related to OPEN must now be copied to accept peer. * bgp_network.c: (bgp_accept) OPEN is now sent on accept peer, due to "Send OPEN immediately on inbound connections", so configuration state that affects OPEN also has to be copied for. Fixes failure with Martin Winter / NetDEFs test cases, where bgpd was failing to advertise configured AFI/SAFIs. --- bgpd/bgp_network.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index aaa38701f..16042392c 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -249,19 +249,29 @@ bgp_accept (struct thread *thread) char buf[SU_ADDRSTRLEN]; peer = peer_create_accept (peer1->bgp); - SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); peer->su = su; peer->fd = bgp_sock; peer->status = Active; + + /* Config state that should affect OPEN packet must be copied over */ peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; peer->local_as = peer1->local_as; peer->change_local_as = peer1->change_local_as; - + peer->flags = peer1->flags; + peer->sflags = peer1->sflags; + #define PEER_ARRAY_COPY(D,S,A) \ + memcpy ((D)->A, (S)->A, sizeof (((D)->A)[0][0])*AFI_MAX*SAFI_MAX); + PEER_ARRAY_COPY(peer, peer1, afc); + PEER_ARRAY_COPY(peer, peer1, af_flags); + #undef PEER_ARRAY_COPY + /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); + + SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); } BGP_EVENT_ADD (peer, TCP_connection_open); From d023f9ffae4b040335d12c1aa7409a9a15b7a3ac Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 16 Sep 2016 15:13:43 +0100 Subject: [PATCH 1275/1342] bgpd: Rollback "always send OPEN" a little, to workaround test suite issues * "bgpd: Send OPEN immediately on inbound connections" doesn't play well with some partial BGP implementations, test and conformance suites e.g., which have rigid expectations about ordering and don't implement much of CD. roll back, but only a little, by deferring OPEN sending on outbound till receive. * bgpd.h: (struct peer) add PEER_STATUS_OPEN_DEFERRED status flag. Kind of a sub-fsm. Main FSM does not allow transition functions to signal next-state - next-state is inflexibly fixed in the table - so can't handle it cleanly at that level. * bgp_fsm.c: (bgp_connect_success) Defer sending open if the peer is an accept-peer/inbound and there appears to be an outbound connection in progress. Set PEER_STATUS_OPEN_DEFERRED to signal to bgp_open_receive that an OPEN still must be sent. * bgp_packet.c: (bgp_open_receive) Send the OPEN here, when deferred. --- bgpd/bgp_fsm.c | 25 ++++++++++++++++++++++++- bgpd/bgp_packet.c | 14 ++++++++++++++ bgpd/bgpd.h | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 84fddeb9b..4198a8e42 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -656,6 +656,8 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) static int bgp_connect_success (struct peer *peer) { + struct peer *realpeer; + if (peer->fd < 0) { zlog_err ("bgp_connect_success peer's fd is negative value %d", @@ -677,7 +679,28 @@ bgp_connect_success (struct peer *peer) else zlog_debug ("%s passive open", peer->host); } - + + /* Generally we want to send OPEN ASAP. Except, some partial BGP + * implementations out there (e.g., conformance test tools / BGP + * traffic generators) seem to be a bit funny about connection collisions, + * and OPENs before they have sent. + * + * As a hack, delay sending OPEN on an inbound accept-peer session + * _IF_ we locally have an outbound connection in progress, i.e. + * we're in middle of a connection collision. If we delay, we delay until + * an Open is received - as per old Quagga behaviour. + */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + realpeer = peer_lookup (peer->bgp, &peer->su); + + if (realpeer->status > Idle && realpeer->status <= Established) + { + SET_FLAG (peer->sflags, PEER_STATUS_OPEN_DEFERRED); + return 0; + } + } + bgp_open_send (peer); return 0; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 23d2f4a79..b497e4546 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1542,12 +1542,16 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) realpeer->obuf = peer->obuf; peer->obuf = NULL; + bool open_deferred + = CHECK_FLAG (peer->sflags, PEER_STATUS_OPEN_DEFERRED); + /* Transfer status. */ realpeer->status = peer->status; bgp_stop (peer); /* peer pointer change */ peer = realpeer; + if (peer->fd < 0) { zlog_err ("bgp_open_receive peer's fd is negative value %d", @@ -1557,6 +1561,16 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) BGP_READ_ON (peer->t_read, bgp_read, peer->fd); if (stream_fifo_head (peer->obuf)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + + /* hack: we may defer OPEN on accept peers, when there seems to be a + * realpeer in progress, when an accept peer connection is opened. This + * is to avoid interoperability issues, with test/conformance tools + * particularly. See bgp_fsm.c::bgp_connect_success + * + * If OPEN was deferred there, then we must send it now. + */ + if (open_deferred) + bgp_open_send (peer); } /* remote router-id check. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index c2df672c2..03df2f6f1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -442,7 +442,7 @@ struct peer #define PEER_STATUS_ACCEPT_PEER (1 << 0) /* accept peer */ #define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */ #define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */ -#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */ +#define PEER_STATUS_OPEN_DEFERRED (1 << 3) /* deferred to open_receive */ #define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */ #define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */ #define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */ From f452d5409a5eb275ee4d5dd24e67461231dc425a Mon Sep 17 00:00:00 2001 From: Jim Carroll Date: Fri, 27 Jan 2017 16:08:59 +0000 Subject: [PATCH 1276/1342] ripd: Fix restriction on default RTE that's incompatible with CIDR * ripd.c: (rip_response_process) A 0 address can still easily have a non-zero netmask. E.g., 0/1 to complement 128/1. These should be allowed through. See bug #903. Modify to check for malformed pseudo-default routes, where the netmask is 0 but the address is non-0, and warn and drop such routes instead. --- ripd/ripd.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index 4ce5cc362..dd3ca5bb3 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1312,17 +1312,19 @@ rip_response_process (struct rip_packet *packet, int size, rip_peer_bad_route (from); continue; } - - /* Default route's netmask is ignored. */ + + /* Default route sanity check */ if (packet->version == RIPv2 - && (rte->prefix.s_addr == 0) - && (rte->mask.s_addr != 0)) - { - if (IS_RIP_DEBUG_EVENT) - zlog_debug ("Default route with non-zero netmask. Set zero to netmask"); - rte->mask.s_addr = 0; - } - + && (rte->mask.s_addr == 0) + && (rte->prefix.s_addr != 0)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("Malformed route, zero netmask " + "with non-zero addr - dropping route!"); + rip_peer_bad_route (from); + continue; + } + /* Routing table updates. */ rip_rte_process (rte, from, ifc->ifp); } From b29cd82299206f77a584699bcb3b7a7b36183787 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Feb 2017 21:24:42 +0000 Subject: [PATCH 1277/1342] HACKING: Update governance --- HACKING.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/HACKING.md b/HACKING.md index 4b0ff5487..adc3b3707 100644 --- a/HACKING.md +++ b/HACKING.md @@ -49,13 +49,20 @@ See also the Section on [CODE OF CONDUCT](#sec:codeconduct). Governance {#sec:governance} ========== -The governance of Quagga is currently in flux. +Quagga is a Sociocracy, as it has been since its earliest days. Quagga was forked from GNU Zebra by Paul Jakma, who holds the domain name. -Governance was soon devolved to a collective group, the maintainers. +Governance was soon devolved to a collective group, the maintainers, +consisting of those who regularly contributed and reviewed code. The +details can easily be changed. -Governance at this moment is again fully in the hands of Paul Jakma, to be -recast. +You are free to use reason to _persuade_ others to adopt some alternative. +If, after that, you truly can not abide by what is mutually agreeable, you +are asked to do the honourable thing: take your copy of the code, make your +apologies, and be on your way with good grace. + +Those who repeatedly violate the [Code of Conduct](#sec:codeconduct) will be +asked to leave. Holding of project assets ------------------------- From 3c06ac025adbd4611e3a290b43fea4cb512688ac Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Feb 2017 21:45:05 +0000 Subject: [PATCH 1278/1342] build/HACKING: add check for pandoc and update make rule for HACKING.pdf --- Makefile.am | 6 +++--- configure.ac | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index b485bc877..3c3b65eb9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,10 +13,10 @@ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ vtysh/Makefile.in vtysh/Makefile.am \ tools/zebra.el tools/multiple-bgpd.sh -if HAVE_LATEX +if HAVE_PANDOC -HACKING.pdf: HACKING.tex - $(LATEXMK) -pdf $< +HACKING.pdf: HACKING.md + pandoc -o $@ $< clean-local: -$(LATEXMK) -C HACKING.tex diff --git a/configure.ac b/configure.ac index 1331deeb7..fe409b467 100755 --- a/configure.ac +++ b/configure.ac @@ -83,7 +83,8 @@ dnl autoconf 2.59 appears not to support AC_PROG_SED dnl AC_PROG_SED AC_CHECK_PROG([SED],[sed],[sed],[/bin/false]) -dnl pdflatex and latexmk are needed to build HACKING.pdf +dnl Check for pdflatex and latexmk, in case someone wants to build +dnl PDFs from TeX (as used to be case for HACKING) AC_CHECK_PROG([PDFLATEX],[pdflatex],[pdflatex],[/bin/false]) AC_CHECK_PROG([LATEXMK],[latexmk],[latexmk],[/bin/false]) if test "x$PDFLATEX" = "x/bin/false" -o "x$LATEXMK" = "x/bin/false"; then @@ -92,6 +93,14 @@ else HAVE_LATEX=true fi AM_CONDITIONAL([HAVE_LATEX], [test "x$HAVE_LATEX" = "xtrue"]) +dnl for making HACKING.pdf from HACKING.md using pandoc +AC_CHECK_PROG([PANDOC],[pandoc],[pandoc],[/bin/false]) +if test "x$PDFLATEX" = "x/bin/false" -o "x$PANDOC" = "x/bin/false"; then + AC_MSG_WARN([Will not be able to make PDF versions of MD documents]) +else + HAVE_PANDOC=true +fi +AM_CONDITIONAL([HAVE_PANDOC], [test "x$HAVE_PANDOC" = "xtrue"]) if test "x${GCC}" != "xyes" ; then AC_MSG_CHECKING([whether we are using SunPro compiler]) From c876b0b27e398c7d733966ce8636c26dd7a8e6eb Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Feb 2017 15:19:38 +0000 Subject: [PATCH 1279/1342] release: Quagga 1.2.0 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fe409b467..ce8aba95c 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 1.1.1, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.2.0, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From 6dbb58c04078c31ca3f43e9754b498aa3be6518b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Feb 2017 15:05:06 +0000 Subject: [PATCH 1280/1342] zebra: Make the --nl-bufsize arg set the input parse buffer too * See bug #887. Existing statically sized NL_PKT_BUF_SIZE input parse buffer in netlink_parse_info may not be enough. As an initial hacky fix, at least give admins a runtime way to change this buffer, with the existing --nl-bufsize argument to zebra. * rt_netlink.c: (nl_rcvbuf) static input buffer and length. (netlink_parse_info) replace the local fixed size buffer with nl_rcvbuf. Improve warning on MSG_TRUNC to advise admin on what to do. (kernel_init) Dynamically allocate nl_rcvbuf input parse buffer to at least 2 pages, or nl_rcvbufsize argument, whichever is greater. Based on the debugging and investigation of: Konstantin --- lib/memtypes.c | 1 + zebra/rt_netlink.c | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/memtypes.c b/lib/memtypes.c index f9eae938e..e5b35465e 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -87,6 +87,7 @@ struct memory_list memory_list_zebra[] = { MTYPE_RIB_DEST, "RIB destination" }, { MTYPE_RIB_TABLE_INFO, "RIB table info" }, { MTYPE_NETLINK_NAME, "Netlink name" }, + { MTYPE_NETLINK_RCVBUF, "Netlink receive buffer" }, { MTYPE_RNH, "Nexthop tracking object" }, { -1, NULL }, }; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 1a9142666..fc6e373db 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -67,6 +67,11 @@ extern struct zebra_privs_t zserv_privs; extern u_int32_t nl_rcvbufsize; +static struct { + char *p; + size_t size; +} nl_rcvbuf; + /* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void @@ -275,10 +280,9 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, while (1) { - char buf[NL_PKT_BUF_SIZE]; struct iovec iov = { - .iov_base = buf, - .iov_len = sizeof buf + .iov_base = nl_rcvbuf.p, + .iov_len = nl_rcvbuf.size, }; struct sockaddr_nl snl; struct msghdr msg = { @@ -314,7 +318,8 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, return -1; } - for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status); + for (h = (struct nlmsghdr *) nl_rcvbuf.p; + NLMSG_OK (h, (unsigned int) status); h = NLMSG_NEXT (h, status)) { /* Finish of reading. */ @@ -407,7 +412,9 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, /* After error care. */ if (msg.msg_flags & MSG_TRUNC) { - zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); + zlog (NULL, LOG_ERR, "%s error: message truncated!", nl->name); + zlog (NULL, LOG_ERR, + "Must restart with larger --nl-bufsize value!"); continue; } if (status) @@ -2005,6 +2012,8 @@ kernel_init (struct zebra_vrf *zvrf) /* Register kernel socket. */ if (zvrf->netlink.sock > 0) { + size_t bufsize = MAX(nl_rcvbufsize, 2 * sysconf(_SC_PAGESIZE)); + /* Only want non-blocking on the netlink event socket */ if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0) zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name, @@ -2013,7 +2022,10 @@ kernel_init (struct zebra_vrf *zvrf) /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize); - + + nl_rcvbuf.p = XMALLOC (MTYPE_NETLINK_RCVBUF, bufsize); + nl_rcvbuf.size = bufsize; + netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid); zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, zvrf->netlink.sock); From 21e8b42dccdf7da3bbb3e057edd5c44da446d729 Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Thu, 22 Dec 2011 18:07:15 +0400 Subject: [PATCH 1281/1342] ospfd: fix NSSA LSA translation (BZ#493) * See bugzilla #439 --- ospfd/ospf_lsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index d7954399a..1a21b0510 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2551,6 +2551,7 @@ ospf_external_lsa_install (struct ospf *ospf, struct ospf_lsa *new, * New translations will be taken care of by the abr_task. */ ospf_translated_nssa_refresh (ospf, new, NULL); + ospf_schedule_abr_task(ospf); } } From e7c65f6f1a951dd94f1c2e327d968bb8d468d0b5 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 20 Feb 2012 00:54:05 +0400 Subject: [PATCH 1282/1342] ospfd: address ospf_schedule_abr_task() warning --- ospfd/ospf_lsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 1a21b0510..f49e263c8 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -49,6 +49,7 @@ #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_abr.h" u_int32_t From 2e0fb0e1eee44e94021fd0b6a5c46bd7f915a7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Sch=C3=B6ler?= Date: Thu, 23 Feb 2017 13:16:42 +0000 Subject: [PATCH 1283/1342] redhat: Add quagga user to quaggavt vty group by default, bug #937 * See bugzilla #937 --- redhat/quagga.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index a1263d12a..fa50aaa17 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -310,7 +310,7 @@ if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ fi if getent passwd %quagga_user >/dev/null ; then : ; else \ - /usr/sbin/useradd -u %quagga_uid -g %quagga_gid \ + /usr/sbin/useradd -u %quagga_uid -g %quagga_gid -G %vty_group \ -M -r -s /sbin/nologin -c "Quagga routing suite" \ -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi From 343074aacfe9ec8d00e2c123f14f418a0920585b Mon Sep 17 00:00:00 2001 From: Brian Utterback Date: Thu, 23 Feb 2017 13:31:38 +0000 Subject: [PATCH 1284/1342] solaris: Fix quagga.init.in shell errors * quagga.init.in: SMF_GROUP assignment shell is missing a space, so never works. Test for DAEMON_PATH and DAEMON being empty never works, fix. Test for configuration file should use the SMF property, not the default - the default config file location is already set in the quagga.xml file that sets the SMF property defauls. See bugs #877, #878, and #879. [ commit message by Paul Jakma / ] --- solaris/quagga.init.in | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/solaris/quagga.init.in b/solaris/quagga.init.in index ee3a987f3..ed3350eea 100755 --- a/solaris/quagga.init.in +++ b/solaris/quagga.init.in @@ -120,7 +120,7 @@ routeadm_daemon_args () { # user and group we need for config file upgrade.. SMF_USER=`get_routeadm_property $SMF_FMRI user` - SMF_GROUP=`get_routeadm_property()$SMF_FMRI group` + SMF_GROUP=`get_routeadm_property() $SMF_FMRI group` if [ "${SMF_USER}" ] ; then USER="${SMF_USER}" args="${args} -u ${SMF_USER}" @@ -197,7 +197,7 @@ fi DAEMON="$1" # daemon path must be given -if [ -z "$DAEMON_PATH/$DAEMON" ]; then +if [ "$DAEMON_PATH/$DAEMON" = "/" ]; then usage exit $SMF_EXIT_ERR_FATAL fi @@ -231,9 +231,13 @@ fi upgrade_config "$DAEMON" -if [ ! -f "@sysconfdir@/${DAEMON}.conf" ] ; then - echo "Could not find config file, @sysconfdir@/${DAEMON}.conf" - exit $SMF_EXIT_ERR_CONFIG +CONF_FILE=`get_routeadm_property $SMF_FMRI config_file` +if [ -z "$CONF_FILE" ] ; then + CONF_FILE="@sysconfdir@/${DAEMON}.conf" +fi +if [ ! -f "$CONF_FILE" ] ; then + echo "Could not find config file, $CONF_FILE" + exit $SMF_EXIT_ERR_CONFIG fi # we need @quagga_statedir@ to exist, it probably is on tmpfs. From 004db27ada7b37adf84408dbb98a3d92e4e4d6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 14 Feb 2017 11:55:09 +0200 Subject: [PATCH 1285/1342] nhrpd: workaround old kernel vs. glibc definition conflics fixes #908 With kernel-headers-3.10.0 we have: In file included from netlink_gre.c:15:0: /usr/include/linux/ipv6.h:19:8: error: redefinition of 'struct in6_pktinfo' struct in6_pktinfo { ^ In file included from netlink_gre.c:10:0: /usr/include/netinet/in.h:536:8: note: originally defined here struct in6_pktinfo ^ In file included from netlink_gre.c:15:0: /usr/include/linux/ipv6.h:24:8: error: redefinition of 'struct ip6_mtuinfo' struct ip6_mtuinfo { ^ In file included from netlink_gre.c:10:0: /usr/include/netinet/in.h:543:8: note: originally defined here struct ip6_mtuinfo So instead of libc's netinet/in.h include kernel's linux/in.h and the add sys/socket.h for struct sockaddr since it does not seem to be defined in kernel headers. --- nhrpd/netlink_gre.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nhrpd/netlink_gre.c b/nhrpd/netlink_gre.c index 7cd30aa30..93998dc5f 100644 --- a/nhrpd/netlink_gre.c +++ b/nhrpd/netlink_gre.c @@ -7,9 +7,10 @@ * (at your option) any later version. */ -#include +#include #include #include +#include #include #include #include From 2d78fe7e35344ad9340fa7e36c704a8c5c2485c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Tue, 14 Feb 2017 13:07:39 +0200 Subject: [PATCH 1286/1342] distro/redhat: package nhrpd --- redhat/quagga.spec.in | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index fa50aaa17..c4eeafe1d 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -21,6 +21,7 @@ %{!?with_rtadv: %global with_rtadv 1 } %{!?with_isisd: %global with_isisd 1 } %{!?with_pimd: %global with_pimd 1 } +%{!?with_nhrpd: %global with_nhrpd 1 } %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } @@ -87,13 +88,19 @@ %define daemon_pimd "" %endif +%if %{with_nhrpd} +%define daemon_nhrpd nhrpd +%else +%define daemon_nhrpd "" +%endif + %if %{with_watchquagga} %define daemon_watchquagga watchquagga %else %define daemon_watchquagga "" %endif -%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_watchquagga} +%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_watchquagga} # allow build dir to be kept %{!?keep_build: %global keep_build 0 } @@ -144,7 +151,7 @@ Quagga is a free software that manages TCP/IP based routing protocol. It takes multi-server and multi-thread approach to resolve the current complexity of the Internet. -Quagga supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng and PIM. +Quagga supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM and NHRP. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. @@ -229,6 +236,11 @@ developing OSPF-API and quagga applications. %else --disable-isisd \ %endif +%if %{with_nhrpd} + --enable-nhrpd \ +%else + --disable-nhrpd \ +%endif %if %{with_pam} --with-libpam \ %endif @@ -345,6 +357,9 @@ zebra_spec_add_service isisd 2608/tcp "ISISd vty" %if %{with_pimd} zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif +%if %{with_nhrpd} +zebra_spec_add_service nhrpd 2612/tcp "NHRPd vty" +%endif %if "%{initsystem}" == "systemd" for daemon in %all_daemons ; do @@ -522,6 +537,9 @@ rm -rf %{buildroot} %if %{with_isisd} %{_sbindir}/isisd %endif +%if %{with_nhrpd} +%{_sbindir}/nhrpd +%endif %if %{with_shared} %attr(755,root,root) %{_libdir}/lib*.so %attr(755,root,root) %{_libdir}/lib*.so.* @@ -548,6 +566,9 @@ rm -rf %{buildroot} %if %{with_pimd} %config /etc/rc.d/init.d/pimd %endif + %if %{with_nhrpd} + %config /etc/rc.d/init.d/nhrpd + %endif %endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga @@ -574,7 +595,10 @@ rm -rf %{buildroot} %endif %changelog -* Thu Feb 11 2016 Paul Jakma - %{version} +* Tue Feb 14 2017 Timo Teräs - %{version} +- add nhrpd + +* Thu Feb 11 2016 Paul Jakma - remove with_ipv6 conditionals, always build v6 - Fix UTF-8 char in spec changelog - remove quagga.pam.stack, long deprecated. From 64c56085661d7e4f41dc59bbf62643e682ce51c2 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Thu, 20 Oct 2016 12:56:34 +0200 Subject: [PATCH 1287/1342] systemd: various service file improvements (1) network.target is generally used as a synchronization point during boot up and not as a "boot target" (target where services are actually enabled). Also as per 'man 7 systemd.special', service implementing networking should pull network.target into transaction and order itself before it. Hence, it doesn't make sense for zebra and friends to be enabled in network.target, because they should actively pull in network.target into boot transaction. Let's enable them as normal services in multi-user.target and order against network{,-pre}.target appropriately. (2) All quagga daemons needs zebra to be running at all times and want to restarted/stopped whenever zebra is. This is expressed by BindsTo= dependency in a unit file (note "s" in Binds). --- redhat/bgpd.service | 8 +++++--- redhat/isisd.service | 8 +++++--- redhat/ospf6d.service | 8 +++++--- redhat/ospfd.service | 8 +++++--- redhat/ripd.service | 8 +++++--- redhat/ripngd.service | 8 +++++--- redhat/zebra.service | 6 ++++-- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/redhat/bgpd.service b/redhat/bgpd.service index 5040284db..ef2484162 100644 --- a/redhat/bgpd.service +++ b/redhat/bgpd.service @@ -1,7 +1,9 @@ [Unit] Description=BGP routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target ConditionPathExists=/etc/quagga/bgpd.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/bgpd -d $BGPD_OPTS -f /etc/quagga/bgpd.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target diff --git a/redhat/isisd.service b/redhat/isisd.service index 4cdf67d67..edb6eea5f 100644 --- a/redhat/isisd.service +++ b/redhat/isisd.service @@ -1,7 +1,9 @@ [Unit] Description=IS-IS routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target ConditionPathExists=/etc/quagga/isisd.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/isisd -d $ISISD_OPTS -f /etc/quagga/isisd.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target diff --git a/redhat/ospf6d.service b/redhat/ospf6d.service index 3c9c46689..b53b97091 100644 --- a/redhat/ospf6d.service +++ b/redhat/ospf6d.service @@ -1,7 +1,9 @@ [Unit] Description=OSPF routing daemon for IPv6 -BindTo=zebra.service -After=syslog.target network.target zebra.service +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target ConditionPathExists=/etc/quagga/ospf6d.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/ospf6d -d $OSPF6D_OPTS -f /etc/quagga/ospf6d.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target diff --git a/redhat/ospfd.service b/redhat/ospfd.service index 5e3de2393..5d6c5bb01 100644 --- a/redhat/ospfd.service +++ b/redhat/ospfd.service @@ -1,7 +1,9 @@ [Unit] Description=OSPF routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target ConditionPathExists=/etc/quagga/ospfd.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/ospfd -d $OSPFD_OPTS -f /etc/quagga/ospfd.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target diff --git a/redhat/ripd.service b/redhat/ripd.service index d35dc47a1..ed7f922cc 100644 --- a/redhat/ripd.service +++ b/redhat/ripd.service @@ -1,7 +1,9 @@ [Unit] Description=RIP routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target ConditionPathExists=/etc/quagga/ripd.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/ripd -d $RIPD_OPTS -f /etc/quagga/ripd.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target diff --git a/redhat/ripngd.service b/redhat/ripngd.service index 567e88806..2519b31e8 100644 --- a/redhat/ripngd.service +++ b/redhat/ripngd.service @@ -1,7 +1,9 @@ [Unit] Description=RIP routing daemon for IPv6 -BindTo=zebra.service -After=syslog.target network.target zebra.service +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target ConditionPathExists=/etc/quagga/ripngd.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/ripngd -d $RIPNGD_OPTS -f /etc/quagga/ripngd.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target diff --git a/redhat/zebra.service b/redhat/zebra.service index 27c3a5229..f9107f1e2 100644 --- a/redhat/zebra.service +++ b/redhat/zebra.service @@ -1,6 +1,8 @@ [Unit] Description=GNU Zebra routing manager -After=syslog.target network.target +Wants=network.target +Before=network.target +After=network-pre.target ConditionPathExists=/etc/quagga/zebra.conf [Service] @@ -11,4 +13,4 @@ ExecStart=/usr/sbin/zebra -d $ZEBRA_OPTS -f /etc/quagga/zebra.conf Restart=on-abort [Install] -WantedBy=network.target +WantedBy=multi-user.target From 9e31fbc996a58047e490333df1f7bf1c809a1488 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 27 Feb 2017 17:43:44 +0000 Subject: [PATCH 1288/1342] distro/redhat: spec syntax error if texi2html not installed * redhat/quagga.spec.in: If texi2html is not installed you get a confusing error about a syntax issue in an %if statement, far from the problem. Fix. --- redhat/quagga.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index c4eeafe1d..b71aa94d8 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -46,7 +46,7 @@ #### Check version of texi2html # Old versions don't support "--number-footnotes" option. -%{expand: %%global texi2htmlversion %(rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1 )} +%{expand: %%global texi2htmlversion %(type texi2html >/dev/null 2>&1 && (rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1) || echo 0 )} #### Check for systemd or init.d (upstart) # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) From 9368746527c6d5c8f55343237326456b2c20a41d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 27 Feb 2017 22:42:59 +0000 Subject: [PATCH 1289/1342] distro/redhat: Update to F24 and fix few issues, add nhrpd.service * redhat/quagga.spec.in: Review Fedora spec file and sync up with any useful differences, inc: - Add tmpfiles.d/quagga.conf config for Quagga from Fedora - Add quagga-filter-perl-requires.sh from Fedora. - Move libs to %{_libdir}/quagga as per Fedora - use systemd_postun_with_restart for postun Add nhrpd.service systemd file. Simplify/chop down the RPM description. * Makefile.am: Update to match --- redhat/Makefile.am | 3 +- redhat/nhrpd.service | 16 +++++++ redhat/quagga-filter-perl-requires.sh | 3 ++ redhat/quagga-tmpfs.conf | 1 + redhat/quagga.spec.in | 68 ++++++++++++++++++--------- 5 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 redhat/nhrpd.service create mode 100755 redhat/quagga-filter-perl-requires.sh create mode 100644 redhat/quagga-tmpfs.conf diff --git a/redhat/Makefile.am b/redhat/Makefile.am index fadfe64c7..b1d49ac3b 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -4,5 +4,6 @@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init pimd.init pimd.service zebra.init zebra.service \ + nhrpd.service \ + quagga-filter-perl-requires.sh quagga-tmpfs.conf \ README.rpm_build.md - diff --git a/redhat/nhrpd.service b/redhat/nhrpd.service new file mode 100644 index 000000000..63f138cd8 --- /dev/null +++ b/redhat/nhrpd.service @@ -0,0 +1,16 @@ +[Unit] +Description=Quagga NHRP daemon +BindsTo=zebra.service +Wants=network.target +After=zebra.service network-pre.target +Before=network.target +ConditionPathExists=/etc/quagga/nhrpd.conf + +[Service] +Type=forking +EnvironmentFile=/etc/sysconfig/quagga +ExecStart=/usr/sbin/nhrpd -d $NHRPD_OPTS -f /etc/quagga/nhrpdd.conf +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/redhat/quagga-filter-perl-requires.sh b/redhat/quagga-filter-perl-requires.sh new file mode 100755 index 000000000..db82cfd87 --- /dev/null +++ b/redhat/quagga-filter-perl-requires.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/lib/rpm/perl.req $* | grep -v "Net::Telnet" diff --git a/redhat/quagga-tmpfs.conf b/redhat/quagga-tmpfs.conf new file mode 100644 index 000000000..8974b64f8 --- /dev/null +++ b/redhat/quagga-tmpfs.conf @@ -0,0 +1 @@ +d /var/run/quagga 0755 quagga quagga diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index b71aa94d8..ba1eb190a 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -114,13 +114,14 @@ Version: %{rpmversion} Release: @CONFDATE@%{release_rev}%{?dist} License: GPLv2+ Group: System Environment/Daemons -Source0: http://download.savannah.gnu.org/releases/quagga/%{name}-%{quaggaversion}.tar.gz -URL: http://www.quagga.net +Source0: https://download.savannah.gnu.org/releases/quagga/%{name}-%{quaggaversion}.tar.gz +URL: https://www.quagga.net Requires: ncurses Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: texi2html texinfo autoconf patch libcap-devel groff +BuildRequires: perl-generators %if %{with_snmp} BuildRequires: net-snmp-devel Requires: net-snmp @@ -144,20 +145,14 @@ Requires(pre): initscripts >= 5.60 %endif Provides: routingdaemon = %{version}-%{release} BuildRoot: %{_tmppath}/%{name}-%{version}-root -Obsoletes: bird gated mrt zebra quagga-sysvinit +Obsoletes: mrt zebra quagga-sysvinit -%description -Quagga is a free software that manages TCP/IP based routing -protocol. It takes multi-server and multi-thread approach to resolve -the current complexity of the Internet. - -Quagga supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM and NHRP. +%define __perl_requires %{zeb_rh_src}/quagga-filter-perl-requires.sh -Quagga is intended to be used as a Route Server and a Route Reflector. It is -not a toolkit, it provides full routing power under a new architecture. -Quagga by design has a process for each protocol. +%description +Quagga is a free software routing protocol suite. -Quagga is a fork of GNU Zebra. +Quagga supports BGP, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM-SSM and NHRP. %package contrib Summary: contrib tools for quagga @@ -192,7 +187,7 @@ developing OSPF-API and quagga applications. %configure \ --sysconfdir=%{_sysconfdir} \ - --libdir=%{_libdir} \ + --libdir=%{_libdir}/quagga \ --libexecdir=%{_libexecdir} \ --localstatedir=%{_localstatedir} \ --disable-werror \ @@ -308,6 +303,13 @@ install -m644 %{zeb_rh_src}/quagga.sysconfig \ %{buildroot}/etc/sysconfig/quagga install -d -m750 %{buildroot}/var/run/quagga + +%if 0%{?_tmpfilesdir:1} + install -d -m 755 %{buildroot}/%{_tmpfilesdir} + install -p -m 644 %{zeb_rh_src}/quagga-tmpfs.conf \ + %{buildroot}/%{_tmpfilesdir}/quagga.conf +%endif + %pre # add vty_group %if 0%{?vty_group:1} @@ -371,7 +373,9 @@ for daemon in %all_daemons ; do done %endif -/sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir +if [ -f %{_infodir}/%{name}.inf* ]; then + /sbin/install-info %{_infodir}/quagga.info %{_infodir}/dir +fi # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then @@ -430,7 +434,7 @@ if [ "$1" -ge 1 ]; then for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ - %systemd_postun ${daemon}.service + %systemd_postun_with_restart ${daemon}.service done # Restart zebra. [ "$running_zebra" = yes ] && \ @@ -474,6 +478,10 @@ if [ "$1" -ge 1 ]; then %endif fi +if [ -f %{_infodir}/%{name}.inf* ]; then + /sbin/install-info --delete %{_infodir}/quagga.info %{_infodir}/dir +fi + %preun %if "%{initsystem}" == "systemd" ## @@ -495,7 +503,6 @@ fi done fi %endif -/sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %clean %if !0%{?keep_build:1} @@ -522,6 +529,9 @@ rm -rf %{buildroot} %endif %{_infodir}/quagga.info.gz %{_mandir}/man*/* +%if %{with_watchquagga} + %{_mandir}/man*/watchquagga.* +%endif %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd @@ -541,15 +551,16 @@ rm -rf %{buildroot} %{_sbindir}/nhrpd %endif %if %{with_shared} -%attr(755,root,root) %{_libdir}/lib*.so -%attr(755,root,root) %{_libdir}/lib*.so.* +%{_libdir}/quagga/lib*.so +%{_libdir}/quagga/lib*.so.? +%attr(755,root,root) %{_libdir}/quagga/lib*.so.?.?.? %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %if "%{initsystem}" == "systemd" - %config %{_unitdir}/*.service + %{_unitdir}/*.service %else %config /etc/rc.d/init.d/zebra %if %{with_watchquagga} @@ -573,18 +584,21 @@ rm -rf %{buildroot} %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* +%{_tmpfilesdir}/quagga.conf %files contrib %defattr(-,root,root) -%doc tools +%doc AUTHORS COPYING %attr(0644,root,root) tools %files devel %defattr(-,root,root) +%doc AUTHORS COPYING %if %{with_ospfclient} %{_sbindir}/ospfclient %endif -%{_libdir}/*.a -%{_libdir}/*.la +%dir %{_libdir}/quagga/ +%{_libdir}/quagga/*.a +%{_libdir}/quagga/*.la %dir %attr(755,root,root) %{_includedir}/%{name} %{_includedir}/%name/*.h %dir %attr(755,root,root) %{_includedir}/%{name}/ospfd @@ -595,6 +609,14 @@ rm -rf %{buildroot} %endif %changelog +* Mon Feb 27 2017 Paul Jakma - %{version} +- Apply 0001-systemd-various-service-file-improvements.patch from Fedora +- Review Fedora spec file and sync up with any useful differences, inc: +- Add tmpfiles.d config for Quagga from Fedora +- Add quagga-filter-perl-requires.sh from Fedora. +- Move libs to %{_libdir}/quagga as per Fedora +- use systemd_postun_with_restart for postun + * Tue Feb 14 2017 Timo Teräs - %{version} - add nhrpd From 4cdc030c8a37d4985dc1b9b7b1f5bf0d3bf52be7 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 3 Mar 2017 15:07:28 +0000 Subject: [PATCH 1290/1342] distro/redhat: build needs pkg-config and nhrpd needs c-ares --- redhat/quagga.spec.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index ba1eb190a..0e2306e71 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -121,7 +121,7 @@ Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: texi2html texinfo autoconf patch libcap-devel groff -BuildRequires: perl-generators +BuildRequires: perl-generators pkgconfig %if %{with_snmp} BuildRequires: net-snmp-devel Requires: net-snmp @@ -134,6 +134,10 @@ Requires: ncurses BuildRequires: pam-devel Requires: pam %endif +%if %{with_nhrpd} +BuildRequires: c-ares-devel +Requires: c-ares +%endif %if "%{initsystem}" == "systemd" BuildRequires: systemd Requires(post): systemd From 45c5426ac96a2ef815a9c21396678e1710ac4e52 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 3 Mar 2017 15:06:48 +0000 Subject: [PATCH 1291/1342] hacking: Add link to buildbot --- HACKING.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/HACKING.md b/HACKING.md index adc3b3707..363e58929 100644 --- a/HACKING.md +++ b/HACKING.md @@ -695,10 +695,18 @@ USEFUL URLs -* Patchwork tracks patches emailed to the quagga-dev list at: - - * Bugs can be reported via Bugzilla at: - + + +* Buildbot runs CI tests, and is at: + + + + It tests commits and jobs submitted on local changes via + 'buildbot try ...' for developers. + +* Patchwork tracks any patches emailed to the quagga-dev list, and is at: + + From db968b6d3277794f2a615a5292c33eec2b9e26e3 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 4 Mar 2017 00:11:57 +0000 Subject: [PATCH 1292/1342] doc: stop generating defines.texi from configure * generating defines.texi from configure means quagga.info will always have to be rebuilt by end-users, even from dist tarballs. Also breaks distcheck assumptions that info won't need to be built - which can be fixed with 'info-in-builddir' automake option, but that's too recent to rely on. * doc/defines.texi.in: nuke * doc/defines.texi: Add static version. * {doc/Makefile.am,configure}: nuke autogen of above * doc/quagga.texi: remove the 1 use of PACKAGE_STRING --- configure.ac | 1 - doc/.gitignore | 1 - doc/Makefile.am | 3 --- doc/{defines.texi.in => defines.texi} | 7 +++---- doc/quagga.texi | 2 +- 5 files changed, 4 insertions(+), 10 deletions(-) rename doc/{defines.texi.in => defines.texi} (72%) diff --git a/configure.ac b/configure.ac index ce8aba95c..7d9aa3f3c 100755 --- a/configure.ac +++ b/configure.ac @@ -1635,7 +1635,6 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile fpm/Makefile redhat/quagga.spec lib/version.h - doc/defines.texi isisd/topology/Makefile pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh]) diff --git a/doc/.gitignore b/doc/.gitignore index ed527fcb2..459531b9f 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -4,7 +4,6 @@ mdate-sh draft-zebra-00.txt quagga.info-* zebra.html -defines.texi version.texi quagga.html quagga.info diff --git a/doc/Makefile.am b/doc/Makefile.am index c7b289172..e20940d94 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -34,9 +34,6 @@ figures_txt = $(figures_names_parts:%=fig%.txt) # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. -# Built from defines.texi.in -BUILT_SOURCES = defines.texi - info_TEXINFOS = quagga.texi # Have to manually specify the quagga.pdf rule in order to allow diff --git a/doc/defines.texi.in b/doc/defines.texi similarity index 72% rename from doc/defines.texi.in rename to doc/defines.texi index a4badef0e..b7b529ec3 100644 --- a/doc/defines.texi.in +++ b/doc/defines.texi @@ -1,10 +1,9 @@ @c -*- texinfo -*- -@c @configure_input@ @c Set variables -@set PACKAGE_NAME @PACKAGE_NAME@ -@set PACKAGE_TARNAME @PACKAGE_TARNAME@ -@set PACKAGE_STRING @PACKAGE_STRING@ +@set PACKAGE_NAME Quagga +@set PACKAGE_TARNAME quagga +@set PACKAGE_STRING Quagga 1.2.0 @set AUTHORS Kunihiro Ishiguro, et al. @set COPYRIGHT_YEAR 1999-2005 @set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS} diff --git a/doc/quagga.texi b/doc/quagga.texi index bcf23de7c..3e21cf87d 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -70,7 +70,7 @@ Version @value{VERSION}. @uref{http://www.quagga.net,,Quagga} is an advanced routing software package that provides a suite of TCP/IP based routing protocols. This is the Manual -for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of +for Quagga @value{VERSION}. @uref{http://www.quagga.net,,Quagga} is a fork of @uref{http://www.zebra.org,,GNU Zebra}. @insertcopying From db2dafa63bd527fc9ef49c1997f385c79294e65a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 3 Mar 2017 18:08:03 +0000 Subject: [PATCH 1293/1342] build: Fix distcheck errors * doc/Makefile.am: Clean up the info files. Ignore errors with DVI building, who cares. * tests/Makefile.am: cleanup stuff to fix distcleancheck --- doc/Makefile.am | 6 ++++++ tests/Makefile.am | 2 ++ 2 files changed, 8 insertions(+) diff --git a/doc/Makefile.am b/doc/Makefile.am index e20940d94..85af812da 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -119,3 +119,9 @@ EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ + +DISTCLEANFILES = quagga.info* + +# do nothing for DVI, so we don't have to generate or distribute EPS +# figures +dvi: # nothing diff --git a/tests/Makefile.am b/tests/Makefile.am index 16c9e4c3d..b13e903dc 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -43,6 +43,8 @@ test-commands-defun.c: ../vtysh/vtysh_cmd.c > test-commands-defun.c BUILT_SOURCES = test-commands-defun.c +CLEANFILES = test-commands-defun.c bgpd libzebra + noinst_HEADERS = prng.h tests.h common-cli.h testcli_SOURCES = test-cli.c common-cli.c From 32b4fb45f577cce2ab354c4914a2af845ebfc4e4 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 4 Mar 2017 00:08:19 +0000 Subject: [PATCH 1294/1342] HACKING: example config for buildbot client and usage for 'try' command --- HACKING.md | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/HACKING.md b/HACKING.md index 363e58929..b0f56c538 100644 --- a/HACKING.md +++ b/HACKING.md @@ -431,7 +431,7 @@ HACKING THE BUILD SYSTEM ======================== If you change or add to the build system (configure.ac, any Makefile.am, -etc.), try to check that the following things still work: +etc.), please heck that the following things still work: - make dist @@ -439,6 +439,8 @@ etc.), try to check that the following things still work: - out-of-tree builds +This can be achieved by running 'make distcheck' + The quagga.net site relies on make dist to work to generate snapshots. It must work. Common problems are to forget to have some additional file included in the dist, or to have a make rule refer to a source file without @@ -710,3 +712,43 @@ USEFUL URLs * Patchwork tracks any patches emailed to the quagga-dev list, and is at: + + +BUILDBOT +======== + +The buildbot client can be used to test changes before committing, with +"buildbot try". + +- Ask for a buildbot account + +- Install the buildbot client + +- Configure it, e.g.: + + ~~~~~ + $ cat ~/.buildbot/options + try_master = 'radia.quagga.net:8031' + try_username = 'paul' + try_password = 'password123' + try_vc = 'git' + try_branch = 'master' + try_wait = True + $ buildbot try -c pb --get-builder-names + using 'pb' connect method + The following builders are available for the try scheduler: + build-fedora-24 + ... + ~~~~~ + +- You can then submit your local changes to try build: + + ~~~~ + $ buildbot try -c pb + ~~~~ + + or use the -b argument to limit to a specific builder (recommended). + + ~~~~~ + $ buildbot try -c pb -b build-distcheck + ~~~~~ From d77ad3cff1d3d32bce7b49dbefebda7c10f1592e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 4 Mar 2017 00:10:30 +0000 Subject: [PATCH 1295/1342] HACKING: fix indentation in URLs list, remove super obsolete import section --- HACKING.md | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/HACKING.md b/HACKING.md index b0f56c538..b63c1b022 100644 --- a/HACKING.md +++ b/HACKING.md @@ -670,48 +670,28 @@ Daemons which are in a testing phase are - watchquagga -IMPORT OR UPDATE VENDOR SPECIFIC ROUTING PROTOCOLS -================================================== - -The source code of Quagga is based on two vendors: - -`zebra_org` () `isisd_sf` -() - -To import code from further sources, e.g. for archival purposes without -necessarily having to review and/or fix some changeset, create a branch -from ‘master’: - - git checkout -b archive/foo master - - git commit -a "Joe Bar " - git push quagga archive/foo - -presuming ‘quagga’ corresponds to a file in your .git/remotes with -configuration for the appropriate Quagga.net repository. - USEFUL URLs =========== -* The project homepage is at: +* The project homepage is at: - + -* Bugs can be reported via Bugzilla at: +* Bugs can be reported via Bugzilla at: - + -* Buildbot runs CI tests, and is at: +* Buildbot runs CI tests, and is at: - + - It tests commits and jobs submitted on local changes via - 'buildbot try ...' for developers. + It tests commits and jobs submitted on local changes via + 'buildbot try ...' for developers. -* Patchwork tracks any patches emailed to the quagga-dev list, and is at: +* Patchwork tracks any patches emailed to the quagga-dev list, and is at: - + BUILDBOT From 08815d59c369ee2698d304d91e22e6eddcce31ae Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 4 Mar 2017 14:30:44 +0000 Subject: [PATCH 1296/1342] infra: buildbot master configs and slave systemd service file * master: master.cfg and example pass.cfg file * worker: systemd service unit file. Setting up a slave/worker is trivial: su - buildbot buildslave create-slave . radia.quagga.net buildbot- --- infra/buildbot/master/master.cfg | 391 +++++++++++++++++++ infra/buildbot/master/pass.cfg | 21 + infra/buildbot/worker/buildbot-slave.service | 13 + 3 files changed, 425 insertions(+) create mode 100644 infra/buildbot/master/master.cfg create mode 100644 infra/buildbot/master/pass.cfg create mode 100644 infra/buildbot/worker/buildbot-slave.service diff --git a/infra/buildbot/master/master.cfg b/infra/buildbot/master/master.cfg new file mode 100644 index 000000000..256123494 --- /dev/null +++ b/infra/buildbot/master/master.cfg @@ -0,0 +1,391 @@ +# -*- python -*- +# ex: set syntax=python: + +from buildbot.plugins import * +from buildbot.plugins import buildslave, util + +# This is a sample buildmaster config file. It must be installed as +# 'master.cfg' in your buildmaster's base directory. + +# This is the dictionary that the buildmaster pays attention to. We also use +# a shorter alias to save typing. +c = BuildmasterConfig = {} + +quaggagit = 'git://git.sv.gnu.org/quagga.git' + +# password defs +execfile("pass.cfg") + +workers = { + "fedora-24": { + "os": "Fedora", + "version": "24", + "vm": False, + "pkg": "rpm", + }, + "centos-7": { + "os": "CentOS", + "version": "7", + "vm": False, + "pkg": "rpm", + }, + "debian-8": { + "os": "Debian", + "version": "8", + "vm": True, + "pkg": "dpkg", + "latent": True, + "hd_image": "/var/lib/libvirt/images/debian8.qcow2", + }, + "debian-9": { + "os": "Debian", + "version": "9", + "vm": True, + "pkg": "dpkg", + "latent": True, + "hd_image": "/var/lib/libvirt/images/debian9.qcow2", + }, + "freebsd-10": { + "os": "FreeBSD", + "version": "10", + "vm": True, + "pkg": "", + "latent": True, + "hd_image": "/var/lib/libvirt/images/freebsd103.qcow2", + }, + "freebsd-11": { + "os": "FreeBSD", + "version": "11", + "vm": True, + "pkg": "", + "latent": True, + "hd_image": "/var/lib/libvirt/images/freebsd110.qcow2", + }, +} + +# ensure "latent" is set to false, where not set. +# add in the passwords +for kw in workers: + w = workers[kw] + w["bot"] = "buildbot-" + kw + if "latent" not in w: + w["latent"] = False + w["pass"] = workers_pass[kw] + +analyses_builders = [ "clang-analyzer" ] + +# default Libvirt session +for w in (w for w in workers.values () if ("latent" in w) + and ("session" not in w)): + w["session"] = 'qemu+ssh://buildbot@sagan.jakma.org/system' + +osbuilders = list("build-" + kw for kw in workers) + +allbuilders = [] +allbuilders += osbuilders +allbuilders += analyses_builders +allbuilders += ["commit-builder"] +allbuilders += ["build-distcheck"] + +# Force merging of requests. +c['mergeRequests'] = lambda *args, **kwargs: True + +####### BUILDSLAVES +c['slaves'] = [] + +# The 'slaves' list defines the set of recognized buildslaves. Each element is +# a BuildSlave object, specifying a unique slave name and password. The same +# slave name and password must be configured on the slave. + +for w in (w for w in workers.values() if ("latent" not in w) + or (w["latent"] == False)): + c['slaves'].append(buildslave.BuildSlave(w["bot"], w["pass"])) + +for w in (w for w in workers.values() + if ("latent" in w) + and w["latent"] + and "hd_image" in w): + c['slaves'].append(buildslave.LibVirtSlave( + w["bot"], + w["pass"], + util.Connection(w["session"]), + w["hd_image"], + )) + +# 'protocols' contains information about protocols which master will use for +# communicating with slaves. +# You must define at least 'port' option that slaves could connect to your master +# with this protocol. +# 'port' must match the value configured into the buildslaves (with their +# --master option) +c['protocols'] = {'pb': {'port': 9989}} + +####### CHANGESOURCES + +# the 'change_source' setting tells the buildmaster how it should find out +# about source code changes. Here we point to the buildbot clone of pyflakes. + +c['change_source'] = [] +c['change_source'].append(changes.GitPoller( + quaggagit, + workdir='gitpoller-workdir', + branches=['master','volatile/next'], + pollinterval=300)) + +####### SCHEDULERS + +# Configure the Schedulers, which decide how to react to incoming changes. + +# We want a first line of 'quick' builds, which then trigger further builds. +# +# A control-flow builder, "commit-builder", used to sequence the 'real' +# sets of builders, via Triggers. + +c['schedulers'] = [] +c['schedulers'].append(schedulers.SingleBranchScheduler( + name="master-change", + change_filter=util.ChangeFilter(branch='master'), + treeStableTimer=10, + builderNames=[ "commit-builder" ])) + +c['schedulers'].append(schedulers.SingleBranchScheduler( + name="next-change", + change_filter=util.ChangeFilter( + branch='volatile/next'), + treeStableTimer=10, + builderNames=[ "commit-builder" ] )) + +# Initial build checks on faster, non-VM +c['schedulers'].append(schedulers.Triggerable( + name="trigger-build-first", + builderNames=list("build-" + kw + for kw in workers + if workers[kw]["vm"] == False))) + +# Build using remaining builders, after firstbuilders. +c['schedulers'].append(schedulers.Triggerable( + name="trigger-build-rest", + builderNames=list("build-" + kw + for w in workers + if workers[kw]["vm"] == True))) + +# Analyses tools, e.g. CLang Analyzer scan-build +c['schedulers'].append(schedulers.Triggerable( + name="trigger-build-analyses", + builderNames=analyses_builders)) +# Dist check +c['schedulers'].append(schedulers.Triggerable( + name="trigger-distcheck", + builderNames=["build-distcheck"])) + +# Try and force schedulers +c['schedulers'].append(schedulers.ForceScheduler( + name="force", + builderNames=allbuilders)) + +c['schedulers'].append(schedulers.Try_Userpass( + name="try", + builderNames=list("build-" + kw + for w in workers) + + ["build-distcheck", + "clang-analyzer" ], + userpass=users, + port=8031)) + +####### BUILDERS +c['builders'] = [] + +# The 'builders' list defines the Builders, which tell Buildbot how to perform a build: +# what steps, and which slaves can execute them. Note that any particular build will +# only take place on one slave. + +common_steps = [ +steps.Git(repourl=quaggagit, mode='incremental'), +steps.ShellCommand(command=["./update-autotools"]), +steps.Configure(), +steps.ShellCommand(command=["make", "clean"]), +steps.Compile(), +] + +### Each OS specific builder + +factory = util.BuildFactory() +# check out the source +factory.addStep(steps.Git(repourl=quaggagit, mode='incremental')) +factory.addStep(steps.ShellCommand(command=["./update-autotools"], + description="generating autoconf", + descriptionDone="autoconf generated")) +factory.addStep(steps.Configure()) +factory.addStep(steps.ShellCommand(command=["make", "clean"], + description="cleaning", + descriptionDone="cleaned")) +factory.addStep(steps.Compile(command=["make", "-j", "2", "all"])) +factory.addStep(steps.ShellCommand(command=["make", "check"], + description="testing", + descriptionDone="tests")) + +for kw in workers: + c['builders'].append(util.BuilderConfig( + name="build-" + kw, + slavenames=workers[kw]["bot"], + factory=factory)) + +### distcheck +factory = util.BuildFactory() +# check out the source +factory.addStep(steps.Git(repourl=quaggagit, mode='incremental')) +factory.addStep(steps.ShellCommand(command=["./update-autotools"], + description="generating autoconf", + descriptionDone="autoconf generated")) +factory.addStep(steps.Configure()) +factory.addStep(steps.ShellCommand(command=["make", "clean"], + description="cleaning", + descriptionDone="cleaned")) +factory.addStep(steps.ShellCommand(command=["make", "distcheck"], + description="distcheck", + descriptionDone="distcheck passes")) +c['builders'].append( + util.BuilderConfig(name="build-distcheck", + slavenames=list(w["bot"] for w in workers.values()), + factory=factory, +)) + +### LLVM clang-analyzer build + +f = util.BuildFactory() +# check out the source +f.addStep(steps.Git(repourl=quaggagit, mode='incremental', + getDescription=True)) +f.addStep(steps.ShellCommand(command=["./update-autotools"], + description="autotools", + descriptionDone="autoconf generated")) +f.addStep(steps.Configure()) +f.addStep(steps.ShellCommand(command=["make", "clean"], + description="cleaning", + descriptionDone="cleaned")) + +f.addStep(steps.SetProperty(property="clang-id", + value=util.Interpolate("%(prop:commit-description)s-%(prop:buildnumber)s"))) + +f.addStep(steps.SetProperty(property="clang-output-dir", + value=util.Interpolate("../CLANG-%(prop:clang-id)s"))) +f.addStep(steps.SetProperty(property="clang-uri", + value=util.Interpolate("/clang-analyzer/%(prop:clang-id)s"))) +# relative to buildbot master working directory +f.addStep(steps.SetProperty(property="clang-upload-dir", + value=util.Interpolate("public_html/clang-analyzer/%(prop:clang-id)s"))) + +f.addStep(steps.Compile(command=["scan-build", + "-analyze-headers", + "-o", + util.Interpolate("%(prop:clang-output-dir)s"), + "make", "-j", "all"])) +f.addStep(steps.DirectoryUpload( + slavesrc=util.Interpolate("%(prop:clang-output-dir)s"), + masterdest = util.Interpolate("%(prop:clang-upload-dir)s"), + compress = 'bz2', + name = "clang report", + url = util.Interpolate("%(prop:clang-uri)s"), +)) +f.addStep(steps.RemoveDirectory( + dir=util.Interpolate("%(prop:clang-output-dir)s") +)) + +c['builders'].append( + util.BuilderConfig(name="clang-analyzer", + slavenames=list(w["bot"] for w in workers.values() if not w["vm"]), + factory=f)) + +## Co-ordination builds used to sequence parallel builds via Triggerable +f = util.BuildFactory() +f.addStep(steps.Trigger ( + schedulerNames = [ "trigger-build-first" ], + waitForFinish=True +)) +f.addStep(steps.Trigger ( + schedulerNames = [ "trigger-build-rest" ], + waitForFinish=True +)) +f.addStep(steps.Trigger ( + schedulerNames = [ "trigger-build-analyses", "trigger-distcheck" ], + waitForFinish=True +)) + +c['builders'].append( + util.BuilderConfig(name="commit-builder", + slavenames=["buildbot-fedora-24"], + factory=f +)) + +####### STATUS TARGETS + +# 'status' is a list of Status Targets. The results of each build will be +# pushed to these targets. buildbot/status/*.py has a variety to choose from, +# including web pages, email senders, and IRC bots. + +c['status'] = [] + +from buildbot.status import html +from buildbot.status.web import authz, auth + +authz_cfg=authz.Authz( + # change any of these to True to enable; see the manual for more + # options + #auth=auth.BasicAuth([("pyflakes","pyflakes")]), + auth=util.BasicAuth(users), + gracefulShutdown = False, + forceBuild = 'auth', # use this to test your slave once it is set up + forceAllBuilds = 'auth', # ..or this + pingBuilder = 'auth', + stopBuild = 'auth', + stopAllBuilds = 'auth', + cancelPendingBuild = 'auth', + cancelAllPendingBuilds = 'auth', + pauseSlave = 'auth', +) +c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg)) + +c['status'].append(status.MailNotifier( + fromaddr="buildbot@quagga.net", + extraRecipients=["paul@jakma.org"], + sendToInterestedUsers=False, +)) + +c['status'].append (status.IRC( + "irc.freenode.net", "bb-quagga", + useColors=True, + channels=[{"channel": "#quagga"}], + notify_events={ + 'exception': 1, + 'successToFailure': 1, + 'failureToSuccess': 1, + }, +)) + +####### PROJECT IDENTITY + +# the 'title' string will appear at the top of this buildbot +# installation's html.WebStatus home page (linked to the +# 'titleURL') and is embedded in the title of the waterfall HTML page. + +c['title'] = "Quagga" +c['titleURL'] = "https://www.quagga.net/" + +# the 'buildbotURL' string should point to the location where the buildbot's +# internal web server (usually the html.WebStatus page) is visible. This +# typically uses the port number set in the Waterfall 'status' entry, but +# with an externally-visible host name which the buildbot cannot figure out +# without some help. + +c['buildbotURL'] = "http://buildbot.quagga.net/" + +####### DB URL + +c['db'] = { + # This specifies what database buildbot uses to store its state. You can leave + # this at its default for all but the largest installations. + 'db_url' : "sqlite:///state.sqlite", +} + +#### debug +c['debugPassword'] = debugPassword diff --git a/infra/buildbot/master/pass.cfg b/infra/buildbot/master/pass.cfg new file mode 100644 index 000000000..34a9340bd --- /dev/null +++ b/infra/buildbot/master/pass.cfg @@ -0,0 +1,21 @@ +# -*- python -*- +# ex: set syntax=python: + +# example pass.cfg + +# privileged users for webui and try building +#users = [ +# ('foo', 'password123'), +#] + +workers_pass = { + "fedora-24": "aaaaaaa", + "centos-7": "bbbbbbb", + "debian-8": "ccccccc", + "debian-9": "ddddddd", + "freebsd-10": "eeeeeee", + "freebsd-11": "fffffff", +} + +#### debug +#debugPassword = "abcdefghijklmnopqrstuvwxyz" diff --git a/infra/buildbot/worker/buildbot-slave.service b/infra/buildbot/worker/buildbot-slave.service new file mode 100644 index 000000000..dcb136fa5 --- /dev/null +++ b/infra/buildbot/worker/buildbot-slave.service @@ -0,0 +1,13 @@ +[Unit] +Description=Buildbot slave Daemon + +[Service] +WorkingDirectory=/home/buildbot +User=buildbot +Group=buildbot +ExecStart=/usr/bin/buildslave start --nodaemon +ExecStop=/usr/bin/buildslave stop +ExecReload=/usr/bin/buildslave reconfig + +[Install] +WantedBy=multi-user.target From 7e43fe44ba1a7da4bd8520625ab5f66867fce761 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 4 Mar 2017 15:09:41 +0000 Subject: [PATCH 1297/1342] infra/patchwork: systemd files and production.py settings * systemd/patchwork-delivery*: on demand socket to take mail in a localhost TCP socket, to allow patchwork to be in a separate container from email. * production.py: patchwork.settings.production file. * pass.py: example pass.py file --- infra/patchwork/pass.py | 4 + infra/patchwork/production.py | 89 +++++++++++++++++++ .../systemd/patchwork-delivery.socket | 15 ++++ .../systemd/patchwork-delivery@.service | 15 ++++ infra/patchwork/systemd/patchwork.service | 12 +++ 5 files changed, 135 insertions(+) create mode 100644 infra/patchwork/pass.py create mode 100644 infra/patchwork/production.py create mode 100644 infra/patchwork/systemd/patchwork-delivery.socket create mode 100644 infra/patchwork/systemd/patchwork-delivery@.service create mode 100644 infra/patchwork/systemd/patchwork.service diff --git a/infra/patchwork/pass.py b/infra/patchwork/pass.py new file mode 100644 index 000000000..65142328d --- /dev/null +++ b/infra/patchwork/pass.py @@ -0,0 +1,4 @@ +# example pass file +SECRET_KEY = "aaaaaaaaaaaaaaaaaa" +EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', '') +DATABASES['default']['PASSWORD'] = os.environ.get('DATABASE_PASSWORD', 'bbbbbbbbbbbbbbbbbbbbb'); diff --git a/infra/patchwork/production.py b/infra/patchwork/production.py new file mode 100644 index 000000000..1683c0c54 --- /dev/null +++ b/infra/patchwork/production.py @@ -0,0 +1,89 @@ +""" +Sample production-ready settings for patchwork project. + +Most of these are commented out as they will be installation dependent. + +Design based on: + http://www.revsys.com/blog/2014/nov/21/recommended-django-project-layout/ +""" + +from __future__ import absolute_import + +import os + +import django + +from .base import * # noqa + +DEBUG = True +# +# Core settings +# https://docs.djangoproject.com/en/1.8/ref/settings/#core-settings +# + +# Security +# +# You'll need to replace this to a random string. The following python code can +# be used to generate a secret key: +# +# import string, random +# chars = string.letters + string.digits + string.punctuation +# print repr("".join([random.choice(chars) for i in range(0,50)])) + +# Email +# +# Replace this with your own details + +EMAIL_HOST = os.getenv('EMAIL_HOST', 'localhost') +EMAIL_PORT = os.getenv('EMAIL_PORT', 25) +EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', '') +# password goes in pass.py +EMAIL_USE_TLS = True + +DEFAULT_FROM_EMAIL = 'Patchwork ' +SERVER_EMAIL = DEFAULT_FROM_EMAIL +NOTIFICATION_FROM_EMAIL = DEFAULT_FROM_EMAIL + +ADMINS = ( + ('Paul Jakma', 'paul@quagga.net'), +) + +# Database +# +# If you're using a postgres database, connecting over a local unix-domain +# socket, then the following setting should work for you. Otherwise, +# see https://docs.djangoproject.com/en/1.8/ref/settings/#databases + +# password goes in pass.py +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DATABASE_NAME', 'patchwork'), + 'USER': os.environ.get('DATABASE_USER', 'patchwork'), + 'HOST': '127.0.0.1', + }, +} + + +# +# Static files settings +# https://docs.djangoproject.com/en/1.8/ref/settings/#static-files +# https://docs.djangoproject.com/en/1.8/ref/contrib/staticfiles/#manifeststaticfilesstorage +# + +STATIC_ROOT = os.environ.get('STATIC_ROOT', '/home/patchwork/htdocs/static') + + +if django.VERSION >= (1, 7): + STATICFILES_STORAGE = \ + 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' + +ENABLE_XMLRPC = True + +LANGUAGE_CODE='en-gb' +TIME_ZONE='GMT' +ALLOWED_HOSTS=['patchwork.quagga.net','testpw.quagga.net', 'http', 'http.quagga.net', '*.quagga.net'] + +with open("patchwork/settings/pass.py") as f: + code = compile(f.read(), "patchwork/settings/pass.py", 'exec') + exec(code) diff --git a/infra/patchwork/systemd/patchwork-delivery.socket b/infra/patchwork/systemd/patchwork-delivery.socket new file mode 100644 index 000000000..bfa675285 --- /dev/null +++ b/infra/patchwork/systemd/patchwork-delivery.socket @@ -0,0 +1,15 @@ +[Unit] +Description=Patchwork unix pipe to accept list mail delivery on + +[Socket] +#ListenStream=/tmp/patchwork.sock +ListenStream=127.0.0.1:8001 +SocketUser=patchwork +SocketGroup=patchwork +Accept=yes + +#ListenFIFO=/tmp/patchwork-fifo.sock + + +[Install] +WantedBy=sockets.target diff --git a/infra/patchwork/systemd/patchwork-delivery@.service b/infra/patchwork/systemd/patchwork-delivery@.service new file mode 100644 index 000000000..d152b2d65 --- /dev/null +++ b/infra/patchwork/systemd/patchwork-delivery@.service @@ -0,0 +1,15 @@ +[Unit] +Description=Patchwork list mail socket processing script + +[Service] +EnvironmentFile=/home/patchwork/patchwork.env +ExecStart=-/home/patchwork/patchwork/patchwork/bin/parsemail.sh +StandardInput=socket +StandardOutput=inherit +StandardError=journal +User=patchwork +Group=patchwork + +[Install] +WantedBy=multi-user.target +Also=patchwork-delivery.socket diff --git a/infra/patchwork/systemd/patchwork.service b/infra/patchwork/systemd/patchwork.service new file mode 100644 index 000000000..90ec4bb22 --- /dev/null +++ b/infra/patchwork/systemd/patchwork.service @@ -0,0 +1,12 @@ +[Unit] +Description=Patchwork Daemon + +[Service] +WorkingDirectory=/home/patchwork/patchwork +User=patchwork +Group=patchwork +EnvironmentFile=/home/patchwork/patchwork.env +ExecStart=/usr/bin/python3 manage.py runserver 0.0.0.0:8000 + +[Install] +WantedBy=multi-user.target From 75ebcd86b1abd5db97b91a2cff1df6ba444cca7c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Mar 2017 10:21:02 +0000 Subject: [PATCH 1298/1342] distro/redhat: fix rpmlint warnings * quagga.spec.in: Use %global when defining globals inside conditional blocks. Comment Obsoletes as rpmlint wants specific versions. The packages are long gone, but leave as historical documentation. Don't use %version in changelog entries, or other live macros. Fix spaces-for-indent everywhere, use tab (sorry spaces people). --- redhat/quagga.spec.in | 86 +++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 0e2306e71..0c927e6f8 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -15,7 +15,7 @@ %{!?with_tcp_zebra: %global with_tcp_zebra 0 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_pam: %global with_pam 1 } -%{!?with_ospfclient: %global with_ospfclient 1 } +%{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } %{!?with_irdp: %global with_irdp 1 } %{!?with_rtadv: %global with_rtadv 1 } @@ -26,8 +26,8 @@ %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavt } -%{!?with_fpm: %global with_fpm 0 } -%{!?with_watchquagga: %global with_watchquagga 1 } +%{!?with_fpm: %global with_fpm 0 } +%{!?with_watchquagga: %global with_watchquagga 1 } # path defines %define _sysconfdir /etc/quagga @@ -41,8 +41,8 @@ #### Version String tweak # Remove invalid characters form version string and replace with _ -%{expand: %%define rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} -%define quaggaversion @VERSION@ +%{expand: %%global rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} +%define quaggaversion @VERSION@ #### Check version of texi2html # Old versions don't support "--number-footnotes" option. @@ -68,9 +68,9 @@ %endif # misc internal defines -%{!?quagga_uid: %define quagga_uid 92 } -%{!?quagga_gid: %define quagga_gid 92 } -%{!?vty_gid: %define vty_gid 85 } +%{!?quagga_uid: %global quagga_uid 92 } +%{!?quagga_gid: %global quagga_gid 92 } +%{!?vty_gid: %global vty_gid 85 } %define daemon_list zebra ripd ospfd bgpd @@ -83,19 +83,19 @@ %endif %if %{with_pimd} -%define daemon_pimd pimd +%define daemon_pimd pimd %else %define daemon_pimd "" %endif %if %{with_nhrpd} -%define daemon_nhrpd nhrpd +%define daemon_nhrpd nhrpd %else %define daemon_nhrpd "" %endif %if %{with_watchquagga} -%define daemon_watchquagga watchquagga +%define daemon_watchquagga watchquagga %else %define daemon_watchquagga "" %endif @@ -106,7 +106,7 @@ %{!?keep_build: %global keep_build 0 } #release sub-revision (the two digits after the CONFDATE) -%{!?release_rev: %define release_rev 01 } +%{!?release_rev: %global release_rev 01 } Summary: Routing daemon Name: quagga @@ -121,18 +121,18 @@ Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: texi2html texinfo autoconf patch libcap-devel groff -BuildRequires: perl-generators pkgconfig +BuildRequires: perl-generators pkgconfig %if %{with_snmp} BuildRequires: net-snmp-devel -Requires: net-snmp +Requires: net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel -Requires: ncurses +Requires: ncurses %endif %if %{with_pam} BuildRequires: pam-devel -Requires: pam +Requires: pam %endif %if %{with_nhrpd} BuildRequires: c-ares-devel @@ -149,7 +149,7 @@ Requires(pre): initscripts >= 5.60 %endif Provides: routingdaemon = %{version}-%{release} BuildRoot: %{_tmppath}/%{name}-%{version}-root -Obsoletes: mrt zebra quagga-sysvinit +#Obsoletes: mrt zebra quagga-sysvinit %define __perl_requires %{zeb_rh_src}/quagga-filter-perl-requires.sh @@ -175,20 +175,10 @@ The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep -%setup -q -n quagga-%{quaggaversion} +%setup -q -n quagga-%{quaggaversion} %build -# For standard gcc verbosity, uncomment these lines: -#CFLAGS="%{optflags} -Wall -Wsign-compare -Wpointer-arith" -#CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" - -# For ultra gcc verbosity, uncomment these lines also: -#CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" -#CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" -#CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" -#CFLAGS="${CFLAGS} -Wpacked -Wpadded" - %configure \ --sysconfdir=%{_sysconfdir} \ --libdir=%{_libdir}/quagga \ @@ -274,7 +264,7 @@ popd %install mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ - %{buildroot}/var/log/quagga %{buildroot}%{_infodir} + %{buildroot}/var/log/quagga %{buildroot}%{_infodir} make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install # Remove this file, as it is uninstalled and causes errors when building on RH9 @@ -318,19 +308,19 @@ install -d -m750 %{buildroot}/var/run/quagga # add vty_group %if 0%{?vty_group:1} if getent group %vty_group > /dev/null ; then : ; else \ - /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi + /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if 0%{?quagga_user:1} # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ - /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ + /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ fi if getent passwd %quagga_user >/dev/null ; then : ; else \ - /usr/sbin/useradd -u %quagga_uid -g %quagga_gid -G %vty_group \ - -M -r -s /sbin/nologin -c "Quagga routing suite" \ - -d %_localstatedir %quagga_user 2> /dev/null || : ; \ + /usr/sbin/useradd -u %quagga_uid -g %quagga_gid -G %vty_group \ + -M -r -s /sbin/nologin -c "Quagga routing suite" \ + -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi %endif @@ -348,23 +338,23 @@ zebra_spec_add_service () } zebra_spec_add_service zebrasrv 2600/tcp "zebra service" -zebra_spec_add_service zebra 2601/tcp "zebra vty" -zebra_spec_add_service ripd 2602/tcp "RIPd vty" -zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" -zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" -zebra_spec_add_service bgpd 2605/tcp "BGPd vty" -zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" +zebra_spec_add_service zebra 2601/tcp "zebra vty" +zebra_spec_add_service ripd 2602/tcp "RIPd vty" +zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" +zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" +zebra_spec_add_service bgpd 2605/tcp "BGPd vty" +zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" %if %{with_ospfapi} -zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" +zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif %if %{with_isisd} -zebra_spec_add_service isisd 2608/tcp "ISISd vty" +zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif %if %{with_pimd} -zebra_spec_add_service pimd 2611/tcp "PIMd vty" +zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif %if %{with_nhrpd} -zebra_spec_add_service nhrpd 2612/tcp "NHRPd vty" +zebra_spec_add_service nhrpd 2612/tcp "NHRPd vty" %endif %if "%{initsystem}" == "systemd" @@ -502,7 +492,7 @@ fi ## if [ "$1" = "0" ]; then for daemon in %all_daemons ; do - /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 + /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 /sbin/chkconfig --del ${daemon} done fi @@ -613,15 +603,15 @@ rm -rf %{buildroot} %endif %changelog -* Mon Feb 27 2017 Paul Jakma - %{version} +* Mon Feb 27 2017 Paul Jakma - Apply 0001-systemd-various-service-file-improvements.patch from Fedora - Review Fedora spec file and sync up with any useful differences, inc: - Add tmpfiles.d config for Quagga from Fedora - Add quagga-filter-perl-requires.sh from Fedora. -- Move libs to %{_libdir}/quagga as per Fedora +- Move libs to %%{_libdir}/quagga as per Fedora - use systemd_postun_with_restart for postun -* Tue Feb 14 2017 Timo Teräs - %{version} +* Tue Feb 14 2017 Timo Teräs - add nhrpd * Thu Feb 11 2016 Paul Jakma From 304ec31598895c8c6da7a9fa9b9ba1f7217cced0 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Mar 2017 12:39:41 +0000 Subject: [PATCH 1299/1342] distro/redhat: Make texi2html conditional, default off, to avoid TeX deps --- redhat/quagga.spec.in | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 0c927e6f8..a4478fd2c 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -28,6 +28,8 @@ %{!?vty_group: %global vty_group quaggavt } %{!?with_fpm: %global with_fpm 0 } %{!?with_watchquagga: %global with_watchquagga 1 } +# whether to build doc/quagga.html - requires a lot of TeX packages +%{!?with_texi2html: %global with_texi2html 0 } # path defines %define _sysconfdir /etc/quagga @@ -46,7 +48,9 @@ #### Check version of texi2html # Old versions don't support "--number-footnotes" option. -%{expand: %%global texi2htmlversion %(type texi2html >/dev/null 2>&1 && (rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1) || echo 0 )} +%if %{with_texi2html} + %{expand: %%global texi2htmlversion %(type texi2html >/dev/null 2>&1 && (rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1) || echo 0 )} +%endif #### Check for systemd or init.d (upstart) # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) @@ -120,8 +124,11 @@ Requires: ncurses Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info -BuildRequires: texi2html texinfo autoconf patch libcap-devel groff +BuildRequires: autoconf patch libcap-devel groff BuildRequires: perl-generators pkgconfig +%if %{with_texi2html} +BuildRequires: texi2html +%endif %if %{with_snmp} BuildRequires: net-snmp-devel Requires: net-snmp @@ -254,13 +261,15 @@ developing OSPF-API and quagga applications. make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" -pushd doc -%if %{texi2htmlversion} < 5 -texi2html --number-sections quagga.texi -%else -texi2html --number-footnotes --number-sections quagga.texi +%if %{with_texi2html} + pushd doc + %if %{texi2htmlversion} < 5 + texi2html --number-sections quagga.texi + %else + texi2html --number-footnotes --number-sections quagga.texi + %endif + popd %endif -popd %install mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ @@ -506,7 +515,9 @@ rm -rf %{buildroot} %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING -%doc doc/quagga.html +%if %{with_texi2html} + %doc doc/quagga.html +%endif %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if 0%{?quagga_user:1} @@ -603,6 +614,11 @@ rm -rf %{buildroot} %endif %changelog +* Sun Mar 5 2017 Paul Jakma +- Fix lint errors +- Make texi2html conditional, disable by default to avoid needing TeX + by default + * Mon Feb 27 2017 Paul Jakma - Apply 0001-systemd-various-service-file-improvements.patch from Fedora - Review Fedora spec file and sync up with any useful differences, inc: From 3bc12739fdaccfcf73cafa51c98046e58529fe80 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Mar 2017 13:33:25 +0000 Subject: [PATCH 1300/1342] distro/redhat: Allow for split info files --- redhat/quagga.spec.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index a4478fd2c..3bf5b9d05 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -259,7 +259,7 @@ developing OSPF-API and quagga applications. %endif --enable-gcc-rdynamic -make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" +make %{?_smp_mflags} %if %{with_texi2html} pushd doc @@ -532,7 +532,7 @@ rm -rf %{buildroot} %if 0%{?vty_group:1} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif -%{_infodir}/quagga.info.gz +%{_infodir}/quagga.info*.gz %{_mandir}/man*/* %if %{with_watchquagga} %{_mandir}/man*/watchquagga.* From 390bffa452d4c9525587dbc8a7a19a9b096c11fa Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Mar 2017 14:27:11 +0000 Subject: [PATCH 1301/1342] infra/buildbot: Add initial RPM check builders * master.cfg: Add an initial RPM rpm check builders, to run rpmlint and rpmbuild tests on builders with "pkg" == "rpm". some issues in buildbot (least on F24): - RpmLint doesn't get imported, have to run manually. - RpmBuild always sets 'dist', it shouldn't really. urg. - RpmBuild 'rpmdir' argument doesn't get Interpolated, so can't put the built RPMs cleanly into a distinct directory. When fixed, can auto-publish RPMs. For now, just check. --- infra/buildbot/master/master.cfg | 104 ++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/infra/buildbot/master/master.cfg b/infra/buildbot/master/master.cfg index 256123494..3bb271112 100644 --- a/infra/buildbot/master/master.cfg +++ b/infra/buildbot/master/master.cfg @@ -79,10 +79,11 @@ for w in (w for w in workers.values () if ("latent" in w) and ("session" not in w)): w["session"] = 'qemu+ssh://buildbot@sagan.jakma.org/system' -osbuilders = list("build-" + kw for kw in workers) +osbuilders = ["build-" + kw for kw in workers] allbuilders = [] allbuilders += osbuilders +allbuilders += ["rpm-" + kw for kw in workers if workers[kw]["pkg"] == "rpm"] allbuilders += analyses_builders allbuilders += ["commit-builder"] allbuilders += ["build-distcheck"] @@ -177,6 +178,12 @@ c['schedulers'].append(schedulers.Triggerable( c['schedulers'].append(schedulers.Triggerable( name="trigger-distcheck", builderNames=["build-distcheck"])) +# RPM check and build +c['schedulers'].append(schedulers.Triggerable( + name="trigger-rpm", + builderNames=["rpm-" + kw + for kw in workers + if workers[kw]["pkg"] == "rpm"])) # Try and force schedulers c['schedulers'].append(schedulers.ForceScheduler( @@ -185,8 +192,9 @@ c['schedulers'].append(schedulers.ForceScheduler( c['schedulers'].append(schedulers.Try_Userpass( name="try", - builderNames=list("build-" + kw - for w in workers) + builderNames=["build-" + kw for kw in workers] + + ["rpm-" + kw for kw in workers + if workers[kw]["pkg"] == "rpm"] + ["build-distcheck", "clang-analyzer" ], userpass=users, @@ -207,62 +215,64 @@ steps.ShellCommand(command=["make", "clean"]), steps.Compile(), ] -### Each OS specific builder +### Default 'check' build, builder instantiated for each OS factory = util.BuildFactory() # check out the source factory.addStep(steps.Git(repourl=quaggagit, mode='incremental')) factory.addStep(steps.ShellCommand(command=["./update-autotools"], description="generating autoconf", - descriptionDone="autoconf generated")) + descriptionDone="autoconf")) factory.addStep(steps.Configure()) factory.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", - descriptionDone="cleaned")) + descriptionDone="clean")) factory.addStep(steps.Compile(command=["make", "-j", "2", "all"])) factory.addStep(steps.ShellCommand(command=["make", "check"], - description="testing", - descriptionDone="tests")) + description="checking", + descriptionDone="make check")) +# create builder for every OS, for every buildbot +# XXX: at moment this assumes 1:1 OS<->bot for kw in workers: c['builders'].append(util.BuilderConfig( name="build-" + kw, slavenames=workers[kw]["bot"], factory=factory)) -### distcheck +### distcheck Builder, executed on any available bot factory = util.BuildFactory() # check out the source factory.addStep(steps.Git(repourl=quaggagit, mode='incremental')) factory.addStep(steps.ShellCommand(command=["./update-autotools"], description="generating autoconf", - descriptionDone="autoconf generated")) + descriptionDone="autoconf")) factory.addStep(steps.Configure()) factory.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", - descriptionDone="cleaned")) + descriptionDone="make clean")) factory.addStep(steps.ShellCommand(command=["make", "distcheck"], - description="distcheck", - descriptionDone="distcheck passes")) + description="run make distcheck", + descriptionDone="make distcheck")) c['builders'].append( util.BuilderConfig(name="build-distcheck", slavenames=list(w["bot"] for w in workers.values()), factory=factory, )) -### LLVM clang-analyzer build +### LLVM clang-analyzer build, executed on any available non-VM bot f = util.BuildFactory() # check out the source f.addStep(steps.Git(repourl=quaggagit, mode='incremental', getDescription=True)) f.addStep(steps.ShellCommand(command=["./update-autotools"], - description="autotools", - descriptionDone="autoconf generated")) + description="run autotools", + descriptionDone="autoconf")) f.addStep(steps.Configure()) f.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", - descriptionDone="cleaned")) + descriptionDone="make clean")) f.addStep(steps.SetProperty(property="clang-id", value=util.Interpolate("%(prop:commit-description)s-%(prop:buildnumber)s"))) @@ -291,31 +301,77 @@ f.addStep(steps.RemoveDirectory( dir=util.Interpolate("%(prop:clang-output-dir)s") )) + c['builders'].append( util.BuilderConfig(name="clang-analyzer", slavenames=list(w["bot"] for w in workers.values() if not w["vm"]), factory=f)) -## Co-ordination builds used to sequence parallel builds via Triggerable + +### RPM: check and build +f = util.BuildFactory () + +# check out the source +f.addStep(steps.Git(repourl=quaggagit, mode='full')) +f.addStep(steps.ShellCommand(command=["./update-autotools"], + description="run autotools", + descriptionDone="autotools")) +f.addStep(steps.Configure()) +f.addStep(steps.ShellCommand(command=["make", "dist"], + description="run make dist", + descriptionDone="make dist")) +# not imported somehow +#f.addStep(steps.RpmLint(fileloc="redhat/quagga.spec")) +f.addStep(steps.ShellCommand(command=["rpmlint", "-i", "redhat/quagga.spec"], + description="run rpmlint", + descriptionDone="rpmlint")) +f.addStep(steps.RpmBuild(specfile="redhat/quagga.spec")) +# rpmdir=util.Interpolate("%(prop:builddir)s/rpm"))) + +# XXX: assuming 1:1 OS:buildbot mapping +for kw in (kw for kw in workers if workers[kw]["pkg"] == "rpm"): + c['builders'].append( + util.BuilderConfig(name="rpm-" + kw, + slavenames="buildbot-" + kw, + factory=f + ) + ) + +### Co-ordination builds used to sequence parallel builds via Triggerable + +# to understand this you have to read this list and the Triggered schedulers +# to see what sets of builds are being sequenced. Bit clunky, but Buildbot +# doesn't have a way to just specify a pipeline of groups of builders more +# cleanly. + f = util.BuildFactory() f.addStep(steps.Trigger ( schedulerNames = [ "trigger-build-first" ], - waitForFinish=True + waitForFinish=True, + updateSourceStamp=True )) f.addStep(steps.Trigger ( schedulerNames = [ "trigger-build-rest" ], - waitForFinish=True + waitForFinish=True, + updateSourceStamp=True )) f.addStep(steps.Trigger ( schedulerNames = [ "trigger-build-analyses", "trigger-distcheck" ], - waitForFinish=True + waitForFinish=True, + updateSourceStamp=True +)) +f.addStep(steps.Trigger ( + schedulerNames = [ "trigger-rpm" ], + waitForFinish=True, + updateSourceStamp=True )) c['builders'].append( util.BuilderConfig(name="commit-builder", - slavenames=["buildbot-fedora-24"], - factory=f -)) + slavenames=[w["bot"] for w in workers.values() if not w["vm"]], + factory=f) +) + ####### STATUS TARGETS From 0d91779a1fd7f90bf13ebfb792dc4e4fcfc57bba Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 5 Mar 2017 14:53:59 +0000 Subject: [PATCH 1302/1342] infra/buildbot: fix "for w workers", use common defs for common sets --- infra/buildbot/master/master.cfg | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/infra/buildbot/master/master.cfg b/infra/buildbot/master/master.cfg index 3bb271112..90316a98e 100644 --- a/infra/buildbot/master/master.cfg +++ b/infra/buildbot/master/master.cfg @@ -80,16 +80,20 @@ for w in (w for w in workers.values () if ("latent" in w) w["session"] = 'qemu+ssh://buildbot@sagan.jakma.org/system' osbuilders = ["build-" + kw for kw in workers] +osfastbuilders = ["build-" + kw for kw in workers if workers[kw]["vm"] == False] +osslowbuilders = ["build-" + kw for kw in workers if workers[kw]["vm"] == True] + +rpmbuilders = ["rpm-" + kw for kw in workers if workers[kw]["pkg"] == "rpm"] allbuilders = [] allbuilders += osbuilders -allbuilders += ["rpm-" + kw for kw in workers if workers[kw]["pkg"] == "rpm"] +allbuilders += rpmbuilders allbuilders += analyses_builders allbuilders += ["commit-builder"] allbuilders += ["build-distcheck"] # Force merging of requests. -c['mergeRequests'] = lambda *args, **kwargs: True +# c['mergeRequests'] = lambda *args, **kwargs: True ####### BUILDSLAVES c['slaves'] = [] @@ -159,16 +163,12 @@ c['schedulers'].append(schedulers.SingleBranchScheduler( # Initial build checks on faster, non-VM c['schedulers'].append(schedulers.Triggerable( name="trigger-build-first", - builderNames=list("build-" + kw - for kw in workers - if workers[kw]["vm"] == False))) + builderNames=osfastbuilders)) # Build using remaining builders, after firstbuilders. c['schedulers'].append(schedulers.Triggerable( name="trigger-build-rest", - builderNames=list("build-" + kw - for w in workers - if workers[kw]["vm"] == True))) + builderNames=osslowbuilders)) # Analyses tools, e.g. CLang Analyzer scan-build c['schedulers'].append(schedulers.Triggerable( @@ -181,9 +181,7 @@ c['schedulers'].append(schedulers.Triggerable( # RPM check and build c['schedulers'].append(schedulers.Triggerable( name="trigger-rpm", - builderNames=["rpm-" + kw - for kw in workers - if workers[kw]["pkg"] == "rpm"])) + builderNames=rpmbuilders)) # Try and force schedulers c['schedulers'].append(schedulers.ForceScheduler( @@ -192,10 +190,9 @@ c['schedulers'].append(schedulers.ForceScheduler( c['schedulers'].append(schedulers.Try_Userpass( name="try", - builderNames=["build-" + kw for kw in workers] - + ["rpm-" + kw for kw in workers - if workers[kw]["pkg"] == "rpm"] - + ["build-distcheck", + builderNames=osbuilders + + rpmbuilders + + ["build-distcheck", "clang-analyzer" ], userpass=users, port=8031)) From 55b11c2e01d0761064863247df9c4af943cd304e Mon Sep 17 00:00:00 2001 From: Jakub Zawadzki Date: Sat, 4 Mar 2017 19:43:46 +0100 Subject: [PATCH 1303/1342] vtysh: Bug 789 - vtysh ripngd does not have distribute-list command Make commands added by distribute_list_init() from ripd/ripngd daemon known to vtysh. Babeld leftovers not included, also other commands (show, write) from bug #789 not included. --- vtysh/vtysh.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5d59062df..9a8aedd12 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1367,6 +1367,158 @@ DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD, NO_STR "Interface specific description\n") +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + distribute_list_all_cmd, + "distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + no_distribute_list_all_cmd, + "no distribute-list WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + distribute_list_cmd, + "distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + no_distribute_list_cmd, + "no distribute-list WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + distribute_list_prefix_all_cmd, + "distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + no_distribute_list_prefix_all_cmd, + "no distribute-list prefix WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + distribute_list_prefix_cmd, + "distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, + no_distribute_list_prefix_cmd, + "no distribute-list prefix WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPNGD, + ipv6_distribute_list_all_cmd, + "ipv6 distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPNGD, + no_ipv6_distribute_list_all_cmd, + "no ipv6 distribute-list WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPNGD, + ipv6_distribute_list_cmd, + "ipv6 distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPNGD, + no_ipv6_distribute_list_cmd, + "no ipv6 distribute-list WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPNGD, + ipv6_distribute_list_prefix_all_cmd, + "ipv6 distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPNGD, + no_ipv6_distribute_list_prefix_all_cmd, + "no ipv6 distribute-list prefix WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPNGD, + ipv6_distribute_list_prefix_cmd, + "ipv6 distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPNGD, + no_ipv6_distribute_list_prefix_cmd, + "no ipv6 distribute-list prefix WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + DEFUNSH (VTYSH_INTERFACE, vtysh_exit_interface, vtysh_exit_interface_cmd, @@ -2607,6 +2759,31 @@ vtysh_init_vty (void) install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); install_element (ENABLE_NODE, &vtysh_write_file_cmd); install_element (ENABLE_NODE, &vtysh_write_cmd); + /* distribute-list commands. (based on lib/distribute.c distribute_list_init()) */ + install_element (RIP_NODE, &distribute_list_all_cmd); + install_element (RIP_NODE, &no_distribute_list_all_cmd); + install_element (RIP_NODE, &distribute_list_cmd); + install_element (RIP_NODE, &no_distribute_list_cmd); + install_element (RIP_NODE, &distribute_list_prefix_all_cmd); + install_element (RIP_NODE, &no_distribute_list_prefix_all_cmd); + install_element (RIP_NODE, &distribute_list_prefix_cmd); + install_element (RIP_NODE, &no_distribute_list_prefix_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_all_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_all_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_all_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_all_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_cmd); + install_element (RIPNG_NODE, &distribute_list_all_cmd); + install_element (RIPNG_NODE, &no_distribute_list_all_cmd); + install_element (RIPNG_NODE, &distribute_list_cmd); + install_element (RIPNG_NODE, &no_distribute_list_cmd); + install_element (RIPNG_NODE, &distribute_list_prefix_all_cmd); + install_element (RIPNG_NODE, &no_distribute_list_prefix_all_cmd); + install_element (RIPNG_NODE, &distribute_list_prefix_cmd); + install_element (RIPNG_NODE, &no_distribute_list_prefix_cmd); /* "write terminal" command. */ install_element (ENABLE_NODE, &vtysh_write_terminal_cmd); From d04f9ec9a6f3df61fc2f0cab2afd552567f83191 Mon Sep 17 00:00:00 2001 From: Jakub Zawadzki Date: Sat, 4 Mar 2017 20:41:02 +0100 Subject: [PATCH 1304/1342] doc: make netmasks in 4.3 Static Route Commands the same In 4.3 documentation shows example for defining static routes: -------------------------------------------------------------- ip route 10.0.0.0/8 10.0.0.2 (...) ip route 10.0.0.0 255.255.255.0 10.0.0.2 (...) These statements are equivalent to those in the previous example. -------------------------------------------------------------- 10.0.0.0/8 is not equivalent to 10.0.0.0/255.255.255.0, fix it. should fix #811 after html regenerating. --- doc/main.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/main.texi b/doc/main.texi index 0874c5c7e..849773b95 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -177,9 +177,9 @@ A.B.C.D format, user must define @var{netmask} value with A.B.C.D format. @var{gateway} is same option as above command @example -ip route 10.0.0.0 255.255.255.0 10.0.0.2 -ip route 10.0.0.0 255.255.255.0 ppp0 -ip route 10.0.0.0 255.255.255.0 null0 +ip route 10.0.0.0 255.0.0.0 10.0.0.2 +ip route 10.0.0.0 255.0.0.0 ppp0 +ip route 10.0.0.0 255.0.0.0 null0 @end example These statements are equivalent to those in the previous example. From f25b7317d77789221e3346b99c459c68e51c742d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 7 Mar 2017 10:36:14 +0000 Subject: [PATCH 1305/1342] configure: libtool < 2.4.6 doesn't work with fstack-protector-strong * configure.ac: GCC -fstack-protector-strong gives undefined symbol error when linking on __stack_chk_fail_local with libtool < 2.4.6. The gcc arg is not passed on when linking. OpenIndiana hipster has 2.4.2 at the moment. Test the libtool version and drop the arg and warn the user. --- configure.ac | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 7d9aa3f3c..402c89135 100755 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,18 @@ AC_PROG_EGREP PKG_PROG_PKG_CONFIG AC_PROG_CC_C99 +dnl libtool prereq. +AC_USE_SYSTEM_EXTENSIONS + +dnl ------- +dnl libtool +dnl ------- +LT_INIT + +dnl create libtool now, so we can test version below for +dnl fstack-protector-strong +LT_OUTPUT + dnl autoconf 2.59 appears not to support AC_PROG_SED dnl AC_PROG_SED AC_CHECK_PROG([SED],[sed],[sed],[/bin/false]) @@ -122,7 +134,6 @@ dnl Sun Studio 10 / SunPro 5.7 is also supported, dnl so lets set some sane CFLAGS for it. dnl --------------------------------------------- -AC_USE_SYSTEM_EXTENSIONS() AC_DEFUN([AC_C_FLAG], [{ AC_LANG_PUSH(C) ac_c_flag_save="$CFLAGS" @@ -159,7 +170,25 @@ if test "x${cflags_specified}" = "x" ; then AC_C_FLAG([-Os], [ AC_C_FLAG([-O2]) ]) - AC_C_FLAG([-fstack-protector-strong]) + dnl fstack-protector-strong gives __stack_chk_fail_local + dnl being an 'Undefined symbol' on OpenIndiana hipster, with gcc 6. + dnl gcc -shared is being used to do the link, however the error is + dnl from ld. Disable. An issue with libtool < 2.4.6 dropping the + dnl -fstack-protector-strong argument from the shared link. + AC_MSG_CHECKING([whether libtool can support fstack-protector]) + if test x"$(./libtool --version \ + | awk -F '[[ \t.]]' \ + 'NR == 1 { \ + if ($(NF-2) <= 2 && $(NF-1) <= 4 && $NF < 6) \ + print 0; \ + else print 1 \ + }')" = "x1" ; then + AC_MSG_RESULT([yes]) + AC_C_FLAG([-fstack-protector-strong]) + else + AC_MSG_RESULT([no]) + AC_MSG_WARN([upgrade to libtool >= 2.4.6!]) + fi AC_C_FLAG([-fpie]) AC_C_FLAG([-fno-omit-frame-pointer]) AC_C_FLAG([-Wall]) @@ -226,10 +255,6 @@ dnl System extensions dnl ----------------- AC_GNU_SOURCE -dnl ------- -dnl libtool -dnl ------- -LT_INIT dnl ---------------------- dnl Packages configuration From 32947f26f944e1a3ea28f935820dbc6c54181e2c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 7 Mar 2017 14:35:29 +0000 Subject: [PATCH 1306/1342] configure: use AC_C_FLAG for Sun Studio cc --- configure.ac | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 402c89135..b9dcddc41 100755 --- a/configure.ac +++ b/configure.ac @@ -155,12 +155,20 @@ AC_DEFUN([AC_C_FLAG], [{ AC_LANG_POP(C) }]) -AC_MSG_CHECKING([whether to set a default CFLAGS]) +AC_MSG_CHECKING([which default CFLAGS to set]) if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in "SUNPRO") - CFLAGS="-xO4 -v -g -xspace -xcode=pic32 -xstrconst -xc99" - AC_MSG_RESULT([SunPro default]) + AC_MSG_RESULT([Sun Studio]) + AC_C_FLAG([-g]) + AC_C_FLAG([-xO4]) + AC_C_FLAG([-xspace]) + AC_C_FLAG([-xstrconst]) + AC_C_FLAG([-xc99]) + AC_C_FLAG([-errfmt]) + AC_C_FLAG([-xipo]) + dnl AC_C_FLAG([-xlinkopt=2]) SPARC only dnl + dnl AC_C_FLAG([-xcode=pic32])dnl ;; *) AC_MSG_RESULT([autodetecting]) From e17ff9be4efb9d013ffa86a460a35ec03ca8d178 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 7 Mar 2017 14:38:48 +0000 Subject: [PATCH 1307/1342] HACKING: git diff ... | buildbot try example --- HACKING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HACKING.md b/HACKING.md index b63c1b022..078de600e 100644 --- a/HACKING.md +++ b/HACKING.md @@ -732,3 +732,10 @@ The buildbot client can be used to test changes before committing, with ~~~~~ $ buildbot try -c pb -b build-distcheck ~~~~~ + +- To test a series of locally committed change use git diff: + + ~~~~ + git diff .. | buildbot try -c pb --vc git \ + -b build-centos-7 --branch=volatile/next --diff=- -p 1 + ~~~~ \ No newline at end of file From 203ab894a8cfc2107179d2d52bac9d16ed7dd8da Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 7 Mar 2017 14:54:28 +0000 Subject: [PATCH 1308/1342] buildbot: add OpenIndiana hipster bot --- infra/buildbot/master/master.cfg | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infra/buildbot/master/master.cfg b/infra/buildbot/master/master.cfg index 90316a98e..0580c3789 100644 --- a/infra/buildbot/master/master.cfg +++ b/infra/buildbot/master/master.cfg @@ -61,6 +61,14 @@ workers = { "latent": True, "hd_image": "/var/lib/libvirt/images/freebsd110.qcow2", }, + "oi-hipster": { + "os": "OpenIndiana", + "version": "hipster", + "vm": True, + "pkg": "sysv", + "latent": True, + "hd_image": "/var/lib/libvirt/images/buildbot-oi-hipster.qcow2", + }, } # ensure "latent" is set to false, where not set. From e28ebbccc870110f0309d93b87c1574c399f2b3b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 7 Mar 2017 15:25:44 +0000 Subject: [PATCH 1309/1342] solaris/buildbot: Add SMF service manifest for buildbot-slave/worker --- infra/buildbot/worker/buildbot-slave.xml | 86 ++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 infra/buildbot/worker/buildbot-slave.xml diff --git a/infra/buildbot/worker/buildbot-slave.xml b/infra/buildbot/worker/buildbot-slave.xml new file mode 100644 index 000000000..d4177a7a0 --- /dev/null +++ b/infra/buildbot/worker/buildbot-slave.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 72e3b8b8d222e43bf74d4a9cd4cba63aa4d83fb5 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 10:27:54 +0000 Subject: [PATCH 1310/1342] buildbot: Add revlink to map quagga git repo to Savannah cgit URI --- infra/buildbot/master/master.cfg | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/infra/buildbot/master/master.cfg b/infra/buildbot/master/master.cfg index 0580c3789..899d6fa38 100644 --- a/infra/buildbot/master/master.cfg +++ b/infra/buildbot/master/master.cfg @@ -145,6 +145,12 @@ c['change_source'].append(changes.GitPoller( branches=['master','volatile/next'], pollinterval=300)) +####### REVISION LINKS +# associate changesouce repositories to URI templates for code view +# +c['revlink'] = util.RevlinkMatch([quaggagit + r"(.*)"], + r"http://git.savannah.gnu.org/cgit/quagga.git/commit/?id=%s") + ####### SCHEDULERS # Configure the Schedulers, which decide how to react to incoming changes. From ca7399f165f892620cbabdeb2b62cf792a6fc9d6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 17:15:00 +0000 Subject: [PATCH 1311/1342] doc: Add a nice CSS file for HTML texinfo --- doc/Makefile.am | 4 +- doc/texinfo.css | 227 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 doc/texinfo.css diff --git a/doc/Makefile.am b/doc/Makefile.am index 85af812da..30d5dd32e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -109,13 +109,15 @@ if ZEBRA man_MANS += zebra.8 endif +AM_MAKEINFOHTMLFLAGS = --css-include=$(srcdir)/texinfo.css + EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ ripngd.8 nhrpd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) \ - texinfo.tex + texinfo.tex texinfo.css draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ diff --git a/doc/texinfo.css b/doc/texinfo.css new file mode 100644 index 000000000..f5fa4f407 --- /dev/null +++ b/doc/texinfo.css @@ -0,0 +1,227 @@ +/* + CSS style for Texinfo documents + + Public domain 2016 sirgazil. All rights waived. + + Obtained from: + + https://sirgazil.bitbucket.io/en/artifact + https://sirgazil.bitbucket.io/en/doc/texinfo-css/tip/manual/static/css/document.css +*/ + + + +/* NATIVE ELEMENTS */ +a:link, +a:visited { + color: #1E90FF; + text-decoration: none; +} + +a:active, +a:focus, +a:hover { + text-decoration: underline; +} + +abbr, +acronym { + cursor: help; +} + +blockquote { + color: #555753; + font-style: oblique; + margin: 30px 0px; + padding-left: 3em; +} + +body { + background-color: white; + box-shadow: 0 0 2px gray; + box-sizing: border-box; + color: #333; + font-family: sans-serif; + font-size: 16px; + margin: 50px auto; + max-width: 960px; + padding: 50px; +} + +code, +samp, +tt, +var { + color: purple; + font-size: 0.8em; +} + +div.example, +div.lisp { + margin: 0px; +} + +dl { + margin: 3em 0em; +} + +dl dl { + margin: 0em; +} + +dt { + background-color: #F5F5F5; + padding: 0.5em; +} + +h1, +h2, +h2.contents-heading, +h3, +h4 { + padding: 20px 0px 0px 0px; + font-weight: normal; +} + +h1 { + font-size: 2.4em; +} + +h2 { + font-size: 2.2em; + font-weight: bold; +} + +h3 { + font-size: 1.8em; +} + +h4 { + font-size: 1.4em; +} + +hr { + background-color: silver; + border-style: none; + height: 1px; + margin: 0px; +} + +html { + background-color: #F5F5F5; +} + +img { + max-width: 100%; +} + +li { + padding: 5px; +} + +pre.display, +pre.example, +pre.format, +pre.lisp, +pre.verbatim{ + overflow: auto; +} + +pre.example, +pre.lisp, +pre.verbatim { + background-color: #2D3743; + border-color: #000; + border-style: solid; + border-width: thin; + color: #E1E1E1; + font-size: smaller; + padding: 1em; +} + +table { + border-collapse: collapse; + margin: 40px 0px; +} + +table.index-cp *, +table.index-fn *, +table.index-ky *, +table.index-pg *, +table.index-tp *, +table.index-vr * { + background-color: inherit; + border-style: none; +} + +td, +th { + border-color: silver; + border-style: solid; + border-width: thin; + padding: 10px; +} + +th { + background-color: #F5F5F5; +} +/* END NATIVE ELEMENTS */ + + + +/* CLASSES */ +.contents { + margin-bottom: 4em; +} + +.float { + margin: 3em 0em; +} + +.float-caption { + font-size: smaller; + text-align: center; +} + +.float > img { + display: block; + margin: auto; +} + +.footnote { + font-size: smaller; + margin: 5em 0em; +} + +.footnote h3 { + display: inline; + font-size: small; +} + +.header { + background-color: #F2F2F2; + font-size: small; + padding: 0.2em 1em; +} + +.key { + color: purple; + font-size: 0.8em; +} + +.menu * { + border-style: none; +} + +.menu td { + padding: 0.5em 0em; +} + +.menu td:last-child { + width: 60%; +} + +.menu th { + background-color: inherit; +} +/* END CLASSES */ From 69f8d5df72b6bd9c39c3a262ae0ed07f2cd566e9 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 17:15:58 +0000 Subject: [PATCH 1312/1342] configure: Add commonly used GCC security flags --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index b9dcddc41..0bfdde6fb 100755 --- a/configure.ac +++ b/configure.ac @@ -193,10 +193,14 @@ if test "x${cflags_specified}" = "x" ; then }')" = "x1" ; then AC_MSG_RESULT([yes]) AC_C_FLAG([-fstack-protector-strong]) + AC_C_FLAG([--param=ssp-buffer-size=4]) else AC_MSG_RESULT([no]) AC_MSG_WARN([upgrade to libtool >= 2.4.6!]) fi + AC_C_FLAG([-D_FORTIFY_SOURCE=2]) + AC_C_FLAG([-Wformat]) + AC_C_FLAG([-Wformat-security]) AC_C_FLAG([-fpie]) AC_C_FLAG([-fno-omit-frame-pointer]) AC_C_FLAG([-Wall]) From 69c62987e47a8c6c852b3bf90bc5e48f8b70ee5f Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 21:54:09 +0000 Subject: [PATCH 1313/1342] doc: pdftex works with PNGs now, remove dependency on PDF figures * Makefile.am: pdftex seems to work fine with PNGs now. So the need to build PDF versions of the figures using ImageMagick convert is gone. Remove the dependency. Can leave the rule for now, no benefit removing it. --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 30d5dd32e..4caa4621c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -40,7 +40,7 @@ info_TEXINFOS = quagga.texi # us to have a generic automatic .pdf rule to build the figure sources # because it cant just work from the png's directly it seems - contrary # to the documentation... -quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) +quagga.pdf: $(info_TEXINFOS) $(quagga_TEXINFOS) $(TEXI2PDF) -o "$@" $< || true quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi \ From dcfb4809158ade2b5070229297b95c944660cdf2 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 21:58:30 +0000 Subject: [PATCH 1314/1342] doc: Tweak internal layout of fig-rs-processing slightly --- doc/fig-rs-processing.dia | 1863 ++++++++++++++++++++----------------- doc/fig-rs-processing.png | Bin 80048 -> 59640 bytes 2 files changed, 1025 insertions(+), 838 deletions(-) diff --git a/doc/fig-rs-processing.dia b/doc/fig-rs-processing.dia index b2bf213da..de7d79f69 100644 --- a/doc/fig-rs-processing.dia +++ b/doc/fig-rs-processing.dia @@ -62,7 +62,7 @@ - + @@ -115,12 +115,12 @@ - + - + @@ -146,6 +146,9 @@ Selection# + + + @@ -153,7 +156,7 @@ Selection# - + @@ -202,12 +205,12 @@ Selection# - + - + @@ -232,6 +235,9 @@ Loc-RIB# + + + @@ -241,7 +247,7 @@ Loc-RIB# - + @@ -274,7 +280,7 @@ Loc-RIB# - + @@ -300,7 +306,7 @@ Loc-RIB# - + @@ -308,7 +314,7 @@ Loc-RIB# - + @@ -342,7 +348,7 @@ Loc-RIB# - + @@ -376,7 +382,7 @@ Loc-RIB# - + @@ -409,7 +415,7 @@ Loc-RIB# - + @@ -442,7 +448,7 @@ Loc-RIB# - + @@ -476,7 +482,7 @@ Loc-RIB# - + @@ -510,7 +516,7 @@ Loc-RIB# - + @@ -538,12 +544,12 @@ Loc-RIB# - + - + - + @@ -557,7 +563,7 @@ Loc-RIB# - + @@ -567,13 +573,16 @@ Loc-RIB# + + + - + - + - + @@ -587,7 +596,7 @@ Loc-RIB# - + @@ -597,6 +606,9 @@ Loc-RIB# + + + @@ -625,12 +637,12 @@ Loc-RIB# - + - + @@ -654,6 +666,9 @@ Loc-RIB# + + + @@ -683,12 +698,12 @@ Loc-RIB# - + - + @@ -712,6 +727,9 @@ Loc-RIB# + + + @@ -741,12 +759,12 @@ Loc-RIB# - + - + @@ -770,6 +788,9 @@ Loc-RIB# + + + @@ -799,12 +820,12 @@ Loc-RIB# - + - + @@ -828,272 +849,17 @@ Loc-RIB# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #X# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #“Out†Filter -for Peer X# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #“In†Filter -for Peer X# - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #X# - - - - - - - - - - - - - - - - - - - - - + - + - + @@ -1107,7 +873,7 @@ for Peer X# - + @@ -1117,13 +883,16 @@ for Peer X# + + + - + - + - + @@ -1137,7 +906,7 @@ for Peer X# - + @@ -1147,9 +916,12 @@ for Peer X# + + + - + @@ -1173,7 +945,7 @@ for Peer X# - + @@ -1199,12 +971,12 @@ for Peer X# - + - + @@ -1230,9 +1002,12 @@ Selection# + + + - + @@ -1258,12 +1033,12 @@ Selection# - + - + @@ -1288,13 +1063,16 @@ For C# + + + - + - + @@ -1316,12 +1094,12 @@ For C# - + - + @@ -1345,7 +1123,7 @@ For C# - + @@ -1371,12 +1149,12 @@ For C# - + - + @@ -1402,9 +1180,12 @@ Selection# + + + - + @@ -1430,12 +1211,12 @@ Selection# - + - + @@ -1460,13 +1241,16 @@ For D# + + + - + - + @@ -1488,12 +1272,12 @@ For D# - + - + @@ -1517,7 +1301,7 @@ For D# - + @@ -1543,12 +1327,12 @@ For D# - + - + @@ -1574,9 +1358,12 @@ Selection# + + + - + @@ -1602,12 +1389,12 @@ Selection# - + - + @@ -1632,13 +1419,16 @@ For B# + + + - + - + @@ -1661,12 +1451,12 @@ For B# - + - + @@ -1677,6 +1467,9 @@ For B# + + + @@ -1694,11 +1487,11 @@ For B# - + - + @@ -1724,12 +1517,12 @@ For B# - + - + @@ -1753,14 +1546,17 @@ For B# + + + - + - + @@ -1785,12 +1581,12 @@ For B# - - + + - + @@ -1816,12 +1612,12 @@ For B# - + - + @@ -1845,14 +1641,17 @@ For B# + + + - + - + @@ -1877,12 +1676,12 @@ For B# - - + + - + @@ -1908,12 +1707,12 @@ For B# - + - + @@ -1937,10 +1736,13 @@ For B# + + + - + @@ -1966,12 +1768,12 @@ For B# - + - + @@ -1995,10 +1797,13 @@ For B# + + + - + @@ -2024,12 +1829,12 @@ For B# - + - + @@ -2053,10 +1858,13 @@ For B# + + + - + @@ -2082,12 +1890,12 @@ For B# - + - + @@ -2111,10 +1919,13 @@ For B# + + + - + @@ -2140,12 +1951,12 @@ For B# - + - + @@ -2169,10 +1980,13 @@ For B# + + + - + @@ -2198,12 +2012,12 @@ For B# - + - + @@ -2227,10 +2041,13 @@ For B# + + + - + @@ -2256,12 +2073,12 @@ For B# - + - + @@ -2285,10 +2102,13 @@ For B# + + + - + @@ -2314,12 +2134,12 @@ For B# - + - + @@ -2343,10 +2163,13 @@ For B# + + + - + @@ -2372,12 +2195,12 @@ For B# - + - + @@ -2401,10 +2224,13 @@ For B# + + + - + @@ -2430,12 +2256,12 @@ For B# - + - + @@ -2459,10 +2285,13 @@ For B# + + + - + @@ -2488,12 +2317,12 @@ For B# - + - + @@ -2517,10 +2346,13 @@ For B# + + + - + @@ -2546,12 +2378,12 @@ For B# - + - + @@ -2575,10 +2407,13 @@ For B# + + + - + @@ -2604,12 +2439,12 @@ For B# - + - + @@ -2633,14 +2468,17 @@ For B# + + + - + - + @@ -2651,6 +2489,9 @@ For B# + + + @@ -2668,15 +2509,15 @@ For B# - + - + - + @@ -2687,6 +2528,9 @@ For B# + + + @@ -2704,15 +2548,15 @@ For B# - + - + - + @@ -2725,6 +2569,9 @@ For B# + + + @@ -2741,15 +2588,15 @@ For B# - + - + - + @@ -2762,6 +2609,9 @@ For B# + + + @@ -2778,15 +2628,15 @@ For B# - + - + - + @@ -2797,6 +2647,9 @@ For B# + + + @@ -2814,15 +2667,15 @@ For B# - + - + - + @@ -2833,6 +2686,9 @@ For B# + + + @@ -2850,15 +2706,15 @@ For B# - + - + - + @@ -2869,6 +2725,9 @@ For B# + + + @@ -2886,15 +2745,15 @@ For B# - + - + - + @@ -2905,6 +2764,9 @@ For B# + + + @@ -2922,15 +2784,15 @@ For B# - + - + - + @@ -2955,16 +2817,16 @@ For B# - - + + - + - + @@ -2989,16 +2851,16 @@ For B# - - + + - + - + @@ -3023,16 +2885,16 @@ For B# - - + + - + - + @@ -3057,16 +2919,16 @@ For B# - - + + - + - + @@ -3091,16 +2953,16 @@ For B# - - + + - + - + @@ -3125,16 +2987,16 @@ For B# - - + + - + - + @@ -3159,16 +3021,16 @@ For B# - - + + - + - + @@ -3193,16 +3055,16 @@ For B# - - + + - + - + @@ -3227,16 +3089,16 @@ For B# - - + + - + - + @@ -3261,16 +3123,16 @@ For B# - - + + - + - + @@ -3295,16 +3157,16 @@ For B# - - + + - + - + @@ -3329,16 +3191,16 @@ For B# - - + + - + - + @@ -3363,16 +3225,16 @@ For B# - - + + - + - + @@ -3397,16 +3259,16 @@ For B# - - + + - + - + @@ -3431,16 +3293,16 @@ For B# - - + + - + - + @@ -3465,54 +3327,61 @@ For B# - - + + - + - + - + - - + + + - - + + - - + + - - + + - - + + + + + + + + - + - + - + - ## + #To RS-Client B# - + - + @@ -3522,226 +3391,496 @@ For B# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #B# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #C# + + + + + + + + + + + + + + + + + + + + + + + + - + - + - #Export Policy -of RS-Client X# + #To RS-Client C# - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #X# - - - - - - - - - - - - - - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #A# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #To Peer A# + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - + + + - - + + - - + + - - + + - - - - + + - - + + - - - - ## - - - - - - - - - - - - - - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D# + + + + + + + + + + + + + + + + + + + + + + + + - + - + - #Import Policy -of RS-Client X# + #To RS-Client D# - + - + - + + + + - + + + - + - + - + - + - + - + - - - - + - + - + - #X# + ## - + - + @@ -3751,79 +3890,54 @@ of RS-Client X# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + - #To RS-Client B# + #“In†Filter +for Peer X# - + - + - + + + + - + - + - + - + @@ -3832,7 +3946,7 @@ of RS-Client X# - + @@ -3841,17 +3955,17 @@ of RS-Client X# - + - + - + - #B# + #X# @@ -3860,7 +3974,7 @@ of RS-Client X# - + @@ -3870,56 +3984,52 @@ of RS-Client X# + + + - + - + - - - - - - - - + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - + - + @@ -3931,17 +4041,17 @@ of RS-Client X# - + - + - + - #C# + #X# @@ -3950,7 +4060,7 @@ of RS-Client X# - + @@ -3960,28 +4070,90 @@ of RS-Client X# + + + - + + + + + + + + + + + #“Out†Filter +for Peer X# + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - + - #To RS-Client C# + ## - + - + @@ -3991,28 +4163,63 @@ of RS-Client X# + + + + + + + + + + + + + + + #Export Policy +of RS-Client X# + + + + + + + + + + + + + + + + + + + + + - - - + - + - + - + - + - + @@ -4021,17 +4228,17 @@ of RS-Client X# - + - + - + - #A# + #X# @@ -4040,131 +4247,135 @@ of RS-Client X# - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #To Peer A# - - - - - - - - - - - - - - - - - + + + + + - + - + - + - - - + + - - + + - - + + - - + + - - + + - - + + + + - - + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Import Policy +of RS-Client X# + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + @@ -4173,17 +4384,17 @@ of RS-Client X# - + - + - + - #D# + #X# @@ -4192,48 +4403,24 @@ of RS-Client X# - + - + + + + + + + - - - - - - - - - - - #To RS-Client D# - - - - - - - - - - - - - - - - - - - diff --git a/doc/fig-rs-processing.png b/doc/fig-rs-processing.png index 1f77263b1293eee01e616f5672e363ea616dd9da..c0cac5c9aefae6e2a10f233d097e74d0ea3801cb 100644 GIT binary patch literal 59640 zcmc$`1z1&GyEeM8Kn0`(X;~m3DJ>u&At0U7AT6nMgCZp*Al)5GNl7b6cOxkx-7Wn; z%kSI&xA(sOz0W!SIsbL$b$Ri=YtA+1m}8FdjQf7>`&oesauQfKNNyky2rMZ{F(m}z zvJw3Az_I0lF*w#WEoZ9}~X3Ced&# z5tr@G5`Kk-YeXE4X0mWJXF7<{_3(1(u1kaa)aX_M$714)eTe+xX%8=xugGHrp>MMR zak}QI4)kd$*jMkp{(a03xcp6esNUauD_)G5FICbpGlL`hB`WH^-rVL@ROg@LG9e-f zu;4<4Cr?g?;iJ3AiadVA7DkKAyL>ESs}WKJ;%nkEFO!L}aS0!<{nC3+t^Pbxk+cW& z^kx$kR_t+IX5`LC^D!DsBN6wcgGZ1{;r(y!BM{z4rEFqZ3EWmYJ3C6}cL)fK0@Ns8 ztd0~23JN+nIMg_8%1KJnGcsz`I2PcJTUlH8baqmw>(n@A<>X9^-T5uOaqmGbIs&1u zd99tTzrWw-8rFbp)X@no7MdzrE`Go4*s2?+`P-oD*BI?a-f!RrsF zmS_nkZd%+GNA{P!7-Z3{9ZNfv7dj)Lpy*lLZ8mu2=_!b71yB6d8x5YGkFUD6R=acL zhvmUif5tsLDF+8G+$4S{>*KxU(9lqKK_MolPhY;Mmlyjv)zk*{*xK18B_;}??~BL!`V>yk1H~G(KNS?n%E)M!7&H%md=?oQ8Ac&MLP~03W7FWY zISu#LsdwjPVp==iU+s7bClr?baW&pCVHG4RMpf-h>M?XHQkb7>)v#%59-01s`oe< zD=~ca>Xo&%HHT@>>8~KxjhTj-BvxGL?N`h@MkIU>AF3bm(a`+fTOJgniF#UET1rh# z9k<#mbWxjUG1!OeEHJ3FCs)%Ozg^TbyikZW+n|6mul6YrqNNSwXqU9`D7Kf#(CR} z^z_(K7=n$Bjqvbr86}$ZG*N#%MHiPUzv73sza9w`BjvJGK#byk)>9{;L)8;l# zvoCv2{)`z^VZxFL#pL=t=JGlyDClOwnf^#kMTHtmjGL=#KH=8hUhT`-H#-t=7`q^U z*;e)R^yCZSDN0KR`B|@xmv@eiKBFhNcIC>0xbn}RKNl2O?Jjg{Rahz#Mz$Mu74jW! z&WvtZFV-x5%FO)zt2wAMn)zcvfpOuZ-7XFd4UK1o+AeD)t(^9^F@KBM?G_w3BJ-o$ zv3YppZ)3q5LiM^|?sF>zjlAhk!+$i0EK z9BojSS5$2LD5Zm$_@@aK2Eqi7F-%+8Vq=~8ZRjIOuvY4|J#+H{#rNtHNd0qjtEw6U zNJ}px5bEfW>qKV<6E>~iQ3nkzEjKrJp=SBhyEvKI*(B9d!NI{>e-Ak8d3LP&>{$x0 zonOGf;2`Bup~=PhVZ+CdA350B`5q1ZS@~E*OG5+wGC2LSeXZ(VknxgYOD|1?nlCc3 z_2%q0^3Q4G!a^OMRD`5a>H>`8r-=3*zht=n@#DwJ%7c?tc0?@N56${gAxs?|9T8Vg zef|11A|e9q@-^s9OG^uj#^>K1QH&i?obfZmOgudBntS58J~r+1+AVAyxtsWr@NrDi z&(Yys#}ydOxrN)kKIk9dcu^9L4|g*Q^j%hbAn34Myh~4QH>t-X_mX#JoW$kCk&^qw zpuy9f@S|#)Gfc}TEEknIrWj#|ZDBQ0QMkD0j_~bROC#J=4uMei4Rf=*>BN`NQks!S ze!|r_L64=dd#rFp>b+p5ct6}|Cv`rP4<&BYK?OIOi+6TTY>%FKoLswj<;lY_V%BS- zx3yjJtl1~(MJVCA zPd@ExqL=SrmzHJevZUB9hOX>0#03X9a&bOb)hRRjT}Oq6Ky=+`M5-rft*`6x@Zk3g z#I5N*BV|07U^s&%;9XE4H;iPzgb?0*TWm%$ZiGF2U17D8J}hziY%bbCu-m0l3`s}Q zIX5rlo=jutsX9y)5|ScGW5dh4tjR(3_lrKJgx{`k(uo&o5LG9&5Qw?Kw2dz?Nq4EJ z6Tn@Mk}Tux6xZR|VuCfYM{!5v3dg`MZjFtmW?^OJO?4)RR$+;qqaHH3EE%=2A%cQt z#r}@n>--JAicesh#(MA>qh-W+Yo*;Ronaw3I`80Mg}b%HxForxGDnE;o0*j8;e!qg z1Y!j1gejiY!o#FQv~0lLVoLB^mOtlOX)YCs=AaNQ4Ar&lv~NaCoSM%KNDv6u+i%4m zFnkPD4hV)tC4HCajiQFeTM;8zVjumlvLFO}=i%MyH{%eZ?OhIs!2SuZ5$P?6dS36S z$Ld%5gv6kC#UvO(2){RNaCW-xOmWlH$5ba&i8=i$fS>+_eyVa3~_m`CZ5!fp~xp zW7etPb&=0zqIJg@y2#-lF23s<-aLIR1J%4AjFCRe-%&8Zc#iwE_AaWM8qm!L5`XVc z3-|9LLft%;3?8Fukc>EFk{CwU3QjQjRJR3C!P7jTe=ClV{`)jfPEex>-@-?s0<5R6<-K;3bgis_R2?X@{91mf5i8t_FmAgl)sd?G|O zu!p*N6siI5WQb-P(_49~I~^6$><;?-<1Nzpu(=QGj__w6AZ( z#>f~n+z$Io@FeN5_1KRefz7`vr(LBPqVl8f)6?G(@~rju_ZPmqG}CbLNuxBBoIks2 ze6!&~kc9;>QzvW$!@~|czuO^tbZNbK@xlWj$Z56zyLazK3UxlFd9NhdJ|v^0gc!D< zUE?UrTA;-^&tsCdpKvP}^)R$;}bPq4dWe)B&p<{RGF7IHUy2@aOx&S6crWK)J8~cYSXIj*yXUttwD%e9WA=psM+jE z5n?5{u|I&$m=Qmle|m=1|5i&Q?lW^RJKhr*Q||!2x6MmSOOJi7y`X1~dRnDj__{_6 z7Z+ECXQ3;O!}fREEx|v+#Dp9i9R66OYU=83voB*AVZXDmvQm9E>@?#M^WnqZ-k|*E zkJ8qbg>T*UI~|ORJxLZ87OM&m0i6m8>RudXB=5)t=Gx5Ev(|1kE)V9=$t9X~394VA zy-z|<&A_(L5ndAWTO73(yd_+|UxFqHHNma_6_KWJhn!qTSGUl3QJrZdS22SIPfAu6 z%Py;;Vx+fMK8}Fc(a~|mTvA?s(Y6ZEMMq}a9YOa$ZQ<1X1RIaAJT@k)ppX1~d^<;{ z#l^+He*MCB($v;|u(2HQPi?Obq=TT9^|T7YE>HY#UqnU&GaoOXcO|MGfc2 zyS*nz zN4E(G9vC`2fBxK{#2N4nJcJBdpx9@Z-G!wkGvo~{to^;c$#RQP0Psidg1B6qoPaOX z)YM#^opV?5@zY31NPrN9lJQ0)B^8|Vw6%ngGBPqME1?c|cXwKu*e!tEp_D@Povtfz ztgc?ZbgBAq7_h*9fq{Do-apNPIg#-s1ep%YkDT9eZMx140s=$^WOzWg$%znyU2do~ zfI|Z4z13?xPnSECwAm28hDD#V@$dj!ig8*0`Ex7v?SBTwydMEILxW?Hbn*<0v$j-6+=a&nT(Vx;zHA%Q*aQ(D?% zje-7t#hA^sjFFL%xz;dN%`(Zj=`qWLp*&?fTiXxDS1zGN5)fa$h6&NePp;sf7&lE} zvf9C7Fk3c~R`&RKwFrorysLGT>$*b9bz)|Ah7?IZT^3&6A456_??MMMjkVgZ&CSie z-JTD$bhNY>V>*F;sNMwjr~74Vu?Xvb!s-0duU*Hn(b0rh9tKDiRaI3JlZ9;Agf~7u z5E?#e-hF^N-UsA={Ag%k5Y4JbK}qSgzcLKe&6wC%gbFVZ_!ST>E)O*G$p){6f8lT4 z5A8GgZ6&3NDA4_qmpU^jK#m3%YWi5hvvbeC|n9+prOPy&$A=fAO&=5?a z)(N&8kBigOMfMHE#eIPhP@H52E5JjOa9gTBecAz$?&_t-ixDg=ECBTR?H0P`J7Xxl zPG1dQr4MdvYishqH99o3bUc^xtLx^*Z#NG!6GrZuW;7KJ20-7<$*PRR)Ad@beIR-=VnEk` z1#4g3wKg};S78VV3w!1m`)Xs7cQ}h7Y1_FrARqvrPVUN;E10ga+yW4_szce;R8^GfSMu3?-c>U7f- z4{k^|oE`7Ob7-^hu(R9#{Q4R$LqkKu3;Ye?BgK8EJ(!r|8s?q8`BqU;Q65;}5b;t| zQ(32|00evnue3LjS5$0yc{yzD0P+P{O3U!( zfvLJYnuexpm>hq7540F9yif2B_CHfo)5?m9`h#(cuuo*1H|rc$$D8$5lG10}`HrEXq3UWr9-d0N6nCXgjb&mElkcsqMY?s>KqxvprKg?< z!8mr^baFa`Fh{VntsW$NKVpcMA(o!?|zu9!c+s+&=k- z<3{$wRLQI)Q+^((;)So(Z8MU?E`hJOjaTj_@A!4VL&Dm`=v7U^1ZR{-Ku>u^PyVM* z;q7>2WYZ(R(9{;lh)&o0{QO?bV_!6^D-5_Dh&P&>{kdF9LgKZI=)&<+|C$>c`$uKL zjFyX}`z3#kFE+NA%BQ)~%q__&&*<%uoMYa1deXS05OXDaCL zBwn}$C%VkSw@vdt1YFA(k|J}JvoqqfHANtVS#b!zja9qr_rDBRl(Vm?^U(4*yWrv+ zD^U;hB9p!1mqEqu$USl5;p2D>0JP-da38`iV|9lJOE*71J)dEiG40Vb16|HtmdeE_ zA8yW1u^ajohbJl1uFYEl0HQX&nwt&wnGjgnGzf)NhcXhG)4zy{Z5vx3?rU0Gn|w&N z@H9l`z|E~jj3w;nZmEur&c&BPG&RxH818Ufmy(z!b2CJ#Z@BmaWr4&fT_j$fb<$v_ zLamPSt``Gl<-5q=hy6H-#v@(MyuF4^^!+*jQ= zWHk~e4$QH^*ANfnF@pNEUIw^ZSy^NbFcuVKx~Z#VVTMYE#4lH0sutBXTDVt$SAj%F z+>4 zk)v(%S?lW|w!A@RRi&k4BNcSyqAxiwF@^?WE?kpuk$qsM%h~kXstmsC`nDLwsm2D} z(yNEYU6;c~9hsu({5j%!z1qJ$R|z}R5PQi32WERl*2v_rXb-h&m6obiMNu`sOL4SRgO-97=td z>QhPW-l4p$_1ei7d2eUQog0zUnCiTubmCd>f5f~edMpiNLU`?4$wWM(wNyu;OR(F6 zgwxgN@^=RZsZJGR<2O5Z1Z&@yxc{y}U2#^wdKSKXf#-bGk;yDOZ!EH%daUQgw$90k z-FjJ6VL=?x4FrtOmXVRefv60gJ%ry^Pc@0J@O|ev4c5lE7 zMy5A+ciw%NKZi>(FLYv)sZgdeQ&&N~x^mEcd6BMMMHMH=fn~iRs(DPiaL=>cPXFSY zl+Bc&{m-Xz*>yHvGp5N-#A(CRPoC&oyKLuNcy!x|SkAPmD?5E3zw;cMM3@dHAKC|( z{#a&`0%p;#8#DRPP*Mg5?hoE7cx|WkjHW+NX_7yp;|i3RXB7At`tKBGG-^xuwoi;R z$Wzq6FF~&PoK+Vlb0_}(ZG;@KF)|_yzA%3LZt+ihS5!-av1xSA;!BrV{)U0A$0;vL z*F8@6#_%CHSSmXqgc)08Y@(A1RByBL7My0xOC)!Yb)WV>quf(h<+(3O6?xxiz590M zMl!?a!vkt$;m4ZQNJEwjMo~>2ak2FfEY+DLg*KyZC+lgUL!a7$C@UaQcVSOs;%@C} z&pMK;3fvUAich>R`E%VZXDfB572ePFGRfE08Lj5Zm|wd}hDf_jdr-6HXQMzWhSoNuI;KU(OWNm+E-SF*`5B z^XJ>|$k1+GRjlDU}7!bB)V&3QKRMFb-29P zd9a~BU8h>SdCctYJ(p-{{2#M!Od3l9j0N2($O@C_Z z{xA#z>9fuuJjpO=LdHKqce!FT2 zDoY{3lw`6|M3fhlhhUXSubMk$2)u*szVfmcaMwnGe{!sKjlv$f3?_SR#xf zBqW4f$nzAa9Vsd4vrp={goFpXy+S8PFZOe-U%beJ^FBUJKT1uT8XNtv$>SpNgf{j?O(h8_}|X z921IGhavoYeIfS+qJgog>BkdEW#vdQWL{Cx#hRo z@?t=UZrr#5#A~9#O9=OcXG}n*(hJCy7#U?&KM^`!qOQ^ww3&W{blq+y0u8MW{$0IE zxOYmb0Q;@C#NbH)b#~@{;i5}F*F*O|7uko~l&P+YBLgC~;*?%&CF)jK`?tl>d9^)z zUB}&sk?d+w8`MbtdI<|VW7QX)HrPS=uIH+iWo3|m0EW&$6!ho#7!q^`zuO~81hdGn zjY`x(O9O$WprD{Nj8d=63^(#>AaHW|Bt9-WI{yI9hR))WlE8p~zP_cNBz|;kvO6Rs zPsJcT20RR=n-~Zq$^*0y1ycl^M;oQ%JKvhVU8=LG)4sKf3^JVC`xAgoFwxKq6{jd}Q+_&tFqEe9jj<67ckOs~vZvgTMvRNV*1-A6+=r+4EE zMCI#O#>X|Qv^SQQ^IZD}2X`B<%9gMHJ3Z;)!-qJE#>U24S`!Q136+*V(wQJU$LctM zELb$F6!3LJfy*!4<=-rKY9TsqL~5X9_Y@p?1~Im|@tmWA6&2PlXTjZidzn z>beTL6|aP?n774jx70PTmkx5wJR{4;}pYCJ*yP1V3xF+~c!DM*N%-$Ez z!8yJdMHW)ZxbsDNjENEJ$!U=!zCQltd+gIS=f2w0D?cfa_T=|>FhADq?$@oRxM8`9 z%X^ePa+O&GG1ij1=HC%%KlzY5Y;QEM3TW^GACk!d=W6u5$saR%TF4C|ZJ^m-)v7?b zt{&)GSy|b}@DJifBw|Uz-_THHH+@GuCa*u$C7d_;Z2;`ksWw8W4gMza$HIRH(By2^ zCjZR~Ae^)uG3_)q;^y0juhT-5Me(F1f8b2)_re9|ZbP|KeIditXhKu^wQA4dM-;3u z+N`WLkXY!F*$W}%0f|x1^T;@9e16**GMtcvRB!O~Sk$rMY&emGDFq1@U~^o}1EpkSEG;dy%gv*N?<#DJ7S#Q3YiQL671Cp-xCl(+Z(OpZ z8bT=o>PP+oJM(Us`vlZM>SUoIU+ZUr7bOeLm`>IK0Yu#Mx>#t=%OMgxJZZg9Y8ww+ z(%gt{*%_D-YCq~-W!0W6es^SM(OqY^nMv4yqxE?&t6Hy@G}8?smg#2jk>M;jAn`=j z#LijlyTL^Dv22!5bgkJYjEFsh&DFBWOLjp1uU@?>D=Q20LFdcM+0@5Aa!Gty^Yy&> zmo8tHe)<%W4)5dRL65I7YL8%iRwyPe{$jV#1T;{Qw3j2FG{_5k<2d|#7dbeFTwlY^ z@t{sff{X)mtYgaN#_dd;KY#Fo_$Z~2o@^!Oqk4QYqBDZW&F`B#*Uye;9u||LM|wYY z>8=*eT+d9?p4Rl3V?^5Cbk=m~AHIlt_mOh+1Le-mV?7v^yLDwqoltg1XGu0b)S;O$ zuImPSwXU1&R1LT%#!F4*d8R!!>kg;gHU%6gPa&aMQ_F%E7#|-$m=#fj| zhn80IjZ0XyCOUl%*vIGHhU*0mwSt}^qe4W*6Z}|&53!@md4@j_E!Bjn<&x^T6`}Uf z2N))CK`Wx~;>&9Z%~GR?DP|SVOD|excOIUi8#0fRNj3hg{=&xk@R8uGK3?7N-iYYx zgIKTQ8@`QVQ)~p?gGmDF;}P;=pSjzc(-&2XD$6IS)AI*BtkHVSHKGpJf=2erEjSv2 zgL4^y8ujH^{X!4YOs2CkMB<`u7`uUkTT-RXFJU?#79UE}KiKg&$*goxw%2g)h|6ZH z?j%r8X6?B^$2i3&w#vC3fjW^2WpjGE9S$YE(-|Tj`f&BCkGL|-^Zwe!*p}BP9^2MEksR`>i52srdF#Bhc{+oV#7ijzy;^32 z5|V&YvIpw;^LyPVMig4@cAYIBzw`Mr_>c{jBDO#45|4x0GTo+hN1;O<6)x(tpr%)3 zcuRLFXzrgBoE(}Q?R|Jgpqhmq(AI79B*v!ZShncCkc#R-RqtGo22-e@W*O$ScMHP6 z3RAN-u8Nr)Cb9@6Y)$x!mA!VgPu!+?`w4slu(`#MzW!sAM zL@(CYnt4UgztRVYN_59q=tg+ye%n!BA_MmIzf>rh2Xef$`^{#uh^69;#+Sr%C3@15wH+mFJ8cGFvx6)EHe>@%;FwoLZ)yKJpq zoTOyBsLpsz&8JOtWGy+$u_WWNHEeb)-+PXm*W9+{OFHBuTUGk`vw9L4pM6_fo#MJ5 zNLlJko~s3wnM!%)abOSHo@;e;cE-5!=KSoWH=b)1JWcT*&(2Ra=YIVH@&f5qZ5C|}!k%7srlAoR zbu%-11yTnf!467b#=+B+$n*lO%HuzOhDJvh7Z-D~vZQG6<{NMTvI}~hpT3%F0ZUV$ zSURY)Aj^_Ja#m=%{|?Y6pfexzTe`K*B@GQ;kbDIFN?UvK^=0&IIS;ex?^9DAZ8&FS z;TkF`AEKi6TS#rp=rcT8U3ra_IOXi%-FD$*aD}jvxcuqsQ$-UUWoy>*$DZV~7e1Pc z-1K;0w5`=JZ*pO}{fH11ImjNczIL(bOTV~3b><~hx9_v1 z7xfFgR26msY^nms=@v?BwyF!Q@dANP_*E%sX|2L*mU)K>Dx?EfW=@V>)nsBK znekmiOiDrb-)-UKH=L6F1f4b}!Hq{wPJZO>sjiNq9RB>wEG!ft*4pJH@YtA4Yt}k% z^KaHFKYP~Nm2>jP{#8V*9QkVZCpSLz1{J!P8i5AOfY9a2@$3m6mQQ-;>z%y>7o)!~ zYR?040Vl2i?EK&(DwI;mf;VLS$hn?8F&)tf<%z>m6bOrN-yd zQqx|bm009_oOE;&^aKmPe*-@AI9adkc<@Y1>jWf3o3Y~Okj8L3+>m|xl;q*dpFrMX zSoK&U+kp@CCh<#%k^j=~ z=&2`8C9X|>aPZN-{-Nk#19_%nl!}T9f(tD&PbEGniJX|YUE2#ZsI${kAg-~P1cZdN zgh8VPS}{pU-30F?Y2a-EWuZ+6Wf2So;D^!@cBUq{fvy{Fdw2vf?PgcV%Q2^N{EyYGMVrK z$1E!v;sXYoLLb|hV9Qg+D_D3~bx!e5OFy$s(g~FOIY+nUvXzqeIeKA0U;=bCa~o?s z0dAGkfz>YV*ZI{z8uc1})V!NEomNL-i(9|Af$JGtJ954((kSPsbm zdau2MgL9Y%y~zS@kQ1?KIO7%)65`=;>W=5KsXxk=p|vnGQ;4>=w;!5!Tgojj-~Y2c z7evTx01cM>Sj$t+S@?bGlI|mXS3d%22=-tQ_?DzH0CnxykG)Rv$?y=mu;4#mCf~JB z@qXX;493G1F$#P2x_8`kD|5&)~F9cAaFkf0BV(+U~vJCFfrO z)ynb#OaH439mOWOR7s2iJpmKp>WMtMe^G+hG&%QPj27y^5Q78`3m5#`H?Xmj`JD>Q zUxP34>sMi9K3GTs12yX1UEJMILB5808D$K*h9r&c%a`=b%)@(Eb6-K$55(?nn9M&u zi@PX7#=wYuK1?J{VW0Z12rivRNA5G7Ix5Rz5!UQ#FyE4ZzT4UGr>x}ENef+KhS&}s z{k__=sgquwjMBrgz{G$yp^YrqbztU70q|Ng13^xw#5;;A5Tr^((zq5S0vQ z|MVY)^*1a%T(+-X#epLwj>D8iul^J=P#;-@pNlB|H1cXwGGEB(8sxl%%Bk zmzU2gZNz-6oiNMnGxJ_}85#zvXx@u#514$INVm3@Jw73ikFnNe(~s$QtK4)@VhLmf z;5oE57Ij+M&iCjd7yDzH=J5Z6j9{*AnU}w$oqgWn+mjPzmbx*7Ps=oZL;RL`#T;Jv zr>ej`0>ZS)=R4`Rnr!y?`sDUEgZ|6(fvCM4SX*;)00=SC(V1@lY8JC!ALlChlZGz| zvB(s;v$chD!*_OemfT!YR`v`GC=fkVopPy=CjKN?tD!EBbj8HJ2jbI>6zR=`OuhM{ zUAUmw0?$jaTqtv(q&j@a%q;f1%|yt=)Ko%+D)Ou*Z+S*mc5{4;Y;9unZ1(Ct?d#bl z3WJGpmnU-d^llC-Tws5 z`A!5`?5(7*6E_IhV7!0>4<8?u|18kFhl8P{tc(R3y6eFYQ-DX%xs>v&Cn`0VqQS#o=j!nE={r9XLS{`)^P$|XzX$A< zfHHsn{MjpbV%hQGetZHpCMMJU`x;fY#^&bcIyy-S2@{d>f_d|w_P~|_v*}rpu8y+u z-2A-5?t-j7vXhwXPf9ZGV&gwQYev?$E6YRA9XOYY6Q^s^HbB}P3W zR^F*9VgJ)i-aE_oBQrKuR)*G75%?an%fuaXFLrSqV)3=Bw<|9L+cG?#&1adCl#`=P zf8};lc7$$@kC^8*W`%QeVnY{;P2%zc&wFUGR7nzGv6T+X2=-4%m=`viH@;>YP|s5v_Yp4vaP|D$xjsq6vZEVAsibOf*!j1~j3<^Ctdg zf~=S-L(bYA^ntW`{Rdq*vBNYA*GvZx>Nr3lDPC)D)VH)yW+_pZ`Fj76WHmm`J)S$r zqLvws)D5~mlf5BM^qv5X=_U~1Ff&1~dx{!vCr-@Fu6j5j_PHO|r6qC~nz4U`2b`Zz z-x9Om2z&i=HnAwmCT>wbmg){4H&ry6aPRXJ@m=FC4?@*NcemJg6ji+ji-a}b?L~7u z2m{Uj;kouIDHj;4ENW^3*OO=TQvplMV?lFVnaV?rx7d89-zCPw2ed+K#3Gb^J;3Zs z_~ftCpgB2n_)uFLu4k<*m#w!mEibhbd)9hJzB+Lj{v3BNtLe`#YOF=~5R9t`eKl|= z1n;@$j|O(1=iAK0Y)mtUKb>P>B>%An{__f^k)(qI()D$*p_!49t5W@6%6fzHIl%3r z5B6d(j*zJh&EdaJChGxPJB79R_{^B|6Nb8>aRzGJ#h2OFuMDoQ=U`l^U=r9UysX(z z%Zj{z2@y*Nub54giR?LUGsYFRORuLb{5FxS~g!pMYI@YD=jlj3fdn_Yw_JtNp3o>I>Vo%XCfwaEIfS_8yvLH?=oHT zwst+&M<(lCK@@|_S$~A!29&gbkp6M!kjFt!_!b*XA|`BT?2$<2Xpxz+ATMtfzXy0v z48akx)K>7RYe?q-(Q!!N)CoAmV+sEymxC`%#Lh%|ldWVo$MuK@6QO?}#_$sTZaSM5 zr>53I3(nuRiC|7$qh$rrdydn{y4Vxy(fD8-g8D5u5^?X+f}Mg7vO;wv21qDl0Lylt zG!^PYZV>!ki9YFp^*;$7V~;Q(5KQh^aOue3K3Bs7e~q90CI$|0DoFdSzKwvb%`7-+g!pj;Q77`4^^zMzJQ59_@V6K;iyZ$K7>n|Fj1G@!G}wm zzxu$v^xaVw1_bIEWUj)!KK zMd^0@QQXbsh=3u89Z8`M`uFvG@6P*13bZ`j-NB@~ySqC$FhGOX?uSJhTUqg6r6V3N zFg(?<`tK7GN%@)ssD#9OD%UDs=q;Gad8VC3?bsINz?lc4Nd4(fr$(uXxP%0XNIjyE zXPqi0>BuxoTmZ9p9Mu!iFxFqF*I$g`<@Z00;tYR{;%WR)e)-Mb5NIZlrqiE3w>~^a zNuj_1eSLi)p;`6W^2g_q5j6)@kHaY^NSi?7cr@VW>(;@u#)xRm`s*M3gw!EyNu6_p(uW@lV zhDGP8m_#TUSo1JbdWizXAk98gv%~{H*pT`=h6%_~jqk4KZj#gj?hbldw z#;|$<%#L>Ei|P*I73i6OJ~A^4cpR43FGi&SYe0voWc3QR~ysHt%?GNOqj2sB&jOA}Lpat11zGZna{yoPA>Fw@PDG&Vl*+G?JKmpZp^5_S&V%vgvn9&CsaT*nh3?_7Zwymb zI}&LMxyQI#T3X$QSy;5zC}8cs@BQNMroq+!T-llyLrp~`R~K06%U7@Z4gH@4-}z=V zA{9xCMas=|@18LfwOo3gY9~cR6a(3>B&g!qnePk}I{&hAiQtKm(Qn`%7Ut&m9+rwU zc&{ENzJ2@F_a>3!$&>2YPS%Fs+s;WuGu{UxHdECHtx8UW;ojYj`X%2hDjsWZ3?3Xb z4YB$U-26Lof_!hqDZ+@z$P!~>DnUm!p*{YG1srTxpQ&7F|GL0UyW^u^jX|VBRy(f8 zt23!F?}7;hKOB-$P~LRw)~14}x%moYop32Bi>e*4aoMyM&DxBBn<9}YCIU4+n=RIl zwOJ}jGlI1$t(lpav}>JT#kAkCXa9%$INiiIU6VyH8Q2)+wkxlkVx0p zQ!k+iS##NOa%RG&fgB%oM8?LBjg5UVA7*$h3^J^FYLCFlS}807xRbo3leD#5?{k{o+zt15oOLgT)*6Z(ab@NJ6`Oe8*EzhGcX`7;;_J zuSfoZ8Bg|P&P5q%{=RdUloY(`6js*Bu8Tcs^&UEVF+{j1EKlW;ti8? ze0)3<%45N<&_$vvs{j9+k6i5g;_lScltl2I@R*pxwbEYAvz2II2J}4PY?{${pMQAa z-^e&RUE+7@7@xRMR4yIvE?68!0+tiD(I30qok|B5Gu8Toc!$TL?a33g=QTU~Z!Gv- zm4=n$GNOutV(d%0jr@bNc%Lo1j!^D){c_~t84efE>Ln%BE6o3eb2e0@rx)TA)ODR@ z<=hb!u7x+#CfbnR)5LZkUgd*oyJ8-wtvfmS=w$Y?TiNSP)V>$6ynn<_CUJNqpv^QvIUrWZZOE4QGWI}YG1hjFUAyF3dWk}k^5&;AVx zi`HQ^BKMH&>3W)4fo8=U5>@}`Gx(P4+8Rhn@7ePD(Y4~=VhDr9K>!fLk2yGA)?1##5*T|_U16wgzM-<5jelO|_b$(uYQEJ? zeKWWcU0e5GsV@ZVo*DyBi$7>1bJ{bZ z6;=-L908O7Q;qmCKt~~9LJV_>Xiz+fIDS)%@x&K35c(R`E=y3U3B{Aw08_(}3N!-s zHy0`_QGd+=Rl^@|&3`f!T<|H!RYSEUqK@ESSN7pvV~6{F0G2UH>_V&g180y0W%>8V z*Zz8mp5O+m<`hi`#i9_`fI70@;i#hmeukibZiLHpjhzf`unqqSrx8N{$x(mH0r|rp zVP;?ua45iZK>htcd-^k*13Ka-?!Tx5Axt<-ARck-DBd8X1P^ZJ4eTUTCGuBt!nGH_ zcvFNXM0BCY4$$8&?7zR{5fytJ*A`F<~|+5WKlY(n&z^TBUo;S5^EHOB9ohUwNo zDQ}|)lykjL+qWpNI%b?isT|ylIupsk?wdf*4U5dM;Z&>a3kWfvHIo?s) zPQX6jODWwu7{9oDU{iLHve#(qQvv9567#p4kiQ(6p9-lak|Hoz=T z

5o=$m|6`E9UBsLUa>EKpEG)L$rb_*K~kMhS2A{Cze@}vXkr)?xH56W8?O)Z;5O5(hd^geGgUE zK9+F9W^k-eF#PuqH`hb9&WkOJ^?IjbrM3Y-79G8)CZbN3P=+2vPCJ{J<(r^4#&qJ)(au5O<= zuqjM^jR=b9FyI3;jhWnpdL?R9XR^L#Pa>}U=30GI{v=&uT5~a}j{iez{S4e14StxQ z&qILBtag7H$Ar=r)`S+UiBxpWLZ9U|crAi;#<{wXJ?MQ-LW0=yi%S@BSnz-fplhf| zkE;DfETt4eDGx5e84b&%kcFv$1Oi_ zOq`s_+tj7I-h-k=eF63oKz*^*HxUR;RGMWy_`&p+x@EtDbH7h!uu*5kxqp;w z|Hoj}{ta&XiMQ6PUIZ_EkP44OWDJl^5APEr_E5F?GQ=!R#IlvogcDT1lxRy% zBT|XR_|Oqw}Ox;IZ zR$37EPKJ=;t?Mn$gzeuv`w;uOJm8$WbC7F68qB9}_ie#Pi6R=MEx zgOh=$p~J?;Qvb)e>mx2jsu-^SBy>I>NI<)3ST-1oz`O!mifj17JFSS%78G+7U9=a~ z#s%qh0!vBE6$g!9>>)BsOE4#!gJjw;DpbS4&NYge` zQvX6K+8%^f#HShX>*dRlKWj6#ins>aLfF=IF`9zH>cbS9C#IVv_`JB`UX#+5*yLtR ztn*t}#BQ{2K3gZ#vAl91vVB+C=>qLHc=E0%{=9@3>7{;TZsgh%xhjP5^u*Mzx!~gj z55A(b>eUkU#ewr0nj@Qg?Oyz)d-u3w80+-9?GDKj_tcuVMRSO{&X*~J^1U8et!!Le zZxy&~_Eia`uxqMCL`7wte)#{wszYhqjxFS<1v)|^#O7Dfjd}--O zNt%uZdk{_jU;Hk@y298$5?*}!71B`u4*4;g+HJoDgRZ0wqtD`v8%#sQ;ptiVJAXYxLdaj$)ir{=3p)+$*XsB9Mw<)jN@mZiD7Af3%&XjT zvhtNU|GcUwNGk9NXf`MrBjcxwS>T_~t`8Af=DgEuy zWc6Zsn!0^6Oj+bbB)3%$FRzr~=BUTiv-rf_VETim!^B12^Ryz_g-nZXH8DI=Eqi^=8cCrby6?KvuL@2EK~Ud`X_{o` zKt$ELx;m1RAN5V0-QeLfiwXK@m%Ttyu;wG@p*zvOHdZxMt3&E>SpBWAGmg?*L0M&N zq;zU+o-icXb$9pInr7`o)fZ+^~a0=ohyh*JSw(EX)AQ-zR5W23L zFZedktu&KH#x>9gdueCoOrz#xV*Koc`%jn7>!z0SiH-3ffr~FwK%q-uqv1AqezD&F zjy6sxw_gZLpku$$3;tVhe*p%x8xQmcc<;=@kZp~P;;Pr5Mlu6)BlF}*7mb+8(e4T) z5NPe~YeXh@CJG6?Xt)ZFA3nZH@Mn_q*rK)+w6x;DClg97QQ@>^X>3dgJ7L)P@1}xk zg6Hu@6S!xVm5qRfaHm}Y@dT6uH6wih;`!`|d*)UiSynv%e#Eyoy3X0NvAgH$$b@vB zEjCAc(k`3QK z;6#UNv=|0=XuDl;`Swc2)UeZR4Ous(8Xpz)2r`Ty>)95RDIj?rvf>wpi{@an3}N29 z&IQ2a9Km;HW25J}+@0E#r(Fq|{DL5o;r@6CU^viCsh|DY2-wRacof0ajfaPKmyGN- z9v-A_y;>e(lWA>lYlHVk{O>S;hzG!11mJ;yJRDFH0eVC;OUZJic;Wb93#G*Hc|Zvy z9h8(Bbi5ND8VBd+LsqxD8QI%bFhs7I*}8A^v>tr%-^^p+a#Y`yG1OU|;S3nwW64+7 za-+NVLe?!msJ7U{I4?+lg_PH;N02c<%=V%ITtmm8 z%K_S2Eb4`63D1VEMkFNEK&Cl#I(K;VF(>RG2{xQ65mHw6$P@EA1J~UNr2hBy%Yw@g z{44VE^1b4Mkdp)6R*ZjzgwtR9_HApN6vcpbOA zqJkbD%MXP|gn6mSWv+~s7lFqQq7~pkhoHsY^02;@?vWLBCgYohDH9*fZbAIEp4sa` z{qOFv81D6MG2e60t^CJQ0_<3{d5(?L^`u79SuXHaH9h~HMmtFAq$d| zN+JFNNC1;Y@%&qCL3#QJh$qBQ$Hy-nRjRzDr>DorhX5&L+7pXH5(~P$di?m!EK#}E zM2VSdM+hKd;LQ(OobjRX04YiN?0!h^*DNvZpR9X}O(A%f6t>XBZbFwtdTX92 zhNpKB-ssDG+G98z9jIiwwAym|a&ATxH8ZUKr4>sYS+HfUvNd@maay+db#=(@#1gr= z$jNHmw-j;dfV)OJ@@Q?r=z3&$63@BmA<*Vn|F`_69>4=mUse!+{J<1Q6TTk z$Z;T91s7KY1r(pC_l;-)S4VsMZP18u-JVb85zkd&z{jGa`wU4_BV_YbAXHFTXbU+n zuy*%XWhp_ZCVjR^qwN!TEkIz8r2pw>*?5lYTHZH^0VF5_T|a2(e*Vjl>|d|nvhWa3ebDNgpG# z>C1^JPR^0$Slm#JT*GU*>R;xv2hLn!e*W}?2J~w<(e2I6)^>K;bBr?YNcdk_!z2W_ zaf1731W4+622D`7S;|m_`orh#(@AbZ#Yu#tApIQvS=Qs*- z70SwYj%2~x3k%31^Pes$=13Op3Jw7QZM%(ctEK(0TvH=iSXd+^nshk7CPK`usH%z| z5>p-`20)xrE>TeXtodkX$!UGE4um?^n-(70g8#fxg&5#&2x|!N^P5(Ov?6`SQ`7DT zzV$Qr>sH(0l2OEO9H{KSC*DU`!YlA_WGz~uWYHA)xuoXR+Mf2F2Ri+rpsg@pQ!dd# zzqjIJZz|CX%-VyJc_Du5}z@ z=Z-HV#P97c(|8v+Dn0sUN^!iXsiDa#roo`YY2#+0k^AL-TYGuY-suhn4PLAfQ`3Uy z7iX)z)VV!=Ah4;RyA!h;fcOq9KOoHVv27;iq=Iz&$8{F_<)MvUIiYwClQ2++0YL7b zJWUdOd=bI4sDb{dqc?;5O5AczIr=mbQ$pw|F-2TMInvjFP2!{o5zR1LyQ zTu!nH{KIIp5Fg(WR~R$5k8CA%Mj zLy&u%otYWMZYY(j58KnlS5bsa?`TYoygk0ULK`-h(^ zDEf=^Lq7zPM%-9FIV@NxnXuWO@8N%uQEkR28pA1cQ@jy0yjEbTg`g@-pBO#I(Qj*j z{BDnN`}h)ht3$TcSG{`Rx`a%6(jc-5i-jHZJ-CA#_3ymBnbp2h0`i+ckRcln8-YQv z3gHDedLQ2({Ng8jwP$3YmUE&lfkMIbD+CE#5I!;T@Tl?ek$?#7b``wD_N^@lKrV5z7Z?2w`w)ee%Q^PfkE5s(t_BwFQGsog%xC+0)P z7_xHBY>$^F*6STt&b#wboPAKGqi<{L*)=1L+{3LoI| z-+E6aPG1r>dK7Zk&TQ2CwG3G zuQjqak2RZqQKk6DU6~U~i1wU$)81S8^PQU5BY$2>9Q1%y{}``?vT}@z$MDH?MRQDY z&E52jtc$#)UliTet*D=8u-<%TM!d zM>C9WLprs^5b3j(3vb}xaLBaaIYGIg=4$IkIJ-ut1=l)pQ%D>abs;GIT_Dft<&l>||Kv~Jiee}aVjL+h@r?yOu z>)xBKbaF;Vrzyf-v{=_5cF~7!TKFzf@ygHERx%w) zXly$C=5RZs#=UvO?X<-6GfVpTt7Woi0p}|UgLNGC=ZATSOw>?HYl{TAud0m|iugFP z3n|xr7Y4P>I*8J3LwOmtHwwPft4lbeD{L>jHThH_{p ztKysyuj+Q}?Nql;`N)Igfs2`+K8o5Abk!32`rakWaz?0Y_P#aeJtibO4H&RW<7CJR z9i0!*5`M%}ej7I{Jlr+WQaeeLaDJXSrZ(X2MV8l`T-1g8+T)5og*jm7_chBIzu>^s0(47p=h?YZ;>1s^&C6pkj3Xt+eYqcW96x=$D`XBBeuOr6itn<|WC^MZ!yxncOX@5c`y2PIH*gUb{dcS5f=Gyc>2{qt&&( zC-ZfF)MT@{#Wq=1eDghlu43Q9st>Uauikx4Rde+My66?4TA?iuZ5JBjWqTVWoD|0B%8p-U^}(v*Zlg=Zj@HDiB1o) zjz*YNc5k8Z?{aSR1#a9aA2t`>UKLVORW#tHQ_K#J5PP2>aOAr4`=o^fK}qyZ3@2uQ zA#4nlX*THVt5L#{iJQ0a2+i9^-&!r#CaZz+p1bx?OS+Vtie9L&E( zO3^#5aLy|e?$eiuBzbew&sQt1oD{dV%s-G};>(F__7fLFuJ;@c<5ztMV|aKjE$U6C z8)vo47KPH_wv6%jOBuq!kBq>a{!-9uAaFg7GxqjyS()=5sqL1}MTjdE0dH4AT$mH# zJ8vNx%l_!GO_5#`EHtEt%JWU@%|t`q_}HGYgtPK4SlT?2LLO2dRaLCAQn63w%$nsx z@yma<$oO-%RK+~dD5>38nPZxW5uxu7TC1^M>B>Eg#m~-?%vHk6YAakdCKq_VHX1kj z`kWUoboD2k_cD1He0^>0cqjr9H?C!L%D9>@#ckq^RQc{&rd>)kX%P&2!b3!E6S@@` zf!}$G#$P)p8oNV5ALdy0!&%XwBtdYgF~foGvjkg18Or{eUrbu3I+%l1-;C+l0!vbV zlq(-isxF0Bp8IY9=gV{_-{i$z*lF|k)hJFn@$8w&J`VD+T6Xi}BI)tXjnj#hXmae0 z&$c(EaBv-Y`Qdi)zgd7JDw~M)N7DZHOtKybxy5_#yeZ7-8|c^W=1rMtc$7zyztDc= zquXVnrSW_hy?pe;)a8=~MbbDVbFq2p$d1( zp34Ti?s&LzxO1%U6I!bVby^!yJuwj-b)$;4!1Co*t#VzvgL>1%!W<66rNiZC64_Eu z@tH>61;^5Et$%T-7|;(-zxQC2%OH_gMLmjTYu%KM?bm~1<;{$epH7OFmaIxy*U+CbjG zna(>;D^>H`!ioupGtyxpWyZ$yTH?}e0-lCHZY2*GGAIZX704yi`jUmdS&$|MeJrZ> ze7@=3>E^>fhl6i4w~~D@-#Q}Kr>qRFFf)s_S7t|z0d2-kI>%zUm#Q>E%BzeD;I>}K zR<(~8(VXO=OvOw-?CFxCW6CQP`e8CP>4oCVsq;r1B1)DSIrp;ZKRbW#&W?c{h4I5u}RSrlh^mtGC)(S-VoUwH5Ny$x?%l=Sra4uZ?|sipgjDVw<^AS+06xB$XC>qx-FIPMtUs>e+4PBOM(}iJPuEeX zI>914_U2v7m1${|rM8Qf`nNQsP~=LR^%MUL*^h+pmleL&e6ND>(pCIvxGX2Hyb`Y7 ze)$pE{zqo*jBtF#FU|e$q4RjSXF9PI;%)1?PRuvhcq;~W`j>qcjK!wT->{btBjxkO+?JH*TQyVXIVtR z)f!z`R~Bz|Om&O&p#Yv4>Ds9r`gFl3CEOr?;(}jheN}|Ho*YATrRunTD}_PEX>mEm zp`c91VtQ0P@x8PkvGdsb!ZRASUBq`=8R?1VcntJqFHE*(Bn?F-U?#g?gYLrO11#Ye`q_*O)tkd9 zg;&5`M8CIzow!+Jw{#VWm3Vx*LWYiyCDe>gG+vocdwFMyT-~*ZG`H!U+zG2;8@I8s zOg24pxbv%TaYRij#3vGgHM=vL#SOZ5-)a`0%|DZ&mKiN2L3~GH>kL+xY88)$sW9&0Gd305qpusiKN{t-9a2&ZNAos9POq7cbQ_PFg5iL+ zI3i8JMtIFnfhQhb^M3<@K!sxhhf#EnW{sk$SBP9G5zj|p(+Xb@reg#Q9#_5Kg_ybd zGMM~ddEbftW@P>y&4I``A0dWQvUt<{=qCHF@Wmg$oB|UIn$FEWE`BXteBpvu1+)-? z4bPY@5ZkSZwt*eN3Y#N@gPJte$9oBnXPpfbw^{|Q82K!gUthfK8ku}fn6iur`iDQ}?x{GU@D)@pB5)v20WqmPp607b zbPkwy%o(mrLLfU0)9@jSlK!03)OjKo5WWNiWe9}scK!n>ORy;f+{{ZXC4zHagoiXg zZ`#Cjo)Bw=D$RW_|BMIcolKC-XDkyJIv-s%hX&E6%425 z!JPVrDXc295dBA#y-tIW`6qb1UKgHV-o(mIuG?n4Q7=)HqWzKK^x$t^1txWdnBOp? zVkLlvGp5xo6d&>)NP#x;ZVKzIL+KpOb3f^g?B06OabQ{9_LNZnn0%*y`d~oHA461O zP9!btVEg+4wdvQDJ=muI3Rre?ZuKQGKQcEkANhMY#&ZN^UPITy@j1yI8}^i+Yrm89 zCy5Cr;nSsocEA3*6)8-19y0)EOOd3*6T|~D=xyT#kElUZyQ5C|FHuBXPK&jw2 zZ<~jseKS+uY;MkvIrG{Db6KUXhHkI&P0yMxZ`d$W#>I{K`6@|)W%-S{EBCs+Jz)o0 z>=yIol0ayF#MJ=G`&@48<)N zJPoZUKZ)98VLHT4A5TgYOjR}Ju2#o15#?CX)${tjjb$^&i&6=7WkO zJX~dEt_^$4p}RoRg!(oI`|gU2El-w`{cN1DzyMXd+duX>=ZqHSOPR0zJMwecK zbopai^IvRX6o(-{=U-~Wkz0T6#^?D4q7nSsP=#Dt z%|)?776;$+geN>!mF)>h?3s?}*IeYdiOHjY$L~v^E5gK*=-b>98rgXBd9zz$?C#J2 z&&<7IXWW(XC)dS$!`x{?xhh03U~boUfq>_dO7v1SA}FY$w4A)&tRkD=K`lX8VHY90 zVz#~T_xfRCPzw{4$V_`jgSR+THzYb0i81m}D5reRRn*@mxfGe)5tmSVRGV2KQ}Ws- z*{MoLhVxZ_gn*N19F@NF*jsarqf5Bm-%qDk2PUUTfAeM!lin?-Tz8B3PkZg}xgd3i zNaUo&@2FW(@$r>gJ=~-ZxFg-%UfTX~3TF%azQy$4jU`BR`3W->?i3@J#bJWunG{M% zLFC|){Tg|e5(+g=y)f?dgsSUpGHFA1@8klCFuALA0I7M+ z085l?!c=6VrCk}Vc=DK*`pOmmmvXrpJzl5ycGRj(gYyV4XXsiY*EWQO z*b4sseE^p&qOM^Mt0;VWPzU@Fypk}JFueZT0tFW+3tpsuee4^f0li|8yLspW?o~cC zn@1x#0C3+$|MMHdWCYKe4U#`xLm+nGtOd6ZrMByXzZ~6(!x(#H#AY=xh-_cIxgLeU ztU7@oE(!girE{!#OmK{uFoX$}26(-+o-kz6%fX+>QG6?i`KW*;I8vkRHO*LH>Luo--I7=uxFrj2Z_7uzyAwW4ko-|%upH78hJqhRVIU{G+ zkgk^~1Ymfl3mf7JQ^u(h_geLA==%9Kve3HHtu$Sfu+@m2iO~amX{1k;h(*4~CT4WIbm**Up#T(y%z5^ZiuSRGsdBRkc z>>z>5UBRF4;Zn+)p9|9?>Ny(jqNtTVBTr7YQtZx;LGa1kOKEC}W z&|HS?>|CV&WDev)vJzq*u>D*-xklQyqmcSLXy_TH^ z;09-YNR{2#hm3Z~w;M}SLNCP6xZEG#wNv9nq8wUPyM8CNgG;3SnjffHZ3V$ zvDkNA2jDdd2ioYBs;A;M^tF%r!?6J^^@*!Gsp{1C7bvroLj+r;)2-%umW{I>>E>rF zs&FVk<|YCL`FGzNEaN<7UB}wR$e6tNjGy@*s^7$13XQlqV<2xtj~nWQ!&AZag1_WE z65Uw}Q{D#bASWXS4)6MGwEYa2T}gT9XTNM*;o-fibq~54IX+K#1@>o4QOS`gA;{K7 zPK7~+sv-Oc2cIGM3}OAUPqwQmi73CC#bPNbLcjdE^>WqTOZN$5_+*%cCL{bBQ8#m)aYMn#NdcBm*u8jGdm5&rHgFapZi>S9zJdt=(BR)U zG1mX#52iq%Gl4Bckccd~kYPS}2QUG^SMga;?`4fs2y7MySqSn5G;t*c5S^uE3fm26^f+|6Ga*`PW>~n}>_!;8STTGp-e~jC{A#I|ylcAV7T)>q@Fh;KH-@}<>z($tE z&Hzr`kj)dRBsQ33{=lF`=vrT=hBQ&kL_xk#ZU%CY2t*17jX&#h@7}KU|J1O)9&JpnUvli~_NKivczP(y(-6_7B81;cKcw6S3c$ zp2IX~VoeN#2D2K#74IvWi3KFQ7srRm4h5hs;$qLcE8xWPUnikRr#NVgkuDsN~swSEl#ng=Ml3G1F=H+lf z;QoXoktLwQa5>+}wIH5Tf-x`fpVM$XY#`N*?%q~kzK9(}{@qLmUvHCu@!kc5>Q@pH z>C0Om{7TVkpSW~C4YfX>O9g(|-+WFFo0{HrwG5u9=BE@VmrV}YUHWtX zO$2y^9I_v}nc>P6vY9;5M|{5qr-gvJ-{-*0x>B?i4l$ol!Pd;*EkRMJ!aHZ&vNzK= z5tn}$zQo~s9hTBq9~|i5t`e1&nY{4Cd@vQB5Dh%QMI6Q`|F_TU@ZnhiQR*9$9#Q$v zYU}|ssPs80cf@mXMmr%!R&979FbpP-dR}L^r-@Hu?ER>6Pr~ZNkK5R|YC z=db^u6-!`GxjZUJN*qe~8qAL8Iyz($POJR8!SQ4V2a5R#+dW$}k)$SSReW1l$VO!b zWuKj1P<$XcC0n=hz?Mkt7Bz#JKDO+Q|HVIl`Ka`Nbj=}C0GyjRK?i^N{kU;tBzupt zL`vO_Zf17&U0*z!@8bK?;CTJM7B4?s+6Shn;EKSit79-H*x}zr{rZJM(cdvN?%gq{ zNRaltn^eNk($X^Y_K%tlL9SasUK|awQ1ycqk@~2-?B)0|QM$dZ(sT|_ZXQ=6*YFgD z7@Pcgl|ohYVs?w_fJaK+m&N@J4Kvp!%~5V0Ey2pI-z-uOSI3X1vVT3T4L`bgzpYJb zb)~hdO5*d2sM@#iG>yHvIgx8@+Ye_d;j#CJ)g`Rl+0yr z`z1Z`74kXz_5SF$7P9;5{bF%bwTo&PDCOrK(!}{Wqbvx z%{nI)OU(T`*!QoW10Sh)SM&UWBuXhAKZS+tQKHqM4DTreZukCAOf1IwqH1+CmtSsf zP!R*}f5ZXaecfPVcVa;5@pYa*a+Zu|J~b7Nk@tem+y zBQ8{*^LoC1k&u;LW-3TmH6It36MM2c)!X_Jy4NpFB~;bU^iGSUtC5V1X}ThW?mEgM zowvQJt?U5k*|T5UZ0Ki+j5IdJRZzCk8$e%y5QWL%_}JEG<%m0YP}+;`Qax)R%Jk1~ zl^BoD$(HZx#l;0qD(6q8Wz5PK57A<46eI$ZUGwK8bjVy5$FD^h5$WPJPtN`L{@apkBRgoh!)mP2CTu%HF1gsy{14aX}r zfeYE!z}ZCNYFIiD>!wVsY})D}dgLusaJp?CeRFbiveYp*^hhX4{g|Ts&eecI+3;ts z1*uezqF-n;f3?PcV5|QvCQ0JN%LwGE(Kn=`a`@+yjircA0-lTBt?tJTWZq-}!bE^a z3|1wu>OF=6V30CBOmWA*aXfhIU@q~WLRnBxRUb-%0?`~JWCrP&6harX8!@Mnh$?;7q)H+8SLX#>@Ktz+`m~B*op9-{@Hq51^r@+Iqsgfjo&;T z$xdm+TWZ_~PoFB5S~Lqfpgxyh=k||ay`>z zP?N_uFqvxlx8ez}P~z%%>K5UAY|!?U>$Kw0Du=cUQwaX=!?L=qI~}?9BgDp%AMcsi z>Qoim)1<0 zk&pQ5P-nG5L#@I-3jinpAZb4ojC`}o-`R(RWsl7kI_N0NA#jIh^Qj>q+N7nUGXcn? zoZvwk&{4}0plXQrJUf95YBY#5K;d4{dV^GLfB}Piq0iJn3b0EV5qfYC_^3+n8#f>Z z)|!;GyExQT`s)EhDobrjqDO|)M7mWCjUSO!zr_!?;g}bv7s#8wTU3b}OiSMWR24oh z*I60f=e|O~;Ccm#6&&-*v~k~m%)CS~+I>;&TR*xW_T!S&>tz*GtG}(Xp;*ARf?KbX zckZf~H6fqviOrLuIM|}m>~=aMb<2FUcLX1)s-JrG(KBeOUKuRS^N=e)ylF%;WL#?l zDpsJ+c?k1`$D5P^arMjF9swVnJ!WF$9yc85XbosW;z zXekp^*n$GmFaZGrUaFV{bsu{H#q-NlxoiI8I}SK6p_|a8)ZQ=`qfO2FXmTbZRW9a9 zmMU0XMnu9gbbuG%H8+_AFel+XyJE7g`aFtM&L1REyMZ3cBU+qa8q_|;w>(KNT}@aH zanun+DJ8@Mk@%bj4*(uc>>AJM5C$`XqI}mpv<&t)5fI`kIQ#sti}#<-K5>*3Dw@I#RKY6-gsgQwR)3Y0uR-%C$#3fgrKQt&Ouc{@C! zA+@3klJ>PQFHnL-d!4(0k<7-F%`)Qy`WYdn^{# z{H_IZ!&}U;=9&1CgZ1av+x3qtJY$&?aqLCx^=})D-xIvgwuw5cx^K6o#1H`{M5!e? zO36_u-q(DbzfUS%Bb~mj{e!bWYk*Gm6_*{4|IAvr!S&ZfHOJ9%Bq6$^>~#EOnh7YfPqztfhRhlo z8lC|(2Y1fdU*hHE1>+m!b~6)-IMVr${-Eml$R=f00)`-HIe@~$3KZRj=^j%m5c(A8 zYzXd8UPxC2!IMm$o?&%#WkT_n%*=hD@Brp*r4>VlJ)wbLLWX|VUFyiT;k0I~Yu7+q zf-~)zHV(mSiJi39m-8zM=hz=Us-Tw3O53(aBBP}{A7WatzUj**n{FbG|6Oq)Bdi3I z4k{&AGiRb=C8w9g@+N|a%|3D@UmoVGaRp$m-;)9nJl`Gw)l@gT1@_tHti-Z+xob|U zeri5^l3uYfPMAkl0X7S6sOIO@!5V)n9+QmRY*&*;0dZt5@m;e5N84S})1KViB`{xJ zEKW=&10XAz#@tqsKU~m!Y)wRL6`!E03q6^9+{w_*!N&v4NLJ}pS^fO>5ZU-uiK)F09g!2<>wP}=m zfkY#KB6FREQJB|7T&RhG4QMHt8IZ&>n6C?rsLw1>iAJvceZYrdIVIsVQh^d4hK4hX z{n>+g?!{{nia=9SSP(7G?+i&fA$uAHZom5%i~V z=R4XBttHJJHowXl!}%shUMNFFEU0^h5D+yLRBuUd@&27cRrw;y!b0%Bfu9Vyc?;Q;F{Y}GzRIIZ zQzKdu;j8l@aH>>2=-=BtNpp*tj^hgnXCVV-895Irq&JC=bDV@k23NRDeO72WGR?M< zRM;r`-Fu}hDY!f|hW1S=Nb>t*`eaWV28H@hG84!G+M}pK*|=Ba6tfL(oeL({E+db; z_K-EE&7cs_R|_z+>fT&hj+h6{Tu?f~RNXw>W{zwF>h-YaDa$ym+5oZs&EJnNcTAwiJOd%#Egw)4&LV2BsLxOZqwPW-*eNhf?W#l$0to5 z8B50Vzmze1O_5O1tRw41uJFb2gR}>)q&}D%Okb#>ct02;opcE|T%7r- zOQa@>OZR14J36jq@zpwA#j+sd^YNv(C67CMWpo;Gon3B?;P#6x$BU|099hlpkytmz`}xvk0l0+>gf^s>=r3k z&S@Ss5((m5iD2e}W%E!-2wh*F3fXBcIuVe1W&qhBZ!TT8wY7y`FRm61Wxi&+JMja1 zOltHr^TzC!qWibs1MHRu#2rfz%U-aP>NraxdKK%~;U@3t)kVjpyryE!+WmowQ><15 z)zFd{Oxy01{Yj|rnB6C-izP9LYhpN$J~#w5VtErOMKhTU+jnvx7+8xgryAh8jo^g%Z``agS3G0LCYy? zb06{R1v`}A&~$XSz%w;~+cA+wO6qstwr}QgNR{nNt<#g*YE2a9+WPCMlZ5?(I|7UY z8nwHebbsR%|yx?AO|az6n?8r;#D=YPNns${|6@sFNqFw$2|?b&bcgcL>DHfc7jo?Jn|EX7yXrKGd2pq;8`zN(JMxvbaU|MAzn5t@n-g zA5^rPnAGK0Y1uhy)%j`ia-{>yw>rR>t1L5jj4eB`B%}7zTRnvedGm?=iNt^OMh_bd z6HN2EF5aa5nIT3%nCOuunfU2WI)PFAZ&Q(C=XZ1`sXXhLV_v-HZJPamL;4aqz4F%Y zHGX@bSd@j+#+hRFaj)`$bdBxNX9}!59r;fYE&SE6N^g^%hLxnInB+z?iy{Ns*_!)3 zt$)R%pUHMwJbWI|r_m;O^pl4$XNBKW!S z(@6KQ6tj~FI(^b~hlKqMH#OhAoS$ifuxXNDMd+}v?2mbjxc0!_zmZ)t=ZgWiObzcm z)0fMLvpdt$;>sRQGJd1$(K}F|&Cdr3CKF?6&l0NNsnt-k<_^EluEOhcmW5_bzr@YF z>dBK-@A^weU`cQ_e>{oIKvJ)O+}H072Jz7GHMR*EFpWO*?LMV0=6|R8ceg50`8SzHdYf3)9P>EMJ+#}2nzX`hdA3h#u6dlnt=EAK6)D>u&Kugu zFdmL?g(XRvM$SRANg(lpn0!z4A|-vwAge1qVk>uC{0Mp*U5E(YcAs?I{r{o!BG*|X2t9r z1IxdgCv2M?vW6#&dxYFCQVP^oYwe!n^_gD{rln7e9V^dvUleLH;g?v_8~j-w!Q>vT4UUOrGB*rzpYhq)Qxm!Eql29I(YVDd%3$h1kNw#C1G*_ z(T52&Wu&E0<}*GVcWTsfG|U^zFF)2RkyBTRDRgk(%}P~HzvoY2@wiFmqjR4}*Zcq1 z80srN%g-TcFKvgiFVcCK-{Dy-END94g@Ru8T*^EyZsp{{M{c)SzG)txBvw8v-42QW zgKyiEskz^!9l-Vo!*pD`--fFRkSKFckpYS2Zed#&ah;Pz)U5BD#g34tLsaFDk(Ptg zWcNrRO^k=*)?6^qKH{&T((!XeqKx{nh+h`G69)%P&uspL)C$mAtXU%IJAb)YZ{|av z8NIJX#E|{H`wt{s+(AobIe!_@FYHXfc*DfD`Pi{pUJ#Xs)V61<3!Fs$b)w)O9^!-D zVkYrctRWWuZtjDL?Qkp9T@Re zAEu`Z64iNMa+>)I&omxawP!~|2FwjRkEzO-dYaPGnet%_kLm>O>_zft)+`mm zLL4*twqH4b6PihgIka(=qS6?dsNP=^Xdx`d+m|Y)eek=+coGW}dZC9&)9LK9)!DYF zf>fdE+G|vw-h@=?*Uu5{14$KvX-%5+qM;z_@$T_3S9WLU&m-9H= z4PN`z5s=&7S>$N1SnO{dl2bh#G@$?Evqx0nOl(n6hVmW4R{knY*+Bj5z*A~*-6LCP zjo&Q6bxb3k+gTZ*v_OjrH(Nh1#Ke=rpBOqa(KeW#HOrD8w`$hqS1B)@1XJW^oe?pV zyTcwt@6YFcUWI?wp3b|y#i^a8{di`vU}kaiQy>uC^@cAoQN;homaxh#4+Q#%W3%oG zBfb}7f|?jmMhzrJkcBUP`h#>IK%LJWuKGZ_R>MOR2x$U_i7Daguh*D{3eHXJHaQ8Dh5R@Z;jjx3<%X{Gs%}>7Bs-8~ zCEW)%8Q_Zx5tvw`P@n))ytGSA5EENzB>Aif4O}t@2A-MZL%$p$Y}wN6FshMZW&`4f z2=G0VSByMl($nc79&b6^i3L~&;?@Q#tL)ht*A#Tmw>!Z(Z_bK^gY+^A!qop~uyES7 z<}myY232eT_NGBLDJ|26wY$t&0b+^;JIuAtxT=W|p9M)`VKVHkl=ofJVwRlrv?)0d zz|~N@c{7D}R;<;HHRK=|8bejFui_C2FmuA~aP!Y7hd5u_0AoXQNst*-`-`vw6Fn2dIWKFgv?;3D@I)qAMjmgXNSAv<=kMJCnq^$+kH8%6=A`w=@>`g5xV`ieW$E-;6$+W(5a~%0Sij%U9A` zLaDvpk5(^3sQ(zk)&Gv`-MJGUDKYn}H`=b)nbaX9%?VA#t*Rdq^3++qc$2BZHq5tK zN2Ep%Ks+8|ds}RX?u~xxIUb*0t}_gYQ@U+NewUQgY(5IQ3@DTVm1w-~5wuyNnrW3N zAw&?_b$X%LgPKf8#U>P-Hr$1o|m~12o8Aef#UPc^HUE_YW9Zs6{Zk+dve1 zWm@NE`^T3hh$qmsxtKOO0WA+_2-|>JS&V<<5!@hUuZQXY@ z$<6|7&Tpxz_k!2*oZYA6|5V&ETmQnqcbz$r?3glkzyoR%e-$d{uA(;()iS>IEpS%9 zMvw}hCouR-3hgGm<@8Z&G=1k^ZbKJN-$0;W9bhEj_9e!Zg@E{~{UoJ(QK+q5OOp?+ z+;rKA_c}M4o3J;CrouJIC@3kDr>`dDQ_~64sWuu06F^GPKL2(c!87;AYGp}s-FuRb zL@ts`uGNTQy(YggPFX*jF@;Am&@ZFPff$#Dzm*AVQU- z6ko|t%P$JXRouMy;4~cQtaIyT7Xt(TMD35eFl+ufN3nN_{Xd)!FdYLN!2hW*|=1ahGXzP2}gFqbvW_#!;m}~oQ%Mtwjzwvgk z@r2j^??}j&)*# zf`k4X%16eZ-w<`P)SZhR$pR0G8P;@4<{va-H)SN;bawzW!>mEi7cO4U0RGk=^OK7+ zfbrsx!ZEu=vM?|t0G9t_(=QiYeg0!&;i(Dt7u|<9hFc|9A!!N!u83S<+IKE-GU!K9 zm*6NL32|g)S5c@thDsk~2+uOEODxPe^w}V)cOLM#lDN9Td0XMUufj{KZ{i+Q*@q75 z==i2L>xFnQGNq+f&Nms_I|_9;2NN7i%UV|L!WGTl*aKG5H^|Rqbo6VM0+C}d$GY<2 zw3F>_+R?X#(egJtfa)2+d@oFSUP64(XnTYonW8WBOxFAPIJ7}IY}RqYKZLT`-XG@q zASFo{g4Ig}7YkbwgojDBo$?GeTBHZwZ7;9p-! zMmW~V9*8r}=Hy$P#&H@_z0zjORk@AJc7wtK9+(&gM#F#gg`Hp;2X~lniSP0+Sj-V; zofGa?IBa%p5NGdMe@r~h@Xbs@mff+jGPAJgA2D6&`r8tUKyHocH~X?*8|w^>7}8%*;@0&-!8D#SC^#H<`K3#QgGx2eaLw++v+dBeQ6s3SMy>m zyqYA^+Unah(3|d#Ld~Q@$1us4q@h7#%}b(lsq9EE9a7)HvB9E-t71H#sgnN3t~E$k zvU5U!m7VI@_01LGAPt2%s_Cih^$hx1u^&_>2(Lq^C?T919$WDv?}3f}8mmCgqrc#z zywFq}T$jROxgWi9LH48fxQHYV@WaVdZSZ*V;@|#>!G*n`11d>L=%=Wq|0N%jbfAxT zeNl>W3WZM>F#{}<9OzQvYK+BZD*_N?W+MDXSm*EY$l-X1OG+-)w=mx!1CuRD428tS z4YKaH7y9ztoB@WJ2X#be-4dIblaa5w&T!^oIJ=u!RHKF9p#`jn$5BFVPwJPAVB3G@3eeU#L&n zTHec0yCmGVun*C|@Q;0Im$?IPUAv~B?!;jZidHeJFx0g$cc2eVMddd{Q$yks)y6!V z#T(dCw-^|x5mpr%cFrDCJmux}+4&-aj0Kl{|JjOEjY01{nv@S8aFl)Mm|A>aECK*2 z|MY4=k}Et6dM*Y$Kc#}2=_5vFG@>Ml62f9V6J${#bQo#ZUN@2!i-?*POH>_V9hu@A&no657T07UlUX%Cq!gSU-_~*dZ_YAC`ix! zs38smNuB|GhWr=g*L){=t#^Qussrk3&EjS>=Ly6O_;nYwd+HzD3kyFW_=>6xevC_Q zcD=IwLXdYa;5_~*Om%R;%hu0d-OWv`<}_62%FT-<0sFcp^g>_wTeC<~{fUYUX}Yfb zW>tRw<18`x`@ElbrG4o=XEyEE*E@3-gFPLfP0&O)|v$EUp7ehQ-31ixSe^ zm&)xap5jHYo204_Ppis;g0e#uApN?5V8U4m4(Tw!dHwS4_-IXfJ$e^^#3jDDoiy7024itr`dI1cdu9utE~4zDAXREqNq2W~ zg4@AQ;<2+3P3e2CUvmxSx0UJxB)**kQI4?%ks0b&`f}lTLO7suFRuUY_$Fg}%%-p= zo~b3RxWo1fly^fYOSR2$uz_1-?Xp0GaI zaGzqy*{O%-YJ(>8jkK6AdQnk{xX)}~Zb`th=ZX;CiyLLTKhm?=A+G3m+^ekt87os( zq0htf{!U1V&}n&MDcSGmB<$VtbO*^ZeA0a)50y@SY|+u4!>CUjhn-EyA7VZ&56y_X z+OmxDXRB)ITpPEorcZml!#91#MwZ7@y#)}xe; z{<9lu7Mvi4kB^QHgL!=6Mn(t~Ur8A)OY1SFhhR}}VTUAr;E>%iSC!fX>R&*0JUqR+ z7=&Tz>AuzVfO2Ru8KhdX;@8hsNej=0n&e%i6K+hbsdmG;%Y4RQ3z6FKmidJKA=LM^ zBc^TA$bWGGf(Sx|9_OKhdE7S6wsm^_6cX;&&`Vel%KZU<7UPW}E9Q%h1DO-Hybc&S z=0C7UUJ`DSYXi1Qcom=T9iiZR|)Euwr62@qy%? zdIiWeB(uZF8ghoZdXw=F>2Etf(5-jw&KDHrkQOJo!(E0f+uU_Y*?;d9mB%Zn(ZR(V zHCIfVGO0qO-`B_5;u7bPNYwz<$-cU92CW)@J!3PojosZQpvyKos@UT=m@2T?}M!Ws6Hk**&Cn8 zSsaq#t=Uhdc)RLahq8tnGjP3&e1_WBhl##VBP#=qA?f-x;(TeqM@EMD)uy+j9_zMQ zRTnGQcVWra!1EF9B7yGLRs@vfHDTruixHMhidzP=R_F05 z2{@ui*}^}#KbygatH3hdjbJEjSAL!1v#J-Z+m~0v0OJ zP^1TuSbJLwj6OmL)hey0KD)>TP?M7z0g+Td&rJe+2k=I`4_J$Z*?ATUzW=j2?_X5B z$T!%R8HMfkTB_w%OknV>TWsDYH;yw3?rV@Rw z$cnp}S31?PlLE=x)E&nwa6#MwLt3D(xY**oI6VCB{d*U{Hn98Guo2K(7FxW4?|zEI{V!BG%T7mRvMd^Ajs}#)C*M9cmd!U{T`^) zb$53I&l;d92UrpL0G01oy61Z=-rYJMZ;SwIEk2jOKRY^%0drL;NBV6BAXze-ht>7= zc66))k-Ed3{qN7Q?gcHAfz_pEb#Ht7cd&X`PSECs5L~3@+q>{0%Y#BwGd3$Xriin0 zLvptYsN>d5u^{oiu|Mceh3XE_!xcm=YzGQ&)T?h(!mF?~ve&y0X@*cQ6OmpYsjQ0zk79$VLNx8sJA>1C>u; z>(YI6*xn8UZlT*}ZLfew67Q#__Ik%{Ft_%$wlsJ9+S=N_eft)lmY)aMMGkv&Gebi* zU}6G`Bp|N~=rU?RzYhdvJPvpkxzh0!VCn)=D)5PQ0W%i(l>wRJJ201@KKccuLctRd zhbeMZTabGE{RQUw{z4NW5s@^AyVb9g)l?aT)pIZWL?T;q=^)44U#wvYwm(?vb1?gF zF-7T&ErlOa@KZwVVhxeiXEJvmvLQ7w=5os)vbSk{d|$iHN#iEMjn1q)oeaBBV9LD% zm@%>C$H&3MNfc^>wO$u9F)IDbgAH<+;fC@|L;8ljM@LKEi!nzVDfUd8tR=7eEyyts zYU4k-*EG&G8Hs484GfOX&z21eM?`Veb;K45<=EG!hNl`ho46N_Sj+$o_JR#?8$Q z*gyqx^crmdGRvCWchO-BP7@dwM0DIu#LaDG2X=806(^q6q#r)BDA5*OS-oMetSIhg zb-10CgvNp`^8<(J;Mc3n!0uE$t{Qacm$axvVtr{B+I9 z#O<`XI=w28yUVHs0hIw;BFp}Mer9C`+3xH!rKiz@>dJ}4eSh-VhCKndG!x4K5Mts)aY^F zQ_2SRf+f05+`tVC_-loyq$~hp5Fq=|=yrkWED;zi7D50_wI^~EKym6r&MZaU3Z;%u zdY*>NEa`VrXN_{GNfs3BXUaO8a#Gpu3^t=!V3L}@k^)W4E1<*gNFqEL+KViZW`F%{ z2XpeRna-7S%QHaB15 z%IS)FzR!qpI8kiU(DT(8*+v~Bh6V5rR3 zD-N@I%<3mbRz%!em^Nzw@mb)crgl(p zb9L6x&|qq84CH#@bG7Awxen-ZQQE&2?_a6FCCnO7-f$VU-&@bs0#kUfo+~tlij!AV zRaKRhx!hbE`O>Ha0%SXF0Bs$}?{gV-zgqi>K?4l5fOd2FM_@#KB~qT$w~M7&y+buy9vb zvYqOE`xXkyWqbRhv^SfP$tFW7o?ztwrHX`XvIwkyoGYTMf$p>s5Q2fIGH}adW?_lQ zMMMBEM2mO5wLq~O@YtmjIb@Q8A-F>G%AW?lSE*rU-k_iuSxN~dZ?s|L)upm%g@+NG za&FEvJQJfdvJh$}&QqY<;{DDW^)B0zLOJS9e0LtSe`olsqV85lq#P$Br_PmSb!F4% z0?+Ex1(7eum~Nzx9AdYiWI-Jq<<_b{91-OE*-7(xM=Rb4z$!(S>VbQ`^aMwGL`6lV zV(6KfnIS_{I>kUa8|BFpz|A)S$5()n8p!-+bF~M6YEJ-iy1Kdxupz~6ij_W~qJpfX!zesv0bER7qS zc5i`mJvc0-I$zb&atG=)VDrffPV4|7W_R~1z*OyaRlWqwb0SXbIl%S=0_=orW^XK0 zI)HD&tMKyj@^9ZnK7RZSPGN!LD!mbL>9N`EO6Nk(H#;}c=LhHSCl+#qiQcRP$m|EQ zFGWZ;CaUf}WQg z3_m0tUvG9o@Uto)n(Cr!JZtqVp^zuK4QakNCf&7AH;Ew#hWNMR+6(k!fJ zV`PjD({Azso(&w@#7Y>nXE(}$V8_a`?C-dc5?>sU2l_vUMg9Gi)3swLJ%#BMO~DBf zH)|2!rgG6{>7%Q|H^>GyZr;K9z6Xq{0OOxD)f4z&)MZUebOb96%Q`*n%?_Wh3#NHZ zy25fPWn#U1e7!rfTs)ht&9JGhtkp{_TsphGlP`77N>IB^PV$4W#lAzkmkh;pI!Zj| z`ieyYPDB69DNTHgZ0(h*3=m(GFLx)J!txI&0I~)aDvJh6p0kStwO}whojGGjS$WuI z{o6RaoSQi~*G?11K1i~R`HQRfvN}b$VxX8%3PTO-gYUOd(%d+>)sx@`v-#cDa=*$F z?H8N|3#vT93m2CM_8R`d44wr#b&M2LA&s+d?&Up{#V5;_8eAzR9H%S}c7}rwujjff z@h%6nEeMBG)QdRRLyhMfFZZ})=ESv9YKt|MLisA8!8V8j?aBr43`>>V4rP58jhMyTqyEp zzG~}ife%nNTsWIRAB%`sYN3+qO??p=Xi6CWs8lbT{VThOoOLsG0%o+$KRi4w@%rc!Z@wX#5i??Rpj0Ed!l-B0+wR8ZI_HUzAl~z))_mJdo9p!;y+Ex?~dkw^-Gg49Z6M;j+Q1h2-rl}bVD1Q zknVZ|$UKKMsq9~(Kbe*&lijfz%9FZQZEb%G(LK>RQh&6xWrX1$0!L z+AQlLGs>v@j&19lF3<_F0wJIsp zR|us2D%HCT$3O4`^)@vF)4(4bN|vJ?EiUI1iw5b%yxSC(ptw95fT5;gB41%`CnEJ| zkB!e!#5%u@mQw- zm9fK>i8{<*Ty9Z)@n>smb8);3s@B;TN>v$^@eC)$p$4==z~(6a7cIbb+%Eo-kIVjL zW)V_C5N82#&_RnZKxVVXPcgBECCXm@YM=RUcXP&%GL*s|9s*>DrJ^v=bUffb#)7=> z>}in|g9>fnJMP>4!*F&Id54YBv7<<)_%0OOmi@%A#pwECubhWx{iEdJXZ_#t{8vY&A9d5S*x(y{etjwPGe%a8vNm&r$|Bqew;b@PuaO2 zvi;v*Dn{|7a&?W&RA}^_FCvbDg3f)O9$b0Vm`})-hzvn7pFe4>7+vBFD7{6HEh9U` z44c&qx*iBt0?>r}_aZCa#B>G{Sy1J;)-UQDm3eN(p-1BDPO*%M;D7?wR|>Cj3*?2BsdS6HuZmW zbd}Y#w#@Uk_{R%xRK!17jBekwtnh{5{FMy0+M)NnNeouox^Z3%`d>|S<6DQDk8$~h zezXJyUyxKClBU=!RTbtOj$R$B5la8`R1!bPlLDJ~(+%yM{A`d54>1EsiZ4fc5ysoY z$)GjX7+kgE=R7f1;pzABgiV>9eNK`v%KzdIo@bT@=peJt<9#N$pSwDWF{yoh()RJ? zadqEY+b7yqZp>0Ys~uhrTkp*$UPl;6kqYdW=GyKMXY1;2a(|6jn({ld-4~0-Tlus@ z?AbX~_17BrzgbY*{n88L>X4Lao&OqagA3LLjS`Tc%!&Yg2ZJD$eh?ve$28Ek_jY zc0dk^wyRvY^~^j#jDZD0_RtHk1X|IfKr%j5H%s}W-^?KO>c-ES}Hi~PH5WV*mSFm~nYMcR;y z&UYj!X869QvVKHW{@L!{%F-dYIlgYaj5(#P^Pj#xmQp>}a@OGG4KOjVf=+BN=npL1 z#Kf|>w3VEh4ls39-8vi(^>|G-H}QFtab8h?CV)!6HvFUYg>|2=7>t~nhO+O{ol5T& zR%%^dO3nE2i*dU9+*5e`@@2Byu^ex6%U{PN!&qI|xJ3_&$;VPfBA%|m?WpDfX>PC2 zvGKY+pAC%hvea1Z*+0MBieCaccghd_z_7(et*>|PU)BAdKoyc;ZmFd{8QmN$dKpCN zCFX?g1n1^kEH8;l6op-9d@a&~K)(ncR!5f@n!zmzr~h=6lqp){2EagjJMQ`e%y+Ve z!n{Y3IPao=LViC$S#GT1AIEQ|DRHG~z^Hr%^k@@g6D(J^#-$Xt2lbBtNdLewW)g*^c=z=K z|EwqxqckAxe>L zN~vJf4<5jQh3qgN{lxIGbx+pVRpG`fGMk8&KsP|(Wd8=%)T-vqlp;2-)@wVh` z2QWSIfj-2c%{xM=og%twq!>}l5V9`XbHjHmMj;bydxKzL-`PK}<(pU&eM$G|ff-;$ z3_skDhzw-OcwKp8-6S#Q8a|_kV+><9xsoE%FBx<+NnmL8uuIJB4WZ8JamL z%TLHfnLmlpA{SGeT3R2P0ZI?R#s3q8RCuRCO=+P1A5igE)v>jpD3x^U9UC0x^3kBo zd-`P+{-DMaozLm~#0nkq(40+_2g3^Y!Tf|hGyrSKyA68|+zB{54yqlF%z%?E5`YbJ zzqtQhHr*bO-~{pB(hCziZgcp27+$7|N){1*tD&WUMfze-Sm#?$+FsPnaY+=x-5zt0 zDA;Kk$f6O1#|k)J{@}e)o_5$ZTmmD2rQSkQECO(F0>^bNtl!ByR+?48BpsNL_{2y* z9{ktCT8yF#Y2AcXSDeU-FIHA;^HRokHj=nbFqkoK@A~Mn7Pfn&EIjjb%JDowg`K>e zy(GR&lr|SRc~*@lctFvBV^D2i=ldc|VGVCM%RDMUY|r}m#>HYb=6FF)EHXy6D|DJa(;P<$ zFWKdY=AjBbryyu~1}Kxtz)zP=>;gi2fhGzAIu_E=vVjIN9#NA?U&o2?;Ypi)6jh%d zi6&=+A9Z);`_3v{jt9I3T$5o2&?wdK4VG6xNKgZSpu5EfvnGcCVD7umew5=!V~;K; zjvME-GIhP21#_l$o-|J{n@c49>Yu*jrKb>uO3Lc_P{n*(@50P3FJ~c#L;DV0^^=>+ zA0RHaaDwT-;^yz>X<3s%!mFbX-Lf<-UK<-R!fE=$ojrqrvGix`@1j3)d?8G(-10$Y ztp#27&X3 ze`!nZ>A-vUV{j)EHJk(@Fsv2r*)G2l?d;qaDQUSfaW@o~GBjFPFQ^ZgA>r<hLW(kh1+ogUeyVpx|%^K+9^>{LDb+fWOvD#orW1%%a$-^mCD&H zDr#~=!V6I~G{>6@CDV)IT&(zXkRM>mx{^<4qD~WF!qAL=W1U59%(Lv_gEVV!HI9W2 zaWe6lmQFQQ#*ankbN&_{uh2Ak$vk>Hqpmc?IL;7P|0KLwvrl&wbR~~><{txuzxvH0 z`gk4==uVO}OIm?+yG3)~0EkYa>M~GR4;`<|JVa<)_RcSsSxU~m1`$L79;4yb>?-yN z-247}K{Z^h*oL-OCFwb<2gs=I;Qit)Eh|9B0E`qz49Zo&iTKYPexI}fTLHX&{HNOD z|CZu~3IkwJXvTfz3Srkjb^czMa|QDJUlPEI0IzN^-QU*FubXu#|K`|p4L|MPZM=_dLsNVz(_jPt{) z1aa~L2QJ!Y7LOgDB2n0%BYpEFfO#_b^3T$m%oW}5y|OvcDh$lS|=GW;PwH5Dh|BSu^PB z?|gr5qo}wx5RWxpS1GLJb-po@N+0wwd;yMvtJv1Y3&n>QY7*XG+o|>9lCTmkjS*Wbcp&Qn8}5p@V~eKAtA}h zNyr*=R+ry`psS;DESc;mO3i?ixAg5zMh7ZxmCdYb@{Iy}{tf%PcV#s-)_>N|M*K)Q z4i5`{p&XE=*-f1D$U0B_Nr0&<2YhdD_qUvKJKO02$G^@NPfkv5uCJpiK7pPhcoMil z6t|JZKv1|`>KlrQiHRaA0|UeA{?89>z6UOik>1z(W@glPg`eNb!HrBz7NzS7X#_$$=L?$J*L@ zdjtIe78$wNSZ8-)0W(@D+8k?e+RUg(5%&C&fGq;9wCUu2ESNgrHueLV5E-aGNU{+Sr)5dI|kn@Vpw-sV%dbD7YU#%Q3M!ViBDQG!>6mj-%^jV*Y2G z0s`IxmnY8q^RrcsmLCgM0nS%F_g)guB29LZd{9HVc_%4p*85Hd23m}i8TNRLufosi zT260W{|f5qd5?F8!>|bn`__;AJpO*Ej#k-4@TTdty#4lUd)ZqoIy{%7#%ghJ)oy-% zPFSrZ%A>b+&f~B>K!pEXkQ}pEtED-wR=v(sMCVIMWm#Dq4yM7!kMi2u9-Ndpr-ZOg zVTOtLg!Yz)t8`3ErX(Ain-B#JSFRrC_oZNR0EEj_F3G>~)AD&wBlG^9B622TG;D^dt|HFY)igPtg+_vJ}}t+`O`QEmpPZ{ z-6VY4mW#L1bG9aEZOAl+b$>m6xob$T(dD$&htp=^H9mf|*@6dn7AYhoIEbW_@J}mY z0tS1F>n5i5!NI^u?eb)EtjSWX$C36XxcTaImbm4*wdhUZgB2s75i^=5By3;+AP!;T zLgnmiEk#AUwYj=PgmshaQBKkjqP*tRe6CimRJZu?te5HkmB8oMLJ@Z~ggGaBDSB;$(`vHREt*267<^=Js(Kp;}Z%#3ef%; zt36mx^>jMlP~cA$FqnSFkvKrV{+bX=LCj>W(FavYQHh~{Ao2VhxN|lFhq=37-#9Zf zK%^GEzixKlU&!nVt*fs+cX7|n%FZ{%V=F`={co>q!o^osHZ~SBM6l?)H)xUrH{`@(0a$?Pq ziIn~UtMXhQtXv;LSdBn|S)y90-Up!hb+*v78ia>1ThO+vp6&|6W6)C7*529pJ)G`& zb$xx^C6~hMalD}`E!_c^^aRi)dqMpJ?AGN2fAKrdR{1=`2}vor)D|-Z3(W*(zp)~7 zB`mDS{-PoPk&-CQOwjcNI z?Jblf4B>UO*1bLD4Qxdxk2fO{0d#9Rn4(i|B=J%3!I9m`&eu`859tZ{H5^Mz%K>=- zVRATx=3C1mFtGSwZ%{x~E)F2!PLnt^>Y68&CD;aLX6MU0Gm#>~r@M=btwTcyjY{B? z$1sbioY}d*KMEVLd|mWLR}0*XgF!Xv`PJs<4LB<&^^OhBJFmPIc}Z*lJ?zt`gW`v-t+o!Q{wG1AhBGB8aE_{M;kS ztm?%Gkn5JRr7Ts8506eLGC+XD+pkknQplvT2l+c$%`B~~z+k0Vm^lMUuDh2fkTze5 zP=X9fiu__qM|%2#yh}Q3y>EUcVxG5Lk=Oy^dU|(-Bbj72b1tt5`=V@i5iJHM7Wov! zvk1NSHo6R)?%Sukwdd!Q{QQeyq)dBMer@p_u7}_JFvy@}U17v@Cw#{TA4r++SO7B8 zp!#$|CDhK6l8GtIzkt907cXFYftQ7mk@A&Tw6Lh7Xke@=Uuj_==@SUx>m_kJNnhs% z1@*1$w_xZXtS1uK_0!YoR7)8d7;Y~6n7|+wo+B|(&@jE}utxm#+e*a5D5Sj6(#@b2eNy}5upUb82RU#@a7fX^A zooZfiA24uT9u367c*l9Q5NqM-!^1-bI3dxyf0F3Y+Mm>#3lw%#*#y|?A~bkUr-45(1S~O2-z6dg1A}It zp!9MV3T^Syg1F>+e|~mzMau6+erw?MnotVH*Wf&Lwcj)2>2`Jt#&f)ijWHG|OkVAC zM4#cSyzD|hJq=nLFf4f>UuCG$;J!}+IoTS?T)Lv^G$=>GAgTrVjdgv{M>@Whp4an~ z9)h+pB`3F6muDeXL5b0%Ab~}ueFrb>yjzx#x!7D<5{6Bxsw%2oG2i*wR#s-~h9+Pu zX~}F!s~g>-(xmMlJb+Wr#+}#&PBAT^^T2phY zh;G#sG-Ueb-6Fp_Qrtab_S%_tKifAoG11h}98BQXnKTQG%*-6e1OPVF4Zw~r&tv;2 zpa*e3;+Xvm;l|OCiC3pBi{6sg!R_|QdjhJK2K(6&D*6k|yRrKL>g(@?LOIo@3e>je zE7xtVPDNp2URM)ppzHz`s%oV=V^dT6v$j<{Xc@N$#8Wl*)|pUt&T z$NBHbSS_XHR$Y#h$fw zg!k6wrpkeoxQ22vb_Wu}y&$S_dV2N>d9po}B2a3OY|5kyO1rOA8ddfWDp0U#85}30 zUjV{%dp5y}C|3u+S5kDeDD0_^4^4i4-~zt*p*L;LH0@1lp#d@N8EZt+n5^oyos+ai za7c*z*^cX0e|$@cHa@pe_v&9;lCUX;_v$oQ3OyMqS=3G&G6P2$MWuB}@3VAD<9tt< zEpYh)fCSAoGdpun0KURY^~~99HuHVYG%40l1NXk!MH~kQ`-PEI7wvrA030b$+lw!~ zN4Gc2%*ujU$gD+eai=xMPF^+UY0q$RS+=&qpbDwFO}F(P7rE?~HP&dr@uG^q`*E}B9>unogyOe zl+kxV5p$Z%BjwT{?{9tG!`aul|%O*|b_%Xo@ zr(@75qN9O^Qv+;#uCehgsmCi|T{}d=$5L6*%3)pPV7%59uwn_mDnR_OOS*4uAb^?| zDtx{ewhvZm*!a&Gjg&Tvf;{PL2k9cmk8dD4&2G^{>uOCoK|xX<1qCfMktvJba+0#A z7Sm;;L4Hx$=;K+!@{tA>g%ZU71ih>#{^o1J+~OV)5kZcJ^6aUrn@d(!R*^1(k&5cW zA&s>YhdpDlSl*x4RdzBd??*b3+;5pb4TcFcyWMCuHkRd?&4vV%XkA&B49K>W|X)`oK zV!5lKu6`jfl>gJELr1h+3fIwf2kJrUhfrcEX~~N68gwwJn09c9fXG#HM8YMoXkLO! zi%ZXWZ@hw_-E5G#x@8CUDob{?*E{U(?5)K_L{vE4xb>7@FD)&BQc|***Jbz(l-q6R zH3W^|T^fh`TPkqtlkfk1xR`$FLi%9C1wJsT#pM&ISL`1h*4i`!o`*&w;C@p`WdNNh zJgnu3vh;6Fo?NM^V7Q`^tc=Yy&O%%B{HvoU>hGz{>IW>0dsq2NIy%}!JG()FLCbng zOGg(#85ayrbiI)msM^C)dAUHn-+yyuT~Y#Kw8v&4n1IU;RJ=F{rtM{=vArJ3LPIMK z!fc9`#nauZ<@1BUzAI4Dm&%bs-TrQjd=c>jTC!eoe2Mt)!LCAJFrL-1Gg$9z=fHAO z`Y=$LkFQCW&rLd&Z?;7g6^NIftCeD6Vxgg-nGVIhb@c?*)WxUM9UrM!5sy%q1wBCm{jC>$|A@v}v2~^Yd#$1qDP#W_?bgh^taWuakk!y|v#l(NLCh&bQ1yD8?IIEpa4md-dgC?}r2x0M zch*UXh1;N(Cl&CtFf#)S_Z5>^=&{ALyv5bP&28^82;RPAw%_`Duu zo{Y>^KUa`ly{4i;>W^V+8k*{gNIt4&Ps`LFe>KE>FL_WNob)9(j2CmF5eaK(MDsQ* zQEg2ouF?KM=S)kMP323BOq?x|A)I?jPz8fqRFn|=?pa%1`_x_By?7y9JJ)uXj5reh zbTHB?EXCLKj)zCa5u-{;_cFvZ+;9eEjo~Vpg)Jt9j-B6aaJF4Zb?}!={m!uXnIKg) zT;%c9*vwIt37=2N^^g*$%}6$#k%<_q2-`T9d^D)a4XI>7eX!rrzOlU>hR>%t#&;R^ zY|3n69bgcaZ9SbDmovpm8<(lr!{64fO9BSJSWstEZX>&)5Qgd+r;#ZPCYp=Xc4;V= z@Sm5AvHq&l)9)*161IuW$fR=LJS&xZvih`ipFYZsmWurvzC=^=MYN4WihY!GSRbn^ z@*Cfcr{7@8owL5z!{S*%7;sSh<7b(C#KCg~3ULe)eyf$$YO`C9{6qrFByY8?1AH93 z;ZTiHIUqJ%awn04%f_LM#rHT`K~iS2Ivg+srp9JJT3(rpb+#rY?R9oCUS7i3{Q3s4 z|G7+vds%8Vsqw)1j;n5y({8NPwE42_*EW{P+ZOu$lX+3t3jW{B^zvi0oCgK^7Q&UL z!~JztyQV;hkZ32spTjC=$7*Z*%O$OM0erP}2EqR7_kQW>{%oGl@oxe?|Fpl~#+Pq+ z&wT2tEYTq&u~I!^m%jsXM-IqQfz%0MIy0H0n zA|e9K)wQx#8>(q;x$XaW_)TKAAr*K=Pgi|P_Xeplb~s~eCDxD87zk@LGB!)TFeaW8 zb8!zRyC1iF1Ckk#k(K?P$(;Jwhk24gAGf$7Bo|17Z?AYolgU}>2pT}>Jcg^7wq?Yp zETCvDuUU2xPNTJ^lRyG`o-6i7d}DBT3=ZOskp=$5lt?f@8^#=BK!SB%Fh`@eDSL=vdQ3 za1`p&8jM!@MATUf@-*{J#~$mm6Db|^Ak)C0I~oQGXtTIOeV+K({KNT=o6{rXIb5L8 zx#L@mXI{@EPX*J>U1#$5fAXjvH-B^C!7E7hhOq7}3})qdX=3bXDRQG~+GbEA_%o^C z{bcJ`(JFc>s{9J``iEIYEf(9lMUXA#3McqdIxQ8#F*zJ2GwWl8sr&DqN2HhfmYKy>>M1hs&3?^okR~B$v)!i*V6t0m3g=0 zMQ_rJ<*=!M0MNGs{gxw>=)pd2r`GSBG&D;BfYMu3T|;du-wnT?IgQzgQC9qs*k zjnm`pE9(qeJG9cUMj#^%j=sYaIi&C;hXRUCN)2OTV(sACS8h+PsWA^(moS>^Sz9y^ ze6Sabb4@7nTsWJOtKHZT2}rn+`Nf`c$ARJI>7v6ODYv69zw-8G*`ZpjvOY*%S{fSc zCkOa!A3uBd#o$cIiA(c-+8WQCo#J=lO#&Sc2a_$QN(I0^ z>R);{*pzUbp6<=%E5!~bpPVduYM}uY1nD`^e-cO(Rm{MQ3UcvG{!K^`NlCh$ zoz|DMbK77S+~<86;E#NQf}Eay6<)WsOalScp}K|!1c*)RA0~3DmFR}}2Pd(6x=k_a zj1Rk2Yd%9c-5y(S)$@h}#^uaXM}!=Z&D{U%{|~FuSpK4SY5GD_WU|Lwo{O)|;nk+w zKCqQF0angkO)nD%vFo>8VyP-uhnm8x%92#HA9Ch+k!1n?)J8AvaYlT?v7%QAT(MpY zqQuDX%mfp+QX$6x)Xcm*>WhIyP+)LoWHjTmu0@6k#Axr9_5p41dD>V11apDPT#c2r z5_G$Ahf=`C#^Wy4o1;jF&J@Gm&Q7&R_vX9@3(CUEYH#ldfQH|8b(}Wy^{(5K`&Vav z#kz1fT<4poT1J>J+VX)5)!lj9@Nn4{dv&9=O=|kAY4_aPe12f+Q0CR2s zRiOj|PDRCHrRq#f1G4@aVlcGFcm%I!UO}`Lv-D?;he|vnuRj(?+pCd9qR{R>p#6Z$ zP?}Uwv?yNZdJiBzy=y3w*>*k)Mn}tZv`CmLL7AY?c1T18P=hfG5Ux|no z2FfB*!pmJ}Ilc(KyN;9-dr8>oD&Vi!x;$U!&dJCqJ6HqGUgQkLN2a9gt!;7dCE9>E zs93uLcIFvnqff%3PYH+<9LiB5y8Y7AR(t2P%X z37YukgVI^o$H!tdRb%7x&AX#$e0_Z%efhm`bG5XJ$jrR(@B(!;bLIzoa&!c~{rg`+ zLV98NWb3Dh>uY<^eQ!wAnoeMcYa&b}h+a6_Ib83}+O!Fa3>YuwI|{aViJ)LiPE|0O z6c>Z}oaVvk_!>rxa??;I`tIaB*hMsYj#X1sK5|PfF=4!fFFzac=vUH?70|`=exMmq zm!cb2yz3tvEXu{jx3I{n8F1_T_xJ6$XYpNx2&Ammo{BeJQ79D1xKfk~&ISfi?<%h!AZ62{pIF?gxE2~!-R;D)8sgw)L87|Yy$>CHlRJht-?o`f>j2x8eR@+Ps zHYkumEzXv;7SwA^t7f980mpk1=dH4qk9)Hm|m%iGl=tYt`OAhRI!n}7==P>BdyFMYxzi(;mw31C4GfT z%^I^20BIv^7CT$qCen3y4xT@RwJ#s2`uYMy7lW8(Wt-XX`1shLnvvfN3>#R=PT-SP zVCwx}zybuIwSnOuv9hCi-3?& zE|F!m>nZB#-s}e$F^|K>LUAH!^*Nx3)f5W^7Z^OHTmKE(xdkPU^N5Ixi3TDnISTR^ zeaI=OOpT1nW_BhYK3wtva|r+xsga31UWY5P#N1V83*h`{CTKdpAoetrC9_;wR;mnD z0V9k3KLIYz>#1y~r`9{Wo;&BC_*3s@%JdI`Lc7Ym=JZI3pGxs?0S|FOhqiuR5ABBA zze%@R31(y@D=T{s=(LbR53R?|R{S9_haJ$6V7fTZ412VA_gH@8s<|wW`f@Nin@$y! zjbPXQS+&@IV{&&E?AbvWHj@hIdJsJO7dEH>$2P!c3JHC=E}XdYjLZc@A?hHy+mVBRCek=8a`I}=b*1|&qUi$6<`9d4rQ~m*pqfZkEiwal zuBqvEf~=O&LdeGRdv5qcP;r@>?axY*W{3Lv$e?t6FP?2%3XOavI=NWyN3cLPx3|67 z-Pj;}!6C)JetL+WWv?T8aUuts`k$Ivt>@Z zeYLgj%*^+A@4=z5lkDJpTwDV)^S5Vc37{#_xJ%>cB_N7gVR&^KQ3x0c_yhzXo{wC3 zm$%TjR0?m$87wMZ)ayq66SVbn)h-}!=>n^hC=@{TvetXEFYdmRd(-xa@IH+G^5q`C zw-;#no%V)|jBIVD3YbtJL4E;E9y(91qeQX635&5IfG!o!BCr7O!owEyc==lH7E0h+ zR3W;LiU#Dl4DyI**z?eQ-ub-63;=Cf%*cq|zP>5=^s5@TYS4b{h>j;S=wAk@*z*}W z3?QB0BYvtDBN3J#VCmbFI5;=~Q;6znoK$%mb90IPQYm>{pBE7w1~V!ynbI=Sfbjr6 z&hnx|yL1beUE`@vDQGD; zb>`%}P%D%X0Es&#F&1yU?&!SS@WSI3fQ zg)x}cg;T||wbnWl`*pc~UDx2WxpXQC9;r7OZQz9gD8wR}4sJmZnm|)FwZ%o@ zia&@(`3F6&l%tCB|8b?(#gUZEc+bCeEw8SvLKHd{U-cT>n0|nf?Ct4!s7@q{uV@!{ zmMk{9-mJ->q6UE;DAow4o~PsbLesM_lH>+keE@(Km?=!9+r7?93LMuU1U;oA?{odp zDsup8GWz+Q?afqfooLXCOHHSkgk>ffv? zFaFmsYX8naXGr9v$^e!58p3Bfn@-I??@MK6LGGc=SUo!gz!Wjj(Gy|Mo$fjvNjTTABODbS?6rFb~tka>f zC_$6M2>Wt#3EZx~J-hJWuav(|%ZM6RhE^2Y+J6rO%h*?LM`#AaYz+<$o?882U+w#~ zSGh^b%0K!88o%B(|EVz3nlE_xzXE!g;r%oc$xXq20!q{N%ma{;uP}%KzmwE6YYY9! zf781@-K;dl(JVFrw3L+C*r{y$bwTsm^W) z82~g`Sy-9;{8*(zlmDMtY)tz4YR2#HtW1p+TZQD_A6V!NoZRowh}dV{<3G#d;>ClC znwFNpg;2m8I;mafvawMaaC0|s*$6im_tW>Qy0|7uN_cyDO-g@S6|o&svc5Wy_~P?& zzpwH(H|!K0OFw6>mLfbL8(PYKBj?*AR&Ft!NTJf#*Y?hkSl`Ag`{wQGpMR!InX=?b zinjM@em1@-^;@Mn_SF4#3z@QX>C^9zk9*sietW(C{jno=>OVMq%A2~&L)3Z3iaEam zEU!*5Y+3p5)`l%x{ycfy|NZU#`VS{20>_Pky;N@2CTZY8lO2_pfg7$5-@SY0%$fxY z9smzVP~G!?d--vl+?GO_|kQ^t0lh<5cP0-oO##G8FoActs4S_A>$h*(v~T0a`95`>$Md&s`LXBTMTdlxiiopb&u`zon?G&3eO~U{V@We} zzTJMf@bt@)-FF`boLHZEb>A8-dw;)s>(+58Dj6H+iqDIAT3`|9rnI@Z`2F>3ay)#e zT4lc~)jJEnwsW4pO81o3(aqUYzB(7VC{GHWd1k6aWz26qo#{WKHUAlhzuGJ)C;xxL z&Y7p5+U4fkbFv*?cwz3oeScFvWov!?`vQ24+>N*2)}8a4e_fh~<=wAUKYl-X_aY)H z!UI@`-@EB4FO#zAX41xr)qDRgy#GHV1LVBC&Dkyr^L>5(*xBCgJ^HA#WzU_THCeA7 z9mu(LN6SG?dqas@{*|Y4OQlZogi55kA3xS2pp`DR+eor9;QL1T(223@r(g1(9Q;p> zYl7Hng>Zw}QpTG8;g*{%ZdR8$*v$^DR9m|-Eii3k$N|Y-uZ<^HymY@*ba#UGjP^60 zD;tcZramf7o_QL0K7O}WbjUTa9=H5M98b8O1xD>$vB|Zxcj3Y{hMP53o>9FIJUVWx zf!860X)`0IcmPiZtddYoWYIngS{UhI*accv`eG4i!$5-`ZjSIpcyY+dsM*B=T3!?JAJR;OXk;vd$@?2>@8XpPm2! literal 80048 zcmb5W1yq$$*EM<&1e8Xkq(SMDZt3oB5RmR}1PMX9L`u4(yGy#eySuyY#`piee~kOb zxc335ix|<3T0q*L-;-+&*g$&klu~T(L8*$m$M!z)ajHq4&|0O9v zgl`}0FX?yl^2SR-g~itUg1vm_wJ_z0KX}SLgxcG+#f`u(k3nSUwQlDsAkbE6K6QF} zT2@|;q|;PfTwGo4EF>hPrG*#R&ggOjPy9`;SWu5n=*#y0OgSSXBS~a8jN>c+HheB8 zArX;Zzv;fA3UnvwgEws5-<(B8Mq&uNeoU~fszSrWB#_E(HK$a_D`H{&Fg}ivuLQ%N z#N+NXnkf!j{F3+^>aH*Y7Reb&q}U5+Xkn6(7rfrle$b}tyUY-CYU(SAEP*rzTH1lx z+1c*5B;YceebdcOXuC3YcIt=DO&5HTMZxIjH*Q8IMPnX-=S|GX2yp7-iqwi6Q;|;4G*DL6ZwwVig}PXPNyfq*8Ik zqbkbFLxO|dj+ehi=JyQ@yodk1*`FXnMfm*YZYgZN+GWKY8CQ3A^X7`OvR$u)+i@{@ zC2ehO6%`c^kNeRqN!b)`(;s!0M@zC(YMPqn1_lN{sBWoTca+2QEM%)+JfG+G<0rcF z%gf8Ft0ONC?E*$-W+ft2Az@*h43gk<@JT+?(af{0AwoVcZcffw?8n#Rwetx~#wtom z72Zw4q?%$95_Qf;i&(lID?2-`%Pn86Jh^TO3;4@pqvnGpM`GjC-)?-*&T|M?+EtQU zc6#!C!^Y zYBTGQkPyvktAzlhcZ+U&h1=WP69uZ|WMp_8cI&GhA-BxS^R@Qvfhcg0;B;{07Zi+* zjWK=vC`2++X4E&!u~ZjHyFXWL{Wl0rFaR-u$NkbD0ZYS!bDY=LwC79{9&&mr6rI&B z_z?#}LAje#$7wL-4{q^-aY4H|LdUX*!}2Q(|30|JN}E6Aw;Y9qrDd^BBQ84n3&`E& z!CZx@qL~?$=UkKL-R3}IjzXRqjmp{DLcMdfm!l-=-&kr@4^K}PTxnt9j_+^CS*_+> zu8&u8b948miUR`!$v=Du2ncx5a=1_*Poqu}-4hiZ?U-U*J~Qxc##bWi^!V6iEtKu~ zxnp8tmY0|5o31}^^u{jSI9;&CvRNBO38{Bb<+b$(UOjZ`oXQteEEL<{6AxlABUVdcKm5r@>Gt^=Q%)#eU zm;39JtgNgTU-epipx{sl{%TEAI>e`uIhJ4kXyBIjqO5Com}cSYHiVQ6PC5xXUeMNZ ztLEYT{ftxf8U#cx3ezXLaX4|_)3#sfxs&*zx8~H}%VsPf(^Zy<<>lpnts9ZkbsE|Kaa?ZGzRGY<{jdWVZVHPL8k zZXVGF)_vMzi_o5iyNioWtybL6D2=|`MF9)2*$ z=f>%e0+=C{dab_G)6)lY)skdU*Vor?sa3EWF!}hJ!3Z`#-tLi!^FCg$U0htSSuZ9r z8i;@gQ#U(V?}?VkD!Z|p)X~u~=nCVpS#GIw+^ZX&xmoTWrt`{g8kF-4JeOSO;3j}@ zcWlf?W{PFiEly+W>!*1WkN&WBX*zqAZ4{sQ^*MNTvghEe&o&1DxKdDT_mHQ0Jl<@D zGRs*5APB*v)u?wm@PUFRAt7mcdUSXDzz=Sr%=_sP#3d$zdh_*a$j;8rxdV=&+H6yM z5f9yniC11RVgF};8+J&`hoA&*0`8=gKYXUMDkpj0%YIl>8f_5>fdRPnIUE!facg@N z@U%&4!z17K9~=^0B#$l1|KqVVcsLO#|5zk&QVfUkN9>~@Ma6iAcYI2?mWK=c!~349 z6{N7L(*(&9mt?b70KvxH_34<=`uz{annVw0Iaw4XC9HZkIO#2&?SAETE&iajBSsn{ z2J`Cm(moA`l7lm9lw!x=(1&79p76@T9Z@*0vi?Sag|-4)ecE5^XR%Tk72RfJrcbMh zSCdKxrD_4Wng)TB?M?|QCsy1&Mv?q@Rn2$|vga0>RL0Rm=<_HNy&2%*f56N#i!eGE zb?uSc8^_Bpfc9}d*vCA*85nvhl;b{GZrun7P^hdEHna%oizzSL_jH_bXL)J)cie`!EeN1nUJ)*ztEBWZC^4FN$#pUR;kF3}fR&-)fqL z6H#Iz6np;F{u|$pH5Bz-?hQQeZF91@+sI%HmZ%E)zd0mEI7kSr1#d$6KOJHOsDlw~F)iJZZKGlE|OzU{pa>E;@(XP#8xqR4@ z;z(Rq<(y75Cre(ttC2IA+1s_>^1Zud&Bc9>MK?8qxII-HH^Q1X{T;T?5ADXaPcPJ| z5bqvj#M6!K`7K+t%;lcA@7FD|dU(H;=`Pp(1*Q5X@;=w|g$ne&({OeS9{j1qk;i6p z%4HLbz4h&Jv;NTC)z`T%nZ}G_#*2k%kGTa(6*1y|2Xln;7HruDI|3B@Z^baf`3!5% z#_jLZs5LI}dkfw>R|k2A#uy#`R=VJs5O~HJbHGK$-;#wCi*n9?-$4b#NAFvUnpSj2 zj*qNfM2+ti@IQZfNTTimw$%TOnG+Z@*8~Rr7Z8j*rR+a3MOFaD7bw?99Im_Ff}b+m z|7ibvV*+ize|JL(fUcUc8>8HMzoNm3iOM@+9;v{s8^O38vB111*PqDm>U6O{j2o&w zpY|0B3Y<@2Wu=+oL@w;KhGs$GERh&yD&M*C7UkBgOrY%N=UFhcvUv~yvoJ}&kNaH+ z9UGeh{X6FIO(GuNj|UViq?Xy<-bRHyISMIB$?~eI!|Q}Wm9&U)BX8CChei=fbKCFh z(jrMS$AdK$P5I?tm~UeXLmlDYYwcD)lCOsOgr5;YYkO*D?_AN@!PN3{9S5!tl9BNJ*vT;zfw_`W7|g8)a3O(s+ifi7)X1%i87ti7)`a*|z!rfuJ7z9!sNf zC-i@woCuCqEfWz2tV?QKVatWa#JW$rN)>Fz|H^7_{C8CxyiI{`{ql;ONwX@P^WXm6U@IWX-5!w^ zb77+^ijG%J?f))C^!)k5NAbYN5RI(%;90I$|2Y8+IDs2nl%+Y(J`&GpT0@QoxUt;o zcC8>e>vU1hAAkBD3I5?69k?aAqp=v|ocqqR@R3MlYj59w(Ter_RMjLLPLu5_AkOAD z-u9uHC_<%8^rvEsjqr@Q&f%_@jag-}-*pIex3Xb8PSrp*R7S zq&4}iPphM7hWnMEpa&$+1twGOc4fp(sOq;0N_B>uP6zm+x zvgAj*=Aq=PGI$SXF3*3L8xM8<{Tn1i@@D)!#%n+Y(Qt4~ee2xfM09BTW|iaJBNSLF zYW|iuY~FO)z&#SSE}x6d0XRs2?)U!!V^4hW|0_-DKr~&SDEpJ_SR43nXw0C%j?$_H z4?+J<#=sy)hEBVD#>T;p?f%;jR?pICLnlv(0wX&sOI=g*U9Et9TBK@EnUnrMsKg7S z7uq!Hi=!opr1;q`&frA>13@QhZ6*HMj`m$hv&w?e%YV~%eOePmckSZ_&Crn%{u;6( zFBKP0E!`F*44`0|SI2Sj7V2&opb7{OmDyYX!IY)8NzcID zfU?<`(6auglY1;%xIt#IC1QTm1$vkZ#_Pe?#O1yZ0Ej3sUPG{3za*9^)N$7BdgW#` zwTDW32LAH8ec%U-2)YaF7aE=}JW74cf9FDaQ~pl#`h)xu3)8FU?W6u%%|UxS(L@*0 z2X-gAc=0v|@#o(2UKdRSl?D^}%0AxPs2`c8b%RiEyZAf<{W4w!2%kyr!rEH)29)WN zPi^3hmmkULI5pC_r`l=+gC%!->qSRHN%=i2>~KegXgo0j6M2$!ky(s0Ceunq<;k)l z4uHc)GIWTB^-D&Ocx6n^Hqc>)yhTU1yE)z1WLw|ZcvyORNX^I~6_1*noNR4v1?=8B zr)76{mu<;otg9=q$52B}?fT|sAdxM6u`9i*%IRpa5fYJ*V0x^7G%MTsr92RY@NrC* z52woGn_Gm=4#Sn)-A=?PMZu#+p}a)syc$49*kNYEoAErw#l^+ha*)1t7X2)e&lm~n zSS@aTbnE$WRlqR4Gc&zL#*d(|(I)f;y8ym`sisj~0 zMXqO?vGMUB>6)y*5S%)DaAE656L}5+0rknjx_QE1;ao~=LFUnGgoElSBa=0P zj@t6lt6Z08xDCoxzL~n2Jv58xgQ1tJAJ3Bvcam{sg!9h;X&KesV zjXox%oSauq=}1aRHF(_Eonhq0CM4jXq7DzF4On`H{7QY+49dztwwF>|Y&~VRV{j&e zyg2)$`j|=|*ahPXv-gBC$i-;2|R@0U}5=46oMZ`CeEa91{~0 zfZF5W;E+U`%#<0;7L1IHd`#Hi9?7uZ><7b(1etGeeFG`duD{%f*WIO&D^xN5@&#Zq z82juei_A%4gt(2QVJs*j;TQ{FhZ>)u)S<1R&69xA8PnIo9*!686BC^UMSP^RcsmXz zEG|t&4%cae4q~Plb4xZ`_IHn3Y+&ne{Iy70&0cUYO%DJ0S%JW!gMs)9=$o6ngGY^s zK!r?KTQ6lxCxRSpXAUIUAW`CumFW0f`il^(*Mb0-Z2zWMq)TL8iJpc#fErlLOrXWWI-g$CB$7ewIR>XKaJbia;Hs#Y5G6 zcXzj3!NkVKMuBRv*X>Tu)zMP1x8yCiWqewk=`Av0bqNHr({790?IMOCnuul#xR%CE z)A;9NZbwhk5IJ~=qKM|5+DaJ<;H=r4Co+L#gth9%q8X1#Nl7p-zJ4OQzCRnXx3{0e z4W>hdS1H!<+!@VU@_uTpslkS94kl}!Mu3%4P*9MZtQ}%xH7g3&WI0!b&*`u|oFJ-Fq#!6@<3*b57~9k4*#j&RcUTJI=#anng;{%9<$1x zN{z$}V44?$?+^9K z)%B+P3($b>4#u~Px>~+Mzr)4-``I?o`I4}(9%!;Udj6fO%CFM+` zdv$$%eNGXhr2(J&pZ246FO>IZ`Y8L>JI!7fT}Sx5qi~r)QHnx+TzJmYX~(Odkv@fr zC}ydIuiJznz@UYPsZDg#$#^>LTDvTM+?CDEDgb{MdsFn7Sa?0fX@jg1c#rei>4T%25!k&$7unhy#OU#hXq5F`6sss=Q$;)YX+ zJ;a6} z9HWmd5}DDg_)fJjw+oDgB85$ba^Gy&lVp$`YohFLBnFKjC0ny_uLOO01bzL9398!Y zs`CjIl*m+dbu+BCe^1S~e_ZOK;>ocJGSvX`qZlE~;7cZ?hg*cK*~hj5$Nu8{+l9~8 z{B6th#t&F^oP_GoL}MmpF})88J6;JiJ_Ed)tEfavh4dU}+P?m+t!=|Z z`avxkzrEXU2_@ocC8I81%9(i{PRjj2*pQ!)5H(;!NFYxN{}F-HmO^WYS#cEE{O!r9 z78Ska7g;-d5(9EqY|p%w;+c%{#HCd~MS84whw-RvsyH7KH$Thk_j17OvgQ6aq(yTl}Dsbpv8nr#tu>%)c6;{MeN zA=XoroGD7YEsNA@*y#H>=<8?}1~bK5HQP6bYB}oyI^&7oA6Do|e2IV_oZ_BC{=^LQNHMp@zaMlN7u6cL%(zE)~QIO&39$gOlZ~d;shG7~RgH(M| zXz$;@U98hgn$0z<#bP+{Qf__7_g!-ii-OrXV5bnnMkhhUSwZ`|R>4tHSq$}%_$aJ!DS zxBD$>jA7G($UR*bKNHt@`|rrh%liQT7oOM;Bk zamWmU^tMr3hh6p0V$F<1c9z8b#e32%&V7FGBd!r5-?aM$LKAkyp4!NCC*6-*SP%Zm9I^fGD8AT)shAffzIpw`~EvBbtgey8VZgnp3B z17bAPbKb%hV#KJ{z95S1On75=O>Gy;ebBm)+4k2^-Y$+^FiXC&NmtPHqa+h}A(I^% zMD;^jBZ&0Hf{aam?=i5xnVPW@&r*Q$(ep5rW&4W(vqp-5e3Z>s#;8?e^EI8KIDtMv zwwqO&NCX}Sq_l=Y16&B93!*jEGi{sPQHZNHaq60~Yj#L#F9UmCoggBeAinf*6ZSMa zIUti)2&SN{-%kk`Ee)!Z$f&y`x;XS3KeF2Y!Zh=>s2wcS)|50TUt%frr)?+*U}+E^ zj&q9y$OGd}xCP>ucV#=DXd=bj>WJaf!dB?X4QXZv1q{gBWTX`sG3XNSrdxu#U_~H4 z74mNN6z|m?sMTX)bR$J~aJ6&fD5HeIOp(=G7QXDWtGPQy)mJNFFf0in6nFSMNBnK} za}{x-Rg{w`HPAaia{Xfi%)bsY^b?O|hI|*=FX*P1-hYN_N_p2Hzw4SfvnV)fk5z&x z@=EIDwjM%z0}@}dSz*pYAk@g#nRjAt(QmE0_f-XGyxt_l1L@hYOVG(E|?ckpa!Y;HP;$EW&~x;Y>jlKZ6fY9A_PMPD?2DE z3c>n)NR%0_nZu&4x~eVR*?w(*IfSSL(*&Gub1eV|{(>I_<~0=9*vzU6Ec={LmZ;?MPFqBXql3diTd z|E51O8sP50Ys2qA&>iK_T37N zLLNj9Xq6udN?D?a9<=Vk%NQ^YQzi9PM7QYJ3OMHtD%ZU`%HOBdXW$jK@EA$f%`d}y z{(+j5TSTL@P-@A`-u}k_JEjaBhOj)<+xF2>gI=lXZsQBr2!(=oeG;_Vwo>FD{XsJF zoV~&H;N2EOt6aAKP=Mpt;0h-=Eq>_OnF}6m(yF!F`1}3M%NJkecLf>=!CKXswqS+K z%Tq`tARJL(K$drR&B}1+y2ug)wF8kH@makcDijLu>&ZeF4c}*+A62og_R-bHYdakU zX8IvUt!(YfT9it_9mm5^An-cLetIF=GA$>|7redqIEyvQ~OH;R;08K zM@@Hh!t!k`Q$OCmPP8Q~)6$4kP`>Soqt!%5NB^OXzncYO`V5_b;Bn5n*|M-OxqsuM zltKosp1CEhcBMGgJ|3nY%P6Tyrsyy=Bs9OXz9a8>Hxd$8H%c%It-E+I3*~G)KRO?6 zz9RSP`dsn?M$pf{6)+q@ZD@7GxShGBa*9w9d2RJJQjNg>@&Y)Lk9hs1xRp9dNR{vg zyDFZj@zYytM%vn$`ldfk?jeSy2LXYIZl>yoiBO!`!<56A@S z5Gr51&tnPN(gxOtQ8;Ac6+u;R2qemVCp|i_jdyOKq@@4;HhNVzyiO+Rc6t9hBbWE* z)9X+25C)Uh)8M~+j2I+uD5$7j#8C(4eJQ!l&Kv2qqTpw6;Z8Bl7i^SYdRp*t`yYa| zu!zWEtc167^fq=AhnuIXwUy!5zDRdtjN20D${&w{f{)iDm zWEwM%`JVi{RaQ_G0@azL)n9Vep6J)sU>m<(N^LQ+2U{OJS^(@TL62m(cTUlhq#s^$v8xK=2 z*HY~srZ7GX2{osny?{iDjZ+M4aryuJBNFFNDxBy2cw-zr5#)vs*5kg^FXkOU&Vj4K zpJXIB__cv5`9DRI(R7r|K-G|Y5_59RBNcn=4hEt$p$cw13LzS74#F%X06?jCi?^N} zd7kJY%bLfcHE{ke0k8;yu$*qr-qEok>RU`5JJhLaM#%2Bku?8avoyEzL2abNBc+$Y7iX3KYsKN z4$6p$)i@n!fC{9OQ&nrhF{n{qUWS1bGbChBG7)Op{($_JhhyYO96}Kt94*`fxCUi< zrh<6h;9XYeD4$*NeWd$Khy|^s-@mPszYP^YZ4rxJ?%pu|R18*$ft$r-;sS2!6JdnU4K09i)nx5P7h(mr6zV;PtF}qzajgdDmDNTB$nszN*XYmm2yFXBtjTId z&Ov)}kZY!^UGuARSmS5`qu zb@I!D}Lh(f{E32aL@Sz_#Oko5(WCEZ@C5iS6qh`jW(vXbTI`vYg-c!6rkrUFE3MmG{x3 z5Rbr>h^8D=vt!sC+evlhKxDq(+7Z*_(F{v7z!U6Z=6iFy^F&bVNAzNi6}MPFSwU0N z9e4rab=-PJM=5xU2hrXDT$A2v8(kV=_ve$hTfy+$X`PAAiXWuNr?w0XJJ&slYbg71 zNT11t9N73^d+7WWtEybXcQN0>QH-5o*@)0u@u#6I$dYf~?ARm9a&By3=MGoMm`1A$ zy`QdVqRw>e1LqS^E2NV-Sx8C!c#pQXbG?ayPH=j8nN5*jR76KjP0h>e1w;nGT=zAi zXGL?SLH0H=IXOE$jh*otRP5j{=wVQy_ZwlS-K7Z`6$MRCsq7Smdc^&|SA%4u#|UiH zd7d`;m#ujfsZcFrgG@nQQ~PKZKxOb`3U7Zi>$+G>1@Tc3?!{$j_bx-EUb3xP}-lz4!Z$tp6RL)cnBx4<&VWpg#-R!`UdkU9wL;{Iw1*% zJl3`$a2={caF*BkO}Wd1fu%nYpddaar^&h(T_4pid8t!58d^ulM7vUv4Ji;2L{I3S z%5WQewzyLD9NpY16B9Mh!g##BpXe%D=jJr;^h`{0KM@552k#1S;HOiVJv}}|e~{+% ze!M?f>&nQ;2$c^}8A3r6g}=avBJxb~NJa5liQZy;s=MER+C0=@y_}HO$(X~zQd84* zA-TA|YyRWybQkk-Y2a@4YN%*a%e1td>47TYL$u@+o~Gl62USw9A59@-03zt=mw*Fj zq297-{oted5+p3cenvMwUorX*tV{X9UD0*FEo3-XqbU2Z*@8COyrar- zn8J~!Vv$e1Cd`2A$8RM^pd+v9lD^MNWI4@Gu~JIyaC&VtdoBL-sByoiSk|8$li%v& zKQ%ESEGnuAl=r#0=7-C<^QH-WpeU;rBu>WAQd1`~8HZI?vc&f#bJ&0BXnz%BnM@A9 zy4>n_czEc3xo@g%r=T#}=zay38G@|r5HuVz_VSx5;4u?`hxm|*dGoi-mtZ|Ht%ZzH z4_YQZSW5j})zgPh?3r}sd#R)&d>Bp{IF+o$buvN!Z*oj!6>+6c zxr)tVURRT+jy&KsI$%7)d182P7o0<7<;NQxV5Yh$*cnG>k8Fofoy*?)yodaj9~V3H z`oR03qB$Pf-EO|PQWlLK(oQUjk_4V~xT3Y_UTwMB)8e5>_zhgsx^M;3;8=?pF zbjdgxc?yi4o*vGjvHIrDj*cA<{yz$N$oQN>Y2ZDB8%te(55)zlt;FL5 ztkKf4oKQZnMuKK1_<)hSuhM{ojT(n(wZT19Fk`y0slTx4Ye8>e_lSCoeJ*KNTp`SR z1e@7x9qb=*iTsO=?(qax+w0@4Fho41mIrY3>g`pP#4ajT zQ*ZhZ@@3QuB>;R_!nDrKrzpmA6x=ZJEO2nlWf+4w)W z$bwKmBE-@3jp&4jUb-Pd4DDu;(_{XVw@YiB{v9G{@}7h8`KuzosY35m{HA__O|5cY ztKy`zDU*XO0B^{jPKInBdfcp1qj1uM`TS{2gRo%2%wJ&S*0xlw0n};1Mny?P^qXs7 zSY`&3`vk*NZ-vZ+Qyf)r(M5IZ;c5PCn=#!siO_({pQ_iol3g}$!;u4S?<~v?PG;+- zi=jqaYao;V7kPoydw5vkJnGjn=Vw|bE0-{Rld|g36Ze^QMKvF68)?qG?}@2t{G-#N z5%$@RGM~MQvl_eSHNJd{VU^x$tpuCxNIlAAcw4`N-G@C4cV|SKe?T zANlkK0v}jN)o_>a=Ts)6qQ&=UVn*OKGE58}J`@ZzJUToqf5bWC$gb3#YNas&!JfNj z0h6Wj_=#m)%1}kOKXYuw@7vDAvVQ9uLEUnjr}#%deXs~?w5$M}$;qKYKm})%KIQ@o z6B8B!*a7e?-zHg$dU`$pO~47DA;7X*DSrM|pwI)KLXFqMtxTnaH&6%!7K{u`xjY9> zm-?K);6G&CxOxG{Lf>Ui$xBE=rNF)py;A|beR1&`i_WALw(z!>^=H(0-Jjj1&M;A# zF%l3|UbZfS-u}sIc{4`?^}MWt`nuAl^?Um49{*c&W0FjfjGLRSRA3_hGL#~HCHS*; z;%N&eV)XvUQ+XJKsBhQV9Yq1x$n$X|;EvodmXz~~D66Q(JF2z9?j)ITx4xQk~-n{$01!!yx5Ni;eslS@mCK{j)IJ-Dp{!YC``V2ReN7mkEx{L_PrC=W!U&>>P zf|Ox7Fusc_<80gwH+qY;)zfFSZT|$^x1fY5CpR1|%X^E-=dOtYg2=iOJtXZPNm{KP76P6{VlDyddYv-`>k`D@!3~#yc zfnkRA^cF5En9Mwf;Q@j8PLs+bNKXU3@Jssj-CecJ7cDwqv?s`|~BJJ+!G6_5Lq zE<*47(v+<^ssm8%vGTM#0U(OyY=r8Y0)&ijh(yICS8ESPoS3E5TJOHqdZcGO68A>s zdCcyu=D7cuqX|}!Fh}sZ58L}-I5#U;V95Hj?hJD`HX^JanRpbLCZS1l<`D2G#pZ8RSV6G)ygUG*3aO3WwCD@pNHOsJl{(|}83kg& zbz(Qf+|8~u>e~s&xn=SO^Y9G-Eu)!hr^0oK5o_GadDCTw1B}66Zp_GI5zy-Ukp^Y$h2I`rRL!Oj(x0OKcKb2ZN zk*S20`Av1#4Srh{tSNha;}j_R13L>jZm*W{sh6W5I9`Tz~zlp^pKWJid6y#*g2(YJZT* zFLWb|O()rSWnDl%Mug7z)WvU;-WlHO2c7G=>K)W4cjznyMjBe4?0$z3kE%YFOC2h8 zeb1G=&F2j9B(SNoZ11l(eKM|*|7frw>{#%{b~dG1me7ovx{gh{_ojg9t&_xAH*P9S zPZ{1Z;*d95^wx}G;qJln$ZF)%7o+8@$9>oeQnc$Edp&N~sFPn-gO{@c{gR*eVxuyF zPsh@AqW81;Vcs}rWD~VB4*#Adw}|&iqu{YY^&}m^<)kRjRM92#kUuLcD==Q$IXkm? zGKqLQLLffr5?*|sM{`4M)r6Ct(4Qs_61}axioq?ZcUB+U1T%^r*IW#%s$aGvD%c6P z%0h_n2=-Rbx&18aVU-i411R*ASyIhYHMo&pmtAAR^1u(zP3B`JWCMC(>p1A zi0e{kuVs$GSh~C915*YQ&0*v8W6Z$v&$$TdWD^usg3^|-M25VQs>*_R1tDYpUFg2! zxMK&BKOZ!t>wOa6IZKt`*5n5Zlq^d6>+eJf$SH~%S}U`+_LdKO<{zmMylpQuO-gXx zp-pdDIsM;ANm3uFt9a2f(IA#{81e;zZXe28t(1re8&J6gohAGG7Jl(ZdwY8a2l&8D zfrZtzVuPsDbYq?yHA?!jgObC@`Aiv!vr5Z6)U?&<^|{?ETr&7e+gGQh4i#3m&{>l) z9~R8LIt}`V$*bwsrq7o`kLvsm=@H@K)k^ff>U+siQmyrcH+&K13MC-tyb&BMD*S5u zZjA3~nB%iA!|qGSZ)QuHd{Oz(x2wMG?n!N3)lDuyLqGp2D0V$OL5Tf3xiOS^?Ol}t z14!vCx=`EWXegWWa_LL2T%vlaOg$%h%x@p&2vsqXY%bhuZ&_g5m6#CtbUZOCsmku*$J?6s( zh-EW`z6&j@pIe*1k$l4hxy8S@*N>=XVo_xx&C&;oit=7wA~^7o?7o2YV+7V0U`r!sJ+1hP%`PzLBU`}+1_N_Ok)sm{d#xXQ7>VMV>ai^jXv8^|Mj3nlgnmP^hWpm_$Lk@>)}4a zRf2wq$?2bRii#BI(ka|Gz~cghj*l+1JTf|(K;!^X9%B-pEumuYf*&}Tyi>$GX z^x<>k{cY@@gH+bISi1#B#9eZAi$@~9)OcM<*R4vgc!XD@VxVgcHuTnTI9GPIu6LFF zha2yJm~tZR+_G~bW{OZiz;l1vccC)CLxa=*hmZSeYtgSKsblSdFub~|%&u6e&Ss^p zqJr6cFV0%n9bZClVx5;FD?UnmFt3MxqFiyfcV_Z^ch~#ruJvpa09QxV1StQZ$aUF~~`|-_ouJ7Vvf08fr#fz&9n@WbqK@SkfXa!bZV8GB6B9UhZ zjMnRy%N2e>#?C&kOc5oV4!ZUlo*wTyi^q;JMgz*YT(c-SR@aljH+J8{LVYwz6A-(I zQ|S2pw0u3l>-rFR!TJ?gY>RbU-1B#NPffFVIwFQj0PqWVkROJMe5NLiESI!wTb7E}?&Y*Ol?qdIQzHB}MkK>3*Z8y$ zj{ZB#qVZ0M&6SBEu#A(Oolfa`LxC>A#LIvZ9E|_zsy+H7&vNtm&MUE=HtS zmo^T05=HbivfXRE?h5APFw)qBbf_m>4le^{zxIz7J-K}vLxr2JH{U!?yXS3yBK`Zi zkdx4wkt>m?M}LpkRKDy+YUxn>n?TyjCCM2%t1{f!(6=!BGKs7chAiniaL>()z(NXP zXsgg{8l4ycv0>EMurEW<_(yN%V7?PKfmb#XaddG=kV|2BcC3avNqze4snRu4zF;^t zy^3>h55_WxzkA-r#l@$rqEx;}MFQtT0-wC<1Dmj^;m5|u%TEt)o@;EtL14y6Ge!N>!Ndw6Jj(L)KtuNc4e%OzT)e3!>G|rc1MyH>o(I3 za%^LkOvA9meK~^m0fn14erq!*V5);f4O3i_fDmk;Ye|3olb64}@ zycB<1fS!F+)yV5XT<$*pp5F`dJGW3}0_XRcppLTFS?JB0cTLMbXrfcX{M!yH-XBCo~3aidh+}-b#3vOpDY{zjt`LN<*Vj6%L2o%1ZodBZD#EKe) zq$pCEXDCnsTuI6D57j+I7|WFFw`$3faH8%m*Kcfz)~5STzurm|rlU-=I$0!UzoP3f z_M&=tV20S>B|oS(Ox!0D!R`G$m^4*KWVA)@zo&3 z0cI#*I6iUVCL~M+i2$gER}{VgHafoB?F?Wx#lpZ~NazQ7(6@kq!`aG^_LcF;Nzixb z3|hiK10e9g#(0@KZ5Jo!BWa@TGL64hcGdXmR2*4XhTBL$3P1Pt1%FBS^AMRt91yYj z?)N489vtfu#8>U$7X`)}Y-8sfpWwlfLn7uSv68tlE@!L){Efhh#CUQWH}V+M*eIk& zx^BLqb-G?g!PWXtp0TrW3vt*-SS>$hfuQR05LT=d+@||-5q5s26I!?eX)^FWgStoh z@nCivS0cNLz`=*U1yOliVZWa#r~O-J&9}P+&!S> z4-V216Sq!HRaaH9Qc~`m?~GB!=DV`n+u7X$>r(yX?A4;Xbw}`9IyyS-f;w-i29GKG z23y^ba}vi@vjef#;O3)(w^W`fpVigb!;hVwdBv&iE8K6IJtIkksoU(kC%faBpcHyY z_%OKVAHP5@TP!XK<>US|_W}Y`&IzQ8S*__?g*|*;jj2&LUDVr#r?N_z=$>a)JU08f zBDc7_q~scyJLBkeACJ7B?m$y(4J~vWsC}$&Z!>^xALPJ)7Z))|edLQL&#Tj_ ztE-!vn<=R$C)o|VBY?ve2*Yh{0)&KwkQ(nNFW_^Nka&$R3k?lTE|WAZBY)KV)RdgO zu+bM^DQ^Kt#Ip<ta7rms|$4KRy)#-m+wC2?dpsiSbHOB-~5>~iGDOm zcoiz49jQYh(~~Cpx|g8h1|?Ax^;>98G~k*DBeSk< z*5^F}%!~b;Pq%w|9-#dJ4jJ#cdl{&*pt7;IyQ}g?&33&T4LPvfuqO&k^r)s2I*ct4 zVwDS2fGXs9y%Grggg}+mFf-c)Q;mYh-m-6EWvZ8MLIVI(i13X9zG1>iNsb@YX4iBO5bA5Gk^s2h)Z%K(oX**nxAyCwb zrzW36ZOmI?90fGBTzw6Vmpht>neP3kdsiAKqDVX}`=NmDWigb;kkHV9p&?lrnYbQ9 zho^)pYZ^K_;JtJN{lB1Rfyeo9es`jv10QarUj=@swy8uNk9?#45ajKl)XyVDty$;<5t%7&To1&;$3p7mCKk^GJ5-6 z(M}@T?k^<=dSuhy*eMU5_I8$`uP5HUKiQaJpUc%tqbaYUxhFn}j1OW_Ys=j0q0Ue~ zdxtxKq^LhF2<1(Xg&d%=iX8t{Jbx&pcjamRy@5=)A`7VVa~)XU+H+h9iN9hI3kLLs zR%L6kTg}&O8YedEdQLOz${PsSYp!DrWuQ$3x4qkf>+3xsxBS{iW0gO2^M|8~VYWDDjgy@t$6 z<%PckCfFKVQbxv+_I79pV02Z6J?Q=d{NYwf03ihgUhtz96&2}v-MohkLx0@g-`8ON zji7wR<`7TZI2{~0y27QbT%V~R`@z0GT5&o9zxql!-~QqPu+7kkk0%FOwstb65;CrU zJL@c-FhLNJ`zVJc>!;wSdaBlp<=zE!K5A~cb`3LvO7gGN5jw&DfF7tLSGnY0G!e~8 z(mFwbCZ(n{%Kx=-%bwtcc%P$Y< zpsda6naQH8t$g`;*jnpXY>N!)x*$FEHv8Xb!;1%_wCDC>v*c@GVU+jd=@j{nKgUv| zqu)GK-JT8c5we(#gXvgwlk76b{raf{^nZY*0RsbrfrSP7*ZaZWMwqQIJy!-e6GgU@ zK*(e~I9_hXc??|g12Z?NJgvZJ&v}QYrLE1S>Bu+U&?na?w_}qErkxS=M957`zZP%2 zb{bn9HF7@1D1-G(AyJnCtlT${^rdw94V(ZoAP`AOc&@@YT_ZL1_)c*R>4=bRZx_;U z{aWN+iEhs=^z-NE=f8gwLByn`vvet(71h+HeP1H5T1+!|KYHBKBZF=YJ%(R_GPm6L zQngxi@qLy$Z2$omy`LUHf5GOFD+?}CMQ_fvB(P%{7ma*WpafZN|EPvhe?D1+d_;_sDd>{} zp4qJ!tqCrSWSg`6VD%%cfpemC5<4R`_1@#i(F|+VC8=mad$p2|yo%%9=0nEP8<>$t zI|E?0{(pFT>!_-}wSRQmK?zC-3W^faqDY6h1q1<+ZV`~~Zd5u&q#LBWVUtRCHycE{ zyX!vtd(Qct_Z{Om#=U>tJsd;O&0?*!=bH1GpL%-AOHE*YR0EC|*pa9XHI(Hdu#h;t z*CEEi3aU-@8jM0hv(XR#`eoQ$^MP|SHO`qXNMvPoHB~&y8blo>w&QGwypmSg9IUF_zphbasaBMfl?_7~_4u*Y(az#(k?HBtF36uCaAGvU zUp0qx@u#?FjD5!EL_}@tfofssp5uIwxU^8TC!Utl-&UlDMv1CQXh0r+`;Aba3$B!pW~;{f-a7m3<1iiFzP`81B#Dz7AZF*Ij z@yjsTslBwygB+cw*ROv4z$5}_!F-F>gf!i=AFWbXm6XOUPFTV|P{4VH z;ZHEoV}1QGLczn^I@|BxJMF@!doF)c#<_`j7q4gCYE(aCr*@6cX=EH#=J)G4`V$nY zJFOqV{d{FuT~|mnAmHb7acYsis+qhVVsw)Gm7$ifQl*Z!v~Pggew28NU;O^;nt ztvb0Aib)hjy4ZUQYfP=QXZPRh`4#Urp(l2N*O=@1anV6?4-V&KUaBUkDf9O++!%SV zWnErY?+Cv(;ncX$8S5D2wy(e%>L)hvpr&xzuTu=Ip8AO?aKB3CC`RV!OUQu8xPM;i z6??^+{lrOmnl0q4J>zm6VgSJ!a~a3l47}bEwZ$^u%#v3thCgl!B239vDT?`-^j%cg z!%A>xO+Rhh-t;-*&p&8Famf}2T)X)|k;$bhG4Xx&ngn5*bhIJI^867mQM~+qHciAY z4Hb)VweHJnxTjYn73@NX%&!} zA3_krO`pF(Kk13s%=*Dt+1affPPqY#3tmB+w*HpJxej5f?w8&aUe8U zoItkFMb?`*uhA&^?PYN@4MnHr%!>}bsdXy9FResiQ*KT?dM37ZR=t0Q_C;W*)aJJs z&Sg<7z4s(S&5Bw|MedP_lU2McxAu<*!%cD(+VP^NU1Bo{mkt~{9gQNbF|h!o02L$z zu+jF1t;s}-(`9B$msE3UAzYSdU%JxNG}wip^yCVX*pAOfDz?kgT2Jx*Og_W9R9Bsw z^d&yNjFMKD>5W?(o>)~*IZ}(sNc6R$9=p*m2E%72#AfNr<;AwoLY_;Tko@sUS$M$o zsNgGh8%te#^dyDmqXK4&PghSW)vN4rbnL3TrY};&S#(;&M$8<4FG=?NaRE^~^9}1l zJk=KIZf>fNGq-%!yBCfMZW^?YYc)QG3p3l81PRTKd2CQl`M=| zePYr0A_7744eM7WgL<_i?4VM$3*35ptvWk-0^0Pv2}H#tAveN%=4B^6Lr-}o;W6vY zoI!Qt4HG77qCi{=7hTsv_jsq8hmx=N?`%X223|rSwp~@O&o#iR0hkyaoxZa6EWSG> z_~w82e)lzKE$v?_8Xc|YwlU5az^((vcz9&wZl%v*pYF)c%GT-KD|X4n{`*H|3gXu- zC?4K}iFj2-yXA`l-W;8a&2$&8%C^Z^soTFTp!tei{e3_hrF3 zq2xhwZgu+&Esb=Q0o&Y~(vF`j`=6cn!q+Y#Y)u~!f8m5m^1EoVH+aDG^neC=pWgq6 z>f*(V;NOKD9gvVC6GO=}R-H2p20Xj&P;g1BB)?-HZn%ZBQ5bh;j{J|2=J#sQ@!fbx z{3U|G8<{DW&1%JrirQ*LeNDX?_$h>TnUsmQZu+T)(|sC`^5Zgvh@U2K>gLVv2t2ow zg3;3mcNaCf%yVO|`&buDWb!O_SZs(Lu!47RV02tIe<;9ilO2B)=J&gg(}t9P_hHEl zKTk88d0JEq$s{JXuKZT~@zJu-Ec4wfVa9SVCT2f8^1Eq9#@*e}`Ct{oBuwF+lSf>CA?$N*!l&5=tjWr*-seE(<2t!*C8Sbr6*foU1W;A zGspM5_H)w%&_WB`hKB@o$z9Z9N9E1ZVj{P!mH+`m^g2!!f&ILr`r zuGG0bYN2`LFKKehFD8$KgfraRbv%x|_0)@G2!tggT)C?38~3H!mfz>9w6f`BOhUAO zo;~^!P3?hl;82Xj+@Eg3hr|~xc}sl=YqW@fB_Gl!%i(=Qu+@ldY4^My-6N-qx$6Q$ z?r>=#BHI~z+IM2RvUQ7y9*!v7Aiuk`xAB44K>m8PT&#N5D*KHfuF=s^vXZ1-uQ@f8j?EJe_xO}2+<&(G zA)o{26#gVc$>GFt@mH`rmAUM6)tTBLT-?>&5@GVo2*j(GOqW@>*@`3UbbRq*m@;J2 z$W}gjeQ{c)cDLKv%zyf35`l;(dj)TLG%IVB{?7mz%pheFYMy?Y;B=4L!%jpc`)w~f z0v>>M764UgiY4m5q3B$`c|G9G(;}KBW8*)&BVLqmq&m$cSa=*ldqsTj}iV3>+F5 zqbY;*=BAj?S>s_+rkg_A)2e%ezte7&=6_YmVmN4ACqW>1!r@W7mz3~p^f!i^UAqAMg#G>f&CMcT<@E%zH6&H&#^Mwe z-pP&Gn&7c-*0bzuINh_wCW^a&K-?B!y1Y#p)&_BVilM3>3@SQDA}a1aqxk&6!@t9l zEJ|KftW;JGtg&ikroX^XpJZN4*U^*J+b``7_a6qZs3AO*`|H}CJl7EjYB!jxsGdA| zLmiAm=uJ?L?QYMLh}4bP!C3Un!7cc-9M;7c!Rg@H+T1^zDuo(qGU)l@4sQ~zjs#5vrDE%pHV(E z*+GN}dzN#KkXre{FU%H%oA5m(D`(;7 zKZp2;F_cwiI`>6%uw2_Gl_%#^NgHzciJNN7I&HA5!Gn9i!=sOlK+FXQBi}xPx_+)m z|5OPw${s(SfdqnGyylLM7(OSIuP;_$6Ofo>;Q5AKyOJ(s1)e}00VE<4U%w1^8pu*% z6P)ut{c$49%CPUnm$J5gp}C+vwUhK``w;BRj&l(@9I8Hd+kHf{dCf}>27c63kK0t4 z(XOoOosQqBVZ%D|Us?A9w>m=gH~R259P#k*aIsWL*`iwCBPUTVlaYbp1Y|@YB#(@X zGttm^iB!tQ?Bd{DVPgcsVrB-0w~~^~jEqJ(>5w$Bv0*AK+yvHYS65d!DNvZNPS&Vr z%MH2IL}X?zU!!pB&Y#FpD%J-G3(9|S+@Byd1;Cz|S#3N|c2n3g(hGM8jI3WL!l|h=jbV@jD zUJiL4GIYE9`!tCF$H7Ix?NV=2HMFJHc77(00C8emgazRJeN zmL%j4Zrv`>y$*e*J9M~OI9lOL?(5LV;Z`*i!B=V+d>(w%dFdW{@?`{6&2mN#OZXjlla;fph`eX0D^pjL=};W#wT(#2+S9|~deXFti_wLE%s2mP!24aG9CZjnms3oFx z4GhM{G4U^AVq$f5bz^*=LbWwNeguf0Nv#qB4bCmZU^L)P z$7=SA$sh^P($eDK=1xsczH;qa>F7b4RMMTB4Ul>0u(Qy!$7Cf&`HT*E7|TbSr;+Ykd4I@%oNKe*)D914uFwkQ*ahZR(H7`S#?{R;|MDb1~{R%^@AfzGY(Y8tLvcw+Zl7i**7 z@7}4Y#R3BaV|b@+ zVS%W?%+eA=0>JY;s-Q%C01U;#+?-qu|9x^XCzq2=Pl)rVm}9OeJ(BjY7ZUO0z5FHB z$S9bO&RSl+l$SVzZ6z+Obx((AE{yHz^jKYo{>QYYylPyYSIo9hrG3C14Z?yC9VQGQ zR6Vip3L+I16;W8NF?UEwQ4kOUk15}h4n8Y31C4pkyJ9p;Q34c{xr>dMjHfl1nEck{1DmSpBo+a>uI`_;=m^~WdtlR~s0B`*}Jf%jU0l@n};kU!ti!reIU5vEX7P^bjesK2t;>4s%y4et4myptLW;n9WybdxfF za^3GGCu6ZmrT5JAR`E~PdNo|%i6Gr0J+NAf;$PBgd0pKviG%IJnC~_rFO2=SIZo@p zlxv(%zf*~MVBh_yp^7xot&6B^&Ra_>5C=t$miZ(U|5Zdn}iAWHUR-VBcq2{i2dG#3u8rp zH@!sA3CZ+_JfCdir|Vhpa*a{Xp-dOhd`m;@=^uy zGyTk>@%ubi-;W=P8Rz$EjaS}Ees~NY5s|M0a^1?3a;>Jngrd?^b*q?^R z!uInTfq6pE&w4zg-S87$Y=?au);m32dLI>*Qy1!8>=G*9Cm)~adX2T`^JT{tEc)*4 zW?#W`>KB!Ubw0{*4e41iFY(?$-%B@3o15t}Khc!lhA}MTmW0jjwT#*^d$3ibwlPCV zh{q~bl^67W(U^Pg67>Y$(eJ5peVog@r0myU_j)tR$BA!~&GpRkRWenlXJ!We9xcIp z;yo!MY7-iR-S1KT4igpg_M*z@)n`tVkzZOmK<09D@oDPl48!t?Km(3pns%o3FxA3s zjE>%l0*T!x_Q0#K(4lv*MA9La0|pIZM(~f1bHTSh95bbPC#vqRs` zZSY}^#PR_1wo+eN%e0Dg2h5KdH9WJr7C%P%$5)3BzC{ttVBUv#0JSsb@B9D#*5aA* zI0q#v+4#Wcj>KXs&OMIq@YisNb{q^;gN21f$(8#4ZedzZG^op;`oaekP6j(0W{8AC z?!0;J-l#yxhK!SuSr7yGgD3CbXo?DDP_!J~ZBen}@vuGusvn`Ta&%M#EnBl~<;+m5 zeyGO0573X~pFdf!3$qJYcLuX#WM%K64Q$1-ClqA~?Ux5jT17oH-oJmpvXb|Q5{})y zQGJ_*8`LsDkAs!B;z=+g{gWwFG?Ma-ghYU!-wX=W*RBz;-L$wvNJteTdi(ZmAkfS$ zEMW8YOAMGN2-ACwL_U7}805}hOYvX>G7FH%e{l@BGvp7-Ah88rUa%pBzXYz8|Ns20 z*X5Ko1mYI{laN*@!yy%Gd|V}6Mt@`P(*HzhD1&~DT|>AU10Yhn1KOzRzkjt@@7hrP zgncRbF@k&j(YOrK&IGuG{yI~ z)WFzEh>QFC`8{{M3(sMzsmnvxCoQvEuwsU4Kbr4pa_L@JjCK>GG~Z0=>06xUr!^F3kDga8J%kr&Q;BunmrXUo@G!b|LOF!EniR#FRr6XgS`p4bVx4=1 z|GSrnRD;wu0fGm%fCkkyTQ?HV7ihGt?czHc`!kJ)!!<%9bpT7Acft+~popnUD z!b|MHPt_mOsG%9auZBDZgC)LN)ql1@T+;g&{a(6EKCELw?x3?vV$&SRM>5&q571w?$*Zwnd(b-W85Rb|btcTL8a z!_jKyKA*h&yEV?6B!Yrc$E0@pU!;q7mh~5h1e?x2PU^|=Qg6AHtggOsSTtu5a0-t_ zuux#IurA0m9{8RZX{?&^hSE}5)K(2$>-qOMv7#Ms zg8fK3b1W)BdjK#oA8)wp8P}F~O^H?36%XN$%1h7uj<6rm;Ee_&$0icz`3#m9`^XDS z^4te#3E9sw%Qn?N`y}JbCiF~gZTeS`5B60K;L>ZoW!d(rw7g+@= z`y)&ToKf)&Mm$f?+OTFr=+N`Ruf{(G?CKrbQjX4?|2*6N8_l@7vgky9v@nrv)Fgj0 z5|M)P%xF`dQCyB1YiscFklNOhB#7Y~50IWXE?Fp&$)_?)DcHE2KYCQrFUxx99ysgb zL}yO%WG_a4ku6~A26s2TT+(9?4O^o79K=v0T!iQOn?iBo66iK6${a5F37?np_%E#b4pKd$t^#V?$}*t8?f8I|4TpQN)!CCqZH1JJ=Z}SWYqG-t5$uq{nDEx z$;rFJ>@nHNO#!e!@}Hq{v}A+YkLhn(Za5-6Y3~l zH`vC_C)GZ^RMfh)L_e09Ye>w6leZW1i7KM@y3uI=^Sa#3cEYJQf&-W|i)=e}PG62$o2Y2Pek|dEim$2=^ zvO`?9VcPzK$Re-b)FkoRvFu%OnM#nDoXeYPErj6Hf-*3R5$jC9aA(yQ3y{{>Adrrc6qoXI9 z#fMF{lr&~tB>C$ypH)pxC1R5^&nz0st$2cxdh7wiy6?LG=n{!X_r#>#%HZ0ao6FO_ zRfflmR&lo7c9sPpT7uKUe#NZ?8T87&xQ#zfUZl>AlFO-z@6KU)dnv5Ov=24m8jn4r zho$#sIP+x|?4YJsDQg$^Nn)FMRc6R@WMyfM&r~c{k5SwsIJity#~%0&0DY|j#*SEREX*t2i!)f|FU>jm2;-5EeP2%&{9k$cuRC@r z$l_>;HcM(oA63l-sH}d->I76>d5Vh_VHw?>A9wnVeVpcejl(gf+351qY!@-JqS-*} z!`JP(F9i2t!BU0M8ed3K-JH?%c>ZY=n&w{KYN;FZp5dYG(;EAtHfOBZg4sIw=$he; zZ}mU|gp~O{wDj5ICq29AAAzr>?WKDqtLItA^)mBP>KhGejQ8|tXkD5QU0tQfDltnx zV2_9tEes-7t|-KqK|jAZ(we2_2?JlYlO0FCNUwe*k#>CXR$xzwBS69=II-LpSd#xm zJFTHb>Jq(le%M?$U@NkjM)yV+<)WnbYLYX0EsQva``!~RnLe*_RMF6w0*BuA))v4t zWeXuKqe8TuI`iWCV>xoIX^m@^3zQ2S<@sF*mv(XPh zTn|yUUrTe-pV0DFi!j!V?n&GGSmaDFCI{NA)y6Plr^ZncbA3{>IY$3-}>xRAiHP_uPPG0Ha!oj^= z{`|OPmPuUky^QsXSCLzbAWed;=E>18Lb7a0n8d~H>-=;Cwtv>7F$a#rxeT4$A*i)OD*^2Zg|l?S>!zR zK0jJh9~l{_`oyz%mvbafm6e{7n7ymHCBuh%$i|q{@qk6RoP~x)2dswm)BD~|oo@w8 zdM-XikO05rx(ND(H_5&KtF$8cU+jQXUFonDxuov=3l09RM6|^>^YUmfo<`)|O0iGP zns57eW0Wml&HaYdUB%EH^b@69}z5=N~Z7ufwvr_5-q7&M%R|eH%U}F9lyYj zsA~_!U+_pLVq70jJP90x0J{bRq%8|zBRsyq0|hT+SpYmJN0Qgc zJg(is6f&+;z(gz!-u;u~CPNn@nhc#u-ol0uie4Yq3T3f`HmDF_3eNjac}HKcx4C$p z6{8&PKD=QPD>E?D=F4h)x*PGI5|8bGKn9wDK;eNvc)-5i_4-iIg`7sAWNyEv|uZOqk~>wR9QlcEpjyRBE2N8n(%cz zkJ~g7w}Ny&+^gI0mk!c6i2ZEVTQqN#e1QuaYHw6FNW_zl-&wzy&fU!%4aW-6Zn(?b zNl`e>5~lifje(y(&dV_Ri@&0byo5Yyd>v-q;MOcwlC{$tDSw;#QUk?kcg>lBqae-; z$z=SwO^r~&JNZdmXdHjbZ6yv|>_uLamH{I&?}dJPU%^2qz1EypVIdfH;T~Fg_#Ute zdak%oa=IEXFSKu>@H!t(fpY#ea*Li=+o1;QR2OTqm+p9bf7^Lvn$x*=wLebC_)O}9 zrWk`5vWl32vE}3vSZK%vY}YQsr99=v<=@#oOISCSk(U=ObreO~FhxI1q(7HH?JR=r zKUY?@3xAY*^vVu*;n9_miTg`Sbka6=;U|Hgg@!+oDB^73fLz!7Xo~Vy(L?7g^EU%i z2=E`>Qb5`59W{MXJ6Gs7Im~cPRr_FD`RjcA54%m!$(DMmJd-w?KITZHOWriGA0i7t zY5$_+-8lnzdm)k>z|Ny4$HyR2787d& zgc7nhl*rw-`DhL!*P zWE&uzx%qiz1%+Eda+&_1vb}NRa4|IwRABH1fI$H+jxxxAT?9zwdwMX?BE%;oCjNz_ zbcidE&m7oQmswa^Iszq_<%ddSk^Vpi#4MCoRIqb?Q>(H^ms`+KQE7t#AL3O%=9g8i zJ|ey-P#SW!a!)REfL8xCOu z`!4k*9?Q%4_hUGn4|L8SQl4H|RV8R{e~KM^uw0SA>luhc;_2F)&Yv42a%6NGJZ1LE z(W7J;$^6gj6w@W?e%cz`DDHev%7Nw-G6f-(dIv+ZfRI)sxffKJ&>`!#l&R^)!REBG zu0D`}p!5R5WgxZIliYrxfmq$pG`z5ITa3A?|8ovO&%eabeOgTYcv?V^f;_LYtqssy zU6W&2VY_+Rh&@z1{4MXkC^!q%pg1|MendjeF?D~9Ymf=TGa%u)uF`HB(5JV<{uT6R zd4^{}r}EV&w2pn9DR{c`-vvGeJp80mdvLI>{*7ZVoQ#W^j#jA|o&;%h-}KiMXNRrj zc^jttly^rzTMkD;&(hS z1zC6ItU@T*YD`KEN8Y>W=e_wiq0~kIG(-;;b7h{%Bww)-uf}gTm(yi+REva%hC~ck zF~HI$)rXC(txKSDjeDx;!IXXV$`wZNR08VQQLO&{J>{+Ik?jH5zxiDONgTIz!bKZ<=isTK}Sh@J6Up7R1 zO{-W*ThHv2>NDzdo?6|tW9*=iNk{(O7{w=jHgO}0nK^7$si=oy2?Hw{lDB&9jx56M zaB?2%eO4-AQ$2EUZ~)LO(2++#Kb=C*GymaC@LYhFqFll|;6B;`MhC?se8Q+zTwGj` z9y_k&H>JFdD1e-u*4C8sjpdp7`LNJX4^Pk1Do=(sNL_|5Q|e&-0mBAsgdy+u~eG;|N1xECYwLP;&aMf>_XEGCD6{(5xcHg7wiF7N3={+9}6 z_1gacXo`+ZxF6YeH)0w6jGCZjVv-OQjf5OP==Q`lM%kuzw1ZZAMuftpU>vJ>L^B)w z$IXVx*mjKZWAx)s)cE;I;$Q|3y`wf+KEUSqb~?sC?DEnJB7dcVor>2;85zZc&7i=N z(+Ji_T6-{rM!XEM6{wta-kmZZ3X+LM#Y%kF?c&3_J8@|kz)kYdDNS|DjzLq&dMnk*!(*jUGzOxKaIS zT|bP1V*hzXL@Z8Ezd}OfjvbJ_u)eRYHG(9dz8(~$JiNSCFS}b>-pD7m;4WNaHJ@n) zytsN5orbsV{viNhAHak#(c=)8&Ll{H4|NTubpXKi4<0;VV+-*mFxrpzCmxk>84*jD zF&-(Hg`g;uf#iKTn%uNvfuzp{OG0Or9o2tXEfkP(z7Ot z7|!a)+jwY2VVwYeE_&9}k@74hv`&vtW5)|Mg0wM`KWr@H`xE}xZ0^`ppG*?>1ydXk zomY3elUy=i=I!e+@es>x%DVqWe@&~cfUnYysV9%BJruZ>++YjOfB2uv*Cw5o-rW8k*&}i=8bk`T6+| z6SuakPtwb5H!1M}6{m*)9~PDk$Q*^148Z#Itor-=4_FBi-&VF-?4^PLZxxlwj}1OI zZc}3tJMB4-&a?XGLh^J~i5B)4VRhUtt##yjU ze^)spL{?qLaLnqcqUF-ZPk0W$(It=A&DrM2wnERgW4=s>1v1i==artg%exW}*G=77QCT{6_W9803p9S5a8N zfsA;no{|U7|NYBqwbT!DikrJT@7}N`issX3kD#Z)CDWHoVNH#V1q@;Ls3;w1-4wnGay#Tpb`=!fMatM8NqRbeb+^WSQGKD*dEzxgn|^Tz znok6o^GL{n|7h49Z$f5BhTRES1(RklV#qb$iQKqSHC=9vv(R90PH+9bibLT^iiYoK zh5rLean)xv{b(uRt*UU_?;jl;cr|=PyWPWw4wH*aw51Q8Kezn#+J0)AT(#lMv z;OU^ddPcP0!2i-NTEYO_qGU1=OM{Bk?*_W&?c}$+ucu=+6`kd5XD5*!k z7gJ)H~gUG~U4%pS!9> zk*8|5j~u2^W9j^xj1AQmf5#~s*@k3tBP8WigFm^PId6!Wu+#Q@c=I49zdnOa-(N1f zN55aGSSeG^fDOf{pDkoz19wN3o$GDs>!h3-sU$gr<+bwyXX(g{QBe<)(8vS3ticSI z!{zx)#4dMlvskMQ|3;MZUA-GG7%PU9+gnxBnMnu~BKdjgQ<|!Ur(l99+;>m~fUoU) z+blSv6hZc%Nrf>Hf!`B)XFBc<$RmFQ2R}0!ErMAVctP-$G|z59!vnv2oCRlpId-$5 z83+g|z(NEE0+tM#*MNKk8gYt?iCLJM>N+}3Ry$!@ApFK+-mtBdN)j6A?}v2}LZph_ z-|!I=hk*j-&0_+z_VN)B35ubz=`tWj0YB2_-ribIl6U%PC`cjgI57ZrPjp28sQ$&P zb<^6S?Mf^;e5HDzU$!;ZsdR*cSYWK$QqkhswVUpgoSb&hj}~Id3^c4>fmOS4 zd3Shc3(xMnn)ro+-4V88-%e5_juKS<7w9L4oCZxy+K#-i0~hgUoj&uXQiW1whZZs9 zJAFEQ>iB85D>svD?uEGY8wu5O7IBNNrf{#&0rK*#v32BDDgA0ux-WV&Pnj%|uX(7Ko-eI1bWNWA&q_cA)ja(V((P)mAG# zgf&4)0`)1hhp@%s#T*?74p3%5wC5Z9Eh! zxAAw`+WE`IGECwelKsWx`%U7dKv{Ozy7Co~k}}U zU}k)d{8+riRj#CHyn5%}bL-3)gR~13L;fIsdQpv{Bl0aZ8cT85Rk0wAE5>w4p_gCc zyfY|GlgI8p!TA%kWw;+0vv=PsAt&1>^C%FFW)4p?c;1WysDYC=&(x#-QmC!Lk} zZqkf1f-$gzfaX?Jd!q)8i;|xCN}&pg#!fDuYT z&R-mID%`~RP^=`L{l$c;ItEqxXa7>h)_c#hub0BA?5)OxD7ki9DQoO}z0+0<8wXa^ zY1>3ADV*AE_M}y8vSbJe?)C=7spH55%^+b+n^9fQTXfy`SLdUxMsW%yIR$@@)>c0sv>RwOEOi2i(A(5`_czuQ=6||4LZwNEFYDZPIo*cCXm7^heynIqS8+F z4<#!;KAOkYp!a7B&qosA_?vDOPLJJJ!Z}8lPTpAawYhj9u1n{#y^r8iS`W=xv{?;Oc!J6P^l&I!fJi}*0ArP zqO491aryuWctZ=Z-{+K-2+5CSrG7{vm8?|1N?#1C{C)j05pL%w%A*3?t80Gy(2+c_ zX?l~?rQ0Qa3>psi>sw6=K@S}a<-2sO*5SFbv05Fx?%;}IDGc`_Uwbxz{Ff->Bz<5Htsb!2cS+1X7l|zRu~tkx*Jg?_cn_oY-_t+=0@tx=Qx8LC;;4 zmR$&xTj@@brK><41-py5VKl@lH=O@YS+rc+>lEK1C2zJ zV&bKNuNRMd{an6D5p_N5wADEr-%k!>MGntMUzo&4tFs`{km&G|IX>;h9$a~z7Oa>vgWB5um{W!uYY6la_Aov(zW9kqL0 zbCu-yiATrA_@N=)#6(PF#9;QHx|36C!od97_7ZVJp|=fuv3lcT3>KF<3m7ux zwzIPwsU^03B6}k`!)tP%l@!+BwEg1!E0{RIwsjz7dY#r_pjg@jA3sypV2O^9kkhAC zg>vhrVcA>N{iHYsB;|8XjP#;b^f@ilQCEFTX)TCIy9mCQs;c!5B=rHvL5k3nme|*Sl|4}KTOuG{we4pU9lot*x#D4$@H_5%31_< zcFLr$$%|p4=naXl(vd2-qcS_Wzkz1Fp4Fnw)Qe`McFX5S6D3X)7S74 zknGCTQ<_|h8U@q6rzMBjT5y!b%=+4v~?6O-uz_C9-yg|N{At>5Pd~=Dl5p&7^ zlLcotWs+$zFiuvjw0kaQeIjV}vX1)~S>CSM;!}H9t#*O+jRy$|NTj^;TLV+SuC%j2 zW5=9U`;dnYhab8-i2sGV2t59~gzuTL%qf4i8&o1eRaCrO@%*!wH~?r}dfRkN>Lfd# z>M9;8X3NQ{DOof1>AfQnK7D#S46Cq|`9SFJ@LHI6@zBQIFeU!9W6~)yK8Ilypvyr5 z@>%-m$@5d9OQ}?PxTkqx^&dr*B+1us_U-L@r-fo#{y0{OFaE>TYkQR_l)xeyCEPX1 z6Dn&tmm$~J>(hEs46Cb~kGB!`2ha1`U%6B5(k<%jOD>E2b_aD7^;X`cQxOmO;`m{M z3y3A@Mvo>sc$7=i`W|&?6#&9jpBOA5K%>M)SfZ8YEWZmMf3jDR|`h1sDo6=ri?$NZ&)7lZpopQPo+QAehZ@!pvw(WW)2tT(= z!xnucPOL)8ZmeQk_IbV8aO0 z8768KD5oULw$!=3IRV51HaseF({NIkekKXta<}S|B65q? zk>pQ#8C4~mPo`n?`*x`t*k!*=P?%w(Olu0i@V)2K%44Il#aL}I<`yq65^BT4{sb|a z(p(Eu{;!_Dt#$9*w6Yb%8k=xBjdNUUC+h;j!jh)hT_EZtZl(WFjC(*PwfFr?KKvkL z??j^bQR4pZ&a?MLpI`P)`8@qO@ZRc*Y$&Kr>@8?^$$F}ZghqBFR!N<=`r?#08q)(y zwRT*|ldjofFV~goHtqYgjwQGH=zDaLo$j5)M`(@?J!83&5K}drsxvZz9hT=QDtW%x zZDP7SpJzC*doLk|cfaZqVj9?*!gxtBr!1Zv+R>sHtoTyd-@Te!eJTRXetw-Eh;!bZ zm|wct$}4=~mB?`HH3Ft5TT$c28V0ksd(>G!xy~efAd^hpvwoX8lN;q2#KNkVZ*qs6 zafOnEdZ9cdj6J)i+9IlUlzL-CUYX;?=?G^Qlq3Du4OfqNZkrVGSwDmg1h@H&R|fT@ z;EG;RVn(DRB`Jq#d=H&qDa_`o5h6%Yswa1}7++Y)`z=){*XzHL5-(-y3%b9vOUhN^ zJ8=-OqB1%vXckjhmeVV%D~7CRVR}i>vT%X75!;mFZ`Wa3fB|CD3=F!~mi~=m=%%WbU zPd6j%s}#G{-dc*TOXz3_~H!X z@aDXFh_CH(cJ_@eZWP0eWcZj{6<-)!lnN!(spN2J52&NmDcx{cU2^=oQL9w#cnF($ z?Sic3)S&}h)z^N%h)DEFGpn5K#bp&kk(7$n_X01xOa%o(Y5&dH@|jEGYpeo-ktE{$ z=Yr>_5#&y8M|+F5+#YqSwowmD9#Ou3f<2L^sL5tCS@}_8T~}j0?Ks-zPt%u2$KE0{ ze~HRgs>_G3R$TsQ@Y;DIgqc5!k?F(bi<63Gug|%W$W%4O8Fmx1!O<|QZFljUJ)S?s z`#Hwvf{Jo~PZu<+3*%Vl(h|h-{=-1ip-@SQfAHeYx<a*-$ADy*o-TIlm5|b7L=o)CcvATNeG#A&|J@DJ!?`a>c z^C{gC#%*-a`aZV#V)`FJi|UG!ed=W<@v^)%oP0^n)2S!j)`D8y>pd)Kf z#rCB8TXEdLILdi#)pkZu_q~?Z447g;2(86BGT?_h!PIO0Z!;!Ars*q;f6kLsGWIUt z!-g6WCB|g(M4O4!uIhNcGc6A=k(PKVT9C0#P#MbD4W@r@KSvK2Rt>e&R3%Z=SWIE#s~*}A;KTVONcAsRXiTgA z3&g!z6Y^6zF>s1~vm>v3AokLKi)SuPKO$5LnAg%}BE!SO!GaVOMIR!Hqel7QL2XwT zGdMsWKKxu^^Z56rE3mlBxNP}laz0D=CP&@<)4S*#5mO_e(uL<_iod>M+DD$27rnb4jAXsOogmyt-@&sar5j|sAs+-<(Rk_S>;rAIQ>%!x3> zOSc*MM`gDzmINO@HfyUY9-W|GI%D00uvg&{LM0iEN`fcKPUW`JC?(_Jh z$R%WFb>E+~C7$eUZDjv5*i~VFs(GQUATm-vRzL))6!Km@`B5hCC4}WaqFOBV^SOof z-DVoGGI6(0(=W+#^$3&ix14s>C}w+1Z6Z63Pt_cQz3L};FUC3TZV@jl_Fh*`cJRPeL8|Gu8c5EZa~(l(b7N}vDv zzw4JTQqplm>MsR6|G7*Ms&bXZ1qiwiq5#Y`TtTx~fu;c{zq=mg`SY0=bfbkiz2GP9 zd3P84o?`<`JN%zG`aVMU3g}?ASs`=>dda?%!Y?nso2xH{kB<=!+Y+9qkeR$8FSjMj z)qO)Ay=w;sv;5+T?SZoliP{PyEs|4R3Dn zs#zEM$?${@SZFuBLWo9(st{~z=g@x`;+)0_^&b%v6PuW<1L9v+Q4xh=Ms#!iTf+=9 z{7)0>?&j-%@6PgF%MPs`NuW3KGvDv?w^6ubC}3u%O_DU97XTj3o9Py zF&G{EVA2+Q{2lVhEYx!F(Y6+y?^?;~^*NcF^qmA!UB*7c3t~St1-@-Tb=a zI^*n zT4(q)V{R6=P4-{#Wy0}f^%?OM$JqT2jnRfMLFTTIlb0vA32jNrdl`4mq9U8gav5VlOPcw>glBSf7_ytY!wsxdbxFS<)YiN z)840z*%H0Vx+LAM*979S)s68R2ol7rnR&g{SwlS<B( z8M)mSMANvT)aldSR47Eos!lA`KV+i3ga{|ZKpHISc=@@WwsRzLSq6l{okZtWNd+x+ z2R}0Qvbu$&L)fvBsEEUy{;;#MtqBL+jrM@!Zz}_89{nQM!i*kyWXKWDTR@XUTiUY4hUbTT)hq zjsHPVf^nbl=~QehSGH?c8kvQ`|3lUf*!hi9C6{Ml9U8D?3|not;USPxdq=xW`)7;#BL|P z=&EtD-}Qy!tStNddy{6Y-_p~9nnLHcKNEW{=x?`s&P@1PIg7h4tAd=FNTd1|g3Fic zXl-A4_f>*x7emB~GXEWdo(KG3C6gW;FEgzl#=P-GEu4d;PpEcj%EZZ}y92$9uUn-~ z>dx9^U&*f^rahvG&d@5J=$ee|7seo8jTgrVd#3wI_uABRVk*srYhD|+sGpU&m@qF> z2U0BPP>i>ADnNPdx(D^OEAIRB;<(cv4pT=}+SgaJ-8cJAoK&(SxwW-ibR>1el6G(r zh*2Dn7jY#DrH^dX4MbPcof7GA`-Y`ld#+G}y1?uPhKXk$FmbMe!{4Py*uGFCVe;>y z)?x1sLRdNB26PBR#6Z1_Sd~^vKQgtEc&V7}EGEgm>9crNB6r|?5z$>db<7d|B>8>B z|6FS)oCO42!OsOb{(^#EMEZM^C8rnYrWqOJb0(=6vt<@bcQ#AxrZy+!D61c$ZXggT z7@IaNSX+Swrw%rg7sN=wFg!0%pzsoY{n|`EQ&v^GlHK|_PVeqbcu!Yx^31GZ;8MI7#T@=_paUn zol!hRZj@U}lXQ)#`Q{79kpFO-_sLBp)CN2#at3MHju;`~VVZh}VB_v98zK-cUpjBS z_J6$T$>A+K9o9bfZoy!QGBySt(5W!yBX!}w%>v5&ZQVQ5{?Wn|=P#2|EeJqv)(|Bm znF?%Rvt9q^O|>#6^&0L}XWDzbwc0(8;iGUhhJvJB>>u4(QoMluCg;bpu6x+8nE8ZX zerCnE)xEd>AL`yZEUK>U8y*w^LAnG46qF8WY3c5g7DYn3I|Kv3Lab5R)KmC5s@%{CEbIczc!|Xk4@4eQ!&ULO|*oJI&?g)PUFp1NCqc7nvQEt}b zg#tBeq%NJiT$mPkx*83YZW@_!lKE~h- zy$iEAxWKDC(c4nL*%#i*NiEIiDDv#9Qqp7Vbf(040A^x97U`Gq^c28WS`-j3o~apX z8tKfY-{$(AC+4s=!@4l0BF5|4k{$N-iHIF}3?JWAbo(Iq2tE+XcX)t)N7=;n6 zdJGp^oA%_U0JL|B7@!5`Bnm&NU@S;ByvteqVA|?s8Kkd>sf~LE==R@1=!U?Q%%+$< zn;oe(LOp{+qTgSREi{u&Q0;=i_Y^rr0;yy*dZOA>k!u9Kv#@B?^5O+}4EAN%RQ)J# zX%HdKZ^61kV{k*gXqL8#p^()<;(JzMSWS+4rDyEPa)|T|fri_#S>=^;!@Kx04S+V5 z1sE_LBCe@Zz^VF`tnuJgwMrX5T-y8%E!$Z*yt%6ExdtIBYF76lJKxw-`j2-5Z&s53 z6YXOE*W!B6c0H!k#vGl}W{oqicBcZSbs4r}qY{X+pYKzt|H#sPRkQWlh_##ns29eL zLU-&pxp+=U(9zOs7M_z>(s6$1Km2d#8e8wpUfGUc>5gRZf~(NSJUq(3+#~KP*w@^fIX^EJ0a^5awZ|$>a59K`tvY*JOOQN+8@>Jb{CK#(8C-<@|DP|6~Ez z{u++4-Ubv;P8+hO|N1vLFM=mad<{9C7QLVc+7=rwg87o-zdJRt+_eMZ^A}JfRM?85_K_P z=I;GM&&>`A$KdBTnfWLx+H%{e_ATeBSL5GY5nfwZeewvMpVr-4;M?3!ES|y$&5VFO zl6LSAQakR9Di?Na|Ay5kkOt059m3V#y%PPedW`+5y`OaE9iQcool#u3!w`o7Qh;c} zf-&z}Vx-XVI2YuN-}4|t0YfrZdIAlH)Fh}Ke&8w@7}zU4>wFQpqu_8Bn}Pm>bpijQ zWMTF;Y5@af%a@aN`E9NYm8Jx|b(XysrScr0N~lW?rtn7|TC9edF)^Z|#Byd`@o%ZS z+~C_yL*sWt3&~w#YA`RzT~hoP1KdyeUxkDeby)Gas+1#tNYiT1NvmYYF+%I7KTm%! zC5ZpD;C5;7Su?>xUE>vd<*zw>CuF5(kEcKB8xQV>0g_FLUN9={ z_?R#a#h>X9U7rYt30a@E)v&xfMoPKOG7V{bT`r-Z&sMxIDJnV?tJ$0>*+BX%61uk<||U@*_5^KJ08pfw=NZ zAEooUIhgLat;bcPU}Hmh`~6;KZbup)4aQsCUT*srGuAtQY~!!x!qL4k%vTev4B`3{ zY&Lr)zv;;a^L!=(i^{|Uhf#vV2v=6)8^2j^lvc3M+OHGsPsXmAL30YWJFk(bqNrz{Ov$*(g7y2v?Je+q7D8k^Mm6eYOp0kH?8IZ1r{w$HZ z|3DpZsI|F&Y}sNHMdwuaeJgU(U9T9W`MGI4lDL16#rZh10{5 zBx*PA;IP=hz#;;>7n+$sRHRtF0caNk)O}PGUa`8_5e^XU0I2)+08D-0L;*BOT;Ose z3xBot8)$8mRx!}9NzZmO5ZJQ-r4d8F3-=d5H2@po??>_Se|kVT;5*@8|9))1H{|{y zM!Y7x{}lVD4j5UYqBwtl`XCN4V*&#u+y4F(V)xhSfw}hmr}rJ`{!rk4eShTt2Y(bo zC*$ND2m!LA?f`-bfRwbfw7?y1bq^V6Bp@OJLcBXb&wPf?tnT4rE0KU}H*^6I7?1+; zB+EDBXaPl%am(3iMu5ixFFrnZsRE=Eb z&efJ9gx3KSFnxR;XwqS0D;0Kt#z+CkHBT~=H6&xf|M{I2$l~&9u-`zyM^seeXRhGH z1>mu1jsWi~i0Gh?uxU;Z>MIIk-G2@SL#eH;Eyx2f{PI-g>HaZ7?zsn2-a12g6B2aP z(Nq)^tRMb|af}l$ttM2F-S8It5C!N`IZ83N5`%+8_?mFWd29-b45MYIgFxB#a`@vHrg@o=tzncU*`4OT++@nGCU|ey3 z5pIe?=a!qI1nI3jGu}^nF*=vtjA~Q5wAS$B;1ME%FXd}jR#$Wp&Btd}9h3X%jbp1E z_hEDi9N8nO;_rW?16k9A_kD`v)j395p8PqAX{Vkh(d`hx%DjBwC{F-_*|AOYk8Z>7 zD*oa*$-Ir$&kj@D7ao^djeY`&d`DmuVT9^pqcJiTt2G0W!|Z2=x+H^Ev=gh0Y=1Lj%3vv#1Y)c=#?u!^Sqkp!kNsvM3_VtpvOd`89Cs`Iqsi7?Kib-G2`WJKEotR^E1}T zOsa=(+XyA4K06|p^0=0qln@Th)?>26unU9ia5o52E~3InaIm4;e?1L%nAw&a^*EFd zTiOTd!>XvN+H!Kw#j)FFVF@XY*h})(mQ)EL`H$Lty`{D!L>pMI%Vz}24_15Ue${=5 zrcE(;Ns%$(e;)o#Hs{PRy{E;O@P_P(>-8a{fD5siUcjB4^`>`(a8`<_CjlaYik`W! znNM4eO7~7RQ_~S9GXZ+^$Y4c_lc7cGGS4z@bYyCNJs4oc59~nSR83`IccF-yn)+~N zJ12n8+tL|-^Cmv9KzfR|l@~%u{wwbrNQ7(?F%WRo2EWv~trPW@$aAXWC-p4|^nBW6 zg-)W3o~43`fe4(<^eHvkC+V-_r^G>eB68Dd#qhUbEF^Zgsrmi9FZNhe@m8-dvySD4 zcute151?SE8XbUOGfE?H4h^w$isX|p!Inm5J|EuMZ3u0tmSM+x$=Ejw7I@4xIxT^L z-R>Zm%eLoyd`~a;Roq8;k9C!QBk}IhpPAGr*@Rv_w|fR2QuU8`fpzD4D+o!%A^KJ$ zz1*j9e;jvO@T*Bf+~|(wjb6zXb@RM$)dSNC5r{}ia@&LL^IhhO4o_HNEKwWlyRKCi zb4X}sL4kp*U_KXhP~pr`Y{W5wyIo0YnwdoE&&3S zg@TsvA}VM%&g18~$;ePDQz8uMN3zjGhH@RqFF2NU(na<)OVY_7(@Ct9 z1nstKKE|cD3+o#P80iWuFt%kXK&Byk(6mAo-V0ndxsKd(;dU-~cs7>)S%vTh2ZYTr|l?+_2 zJQfjamTHg^6^*&Stx|)7gFx8H=V!c-)jzQS&tDd`&tXqNrAmy^D@V)BaMwfMw(+3& zU=b2-?C#F3sw4W@wQT76GvP;lUTHr1&VPT+$Iy^kJ#$+z5Y{O@$>Y1*zzbjoiAhO| zN4L}mBb$=MGrxs|prfIgIij6;Iu-IN0k0?4E#QKT&m|Vs%gw{yoxU^1yFq z+`>?&HN0b7z=wh$MMuqL?R(#kb3~F{;tdV_oTqfCWG%CM*;6NRaZlOKV~SK%$ZcOy z)PVpWm>{K?$Ah6WMZ1bF1Prz{&(5thd2>|pvnSrvQEbq7f6L^le1+(A$7_ z%hllaKJB?Z50y2e2nEFsNXkWXRsoEBw)jqc%8?zG-)Ott+sajtx{}qq|3Uw_0}pid zH{jw}SsXSL!^%Q9NlO`j(WpmHyrG_=?P*K~6E?|5Fx8K$@Lbg|HZKh3E|eD3P8)%D zTqVeW?L|OqUZRP(q>L<7UXA#3Soi)2?4CJrqZT#%5M9?5JXpfigr~pHbqLm>yDG`5 zmttz9ByYg%*$=YOKv^*cnME~wsuGHww;u-yo}bzCI3Dx@8@%AaK;pl?@b5N4Eiqw)6JA^ML&7%?N5-Vdmoy$O>pLzL_5nV%=hZW)vm* zafoB+H)$^|r80E{gHs{Xf6JmBR4R5qnqdguG+RG)Q0 zKkI%FRKP=^<{-=XSXy3Q?{r!^JEQ=9!d-F`kT=iIIM1OOWo*1oHk})yUG8#hq_4mD z^XJ=m)IC6+0J6LpCX6p;lfJ|SYK4NOfvStkC6G`8cGW7%%2is$J+qjosHi9?PX*jB zfS43;N$#1oDmdfR%LJT}9rTR#lz^u8PR)8|R^Q!zjg_^taTShf>)baeq4z8!m>OKB5eyR6;-_dVw%;`FUQ^jl{|U zq}q^1aV;4y!!-`p>$cAEksoVi9&kq`yoPzf0axK_mj^7^@gV4GCV&0<6)Y>1@c!)i z#g7i(89Dd9-V2ZaMk!J5S}dOn`cYt57$#cb`N!r8*3d~6U*r^#eZ^XMT(h(zu{^9b z2lM^m;lu&3jCok*AJ544!=Dyi69Z@>mi7K%bb3xjq4MWEyr&)y4-Xi;e9H*zwt3e= z@W<&s4R>~>xW*{b5AL?fpb-}n(_9tQ>OAz9Yd@N=-9yk6egSbJpF4xZ?2Avazq4+9 zS-84t`0i783@;XLcs^M0I)Jss@Rt21{&yDz5iG+}YLvKhcGpKc_VplEP4|scgmC@m zBtC{1YzJ$ytqWH$0mCW;@BGNL*OM(tsE=~w>;GEahF7L3Cgf)bf9uwql*YxzCc0lQ zODQNId#CXCYe9{}%(4e$=!kz06^Uir5)l1$wq_^c2_RPb_^BDI(^ijdFU~884fj z+bw3}roNl~$M=+GPvBWBj%3MVN_d3@QDZm-k1*oG{?5{Sq1x)!L}$*$!kFS${_j6LS2je+@S zLTe7IQAGqb1$ReF0SZHI={xtvgy%$eVXs}~*+3%5AoI{82~urs_a-ft%+@tM3TA&! zCh5RI(^(&bQcR!z#yQ{dKv8=vhGspb5m+hDY6T*RxX7!+hHpx^FvHKXEN=cR`A}mp zIWJ$pOVy(BMDU<@=ZDQMqnOw9S9A44kR$A{?OQ89P@ybMkZd#N#{H>^P#)@>(4K#7BHhV z?@l>Koe?0kQd8w*x#urr0*;iYxZB3j1cWvh$X8Old&Qf3i~IK@J0(dhU!;4acszXD zIvrU*ppSWL4ILT0J;~kAzS-B_XK}hCy;}*qgA1*VA!MMW!6_>%&i64iugKBPlC+pj zAJI@xHm@_#MT1*E29^RZ33*B2w7z6|b!Hs~^Xct8@uSMCZvrXk=)*mUx`+w0ffm3JWsing?B`dS}Ghda3Q&i_nqxQ0C2@qp{n1mPfS zBg>qn5%`5z1i<(o8Vh(_jOV)Xaq27P@A5S@@LvSltL9hZ;sxCX3-t2W-yNOZWm8}C zy)lA*;*}LO6moC=Vfa!mU2W0sozrG~Nad;rhSg69goY`+@aC$Ae*vuv`;L1z`C!IB zAsx#*m%MZE>rC^SLjo{#yWV3A4(bhNnEo~+TD~b<5n?9+0gphnwxems&$B=Mx#SS#Oku)a-tRzuC7<#iP#wCgYRcx7rEL?0Ycnk?#R$b?DV zz=FvX_>h0Lb}>5-0`)TOdav8>zRY|jaMR4@qLaixz$ z@WRq4)*6573rH$=SCcId9zIl~i%w3~1rBuNuAAvcN45|^5dwTA1na94Qz5Jb-p%zW zOB^t^T!>QZ3q2%bc#Aif-}kW6Ac_vL%lXQ^+;LWbA$Yf9Gwx zB~*-M)BYjg}H7U5*mn8=Y%+U3N#h1_Dku?cd#NEgmLV z==v~yx25G~KPRRmyS>j57&Qvg*++oq4+>CW0#_z`cTd?BhW%D6?{0r9Y8s5T)@>9$ z0`q{(=;+|>hHphtpO5sKAotA2DGLXET9iSdrh*{U9X=Z3C-^ShKes)beRbpETLWzQR539>Q#TW> z0TL@0TF4Z4LJlVB^)m(Iq^r}h>ZxCMjkm}2Y?E?mcg`md@0vEItx~^Dm+v-ECZ6TO znsltEpA#pH6$L~ZTkQ*soW*}14f8zg#*}Em9lqvG-%Aoshx~|+#>d6A+nr*;t)dCa zRcDx(<8}F6@oo}9ByvRn$@(ahOBaqwRKMK!g2ikO8MAc14cu2kPEQy%PsLg5B6Y|# z$69EMksMQ>q~50R(*DlLv@VK$5`l_1p!yK2Uvsj$&zPIT8l+iKVk`;b-;xd}GgpmVuh+ zX)k^0oV91kmB(s-e?MRo1N~n>ubKnn2V}D&p1?7Wl;;HWYhJ*&b9OeLtHt(?QU{9A zYAf6wow1fr1__lD%Z@dk0*d?6^&|6X|DoFui^Gfev^qSR^~O1dW&uI0QTXl69WwcO z&s6CG5?XG=0*U;Hz#Fb|PUJL`zYBV)CzEG0lc%n3!&ROAc&*8^ad~uh0XmbDZzn4w zj+$!I$g{C9?iM$p3;Gg_62?6zIOUo!1epC5YLo(&v^iLe%8xXqV%@ukv#D?e&(G_j8+UFdYYM(8bv1BZ5k$W&atzA-R{nV(4rKLfXLAeTyRQ94 zQ`flOW-;20x{VZGFOd0&1OTD%Ebi*7^&wFu273B?zhdAiCo#ia(t!VJlo< z?rYp#S^+M$rTRGCRr8fmKW#)Xi!NC1gps`IX=8EMi+L`#?w??2YNIpray4rgHFaU>1r7>?T#15+Q3uXV3#d-@Rn_fdu3%IUnHO* zB^%G$v9KV(!*jJ)vsl7L3fP_xUK{mxf*21pmE6wv7l9`^+7jSxx-NgCrlX_F$|a$s zpon46q(JehsW}hAr-#%65az4T_Gv`f_nQwnCta0Z;|rJLUzm5?F-0i)g8a|LKMW8~ zsYnn$&zNK1R0n5?by}m)uxN~Cdrv%1jv`S=os(?Gg|yjW5vaaM;}$FcESKiT!X#s;>!N^ZZkVO0+jFPfmM zh~+DS^RuUp+QTk;hv)hvwa(eS=_Sa-1&oi!I8mfKerm3Gy8Y2o?;g#$xjK=qc|VY5 z3_ET42+=zGkWaI%g4q%oevJ=-hYFQ6JE5S?_Ezjh&>J6(;D9#|vb<7tqRyt94Ec~J zLcA0$MA{A&XYq2|WOw3AW!Jgufx4gE=yH&JEkkRj5>%cU6 zcev7JrqC%Ne*e;Ic6R|LWk5%t9}GbtiStM(FeJnS2zq4MfrT<~=JN(Fb)7AzwnwW{ z5TGZlp05f)MMI;frw2=x>;S6FjEt;7NtSYi0h)QRc^09e`Dsf7xjFCn$9Mg=Hui|# zwrG4GXm*?>iQhzYGh7Qc+cRq{(^8*H~eEQsmqZFkHC6CNuw zuj?_;^jXQ8MPK!f&7tMj5fZvj5jdX9LtN%GsJe2NhPmv@e{&SC*2iS7lWA*@nsQ9xy_v|`X+zo?VS6^kGYJh>Kl>cVS%_G&TQvC7o``@uKc|31qWFA0?gwCG`)_$=2 z!c=%Qm^4~%QK?>gen!G)B|JII#l=gSL#CG$ejPnC%w;_Vm$$qrB&TDZ(3M&o_oPC5 z_0TwM@#>fDN>~Sxix-2A+p6Fl$;k=7&^dDsU|ak` z#2;*YHeM_TLly4HSZCA5`}I3Oro$DWQ!lTsfTWBA5U?9jGJQd^H4p}5(^|rlqaG{* z>MuV(f8lvGLe4eR;}_-D35N zHBQPNN6N{F-uaIXi0i*-A#r~}B~ zonrb6}EEpFZc^>WeIR)J=Ks$N&anHckN{h>5! zxGT=3CKjS>{t9zF9{NMPGbYrYHAhj?WrSGlIeCvn4dMIKkN9;?WBG1VLfIF zSF4j~YNvjj!z~FU*_W(@6g6>Auyxo+`2{eL$QD+lL-c!20~S)kinNdX4u<4A#*;N_ z9{DNLUfVShx($bWsWGd2Tlbc!6gXn38O@SM5vhW9aAaF_ENO3Cx zjtf8z1b)5`q{W5+$C%flVC7Xem`>$W_*{Sr7^>fLjJ73MK~00?9W0Zm8G}`*f#C%} zX#)4|tp%G(87_b&F;w+9l3n0#8xYi=b+mqKtsvV-UNcW2Q+yR~(8yUG*YvDLp<}Sr z#z;_}Dx(1BO#T4lXE!p-XNn}b1Lq!e8hq(g`DTG+cafXYVhmj!y_fu1aS4g8tT$7w z!N^v%oN}BMI8SEzkm^5?7C0qO5p3VB+wx*ELoRb8LYps>&Nq3Z&o~4Zby5s^XZwu`7vc*Bl4-q^{YpkaD>{cs!d;Zj;94D zc_WEsLS~U}oEEc1_+%ap=-`oCsfrAZGH6%tf{cLp^?UE);=M><-QCYNG*@;A)<2Ec zM}4J@N4?-f?hn6En3+pKy>lRutL5$%4r-`CSO##?;9#}A(=gZG{t@IDR!yf9y!(xr zqg%k#4*X3gx~<1OZZ9{0i+3l`=K2v6v%b6xFz~EEo(swK0;KgoG9O4)5tCb( zJ8oTpTu|pbKowE7CAajBn2*MrHbT7hM25}s+y}S8lr1IbHC299(;wOLoNkfx!8`2C)E~ULXj?%TO+ozO zX1G`fO^x0#f`4zC^yeJkX3=~25P7I&h`LGxh#>7X6oME6N(bQr{2Hk<8cpEFF}GY-RLz5B zIY@}pq)3ks4lY0{CwN;Mn#=kFt}a2rywD1oj3mtk&?`M_ z@XSRAyJLNJ7^x<1#3{f$6%QRP3V>NUf1#ZM6>RqII|hd>?VwOYUJ>PJwpZT z>nCSMT5n>`Tlc`4oG+t~bcH?`6*rR_k?+L$T*Bzn{vv6`iQtG21CiIuC(iK52pPir z4#olCspzY1Kp;>)k+WEBP88{v{!!?6baFK8AGeg$%Qd9Dh$uq>aE2!tG{mCV8Lbds znjkE(hoXT-3MQ!`T|9*BtA0HKLbs;iJj}2lJh;L$h=qq6( zWXbXxpfcYO4tyLyR>panZYzWRCDktMJJFToY4W0n9pqwZ`M%4J zeNbY5GQ*AJo4%dO@7g|Y_nrFMF7HZSi5Z%CXPgU46#jG`Ar`*3+hLQZ8&^3`?oJfJ zp{`B#&CQLh%$NKA%C*n!Nj>bklMYjEWKYx-3;gSTtg`kmvYVCG5CGs6^b_GH=F8Li zh8LXDiC+?aC<)ap;y7zl!{s4#N963rvHqS%*(dJl;U=%2xjKaIC!agieRSW>fkK(F zRp}tMi^n=Zvu8ztb77oSnFbG+O15^5z)nzTRv>zvfJ{G8u?sYA($jB&ctAC~RnNFl`7)`cp*`u%Jzz1NKqGWjqOtI=4zhp(ez3!f!Jp3?O) z&O=?t=HJifvx(q=f#BK{_ajOTV|7&|R5yOHn+|yikh!-@1Y@PhG)kmu> zvhjiH$U=$DyqjZk8#E#qxBE$XcIgw{=0S_4vWLuko}`D#)-dN()jJ>i+9p13 z*LHxQu&}qgp}DALC=9M)Oc`l7&E^okSfn44Dp`%>z|2pH(zMZ}{!xGN(f(L%*5Fzi zW5)$;BM9q!K>ABgH>60u6W=|74m8YEyJi1ojznI!;bC5PAMKD?+emcr;2*C$Wi>5~ zw~BNR_Q`mx&zx}w2@?c`{)q+9;I5nB9kvjj@Y`3oAsYwVAC{g@k9`iEe!PovV>q4@ zmuoS$7~5N0d3#C7I_TLldy&~Y$a&GK4Hxu`jdXIm#4khY_cPQL4vAGH6O)mgB8$!3K2Do@OLY}u;kh>|3yioMldOs<6Zw@qCR}XR8mRy=C)5yq2;BYFr=EvvYKh&=4a?Q zeNVmZQDHLZ51T2!zf^WQ?M_UuzN$xe6~Q~5&QBcL^LTOE-4M#u6wOI`67Ba2sMN-+ zL40yj9T=;a3Lo})z1~EJm_Hk9$^{X07zH`3`nY&+!Ut@0_Ko9n4JL7zG4a_Ec-PcC zBGV48Reg$HK6g>5@K7Y)@Sj_jiGSUp^&mGH_xW>*;n&fI+ zL~Q4}z9=a?RGgV!yxxX)veB2UsuSqgz^3(J&SaPS6F(0{kOztPi%gHG%}Auu%k~89 zzZw7Zjo)Zt>=jV`QK!HTM8rZJ2XD#dscPX0WlA;EQ@SE4oQ#*TP1U5kaCyufF3P#V zj(RdVOF^)4TL0DGAK(hncevjFvW_!G!0<)b;gZZAP=dLRICGW$O0$mJAS)6I8=xN8sM>~>X%C1L$iuw}_479`&rbk6Yg5`foL!cHSsSW!1C2;sy z&UoubMdUCcBO1ejh>2?+XV}-~(ROp*cUz-9d!jqO|YV4u_dB5^gV(d5h~;T2K0YH(vGxy<;4CMC~YMJz&t;*YUAlA{i2&# zB5-YNJ8e1zeQYQ3+<=tfjb4R3=O8Jmdjr_^Mt=Tx`JoifC-hrXo(H}dM^7Cl?PWpV zSD)l&-@@G>Z4sSj_`DpoF-%sSnt{O_q_BTMIWdA`dv)bAhk+x!zn@=^Zl1t+S3?DC zUoRn|qf2H&66-&&mp^z=f9_OJo#B1iRZKH9fTKzW4F*jxyVH7%%|Z6R0_(c(J98?# zk(5rWu5Kh>+V{vYw-|4QzKi9FU9#CGczU!@K$3zav}xOQ!Q}KkHs4CrP!o*L?6J@H zo_LJ&Xvd~jD;DYf^SsI}aAAFQy6sbG-iDHMxgGaeQm6u(Y82NkQ*Pd5>?ghI^E2AM z`bMWgk%>yr7f_~=WflBaTh$orZfh+WFLmiGs)NSV!6vWLj@{MhIZ`7uL*zUK%uL4x zLBU!JMlO~UV2cOroRl~oKe;*QVzl}(Lv4DPpE0*m0&q=YbzLFZ-?YF`3)Fh0PZ8_Ij28^4V!z zL02cE`yC3QF&ChTuJ3S5#U}60aus|+$rl(t?NA+K7?=gdK8nb+-;din( zjutgiY#tO;k~`bUH&#!)!CZPZ5-~{Go_%aaUcgYRZ2zL}j)Y|d$HS*0RPf1;_8#{| zJ|SXsZ*^p1dd0}I%xrZrEq6LTKEC5Q|LeX64|u=L*)xi+N`LSmAH~C&k}t9vFK`G` zDO3QWJ40Q{pwN+oea_BNejXBqN(L)1YE_x+PL%`5x@{E7e}sh9K6{l% zx(u-CP=WYwE!pmu`on32c&N}s<9(M>1nYxCw3OrJ_@S5}*QU1435x@iQl*dg_ip=a ziLz;<+0}Jzq-DiRb%y&wA>`}{=^EI}{6a|9venU{(Z}uzHO`o+y}*Nt-_OifCoYys z$?$pP5NmSwj4QGg)~`^^X*W2A^Ulh)+ZB^@Zl@Z0(V6+ipAHU;Z+RhqJPhwK?0*5> zXTAeK4P(iurGF2~PO8Zxo_R?18TXGiYvF z5Rky1WloNSh+?nCC=ekOUx%^JKj~a*owsXLlk(P`k!LubSJ|I`Qc6jVcQZ^S${7$3 zAqM7_rHtCuI`#InfDPF!9I^^_FIQIVHjN>pUq;T&Ta#2ICN|I1kTXigU-HSd(73l^0=QJ zU!KfWQ0bZkR|q8Aai9^r8v;kn&CR)ccyL>Yi>ia!0bs@_+dcoZx9Y=w-?%iEPs@96 z=DsNw#m}t;pjU)N2`YLupr^i`Xa$gAKz3c^hY%>BfycA}s_#cfM44gQ@#m#y_;lBJxu3Qn05y)ePZ{Yz`wuz*cKAw} zCu7_Gk5_mP4o*ZbNC7G-d_`30dr%M^P1#R$xfSR39D_^CxifDDfKF(@v~+{?IZ>Ju zuacAs;hiV-d$^qTjL$0Dq0$k*QOSIhDJ(*bg&lr*j~Du%aY;|niX#6TSP~U^Db0tw z_{K>A!P7-XLe|o`C2Vm_p-G``HUkF$Dg`*3{|jKrWXz42Dov5Xb^_8fTLoE9<i0$le66LaP0Sz)C#jMq1Pv0aU4r7^L9!Vn3D;!Z?V z6yn|8HK$BKxsD+8e5|8w-|@}^w!cga$451AwwmlVSb&jQWRn+? z&)*Ep`qg>WWHH@iQbFfTSU1-iKKHuySXWjGxj_|rinD90kmqDf=m1Tglz%!tG26jC0tsk;d_F!MfjF^PWd0ixU06@1dtm zV4&2OkM&28JLZzh^^}(DLo8tnHf@1S#F%g%W>u625bfyY9-G^0y5>!BQNwXi$!0R; z{v-f33Y#gb=2@uP9U;dV#WXDqgkqfTt@9a(5_&NQAThYBM`2ln_BmY-jzER{HR*6GGwv)jeL1s`1f2Bk1yZo$CycSD}g^3CD&d;Vl=%XU@{ zHtqym9T&ge0AA1iR8#jIwqJhwwlgBc*q4LUP*x@rRtuBR)^@JV)Og+2`F``gUD5X& zOtuh0$d8Dxq&qgQau*Z4kS~H&No|o(Vv7oDRj0JuDA|QVr za)2>mZ(^uIMmo;ccB3`(0`vzo(C*+Facq{n<4#@ETn9h!KFZ1Nw!sopRZCBUY%o7J zK*n)=uZXhXj4yAL(8M<6e5&^Dm}hws;+;c{B=J)`gkDpU|J#jrxfeYwZXrV_PUYR< zXi8s$!s;eE2X1;x?8;Z{1&;=9uKZTwmIoj9>LdU#lo-IJC{0m|)3Q*#8@CRo>n5wk zu)9J(9^yQE6X<94VH$^~pWV#F|FFd6;i1{mRsc8sZ_3qrk$6HIXSZXKKhYVz`e(Yg z{Im_y`fT-=E;Ea~jeP_2ya`rkfM&<=1(Y-mlZ4q|EM0Ty&(jv=0yX_5Qh%nmOUnLY zq%@>e4W3(R`WG?9J0NFWNkQ;?@^q3BnsmW!&Hm9~<}|*VKXHKj+%Al0;Z>FdHI*<$ z#u+G;uBv&U4s<`;`aO$wz8LJVbGU<1xhCArw?L|o@N+8O;cMGEEmPr4h2Tf{pQ5AQ zgl}b)!B;7N7DU|Y6ArQEz_q`=-@w|VWv84T{S)}-T@6|8P+arc{YFWo8|1yUC>k6E zQtc@3Aue#z=A{s&zG?Q%cHe}AyWh>(O2e-X)`E*29{rxl+)Vw}p6rd+%5jS8Ol{r1 zuLxuQ)34E;dwDrruRijej6&X8%2O(&*6qIk59pLM5=wHtT@t*Ilf@qM zQL&sqeW}c;jOnSb%2Ak#G;jTVZVX9s*bMXB2OV(zmiofWm zwwcEzS~u>2QtG-fR*kK`;W-^C135i@@%d6tn5V2lVEP(U2X)!TUV3zGOv5o3$pwec ztd$4zVP)m5x*tE8wvYj&*qEWYe%M!L>seov&B;)nNJ)4IqPmm_n_*Bvev5d$!2XhpZBR*i+Q zUayI%L<6+BBZ#K|u9`nz1{EW;lC4EP7tbh61<*rd|HGO8D@BIOLI|`+;ywy?_OQ9& z{u$K&WLmw|&#nh~TbjPfq1t>;t4#(-?7Dv=vdT$LWHyBWTICGceLx9o@c6Yf7z6XW z{3pBh)Le>*>#`;pGlX5-jRfFkq5L3o1TR2c{ZGuu3eJ0;iFdzjrTRcW;_uSbM*@t1 z{N1oHMB67!XB-abvf&)}bI%8W_ktJ?CP262DOxZ^oVgR_=XzB?SLipo?BcmYKYrE0h#?B6EM$_naY3LSy5N+S)flSY?;S zvdN(r`fIKeui0=9TRv>to8M|;eFgtCHb!H3Yx1wP_bT`XFM0!~0Sx73k?*6fzbLVb zye|rI2?(lzUoO!6PnHkpkXd8O9X9#!@nd^i+bWZ4>h_8*x5Ak%0r@@tm=Pog;y@8j ztJv{B@GW2Y09xaN2mYAk&F@dQ-ABML8sNPgc#_>;0a$~2 z;e54)HrOTtFW?UC4h5XXXfSRn%KnMD=jU)<;y%IfYY5vaG|c_8N@jj_Pc#KB28PiL z4E-mcz#$wffU^^$s;GzsykmntOtCX8hRl-PC$84#trnQ?FD<{yf!zvV3{~eL_nHm*b?>sYv*m40Nwrl1BZZlt?*p2}T${DDMbh9HyH>nKe`DA_i zi-;;8V1OxtmtHDtKxUs?4oBX-Mc|tEcPU)jWRSQIWrScUDJ!19${w}x;0Fh(c#D&T zHlB?Uxj=Hj#|Et9H+q^@q5E5)m5IOZys_fHvwwQ$q2MxcyPM2r=mAs2!s5d#weW7j z4ZZvJ@Q`)<1z_fffmTF4Yfw2>=7vVWM5fR0MTwgZH;)DCT2Z9r8_6(rE+UB+k zeMDHAQ{tYX0-;&xAG}rDTjvO~B`9v^2F4>H$iZoLryfmHn9jy!wpbj|lW6qjH;Z|W zQK)!Z)w2$DP32G!Z;S7ln~$DuV2HrqBoxR&`5~L9A^cu8RZcKiE?Q_a=J5Lh0W3ga z1{2blcoe}yZoAEs+R6sSi4h>Hafu)vO=|oSDAk6s|e7kqiKN! z4NqnLb5l(Zi8by0E5!$pIs2WEA$FQyZiIS)9t$3fiC#T^ z7sd%DAPP{jG-QPWqG!F?GdKk#kfJxp<`3dXl_CwxrPv(Ne3c`jpIq*bNef-qHF7-$ zV!G_)PhR`oGXfnBzo_Y`1xFndLFj+>5Atc$KDRLBvA)iHnNp^m#`olJ2U`b^KO33- zJHDxH7Qfn~jfxrtTcUc|J&rcK8zA#A0dm!D_V1B?6;y4VrQY)|t6>lMJI(v$+;dp> zzgBfAD*ZU#h#chN-x;$rYM%u3>crL!(4#Xi<|a7@=RbLbDysiKb4>@~6Y2>lA&A*C zpSs-!x$e-~pn^ow%(oFYv+Y+A_J5H)`+e_QqB|qU=4`K$pB{*r_5%M|Q59 zF&BE>in6P&k-HxEwoZo7&w!ppa!;#sz*P+`X^#ce^@ghz|5vn$ww|e`G=0_YL64B6 z0w;)JcRewIOq&`p(naq~mg-Xu;`5xOtPx*@r`fW@3c3Z7qF*Tr*hIMqQDJbIa^#?}&N)P0Y41P7C4nKF} z9`>%)2zP%<9AX6YFXZag4R&@N`wECt1!)BuI5)zmpWt6o?NNa_8tIrXsDNAo14Gd?;}m?pczY=|@#6a-CC$~c%rtLK z{S!U&4L6C0gaoOxn|N>PrXBK&al~%@zI1C@1Frs2TYEcHYY(tVfovZM9-jRQS^^Ud z&3$Pxn1FHQGZf?(jOGKK*)Z(n@E|6QNz4e_bq1IMu3Mo z`5?GckN%lmWIV?EtN}*gBMAZxI7-kvXIr(kXg0t}$2Cv-oTRT7_aTqQ`P#DP&Un9h z#f<0fjknie6PMe*oG6Ykmi8`D`G*NTD6Mopzm}>JeqzCha@1$F0`Y^&=qW@^3X!u2 zmr59ai(sf;_!?E+#zNvM-1A1SWwM88s5WKY^EkWPO-1#t2Qq5ba`}+bihE=aSk)Y{AHVq89k47cEU9Liz*V#9 z@_+dH3aBc(cH0d|HzFV{DqYfz(%s$N-5pW_(k&(3-Hig$-7V4}-F+9|cm6x>9rxU` z$5z0Nd%y3BXFW0Jd<43tv|U6rqEj3kO;nDd<_S0M<6XmDWzX4OF$GamzJC)K9hKD> zjgbuzAfh=d4{_Q=DxjnEGy1(+HEw6N9dq$UbtNT&*gf^K|O%xbX)Pl&8ULoe&tBZ;cna9p6%s@?JEd1-lr<@Vd8@);h&;|)k}-aw zi;yxoVZG+sogsksqw5=xMb=_*{3xlqEJM7d@mcGTp6*k5j?K=2-K6982mmX;qo63M z9rOACco8)<`;!GxpnGTWAQ&>^?B_{G`5N4wXxwt(OAd2t)^=M!@WRPiXS?ci@~1~bLjy^+ zBilmL+n8Rroi?T#4W@VD{BOlx^|9FC(nP-L)BSk^CIuRR{iYN&G6F|-bQB#rYd@FM z0?UYoj+8u*@&#xvNOW^|_Y8C6;`-J>D)p=0v0G31$k~jYB{~UG*QQ4o4IxZ zVCo;SAvRInLOed7146QMa@yM39v&V%FKHc_b#?mpEO-6%k;nR8Zn=bwzUPEvc$ZlL+kE0(f|q&!-l8L6{j$Kee(Q@M$k4%QrU!4?fK`05@H?rf{GOdkjvRa7t> z%_nqD&o*(Am%(&B`9^+)#LfI@;#5-B1#4^X>mPw^oyUhOT?ig8G_*0Rj6Wntv~^UY zsZq+?Zx{jyF~Is1Cf(nALCk&^PiYY}w*T{c>EEbX73sMXrjmfc z;mUER5NgwEa)5>C8X^rEnBVYOZvJ7~G?&s>Z~UvIpetaJb$)&h;DywTpDZmcL8KWr z_3qiGAiN2~#lg9}nAO#7^I+v2J%XXb#UG*YrC5o2yFy-sT*=*B5RYO%DQEFB>GiUb>4??rH;HGwm~!4V&P zC)lv->+7#Fk&6<*6??g-WAR;GsYk8wC^>(M&#j+sXx7V{XpPUEqPUVuty>%EPJ7z_ z@n;tuM;86w##mp5O^xlm-~j6E*XonQKuMP;r1jRA-48xIzo>dCcR{1h;?-dF<)Pz+ zRO)ehl6H=|$PAI9qM|vcLN?_&amul=UCo=`!zZq*?$RwZI=+jviKTW}hIyxhiyu)Q z&6PERv-Eg;*kpNZwwqI~xexIC7G^(&;4XN_>=AgHsSMv7?`jg{t zc0;&!)wZmG5Zhw^#lZrG<0X13@q@vGtn2kILrgoA8qUWD#G2TnWs4^BOe9H};v$fV z0Q?%5ugVWG1O4L*##SEp!+>f=MZvAG4y^Zec3Bp4@$}sCtSe8L&o$+@?VYg#el;9e z*e~I|H6H^5$v9s-@~^+IV4|#P=k5J${Dw-%1V1~#Zl7W47Fn9ha7Ab5^=XX0^YrGm zvH2$-m#KZ#5SI|*r8O?+$Hh)jh=9*IZ1fqq0@=toBhv>b^K-L{?HO&4MW-X033fT> zB5_tAGKz{yKo=uan3WrxYdVpvA9#CvJJ26Frt36kU{1Dz7B&_dH7j_anjzw&;N*87m~Gi@ z9*qyZ&U;=W?)J|tJ1{(+&NoV$YTOYkS^JCET>>fnrJ-3k z9J++WoZx!SL5au5JKMZXF$*?)T`{+A=d4$}XOy>VOD}7#i9%*uIUz>d#|b|3U_%Cf z>Z(_BC*-H^*(Nl+CiG%#!qRMcH4i7CCH&FRm5Yo%%b0(Is zc|E#3pK~;X?`}EK*~jneoZb%cE7wjBu1R`vH1A~l*bUaU@RPSdER9dK$=XAZB5~O_ zP228wsDg&lhKk_w4oiAluGCSYQlasQ;yIcX_By206Gn-ESMfqQrGVZoK;V;7;H6kMfKKA5b&gKls+J;L|5-? z3YDyI)Dcx=Q1YyW?fzM^-cLB=4vk;R>8^Ibhfp%bxLtM z%KrpTebBrWB&@VsTu@&#y#rdmii$7&l&CK*FQ5Cig4+arM*-ORaHTCZHdaAJp{S?` z^p7PcCkK6-o$T#_dV(+Lz6?s&fY1|usAHzDf3obls+`>p0sZJN=1nuz)zuR;Fhxas z0TBVT>a$vIt^=)-0iml*wIbs_R8dO|yJ#}e<(0S4hw+Ikc z%aAe{gl1i%MCRe!pvt(1hS5S1bTaWJD?!ZUs!&}swVp>;4?=?*Eh?^ zXvJt*RUeeVK~HY9detO;@>NX9b^|-yC0)`tRv$%s38{ujvaL@d@5Y=;IO#?43?AH- z;7Ud_5qo1Bs&I(cON8W?vxeR7vHlrs7uFZl=cQ%fad3BFgwJNB777gp+8&+FVyY0_ zI{@c`bRJl25VE&#fm=kv>ycYf0N=U1+$I`zdiz_oLdV*`z~NwlRULZ{%)k5D)~lA` zp&_fapFs(f)P8lAvyp)OGNp@99R{e^&y6MlfD-@_cEJHk?)wKE3x%-rsVX_Q3EyN1 zh$7fOhyjU;^X&LU)b>3v30GHV&ewBwk9m-vmuJM% zvq7I9?fy?xQ~T56{q}m?71_}*({4$1^Pn*OEZh0M{12{#X&5XwvxvUDH*vz7tAR5P z(EgB*KqtAP;t2F(#*QW%Y+tHc(I4wmNxe#Cvn6oRH z)(b4&-ritgzod|X{LWSezJ64s;?(rCcAG~X5Yq;IwRwWJ<$T{1VV3Iz#s_i0SG=`5 zgucA@Lw>yWc`5Z(S(|AS(-g+9-HR1xH%zFx=jqJ!2e}dXJ0tR?aFpouDID{~RF0_+ zMTWKt1?A?;T;$F~QiSKV1De=5C6W!>_Wn!uHu{HGN$d}Iw=)J6oB7T8uZl3B9>bBL zK(|989=A%clK|mM`E{aFbWFw>`9!I^Cb0br!fE$;r0doyLdm_V?Mu+fU**nkul)=8 zqabFjb`kA{-q_lR)xzAf=DP7x^&7Dt6X>&U8JWkdR{Q?m)@=M{S0{)JX`KFmxAbGC z>2sU9kc`U~SDBXdA#4Gxh|voXBbIVYj>+cs#?K^Q{Uw^DM5M}K5u+=Ga>v-_j%!xBN)5=zH? zn6_u7L6Jas5hGHeEn<~EL~omRcDOn5w4GsuZU|Kp2|VdMCZtA}espI=iZ65JJMSmY z6d5YaE{us#VmPRBw>T|dtRW08t~HPoZ2bj0c*X_a!3Gn3+9^F@X2_HB{g5a6$(UHg0Tj^GQ$o zsV#@glUUIiBS-5{7v4sIu1`+~36Tae&Ez~&n^l^T`g^J$5h`g1ad5WUhQ-mPL%HIxoPYHdw@KcWNobO263wNU zH@L7OBFMz0yA!9}@G#ZLYX^WsgZ@<%8aU)ZZ|73o;pJssO3K11?h4(G!#{tZ^?+6K z_xFF_vH=vczylPbp4pG!U^gAj&<0_+elm!uWz)G5S|~sRXiYsHIy&h`bp{5VRtO_# zjTq zWYP?b;M~fuI_4J9X%TFH(^*fH&UR0uPJQ>G#7Ie(Ckc&WOtU-=9PT-m_M&UIn^fOyYPv3}ogo)c=(TllPI5tNvU60(Udt$Z^64hvR8f>(Mlg9Hw5LIZj{aP1uBGDT7 zTcpg$n3!L};QYoV78-O!%rBNZUO?1vn&!W_MJCH31mZQl@Xn`XBY`kZe6YzjTUJX{;1;)$S;}MHV`D5&+l^BwIzQ@o@&RW(SCQiVJgxaX zlKj`eHGgu1bZC3$WMff5keATi??}(B_uSQF>jN>27Ab}kkbnU_Nk~ccK#%aHYK}Z6c6Jb!_y+_C_Ip=# zb#*~~>G=a}rS*KZu%cp3cFCHYmYADT?b+8=KIRVQqbO(R@k*#*bm8sD)(vI0yy>e6 z-ya3RIHh~pR|UuT=-jw`)zm?9q_xcT4b1gdrB^=AJAYegZK4f~EH=U$P0_Q7y_~GS z8NJhv)u}YoPdu+2dSy`3XE@Aejcf_oWys`Huj$O!B*~IFfzo#`5(n9y!TI$(FA{B) zbwES`l0cG4#k<%g*~#DT_~MN*G2&hLuglE!TeBxvs`iP`9Bf^R$#5u&?LmMS5NXQh z#E7@jGg7rApOMOLo5AU50%j9*YB3#3{s2^sqR4?((sQZ}L_4F&A94gk&}L?4fE2us zj}Kr8Ym0~k7ZsTUt0bFF?Py5_+*>fV<=QQmskZH*k&!cFV|K2tnLO?e{dh84V9X!) zN-A*ZG_YU3G&C@ns5Tx1eDoy6pWxj=epi?lXE2y;;Cz1;-R~o*or42DtHl(UWt!%9 zd>|FiP(8xz^Y&*6uDf{spLoU9)u}o|VOhzJtU66WOLlwz>&dS54fV<~JaU(>56j7S z5|kM}ytpdV2^(QST+LOFJ}0W9+XZ=e?3ZTO^RcQOf8mbx##svNnIXA+Xl~ACvN{&k z+DD%*M5I*&<_CJKOFxoQQgAuh*(Eatg+v+%m;CsYh0^trRBmnz!CH_4a?>OpCQ%tY zK91Eqx2uldmYKX-soxcAtLp6R?0d6`YqQ@}9q(l^5AHINZap$0BI21WjFd3^^QXZb zkhW+@Vqz0i>C4WWo|w1=vR#0ZzvzIZa{dT{v;?jajW>!ER3Hn;d9fiYTH~R6^%UG| zAGr6N2Bcjqw+eOFbU7a&W2P=?GZf|irGtJ8alq=n$N6H6%ryB{hIpdRd5nb(R&S*_ zz`6noRz0Pm0L2BLx$H4ez5mLlZmBj(Gy477ue_~&m#x-Nw`voAuI?bnKqxZsetRPb zROxicYV=5Sm$o-IA65~AVav6ephb>*aCIwb)e?=N5@82F!`>bKeh^PI{*m4Nsme2q zq_ssF>CoR5T|(UkW9c8mJkWk;kkC%^B3JJRSx5Bn2%W95UQD$4YG0|Z=02`06Fc?J z%a;gsP?e>vlGDuZBUd6;jl)*utays8Hnggu>o+Qu4@V}LsOeT?UwfBA(ggZN`K*bg z^+$1V+B7wGEpRi-WQ!w#%aP=A!6RCSpR=bxDQjI~TT~vR^FVQY6uS-k^?OR2sA|$- zPIF|x>}cjrN$z7=OHD5X!(tzg)yejLQ{!-7tgtN3?jf7w1DaoL<@Jki!OXZH$YS!V zQfj}SI$H8c0A6g6fd5BQ3P-6-9Nz~y&C&wevywl-E> zB6$@#k{;pw6>6ivH+zVzZrMGMK$o&hA`e}4sQ!q#yMETMFD^ua@8=gG$k8Ao$ZV@W zrWzmB7`=f00rbqcU6d{n78Z7aqhItXD_?A^C{%rwZHD|dZ}fEqnY{=HgeYL)BK-Y^ zvCr1&!PTF4c0Qf+Q*!ln84@v@dEZ*NjYO-t3uPhXT&V*g?4JnmASQX zE`YZ6xf6K4@{4hPy{J4ZSMWslXl`kVTymzQ*(r|( z9~U%=0?K34BO~S1hz>N@j86x-2FrD_%lhjZ?u_hIkB5IhXlx}$OXS50XcNHS`3Md# z_BHg%T%4af|0-#;nvc@J|9nUc)}i|A#5os^ruFTUYi1Ort@4aCrXkJlIN zHFA=IV>wMht~4}Z2nnHlmZ0b>u3i)%o?cT!KTt2G0-wjg+r=2MRYvPF;(fy2Lrmq& zX{H=w9b{^0$qkgI6p}ucP|hRqC5+k3et?t;#hxC^93Mu+w(^w7@RsPjW9^3aT@Krf zbY=-!PSrfODf+5YGPEJO1||6pHpQ7Y(QHrYG_#0{3+O(Yz7YWpa;Md0ODYcxnJ`n(uT1IQk^6oA6w}!)Leg}v1 z-Bk+1E6OT!1{<>&#rsgGtyREVs}dYhg25>Azo!gs^4SUoPX_holelNN(K5}(>m6%XPby&+(;JSk z0PpB8=H(#0aDqfxWoJ)FXaM)zrI}4uNsq0l+n@b;+~Xs&kX%lc zvd*rsZfomLZLEzyVrEH<7syV97Zhv-Peb8yv$INSXv!G+&wo0W3LJD}tlK&rsi z&aQKi)C%+>tv^8Ot)6R!VF(~3B-|QR{qd_&%e#wstrMw|Wd2wRN{tGw^yA#y!s7N^ zETz{!k_fP&-R}N`W?33;#tZk?vIcp<2MGo1fBcm7?Yl2rwhjs^Dmo!YCnL)Jh~Bx| zweAMo6P1nu**${+_$gfwet3I>wP(`vZXx1JMKsbD_vuo&Y@>_W)r{{)RC5Ffbm_GR592(!UG z{agCQ-)BEbPX~%NAj0sxRGRO+$-Y?D9*9gr%0Ioua_(ldaZH3gS|+srgBz3K(={(S z&~$b97qpA3#tLoEaf}mQ#p7V7-QHRVdvYZTJPrWW&qz?d2IXXsbZ`R)GLW_biMt@v zHP8)rV`B=qhd^)TjJ;P;rmn1AA}%unr`6Ih&X_<+8{*u!%sF$T?n^VM+LQn;==$HBCiMv;Uy|%3eHsV1;CPrVc9+~oQ~?g zZ!%CJ!?duRC1M&WcC3hP5I;Lp$XtqJmR2F_m;O3iRkf~Sn-BS-^tr8#7wM0q;~Ch} z0;n+WH9;Sz^N?ffUiUeHE$CZ6wAGg1jH^T?PmUTO4AVgvOW!`#JN)){ck2>1&8`$_J6Pd z0jqF)&={vV41Q_sF_V%6|-0bz|7gD6wo)dOTU?*@4N}Tl|F2$R|zyzdoyMpY!hJ5JD zXJALJ29}vcN}Yx6OmUlX(uzMp;=DV$i4d8!Btft23S9xk)I=gqd-$S+&L6ZniL&$& z;1+zeB#vV;v$V7YUg}J#x-Jmx1VE3;vr?wGLmEbJM@M8w#~L8+Wj$BL4nk0mGHhKTmSpl>-tz90#sUosymX@{K7)>Wht9* zJisV`r4Z+KCvhD^qFxk;iBLO4OE9d7_;I#e2JG?AS5^k^vHXMc)%Ve6v^}3ca^t!` z@c&8iWM~g-)V6e(X~ezXUo}>Yna)6@3eU=VW6dB`jQosRnwDLM)lKqPX;p>?6|}I7 z7&<|<)7Z!e@3Xqa@C5n zEL9{8mMYIP76Jfw1S}A2Ff{L3eU))@Im*RYennzjh(0555~k|I!_mE5Q!jSL1N4*o z_|bZ`xpK%!%yk?LKy)4BOK5_ZFB(N$Opo?v(SJP z8A3XY?J6vD;Y?{p+Uwhs@rC1-FZ*o!3w0&M$l3H;qnS|yhg^aPYcLnjm;3!kbmUgV zp3be8>_SN+5^o>A8Ge+V?$Y8X@8-tqkIN>3(H8z-MSL+xW_7~5o!v{-B|+qJ7hExY zA@%8qt2A+JV88;@Zg_Aa0Um|WjE_lP5l9>ZF`|>pOBZKnW4GU6OC21vnGAmeravkv z*q1e@os6igoPhjdiAzvXS2W`ec~L{M?BbdR9f0nTvQC2P;=e^PoL^mKG8sz%R1Mat zgPq-6hi^wxQWDlFwIom~5>fio)6^0N{dTZPbnkoSks=971?(G(h+nu^*)}`8O#dy| zh_g5})b0KSJi4%`sHdmr-QC^Q-+9H8roK-qx{~lHntmb~j17uj^!*>)P8ei-(BDs~ zQpfySK^>7Errsu2QB@i%p@#+dv}~2aj><%Z#mAptzoG!WF2Do<@S^)BJvTH$HJtXv zHP>H1e!O91l)Jh6(D#fiBKL&}-i{$E#pb8$&FlJI)Ltrte|wb<&n;6Rn%Gjv6mSnE zGr_IAj|CStz3!CsH(fY zm0TNn^&JE9wlmk+&IT=LHYuUHVq}GT+_mQk=kYq`I|ikdjrb=30W5qIh8*f~1GFEZ z^v)3w;-@)ap}!KJ{DT&{NP+d26X!$N&xb z(V-oFqB>bX^0x?f_%G1ke}R}7UP=$>{|Cfmm@UrP__tVXHF=Q%+UrTm?Ywx--CyoE zQ=xYWCk*P}VJJqD%e%*KPTYClTW=@GFqDc{TQ!D+O@9MYPY>izMlu=X7O8F-A25yQ7maayhjwgTK2pORxwX z=>;@|jA&SA(Il*v^@g4Ttm@+LAeZ=lZ=r@u`&(f%_JE?|ekwkeqwRjtEG|iQH<=?^ zdTMP3`&_ko+i3Co_Ea=`)K$7QtLt~`#o%K4aHgr&+ji8b zj*f>4RZ|!>^OG-QBa>wptv_by!Ye*0#(tzMT&;*$JRT92btrlL@)`9B>{EMV)WM_C zlY7Sp0_#P#4PFf-#GaHIw_B8xlfL1ANVK8hH8prt0=;XBF*y-#RT*#51>fVGV4NW< zxm6gVkj|XcpE%H?Ut~Ng*PZ%yebqy2=icup(pzt#S6Nfo9-#akZYh5{U%vv-RC$t{Sg~N{44&J`A*rDhj9)Rq9>Y7HKh0y^RIechM{qY0hzef1 z3nR} zCI@A_?#xD0l6ot|Pm#m5nOsXIEmrh^bas3dGuUMq(^=lf2vI^@8pHW+xV$et+52pV zM8H@Z9>GzO28=PLod%TCd$Hr9BSFnA=pBDFv!o(@dvmO_I>Cs7U*9vZJ~l4;TYBlL z!Vc+A{MW^OU+x)i``>GWJ)Z?$;&NA{XQH0n4OE4|KU<-H;aQt}^(~R=C#tDP;far& z@DM?`p9_124b+Go7j&t{L~gRseyIi2$4WXLm&->o#0T{|yZ*>QO(a&~rb?sDAxGzH zPo>VMHo}6h_GZjq1wycHR+5MGS%!Z*b%XbgO45JCxE`KIj4 zsm#K_sLvhtA@vtfzpX!OvCCHP{Vli5%zRJpp|JX^wx<*dm4Ejg2I4C7Di&kC++bp`+4(lU(KL9-QWE6EMnC)u%JFs$%^9{Ql?)9w^}hb`xr zQ#P(}AXsP|*tjza_hrV~3ggomlEo8ZE#!w^zW#hFr+!DDcC%+1M0+-3=skGxZ;|xq zVXaA=&g4?n?E`RYlyslR{#Dpn#$SHjz4x#}V%}}`TeOdS0V{1|opq$%|+KmyKqO>#LQoLMO?V1V(nH_M?Uf}bI6aMljdIi?%5$7sg>;7aX zsB}cvO3x|?`D+yz^p*}4C7>woRpM+fWexy^JxD_QjAK$GzHEO%4Ep#bMsmzF%-{@c z0)>|Uq~|O6m{Cz_HNX0J+aK~|!2UUTiH$9wii>u+vkrT-!Wd)wxt#2u_mb>r=N=pT ztgLt`=h?nMGEa_Xl6GFEI@(EiPud|_>V!s9vP*w zbqND7&fh}7u>r;a0~%cT^VjE@e17{t3=o-R+kip_93(VUVwm*<=0^~+Bz&Xtd)iAS z%$bsE`UhnDA7n3xrl3ecwxkIz1X5Wg{{zPXg#VfU7hV@&dU0iCWg#3MgbGEm)$t%_ zaeY^s5I#6%%btt%ev>kx)As7F6tERAUI!biD<}C!UokN;fj$!8;9r|0IotlMe?1&! zyw*bGV+yhiKqmzi74>Gg{Dr!=XJprgZRhcQ50$p zvg_u?5|Eeor$$_=d!2&A4JhHEbY1^?0`PA@2$hJKm>3_w`1l<3 zCP+(5TWGNDa62)eqoWHd(3JOeCBmLfA>!;@%+Eh{`V*U*DH4a`M~ED_RsIW zEk2J!>7uM8%-zygSLx?eNPV}N!zMn3S|^@u^BkT2^M=a13>#@@XNqE+V$u_!8B|b{ zV(Pp1@~Q9kf*0P&vuma1KK>6&?cb{_+G_>J^_v7aIl1FI65m$08z%ZUZ`jyW)^-;c z78cahSsfhjjCSO}yayG?S`b^ry?9=(Uru?w&dv5CiNyQ+?~O4Do*#F=$8*jeAJ4Xi z%*R_fecfa5{TAN+J7f|UJNc0->`X}q6rKCpVxn`rFaU_IF1zxMvE!f^kB(Ww2L3vznM2^KaqV}szfKKO~Z*Z=w5o@XI`J3doa z!GUQB-(ZE1QeTuQ_(v--npapN6M5d+Law8ulm>k8(|12iy$LQ3cKAB+i)T(s zAmu2)N&f5TUhJ!qcJ5#v)sSxpYIPm|U#@Pp%0IKbNkvKf!Vj)oVz|zKA8frFj9JFC ze^K@paTd=mC4ziL!Dt55Z%Y8Hr=?ppmF^2^4E`~h{Il9_UOrVx@c*zD|4!lmXMtJN zf!Gm%K$NtR1Xkp&1C&nq+-fD+<=OA+`V;9izVsMe{fY=dCAQMj``#IkSQL2L;dblc zIhw*MX&zLR7ORYb6y(v|48&gf9`0NZ=c=gtGjiT1C6qV&p0ehADrTb3)ou=LUaOPl z^L(Ak5b1kzy15G~U{3dLnU4>z-&?tUDz5t?CY2ug8M;&>_;5K)H{$EhbM?ylUn|;U zGsRkH-feA?yhkgA@|##n@%Q)lwGFmq8){=ACD4P_3Pmh{mvVoxzs;b-<9i~Ypf*=# zIV)jAC$|v0K0TI-L3<(ciEryr;Lg9N;#Z)7x~>|>?^NIKc{yRHC;68wVhKG#)!NPb zUxdOVA{H$z7sIi2li7oU8XO(j+r0@Aq*|QfqN3}>>3BWwe$}ATEt>5uP%?TKvG6nR z`T$gV}Z-}?`|yx#Y7RY+2qQy(LpKUg!l90VP?uvjBG)?6i>o>grTh^d$A$nSo~ z@LO;}LL+2DIlYL%e!hMR0I@kf8wFpAmu8RoeIJxV3oH;lRljP43F@vF7~5IGzbv^* zLOQLq#>rLiYA?u#4JwpIRbcgf)$g*Kp{Hjzy5iH=&PM{6C!R58jqQ)%LJ{HMzzkA_ zluB#NkgSbgeQsL+*aH^?c>yi`w&W5J8XOK9k@aNmPeg%maM2wJ&HCG1<#zscn={)wQ8$Sd?61{GWlVsA5SAQ2wQpnn@w%z?2 zPR%DL2VKIg7xN=%G3{**V+?!Cmm6bZV-0LfX7U`jKfD#Su(TYs`K@q$c6}nf>Puqx z^q8hzQ-83eem=1V13xr8Oe1HL2-}J6es?*}gstqrfjd}@d;c)1+j`AKmi_&E=iFRl zWI)$9<&yftCHKv}>7cXitDTv$o#9E-(UJa<$BXSu8o8~#08G7n2AqqZaV3pjFL-;Q zJ0FmbpI%$vw%*ChH~NOx6v&c195g5v$l_w-)LSomtfX;radCAJb6+N9>VoXfB)Rm~ zaEjrHE^-!}dJkODw?_e+lD|zNA_EJ#1Oj^HF_^`blCBaKdlLyXP`SCecJK*rQ%!S^ z5k*<@%BdTJ^(XC+x+rs$7g)cck-mE;1b|HECc<@XVcGS?^rdBtrZ^Blg|Dg-llb{- zxU#xC3AytOV;W~T)$`(S3IJZ*g^)Bd11PI#6p8IZu6Wg_b9kSd&6$J6dN#HbM8y5} z2R3T1Z``_SYK>mg#r!hq)m8PxY(`(|>Mr^LrlQ?KIZH@^w!#}8jmPJ9s>#QjhNk30 zj)*-)?^k?QlPOAV?Pa7_cQPL#5P0~Iu*57S+CiJ8R`gT*=m9=q?Nlled` z3#+Ksa(e_)uG67&{`fmOdS_=xhu1@?aA-O_2!`AX6%sN_`Ub1Wey#|`eJam%Cc^ILn-fN>#xr5o$jw)*`>ZY9sLN{XSa1Z zoGJ<^*nSLv2c2C_q%(D_W~Rz~pO)LaTO#V}jxG-#ljzd{0mLSLx(OLq2M*SGZ%ltT zTNtIQlD5TXGCvi-iH@(1W(#D;v7hhV^v(rvu^_{#tlSQN@%*Zuyh#SBK*KArgIcZ* zV8%*3T@Q2bjVY%SK+BHhMtw`en%za)VJYcw9gDR!eLcP7os)HtdII3{!;K)xB*=N` zxcwVH`Y!t;9%8NTLw5{>=(tb@bb-+?Nv$K=jg_XoXp+d`W0jRnx?U$8C92j|R+oS0 z^o`A5za-!`{`D0QfNE$pYo!$eN}a%TX!Thq4F7w&DSIRxf;H&6JBQhsLm^Ae?i63+ zaNh8B}(uHzylVDLwD{b%(8 z@nCfaF|WtpZp1|6^!?eRi9BRKAkpK9OP_XiMZ)W_kqppGESpVg0a^9MB6x7RKK`MK znAe05a@j!7lMW2(ZD}c~{y2bmtTy!ae&A#_Em!aGna$uuu{-z`@g@Lnx=gWP?rn|f zP-Rs;+}P~m;?qPP#nVInW-~q9&9$9$jDGSb7`UZY=l#8l{hoH{?U8Ri-temNw6%1U zlwyFd$)(M+Shv4gp({KnNBtCz3nfL!-#+Kc2#FD!s`9=ASGv^b94<-C&VIFUv40pr zusFYf&> zgcb)E8`}(L*D4!MeHX6i&joTx4Cp7N8%1P!w40KW;(py1<01@4qa-F^U;w(ZK)rka zo^!V1Y5Z<5h3%m8STbD z_THTQrDzOTtgqPlOV#7Z^K=dtn$EyBFk0Pduvx_k?_s@rU;Q-(7H+6>`~osoN)z>( z)y{bn&B#}u&Fa|4Cj5JChfmQbmF7B9q;|@ZXQo0oVWg}AMT$G&DUfOCuc=} zj=`@mS_}`5db*hVKtz;oJ6lFGGd$BdeX;1gZ!(o z6KXL@SE=1!G&?`Qp%zP=e94YqxE#sgXNVE=y1k&eST3ncPzEjp^7~k@V(m;Ntm&%b z^4Rb!N-P46tMp$gD4a}7sA-TgA@LK-X>5VwPe>FoD>F09@o1AHXk@mzG~~VA?{dD@ ze(&JuXv}UG9<;khY3tuYo#=lD4RC&x7sVe*cb1A?4pz_FtbC0K_r$@QYcdo~XChCW zc}E-0dv?Nxd3O182s#@@Ydov2BmNq3{rWpHgpr+@hSOJq7KcHrdSmWnUFKp>I)kIiHnh8@fvK*po+;Iu|1rt@p7o*^W-}-kGbRSI_iz>YHT4Nw-DtD^_zME$ zVsAQ*!m@tn)-6G~hl$0`9?A}!3Dq{g$^CU&d>;PfNkUpZE=wiMOTr!b*T$cIGb10| z8qTONqKq8&o@o}-s~}F1(kzhf@-pe75%aa0KX?Ea|7}jT$xy}vEn}s_ZhRVDVL?HI z^V!yECcr(Ca9b!<-6+EQJaY2zc+Ew>iKCF&7^yW|@!B0ofJY}_aI+lY{Rz|2&9DNH8&;2C@&ws1fw#VlR;RnI*+qBe6R@E)_zA(t~=&mMlLb(AmL!P*sZyYMpYp|UH;p!2B%rXMlkh*@9P2m0p&Cg>Y;0^GynsHu z$OMwt5p~XHYHC(mY3XHjvx7P{Z9c(o_vJcX2m2yIA{KL2S<-HxTDI3)2FH|B4_1L0 z$o^F9sfDK{H^$4xmT7#Yu7*N?vd@tF{ky4^6;aGic3D~EH)~dI>rD2UeB8Ytq z@j4O}r{-9tLPV_be0UNA%x@f>Z5GP~B~?}Sxmd~!!uXw6z!uYq7 z)oQ!vY&rO!&Ra`O(o4(W=!=bu3-}z+U_1X)8dnc5-!h55HDUN2M0&YpdGAMtUxoJ= zOG8s~)~47_skm1;!>@Gf-C$vBn+Pbrq)9ZmH9hVKj64`uFSiL+Nayu!FO{4ukm7Vb z`BQRyJkM-8AaGx<-K^E(erEHr6Kq`IfYG<4XnJ(@^%Yh$Ty@*8v#_l6Ad|)Hq*iqB zorc$OK_Ix>;zFO4fcXTD3Nf#{fr$y5)A4WM0EhC`%ghg%PcktxAMtx7rzWZPRIEuP z`FAl6{k%CNU^BD3yuUH^_ebecQ`d0Wo$8hL+-6`0CT94rE2jJ;g~ea@)K$&s$5vks;&0Ps7otyLdCMX1Br{>!_IM z9c-0mc|~VFBOyw$xGttZZ^7;Mln5KTvZe;v^Md+zm|z|Wtw%^i6s9mTyii`#`{<9c zR^u0tI4R1!X?r)iuwi?*ll-V35udrgzlV?(%yhq-%y zJ<8JZ#iwxo=!A4OrKM#uG2iX)$rPTZK5Bf{yiGHnXDv}ls6%`k6H+(WSercfTKr09 zRdf9N8G2_6KO{TDYQUX9t76lF=q>Jh?3|{M=g7L@Xo-r3{{Cu&=&-(8L9P#C!6&Eb zU7;GKKqinP|CZ4r5KB^UV8e9_1yZ3=X{F!$V~3-0sD!WPx8fF4zL0zI1ZhdHml1r7 zSz8g6pK?(VW>8R7P*5fX#bUTn`_|UpG*v-jV}&n>n>->TX$Mz)ujQuS7jNPDE2i28 zk+n6Puw&__{~pQf(UL*nwy;fg)o-x&zkzdfjO=92jEoI@?)aKi?hmR@4Dcuf8xkoUA3#t($eaIA$K5_oVc* z5OeLwYDr|HAG7y$lt_8jz|jfV(R!{;7-Ed*-5(kg`AR^WKl|A*kRGO`dg1zMd-_Q$ ziQhiGzBG1RkspQ6UL9{fiGKecYyof?(goTjMp!KNQRITQlhf?(vY+=lAfPbzdQrk0 z?fY`rN-VF_jGFN=%{{)GJpf5D$+a)UNzw5tf_kVYp zwT1wNq=e^nUvk?;-Kvu!ulr>fkFgHRy8l+Ip`%MsO8{ajb6ae3!ok>ephDv=8B1Ln z#ZB6S&5~0~2Sb+xR77j(puXEbsv64EbZyPc)XKwgn<4td=v(t3?g)MGtIlxBDz-;G zU}B+B`@G!Dz#TSN%l5M_TT!o0_GpspIvd%wUnC9*tD%n6BS?Q9S{z`%d7~Bhv9gjm zQjLaYG%v5H;bE@Pt)2(3X^+C7ftM={go_r27ITeW)FoKjSBLo|rW}G$T$K))n1#9i zq21{I*oj=uVp+EzEio|vf;=RW+@5RUoF8);+;gDL}@n ztdpZ6C;Ogvk-ZU zlB+_OiT7=pIu7oNOgx=b8;5Q)YYgv|FJ)XHIv~;GM*T+3P^V9G3_3AORTXZ5z<2pwqL4~5q`%8cns#ue;j zZqF99y0V#RT8GAX`z@3fw{y%}jhuG}nTQh)4ZP6FvBA}0`tpz%i8KdAUj>NLK;)9Q z?5%n?ty=QKqt`aoA3l*;&HqE<(XVyMYW~9~8-aB0JKCtbg-~I^{vG}!N4~{#RM>jR zLd6FWUI{_NVZNVi&c0{IFuP?jQc}kcBzB@9S{BtZ)N{*8NggQFeJ37Hhr=f9$8{|k znegeF>Cg$ZaRlcg%K))<89QRM5Ku9-#DBTls%kVMf|-oOe%S&hWQvO)Gi^^6|6#={ zLLFA)LH186BO{yPeG|TG($ZG#;gx%971N*ilLh(T3B2l^2@G+S`}F+2nFsw^)|Xm+ zrVWbLGcxuB;RhqUzp@=r%Hu;jt?l8WtF`iB*Ir&MD>y)?x3hV9>ErOPi6ifZ)NT_E z76Qh;KeC5sOSG{FN*icmV4RxovSBOXP=3kemBCalHFL}P{^YmALt}!Y z<%!MFMdkX^AHv;)Nv3y!gl@k3KeR+zFi$ zkB}_tGiWwv&&4q3Vy>-@NFb&q5C{z{CB2*1yA`j?t(9eG<3`H7=*r(+kL5KCre_dY zCwNzEbiQnPbIe`$)Y~gsR&!{bY%yW6z&~@H)f=`5n=b$(Ab#_i`b+sHmaD%%I~7I? zVQN9*{djoxt}ZS69QdvlfQ&?x?c(Mdw7(tG{eY0As+ykkeDlv4o47fs5Dp5m2Pik| zVeTn>o1`Qs)4C#*qa=K*|C3ME`^qmg5nG1AL}u(cma%@v%#VcKe_cIf4^`oxD^m7l&Pk+mLv#Rs1D_J zqYBnP^W!x&9l5#sMMYl@W^)%7Vq;_DlEoQmsQ5x@m|Q0&cXxIpz6w1}NJ;eE_(INX zJ^$L=U-CJQ{YNrDzCAXkR(2`qAj^cTcRud+N0j8j-?p>J0|P<*M^#Y!;C1xLM!E}` zi^2*3-J_yvON{mkRYQNarLd?6N-9w8=l~z%O$vV7i#H)Da^7MPrGN=h!ykH2I3R~7 zhri|d!5HF4ygIgi%n^oNpGZi90F*m(dL%4!dXK4t?cznaptPL$ z<`@p{U=8x3R+b5k^$m|OPYTfzf+qztl9BUamuzg1NE_Sjqf-r9HijHn#ZS?2$;jj2 z;qQT`9g!tt6=P##)%5hr$N{=1O(~p_FeqAuU-In)ev+UY(W$t%i5^y!Htf}o{>=2f z$Exak(+hpQCo2{%GjXFx(eN z8Cc61#pD-&_n})i!^h0T(Z#OLzMVp!IUzoRaZFQ#dUIdjT`GOLd)?Cd8ioL}PPc`-&pP)~Ksr>WIt++9&-gxDbs}^p zd**lYX4b-i@Md=QoSG(nbpfDV6hUtDUDPfazgDOr0Q7Bs^Y-)G7KxFUAr~O7nX=jw zq<-_R@?0&aI~~0V=<2E`RsQvHb>4t2&cM^t4F-!-mX?zC{xyy%D6j({Z)MHz*$?WF zHrd-Oe_YiO9hTib{g@%*}T? z+EPOKnG>XbJ0g*8uwFVqlK7g7I)o4Aeln0L=lmVlc&x?YOGkU~=6`8BAuV1eFJfa$j_zhorix)H-mu&Sb=p`DzZ4D;YrK~#O|{dy4s z9AzZ$dDZVj-d7Z`v9PCP#9x3UAWSJnPwP1T&VyX{<1mAwbwAVct0!TAh7}_5W~qw% z%%agLlEb4z8ynjZ!+fr%$E&IPSKh~$#g3*GH=aWv z_Pnu>u7!tDFb?60LI~uCZp?8r2;}9pW2Q^JT~`A_UhuBo15H}JRmC+i^8hM^Lp=!nwhh3 zsuBVcBiU6yc}JpGR%&F4U1r=Ozy*XNms=)IOVc zJ$A#kQ&SUlP2n+E?0%87-F+SvmTJ}L&a{;co@TfCI2dfRWmg9P#Gl(Eijr>=M>JE@ zX#)X?UeT|vt}e(!y(i;wOVpSyA0m;+34{%m|27GQD%g9PKYcNKUaA!zGhVmprQU9w zE(R3KVCGD?99Mzq_zxUfxy z7X{mmw(&#(@Hi|y^opXpjknYKpKp&Nna62(=l?(z>lOmWe`EIVrJDYlW z?TxIBQOc{jfZ~IYJMjzNCfFXAM8s_J@89SBcmxZ(d^;Wme*0>U4v-Z^O(foA?utu3 z$fM-`Z-ismXo@}0zfGMwYvT!`qQnK&)RG_DfzI|X>hhPmmyl_O4dlKz)FTPmm!1nL z9BrJPJjY^JAH|-1@9QOj07~A~xJ%VZKMQ2O+FueJCKr3`de|1+D<cqG=hPo?TW6h1E!<&`mw#XXIf~lC&U8G^0T^` zc!4K|f0GGB+NBw}WO02%?tG*OAds{mrE^k*rkg-{h1EN;G${QXHOaj@OAx-t6s~cq(rg-M!2Vx!o$L_tFGJ zf91FvEByMUx;~LtRCHu(kof+m#?PTV@15OS!nc?&G0T;j>n^LQQ~s;dq{fQ$J_}FJ zeI;Z+t@D-1pEGaYxdq$uqiX?f)?1%lA2$Y;p9su9Y@8Ps(veXGHLS+8{Bu}{U za=az{s^Stp^W@~+tz2tKuKJdUn3#~r6)2Lvc;&cv&$ z%!+IFxB)OFdM_`aob;KQlVWvlB%3@nGD0AfQiL{mI@N;~o+> zdx57fqSFE8cuQQ|<(ZQJ)f~pQ|L1KNY=NB~40aE>R9snkbF;}Bi5%@*9#ir&didB! zLdDFARoJ$vdiPgG1~Ban@U(@^NzJg|XOxU80sA7tQbPtpxg2!&3~X$CY!<+?3bZp< zRS*{)x#?KJdk|N`eY4hwBgLN4nyToirRkC-f-oqW_H$)*VtgE*CF2<02=$6fPO0s% zs`|SGoWK&G7h_L&#Q^yAP$qRe(7;pR)jT@b;NavGqobmtW?(fOFns#pfAGgR@+F)$FQC>2V0 zo5weHTBHKQJ&lJwWwwx-ejg@zGuu0oNll$)pEi$g^R(!@08+G9pbRVz3h@}&-wWgU z)lRL(=VAq@-Y1KNhI1D8J!w@hnUN5DE5x3lHDUq3YN*~RFd%;SzgWv}|36__X9JA} zF>eqY^dBnz7mb+-m~}xuB7K*@CGwLnDt-a;nZWbrkLf`V<-mRZ{rj7y!~J5rxHs-V z;O$EDS4?U<@!=)Ge3!vsbhI}y|9d~Opfk09PwsvW^EL+5U}nnlR}0ILMQfB*mh From 974511e28a30f478dbc38d782f2dc0dbf4bc7d04 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 22:01:37 +0000 Subject: [PATCH 1315/1342] doc/routeserver: Remove needless figures, centre and tweak other figs * routeserver.texi: The full-mesh v RS topology diagrammes are fairly obvious and don't deserve so much space. As smaller wrap-floats they might be acceptable, but there seems no way to access that TeX feature from Texinfo. So nuke them. Centre the 2 other figures. Tweak size to avoid bbox overflow messages. --- doc/Makefile.am | 3 +- doc/fig_topologies_full.dia | 533 ------------------------------------ doc/fig_topologies_full.png | Bin 8489 -> 0 bytes doc/fig_topologies_rs.dia | 499 --------------------------------- doc/fig_topologies_rs.png | Bin 9994 -> 0 bytes doc/routeserver.texi | 14 +- 6 files changed, 3 insertions(+), 1046 deletions(-) delete mode 100644 doc/fig_topologies_full.dia delete mode 100644 doc/fig_topologies_full.png delete mode 100644 doc/fig_topologies_rs.dia delete mode 100644 doc/fig_topologies_rs.png diff --git a/doc/Makefile.am b/doc/Makefile.am index 4caa4621c..af7126262 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -20,8 +20,7 @@ PNGTOPDF = $(PNGTOEPS) EPSTOPDF = epstopdf # The figure sources -figures_names_parts = -normal-processing -rs-processing \ - _topologies_full _topologies_rs +figures_names_parts = -normal-processing -rs-processing figures_sources = $(figures_names_parts:%=fig%.dia) figures_png = $(figures_names_parts:%=fig%.png) figures_pdf = $(figures_names_parts:%=fig%.pdf) diff --git a/doc/fig_topologies_full.dia b/doc/fig_topologies_full.dia deleted file mode 100644 index 7ec3398f5..000000000 --- a/doc/fig_topologies_full.dia +++ /dev/null @@ -1,533 +0,0 @@ - - - - - - - - - - - - - #A4# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF2# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF4# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF3# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF1# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/fig_topologies_full.png b/doc/fig_topologies_full.png deleted file mode 100644 index d39e5e242250d11965ac28f9c52f72f10003621f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8489 zcmb`NbySq!pT{4NMoLPMl$7pnrMm zVyJ!i?*4Yq*>m>n{;_k;%zU1?^*s09&%N*a`b?~zjw%rWEdc-kMCxi!48ZTj+czF2 z__=`nXc_#vz?8$fe;lBW?8j+=Nl&*W0}@fyiTS>XiBeDrhS`g* zDgi^4Dqf4LxYVb-lzRciTsc2$jYeHc9?naksAW|i#^N*2{JH20*PQqPYY zj@Zc2Ux%Y$`H}jIzx5;c@R;$klatA+CT4&9_%Sy(x3si0HTB0wYT;$W;F^Y-nwpM| zj;5xjwl;Eba1e>)<>XY;&>#pYqkYF5k9Z<6+2XrBxzZJF{_NT8+}wG3(b#6L|7t9o z=KIvt)Zf2;9d_4lu9O24fL ztu}iK(*6M*T?_2uWTMKXxw%TztHZwY8EQ4$%w!I0WZ? zwRhE3RoQ|zIKvO9sZE|fot&N3c*lC9WWi_R?R}Ib>Qe4eUsp#y(Wzk;0& zgzA)C{7%s=o^kRi^njVw%*@YMk8J{0S7_8dh;(4IJ~X#Rarm2{_6&FPAGpa9mDKPT1Mm2OfyqqqZi1x2dV)OH2IjtjQ72 zj!VqFZEacQF)tAJG8!G9& z&go}AyRpG32YKn}_*R+*DO(nG`C}`97z2yu$G6 z2z-L!;o-KMt37zjA%WbhGE+p5B=A8FCbjYF>$8>3vX#TNd||HW!F15>a3&IC)P|UK z(=#y0dHw!=xHcGqs)EoYsDyXCO-?@Oec*1<;{T)JH$Iw}h=>eJ(CKF}=>3&WYv)Y! zt3C10`KWDv4IPMYoPx;jl92Ruci+E@la1_c$a8dgY%h$d z@aU0RWd)?rs-Y;A0xNXLetfc5IHe8oGd}Roa87>;hj8hSO&?rhx_ph3iK)=&<)fn` z8ylM|Z_6g1Sade4dh^2K(o)F!5X~jUPija|t;0wzy|mva?DXVh&%@v9i5mwkJaO_j z=OdQzDJuaADynO6bi2B`J|CxW=<@OK$b?*9&eS^`?3nOXKb`*K(vtazKRUM5gy!Ht z&yv`@A#8%+DR&0)lMQYLaz0byI8Do z&5DFn#QxzRfB2G`Yx{=!yW0^3Hc$bIg{RTHQB6%!fN8BYwzpV_;i|5$@AqWR_$}wC zA{+7YHiQN#^)FPw!Ewv)-?q*yCGg$ega<&VJNZF06JC%?j6<;oez5=XKpOWk|9&L# zuSg{gf@%oAvd6to!Lr50qvCapfp};Q_K!Mcn(FEpp&cEH|J1UM%m&_OWziZH+_`gS z3J$>qE(LN^i%Uu{+WFfqg%Gh_srSF+*`dQmBxqis>6J!Jggj*#MrzC(0H&U@x`gd` z{v1c@mU*}9jg5^eI3kXmPCnS8SS*hh$915%m^EU$*?s3IKmK&e1b@}KT(P~bPACLM zRiEFhlc#(Xl_Mpd4Xk zMVJaYI>e`MjJRk{6}{T+k)Y=T--m|imMBK^$%MTkUeL)O3bXY>Ag_AZ)V)AY0rJN- z9e3EGeo|BMm;%7ls)q>I>mBjh;nnKfL=qcIPDlPEO8zhh+gr+cyn1m#Pb9 zTCoRHCMurl@48vGKsU_`xt6q{)qv0=p7w=fV=&_te*H?7SH8Q{b~DJ|_B%z>bU%ju zi^!scz3}HRislcxTAN>ElvgA_l)x{qc>Nj!t#V@X2M(WJeHgJAbcBR1!Jvn~`)@A) z$b&V%>a|TpG|kUj0B5_+d;Yst>qD7=r@K8N@Mm8J?CbH#{79Ea&2%%SpUgIp&=LO# zCw~xq=VT}QQ)H16CZM2)j^lc1XJ_Z;#tYEN2KZcGp1bziV^N%5x zaOg^Bq(lcecO%`7?(~KRmV1{B~^OO2l4puZqONx67< zutL|@?YWfOH^`I%PyTi|mFngNgF_)u)F%OJClSO5-BXbvbOCQukurYtPIzV0O7%zL zfm8|+SP3;0oIw(rDk{CWJjJ=O&Yqfz$SEzZ2S z;HrKn^m(%%w((yHUS4KB<9e>zhJ`?8S(+PCtHFZR5@bl@q{A4g6V>n457%zu^eWGNPuLAoLX;+9Tx>d#7 zN6A~R192nka#Zw1J8QP7kZt`mF&B_-(o06ny5JNNQf^kYeqh_ui$~0I*A$W&Z&dxI z#-P2+@zquT)Q8#5x6=$Uu}3n@D#f=qC0B;X})ER5i~_74@fHBy8TB$@HA|$tQT<7Iwe5Ox?r60LDtStE#HV_dmYr`z7hKL5k2VncC*&;`*TT z=WGgvvLN~D%z%oXOCB#nGA^z^yv6mJV-C5ei3_U(Ro}HZ)aLMReDX*v~$W0g; z9NgaCF5)OeZDy&?EN`miEq-_!Dub>gj}RqOVpX4gLvCejET(RK&0(loS>g1_i6F5V+%lg0_AJ2N&0U2>}CD)b8#sxR0Nl z__g5NS0uHsf3?u$+tbrC{z71M6o9w(iZ_0sKHf(f zKuGNDTp=1Y{0|gqGJBEP;?TXtR;v!opsY^v932xQBO_yD-?afs%jT7_vOmA`2QXeP`_%zM$Ms#%fl>c zq#~3teUiiR22CZE^Rl7YkQ7FP-#3LJkexikqoq$bwTW{FeP;9G=F-%rom7;CXx<+wa_5Ue1jkruKTEs!$yy&4V7GRrg3O5-OUEl1 z&|nVqJ~+;a!JD+Tpf!CPr;OVCd@#rf6}(y{Q?YXICQ7`fVDGW-1qztW4FT ztU}~&zqB>_meR&gru6(d=JEQyjqULK$-8F+dHdW?+nt{2uMX!2#o~t~e!>EaeGt9# z^pWSV+Wi=RXw>rHezFB*rMmy9#=&~gm!2bR;ZZz)@?A86t#+=lMqL!Sa=G-{VF}&s z4@+EW@03CepZlUBs3X+JJPKpH%PbI24mY?XL@T%=!+Ui_E}{}i>*hG>3r_CO%5;$>Bn={j7c@c(2*8^|oY*st~ktHeId0lt*n@=gS3HZ7QMu0u9D( zqTLf#s7lmr$ya3aIb^?XtM$Y3abP_Mvl(HAH41m$Hoz4jut4+bwm{nB@4Ii*APp}M6(Zfl>DyuZh9B+fdE+` zbV~Zf-S)yD2=?Wv@LfkY4m*t)ABaYnJ#xQ&otry*S+mvh$nI?8H?hK%fS*Hh05J>b zUR}R7^!=|;_}c7%f9pPa+vB)gOHdgPOaLx^o(kbX@H@g?{E#^>^38;eZe1(C0E3pc zeSi7*xwnJAW4a>q%AV%ZHp9)qu!&_di$)sDPrYE)B_aaH#ppNw zQ0GY_D#ZoHB-dMulzC__#_HB0U>@O!GrF~~UJQH3tASQ3qvAS5C0AP1W#CQdQ5efm zPL}A}ll}9pqs_v1+;{iI=mgomO;yaW#;IuGqlWJTRr(q z^0{%dVSTC3_ruG^fQ1S(!-uvOQwk-!);IqDqv$2^fRzn{T#5dxOk%l5ed@OfWV6)(W!*tw_)!Na_SF#I5y)3(VJeYsJQaR^6=?1hz;1ee}4jdI;Jy&XcT1WBei3N*)gFd3;R&vG$nO zcESx%sPd|K)Ewsl8#^b|&$j@L_BiEyjgZ5WO&!s%#i}r%BCM>oz2>S6ie1?o9?-C@ z#rvdMi$W?wZ=Cn z0q49%5o%L^TT@E`Y$X9k8Jw5cJq~^N&@|Yj@_=k zt6C2VjCm9*DRz;buZ{9Pp1%w00^6{80H!BPpwY~UqE3{WZ@H9F>;I(U6iHVsTC~eO zzYDt}brWJUu8pWPFmg|n@9D|nr`d-(cpgM7X}^`DkIjcO7Mi70nuZxYT3VzF!BaY7 z6BdD@uk|obHaoWlBQgv}k@g*x6gA?fSB{9|=yjc0Rj?d>B|mv*i=3~mZMX9mKOdiC z5TKl%o}y5aIXVqvn_kW23;~>yl9If%M%2~i57>-1jBffgFXV)645~>W5U-BbcNdzec}x{Z zv2J9ye3}Xi3&FD|x5>x-*@O`H-JAY?#k4ewQ-Pw_w+cWqSa$eiWuZ*77!)to)utcb zvd)Z;`|K}wOin&+QHD=ZQ&8|c`^*W7m;Zx)dB=(o%7j-x)ADkmX?1lqBjf($m8eL& z3;ckHj{{djv*0s@mv^`<-jg3~F|m&^gl>;VR<`x)*GaNP8SdyVeM3WG=&pr@y``lk z1i~mwmbXX;HJDBgvk0yv%XS+ok_q8!W7J@P&8*mIH_WyA?K}(W6m*;Y+|<;RUr8p; zko0G?;PK|>X5+8&@^TNfm_OardKL@K%BFtawvQyrj^mRk{CV@qv`rF*f~)J_lbyM) zYIRqMoZ+3h29RR`8K9ybk-w2S!M1V#DEW?Lo&h#mHdxIsjZysyJm@?!EL|Q0*&iPs z1qXLJKO|S!ff!)r;0QrYm>e%!c-uM(1dM}@lRbp?>ilo?Z|~QEwRQc>dmb}PKq_Z9 zMLSzWm7xDgQtot}vOP@xJc5O-N;Eq=+gFMnsD`x3O}kVH90ashJ*~kEH4R?@)w^0H zgg5TfT(-FTBw54|y0SqKT5zx&V9G<4)W@P6`q#g8k=oK9 z12{Z7+FNSlcNa*09S0)B`j!?tz@9IM3Wfhi2?8Rp=AH#H2I>UqO+iH1qF&=tI@P5`ug=0T{(PU zuk|!Hs1|$u>U0S=v@AD3V^`re89PExSC<4}WoPFK`nwNuAMjX?rD)OYrwta5&_GRK zD0q7d13b^0D3<=3@ZjU)v$3(^feS2}H2!QP1S>)9nG%s@3CKO`8yhn;M8N4AhMm%% znw(q4AZPfb+F<-5jY%2ATHH zLFZn81Ptvn+UNGAb4>TKrsgP3+G9;ZnJW>~nvV6NP44){H$nRyxDsrle?mbHX+SGeC{p+R+F<%G!iJTV70~m;JFI@mD}JnTbFGL? zrSR3YuAA$#6nPMjZT<8kAk~`vj{da!~AtB*No_xs3U$dZ#G{P!Mza3h4`+-4bIXML? zHgZOiwY5*a+@>{FU&3bYO8bS*4CTZ=hCJ#idC@QjMmchHINX}y2t8wCY{0!0^&VbS z5!YjX-izx(HIyrxU1Yr`z&AF4`76}U(2$&O;L@rfhS&Tnpa6nG6Eh=Cb=df#t#x@+ z3L48<@d}luYynYwce$_^j0@D;BQ>aV|G3V7%^=8ycozP>kSee%}U z)`|4e@87;vxOo551p2F&2xxDJJ$p?01SHbHGEK#*=gl?jvai~#exFg|7~CI5Q@mnQ z-(hY~#nY5VR6|G}JvvVK+s6=wD2xjP8&7y3j@gcYT@VluT$1adw_Yx`-~)}%*GAgg z+fmz7%xCLjreGvxpYfJQA22#OIRX11S$e}kFz)q4EhYBAUE)zja5U*LrS3e)hSJ`@ zPki$Rj09aCB!$>&34h!JhX^CouVWA;5^iSaNiX*)cErq4ogldN1VWV#Xm)k}lC@ z>f_Zmgi;}mDYBVvp zs{;FDy7Ge0j&`5y`xseJ{fkB(b&<#~6ME<9K(8-fwba7lB!G~xaNiiVh@-Es#0yU1 z+3oNDjuowMu_6b~%*@Q`?m`i4+g)1&V*1Gn12C<5dUF>z7PfoGS`jGlK>Q^IR{-%f z_<+9(srW75G<=YT5(D52+EACgOH1=>=l+d8l*-Wh5|w5;e}g5=Z3ohjRD@JeO(HHK zrV{BBkO<1@FSLc+q(g%HL*NB3#Inn@vvGi(ogIHdh9AZ3SZC~!U&S04`nR{$hb7;9f+?m5Aj?PHd2xJM1YlHgccS)TvEvh+!)+Ofl)eA4%2U5c4uyKU@dnbGj_JN%e;-zQm+nemxn&{ z$zcvlz($15k@AOACX%Z{RLYwVtPJSPV`XJ!$Di}`q7X_k!9G6YAuPtR;;z%7pVd9X zbZ&8FRHN%?+~EW@sZwNQD~Lu9~&}&+M^GFVbaSF%y0GzrsesGKB;Wy)1;HDLM0#cec-; zFT9}<-X8{qF}N8&GdB;fwB<{$`u6P=GD}oYP_Xesbu~}Ry_f$Hh-M?*6Ez>^2mc_@ ze*0g5l5daH-nlwEOZo3xfvR}1aB7>7fPjkkS!(7#ubdn=q0BcbMg6vQGp^y`;b1%& z5rA@rLZJ>04uOHv!D5;JrOd6j1Vn6AnbA?!+HvL$FX`oi8cRw_T3d5MBtg9x%aLnZ zXR8hdCP&!zL~RuS2_OgQg=;TzER_V)I+x4mzX9vCKJV`T+(X&G2SY3cgf s+S>X$6$J$=8(UDH|L$WOaK4? diff --git a/doc/fig_topologies_rs.dia b/doc/fig_topologies_rs.dia deleted file mode 100644 index f8aa18d67..000000000 --- a/doc/fig_topologies_rs.dia +++ /dev/null @@ -1,499 +0,0 @@ - - - - - - - - - - - - - #A4# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RS# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF2# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF4# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF3# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #RF1# - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/fig_topologies_rs.png b/doc/fig_topologies_rs.png deleted file mode 100644 index 014225c8f5141792f1728201f5d2a067e6cf4709..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9994 zcmbVy1yodD+wUL>NDC<4A>Bg{AdQp~(k&ni-6?|7B_Pru-QBIEh%`eC-Ca@=!nggu z>%KR>@7{IqJ!{RGGwU1<=j^?o=lR7G_Ci%22a^mF0)gNtD#)mV?}fh~jC)`||A1u) ze4)BXDQaS1V9YM7{r&mSQ9;)Q0zn`7`$1`n*vy1LXdsF*&on*L_S3C3HRX|gcWpD@ z^Q#%&VFa>g6FwXb_#y{;sv0>e9NPVwAaRN06A#*P6ccZlESxRP(myDRg zfR1TsDKIuN``PGzbU?I=i}jeBE$e%nki~ zR#LFL_7*$*2R?ILUS9Ic(BR9+%d4dc@i70hv9tf|?^k4hA}TBl6%bhH@V`5lZxOVg zV`gDt;pF6GXMatC28roQwRdzpDmQFdb8dRs>zG85IyQwd#m>q~2DKq-(~*>v zw6wH@!%JQgYvk0`LFwtuw??w~2fu&+{^Q4w1%~gV*Xdf6Bp8mdL0` zZf9p_ZEbxo03sUY&LgC=K2etx2N ziHTGF@lOZ+gmLvJwG-hR>+5Ixv&3H`xZ0=3#>~{|>&B+1g)Dv$L43vUz6PLvZYnf4 zTfMSz8=RXn5YNOjS?&ya^48znB~u{wW}uAS2pg0;{|G9#9y`yT4qsw z=FmrzWF~UH+hYoOd}ZS}`0JOmhlj^5QYBf?feNCgHe6iHx~pfVRw--jHf8JJ5ECAL z51*L$X?#Ds=@<7k=gWyA4HOw!S(x|f_vYSdboMdrd1xZ1Atnt2LvB;kjQW$EmF2FG z({xTK6oIUtMr9vsh=6Cnd_MQBJ`CyvkEc5#1~X{))uqA5xF2Zz_Ob_AUrFx1UE-?J zWT1Lo^r}?H)am5(=%D3rEQ6EqTwRE)bX0!^&K8?~wP{n;`* zEPd1T_VjX=_USd}FH$L!Cr3x0?GCiK z?^oAz?7fe=a&O*n8HS;ojOVLN)~HA<`kvstJ6`S6pT$4_Cg=AIgN2O^b?M;1e$_5S zMMVXyP%)~C?CehPybnL`44{8ZO~o=n)>_xrELu9bxF{(o(0tgNYa0K1zJ5muBP=Wo z1zb~dWK3BT)otcvVqzjC)!FWM?W$>jU7K&*@pgWAe`~AJak;ZMirm=mOv~TjA0Zur zM~#M0P7cow+`%v0hCg;nO-TXaVEHrY5e3Cuff{vyBt8kr?_P2TgI3R%Pzx=;(UFm_ ztH)PhJQfzpLrs@t8o^ppVj$4aRl~Uay&9A0f9pj|OpFjJew31$DoYppg4x#AmS2;! zFTbVzGjT(G{UidRWlkZU+2M6!Df^@N3e%djY^*k<+@QM)jiFyu9_If{f?N%DLmb`uh4Y6vEZ6+hf7O!Lkug zV1G`>bL3;>wEbc;GH^|fS9*$jq+V9mCiJxVT#RAR($b1xzVh^JeDomgBceq6?xN!^ z&#n_`>$#ck0m&^WAWx|78Z$H=h`2sl?lSL-c024B^*o|cu>n&SE*aF`85c(Yadi(} zW?*3O^zoURn$p(NB6Z8Q9~&Dx?aksl-O_&=V&wg$qQ7T*={rR{+BCxnT^n-a&}gph;9 zjtUITt$_}gOQ%e8GMGa%-TX zqy+V7EnbZ*!OX^n)liIqk+G-ye5Y%05JwVZ=AeoJ^+?22+)9R!Q+8e53phOxM$1PcpG&|$%MdyEmH^qD;w%x!ednzNU*^!xf8v#Lh)sIL>Q zMVdByVbNiil&>GA@Ti-URB z?sw~1QR!s*rozqRsD2zY2Ulmi)+Lh#nQyOR{BNYsKB_M+Etx>3DvY(y3}nA~Pd^r+ zcq|EK``}Sg_?za4Xxv&Dl#PuI<^F>QXF?Vs*)8ppj}uLkVkB-!AeqD3K1S+9S7v+D zRS--}Oietv3s$fxksmiGG?vvy4LAjAnP~Wwl=G{fD8mn~^j;bSo4$!?j))kDrI+XL z1w&qNxKmpt$t6a`#m5)_N)r?*&z0_n(nGu)wXzyj{8S6JK+R)z{~Z=FCy6JDzyF=v?&RnpNPTu7>VjtEBvm$FAqDVrPN5}@ z)V@d0EG?Pd&9`{;_4e9CV03nNir@Y= zN2)iQd<*0;?=3uso{=E)WwY#hYyuuUctA->Syff#ilD-6JC!t!k7#-O=L%%5dnEjC zMnDdQ_9`kX-*^1ArkL0M;Ug422}$C!ith9}d%`ZIATN(@2t$`NFi6wG;=mC+FH+Pl zLwpcC!#R}<%9)kT+A`5U(&#cjD6ler9~31j*})%5wgy`{eQL=Zn7ss$suprbar zn=&*sG*=5Xe>pz&YlUnp#b$i6vA-P`h5T&&vw|bWbRkzmWu)|1Ilrd$Mv4cM+XEbC zTg;WJ#`fFV=z)e;&RCYBPuRy2XDz>0nZ&lwZLs5_>z}UI*E-ASWL4NX+-D}*u$#5) zR}#f-nwjyX8vb#0ZbB~^e%3IR#vc~i!vIZ~n9|?a!F}cjQ&eFzb6QyIFP#%lFk4p% z6SSp)poF%F>ehwpuwL(d{`{oc=CPB<;ZFn(`E>I(e@}{j6EzH(9Co_8D$UCqs%e9Z zx<^s;>Gf-T>P*f{uT$o#@^+EY!;}yBMVcc1x4u*{=wG|K=-Jo?KD6=jCbNr*rk-m& zydU^4MB+wOQn(eDa7sw_-2ITrpy6WxH}*_h>W5&P@BMw|SY`PYs@Tpd&tJZLw7-21 zA0Pi?a`Mao!6Xuy5*wS9L{3Ud3gFcYW3aMZw;7HX=Eqq2{uqgK@M_;;B;sP}p;ljX zl$-0}de4m0NtVGg1)Ek^SNr<<5~2E74W%V#W;$rn#w##1H8m+JD$>P<<`Ys-C~J2j z@O^$e4hkzt_+Mi2_~V2nq)DjV{vtNi74-GIh%fz8;qKYJl-Kl_8@tB;?v_Kper z^TXQO+V9_yw2UBk48sFGcq!QncD2g2?%kb_IAP(P_oBgaVc5UY%;P$vOtCmz*wDP7WX zV|iWDgSpWY2i&DS-8aTkT~8{#rhJbe$Z(U_3=2MZrlz5x?`mo+2CMC;V4aAP#AU;UQv$BSTlR0!`eQ3>@*U2nVyg@0k)Glw(aa%ocVLpuT z;eN2S!_#Na(gV=(^k$#`sr&}5Fxvk)k}jGM&|v=v4=)eme?`b+JMu1ld{XZA^r=O? zrzbvwM_kmyJ=nO-21bYzgi}7Vp!z|IfK+ip#Ps4|f2=Lb<mN8E$V{d+Tz0g3F zjy~*#g65=po$mBf%7>35FGLz&q<72YVT(}-yZ>DIJVVeI{fJ5}nKmqpY=r{$TuPe5 zURTW|4F2}EY2zrLiGZS%sB21lS2N20Zq|2Fm&i^~-B``nFG2Sag>p&?f8WICWC1iK z1C2h<;u@>47loe~#EqoWHY`_GrEML`sB^6C7{$e9R(H^jkAEoRWA@L~=n+;SdR8V( zq*ot7+TBIX&5wuuS^YOQR%RU#tEI*2lZo94{q^-R-_t5W}zvf;GSWdLGzkeyM4`a-_5GhIvY1$5 zl3z9-f2^Cn@l?ra^uUXaZFDI(Dd>*x{E)4;*c^XDq7sOUsA6Hh{7{VSV< z#LX33Yip@RN`F{Y^HDX$@R}pN1Y)SonuKUEB1oM*P@VAQrLYMdB08 z*rd=H3Cjw2^(CI)lH_ZPtlay@$J~zDr)RsC_5EoiZ^U9ketUlUM8k%Kik>pV#Mfy# zl`A8&^c5uy7ID0KCSQM8zy#=x(>XgXg`~`fOB`OVbA+esDf8Ia3-xSh;ET}7SEt+N z&r+2?Xkro*8)_v!qCc9k^4w;`LcTVdzMIfo&r5VXrmJ`8Tl$tl|NS*HS3{vMFaW?Fdac>Zca&(ylBcCca?Lr&e_hm1$x8a{1z#d zjECt&P5_Q!(t~-Xt@-(tAmXRH)3@-)g@uwf#m+l5ex?QGicTJVKN6U^`Z|MNuxIzV zPZ5PxI@10asB+Hps}QlADpx!{{Vwkq+S0*k2M71X)SAiDG`RCL z^MAF&MS8x*05peVe9VpENra!TuUr(_84_O6)7N)WhgSx8mIR<_pkM(x0q7c2qocG> zA^_3?q?P*7qvM}^!(w+gCu*>>Pc!y`gE}txRZ#Am@-7_xBi~4F)}P`A_Vt;r^fH5bDWN-IGyy>Y{YFrLO@K6PggIEN&j2;~rvTY;0_z zFc}UG4gd|?z0Y=LYOK^U#qCB#O^GKt$v^iVwY(C8*2zw{cyLAG6A+C3d84e14Fklm zgd<2kh6)tJp$`JHgt*8M`|pNqJ1IyyLa7YjU;S5C-T{&{y8`#;`}>R9+UBRGE&%sw z+q34Mv-An{kv0MIsH=I(K@u? zMYoG7nk#Q3J-w8KgtOCewecK4VoXWoz^M5i2ib7&(aS`x?JE^=MN_BSsf8-8(qXfr5!+Vd8hxS5WA1*S!hYp5T zL0x^U(PKyn_K|f1iCpMQ`}=jB7bbJEh#(6I0m4;y<8t;hPkkBv>wN06D65;>#DpyAQn$YwXV znHe3970Jer1U9e=dU|^D^78y|j{5-dN6yXy0V5_x4WteOgE@Fb+hl`-F(J}c&9S`y z-t-%n!)2rQLbgOhP~rc>4&AV=izo4mB{A;#gqX(=^2zDFSL6<2xT`6QjG+4_nQ%&oT~`W{Gr zv=;Zl9UBHl)8CFayT&F-Lz1srm>|L5I&OoOyJA0m*s&=AsdR4w3Wvw0gjaI=UYA`N z4YJR784cPdV=umqsN~Mg?^NA%n4bTh6M}bqx%qpCt+w7K+Hn)t*N+1p&r(|LN}`l#_7yVl_lDo0`g)a4^pj=SHVNs;x zqn}QO=NEJhV9hp2S4nS_>3g22luTPZDHWR>(0px4AbF|VZs4^QL@a_DLs6CC$F%Z2 zcF4zT`GLjKuXV!%7~i<}c``wZ;~<;1!eaY#yX>4W&0?{u0j>{y^pK+B>Xe}T?BZ|; z_|B|WA;TS z4~s-(ugX~tzp{J~Bme6ce>WhvKhxpjyUG|!-tRN~o>*8E7QPD!;XN9nl#yFmXdB9; zrDf*qT}9kc#%@@OonZeM5cT)=TAng)iTnjfiF7cHSlVO0rRfn*8H{oxS!qUfmdV2W|aX+f3I6%^nfixe)6p?xul!hX6B~| ztfHcA?3=wBPOTCsywoO}qsmexG3|1%X6Pt|Y-MGPRL9Uxix4Ler`&5Vi8p8QZ7ROh zP&z$bEU)8=jF0EFz+-3OWTBVI!gPUlrnKpg~bvJyYDcKDy*yuHTZv&zoN z;p?7lQHsGp-+!o4%CI;Zkj!^H>+pMn+=2qZUZ*wvWeZXA<8XgJG(sc#t0VvU@Dhn6LLpo3g3x%_AxY;{MT~B8{pyvA+tCjvfa^ z)?~HoIUN!!DTWv8iXq=wb5!8@8L+_mi*|;Da;ICg05g%Iw|3crT(WJW@&>j z^h?qLozGaGE1gxOnw*>*tMCaHwzai=`SPW(u&}kY73jBsw3n5suqHfbAONlj7gt39 zD*DysrL3G>Gzkx#hzN3ge0(Gqhh?#@uCT1f{|*ac-b(|UUp6>FLQ8c5I;H4USva6` z(80nAT<;Ta|IMLvAil;>icS`;vtIh%ZjI)EJ5(69Qxb?6l|$!;hyDHi$H&KXvedz3cfZlwZ}noHNr#xNKX1L^ZQ0aL zx-V7fKrMcQ4+wo&a$4k1sp?PUcVvk+j}>Q`9`Pt;hMm9Bu^(a zB0L-*Ls_mT|I%2HNSleCi8pq3z-c1+3j+9fdBG&8!{QnmHqy?{7*hpe&(9Y~Og3v9 z;#E>ZD=IdyPtRXP*i-t|nSX>o&l|fu*&N3V2?>#Z_3HD>9tFXFq#sclns>KO?E3Yk zDm>Wr<*L#d-rjL_aK%IC!GJe*jPNM}H8mVzU2XXs9TnsBEsw$Q@Ngh*-rE9h5K!{D zl;Q-CNF4|uVZ!n0?IrLHdY)Nd8Y$bOmvc03{}e)F-h$*q4l@Sd5W zpIdexbU0IDvBFqF&rrz!wl!>T0u*U&DQRgGPcN@@F|WASuU#$87Ted-Jrw-fns6#z zc6R$k51BV#TD;cL1yABU*xD-Atbg%eTU$z8k77d^o)V&Bl7?i>HOt1uhbep#bSq9c zgE>mdE0>igr=|{Uo}jQBG>%Mrlo-(^4uBPi^(E#-QiEFwBiFvrn*B`Y=5cAML#DVF znN=9RRBhA7_IN>hT3X?}Wz7pb;7y{^5MiE)UkXPC{nr*4t7wvxJ>UQ8fYrEb)EjVS ziny`91JMMKvhEbg^*hYo zv&Hn46c$$2bJzyvUHw8?+t|35Bw$Cjzt^BUH#Y~MG6t=v$3gAi^JP~AQf6jm5O59a zji8vA!R)13l@K>KH!ZE{V!NLRD<_)XI9NeFEI#LZUMGWs^z`)Bf+;%eK<)EhPteAt z6v=&~A>{j;``z@k&dDeJYZ(>elF*Xay**npJ~6Sh;KH4V;9xYWm?=PU+!Ok-MM||T z{^3yFnv=Vs=RepgMu;0WHY{Tm7>F>*$;olzdX~4#E3~@zRTUM(R#?g%RkZwqY9ETT zvKGhW+pTdLx0n7N;#O8tQqs~w0Qq{GJ(v3JZ_~jPD7D{dtiUQ79+mIb2rcF0iPq=Q zUuS3OKoJLq5FI`J^~E93E&l+AB|k3@%Fpk6_vd1@H_B(Xtiiz05D+;aUc2l}6cx?I z@uGc^HdeBK*!2toLCgBv3lLr+r=&CxNy-O8aiUY}OxD|5FZf>A6s&TLc zwcq^D78hz^aWU_X4CP1|y^V5)Sn}HG>U+d)u}^^u5sF?}vhPAHP{xhXLq0!Fz40s>C4pnp;p7$HIs2yA4k zbj7IIm4%Vw+(+4v$?ssArJ`eTPHX>Fk-WfZ*MO;#<@WI z!TlG;#txIaNE~nz-xUEUbTEl0r>zY}OS=qc-6V;85wOA7Aa%q>^N85!=;$dUpD4NM z28T@HV)_sGO$Hh1=^RfYP}q&z4MyL}q>qh{*YvT763w60eQw0=`kBOoD(UFx*tJSJ zJ3)fTCAz}g{>3kqmBF}*K^sE_D=sew{Rej<86xc-90r92jVFbCHpe zUD`VAZN~N*d7=jcIbTg5l{cM;B#1%o;OMIh=imO zI4MBkF6srV_Y^IXwHjB+!>^3)0F(jiT`kM0dBYY7=;Nzj)~oT#OnhtJnC^!QF!&^U z&SX8`hoqz=z|p8dodNv~y^*9KKyEwkt~)?Eh54K_ukZ^BqK-^s4veN#ZNZ(L$jQjS z^V23gzdLW};Lxd*^mv`u{_Wd0NV##x!h9l%*d8WjG$sv*;fqjBS$U5nG@ZXbS`Q67dudUT;{Kb9f_y3CNJ`Nsl7P2f5RR1P z|KyI$#$y8ZC5Y1{iMvZY6&nz@{A-|j0+PLNDXPggZfJ}ZaXstMLHgVA0k^|~SWvs~ zRktd`uvZTR-Lwb9sLFwICGi_ zvrw2%*JDU{?tKL`A6smEanXN%wT%vxi`nVvHxofoL4B)dhl|vbN=jHbS^4Bbasge; zAO`F~(}wi^h!8NCPd9-vpKwJb@s{E%05)3Goz1E3pa%jF?l&I<7d&$=hJ7h(>+8n^ zGrqk?AIHDKa|1mkM)`X*AR^tn5lNq(hYm2IoxjW(s z2i@Ekq190yX4P4i4Sa2K8^xlX5-aAaXql-}UFp@oru5|G`GPk!btdq`DaCyo^YinY znl6DM3)pg=3JEG2_LqntXX!AXclBA_BC0%1jmQ^D#RD(Qf+$@!e!fgI2|WYU+x3hB z0(iL%M=h+9O7H0GjDwXm+iBxxGU`8mo0u*x6fCfEfr&VEg!V}-RJ!!(hrhiAJaKmL zsUU72lRwRFyGCB?38r1aqo!O32L~YC8MU~VWp^Z`)=%XJkX+GJwj1mp`p z(z_TyYt5BmJU(5*^UdK*HTg4dPtVsD7Ri;`|LWTrf6E#mS!p{{U0*Mt!8l}!QD0Q? ztXz==33W0o4e2Y-~R9H1ZCWP`@Zg6)B8=_a2%38zu@C ze^g|M1GO(VmmyX`X8a*8Za&*GnFV%8e-(?L*ZG h2XjbIWqA7?p60BikS6p21?XmjD9WnJluMZe{s#_Ysb&BG diff --git a/doc/routeserver.texi b/doc/routeserver.texi index f4a454621..5fb8cba62 100644 --- a/doc/routeserver.texi +++ b/doc/routeserver.texi @@ -60,20 +60,10 @@ of a peer are announced to that peer. @end itemize @float Figure,fig:normal-processing -@image{fig-normal-processing,400pt,,Normal announcement processing} +@center @image{fig-normal-processing,400pt,,Normal announcement processing} @caption{Announcement processing inside a ``normal'' BGP speaker} @end float -@float Figure,fig:full-mesh -@image{fig_topologies_full,120pt,,Full Mesh BGP Topology} -@caption{Full Mesh} -@end float - -@float Figure,fig:route-server -@image{fig_topologies_rs,120pt,,Route Server BGP Topology} -@caption{Route Server and clients} -@end float - Of course we want that the routing tables obtained in each of the routers are the same when using the route server than when not. But as a consequence of having a single BGP peering (against the route server), the BGP speakers @@ -173,7 +163,7 @@ they do not hurt anybody (they can always be left empty). @end itemize @float Figure,fig:rs-processing -@image{fig-rs-processing,450pt,,Route Server Processing Model} +@center @image{fig-rs-processing,430pt,,Route Server Processing Model} @caption{Announcement processing model implemented by the Route Server} @end float From 3db7c8743a87c77f2e00254dd171b1eca4315a35 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 23:29:08 +0000 Subject: [PATCH 1316/1342] doc: Explicit quagga.pdf rule can go now * Makefile.am: The Quagga specific PDF dependency is gone. The overfull boxes that caused texi2dvi to return fail code are gone. So the custom rule can go. --- doc/Makefile.am | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index af7126262..4520c59e9 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -33,14 +33,10 @@ figures_txt = $(figures_names_parts:%=fig%.txt) # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. -info_TEXINFOS = quagga.texi +#quagga.pdf: $(info_TEXINFOS) $(quagga_TEXINFOS) +# $(TEXI2PDF) -o "$@" $< || true -# Have to manually specify the quagga.pdf rule in order to allow -# us to have a generic automatic .pdf rule to build the figure sources -# because it cant just work from the png's directly it seems - contrary -# to the documentation... -quagga.pdf: $(info_TEXINFOS) $(quagga_TEXINFOS) - $(TEXI2PDF) -o "$@" $< || true +info_TEXINFOS = quagga.texi quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ From 7ecc5f5f2c8d967670b0bf4bb4cd6d2684daa94a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 23:31:03 +0000 Subject: [PATCH 1317/1342] doc: Remove refs to removed topology figures --- doc/routeserver.texi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/routeserver.texi b/doc/routeserver.texi index 5fb8cba62..cfe904127 100644 --- a/doc/routeserver.texi +++ b/doc/routeserver.texi @@ -11,9 +11,8 @@ The purpose of a Route Server is to centralize the peerings between BGP speakers. For example if we have an exchange point scenario with four BGP speakers, each of which maintaining a BGP peering with the other three -(@pxref{fig:full-mesh}), we can convert it into a centralized scenario where -each of the four establishes a single BGP peering against the Route Server -(@pxref{fig:route-server}). +we can convert it into a centralized scenario where +each of the four establishes a single BGP peering against the Route Server. We will first describe briefly the Route Server model implemented by Quagga. We will explain the commands that have been added for configuring that From 1bfd6551c9d1b9e3e0f2d04bbbc636ef33e4a2fd Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 8 Mar 2017 23:31:47 +0000 Subject: [PATCH 1318/1342] doc: Fix overfull hboxes errors that cause PDF build to return fail * overfull hboxes cause texi2dvi to return fail, even if the PDf is written. We hacked around this by running it with '... || true', but that sucks for buildboting the docs. Fix all the overfull hboxes. * ospfd.texi: Long command definitions can cause hbox overruns in the columnar command definitions index. This leads to strange errors about "Missing number, treated as zero." when building the index - very hard to figure out. 'show ip ospf database ...' was the culprit. Use a distinct deffnx alias for each option instead of trying to stuff them into 1 line. --- doc/main.texi | 2 +- doc/nhrpd.texi | 5 +++-- doc/ospfd.texi | 18 ++++++++++-------- doc/snmptrap.texi | 18 ++++++++++++------ 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/doc/main.texi b/doc/main.texi index 849773b95..6d42c04e7 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -355,11 +355,11 @@ Within a route-map, set the preferred source address for matching routes when installing in the kernel. @end deffn -@example The following creates a prefix-list that matches all addresses, a route-map that sets the preferred source address, and applies the route-map to all @command{rip} routes. +@example @group ip prefix-list ANY permit 0.0.0.0/0 le 32 route-map RM1 permit 10 diff --git a/doc/nhrpd.texi b/doc/nhrpd.texi index 6caf5a629..71d1ce996 100644 --- a/doc/nhrpd.texi +++ b/doc/nhrpd.texi @@ -91,8 +91,9 @@ This can be achieved with the following iptables rule. @group iptables -A FORWARD -i gre1 -o gre1 \ -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \ - --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 \ - --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128 + --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 \ + --hashlimit-dstmask 24 --hashlimit-name loglimit-0 \ + -j NFLOG --nflog-group 1 --nflog-range 128 @end group @end example diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 1cc7973a5..d60ecf29a 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -613,14 +613,16 @@ interfaces if no interface is given. @end deffn @deffn {Command} {show ip ospf database} {} -@end deffn - -@deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {} -@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {} -@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {} -@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {} -@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {} -@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {} +@deffnx {Command} {show ip ospf database asbr-summary} {} +@deffnx {Command} {show ip ospf database external} {} +@deffnx {Command} {show ip ospf database network} {} +@deffnx {Command} {show ip ospf database asbr-router} {} +@deffnx {Command} {show ip ospf database summary} {} +@deffnx {Command} {show ip ospf database @dots{} @var{link-state-id}} {} +@deffnx {Command} {show ip ospf database @dots{} @var{link-state-id} adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database @dots{} adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database @dots{} @var{link-state-id} self-originate} {} +@deffnx {Command} {show ip ospf database @dots{} self-originate} {} @end deffn @deffn {Command} {show ip ospf database max-age} {} diff --git a/doc/snmptrap.texi b/doc/snmptrap.texi index 31145639c..6c67288d7 100644 --- a/doc/snmptrap.texi +++ b/doc/snmptrap.texi @@ -69,15 +69,21 @@ like sound a siren, have your display flash, etc., be creative ;). # get some vars from stdin uptime=`echo $INPUT | cut -d' ' -f5` - peer=`echo $INPUT | cut -d' ' -f8 | sed -e 's/SNMPv2-SMI::mib-2.15.3.1.14.//g'` + peer=`echo $INPUT | cut -d' ' -f8 | \ + sed -e 's/SNMPv2-SMI::mib-2.15.3.1.14.//g'` peerstate=`echo $INPUT | cut -d' ' -f13` errorcode=`echo $INPUT | cut -d' ' -f9 | sed -e 's/\"//g'` suberrorcode=`echo $INPUT | cut -d' ' -f10 | sed -e 's/\"//g'` - remoteas=`snmpget -v2c -c $COMMUNITY localhost SNMPv2-SMI::mib-2.15.3.1.9.$peer | cut -d' ' -f4` - - WHOISINFO=`whois -h whois.ripe.net " -r AS$remoteas" | egrep '(as-name|descr)'` - asname=`echo "$WHOISINFO" | grep "^as-name:" | sed -e 's/^as-name://g' -e 's/ //g' -e 's/^ //g' | uniq` - asdescr=`echo "$WHOISINFO" | grep "^descr:" | sed -e 's/^descr://g' -e 's/ //g' -e 's/^ //g' | uniq` + remoteas=`snmpget -v2c -c $COMMUNITY \ + localhost SNMPv2-SMI::mib-2.15.3.1.9.$peer \ + | cut -d' ' -f4` + + WHOISINFO=`whois -h whois.ripe.net " -r AS$remoteas" | \ + egrep '(as-name|descr)'` + asname=`echo "$WHOISINFO" | grep "^as-name:" | \ + sed -e 's/^as-name://g' -e 's/ //g' -e 's/^ //g' | uniq` + asdescr=`echo "$WHOISINFO" | grep "^descr:" | \ + sed -e 's/^descr://g' -e 's/ //g' -e 's/^ //g' | uniq` # if peer address is in $WARN_PEER, the email should also # be sent to $EMAILADDR_WARN From 6a48343cd6e392a3ae48dbb735008f911e60420d Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Mar 2017 00:54:44 +0000 Subject: [PATCH 1319/1342] doc: Clean the tex index files up --- doc/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Makefile.am b/doc/Makefile.am index 4520c59e9..38920c8e3 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -117,6 +117,7 @@ EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ +CLEANFILES = *.{fn,fns,cp,cps,ky,kys} DISTCLEANFILES = quagga.info* # do nothing for DVI, so we don't have to generate or distribute EPS From 5e558004594497ea91dee123ff14e5e487275d73 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Mar 2017 00:56:32 +0000 Subject: [PATCH 1320/1342] doc: Nearly all the world uses A4 paper, set as default for TeX output --- doc/quagga.texi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/quagga.texi b/doc/quagga.texi index 3e21cf87d..13e988e61 100644 --- a/doc/quagga.texi +++ b/doc/quagga.texi @@ -5,6 +5,9 @@ @c Set variables - sourced from defines.texi @include defines.texi @settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} +@iftex +@afourpaper +@end iftex @c %**end of header @c automake will automatically generate version.texi From 431900f023137d8ffb4010314913a2ecadfcfa91 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 9 Mar 2017 17:58:39 +0000 Subject: [PATCH 1321/1342] buildbot: build documentation, add nightly upload of master docs, other tweaks * master.cfg: Add a "build-docs" builder to test generation of HTML and PDF docs into the commit checks. With nightly=true property, upload generated docs to a static dir on the master. Run from a NightlyScheduler. Add the properties from the internal worker config to the buildbot BuildSlave properties, so they're visible in the web UI. Filter through a workers2publicprops helper, to whitelist allowed props. --- infra/buildbot/master/master.cfg | 183 +++++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 11 deletions(-) diff --git a/infra/buildbot/master/master.cfg b/infra/buildbot/master/master.cfg index 899d6fa38..00e56dd90 100644 --- a/infra/buildbot/master/master.cfg +++ b/infra/buildbot/master/master.cfg @@ -16,18 +16,52 @@ quaggagit = 'git://git.sv.gnu.org/quagga.git' # password defs execfile("pass.cfg") +# filter a given 'workers' entry into a property list +# suitable for public display +def workers2publicprops (worker): + publicprops = [ "os", "version", "vm", "pkg", "texi", "cc", + "latent", ] + return { k:worker[k] for k in worker if k in publicprops } + +# vm: non-VM are assumed faster and used for initial build +# pkg: rpm, sysv, dpkg - only do test rpm builds at moment +# texi: True or "true" if we can use for doc building +# cc: List of tuples of installed compilers, with: +# (, , ) +# tag: gcc, clang, sunpro +# latent: VM spun up on demand via LatentSlave, uses "session" for +# the libvirt URI. +# session: libvirt URI to use for latent workers. Default will be set on +# latent VMs if not specified. +# hd_image: libvirt image to use workers = { "fedora-24": { "os": "Fedora", "version": "24", "vm": False, "pkg": "rpm", + "texi": True, + "cc": [ ("gcc", "6.3.1"), + ("clang", "3.8.1"), + ("gcc", "3.4.6", "gcc34"), + ], + }, + "fedora-26": { + "os": "Fedora", + "version": "26", + "vm": False, + "pkg": "rpm", + "cc": [ ("gcc", "7.0.1"), + ("clang", "3.9.0"), + ("gcc", "3.4.6", "gcc34"), + ], }, "centos-7": { "os": "CentOS", "version": "7", "vm": False, "pkg": "rpm", + "cc": [ ("gcc", "4.8.5") ], }, "debian-8": { "os": "Debian", @@ -35,6 +69,7 @@ workers = { "vm": True, "pkg": "dpkg", "latent": True, + "cc": [ ("gcc", "4.9.2") ], "hd_image": "/var/lib/libvirt/images/debian8.qcow2", }, "debian-9": { @@ -42,6 +77,7 @@ workers = { "version": "9", "vm": True, "pkg": "dpkg", + "cc": [ ("gcc", "6.3.0") ], "latent": True, "hd_image": "/var/lib/libvirt/images/debian9.qcow2", }, @@ -51,6 +87,7 @@ workers = { "vm": True, "pkg": "", "latent": True, + "cc": [ ("clang", "3.4.1") ], "hd_image": "/var/lib/libvirt/images/freebsd103.qcow2", }, "freebsd-11": { @@ -58,6 +95,7 @@ workers = { "version": "11", "vm": True, "pkg": "", + "cc": [ ("gcc", "4.9.4"), ("clang", "3.8.0"), ], "latent": True, "hd_image": "/var/lib/libvirt/images/freebsd110.qcow2", }, @@ -67,6 +105,9 @@ workers = { "vm": True, "pkg": "sysv", "latent": True, + "cc": [ ("gcc", "6.3.0"), ("sunpro", "12.0"), + ("gcc", "4.4.4") + ], "hd_image": "/var/lib/libvirt/images/buildbot-oi-hipster.qcow2", }, } @@ -83,7 +124,7 @@ for kw in workers: analyses_builders = [ "clang-analyzer" ] # default Libvirt session -for w in (w for w in workers.values () if ("latent" in w) +for w in (w for w in workers.values () if ("latent" in w and w["latent"]) and ("session" not in w)): w["session"] = 'qemu+ssh://buildbot@sagan.jakma.org/system' @@ -93,12 +134,17 @@ osslowbuilders = ["build-" + kw for kw in workers if workers[kw]["vm"] == True] rpmbuilders = ["rpm-" + kw for kw in workers if workers[kw]["pkg"] == "rpm"] +# compilers +# not using yet +# [kw for kw in workers if len([v for (c,v) in workers[kw]["cc"] if c == "gcc"]) > 0 ] + allbuilders = [] allbuilders += osbuilders allbuilders += rpmbuilders allbuilders += analyses_builders allbuilders += ["commit-builder"] allbuilders += ["build-distcheck"] +allbuilders += ["build-docs" ] # Force merging of requests. # c['mergeRequests'] = lambda *args, **kwargs: True @@ -112,7 +158,9 @@ c['slaves'] = [] for w in (w for w in workers.values() if ("latent" not in w) or (w["latent"] == False)): - c['slaves'].append(buildslave.BuildSlave(w["bot"], w["pass"])) + c['slaves'].append(buildslave.BuildSlave(w["bot"], w["pass"], + properties=workers2publicprops (w), + )) for w in (w for w in workers.values() if ("latent" in w) @@ -123,6 +171,7 @@ for w in (w for w in workers.values() w["pass"], util.Connection(w["session"]), w["hd_image"], + properties=workers2publicprops (w), )) # 'protocols' contains information about protocols which master will use for @@ -197,6 +246,11 @@ c['schedulers'].append(schedulers.Triggerable( name="trigger-rpm", builderNames=rpmbuilders)) +# Doc build check (non-nightly, so no upload) +c['schedulers'].append(schedulers.Triggerable( + name="trigger-build-docs", + builderNames=["build-docs"])) + # Try and force schedulers c['schedulers'].append(schedulers.ForceScheduler( name="force", @@ -207,10 +261,23 @@ c['schedulers'].append(schedulers.Try_Userpass( builderNames=osbuilders + rpmbuilders + ["build-distcheck", - "clang-analyzer" ], + "clang-analyzer", + "build-docs" ], userpass=users, port=8031)) +## nightly docs build +c['schedulers'].append(schedulers.Nightly( + name="nightly-docs", + branch="master", + builderNames=[ "build-docs" ], + hour=3, + minute=0, + onlyIfChanged=True, + properties = { "nightly": True }, +)) + + ####### BUILDERS c['builders'] = [] @@ -218,12 +285,15 @@ c['builders'] = [] # what steps, and which slaves can execute them. Note that any particular build will # only take place on one slave. -common_steps = [ -steps.Git(repourl=quaggagit, mode='incremental'), -steps.ShellCommand(command=["./update-autotools"]), -steps.Configure(), -steps.ShellCommand(command=["make", "clean"]), -steps.Compile(), +common_setup = [ + steps.Git(repourl=quaggagit, mode='incremental'), + steps.ShellCommand(command=["./update-autotools"], + description="generating autoconf", + descriptionDone="autoconf"), + steps.Configure(command="../build/configure"), + steps.ShellCommand(command=["make", "clean"], + description="cleaning", + descriptionDone="make clean"), ] ### Default 'check' build, builder instantiated for each OS @@ -238,6 +308,8 @@ factory.addStep(steps.Configure()) factory.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", descriptionDone="clean")) + +#factory.addSteps(common_setup) factory.addStep(steps.Compile(command=["make", "-j", "2", "all"])) factory.addStep(steps.ShellCommand(command=["make", "check"], description="checking", @@ -348,6 +420,95 @@ for kw in (kw for kw in workers if workers[kw]["pkg"] == "rpm"): ) ) +### Build documentation + +def build_is_nightly (step): + n = step.getProperty("nightly") + if n == True or n == "True" or n == "true": + return True + return False + +f = util.BuildFactory () +f.addStep(steps.Git(repourl=quaggagit, mode='full')) +f.addStep(steps.ShellCommand(command=["./update-autotools"], + description="run autotools", + descriptionDone="autotools")) +f.addStep(steps.Configure(command=["../build/configure"], + workdir="docs")) +f.addStep(steps.ShellCommand(command=["make", "V=99", "quagga.html"], + description="making split HTML doc", + descriptionDone="docs: split HTML", + workdir="docs/doc", + haltOnFailure=True, +)) +#f.addStep(steps.FileUpload( +# slavesrc="build/doc/fig-normal-processing.png", +# masterdest = "public_html/docs/nightly/quagga/", +# name = "Upload Fig 1", +# doStepIf=build_is_nightly, +#)) +#f.addStep(steps.FileUpload( +# slavesrc="build/doc/fig-rs-processing.png", +# masterdest = "public_html/docs/nightly/quagga/", +# name = "Upload Fig 2", +# doStepIf=build_is_nightly, +#)) +f.addStep(steps.MultipleFileUpload( + slavesrcs=[ "doc/fig-rs-processing.png", + "doc/fig-normal-processing.png" ], + masterdest = "public_html/docs/nightly/quagga/", + name = "Upload Figures", + doStepIf=build_is_nightly, +)) +f.addStep(steps.DirectoryUpload( + slavesrc="quagga.html", + masterdest = "public_html/docs/nightly/quagga", + compress = 'bz2', + name = "Upload split HTML", + url = "/docs/nightly/quagga/index.html", + workdir="docs/doc", + doStepIf=build_is_nightly, +)) +f.addStep(steps.RemoveDirectory( + dir="docs/doc/quagga.html", +)) +f.addStep(steps.ShellCommand(command=["make", "V=99", + "MAKEINFOFLAGS=--no-split", + "quagga.html"], + description="making one-page HTML doc", + descriptionDone="docs: one-page HTML", + workdir="docs/doc", + haltOnFailure=True +)) +f.addStep(steps.FileUpload( + slavesrc="quagga.html", + masterdest = "public_html/docs/nightly/quagga/quagga.html", + name = "Upload single HTML", + url = "/docs/nightly/quagga/quagga.html", + workdir="docs/doc", + doStepIf=build_is_nightly, +)) +f.addStep(steps.ShellCommand(command=["make", "V=99", "quagga.pdf"], + description="making PDF docs", + descriptionDone="docs: PDF", + workdir="docs/doc" +)) +f.addStep(steps.FileUpload( + slavesrc="quagga.pdf", + masterdest = "public_html/docs/nightly/quagga/quagga.pdf", + name = "Upload PDF", + url = "/docs/nightly/quagga/quagga.pdf", + workdir="docs/doc", + doStepIf=build_is_nightly, +)) + +c['builders'].append( + util.BuilderConfig(name="build-docs", + slavenames=[w["bot"] for w in workers.values() + if "texi" in w and w["texi"] == True ], + factory=f +)) + ### Co-ordination builds used to sequence parallel builds via Triggerable # to understand this you have to read this list and the Triggered schedulers @@ -367,7 +528,8 @@ f.addStep(steps.Trigger ( updateSourceStamp=True )) f.addStep(steps.Trigger ( - schedulerNames = [ "trigger-build-analyses", "trigger-distcheck" ], + schedulerNames = [ "trigger-build-analyses", "trigger-distcheck", + "trigger-build-docs" ], waitForFinish=True, updateSourceStamp=True )) @@ -383,7 +545,6 @@ c['builders'].append( factory=f) ) - ####### STATUS TARGETS # 'status' is a list of Status Targets. The results of each build will be From da94416dd48171d53a9fe3ac57763d7552987dca Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 10 Mar 2017 12:55:06 +0000 Subject: [PATCH 1322/1342] release: Quagga 1.2.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0bfdde6fb..db663565e 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 1.2.0, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.2.1, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) From b2f18740c4f9a5a0cc473d90b1091082629b830d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 25 Mar 2017 17:27:24 +0200 Subject: [PATCH 1323/1342] nhrpd: implement 'show ip nhrp nhs' --- nhrpd/nhrp_nhs.c | 28 ++++++++------- nhrpd/nhrp_vty.c | 88 +++++++++++++++++++++++++++++++----------------- nhrpd/nhrpd.h | 13 +++++++ 3 files changed, 86 insertions(+), 43 deletions(-) diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index d463e0625..7a5d23936 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -15,19 +15,6 @@ #include "nhrp_protocol.h" static int nhrp_nhs_resolve(struct thread *t); - -struct nhrp_registration { - struct list_head reglist_entry; - struct thread *t_register; - struct nhrp_nhs *nhs; - struct nhrp_reqid reqid; - unsigned int timeout; - unsigned mark : 1; - union sockunion proto_addr; - struct nhrp_peer *peer; - struct notifier_block peer_notifier; -}; - static int nhrp_reg_send_req(struct thread *t); static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) @@ -367,3 +354,18 @@ void nhrp_nhs_terminate(void) } } } + +void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx) +{ + struct nhrp_interface *nifp = ifp->info; + struct nhrp_nhs *nhs; + struct nhrp_registration *reg; + + list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) { + if (!list_empty(&nhs->reglist_head)) { + list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) + cb(nhs, reg, ctx); + } else + cb(nhs, 0, ctx); + } +} diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 9b1c69de5..0cc0de2a8 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -589,6 +589,56 @@ static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) VTY_NEWLINE); } +static void show_ip_nhrp_nhs(struct nhrp_nhs *n, struct nhrp_registration *reg, void *pctx) +{ + struct info_ctx *ctx = pctx; + struct vty *vty = ctx->vty; + char buf[2][SU_ADDRSTRLEN]; + + if (!ctx->count) { + vty_out(vty, "%-8s %-24s %-16s %-16s%s", + "Iface", + "FQDN", + "NBMA", + "Protocol", + VTY_NEWLINE); + } + ctx->count++; + + vty_out(vty, "%-8s %-24s %-16s %-16s%s", + n->ifp->name, + n->nbma_fqdn, + (reg && reg->peer) ? sockunion2str(®->peer->vc->remote.nbma, buf[0], sizeof buf[0]) : "-", + sockunion2str(reg ? ®->proto_addr : &n->proto_addr, buf[1], sizeof buf[1]), + VTY_NEWLINE); +} + +static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx) +{ + struct info_ctx *ctx = pctx; + struct nhrp_cache *c; + struct vty *vty = ctx->vty; + char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN]; + + if (!ctx->count) { + vty_out(vty, "%-8s %-24s %-24s %s%s", + "Type", + "Prefix", + "Via", + "Identity", + VTY_NEWLINE); + } + ctx->count++; + + c = s->cache; + vty_out(ctx->vty, "%-8s %-24s %-24s %s%s", + nhrp_cache_type_str[s->type], + prefix2str(s->p, buf1, sizeof buf1), + c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "", + (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "", + VTY_NEWLINE); +} + static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx) { struct info_ctx *ctx = pctx; @@ -628,38 +678,13 @@ static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx) vty_out(ctx->vty, "%s", VTY_NEWLINE); } -static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx) -{ - struct info_ctx *ctx = pctx; - struct nhrp_cache *c; - struct vty *vty = ctx->vty; - char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN]; - - if (!ctx->count) { - vty_out(vty, "%-8s %-24s %-24s %s%s", - "Type", - "Prefix", - "Via", - "Identity", - VTY_NEWLINE); - } - ctx->count++; - - c = s->cache; - vty_out(ctx->vty, "%-8s %-24s %-24s %s%s", - nhrp_cache_type_str[s->type], - prefix2str(s->p, buf1, sizeof buf1), - c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "", - (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "", - VTY_NEWLINE); -} - DEFUN(show_ip_nhrp, show_ip_nhrp_cmd, - "show " AFI_CMD " nhrp (cache|shortcut|opennhrp|)", + "show " AFI_CMD " nhrp (cache|nhs|shortcut|opennhrp|)", SHOW_STR AFI_STR "NHRP information\n" "Forwarding cache information\n" + "Next hop server information\n" "Shortcut information\n" "opennhrpctl style cache dump\n") { @@ -673,13 +698,16 @@ DEFUN(show_ip_nhrp, show_ip_nhrp_cmd, if (!argv[1] || argv[1][0] == 'c') { for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) nhrp_cache_foreach(ifp, show_ip_nhrp_cache, &ctx); - } else if (argv[1][0] == 'o') { + } else if (argv[1][0] == 'n') { + for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) + nhrp_nhs_foreach(ifp, ctx.afi, show_ip_nhrp_nhs, &ctx); + } else if (argv[1][0] == 's') { + nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx); + } else { vty_out(vty, "Status: ok%s%s", VTY_NEWLINE, VTY_NEWLINE); ctx.count++; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) nhrp_cache_foreach(ifp, show_ip_opennhrp_cache, &ctx); - } else { - nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx); } if (!ctx.count) { diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 307546e08..9222ad4e4 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -251,6 +251,18 @@ struct nhrp_nhs { struct list_head reglist_head; }; +struct nhrp_registration { + struct list_head reglist_entry; + struct thread *t_register; + struct nhrp_nhs *nhs; + struct nhrp_reqid reqid; + unsigned int timeout; + unsigned mark : 1; + union sockunion proto_addr; + struct nhrp_peer *peer; + struct notifier_block peer_notifier; +}; + #define NHRP_IFF_SHORTCUT 0x0001 #define NHRP_IFF_REDIRECT 0x0002 #define NHRP_IFF_REG_NO_UNIQUE 0x0100 @@ -308,6 +320,7 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); int nhrp_nhs_free(struct nhrp_nhs *nhs); void nhrp_nhs_terminate(void); +void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx); void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp); void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu); From d7f6770b298a7f4aab6cb079b9b3895ea407980b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 21 Apr 2017 13:37:07 +0300 Subject: [PATCH 1324/1342] nhrp: implement 'no ip nhrp map' command was accidentally not implemented earlier --- nhrpd/nhrp_vty.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 0cc0de2a8..3f903aab4 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -503,6 +503,32 @@ DEFUN(if_nhrp_map, if_nhrp_map_cmd, return CMD_SUCCESS; } +DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd, + "no " AFI_CMD " nhrp map (A.B.C.D|X:X::X:X)", + NO_STR + AFI_STR + NHRP_STR + "Nexthop Server configuration\n" + "IPv4 protocol address\n" + "IPv6 protocol address\n") +{ + struct interface *ifp = vty->index; + afi_t afi = cmd_to_afi(argv[0]); + union sockunion proto_addr; + struct nhrp_cache *c; + + if (str2sockunion(argv[1], &proto_addr) < 0 || + afi2family(afi) != sockunion_family(&proto_addr)) + return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH); + + c = nhrp_cache_get(ifp, &proto_addr, 0); + if (!c || !c->map) + return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND); + + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + return CMD_SUCCESS; +} + DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd, AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", AFI_STR @@ -951,6 +977,7 @@ void nhrp_config_init(void) install_element(INTERFACE_NODE, &if_nhrp_reg_flags_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd); install_element(INTERFACE_NODE, &if_nhrp_map_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd); install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd); } From e916ffd156a3edfef74c5f9cc36581f91abb2cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 20 Apr 2017 16:24:14 +0300 Subject: [PATCH 1325/1342] nhrp: fix protocol address family parsing on receive See bugzilla #948 --- nhrpd/nhrp_peer.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 45bfd7deb..ff4ff6e01 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -729,6 +729,15 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir) reply ? buf[0] : buf[1]); } +static int proto2afi(uint16_t proto) +{ + switch (proto) { + case ETH_P_IP: return AFI_IP; + case ETH_P_IPV6: return AFI_IP6; + } + return AF_UNSPEC; +} + struct nhrp_route_info { int local; struct interface *ifp; @@ -748,7 +757,7 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) const char *info = NULL; union sockunion *target_addr; unsigned paylen, extoff, extlen, realsize; - afi_t afi; + afi_t nbma_afi, proto_afi; debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s", sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), @@ -776,20 +785,21 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) pp.hdr = hdr; pp.peer = p; - afi = htons(hdr->afnum); + nbma_afi = htons(hdr->afnum); + proto_afi = proto2afi(htons(hdr->protocol_type)); if (hdr->type > ZEBRA_NUM_OF(packet_types) || hdr->version != NHRP_VERSION_RFC2332 || - afi >= AFI_MAX || + nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC || packet_types[hdr->type].type == PACKET_UNKNOWN || htons(hdr->packet_size) > realsize) { - zlog_info("From %s: error: packet type %d, version %d, AFI %d, size %d (real size %d)", + zlog_info("From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)", sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), - (int) hdr->type, (int) hdr->version, (int) afi, - (int) htons(hdr->packet_size), - (int) realsize); + (int) hdr->type, (int) hdr->version, + (int) nbma_afi, (int) htons(hdr->protocol_type), + (int) htons(hdr->packet_size), (int) realsize); goto drop; } - pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[afi]; + pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi]; extoff = htons(hdr->extension_offset); if (extoff) { @@ -805,7 +815,7 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) extlen = zbuf_used(zb); zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen); - if (!nifp->afi[afi].network_id) { + if (!nifp->afi[proto_afi].network_id) { info = "nhrp not enabled"; goto drop; } From e0401e107105b6444f45d5e0881bee4356d827ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 21 Apr 2017 13:57:28 +0300 Subject: [PATCH 1326/1342] nhrp: explicitly cast ints to size_t for vici_request_vc va_list handling --- nhrpd/vici.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 507dd14a9..12409f90b 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -449,9 +449,9 @@ void vici_request_vc(const char *profile, union sockunion *src, union sockunion vici_submit_request( vici, "initiate", VICI_KEY_VALUE, "child", strlen(profile), profile, - VICI_KEY_VALUE, "timeout", 2, "-1", - VICI_KEY_VALUE, "async", 1, "1", - VICI_KEY_VALUE, "init-limits", 1, prio ? "0" : "1", + VICI_KEY_VALUE, "timeout", (size_t) 2, "-1", + VICI_KEY_VALUE, "async", (size_t) 1, "1", + VICI_KEY_VALUE, "init-limits", (size_t) 1, prio ? "0" : "1", VICI_KEY_VALUE, "my-host", strlen(buf[0]), buf[0], VICI_KEY_VALUE, "other-host", strlen(buf[1]), buf[1], VICI_END); From add1dcd0b36fd5a8f20835db7b1b016be59a476b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 21 Apr 2017 14:56:45 +0300 Subject: [PATCH 1327/1342] nhrp: notify 'tunnel protection' changes to triggers refresh of IKE SAs immediately on this command --- nhrpd/nhrp_interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 8118927ab..4ea807646 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -391,6 +391,8 @@ void nhrp_interface_set_protection(struct interface *ifp, const char *profile, c if (nifp->ipsec_fallback_profile) free(nifp->ipsec_fallback_profile); nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL; + + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); } void nhrp_interface_set_source(struct interface *ifp, const char *ifname) From b328262a461263b98142d0ca5f3fe0cadcfb5b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 21 Apr 2017 14:57:57 +0300 Subject: [PATCH 1328/1342] nhrp: fix potential crash when vici profile name is not configured --- nhrpd/nhrp_peer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index ff4ff6e01..728fa1c4d 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -248,6 +248,8 @@ int nhrp_peer_check(struct nhrp_peer *p, int establish) return 0; if (p->requested) return 0; + if (!nifp->ipsec_profile) + return 0; if (sockunion_family(&vc->local.nbma) == AF_UNSPEC) return 0; From a2c23534a41af8fed5a4dce3eb30e4a91f003103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 21 Apr 2017 14:58:17 +0300 Subject: [PATCH 1329/1342] nhrp: parse and log command response errors from strongSwan helps to debug configuration problems --- nhrpd/vici.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 12409f90b..5491bacf7 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -220,6 +220,23 @@ static void parse_sa_message( } } +static void parse_cmd_response( + struct vici_message_ctx *ctx, + enum vici_type_t msgtype, + const struct blob *key, const struct blob *val) +{ + char buf[512]; + + switch (msgtype) { + case VICI_KEY_VALUE: + if (blob_equal(key, "errmsg") && blob2buf(val, buf, sizeof(buf))) + zlog_err("VICI: strongSwan: %s", buf); + break; + default: + break; + } +} + static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event) { char buf[32]; @@ -265,11 +282,14 @@ static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg) else if (blob_equal(&name, "child-state-destroying")) vici_recv_sa(vici, msg, 2); break; + case VICI_CMD_RESPONSE: + vici_parse_message(vici, msg, parse_cmd_response, 0); + break; case VICI_EVENT_UNKNOWN: + case VICI_CMD_UNKNOWN: zlog_err("VICI: StrongSwan does not support mandatory events (unpatched?)"); break; case VICI_EVENT_CONFIRM: - case VICI_CMD_RESPONSE: break; default: zlog_notice("VICI: Unrecognized message type %d", msgtype); From 8e8945bb1b65ea952468cbf9e07b1fa54fa2e2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 3 May 2017 08:40:43 +0300 Subject: [PATCH 1330/1342] nhrp: improve CIE prefix length handling RFC2332 states that prefix length MUST be 0xff for unique bindings. However, it seems at least some Cisco firmwares use host prefix length instead (which on wire level makes sense). Relax the handling of prefix length to treat all value longer than address length as 0xff. Additionally treat 0x00 the same way too, this is required by the RFC. This also fixes the prefix length address family to be checked against protocol address. --- nhrpd/nhrp_nhs.c | 2 +- nhrpd/nhrp_peer.c | 11 ++++++++--- nhrpd/nhrp_shortcut.c | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index 7a5d23936..535f9559f 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -181,7 +181,7 @@ static int nhrp_reg_send_req(struct thread *t) hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT); ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr); - cie->prefix_length = 8 * sockunion_get_addrlen(&nifp->nbma); + cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr); nhrp_ext_complete(zb, ext); nhrp_packet_complete(zb, hdr); diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 728fa1c4d..5095d55a6 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -383,11 +383,12 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) struct nhrp_extension_header *ext; struct nhrp_cache *c; union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr, *nbma_natoa; - int holdtime, natted = 0; + int holdtime, prefix_len, hostprefix_len, natted = 0; size_t paylen; void *pay; debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req"); + hostprefix_len = 8 * sockunion_get_addrlen(&p->if_ad->addr); if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma)) natted = 1; @@ -409,13 +410,17 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) zbuf_init(&payload, pay, paylen, paylen); while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto)) != NULL) { - if (cie->prefix_length != 0xff && !(p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) { + prefix_len = cie->prefix_length; + if (prefix_len == 0 || prefix_len >= hostprefix_len) + prefix_len = hostprefix_len; + + if (prefix_len != hostprefix_len && !(p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) { cie->code = NHRP_CODE_BINDING_NON_UNIQUE; continue; } /* We currently support only unique prefix registrations */ - if (cie->prefix_length != 0xff) { + if (prefix_len != hostprefix_len) { cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; continue; } diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index 421f2886f..60c63929f 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -224,7 +224,7 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, void *ar prefix.prefixlen = cie->prefix_length; /* Sanity check prefix length */ - if (prefix.prefixlen >= 8*prefix_blen(&prefix)) { + if (prefix.prefixlen >= 8*prefix_blen(&prefix) || prefix.prefixlen == 0) { prefix.prefixlen = 8*prefix_blen(&prefix); } else if (nhrp_route_address(NULL, &pp->dst_proto, &route_prefix, NULL) == NHRP_ROUTE_NBMA_NEXTHOP) { if (prefix.prefixlen < route_prefix.prefixlen) From 9d510fc6fed74dc9bddc998b385bdd194c1f95a9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 18 May 2017 08:55:51 +0300 Subject: [PATCH 1331/1342] nhrpd: Fix some missing newlines Signed-off-by: Donald Sharp --- nhrpd/nhrp_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 3f903aab4..91269f27e 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -206,7 +206,7 @@ DEFUN(nhrp_event_socket, nhrp_event_socket_cmd, NHRP_STR "Event Manager commands\n" "Event Manager unix socket path\n" - "Unix path for the socket") + "Unix path for the socket\n") { evmgr_set_socket(argv[0]); return CMD_SUCCESS; @@ -218,7 +218,7 @@ DEFUN(no_nhrp_event_socket, no_nhrp_event_socket_cmd, NHRP_STR "Event Manager commands\n" "Event Manager unix socket path\n" - "Unix path for the socket") + "Unix path for the socket\n") { evmgr_set_socket(NULL); return CMD_SUCCESS; From 1a8b0177155cc434d3fa4f6dbe7adfc1e854b809 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 17 May 2017 18:31:02 -0400 Subject: [PATCH 1332/1342] nhrpd: Fix crash in 'no nhrp event socket..' command Signed-off-by: Donald Sharp --- nhrpd/nhrp_event.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nhrpd/nhrp_event.c b/nhrpd/nhrp_event.c index aab9ec642..34cb0655f 100644 --- a/nhrpd/nhrp_event.c +++ b/nhrpd/nhrp_event.c @@ -211,9 +211,12 @@ void evmgr_init(void) void evmgr_set_socket(const char *socket) { - if (nhrp_event_socket_path) + if (nhrp_event_socket_path) { free((char *) nhrp_event_socket_path); - nhrp_event_socket_path = strdup(socket); + nhrp_event_socket_path = NULL; + } + if (socket) + nhrp_event_socket_path = strdup(socket); evmgr_connection_error(&evmgr_connection); } From 7101ccb2a765880bc22cb24cbcf37565e35349d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 18 May 2017 12:00:22 +0300 Subject: [PATCH 1333/1342] nhrpd: announce ipv6 routes to zebra --- nhrpd/nhrp_route.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index cc6b5fa24..a80f3e0c2 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -90,7 +90,6 @@ void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu) { - struct in_addr *nexthop_ipv4; int flags = 0; if (zclient->sock < 0) @@ -113,6 +112,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); if (p->family == AF_INET) { + struct in_addr *nexthop_ipv4; struct zapi_ipv4 api; memset(&api, 0, sizeof(api)); @@ -122,7 +122,6 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if (nexthop) { - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); nexthop_ipv4 = (struct in_addr *) sockunion_get_addr(nexthop); api.nexthop_num = 1; api.nexthop = &nexthop_ipv4; @@ -151,6 +150,45 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix zapi_ipv4_route( add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); + } else if (p->family == AF_INET6) { + struct in6_addr *nexthop_ipv6; + struct zapi_ipv6 api; + + memset(&api, 0, sizeof(api)); + api.flags = flags; + api.type = ZEBRA_ROUTE_NHRP; + api.safi = SAFI_UNICAST; + + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + if (nexthop) { + nexthop_ipv6 = (struct in6_addr *) sockunion_get_addr(nexthop); + api.nexthop_num = 1; + api.nexthop = &nexthop_ipv6; + } + if (ifp) { + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifp->ifindex; + } + if (mtu) { + SET_FLAG(api.message, ZAPI_MESSAGE_MTU); + api.mtu = mtu; + } + + if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) { + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra send: IPv6 route %s %s/%d nexthop %s metric %u" + " count %d dev %s", + add ? "add" : "del", + inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), + p->prefixlen, + nexthop ? inet_ntop(AF_INET6, api.nexthop[0], buf[1], sizeof(buf[1])) : "", + api.metric, api.nexthop_num, ifp->name); + } + + zapi_ipv6_route( + add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, + zclient, (struct prefix_ipv6 *) p, &api); } } From a929c52ec36b3f868e85fd91e1f013bd9a59d05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 19 May 2017 14:08:35 +0300 Subject: [PATCH 1334/1342] nhrpd: configure mgre ipv6 nd for nhrp --- nhrpd/linux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nhrpd/linux.c b/nhrpd/linux.c index 1e9c69eb8..75a16eab3 100644 --- a/nhrpd/linux.c +++ b/nhrpd/linux.c @@ -138,16 +138,16 @@ static int linux_icmp_redirect_off(const char *iface) int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af) { - int ret = -1; + int ret = 0; switch (af) { case AF_INET: - ret = linux_icmp_redirect_off("all"); + ret |= linux_icmp_redirect_off("all"); ret |= linux_icmp_redirect_off(ifname); - ret |= netlink_configure_arp(ifindex, AF_INET); - ret |= linux_configure_arp(ifname, 1); break; } + ret |= linux_configure_arp(ifname, 1); + ret |= netlink_configure_arp(ifindex, af); return ret; } From a0e8ee2e4e2faa912f2f956eadca55573951b432 Mon Sep 17 00:00:00 2001 From: Balaji Gurudoss Date: Sat, 13 May 2017 13:05:58 +0530 Subject: [PATCH 1335/1342] vtysh:address-family vpnv6 and vpnv6 unicast added to resolve " % Ambiguous command." Fixes bug #950 Signed-off-by: Balaji Gurudoss --- vtysh/extract.pl.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index ca223e582..6e24b7756 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -49,6 +49,8 @@ $ignore{'"address-family ipv6"'} = "ignore"; $ignore{'"address-family ipv6 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; +$ignore{'"address-family vpnv6"'} = "ignore"; +$ignore{'"address-family vpnv6 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; $ignore{'"address-family encap"'} = "ignore"; $ignore{'"address-family encapv4"'} = "ignore"; From 0600823386dab2865d5c642298bf247a29df923c Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 19 Jul 2011 21:54:06 +0530 Subject: [PATCH 1336/1342] ripd: ripv2 fails to send packets on non multicast interface Fix to resolve ripv2 update process from skipping over non multicast interfaces when sending updates. Reported by: Christian Hammers --- ripd/ripd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index dd3ca5bb3..c073ecab6 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2522,7 +2522,7 @@ rip_update_process (int route_type) { if (vsend & RIPv1) rip_update_interface (connected, RIPv1, route_type); - if ((vsend & RIPv2) && if_is_multicast(ifp)) + if (vsend & RIPv2) rip_update_interface (connected, RIPv2, route_type); } } From 5178613d645de44d6862f259ec5c3f0962e38728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 15 Jun 2017 09:37:16 +0300 Subject: [PATCH 1337/1342] nhrpd: add few tested kernels, improve readme notes --- nhrpd/README.kernel | 10 ++++++---- nhrpd/README.nhrpd | 17 ++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/nhrpd/README.kernel b/nhrpd/README.kernel index 5831316f1..3fe1f65f9 100644 --- a/nhrpd/README.kernel +++ b/nhrpd/README.kernel @@ -1,13 +1,15 @@ -KERNEL REQUIREMENTS -=================== +LINUX KERNEL REQUIREMENTS +========================= The linux kernel has had various major regressions, performance issues and subtle bugs (especially in pmtu). Here is a short list -of some -stable kernels and the first point release that is supposedly -working well with opennhrp/dmvpn: +of some -stable kernels that have been tested (at least briefly) +and seem to be working well with Quagga/NHRP: 3.12.8 or later 3.14.54 or later 3.18.22 or later[1] + 4.4.52 or later + 4.9.30 or later [1] But you need to apply the following two backported commits: 3cdaa5be9e ipv4: Don't increase PMTU with Datagram Too Big message diff --git a/nhrpd/README.nhrpd b/nhrpd/README.nhrpd index 569b3f446..af358fa92 100644 --- a/nhrpd/README.nhrpd +++ b/nhrpd/README.nhrpd @@ -9,17 +9,18 @@ Cisco DMVPN (and potentially with FlexVPN in the future). Current Status -------------- +Implemented: - IPsec integration with strongSwan (requires patched strongSwan) - IPv4 over IPv4 NBMA GRE - IPv6 over IPv4 NBMA GRE -- majority of code exist; but is not tested -- Spoke (NHC) functionality complete -- Hub (NHS) functionality complete -- Multicast support is not done yet - (so OSPF will not work, use BGP for now) +- Spoke (NHC) functionality +- Hub (NHS) functionality -The code is not (yet) compatible with Cisco FlexVPN style DMVPN. It -would require relaying IKEv2 routing messages from strongSwan to nhrpd -and parsing that. It is doable, but not implemented for the time being. +Not yet implemented: +- NHRP Authentication +- NHRP Groups +- Multicast support (OSPF will not work) +- Full Cisco FlexVPN compatibility (IKEv2 routing) Routing Design @@ -32,6 +33,7 @@ To create NBMA GRE tunnel you might use following: ip tunnel add gre1 mode gre key 42 ttl 64 dev eth0 ip addr add 10.255.255.2/32 dev gre1 ip link set gre1 up + sysctl net.ipv4.ip_forward_use_pmtu=1 #for kernels>=3.14 This has two important differences compared to opennhrp setup: 1. The 'tunnel add' now specifies physical device binding. Quagga/NHRP @@ -114,6 +116,7 @@ Getting information via vtysh Some commands of interest: - show dmvpn + - show ip nhrp nhs - show ip nhrp cache - show ip nhrp shortcut - show ip route nhrp From 1d00f7e16b80f95a901daddd4f9c64d4ae7ed4ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 14 Jul 2017 11:20:12 +0300 Subject: [PATCH 1338/1342] nhrpd: add example nhrp event processing script (in lua) --- nhrpd/nhrp-events.lua | 272 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100755 nhrpd/nhrp-events.lua diff --git a/nhrpd/nhrp-events.lua b/nhrpd/nhrp-events.lua new file mode 100755 index 000000000..e5e3bbf70 --- /dev/null +++ b/nhrpd/nhrp-events.lua @@ -0,0 +1,272 @@ +#!/usr/bin/lua5.2 + +-- Example NHRP events processing script which validates +-- NHRP registration GRE address against certificate subjectAltName IP +-- and auto-creates BGP pairings and filters based on sbgp extensions. + +-- Depends on lua5.2 lua5.2-posix lua5.2-cqueues lua5.2-ossl lua-asn1 + +local posix = require 'posix' +local struct = require 'struct' +local cq = require 'cqueues' +local cqs = require 'cqueues.socket' +local x509 = require 'openssl.x509' +local x509an = require 'openssl.x509.altname' +local rfc3779 = require 'asn1.rfc3779' + +local SOCK = "/var/run/nhrp-events.sock" +posix.unlink(SOCK) + +local loop = cq.new() +local nulfd = posix.open("/dev/null", posix.O_RDWR) +local listener = cqs.listen{path=SOCK} + +posix.chown(SOCK, "quagga", "quagga") +posix.setpid("u", "quagga") +posix.setpid("g", "quagga") +posix.openlog("nhrp-events", "np") + +function string.hex2bin(str) + return str:gsub('..', function(cc) return string.char(tonumber(cc, 16)) end) +end + +local function decode_ext(cert, name, tpe) + local ext = cert:getExtension(name) + if not ext then return end + return tpe.decode(ext:getData()) +end + +local function do_parse_cert(cert, out) + for type, value in pairs(cert:getSubjectAlt()) do + if type == 'IP' then + table.insert(out.GRE, value) + end + end + if #out.GRE == 0 then return end + + local asn = decode_ext(cert, 'sbgp-autonomousSysNum', rfc3779.ASIdentifiers) + if asn and asn.asnum and asn.asnum.asIdsOrRanges then + for _, as in ipairs(asn.asnum.asIdsOrRanges) do + if as.id then + out.AS = tonumber(as.id) + break + end + end + end + + local addrBlocks = decode_ext(cert, 'sbgp-ipAddrBlock', rfc3779.IPAddrBlocks) + for _, ab in ipairs(addrBlocks or {}) do + if ab.ipAddressChoice and ab.ipAddressChoice.addressesOrRanges then + for _, a in ipairs(ab.ipAddressChoice.addressesOrRanges) do + if a.addressPrefix then + table.insert(out.NET, a.addressPrefix) + end + end + end + end + + return true +end + +local function parse_cert(certhex) + local out = { + cn = "(no CN)", + AS = 0, + GRE = {}, + NET = {}, + } + local cert = x509.new(certhex:hex2bin(), 'der') + out.cn = tostring(cert:getSubject()) + -- Recognize hubs by certificate's CN to have OU=Hubs + out.hub = out.cn:match("/OU=Hubs/") and true or nil + do_parse_cert(cert, out) + return out +end + +local function execute(desc, cmd, ...) + local piper, pipew = posix.pipe() + if piper == nil then + return error("Pipe failed") + end + + local pid = posix.fork() + if pid == -1 then + return error("Fork failed") + end + if pid == 0 then + posix.close(piper) + posix.dup2(nulfd, 0) + posix.dup2(pipew, 1) + posix.dup2(nulfd, 2) + posix.execp(cmd, ...) + os.exit(1) + end + posix.close(pipew) + + -- This blocks -- perhaps should handle command executions in separate queue. + local output = {} + while true do + local d = posix.read(piper, 8192) + if d == nil or d == "" then break end + table.insert(output, d) + end + posix.close(piper) + + local _, reason, status = posix.wait(pid) + if status == 0 then + posix.syslog(6, ("Executed '%s' successfully"):format(desc)) + else + posix.syslog(3, ("Failed to execute '%s': %s %d"):format(desc, reason, status)) + end + return status, table.concat(output) +end + +local function configure_bgp(desc, ...) + local args = { + "-d", "bgpd", + "-c", "configure terminal", + } + for _, val in ipairs({...}) do + table.insert(args, "-c") + table.insert(args, val) + end + return execute(desc, "vtysh", table.unpack(args)) +end + +local last_bgp_reset = 0 + +local function bgp_reset(msg, local_cert) + local now = os.time() + if last_bgp_reset + 60 > now then return end + last_bgp_reset = now + + configure_bgp("spoke reset", + "route-map RTT-SET permit 10", "set metric rtt", "exit", + "route-map RTT-ADD permit 10", "set metric +rtt", "exit", + ("router bgp %d"):format(local_cert.AS), + "no neighbor hubs", + "neighbor hubs peer-group", + "neighbor hubs remote-as 65000", + "neighbor hubs ebgp-multihop 1", + "neighbor hubs disable-connected-check", + "neighbor hubs timers 10 30", + "neighbor hubs timers connect 10", + "neighbor hubs next-hop-self all", + "neighbor hubs soft-reconfiguration inbound", + "neighbor hubs route-map RTT-ADD in") +end + +local function bgp_nhs_up(msg, remote_cert, local_cert) + configure_bgp(("nhs-up %s"):format(msg.remote_addr), + ("router bgp %s"):format(local_cert.AS), + ("neighbor %s peer-group hubs"):format(msg.remote_addr)) +end + +local function bgp_nhs_down(msg, remote_cert, local_cert) + configure_bgp(("nhs-down %s"):format(msg.remote_addr), + ("router bgp %s"):format(local_cert.AS), + ("no neighbor %s"):format(msg.remote_addr)) +end + +local function bgp_create_spoke_rules(msg, remote_cert, local_cert) + if not local_cert.hub then return end + + local bgpcfg = {} + for seq, net in ipairs(remote_cert.NET) do + table.insert(bgpcfg, + ("ip prefix-list net-%s-in seq %d permit %s le %d"):format( + msg.remote_addr, seq * 5, net, + remote_cert.hub and 32 or 26)) + end + table.insert(bgpcfg, ("router bgp %s"):format(local_cert.AS)) + if remote_cert.hub then + table.insert(bgpcfg, ("neighbor %s peer-group hubs"):format(msg.remote_addr)) + elseif local_cert.AS == remote_cert.AS then + table.insert(bgpcfg, ("neighbor %s peer-group spoke-ibgp"):format(msg.remote_addr)) + else + table.insert(bgpcfg, ("neighbor %s remote-as %s"):format(msg.remote_addr, remote_cert.AS)) + table.insert(bgpcfg, ("neighbor %s peer-group spoke-ebgp"):format(msg.remote_addr)) + end + table.insert(bgpcfg, ("neighbor %s prefix-list net-%s-in in"):format(msg.remote_addr, msg.remote_addr)) + + local status, output = configure_bgp(("nhc-register %s"):format(msg.remote_addr), table.unpack(bgpcfg)) + if output:find("Cannot") then + posix.syslog(6, "BGP: "..output) + configure_bgp( + ("nhc-recreate %s"):format(msg.remote_addr), + ("router bgp %s"):format(local_cert.AS), + ("no neighbor %s"):format(msg.remote_addr), + table.unpack(bgpcfg)) + end +end + +local function handle_message(msg) + if msg.event ~= "authorize-binding" then return end + + -- Verify protocol address against certificate + local auth = false + local local_cert = parse_cert(msg.local_cert) + local remote_cert = parse_cert(msg.remote_cert) + for _, gre in pairs(remote_cert.GRE) do + if gre == msg.remote_addr then auth = true end + end + if not auth then + posix.syslog(3, ("GRE %s to NBMA %s DENIED (cert '%s', allows: %s)"):format( + msg.remote_addr, msg.remote_nbma, + remote_cert.cn, table.concat(remote_cert.GRE, " "))) + return "deny" + end + posix.syslog(6, ("GRE %s to NBMA %s authenticated for %s"):format( + msg.remote_addr, msg.remote_nbma, remote_cert.cn)) + + -- Automatic BGP binding for hub-spoke connections + if msg.type == "nhs" and msg.old_type ~= "nhs" then + if not local_cert.hub then + if tonumber(msg.num_nhs) == 0 and msg.vc_initiated == "yes" then + bgp_reset(msg, local_cert) + end + bgp_nhs_up(msg, remote_cert, local_cert) + else + bgp_create_spoke_rules(msg, remote_cert, local_cert) + end + elseif msg.type ~= "nhs" and msg.old_type == "nhs" then + bgp_nhs_down(msg, remote_cert, local_cert) + elseif msg.type == "dynamic" and msg.old_type ~= "dynamic" then + bgp_create_spoke_rules(msg, remote_cert, local_cert) + end + + return "accept" +end + +local function handle_connection(conn) + local msg = {} + for l in conn:lines() do + if l == "" then + res = handle_message(msg) + if msg.eventid then + conn:write(("eventid=%s\nresult=%s\n\n"):format(msg.eventid, res or "default")) + end + msg = {} + else + local key, value = l:match('([^=]*)=(.*)') + if key and value then + msg[key] = value + end + end + end + conn:close() +end + +loop:wrap(function() + while true do + local conn = listener:accept() + conn:setmode("b", "bl") + loop:wrap(function() + local ok, msg = pcall(handle_connection, conn) + if not ok then posix.syslog(3, msg) end + conn:close() + end) + end +end) + +print(loop:loop()) From 44b486f5256be676a86a251017518f4ca147d977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 17 Aug 2017 16:55:43 +0300 Subject: [PATCH 1339/1342] nhrpd: use hop count 1 for registration requests Cisco has a bug that it rejects packets with zero hop count. Use one to avoid potential forwarding of registration requests. --- nhrpd/nhrp_nhs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index 535f9559f..d77ec0b80 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -163,7 +163,7 @@ static int nhrp_reg_send_req(struct thread *t) zb = zbuf_alloc(1400); hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST, &nifp->nbma, &if_ad->addr, dst_proto); - hdr->hop_count = 0; + hdr->hop_count = 1; if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE)) hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE); From fceb0cfe4590d43c93a1d3ae2d83491b08239aad Mon Sep 17 00:00:00 2001 From: Balaji Gurudoss Date: Mon, 2 Oct 2017 19:21:57 +0530 Subject: [PATCH 1340/1342] zebra: Fix to set tag for a static route configured. Fixes bug #955. Removed the installation of vrf specific tag and distance command. Reported by: goodman --- zebra/zebra_vty.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 2914f15b6..0c08990f9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -5293,7 +5293,6 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_protocol_cmd); install_element (CONFIG_NODE, &ip_route_cmd); install_element (CONFIG_NODE, &ip_route_tag_cmd); - install_element (CONFIG_NODE, &ip_route_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_cmd); install_element (CONFIG_NODE, &ip_route_flags_tag_cmd); install_element (CONFIG_NODE, &ip_route_flags_tag_vrf_cmd); @@ -5311,7 +5310,6 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_cmd); install_element (CONFIG_NODE, &no_ip_route_tag_cmd); - install_element (CONFIG_NODE, &no_ip_route_tag_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_tag_cmd); install_element (CONFIG_NODE, &no_ip_route_flags2_cmd); @@ -5326,7 +5324,6 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_vrf_cmd); install_element (CONFIG_NODE, &ip_route_distance_cmd); install_element (CONFIG_NODE, &ip_route_tag_distance_cmd); - install_element (CONFIG_NODE, &ip_route_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &ip_route_flags_distance_cmd); install_element (CONFIG_NODE, &ip_route_flags_tag_distance_cmd); install_element (CONFIG_NODE, &ip_route_flags_tag_distance_vrf_cmd); @@ -5344,7 +5341,6 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_tag_distance_cmd); - install_element (CONFIG_NODE, &no_ip_route_tag_distance_vrf_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_cmd); install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_vrf_cmd); From 7a42b78be9a4108d98833069a88e6fddb9285008 Mon Sep 17 00:00:00 2001 From: Andreas Jaggi Date: Mon, 2 Oct 2017 19:38:43 +0530 Subject: [PATCH 1341/1342] bgpd: Fix AS_PATH size calculation for long paths If you have an AS_PATH with more entries than what can be written into a single AS_SEGMENT_MAX it needs to be broken up. The code that noticed that the AS_PATH needs to be broken up was not correctly calculating the size of the resulting message. This patch addresses this issue. --- bgpd/bgp_aspath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index b7af5e88b..d813bfbab 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -903,7 +903,7 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit ) assegment_header_put (s, seg->type, AS_SEGMENT_MAX); assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit); written += AS_SEGMENT_MAX; - bytes += ASSEGMENT_SIZE (written, use32bit); + bytes += ASSEGMENT_SIZE (AS_SEGMENT_MAX, use32bit); } /* write the final segment, probably is also the first */ From 4f721a713d6e973fed8872a62f1c8c56e04fb045 Mon Sep 17 00:00:00 2001 From: Balaji Gurudoss Date: Tue, 3 Oct 2017 20:27:10 +0530 Subject: [PATCH 1342/1342] Bumped up the version to 1.2.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index db663565e..ae292f118 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 1.2.1, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 1.2.2, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h)